chore(sync): develop → main — chart/image uid guard - #428
Merged
Conversation
The MCP chart pinned `runAsUser: 1000` against an image that creates
`evolith` at 1001 and chowns the corpus to it. A securityContext
overrides the image's USER, so the process landed on the base image's
`node` user: `policy.wasm` is mode 600 owned by 1001, OPA got EACCES,
dispatch requires both engines to allow, and every `tools/call` returned
FORBIDDEN — 51 tools advertised, none executable.
That value is correct today because it was corrected by hand two days
ago, and nothing was watching it. This is the part that replaces the
hand: a hand-corrected value with no guard is one edit from the same
outage, and the next person to meet it meets it in a cluster.
Nothing here could have caught it before. The test harness runs the MCP
server IN-PROCESS — no container, no securityContext — so the defect was
unreachable from every suite in the repository and only a live deploy
showed it.
All four pinned fields are compared, not just `runAsUser`: `runAsGroup`
and `fsGroup` too, because getting three right and one wrong reproduces
the same failure through a different door — `fsGroup` alone decides who
owns mounted volumes. A chart pinning NOTHING is reported rather than
passed: it inherits the image's USER, which is right today and unanchored
tomorrow.
Watched failing, not declared able to:
- reintroducing the exact 1000/1001 shape → 2 divergences, exit 1;
- moving ONLY fsGroup → 1 divergence, exit 1;
- 10 unit tests over the predicate, including a green case so a
reject-everything predicate cannot masquerade as thorough.
The first version failed for its own reason and not the repository's: its
`adduser` regex required every token before `-u` to be a flag, but the
username is POSITIONAL (`adduser -S evolith -u 1001 -G evolith`), so it
read all three real Dockerfiles as unparseable. Caught by running it; the
shape is pinned by a test.
Guards: 42 classifies it (74 total, none unprotected), 43 sees it turn
red on the empty fixture (50/50), governance suite 17/17, gitleaks clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📊 Bilingual Coverage ImpactPR Changes
Repository Coverage
✅ Good: All EN changes have ES counterparts. Generated by GitHub Actions |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings #427 to
main. A chart'ssecurityContextoverrides the image'sUSER, so a chart pinning a uid the image does not own files as puts the process on a user that can read none of its corpus.The MCP chart shipped
1000against an image built at1001:policy.wasmis mode 600, OPA gotEACCES, dispatch fail-closed, and everytools/callreturned FORBIDDEN — 51 tools advertised, none executable. That value was corrected by hand two days ago with nothing watching it; this is what replaces the hand.Nothing in the repository could have caught it: the harness runs the MCP server in-process, with no container and no securityContext.
Watched failing: the exact 1000/1001 shape → exit 1;
fsGroupalone → exit 1; 10 unit tests over the predicate. Confirmed running on the runner, not only locally (pairs checked ... 3).🤖 Generated with Claude Code