fix(pulumi-guard): align the OIDC contract with the retired personal repository - #96
Conversation
…ract v3) Epic #78 C4 deleted kyle-sexton/github-iac and reduced live Pulumi OIDC trust to the single organization rule, so the exact-match v2 contract now fails every production deploy before mutation. Contract v3 carries only the surviving melodic-software/github-iac policy; v2 is removed with the repository it described. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JLfjHY8PY6ozhgZPiuHKik
|
Claude finished @kyle-sexton's task in 1m 33s —— View job PR Review: fix(pulumi-guard): retire the deleted personal-repo OIDC policy (contract v3)Tasks
SummaryThis is a clean, minimal fix. The exact-match guard is working as intended — it correctly failed because the live Pulumi OIDC trust no longer matches the v2 contract. The right response is to advance the reviewed contract (v3), not relax the guard, and that's exactly what this does. OIDC trust surface: 2 allow policies → 1 allow policy. This is the correct direction. Contract JSON (
|
The contract is a living exact-match document; its identity is the stack it guards, not a revision. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JLfjHY8PY6ozhgZPiuHKik
|
Claude finished @kyle-sexton's task in 1m 29s —— View job Tasks
PR Review: fix(pulumi-guard): align the OIDC contract with the retired personal repositoryThis review covers both commits: Contract JSON (
|
| Check | Result |
|---|---|
sub field matches guard.sh derivation formula (repo:${owner}@${ownerId}/${repo}@${repoId}:environment:${env}) |
repo:melodic-software@58273638/github-iac@1277417810:environment:github-iac-production ✓ |
No wildcards in any rule value — test("[*?.]") | not still passes |
✓ |
schemaVersion: 2 (contract file schema, not a revision counter) |
✓ |
actor_id: "153232337" pin preserved — only kyle-sexton's identity can mint the token |
✓ |
run_attempt: "1" constraint preserved (intentional; re-runs fail the OIDC grant) |
✓ |
kyle-sexton/github-iac (deleted repo) entry fully removed |
✓ |
Unversioned naming (the 88eaf4c commit): Renaming from kyle-sexton-github-iac-v3.json → kyle-sexton-github-iac.json is the right call. The file is a living exact-match document — its identity is the stack it guards, not which revision it is. Future OIDC trust changes update this file in-place rather than creating v4, v5, etc. Consumers identify by the unversioned name, so future contract updates won't require caller changes in melodic-software/github-iac.
No orphaned version references remain — confirmed by grepping the full codebase for kyle-sexton-github-iac.
Test Coverage
guard.test.sh — All three name references updated consistently:
line 5: contract path variableline 74:POLICY_CONTRACTenv varline 140: temp-dir mutant contract path for tampered-contract rejection tests
The tampered-contract tests (lines 137–145) still write a mutant file and verify the guard rejects it. 22/22 pass reported ✓
pulumi-deploy-guard.test.cjs — All reductions are correct:
line 25: contract path updated to unversioned name ✓line 89:personalAllowPolicies.length === 1✓lines 96–101: identity map reduced to singlemelodic-software/github-iacentry ✓line 116:actor_idpin still asserted ✓lines 124–126: wildcard-free loop still covers all rule values ✓lines 128–138: finaldeepEqualcorrectly reduced to single repo:id pair ✓
5/5 pass, 0 fail reported ✓
Security
- Trust surface shrinks — this PR cannot escalate privileges
- Fail-closed exact-match guard behavior is fully preserved; only the reviewed contract document moves
- Removing
kyle-sexton/github-iacfrom the OIDC allow set is correct (repo no longer exists) - No workflow files modified — no trigger changes, CLAUDE.md security rules not implicated
Follow-up Confirmation
The downstream consumer (melodic-software/github-iac) must set policy-contract: kyle-sexton-github-iac (the new unversioned name, not kyle-sexton-github-iac-v3 as the earlier review noted) and pin the new guard SHA. PR body confirms this is tracked.
Verdict: Approve. Both commits are correct, minimal, and security-appropriate. The naming refactor is a sound design decision. All test assertions are consistent with the reduced single-policy contract.
There was a problem hiding this comment.
💡 Codex Review
This adds the changed single-policy contract under the unversioned stem kyle-sexton-github-iac, while the action contract I checked (action.yml and guard.sh) still describes policy-contract as a versioned contract name and resolves it directly to contracts/$POLICY_CONTRACT.json. For callers following that documented interface, the old kyle-sexton-github-iac-v2 name was removed and there is no new versioned name such as ...-v3 to pass, so upgrading to this action SHA with the documented naming scheme fails as unknown policy contract (or forces callers onto an undocumented mutable name). Please publish this semantic contract change under a new versioned stem.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ct (#111) ## Why melodic-software/github-iac#112 bumps its `pulumi-version-drift-check.yml` pin to ci-workflows `15aefd8` (the commit whose deploy-guard contract matches post-retirement Pulumi OIDC trust — melodic-software/ci-workflows#96). The runner-policy engine allowlists reusable-workflow contracts by exact `path@SHA`, so the consumer lane rejects the new pin until it is reviewed here (Codex confirmed this on github-iac#112; the Runner policy check fails there today). ## What - `policy.json`: add the `pulumi-version-drift-check.yml@15aefd8` contract (identical shape: hosted-only, `fixedRunsOn: ubuntu-24.04`) - `runner-policy.test.mjs`: assert the new reviewed reference alongside the existing one (same staged-set pattern the selector allowlist already uses) ## Cleanup contract The `@99ac2f8` drift-check entry stays only until github-iac#112 merges; a follow-up removes it the same day — no lingering legacy references. ## Verification - `node --test components/runner-policy/runner-policy.test.mjs`: 101 pass / 0 fail 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JLfjHY8PY6ozhgZPiuHKik Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Why
Production deploys on melodic-software/github-iac fail closed at the deploy guard:
Pulumi personal-token allow policies do not exactly match the reviewed contract(first failure: run 29372145481). Root cause: Epic #78 C4 deletedkyle-sexton/github-iacand reduced live Pulumi OIDC trust to exactly the one organization rule, while the bundled contract still required the deleted repo's policy. Exact-match guard = correct fail-closed behavior; the reviewed contract is what must move.What
contracts/kyle-sexton-github-iac.json: the single survivingmelodic-software/github-iacpolicy (byte-identical rules to the prior org entry); replaceskyle-sexton-github-iac-v2.json— version markers dropped from the contract name, since the contract is a living exact-match document whose identity is the stack it guardsguard.test.sh+pulumi-deploy-guard.test.cjs: repointed to the unversioned contract; content test asserts the single-policy shapeVerification
guard.test.sh: 22/22 PASSnode --test pulumi-deploy-guard.test.cjs: 5 pass / 0 failFollow-up
melodic-software/github-iac PR bumps its pinned guard SHA +
policy-contract: kyle-sexton-github-iac, unblocking the dotfiles-enrollment deploy (#109 merged but unapplied).Closes #85
🤖 Generated with Claude Code
https://claude.ai/code/session_01JLfjHY8PY6ozhgZPiuHKik