diff --git a/README.md b/README.md index d18525a4..ea596eca 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,8 @@ The overlay removes the general shell tool for every session, including admins. File tools stay inside the mounted checkout. Two dedicated delivery tools stage explicit paths, run the CI queue guard, push through `git-credential-mosaic`, and open PRs through `pr-create.sh`. They resolve only the `stack-dogfood` slot and fail -if it is absent. +if it is absent. The overlay enables Docker's init process so the R4 helper can +establish the gateway's seat lineage below PID 1. This deployment route is separate from the local source-development restrictions below. diff --git a/docker-compose.dogfood.yml b/docker-compose.dogfood.yml index 266a1dc3..cc08567f 100644 --- a/docker-compose.dogfood.yml +++ b/docker-compose.dogfood.yml @@ -2,6 +2,9 @@ # Use with docker-compose.yml. The base stack remains credential-free. services: gateway: + # The R4 credential helper establishes ownership from process ancestry and + # intentionally does not trust PID 1. Keep gateway Node below Docker's init. + init: true environment: # Identity and credential layout match a fleet seat. This fixed name prevents # an operator from mounting one seat while attributing actions to another. diff --git a/docker/gateway.Dockerfile b/docker/gateway.Dockerfile index 06836050..9a713491 100644 --- a/docker/gateway.Dockerfile +++ b/docker/gateway.Dockerfile @@ -33,7 +33,6 @@ ENV NODE_ENV=production # bash/curl/python3 are runtime dependencies of the provider-neutral Mosaic git # wrappers. jq supports wrapper discovery for non-canonical Gitea hosts. RUN apk add --no-cache bash curl git jq python3 \ - && ln -sf /bin/bash /usr/bin/bash \ && mkdir -p /opt/mosaic/.workspaces \ && chown -R node:node /opt/mosaic /app ENV MOSAIC_ROOT=/opt/mosaic @@ -45,6 +44,11 @@ COPY --from=builder /app/packages/mosaic/framework/tools/git/ci-queue-wait.sh /o COPY --from=builder /app/packages/mosaic/framework/tools/git/detect-platform.sh /opt/mosaic/tools/git/detect-platform.sh COPY --from=builder /app/packages/mosaic/framework/tools/git/repo-decl.sh /opt/mosaic/tools/git/repo-decl.sh COPY --from=builder /app/packages/mosaic/framework/tools/git/git-credential-mosaic /opt/mosaic/tools/git/git-credential-mosaic +# R4 hardening (P0-SEC, brain 15f6979a): the credential helper is a pair. +# python entrypoint (allowlist envp, execve boundary) + the bash implementation +# it execs. The entrypoint derives the .impl path from its own directory, so the +# pair sits side by side; system gitconfig keeps pointing at the entrypoint. +COPY --from=builder /app/packages/mosaic/framework/tools/git/git-credential-mosaic.impl /opt/mosaic/tools/git/git-credential-mosaic.impl COPY --from=builder /app/packages/mosaic/framework/tools/_lib/credentials.sh /opt/mosaic/tools/_lib/credentials.sh COPY --from=builder /app/packages/mosaic/framework/tools/structure/validate-repo-json.sh /opt/mosaic/tools/structure/validate-repo-json.sh RUN git config --system credential.helper /opt/mosaic/tools/git/git-credential-mosaic diff --git a/scripts/verify-dogfood-compose.sh b/scripts/verify-dogfood-compose.sh index 0e34a922..0163decd 100755 --- a/scripts/verify-dogfood-compose.sh +++ b/scripts/verify-dogfood-compose.sh @@ -57,6 +57,7 @@ import os config = json.loads(os.environ["CONFIG_JSON"]) gateway = config["services"]["gateway"] +assert gateway.get("init") is True, "gateway must run below an init process for R4 lineage" env = gateway["environment"] expected_env = {