Repository navigation
Run container remediation with Pi, without agent write access - #33
Conversation
|
Picked ulziibay-kernel to review: touched the changed code in |
|
Pushed 323f8e6: the job that runs Pi no longer references any GitHub App secret. Every secret a job references stays in runner memory for the whole job, and hosted runners have passwordless sudo. A prompt-injected agent in the old
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 323f8e6. Configure here.

Summary
Moves
container-remediation.ymlfrom Claude Code (claude -p --dangerously-skip-permissions) to Pi, and takes GitHub write credentials away from the agent.Agent invocation
pi --print --no-session --approve --model "$PI_PREFERRED_MODEL" --thinking max @<prompt file>, using Node 22,ANTHROPIC_API_KEY/OPENAI_API_KEY, and thePI_PREFERRED_MODELorg variable (replacesCLAUDE_CODE_PREFERRED_MODEL). The workflow had no model input, so none was added.security-workflows-ref. They are rendered withenvsubstto a file instead of piped.curl. Claude Code had a web-fetch tool; Pi does not.$SCAN_DIR(outside the checkout). The prompt also says the agent has no GitHub credentials and must not commit or push.Credential boundary
Before this change, the fix job minted an App token with no permission limit, wrote it into a global git
insteadOfrewrite, and then ran the agent.go-version-file): if the module needs privategithub.com/kernel/*modules, it mints acontents: readtoken scoped to just those repos, runsgo mod downloadwith an env-only git rewrite, and revokes the token. It checks outmainand uploads only$GOMODCACHE/cache/download/github.com/kernelas a 1-day artifact. Thefixjob builds on that samemainSHA, so the module cache matches the tree the agent edits. This is a separate job because every secret a job references stays readable in runner memory for the whole job, and runners have passwordless sudo, so revoking the minted token before Pi starts would not protect the App key.contents: read; references no secrets exceptANTHROPIC_API_KEYandOPENAI_API_KEY): checks out withpersist-credentials: falseand copies the private-module artifact into its module cache. Public modules download through the proxy as usual.origin/maincommit, committed or not. It keeps onlygo.mod,go.sum, andDockerfile/Dockerfile.*/*.Dockerfile(the oldgit add '*.mod' '*.sum' '*Dockerfile*'set, tightened to basenames). Then it cleans the checkout, re-applies the patch, and runsgo build ./...in each changed module.setup-gocaching is off in both Go jobs, so neither private module sources nor a module cache the agent could have written is saved to the Actions cache.mainSHA and applies the patch. It re-checks the allowlist, rejects non-regular files and addedreplacedirectives, and commits. Only then does it mint a token limited to the calling repo (repositories:comes from$GITHUB_REPOSITORY, because scheduled runs have nogithub.event.repository) withcontents: write+pull-requests: write, to push (--force-with-leaseagainst the branch SHA recorded before Pi ran) and to create or update the PR. It never runs Go, Node, or Pi.Other
trivy-actionis pinned to the currentmastercommit, so the Trivy version does not change.scanandtriageno longer persist the default token.security-workflows-ref: ${{ github.sha }}so it uses the branch's prompts and allowlist instead ofmain's.scripts/test_container_remediation.pyandcontainer-remediation-tests.ymladd credential-boundary regression tests.Callers
kernel/kernelcalls this workflow 5 times withsecrets: inherit, soOPENAI_API_KEYand the App secrets reach it without caller changes. Itscontents: write/pull-requests: writegrants are no longer used by this workflow and could be lowered tocontents: readlater. That is optional; nothing here requires it.Validation
actionlint1.7.12 with shellcheck 0.11.0 on the changed workflows: clean except twoSC2016infos for the single-quotedenvsubstvariable lists, which are intentional and also present onmain.python -m unittest discover -s scripts -p test_container_remediation.py: 17 tests pass. They cover:secrets.*beyond the two model keys (toJSON(secrets)included);github.com/kernelcache subtree (stubbedgo/gh), and the fix job copying it into the module cache;go-modules;fixresetting to thego-modulesmain SHA rather than a newerorigin/main;replace).ADMIN_APP_PRIVATE_KEYortoJSON(secrets)is put back into the fix job, the publish allowlistexit 1or file-modeexit 1is removed,publishgoes back to the default success condition, the allowlist is opened up, the token revoke is removed, the replace check is removed, the pre-agent soft reset is removed, a checkout persists credentials, or a token is passed to the agent step.go-modulessplit).PI_PREFERRED_MODELand wrote a validtriage-result.json(71 findings, 6 actionable groups).go-jose/v3,x/net,grpc, andotel/sdkversions, and the build passed.security/container-remediationand opened security: container vulnerability remediation #32 with the usual assignee and reviewer. I closed security: container vulnerability remediation #32 because it was test output, as security: container vulnerability remediation #15 was.ADMIN_APPreference in the fix job. It opened security: container vulnerability remediation #34, which I closed as test output.github.com/kernel/*dependencies. The firstkernel/kernelapirun will be the first real test of that path. The four callers withoutgo-version-fileskipgo-modules.fixandpublishuse explicit!cancelled()conditions so that skip doesn't cascade, but no live run has exercised that skipped path.Trade-off: the private-module artifact (module zips from repos such as
kernel-images-private) can be downloaded for 1 day by anyone with read access to the calling repo.Not verified: whether the
PI_PREFERRED_MODELvariable and theOPENAI_API_KEYsecret are visible tokernel/kernel(no org admin access). TheREADME.md"Required secrets/variables" section is left as-is because other workflow migrations in this repo touch it.