π File detail
utils/caCerts.ts
π§© .tsπ 116 linesπΎ 4,401 bytesπ text
β Back to All Filesπ― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes getCACertificates and clearCACertsCache β mainly functions, hooks, or classes. Dependencies touch lodash-es. It composes internal code from debug, envUtils, and fsOperations (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import memoize from 'lodash-es/memoize.js' import { logForDebugging } from './debug.js' import { hasNodeOption } from './envUtils.js' import { getFsImplementation } from './fsOperations.js'
π€ Exports (heuristic)
getCACertificatesclearCACertsCache
π External import roots
Package roots from from "β¦" (relative paths omitted).
lodash-es
π₯οΈ Source preview
import memoize from 'lodash-es/memoize.js'
import { logForDebugging } from './debug.js'
import { hasNodeOption } from './envUtils.js'
import { getFsImplementation } from './fsOperations.js'
/**
* Load CA certificates for TLS connections.
*
* Since setting `ca` on an HTTPS agent replaces the default certificate store,
* we must always include base CAs (either system or bundled Mozilla) when returning.
*
* Returns undefined when no custom CA configuration is needed, allowing the
* runtime's default certificate handling to apply.
*
* Behavior:
* - Neither NODE_EXTRA_CA_CERTS nor --use-system-ca/--use-openssl-ca set: undefined (runtime defaults)
* - NODE_EXTRA_CA_CERTS only: bundled Mozilla CAs + extra cert file contents
* - --use-system-ca or --use-openssl-ca only: system CAs
* - --use-system-ca + NODE_EXTRA_CA_CERTS: system CAs + extra cert file contents
*
* Memoized for performance. Call clearCACertsCache() to invalidate after
* environment variable changes (e.g., after trust dialog applies settings.json).
*
* Reads ONLY `process.env.NODE_EXTRA_CA_CERTS`. `caCertsConfig.ts` populates
* that env var from settings.json at CLI init; this module stays config-free
* so `proxy.ts`/`mtls.ts` don't transitively pull in the command registry.
*/
export const getCACertificates = memoize((): string[] | undefined => {
const useSystemCA =
hasNodeOption('--use-system-ca') || hasNodeOption('--use-openssl-ca')
const extraCertsPath = process.env.NODE_EXTRA_CA_CERTS
logForDebugging(
`CA certs: useSystemCA=${useSystemCA}, extraCertsPath=${extraCertsPath}`,
)
// If neither is set, return undefined (use runtime defaults, no override)
if (!useSystemCA && !extraCertsPath) {
return undefined
}
// Deferred load: Bun's node:tls module eagerly materializes ~150 Mozilla
// root certificates (~750KB heap) on import, even if tls.rootCertificates
// is never accessed. Most users hit the early return above, so we only
// pay this cost when custom CA handling is actually needed.
/* eslint-disable @typescript-eslint/no-require-imports */
const tls = require('tls') as typeof import('tls')
/* eslint-enable @typescript-eslint/no-require-imports */
const certs: string[] = []
if (useSystemCA) {
// Load system CA store (Bun API)
const getCACerts = (
tls as typeof tls & { getCACertificates?: (type: string) => string[] }
).getCACertificates
const systemCAs = getCACerts?.('system')
if (systemCAs && systemCAs.length > 0) {
certs.push(...systemCAs)
logForDebugging(
`CA certs: Loaded ${certs.length} system CA certificates (--use-system-ca)`,
)
} else if (!getCACerts && !extraCertsPath) {
// Under Node.js where getCACertificates doesn't exist and no extra certs,
// return undefined to let Node.js handle --use-system-ca natively.
logForDebugging(
'CA certs: --use-system-ca set but system CA API unavailable, deferring to runtime',
)
return undefined
} else {
// System CA API returned empty or unavailable; fall back to bundled root certs
certs.push(...tls.rootCertificates)
logForDebugging(
`CA certs: Loaded ${certs.length} bundled root certificates as base (--use-system-ca fallback)`,
)
}
} else {
// Must include bundled Mozilla CAs as base since ca replaces defaults
certs.push(...tls.rootCertificates)
logForDebugging(
`CA certs: Loaded ${certs.length} bundled root certificates as base`,
)
}
// Append extra certs from file
if (extraCertsPath) {
try {
const extraCert = getFsImplementation().readFileSync(extraCertsPath, {
encoding: 'utf8',
})
certs.push(extraCert)
logForDebugging(
`CA certs: Appended extra certificates from NODE_EXTRA_CA_CERTS (${extraCertsPath})`,
)
} catch (error) {
logForDebugging(
`CA certs: Failed to read NODE_EXTRA_CA_CERTS file (${extraCertsPath}): ${error}`,
{ level: 'error' },
)
}
}
return certs.length > 0 ? certs : undefined
})
/**
* Clear the CA certificates cache.
* Call this when environment variables that affect CA certs may have changed
* (e.g., NODE_EXTRA_CA_CERTS, NODE_OPTIONS).
*/
export function clearCACertsCache(): void {
getCACertificates.cache.clear?.()
logForDebugging('Cleared CA certificates cache')
}