You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
sec(cli): the GCP setup wizard grants roles/compute.admin at project scope #1946
Step 4 of cudly configure-gcp grants the CUDly service account roles/compute.admin at project scope, and the prompt treats empty input as Run. The next steps mint a long-lived JSON key for that identity and upload it to AWS Secrets Manager. That role confers full control of Compute Engine, including deleting VMs, disks, images, firewall rules and networks, where CUDly needs to read usage and buy committed use discounts. The project's own IAM policy names this role as the anti-pattern to avoid.
Step 4 of cudly configure-gcp grants the CUDly service account roles/compute.admin on the operator's project, then Step 5 mints a long-lived JSON key for it and Step 6 uploads that key to AWS Secrets Manager. compute.admin confers full control of every Compute Engine resource: creating and deleting VMs, disks, images, firewall rules and networks. CUDly needs to read usage and purchase committed use discounts. Anyone who obtains the stored key can delete the project's production infrastructure. The project's own IAM policy in CLAUDE.md names this exact role as the anti-pattern ("Prefer custom roles ... over broad predefined roles like roles/compute.admin"), and the prompt defaults to Run on empty input.
Evidence
member:=fmt.Sprintf("serviceAccount:%s", saEmail)
role:="roles/compute.admin"...fmt.Printf("[R]un, [S]kip? (grants %s to %s on project %s via SDK) ", role, saEmail, projectID)
Suggested fix
Grant the narrowest predefined pair the CUD flow needs (roles/compute.viewer plus the commitment-purchase permissions) or provision a google_project_iam_custom_role holding only compute.commitments.* and the usage reads, matching the runtime-permissions rule in CLAUDE.md.
Found by the 2026-09-02 codebase audit, finding A10-018, reported by one reviewer and independently confirmed by a second. Full report: docs/audits/codebase-audit-2026-09-02.md.
Post-merge verification for #2122 completed on actual merge commit 76d1d4e72f13731ba071c7932f8e7e233cb4f6c6.
The merged tree is exactly identical to independently reviewed 1272e721b8d5185634840c9aa9fc7698dd7cb124: both tree IDs are 8736682a2fcc3ac7ff52b0187e696be35a82ddec.
Checked out the merge commit and ran GOWORK=off GOTOOLCHAIN=go1.26.6 go test -race ./cmd -run 'TestGCPStepGrantRole|TestAddMemberToPolicyBinding' -count=1: exit 0, 26.461 seconds.
This covers the actual wizard coordinator and Google SDK request path against local HTTP fixtures, including preserved conditional and existing broad grants, unsafe custom-role rejection, and failures before key minting. The independent pre-merge overlay also proved the unchanged regression fails on the original Compute Admin policy request.
No real IAM mutation or purchase was performed. These fixtures establish request behaviour, not live IAM enforcement or propagation. Existing broad grants remain unchanged and need operator review. Follow-up #2123 tracks that inventory and authorized migration; #2124 tracks the pre-existing Recommender permission setup gap. Main-branch CI is tracked separately by the coordinating session.
Activity
cristim commentedon Sep 29, 2026
Post-merge verification for #2122 completed on actual merge commit
76d1d4e72f13731ba071c7932f8e7e233cb4f6c6.1272e721b8d5185634840c9aa9fc7698dd7cb124: both tree IDs are8736682a2fcc3ac7ff52b0187e696be35a82ddec.GOWORK=off GOTOOLCHAIN=go1.26.6 go test -race ./cmd -run 'TestGCPStepGrantRole|TestAddMemberToPolicyBinding' -count=1: exit 0, 26.461 seconds.No real IAM mutation or purchase was performed. These fixtures establish request behaviour, not live IAM enforcement or propagation. Existing broad grants remain unchanged and need operator review. Follow-up #2123 tracks that inventory and authorized migration; #2124 tracks the pre-existing Recommender permission setup gap. Main-branch CI is tracked separately by the coordinating session.