Apply install-script allowlist to Dockerfile npm ci #69

Closed
opened 2026-06-16 12:13:08 +00:00 by james · 0 comments
Owner

Follow-up from #16 (see ADR-0014 "Consequences").

The CI install-script policy from #46 / ADR-0010 blocks lifecycle scripts on every npm ci in .forgejo/workflows/pr.yml and runs only the packages allowlisted in package.json under lavamoat.allowScripts. The RUN npm ci line inside the multi-stage Dockerfile is not covered — lifecycle scripts on the production image build run unrestricted.

A compromised transitive dep that survived the PR-time gates (Renovate quarantine, OSV/Trivy scan, npm audit) could still execute a malicious postinstall during the release image build and bake the result into what self-hosters pull.

Scope

  • Update the Dockerfile deps stage to install with --ignore-scripts then run npx allow-scripts, mirroring the workflow pattern.
  • Make sure the builder and runtime stages don't regress this (today only deps does the install; builder reuses node_modules from deps via COPY --from=deps).
  • The next>sharp, vitest>vite>esbuild, and eslint-config-next>...>unrs-resolver allowlist entries must apply during the Docker build too — verify the npx allow-scripts invocation finds them inside the build container.
  • The lefthook entry in the allowlist is local-dev-only (postinstall short-circuits when CI=true); confirm it doesn't break the Docker build, where neither CI=true nor .git is necessarily present.

Acceptance criteria

  • docker build . produces an image whose runtime layer matches today's image bit-for-bit (modulo the layer that ran the install step), confirming the allowlist correctly ran the needed native-binding scripts and skipped everything else.
  • A purpose-built test (e.g. temporarily injecting a transient postinstall into a leaf dep and confirming the build fails with the allow-scripts "missing configuration" error) demonstrates the gate works inside the container.
  • Dockerfile install policy is documented in docs/ci.md "Install scripts (allowlisted)" — at minimum a sentence saying the same policy now applies to both PR runs and the release build, with the consequence that adding a new install-script dep needs the allowlist update before the next tag.
  • ADR-0010 is amended (or ADR-0014 is updated) to remove the "Dockerfile is exempt" caveat.

Part of epic #2.

Follow-up from #16 (see [ADR-0014](docs/adr/0014-release-pipeline.md) "Consequences"). The CI install-script policy from #46 / [ADR-0010](docs/adr/0010-install-script-allowlist.md) blocks lifecycle scripts on every `npm ci` in `.forgejo/workflows/pr.yml` and runs only the packages allowlisted in `package.json` under `lavamoat.allowScripts`. The `RUN npm ci` line inside the multi-stage `Dockerfile` is **not** covered — lifecycle scripts on the production image build run unrestricted. A compromised transitive dep that survived the PR-time gates (Renovate quarantine, OSV/Trivy scan, npm audit) could still execute a malicious `postinstall` during the release image build and bake the result into what self-hosters pull. ## Scope - Update the `Dockerfile` `deps` stage to install with `--ignore-scripts` then run `npx allow-scripts`, mirroring the workflow pattern. - Make sure the `builder` and `runtime` stages don't regress this (today only `deps` does the install; `builder` reuses `node_modules` from `deps` via `COPY --from=deps`). - The `next>sharp`, `vitest>vite>esbuild`, and `eslint-config-next>...>unrs-resolver` allowlist entries must apply during the Docker build too — verify the `npx allow-scripts` invocation finds them inside the build container. - The `lefthook` entry in the allowlist is local-dev-only (postinstall short-circuits when `CI=true`); confirm it doesn't break the Docker build, where neither `CI=true` nor `.git` is necessarily present. ## Acceptance criteria - [ ] `docker build .` produces an image whose runtime layer matches today's image bit-for-bit (modulo the layer that ran the install step), confirming the allowlist correctly ran the needed native-binding scripts and skipped everything else. - [ ] A purpose-built test (e.g. temporarily injecting a transient `postinstall` into a leaf dep and confirming the build fails with the `allow-scripts` "missing configuration" error) demonstrates the gate works inside the container. - [ ] `Dockerfile` install policy is documented in [`docs/ci.md`](docs/ci.md) "Install scripts (allowlisted)" — at minimum a sentence saying the same policy now applies to both PR runs and the release build, with the consequence that adding a new install-script dep needs the allowlist update before the next tag. - [ ] [ADR-0010](docs/adr/0010-install-script-allowlist.md) is amended (or [ADR-0014](docs/adr/0014-release-pipeline.md) is updated) to remove the "Dockerfile is exempt" caveat. Part of epic #2.
james closed this issue 2026-06-18 01:30:11 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
james/carol#69
No description provided.