SSL / TLS issues
apm install and apm audit reach out to GitHub, GHES, GitLab, Azure DevOps, and package archives over HTTPS. When the system can’t verify the server certificate, the operation fails. This page maps the failure modes to fixes.
Related: environment variables, install failures, security and supply chain, authentication.
Symptoms
Section titled “Symptoms”Typical errors APM surfaces or passes through from the underlying HTTP/git stack:
[!] TLS verification failed -- if you're behind a corporate proxy or firewall, set REQUESTS_CA_BUNDLE to your organisation's CA bundle.SSLError: HTTPSConnectionPool(host='api.github.com', port=443): Max retries exceeded ... [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificatefatal: unable to access 'https://github.example.com/...': SSL certificate problem: self-signed certificate in certificate chainfatal: unable to access '...': server certificate verification failed. CAfile: none CRLfile: noneAll of these mean the same thing: the TLS chain presented by the server can’t be validated against the trust store APM is using.
First diagnostic
Section titled “First diagnostic”Decide which of the three categories you are in before changing anything:
[*] Corporate TLS-intercepting proxy (Zscaler, Netskope, Palo Alto, Cisco Umbrella, Blue Coat). The server cert is re-signed by an internal CA. Affects every HTTPS host. Fix: trust the corporate CA.
[*] Self-hosted server with internal CA (GHES, GitLab self-managed, internal artifact host). Only that one host fails; public hosts like api.github.com work fine. Fix: trust the internal CA, often per-host.
[*] Genuine certificate problem (expired, wrong hostname, broken chain). Reproduce with curl -v https://<host> from the same shell. If curl also fails, the problem is upstream of APM.
Re-run the failing command with --verbose to see the underlying exception and the host that triggered it:
apm install --verboseConfigure trust
Section titled “Configure trust”APM uses requests for HTTP and shells out to git for repository operations. Both honour standard environment variables. Set them at the shell or in your profile (~/.zshrc, ~/.bashrc, or the Windows user environment).
Python HTTP layer
Section titled “Python HTTP layer”export REQUESTS_CA_BUNDLE=/path/to/ca-bundle.pem# or, more general:export SSL_CERT_FILE=/path/to/ca-bundle.pemexport SSL_CERT_DIR=/etc/ssl/certsREQUESTS_CA_BUNDLE wins for requests. SSL_CERT_FILE / SSL_CERT_DIR cover the rest of the Python TLS stack.
Git operations
Section titled “Git operations”export GIT_SSL_CAINFO=/path/to/ca-bundle.pemFor one host only, prefer per-host git config so you don’t widen trust globally:
git config --global http.https://github.example.com/.sslCAInfo /path/to/internal-ca.pemThe trailing slash matters - it scopes the setting to that origin.
Windows (PowerShell)
Section titled “Windows (PowerShell)”$env:REQUESTS_CA_BUNDLE = "C:\certs\corporate-ca.pem"$env:GIT_SSL_CAINFO = "C:\certs\corporate-ca.pem"
# Persist for the current user:[Environment]::SetEnvironmentVariable("REQUESTS_CA_BUNDLE", "C:\certs\corporate-ca.pem", "User")Where do I get the CA file?
Section titled “Where do I get the CA file?”Your IT or platform team owns it. Ask for the PEM bundle for the proxy or internal PKI. Do not export it yourself from a browser unless that is the documented procedure - you may capture an intermediate, not the root.
GHES and GitLab self-managed
Section titled “GHES and GitLab self-managed”Trust alone is not enough for self-hosted forges. APM also needs to know which host to talk to.
GHES:
export GITHUB_HOST=github.example.comexport GITHUB_APM_PAT=<token>export GIT_SSL_CAINFO=/path/to/internal-ca.pemGitLab self-managed:
export GITLAB_HOST=gitlab.example.comexport APM_GITLAB_HOSTS=gitlab.example.com,gitlab-eu.example.comexport GITLAB_APM_PAT=<token>export GIT_SSL_CAINFO=/path/to/internal-ca.pemSee environment variables for the full list and authentication for token scopes.
Proxies
Section titled “Proxies”APM does not implement its own proxy logic. It honours the standard variables, which requests and git both read:
export HTTPS_PROXY=http://proxy.example.com:8080export HTTP_PROXY=http://proxy.example.com:8080export NO_PROXY=localhost,127.0.0.1,.internal.example.comIf the proxy performs TLS interception, you also need the proxy’s signing CA in the trust store - see Configure trust. Importing the CA into the OS trust store (Keychain on macOS, update-ca-certificates on Debian/Ubuntu, update-ca-trust on RHEL, the Trusted Root store on Windows) is the most durable fix; consult your OS documentation rather than copying steps from here.
Verify the fix
Section titled “Verify the fix”# Python sidepython -c "import requests; print(requests.get('https://api.github.com').status_code)"
# Git sideGIT_CURL_VERBOSE=1 git ls-remote https://github.example.com/org/repo.git 2>&1 | grep -i 'ssl\|cert'
# APM end-to-endapm install --verboseA 200 from requests, a successful ls-remote, and a clean install confirm trust is wired through every layer APM uses.
Development-only escape hatches
Section titled “Development-only escape hatches”If you are isolated on a laptop, debugging a local server with a self-signed cert, and you accept the risk:
export GIT_SSL_NO_VERIFY=true # git onlyexport PYTHONHTTPSVERIFY=0 # Python stdlib only; requests ignores thisWhat you lose: any guarantee that the host you reached is the host you intended to reach. Tokens you send may be captured. Packages you download may be tampered with - APM’s built-in security scanning still runs on the bytes received, but it cannot detect substitution upstream of itself.
Unset both as soon as you are done:
unset GIT_SSL_NO_VERIFY PYTHONHTTPSVERIFYStill failing?
Section titled “Still failing?”[>] Re-run with --verbose and capture the full exception chain.
[>] Check curl -v https://<host> from the same shell - if it fails, the problem is the system trust store, not APM.
[>] Confirm REQUESTS_CA_BUNDLE and GIT_SSL_CAINFO point at a readable PEM file (openssl x509 -in $REQUESTS_CA_BUNDLE -noout -subject should print a subject line).
[>] If only one host fails, see GHES and GitLab self-managed and the per-host git config recipe above.
[>] If the install proceeds past TLS but then fails, continue at install failures.