Skip to content

Conversation

@Iamrodos
Copy link
Contributor

certifi is imported as a fallback when system CA certs are empty, but it's not listed in requirements.txt. This causes ModuleNotFoundError for users on systems without proper CA cert configuration (e.g. Codespaces).

https_ctx = ssl.create_default_context()
if not https_ctx.get_ca_certs():
    import warnings
    warnings.warn('\n\nYOUR DEFAULT CA CERTS ARE EMPTY.\n' +
                  'PLEASE POPULATE ANY OF:' +
                  ''.join([
                    '\n - ' + x
                    for x in ssl.get_default_verify_paths()
                    if type(x) is str
                  ]) + '\n', stacklevel=2)
    import certifi
    https_ctx = ssl.create_default_context(cafile=certifi.where())

The dependency was added in commit 548a2ec but never added to the requirements file.

Fixes #444

@josegonzalez
Copy link
Owner

I really dislike this. Because Of Reasons™, I want this package to not have any dependencies.

Can we make the certifi usage optional?

@Iamrodos
Copy link
Contributor Author

I really dislike this. Because Of Reasons™, I want this package to not have any dependencies.

Can we make the certifi usage optional?

Agree. This forced me to dig deeper into the previous issue and resolution that introduced the certifi package. It was a bit naive in its approach so have tweaked.

@Iamrodos Iamrodos changed the title fix: Add certifi to requirements.txt fix: Improve CA certificate detection with fallback chain Nov 16, 2025
@Iamrodos
Copy link
Contributor Author

Ok, all updated. See the commit message for the "story".

Also, I don't like nest if/else blocks but this is the clearest way I could get the logic flow, even though it has pass. Alternative is using not, which I did, but that was harder to follow the logic chain.

Normally if this was in a function I would use early returns so there is no nesting. Trying to keep the changes minimal, this was the best I could come up with.

The previous implementation incorrectly assumed empty get_ca_certs()
meant broken SSL, causing false failures in GitHub Codespaces and other
directory-based cert systems where certificates exist but aren't pre-loaded.
It would then attempt to import certifi as a workaround, but certifi wasn't
listed in requirements.txt, causing the fallback to fail with ImportError
even though the system certificates would have worked fine.

This commit replaces the naive check with a layered fallback approach that
checks multiple certificate sources. First it checks for pre-loaded system
certs (file-based systems). Then it verifies system cert paths exist
(directory-based systems like Ubuntu/Debian/Codespaces). Finally it attempts
to use certifi as an optional fallback only if needed.

This approach eliminates hard dependencies (certifi is now optional), works
in GitHub Codespaces without any setup, and fails gracefully with clear hints
for resolution when SSL is actually broken rather than failing with
ModuleNotFoundError.

Fixes josegonzalez#444
@josegonzalez josegonzalez merged commit 3eae9d7 into josegonzalez:master Nov 16, 2025
10 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.

certifi missing from requirements.txt but imported in code

2 participants