Skip to content

feat(cli): trust an extra CA bundle in builds and the container - #57

Merged
aledbf merged 3 commits into
mainfrom
ca-bundle
Nov 12, 2026
Merged

aledbf merged 3 commits into
mainfrom
ca-bundle

Conversation

@aledbf

@aledbf aledbf commented Nov 12, 2026

Copy link
Copy Markdown
Member

--ca-bundle <file> on build, up and run-user-commands, plus the tests #50 asks for around secrets on tmpfs.

Closes #50

Builds

  • Every Feature install RUN mounts the bundle as the BuildKit secret devcontainer-ca-bundle at /run/devcontainer/ca-bundle.crt. install.sh runs with SSL_CERT_FILE, NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE and GIT_SSL_CAINFO pointing at it, and the variables apply to that RUN only, never as an ENV.
  • A user Dockerfile gets the same secret id (--secret id=devcontainer-ca-bundle,src=<file>) and opts in with RUN --mount=type=secret,.... This is documented in docs/go-only-features.md.
  • Without buildx the bundle is left out of the build with a warning, as --secrets-file is. A Compose configuration's docker compose build takes no secrets, so it also gets a warning.

Container

  • up bind-mounts the file read-only at the same path and sets the five variables over the configuration's containerEnv. This covers both single containers and Compose services.
  • run-user-commands sets the variables for the lifecycle commands. A container created without the mount is refused, because a running container cannot take a new mount.

Never copied

  • The e2e test scans the layers and config of the built image (history and labels included) for the CA's body and for the file. It finds neither.
  • A rebuild with a different CA's bundle passes only from cache and produces the same layers.
  • One thing does change: a build with the flag differs from one without it in the Feature RUN text (the secret mount and the variables), so those two builds don't share cache.

Also in this change

  • up --secrets-file now reaches the user Dockerfile's RUNs. It reached only the Features' before, which contradicted the issue's item 3.
  • Tests for DOCKER_CONFIG outside $HOME with a symlinked config.json, and for the bridged build auth being written under TMPDIR (documented).
  • The flag is in the flag inventory and in DIVERGENCES.

Tests

  • Unit: the generated Feature RUNs, buildx file secrets, flag validation (a file with no PEM certificate is refused), the env merge, the Compose override and its warning, DOCKER_CONFIG off $HOME.
  • e2e, against a real TLS server container signed by a test CA:
    • TestE2E_CABundle: a Feature RUN and an opted-in Dockerfile RUN fail without the flag and pass with it. In the container, curl, node and postCreateCommand trust the server. The mount is read-only. run-user-commands is refused on a container without the bundle.
    • TestE2E_UpSecretsFile: the value reaches a Dockerfile RUN and postCreateCommand, and it is absent from the layers, docker history and the container's inspect.

🤖 Generated with Claude Code

aledbf and others added 3 commits November 12, 2026 16:35
--ca-bundle <file> on build, up and run-user-commands takes a PEM
bundle (the system CAs plus a TLS-intercepting proxy's). Every Feature
install RUN mounts it as the BuildKit secret devcontainer-ca-bundle at
/run/devcontainer/ca-bundle.crt and runs install.sh with SSL_CERT_FILE,
NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE and
GIT_SSL_CAINFO pointing at it, for that RUN only. A user Dockerfile is
given the same secret id and opts in with RUN --mount. up binds the file
read-only at the same path and sets the variables in the container's
environment; run-user-commands sets them for the lifecycle commands and
refuses a container created without the mount.

The bundle is mounted, never copied: no layer, config or history holds
it, and its content is outside the cache key, so a rotated CA reuses the
cache and builds the same layers. Without buildx it is left out of
builds with a warning; a Compose configuration's build takes no
secrets, so only its container gets the bundle.

up --secrets-file now reaches the Dockerfile's own RUNs too, as build
does; it reached only the Features' before. Tests hold a DOCKER_CONFIG
off $HOME behind a symlink, and the bridged build auth under TMPDIR,
which the docs now say.

Closes #50

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The server container ran with --rm and its address came from the
bridge network by name, with docker inspect's stderr discarded: on
CI the lookup failed with a bare "exit status 1". Keep the container
until cleanup, read the address from whatever network it is on, and
report the inspect output, the container's state and its logs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
docker run's stderr carries the image pull's progress when the base
image is not cached, as on CI; combined with stdout it became part of
the container id, and every later docker call on that id failed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@aledbf
aledbf merged commit c890877 into main Nov 12, 2026
3 checks passed
@aledbf
aledbf deleted the ca-bundle branch November 12, 2026 20:00
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.

Extra CA bundle in builds and containers; tests for secrets on tmpfs (Spinbox integration)

1 participant