fix(docker): install ca-certificates so git can clone over HTTPS
Operator hit "Git clone failed: ... server certificate verification failed. CAfile: none CRLfile: none" the moment they tried to add a project in the container. The runner stage installed git but not ca-certificates, and the slim base ships zero CA certificates (/etc/ssl/certs was empty). git verifies TLS against the SYSTEM trust store, so every HTTPS remote failed and project setup — the first thing anyone does after logging in — was impossible in Docker. It hid because Node carries its OWN bundled CA store: the dashboard, model API calls, and the OAuth token exchanges against platform.claude.com and OpenAI all worked fine, so the image looked healthy right up until the first clone. Nothing else in the image exercises the system trust store, so a guard is added rather than trusting someone to notice next time. Verified in the running container: installing ca-certificates took it from 0 to 301 certs and `git clone https://github.com/Runfusion/Fusion.git` then succeeded as the node user. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
7
.changeset/fix-docker-ca-certificates.md
Normal file
7
.changeset/fix-docker-ca-certificates.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Fix HTTPS git clones failing in Docker with "server certificate verification failed".
|
||||
category: fix
|
||||
dev: The runner stage installed `git` but not `ca-certificates`, and the slim base ships zero CA certificates. git verifies TLS against the SYSTEM trust store, so every HTTPS clone failed and project setup was impossible in a container. It stayed hidden because Node carries its own bundled CA store — the dashboard, model APIs, and OAuth token exchanges all worked. Guarded by a new assertion in scripts/__tests__/dockerfile-workspace-manifests.test.mjs.
|
||||
@@ -68,8 +68,14 @@ LABEL org.opencontainers.image.description="AI-orchestrated task board"
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=4040
|
||||
|
||||
# FNXC:DockerRun 2026-08-18-05:35: ca-certificates is REQUIRED, not optional hardening. The slim
|
||||
# base ships zero CA certificates, and git verifies TLS against the SYSTEM store — so every HTTPS
|
||||
# clone failed with "server certificate verification failed. CAfile: none CRLfile: none", which
|
||||
# breaks project setup outright (operator report). It hid behind Node, which carries its own bundled
|
||||
# CA store: the dashboard, model APIs, and OAuth token exchanges all worked, so the image looked
|
||||
# healthy right up until the first clone.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git \
|
||||
&& apt-get install -y --no-install-recommends git ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN corepack enable && corepack prepare pnpm@10.33.0 --activate
|
||||
|
||||
@@ -102,3 +102,28 @@ test("coverage ignores post-install and runner copies while tolerating removed p
|
||||
"removed or nonexistent COPY paths must not affect selected workspace coverage",
|
||||
);
|
||||
});
|
||||
|
||||
/*
|
||||
FNXC:DockerRun 2026-08-18-05:35:
|
||||
The runner stage MUST install ca-certificates. The slim base ships none, and git verifies TLS
|
||||
against the system store, so without it every HTTPS clone dies with "server certificate
|
||||
verification failed. CAfile: none CRLfile: none" and project setup is impossible in Docker.
|
||||
|
||||
This regressed unnoticed because Node carries its OWN bundled CA store: the dashboard, model APIs
|
||||
and OAuth token exchanges all worked, so nothing looked wrong until the first clone. Nothing else
|
||||
in the image exercises the system trust store, which is exactly why it needs a guard rather than
|
||||
relying on someone noticing.
|
||||
*/
|
||||
test("runner stage installs ca-certificates alongside git", () => {
|
||||
const dockerfile = readFileSync(path.join(repoRoot, "Dockerfile"), "utf8");
|
||||
const runnerStage = dockerfile.slice(dockerfile.indexOf("FROM node:22-slim AS runner"));
|
||||
assert.ok(runnerStage.length > 0, "runner stage must exist");
|
||||
|
||||
const aptInstall = runnerStage.match(/apt-get install[^\n]*(?:\\\n[^\n]*)*/)?.[0] ?? "";
|
||||
assert.match(aptInstall, /\bgit\b/, "runner stage must install git");
|
||||
assert.match(
|
||||
aptInstall,
|
||||
/\bca-certificates\b/,
|
||||
"runner stage must install ca-certificates — git cannot verify HTTPS remotes without a system CA bundle",
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user