Skip to content

Keep the npm build token out of builder-stage layers#52

Merged
chiro-hiro merged 1 commit into
orochi-network:mainfrom
chiro-hiro:chore/builder-credential-hardening
Jun 4, 2026
Merged

Keep the npm build token out of builder-stage layers#52
chiro-hiro merged 1 commit into
orochi-network:mainfrom
chiro-hiro:chore/builder-credential-hardening

Conversation

@chiro-hiro

Copy link
Copy Markdown
Contributor

Stacked on #51

⚠️ This is stacked on #51 (chore/security-and-extensibility-hardening). Because that branch isn't on the upstream repo yet, this PR is opened against main, so it currently shows #51's commits too. The net-new change is the last commit, 14c81cd. Please merge #51 first (or merge them together); GitHub will collapse this diff once #51 lands.

Problem

In the current template, the npm credentials (.npmrc/.yarnrc.yml) are written in a dedicated builder RUN and never removed, so the token persists in a builder-stage layer and in the builder image filesystem — recoverable by anyone who can pull/run that stage or an exported build cache (--target builder, --cache-to mode=max). The BuildKit secret mount keeps the token out of the build context, but copying it into a real file re-introduces it into a layer.

Fix

Create, use, and delete the credentials inside the single build RUN (under --mount=type=secret,mode=0444), so they only exist for that one layer's execution and leave no trace in the resulting layer:

  • Dockerfile.template — the first builder RUN now only prepares the home/workdir; it no longer writes credentials.
  • dockerfile.sh (generate_build_command) — emits a secret-mounted RUN that writes .npmrc/.yarnrc.yml, runs the build, then rm -fs them. set -e aborts the RUN on build failure, so no partial layer is committed. mode=0444 lets the non-root builder user read the mounted secret.

Credential content and scopes (orochi-network, zkdb) are unchanged, so build behavior is identical for consumers; the secret-mount requirement (BuildKit) is unchanged from the previous template.

Verification

Built the builder stage (--target builder) with a canary secret, old vs new:

Pattern Token in builder image filesystem
Old (main) present in /home/ubuntu/.npmrc
New (this PR) absent

For the new single-RUN pattern, "absent from the final builder filesystem" equals "absent from every layer" by Docker's layer-diff semantics (one RUN creates and deletes the files → the layer diff contains neither).

Enforced in CI: new builder-secret-no-leak job builds the builder stage with a canary secret and fails if the token is found in the builder image. (orochinetwork/ubuntu:node is public, so CI can pull it; the secret is a throwaway literal.)

SECURITY.md updated (no longer a known limitation), CHANGELOG.md updated, checksum.sha256 regenerated.

Previously the credentials (.npmrc/.yarnrc.yml) were written in a dedicated
builder RUN and never removed, so the npm token persisted in a builder-stage
layer and the builder image filesystem (recoverable by anyone who can pull or
run that stage / exported build cache).

Now the credentials are created, used, and deleted inside the single build RUN
(under --mount=type=secret,mode=0444), so they exist only for the duration of
that one layer's execution and are gone from the resulting layer:

- Dockerfile.template: the first builder RUN only prepares the home/workdir; it
  no longer writes credentials.
- dockerfile.sh generate_build_command: emits a secret-mounted RUN that writes
  the .npmrc/.yarnrc.yml, runs the build, and removes them (set -e aborts the
  RUN on build failure, so no layer is committed).

Verified by building the builder stage with a canary secret: the token is
present in the builder image filesystem with the old pattern and absent with the
new one. Enforced going forward by a new CI job (builder-secret-no-leak).

SECURITY.md updated (no longer a known limitation); CHANGELOG updated;
checksum.sha256 regenerated.
@chiro-hiro chiro-hiro force-pushed the chore/builder-credential-hardening branch from 14c81cd to 0271ad9 Compare June 4, 2026 07:43
@chiro-hiro chiro-hiro merged commit 2020f7f into orochi-network:main Jun 4, 2026
4 checks passed
@chiro-hiro chiro-hiro deleted the chore/builder-credential-hardening branch June 4, 2026 07:50
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.

1 participant