feat(ca): trust package-cache frontend CA in build containers

The package-cache frontend MITMs the registry with a cert signed by an
independent CA, not the stack root CA. Wire that extra CA into all three
container entry points so npm traffic through the cache validates. Gated
on the CA file existing, so it is a no-op when the cache is inactive.

- container.py: mount the frontend CA and set CA_TRUST_CERT_EXTRA in the
  container-run wrapper
- with-ca-trust.sh: consume CA_TRUST_CERT_EXTRA (combined bundle for
  single-file readers plus a separate OS trust anchor)
- compose_ca.py: compose and swarm side injection (env-only when unwrapped)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 4.8 committed 2026-07-24 15:22:35 +02:00
1 parent 0a3570ecea
commit e79183f96a
3 files changed
+61 -35

No files matched your search

+22 -27
View File
@@ -26,7 +26,6 @@ if [ ! -r "$CA_TRUST_CERT" ]; then
exit 2
fi
# Sanitize trust name
name="$(printf '%s' "$CA_TRUST_NAME" | tr -c 'A-Za-z0-9._-' '_' )"
if [ -z "$name" ]; then
echo "[with-ca-trust] ERROR: CA_TRUST_NAME resolved to empty after sanitization" >&2
@@ -37,13 +36,21 @@ log "Sanitized trust name: $name"
installed=0
# Always provide env-based trust hints as a fallback (works for many TLS stacks)
export SSL_CERT_FILE="$CA_TRUST_CERT"
export REQUESTS_CA_BUNDLE="$CA_TRUST_CERT"
export CURL_CA_BUNDLE="$CA_TRUST_CERT"
# Optional (harmless if unused; helps Node-based tools if any)
export NODE_EXTRA_CA_CERTS="$CA_TRUST_CERT"
if [ -n "${CA_TRUST_CERT_EXTRA:-}" ] && [ -r "${CA_TRUST_CERT_EXTRA}" ]; then
combined="/tmp/infinito/ca-trust-combined.crt"
mkdir -p "$(dirname "$combined")"
cat "$CA_TRUST_CERT" "$CA_TRUST_CERT_EXTRA" > "$combined"
export SSL_CERT_FILE="$combined"
export REQUESTS_CA_BUNDLE="$combined"
export CURL_CA_BUNDLE="$combined"
export NODE_EXTRA_CA_CERTS="$combined"
fi
install_anchor() {
src="$1"
dst="$2"
@@ -58,9 +65,6 @@ install_anchor() {
return 1
}
#
# Debian / Ubuntu style
#
if command -v update-ca-certificates >/dev/null 2>&1; then
log "Detected update-ca-certificates"
if install_anchor "$CA_TRUST_CERT" "/usr/local/share/ca-certificates/${name}.crt"; then
@@ -68,9 +72,6 @@ if command -v update-ca-certificates >/dev/null 2>&1; then
fi
fi
#
# RHEL / p11-kit style
#
if command -v update-ca-trust >/dev/null 2>&1; then
log "Detected update-ca-trust"
if install_anchor "$CA_TRUST_CERT" "/etc/pki/ca-trust/source/anchors/${name}.crt"; then
@@ -78,9 +79,6 @@ if command -v update-ca-trust >/dev/null 2>&1; then
fi
fi
#
# Arch / pure p11-kit style
#
if command -v trust >/dev/null 2>&1; then
log "Detected trust"
if install_anchor "$CA_TRUST_CERT" "/etc/ca-certificates/trust-source/anchors/${name}.crt"; then
@@ -88,18 +86,19 @@ if command -v trust >/dev/null 2>&1; then
fi
fi
# ------------------------------------------------------------
# Chromium / NSS trust (per-user DB)
#
# Puppeteer/Chromium often uses NSS trust DB and may ignore OS CA store.
# Import the CA into the user's NSS DB if certutil is available.
#
# Requires:
# - Debian/Ubuntu: apt-get install libnss3-tools
# - Alpine: apk add nss-tools
# ------------------------------------------------------------
if [ -n "${CA_TRUST_CERT_EXTRA:-}" ] && [ -r "${CA_TRUST_CERT_EXTRA}" ]; then
if command -v update-ca-certificates >/dev/null 2>&1 && install_anchor "$CA_TRUST_CERT_EXTRA" "/usr/local/share/ca-certificates/${name}-extra.crt"; then
run update-ca-certificates || true
fi
if command -v update-ca-trust >/dev/null 2>&1 && install_anchor "$CA_TRUST_CERT_EXTRA" "/etc/pki/ca-trust/source/anchors/${name}-extra.crt"; then
run update-ca-trust extract || true
fi
if command -v trust >/dev/null 2>&1 && install_anchor "$CA_TRUST_CERT_EXTRA" "/etc/ca-certificates/trust-source/anchors/${name}-extra.crt"; then
run trust extract-compat || true
fi
fi
if command -v certutil >/dev/null 2>&1; then
# Prefer real HOME; fall back to a writable temp dir
home_dir="${HOME:-}"
if [ -z "$home_dir" ] || [ ! -d "$home_dir" ] || [ ! -w "$home_dir" ]; then
home_dir="/tmp"
@@ -108,18 +107,14 @@ if command -v certutil >/dev/null 2>&1; then
nss_db="${home_dir}/.pki/nssdb"
log "Detected certutil; importing CA into NSS DB: ${nss_db}"
# Ensure directory exists
run mkdir -p "$nss_db" 2>/dev/null || true
# Create NSS DB if missing (empty password)
if [ ! -f "$nss_db/cert9.db" ]; then
run certutil -N -d "sql:${nss_db}" --empty-password 2>/dev/null || true
fi
# Remove existing cert entry (best-effort)
run certutil -D -d "sql:${nss_db}" -n "$name" >/dev/null 2>&1 || true
# Import as trusted CA (C,, = trusted CA for SSL)
run certutil -A -d "sql:${nss_db}" -n "$name" -t "C,," -i "$CA_TRUST_CERT" 2>/dev/null || true
log "NSS trust import attempted (best-effort)"
+25 -8
View File
@@ -502,6 +502,16 @@ def _load_services_via_config(
return services
def _cache_frontend_ca_host() -> str:
"""Runner-internal path to the package-cache frontend CA, or '' when the cache is inactive."""
path = os.environ.get(
"CA_TRUST_CERT_EXTRA_HOST", "/opt/package-frontend-ca.crt"
).strip()
if path and Path(path).is_file() and Path(path).stat().st_size > 0:
return path
return ""
def render_override(
services: dict[str, Any],
service_to_compose_cmd: dict[str, list[str]],
@@ -537,6 +547,7 @@ def render_override(
We escape any $ in the command argv with $$ so container-side expansion works.
"""
out_services: dict[str, Any] = {}
extra_ca_host = _cache_frontend_ca_host()
image_meta = gather_image_meta(
sorted(
@@ -563,16 +574,22 @@ def render_override(
if php_ini_host and php_ini_container:
volumes.append(f"{php_ini_host}:{php_ini_container}:ro")
environment: dict[str, str] = {
"CA_TRUST_CERT": ca_container,
"CA_TRUST_NAME": trust_name,
"SSL_CERT_FILE": ca_container,
"REQUESTS_CA_BUNDLE": ca_container,
"CURL_CA_BUNDLE": ca_container,
"NODE_EXTRA_CA_CERTS": ca_container,
}
if extra_ca_host:
extra_ca_container = str(Path(ca_container).parent / "ca-trust-extra.crt")
volumes.append(f"{extra_ca_host}:{extra_ca_container}:ro")
environment["CA_TRUST_CERT_EXTRA"] = extra_ca_container
override_svc: dict[str, Any] = {
"volumes": volumes,
"environment": {
"CA_TRUST_CERT": ca_container,
"CA_TRUST_NAME": trust_name,
"SSL_CERT_FILE": ca_container,
"REQUESTS_CA_BUNDLE": ca_container,
"CURL_CA_BUNDLE": ca_container,
"NODE_EXTRA_CA_CERTS": ca_container,
},
"environment": environment,
}
if not wrap:
@@ -341,10 +341,24 @@ def container_run(argv: list[str], debug: bool, with_ca: bool) -> int:
"--entrypoint",
wrapper_container,
]
extra_opts: list[str] = []
extra_host = os.environ.get(
"CA_TRUST_CERT_EXTRA_HOST", "/opt/package-frontend-ca.crt"
).strip()
extra_path = Path(extra_host) if extra_host else None
if extra_path and extra_path.is_file() and extra_path.stat().st_size > 0:
extra_container = str(Path(ca_container).parent / "ca-trust-extra.crt")
extra_opts = [
"-v",
f"{extra_host}:{extra_container}:ro",
"-e",
f"CA_TRUST_CERT_EXTRA={extra_container}",
]
final_cmd: list[str] = ["docker", "run"]
final_cmd.extend(run_opts)
final_cmd.extend(inject_opts)
final_cmd.extend(extra_opts)
final_cmd.append(image)
if user_entrypoint: