Repository navigation
Authenticate CI Claude review with an API key in a main-only environment - #968
Merged
seathatflowsinourveins merged 1 commit intoOct 10, 2026
Merged
Conversation
The owner ruled on 2026-10-10 (relayed by the command center, paraphrased) that CI Claude review authenticates with an Anthropic API key, not workload identity federation, which refused every run so far. The key is the environment secret ANTHROPIC_API_KEY of `claude-review`, whose deployment branch policy allows main only, so a workflow pushed on another branch gets no key. claude-pr-review.yml, claude-pr-toolkit-review.yml and harness-audit.yml pass anthropic_api_key from that secret and no federation input. The job that uses the key declares environment: claude-review, and no job holds id-token: write. They pass github_token, so the pinned action (2dca132f) requests no GitHub OIDC token (src/github/token.ts:160-168, base-action/src/workload-identity.ts:43-47). Every other guard is unchanged: dispatch and schedule on main only, the owner and first-attempt guards, the bounds step, the daily ceiling and the read-only tools. The federation exemption and the three id-token write grants leave tests/test_workflow_policy.py. The new tests.test_workflow_hardening.ClaudeApiKeyAuthTests requires the secret once per workflow, the key-using job in the environment, no federation input, no id-token, no pull request trigger, and the secret in no other workflow. It fails on main's workflows and passes here. The decision records and docs/github-automation.md carry the ruling, paraphrased. #961's federation diagnostics record is marked superseded for CI review; its vendor snapshots stay retained and tested, and its two workflow-header tests now require the API-key environment and no federation claim. #961's error_class logic in the three workflows is kept. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
Dependency limit exceeded — report not shown. This pull request scan exceeded the 10,000-dependency limit applied to this scan, so the results are incomplete and may be inaccurate. To avoid reporting false positives, Socket has not posted a report. Upgrade your plan to raise the dependency limit and get complete reports, or view the partial scan in the dashboard. Socket is always free for open source. If this is a non-commercial open source project, contact us to request a free Team account. |
seathatflowsinourveins
marked this pull request as ready for review
October 10, 2026 16:32
seathatflowsinourveins
deleted the
claude/api-actions-ci-api-key-20261010
branch
October 10, 2026 16:44
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 10, 2026
The record's inverse named a SHA that does not exist; #968's merge commit is 9d4c00c (git rev-parse 9d4c00c). The federation note now says the history of those workflows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 10, 2026
The record's inverse named a SHA that does not exist; #968's merge commit is 9d4c00c (git rev-parse 9d4c00c). The federation note now says the history of those workflows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 10, 2026
The record's inverse named a SHA that does not exist; #968's merge commit is 9d4c00c (git rev-parse 9d4c00c). The federation note now says the history of those workflows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 10, 2026
The record's inverse named a SHA that does not exist; #968's merge commit is 9d4c00c (git rev-parse 9d4c00c). The federation note now says the history of those workflows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 11, 2026
… git The GPT read at 13d1eb7 asked, under the correction rule, for: - the upstream sources of the environment reading: GitHub's workflow syntax for jobs.<job_id>.environment (a name, or an object with name and url) and YAML 1.2.2's block and flow mappings, quoted keys and comments, cited with page digests in the record and next to the regression cases; - a regression for the corrected inverse pin: RetirementInversePinTests reads the pin from the record and checks it is #968's merge commit holding the three workflows. It fails on the former SHA (no such commit) and is skipped, with the reason, only outside a worktree or in a shallow clone (CI clones with fetch-depth 0). Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 11, 2026
The record's inverse named a SHA that does not exist; #968's merge commit is 9d4c00c (git rev-parse 9d4c00c). The federation note now says the history of those workflows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 11, 2026
… git The GPT read at 13d1eb7 asked, under the correction rule, for: - the upstream sources of the environment reading: GitHub's workflow syntax for jobs.<job_id>.environment (a name, or an object with name and url) and YAML 1.2.2's block and flow mappings, quoted keys and comments, cited with page digests in the record and next to the regression cases; - a regression for the corrected inverse pin: RetirementInversePinTests reads the pin from the record and checks it is #968's merge commit holding the three workflows. It fails on the former SHA (no such commit) and is skipped, with the reason, only outside a worktree or in a shallow clone (CI clones with fetch-depth 0). Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 11, 2026
The record's inverse named a SHA that does not exist; #968's merge commit is 9d4c00c (git rev-parse 9d4c00c). The federation note now says the history of those workflows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 11, 2026
… git The GPT read at 13d1eb7 asked, under the correction rule, for: - the upstream sources of the environment reading: GitHub's workflow syntax for jobs.<job_id>.environment (a name, or an object with name and url) and YAML 1.2.2's block and flow mappings, quoted keys and comments, cited with page digests in the record and next to the regression cases; - a regression for the corrected inverse pin: RetirementInversePinTests reads the pin from the record and checks it is #968's merge commit holding the three workflows. It fails on the former SHA (no such commit) and is skipped, with the reason, only outside a worktree or in a shallow clone (CI clones with fetch-depth 0). Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 11, 2026
* Retire Claude review inside GitHub; AI reviews run locally The owner decided on 2026-10-10 (about 17:15Z, relayed by the command center) that Claude review no longer runs inside GitHub: AI reviews run on the local host and GitHub enforces the gates. The API refused every request that carried claude-code-action's attribution (CLAUDE_CODE_ENTRYPOINT=claude-code-github-action, base-action/src/parse-sdk-options.ts:284 at 2dca132f) on all five Console keys, while the same keys work from the CLI and the Agent SDK (the command center's correction #141, measured). Removed: claude-pr-review.yml, claude-pr-toolkit-review.yml, harness-audit.yml and their three test modules, their zizmor-coverage entries and their local-pages inventory paths. test_claude_federation_diagnostics keeps its retained-snapshot and decision-claim tests. A new InGitHubClaudeReviewRetiredTests keeps the three files absent and no workflow running the Claude action or naming an Anthropic key. New record docs/decisions/2026-10-10-retire-in-github-claude-review.md (cause, what remains, revisit triggers, inverse); supersession notes in the four claude-actions/federation records and the decision-record index; docs/github-automation.md's current practice. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Pin the repository grant count at 90 after the retirement The three removed workflows were in the local-pages repository grants. At the landing base, main f38116f (93 grants), the test's own derivation (grants.inventory_paths over git ls-files) gives 90 for this branch, equal to the policy's repository grants, and the test pins 90. At the earlier bases eb31d23 and 9d4c00c the same derivation gave 90 and 89. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Take up the command center's notes on the retirement - .github/actions-permissions.json drops anthropics/claude-code-action@* and oven-sh/setup-bun@*: no workflow uses them; a new test keeps every allowed pattern in use, and the record's inverse puts them back. - docs/github-automation.md: the allow-list text, no "harness description", no "still awaits hosted acceptance" clause. - The retirement test catches the claude-review environment in its plain, name: and quoted forms, and reads *.yaml as well. - Record nits: #953 marked open, the check is named sota-sources, and the federation-diagnostics note says the three workflows. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Cite #968's real merge commit in the inverse The record's inverse named a SHA that does not exist; #968's merge commit is 9d4c00c (git rev-parse 9d4c00c). The federation note now says the history of those workflows. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Read each job's environment in the retirement guard The GPT read at 48e4bd3 found three valid YAML forms of the claude-review environment that the regex guard let through: a flow mapping, a quoted name key, and a comment after the key. The guard now reads each job's environment as a scalar or a mapping's name (job_environments), cross-checked against PyYAML when it is installed; all three forms are regressions, each caught here and missed at e46f68e, and actionlint accepts each fixture. The record names the claude-native-practice skill rows as a dated follow-up for cc-native-practice (the command center's ruling at 20:19Z). Co-Authored-By: Claude Opus 5.5 <[email protected]> * Word the skill-row follow-up without the pinned-copy premise The command center's correction #146: no personal copy of claude-native-practice is installed on this host; sessions load the checkout's project skill. The follow-up is now stated neutrally: the skill rows for the retired route are updated in a cc-native-practice pull request, then re-pinned. Co-Authored-By: Claude Opus 5.5 <[email protected]> * State what the environment reading covers, and what PyYAML covers The docstring claimed comments in general; the text reading handles a comment after the key, not a comment line before name: at the job's indentation or a multi-line flow mapping. The PyYAML comparison covers those, and CI runs it (validate run 38084944806, passed, not skipped). The command center's micro at 08a76ab. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Cite the environment forms' sources, and test the inverse pin against git The GPT read at 13d1eb7 asked, under the correction rule, for: - the upstream sources of the environment reading: GitHub's workflow syntax for jobs.<job_id>.environment (a name, or an object with name and url) and YAML 1.2.2's block and flow mappings, quoted keys and comments, cited with page digests in the record and next to the regression cases; - a regression for the corrected inverse pin: RetirementInversePinTests reads the pin from the record and checks it is #968's merge commit holding the three workflows. It fails on the former SHA (no such commit) and is skipped, with the reason, only outside a worktree or in a shallow clone (CI clones with fetch-depth 0). Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 11, 2026
docs/secret-storage.md gains rows for anthropic-api-5 to anthropic-api-10 and a "Key practice (2026-10-10)" section, the repository copy of the command center's record. It covers slot purposes by organization id prefix, one purpose per slot, hidden-prompt storage, per-command use, main-only environment secrets for CI, the health check, tracking, rotation, spend control, and fill-first failover with anthropic-api-3 kept for CI. Owner direction is attributed, not quoted; account names and balances are left out. The no-Admin-API and cache-isolation statements quote Anthropic's Admin API, Usage and Cost API and prompt-caching pages, read 2026-10-10. The gh stdin statement quotes the installed gh 2.102.0 help. The inventory gives anthropic-api-3 its purpose (CI Claude review, the main-only claude-review environment secret) and a rotation step that resets that secret. The notes of anthropic-api-3 and anthropic-api-4 mark "no Anthropic key is stored in GitHub" as superseded under the owner's ruling of 2026-10-10 (PR #968). No other entry changes. The new decision record names the evidence, alternatives, overturn conditions and SOTA sources. As in #930, the harness-defaults correction row now covers every slot, and the five secret-storage line citations in upstream-surface-dispositions.json move by the 122 inserted lines. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 12, 2026
docs/secret-storage.md gains rows for anthropic-api-5 to anthropic-api-10 and a "Key practice (2026-10-10)" section, the repository copy of the command center's record. It covers slot purposes by organization id prefix, one purpose per slot, hidden-prompt storage, per-command use, main-only environment secrets for CI, the health check, tracking, rotation, spend control, and fill-first failover with anthropic-api-3 kept for CI. Owner direction is attributed, not quoted; account names and balances are left out. The no-Admin-API and cache-isolation statements quote Anthropic's Admin API, Usage and Cost API and prompt-caching pages, read 2026-10-10. The gh stdin statement quotes the installed gh 2.102.0 help. The inventory gives anthropic-api-3 its purpose (CI Claude review, the main-only claude-review environment secret) and a rotation step that resets that secret. The notes of anthropic-api-3 and anthropic-api-4 mark "no Anthropic key is stored in GitHub" as superseded under the owner's ruling of 2026-10-10 (PR #968). No other entry changes. The new decision record names the evidence, alternatives, overturn conditions and SOTA sources. As in #930, the harness-defaults correction row now covers every slot, and the five secret-storage line citations in upstream-surface-dispositions.json move by the 122 inserted lines. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 12, 2026
docs/secret-storage.md gains rows for anthropic-api-5 to anthropic-api-10 and a "Key practice (2026-10-10)" section, the repository copy of the command center's record. It covers slot purposes by organization id prefix, one purpose per slot, hidden-prompt storage, per-command use, main-only environment secrets for CI, the health check, tracking, rotation, spend control, and fill-first failover with anthropic-api-3 kept for CI. Owner direction is attributed, not quoted; account names and balances are left out. The no-Admin-API and cache-isolation statements quote Anthropic's Admin API, Usage and Cost API and prompt-caching pages, read 2026-10-10. The gh stdin statement quotes the installed gh 2.102.0 help. The inventory gives anthropic-api-3 its purpose (CI Claude review, the main-only claude-review environment secret) and a rotation step that resets that secret. The notes of anthropic-api-3 and anthropic-api-4 mark "no Anthropic key is stored in GitHub" as superseded under the owner's ruling of 2026-10-10 (PR #968). No other entry changes. The new decision record names the evidence, alternatives, overturn conditions and SOTA sources. As in #930, the harness-defaults correction row now covers every slot, and the five secret-storage line citations in upstream-surface-dispositions.json move by the 122 inserted lines. Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 12, 2026
…ken health check (#969) * Add Anthropic API key slots anthropic-api-5 to anthropic-api-10 Stored through the credential terminal on the owner's direction (2026-10-10). No admin-key slots: every organization behind the stored keys is an individual account, and the Admin API is unavailable for individual accounts (Anthropic docs, read 2026-10-10). Data-only inventory entries; api-actions' PR adds the docs, evidence and tests. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Cover anthropic-api-5 to anthropic-api-10 in the runner tests The six slots added in the previous commit were not in INJECTABLE_IDS, so both inventory-driven set assertions failed at that commit. ANTHROPIC_IDS now lists all ten Anthropic slots; INJECTABLE_IDS and the same-grammar setter/runner test use it, so every slot is written through the hidden-prompt setter and injected through credential_run.py with synthetic values only. Failing-first: with the e1c88ff inventory the three affected tests fail (failures=14, errors=18: the setter and the runner refuse anthropic-api-5..10 as unknown ids, and both id sets differ); with this branch's inventory they pass. The previous commit changed adoption/credential-inventory.json without its evidence binding, so this commit registers it with the test file. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Add a no-token health check for the Anthropic key slots tools/credentials/anthropic_key_health.py ports the command center's anthropic_key_health.sh to the repository. For each anthropic-api slot in inventory order it runs credential_run.py <slot> --check (starts nothing), and for a stored slot runs the probe child through credential_run.py <slot> --only ANTHROPIC_API_KEY. The key reaches only the child's environment; the request headers go to the child as JSON on stdin, so no argv carries a value. The child sends GET /v1/models and GET /v1/organizations/me to the fixed API host, follows no redirect, reads no body, and prints statuses and the first eight characters of the anthropic-organization-id response header. The report never holds a key, an organization name or a response body. The port drops the script's organization-name read and its admin-key probe. HTTP handling follows tools/credentials/alpaca_rate_limit_probe.py; the header and endpoint are documented in the Claude API overview and the Admin API page (read 2026-10-10). Tests use a fake opener, a fake runner, and the real credential_run.py over a temporary store with a synthetic key; no test makes a network call. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Record the Anthropic key slots and the 2026-10-10 key practice docs/secret-storage.md gains rows for anthropic-api-5 to anthropic-api-10 and a "Key practice (2026-10-10)" section, the repository copy of the command center's record. It covers slot purposes by organization id prefix, one purpose per slot, hidden-prompt storage, per-command use, main-only environment secrets for CI, the health check, tracking, rotation, spend control, and fill-first failover with anthropic-api-3 kept for CI. Owner direction is attributed, not quoted; account names and balances are left out. The no-Admin-API and cache-isolation statements quote Anthropic's Admin API, Usage and Cost API and prompt-caching pages, read 2026-10-10. The gh stdin statement quotes the installed gh 2.102.0 help. The inventory gives anthropic-api-3 its purpose (CI Claude review, the main-only claude-review environment secret) and a rotation step that resets that secret. The notes of anthropic-api-3 and anthropic-api-4 mark "no Anthropic key is stored in GitHub" as superseded under the owner's ruling of 2026-10-10 (PR #968). No other entry changes. The new decision record names the evidence, alternatives, overturn conditions and SOTA sources. As in #930, the harness-defaults correction row now covers every slot, and the five secret-storage line citations in upstream-surface-dispositions.json move by the 122 inserted lines. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Apply the owner's revised fill-first order and anthropic-api-3's purpose The owner revised the fill-first order at about 15:12Z on 2026-10-10 (relayed by the command center). The order is now anthropic-api-4, anthropic-api-3, anthropic-api-5, anthropic-api, anthropic-api-2, then anthropic-api-6 to anthropic-api-10 as stored. anthropic-api-3 serves the CI Claude review first and local quality work second; it is no longer kept out of the order. Its key remains the main-only claude-review environment secret. The key practice section, the practice table (anthropic-api-5 now follows anthropic-api-3), the credentials table row, the inventory label and notes of anthropic-api-3, and the decision record follow the revision. The decision record also adds an overturn condition for CI credit drawn down by local work, and corrects the CPython citation range to L623-L656. The five secret-storage line citations in upstream-surface-dispositions.json follow the doc's line count. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Rewrap two key-practice paragraphs Two paragraphs of the key practice section carried uneven line breaks from earlier edits; the text is unchanged. The rewrap removes one line, so the five secret-storage line citations in upstream-surface-dispositions.json move up by one. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Cite the refreshed key-practice record The command center refreshed its record to the 15:12Z fill-first order; the decision cites the new sha256. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Check the inventory first, and fail a probe that failed The co-op's GPT read at 445c61c (2 P2): - slots() now applies scripts/credential_status.py's inventory check, as the credential runner does, and refuses an anthropic-api entry in another shape or an inventory with none: exit 1 before any slot is checked, naming counts and inventory ids only. Before, entries: [] or an entry with no variables gave an empty report and exit 0. - probe_slot() fails a child that exited nonzero or was killed (CompletedProcess.returncode, CPython 3.13.16 Lib/subprocess.py:484) before reading its output, and a line that reports an error is probe_failed whatever status it printed. Before, a 200 line followed by exit 7, a signal, or an error passed with exit 0. - docs/secret-storage.md says so; the catalog's five citations of its later lines move by the four lines added. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]>
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.
Scope
claude-pr-review.yml,claude-pr-toolkit-review.yml,harness-audit.yml) authenticates with an Anthropic API key, the environment secretANTHROPIC_API_KEYof the main-onlyclaude-reviewenvironment, instead of workload identity federation. This follows the owner's ruling of 2026-10-10 (about 13:44Z, relayed by the command center, paraphrased): use the keys; federation stays unconfigured. Its acceptance dispatch, run 38056354892, was refused like the runs of 10-08.e1c88ff3d(main after Fence the headless /skill-doctor run #925).lane:foundation.tests/test_workflow_hardening.py,tests/test_workflow_policy.py,tests/test_claude_pr_review_workflow.py,tests/test_claude_pr_toolkit_review_workflow.py,tests/test_claude_harness_audit_bounds.py,tests/test_claude_federation_diagnostics.py; four decision records;docs/github-automation.md;manifests/evidence.json.What changed:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}and no federation input.environment: claude-review, and no job holdsid-token: write.github_token, so the pinned action requests no GitHub OIDC token.error_classlogic.The secret:
ANTHROPIC_API_KEYholds the inventory entryanthropic-api-3, the cold spare, so CI spend stays separate from the local worker's api-4.credential_run.py, with the value on stdin only. It was first a repository secret (2026-10-10T13:49:43Z), then an environment secret ofclaude-review(2026-10-10T13:55:05Z); the repository copy was deleted.mainonly, the environment holds the secret, and the repository has no secret of that name.Policy and tests:
id-token: writewrite grants leavetests/test_workflow_policy.py.tests.test_workflow_hardening.ClaudeApiKeyAuthTestsrequires:claude-reviewenvironment, and no other job in one;id-tokenand no pull request trigger;SOTA sources
anthropic_api_keyinput with${{ secrets.ANTHROPIC_API_KEY }};id-token: writeneeded for the default GitHub App authentication and for the federation exchange.2dca132ff0e0c4094ce6048b422c6915a071210b(v1.0.247):action.yml:67-89(theanthropic_api_key, federation andgithub_tokeninputs);src/github/token.ts:160-168(no OIDC request whengithub_tokenis given);base-action/src/workload-identity.ts:43-47(federation only when its inputs are set).secrets-outside-envaudit, auditor persona: on main it reports six findings in these three files; here, none.Evidence-class table
claude-reviewenvironment, carry no federation input, hold noid-token, and have no pull request trigger; no other workflow names the secretsynthetictests.test_workflow_hardening.ClaudeApiKeyAuthTests(fails on main's workflows, passes here)github_tokenpassed, the pinned action requests no OIDC tokensource_reviewmainonly and holds the secret; the repository has no secret of that namenative_provengh api repos/…/environments/claude-reviewand its deployment-branch-policies;gh secret list --env claude-review;gh secret list(names and times only, 14:11Z)total_cost_usd> 0, non-emptymodelUsage)Local commands run
Decision record
docs/decisions/2026-10-08-claude-actions-pr-review.md, "Authentication by API key (the owner's ruling, 2026-10-10)". Short dated notes in2026-10-04-ci-least-privilege.md(federation exemption withdrawn),2026-10-08-claude-actions-harness-audit-bounds.md,2026-10-09-claude-actions-pr-toolkit-review.mdand2026-10-10-claude-federation-diagnostics.md.🤖 Generated with Claude Code