fix(wif): preserve GitHub canonical case in attributeCondition and IAM principals - #3692
Conversation
…M principals The WIF provisioner lowercased org/repo names before substituting them into CEL attributeCondition literals and IAM principalSet paths. Since GitHub's OIDC token preserves canonical case and Google STS compares claims byte-for-byte, any org/repo with uppercase letters permanently failed authentication with "unauthorized_client". Separate case-insensitive dedup (for internal bookkeeping, provider ID generation) from the values written into security-critical CEL conditions and IAM principal paths — those now preserve the original case. Fixes: #3678 Assisted-by: Claude Signed-off-by: Wayne Sun <gsun@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 5:23 PM UTC · Completed 5:38 PM UTC |
PR Summary by QodoFix WIF: preserve GitHub canonical case in CEL conditions and IAM principals
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Site previewPreview: https://e5e040af-site.fullsend-ai.workers.dev Commit: |
Code Review by Qodo
Context used✅ Tickets:
🎫 WIF attributeCondition forces lowercase org/repo, rejecting auth for mixed-case GitHub orgs✅ Compliance rules (platform):
54 rules✅ Skills:
writing-user-docs, writing-adrs 1. EnsureOrg flips existing case
|
ReviewOutcome: Approve Re-review: Head advanced from SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Incremental Change (commit 4)Commit
Reviewed Dimensions
Previous runReviewOutcome: Approve Re-review: Head advanced from SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Incremental Change (commit 3)Commit
Reviewed Dimensions
Previous runReviewOutcome: Approve Re-review: Head advanced from SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Incremental ChangeThe new commit ( Reviewed Dimensions
Test AssessmentThe prior review's low finding has been fully addressed. Test coverage now includes: case preservation for org-scoped and repo-scoped provisioning, case-insensitive merge dedup, case-insensitive removal, provider ID lowering, and the re-enrollment precedence scenario. The test suite exercises the critical invariants that the provider ID remains lowered (GCP requirement) while CEL conditions and IAM bindings preserve canonical case (GitHub OIDC requirement). Previous runReviewOutcome: Approve SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Reviewed Dimensions
Findings[low] Merge precedence during re-enrollment could cause condition case change — In Test AssessmentTest coverage is strong: 7 tests updated or added covering case preservation for org-scoped, repo-scoped, merge dedup, case-insensitive removal, and provider ID lowering. The test Labels: PR modifies WIF provisioning in the dispatch component Labels: PR modifies WIF provisioning across dispatch, CLI mint, and CLI inference components Labels: PR modifies CLI mint enrollment and inference dry-run paths alongside dispatch WIF provisioning Previous runReviewOutcome: Approve Re-review: Head advanced from SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Incremental Change (commit 3)Commit
Reviewed Dimensions
Labels: PR modifies WIF provisioning across dispatch and CLI mint components Previous run (2)ReviewOutcome: Approve Re-review: Head advanced from SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Incremental ChangeThe new commit ( Reviewed Dimensions
Test AssessmentThe prior review's low finding has been fully addressed. Test coverage now includes: case preservation for org-scoped and repo-scoped provisioning, case-insensitive merge dedup, case-insensitive removal, provider ID lowering, and the re-enrollment precedence scenario. The test suite exercises the critical invariants that the provider ID remains lowered (GCP requirement) while CEL conditions and IAM bindings preserve canonical case (GitHub OIDC requirement). Previous runReviewOutcome: Approve SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Reviewed Dimensions
Findings[low] Merge precedence during re-enrollment could cause condition case change — In Test AssessmentTest coverage is strong: 7 tests updated or added covering case preservation for org-scoped, repo-scoped, merge dedup, case-insensitive removal, and provider ID lowering. The test Labels: PR modifies WIF provisioning in the dispatch component Previous run (3)ReviewOutcome: Approve Re-review: Head advanced from SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Incremental ChangeThe new commit ( Reviewed Dimensions
Test AssessmentThe prior review's low finding has been fully addressed. Test coverage now includes: case preservation for org-scoped and repo-scoped provisioning, case-insensitive merge dedup, case-insensitive removal, provider ID lowering, and the re-enrollment precedence scenario. The test suite exercises the critical invariants that the provider ID remains lowered (GCP requirement) while CEL conditions and IAM bindings preserve canonical case (GitHub OIDC requirement). Previous run (4)ReviewOutcome: Approve SummaryThis PR fixes a genuine authentication bug (#3678) where the WIF provisioner lowercased org/repo names before substituting them into CEL The fix correctly separates two concerns:
Reviewed Dimensions
Findings[low] Merge precedence during re-enrollment could cause condition case change — In Test AssessmentTest coverage is strong: 7 tests updated or added covering case preservation for org-scoped, repo-scoped, merge dedup, case-insensitive removal, and provider ID lowering. The test Labels: PR modifies WIF provisioning in the dispatch component |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Add TestEnsureOrgInWIFCondition_ReEnrollmentInstallingCaseWins covering the case where an org re-enrolls with different casing than the existing WIF condition — verifies the installing org's case replaces the existing one, per review feedback on #3692. Signed-off-by: Wayne Sun <gsun@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 7:50 PM UTC · Completed 7:57 PM UTC |
ralphbean
left a comment
There was a problem hiding this comment.
LGTM. One non-blocking note inline.
runMintEnrollOrg and runMintUnenrollOrg lowercased the org name before calling EnsureOrgInWIFCondition/RemoveOrgFromWIFCondition, silently discarding the canonical case those functions were fixed to preserve. `fullsend mint enroll AcmeCorp` still wrote `acmecorp` into the attributeCondition, which fails GitHub OIDC's byte-for-byte claim match for mixed-case orgs. Keep the lowercased org for ALLOWED_ORGS env var bookkeeping, but pass the original-case org to the WIF condition calls. Assisted-by: Claude Signed-off-by: Wayne Sun <gsun@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 1:34 PM UTC · Completed 1:45 PM UTC |
…views runMintEnrollRepo lowercased repoFullName before it reached ProvisionWIF, so the per-repo attributeCondition and IAM principalSet still got a lowercased owner/repo, reproducing the byte-for-byte STS mismatch this PR fixes -- just via the repo-enroll CLI path instead of the org path. Keep the lowered value for PER_REPO_WIF_REPOS bookkeeping, but pass the original-case repo to ProvisionWIF via gcf.Config.Repo. Also fix two dry-run previews (mint enroll --dry-run, inference provision --dry-run) that printed a lowercased condition even though the real provisioning call now preserves case, which would mislead an operator reviewing the preview before approving a security-sensitive WIF change. Add gcf.LastWIFProviderCondition test helper and regression tests covering the repo-enroll case-preservation and dry-run preview text. Assisted-by: Claude, Gemini Signed-off-by: Wayne Sun <gsun@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 2:11 PM UTC · Completed 2:23 PM UTC |
|
🤖 Finished Retro · ✅ Success · Started 2:29 PM UTC · Completed 2:36 PM UTC |
|
PR #3692 fixed a WIF authentication bug where case-preserving org/repo names in CEL conditions were defeated by pre-lowercasing in CLI callers. The review agent approved the initial fix but missed that CLI callers ( Proposals filed
|
Summary
Fixes #3678 — WIF
attributeConditionforces lowercase org/repo, rejecting auth for mixed-case GitHub orgs.The WIF provisioner lowercased org/repo names before substituting them into CEL
attributeConditionliterals and IAMprincipalSetpaths. Since GitHub's OIDC token preserves canonical case and Google STS compares claims byte-for-byte, any org/repo with uppercase letters (e.g.RHEcosystemAppEng/sdlc-plugins) permanently failed authentication withunauthorized_client: The given credential is rejected by the attribute condition.Changes
parseConditionOrgs— preserves case from existing CEL conditions instead of lowercasingensureWIFPoolAndProvider— case-insensitive dedup using lowered map keys, preserving canonical-case values; installing orgs take precedence when casing differsProvisionWIFrepo path — split intoparts(original case for CEL/IAM) andpartsLower(forBuildRepoProviderIDand validation)ProvisionWIForg path — preserves original case inorgsslice while deduping case-insensitivelyEnsureOrgInWIFCondition— case-insensitive dedup preserving canonical caseRemoveOrgFromWIFCondition— usesstrings.EqualFoldfor case-insensitive matchingstrings.ToLowersinceattribute.repositorymaps directly from the assertion without normalizationProvision— stopped mutatingp.cfg.GitHubOrgsentries to lowercaseWhat stays lowered (correct behavior)
BuildRepoProviderID— GCP resource IDs require lowercaseEnsureOrgInMint/RegisterPerRepoWIF— env var bookkeeping (ALLOWED_ORGS,PER_REPO_WIF_REPOS)RemoveOrgFromMint/RemoveRepoFromMint— env var bookkeepingTest plan
TestProvisionWIF_PreservesOrgCase— condition preserves original caseTestProvisionWIF_RepoScoped_PreservesRepoCase— condition and IAM binding preserve case, provider ID still loweredTestParseConditionOrgs— mixed case preserved in parsed outputTestEnsureOrgInWIFCondition_AddsOrgAndStripsPlaceholder— preserves caseTestProvisionWIF_OrgScoped_PreservesOrgCase— mixed-case org in condition and IAMTestProvisionWIF_OrgScoped_MergeDedupsCase— installing org case wins on mergeTestRemoveOrgFromWIFCondition_CaseInsensitiveMatch— removes by case-insensitive matchgo test ./internal/dispatch/gcf/passesgo vetclean