Skip to content

feat(certifi): optionally use certifi certificates - #394

Merged
ekalinin merged 6 commits into
masterfrom
feat/use-certifi
Aug 14, 2026
Merged

feat(certifi): optionally use certifi certificates#394
ekalinin merged 6 commits into
masterfrom
feat/use-certifi

Conversation

@ekalinin

@ekalinin ekalinin commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Builds on #388 by @mvdbeek: the two original commits are kept as-is and rebased on current master, with review fixes on top.

Why not just merge #388

  • --with-certifi fell back to the system certificate store without a word when certifi was missing. The flag asks for a specific trust store, so the user ended up with an opaque CERTIFICATE_VERIFY_FAILED instead of "certifi is not installed" - and a broken system store is exactly the situation the flag exists for.
  • The try block wrapped the network call as well as the import, so an ImportError raised from inside urlopen would silently repeat the request without certifi.
  • The SSL context was rebuilt per request, re-parsing the CA bundle on each of the 3-4 downloads a run makes.
  • with_certifi was not a Config attribute, so unlike every other persistent option it could not be set in ~/.nodeenvrc, tox.ini or setup.cfg, and it was missing from Config._dump().
  • No documentation, no tests.

What changed on top

fix(certifi) - certifi is resolved once in main() via a new make_certifi_context(), which imports certifi, warns and returns None if it is absent, and otherwise returns a context built a single time. The try now covers the import only. The global use_certifi is replaced by certifi_context - the context has to be stored anyway, so a separate boolean was duplicate state, and this also settles the --with-certifi / args.with_certifi / use_certifi naming split. Precedence over --ignore_ssl_certs is now explicit rather than an artifact of the return order.

feat(certifi) - with_certifi = False on Config and default=Config.with_certifi in the parser, so the option behaves like all the others.

docs(certifi) - README option entry and the configuration defaults block, plus a CHANGES entry. The README also mentions the SSL_CERT_FILE alternative, which reaches the same result with no code at all:

$ SSL_CERT_FILE=$(python -c 'import certifi; print(certifi.where())') nodeenv env

chore(setup) - extras_require={'certifi': ['certifi']} for pip install nodeenv[certifi]. install_requires stays empty.

Tests - TestCertifi covers the three urlopen branches, make_certifi_context with and without certifi, and that the option reaches Config.

Verification

  • flake8 --extend-ignore=E127 nodeenv.py tests setup.py - clean
  • pytest tests/nodeenv_test.py - 88 passed (the one warning is the pre-existing ssl.PROTOCOL_TLS deprecation in the ignore_ssl_certs path)
  • nodeenv --with-certifi -l with certifi installed - works
  • the same on an interpreter without certifi - warns and continues on the system store
  • with_certifi = True via -C configfile - enables the option

Closes #388

mvdbeek and others added 6 commits August 14, 2026 21:39
We're using nodeenv to set up node on various HPC systems, and we
already use certifi. Tools that use urllib3 work out of the box with
certifi, but for urllib2 this is needed for certifi certificates to be
picked up.
Defaults to not using certifi
--with-certifi asks for a specific trust store, so silently falling
back to the system one leaves the user with an opaque SSL error
instead of "certifi is not installed". Resolve certifi once in main()
and warn there.

Also narrows the try/except to the import only: it used to wrap the
network call as well, so an ImportError raised from inside urlopen
would silently repeat the request without certifi. Building the SSL
context once instead of per request drops the repeated parsing of the
CA bundle.
Every other persistent option is a Config attribute used as the
argparse default, which makes it settable in ~/.nodeenvrc, tox.ini or
setup.cfg and lists it in Config._dump(). with_certifi was hardcoded
to False and so was reachable only from the command line, while a
config default is exactly what a shared machine needs.
Adds the option to the "Other options" section and with_certifi to the
configuration defaults block, which mirrors Config._dump(). Mentions
the SSL_CERT_FILE alternative, which reaches the same result without
the option.
@ekalinin
ekalinin merged commit f1bd387 into master Aug 14, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants