Skip to content

fix: Support corporate TLS for Anthropic (NODE_EXTRA_CA_CERTS)#27

Open
petre wants to merge 3 commits into
knostic:release/2026-05-14from
petre:fix/corporate-tls-anthropic
Open

fix: Support corporate TLS for Anthropic (NODE_EXTRA_CA_CERTS)#27
petre wants to merge 3 commits into
knostic:release/2026-05-14from
petre:fix/corporate-tls-anthropic

Conversation

@petre
Copy link
Copy Markdown

@petre petre commented Apr 22, 2026

Summary

OpenAnt’s Python code calls Anthropic over HTTPS. On networks with TLS inspection (e.g. Zscaler), the proxy uses a certificate chain signed by a corporate CA that is not in the default trust store. Node and Claude Code commonly work because operators set NODE_EXTRA_CA_CERTS to a PEM file containing that CA. This PR makes the Anthropic Python client honor the same variable and documents it in the root README.

Changes

  • libs/openant-core/utilities/anthropic_http.py (new): Builds an httpx client for the Anthropic SDK using the Mozilla CA bundle via certifi, then loads NODE_EXTRA_CA_CERTS so trust matches “public CAs + corporate root”.
  • Python 3.13+: Clears VERIFY_X509_STRICT when using the extra PEM so corporate intercept CAs that omit critical Basic Constraints still verify (avoids false failures vs typical Node behavior).
  • Call sites: Anthropic construction goes through create_anthropic_client() so all LLM paths share the same TLS behavior.
  • core/analyzer.py: Fix NameError: define tracker via get_global_tracker() before add_prior_usage when restoring checkpoint usage.
  • core/scanner.py: Report failures log the full exception chain (underlying SSL/connection errors), not only Anthropic’s generic “Connection error.”
  • libs/openant-core/pyproject.toml: Declare certifi explicitly (imported for the trust bundle).
  • README.md: Short NODE_EXTRA_CA_CERTS note for users behind HTTPS inspection.

How to test

Using the openant CLI (typical): configure a key with openant set-api-key …, or pass openant scan --api-key '…'.
Behind TLS inspection: also export NODE_EXTRA_CA_CERTS=/path/to/corporate-root.pem (same PEM many teams use for Node / Claude Code).

@petre petre changed the title Support corporate TLS for Anthropic (NODE_EXTRA_CA_CERTS) fix: Support corporate TLS for Anthropic (NODE_EXTRA_CA_CERTS) Apr 23, 2026
@ar7casper
Copy link
Copy Markdown
Collaborator

Hey @petre — sorry for the silence on this one, you've been waiting way too long for a review on what's actually a clean, well-scoped fix. Apologies.

Reviewed end-to-end, this is good work:

  • Real bug, real users. TLS-intercepting corporate proxies (Zscaler, Netskope, Palo Alto) are an effective wall today — Python's SDK doesn't read OS trust stores, so OpenAnt fails at the first Anthropic call from inside an enterprise network. Nothing to do about it without a fix like this one.
  • Opt-in, no risk to existing users. Nothing fires unless NODE_EXTRA_CA_CERTS is set; default behavior is unchanged.
  • Reuses a Node convention so users with one PEM file can point both runtimes at it — matches Claude Code behavior, easy story to tell.
  • Defensive fallbacks throughout — missing PEM, missing certifi, very old anthropic SDK. All degrade gracefully.
  • Bonus: _format_exception_chain in scanner.py. Surfacing the underlying TLS error that the SDK normally hides under a generic APIConnectionError("Connection error") will save real debugging time. Good catch.

Four small things and we can merge:

1. Add a few tests for anthropic_http.py (the only ask I'd call a blocker)

It's a TLS boundary with zero regression coverage. A future SDK upgrade or an ssl module change could silently break it for the exact users least equipped to debug. Three small tests would lock it down:

  • _ssl_context_from_node_extra_ca_certs() with a self-signed PEM in a tempfile — assert the cert ends up in the context's trust store.
  • create_anthropic_client() with NODE_EXTRA_CA_CERTS set, monkeypatching anthropic.Anthropic to a stub that records kwargs — assert http_client was injected.
  • create_anthropic_client() with the env var unset — assert http_client was NOT injected.

Probably ~50 lines total.

2. Drop or split out the core/analyzer.py change

The tracker = get_global_tracker() addition + downstream rewrite is a benign local-variable refactor with no behavior change, but it's unrelated to TLS. Either lift it into a separate commit so this PR stays single-purpose, or pull it out entirely and we'll take it as a follow-up.

3. Rebase onto current master

The branch is based on d710b90 (pre-release/2026-05-10). Master has moved through PR 56 (Windows compat / CI hardening) and PR 58 is queued. Current CI shows gitleaks failing — likely a stale-base artifact, but a rebase + re-push will clear the signal either way.

4. Document the X.509 tradeoff in the README

Currently the _relax_x509_strict_for_corporate_cas rationale lives only in the module docstring. Worth one line in the README's NODE_EXTRA_CA_CERTS section: "When this is set, Python 3.13+'s strict X.509 validation is relaxed to match Node's behavior, so Zscaler-class CAs (whose Basic Constraints extension is sometimes non-critical) validate." Users opting in to a custom CA should see the tradeoff stated explicitly.

Minor (nice-to-have, won't block)

  • Title could narrow to "for the Anthropic Python SDK" — Node already honors NODE_EXTRA_CA_CERTS natively, so the parser-bootstrap path isn't covered by this PR and the current title can read more broadly than intended.
  • One smart quote in the README (OpenAnt's line) — easy to ASCII-ify.

Address #1-#4 and this is good to merge. Thanks again for the patience and for sticking with it.

Petre Ghita and others added 2 commits May 15, 2026 10:40
Add regression tests for NODE_EXTRA_CA_CERTS, merge README guidance with
upstream Python runtime docs and document the Python 3.13+ X.509 tradeoff,
and drop the analyzer tracker change from the TLS PR per review.

Co-authored-by: Cursor <cursoragent@cursor.com>
@petre petre force-pushed the fix/corporate-tls-anthropic branch from 37c1122 to b7cbbb1 Compare May 15, 2026 08:42
@petre
Copy link
Copy Markdown
Author

petre commented May 15, 2026

Hi @ar7casper Thanks for the suggestions, I have implemented them. Please take a look and let me know if I should I add/remove anything.

@ar7casper ar7casper changed the base branch from master to release/2026-05-14 May 17, 2026 06:42
@ar7casper
Copy link
Copy Markdown
Collaborator

@petre Hey, some tests are failing, could yu take a look please?

report.generator no longer exposes module-level anthropic after TLS
factory wiring; patch create_anthropic_client so tier-2 disclosure tests
keep a stable fake client.

Co-authored-by: Cursor <cursoragent@cursor.com>
@petre
Copy link
Copy Markdown
Author

petre commented May 18, 2026

@petre Hey, some tests are failing, could yu take a look please?

Tests updated

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