Repository navigation
fix(api/purchases): base build broken - session.Role removed by #907 but still used in authorizeSessionExecuteDirect (#803) #940
Description
Severity: base branch feat/multicloud-web-frontend does not compile
Two already-merged PRs are mutually inconsistent, leaving the base branch in a non-building state:
- PR feat(api,recs): execute-any/own permission gate on direct execute (closes #289) #803 (execute-any/own gate, feat(api,recs): permission-gated direct purchase execute (execute-{any,own}) bypassing approval email, with cost warning + confirm gate #289) added
authorizeSessionExecuteDirectininternal/api/handler_purchases.go, which starts with:if session.Role == "admin" { return nil }
- PR feat(auth): group-membership-only authorization, remove roles, require >=1 group (closes #907) #912 (group-membership-only authz, Revamp authorization: group-membership-only (remove roles), require >=1 group per user #907) removed the
Rolefield fromapi.Session(nowtype Session struct { UserID string; Email string }).
Result, on a clean checkout of feat/multicloud-web-frontend:
internal/api/handler_purchases.go:520:13: session.Role undefined (type *Session has no field or method Role)
This was not caught because CI does not gate on go build ./... / go test ./... (only pre-commit + read-only sanity + CodeRabbit run). Every open PR that compiles internal/api is blocked from a clean rebase by this (observed on #804 and #808), and any deploy built from this base would fail.
Fix
Remove the dead session.Role == "admin" shortcut from authorizeSessionExecuteDirect, matching its sibling gates. authorizeSessionApprove, authorizeSessionCancel, and the retry gate already have NO Role shortcut post-#907 - Administrators-group users pass via the HasPermissionAPI(ctx, session.UserID, auth.ActionExecuteAny, auth.ResourcePurchases) check immediately below (the Administrators group carries the {admin, *} wildcard permission, which matches ExecuteAny). The function's own doc comment even says it "mirrors authorizeSessionApprove / authorizeSessionCancel", which no longer use Role.
Concretely:
- Delete the 3-line
if session.Role == "admin" { return nil }block at the top ofauthorizeSessionExecuteDirect. - Update the gate-logic doc comment: drop the "admin role: always permitted" bullet; note admins pass via the execute-any permission (matching the sibling functions' comments).
Acceptance criteria
go build ./...succeeds on the branch.- A regression test asserts an Administrators-group user (no execute-own/any explicit grant) is still permitted by
authorizeSessionExecuteDirectvia the wildcardHasPermissionAPI(ExecuteAny)path (so removing the shortcut does not lock admins out). - Non-admin without execute-any/own is still 403; nil auth component is still 500 (fail-closed unchanged).
Provenance
Discovered by the pr-iterate sweep while rebasing #804 and #808; both correctly STOPPED rather than fixing base code out-of-scope.
Activity
fix(api/purchases): drop removed session.Role shortcut in execute-dir…
fix(db/migrate): admin-upsert SQL parity with post-057 schema + decou…
fix(api): restore base build - drop removed Session.Role from handler…
sec(api/plans): stop leaking raw account UUID + DB error in plan-acco…
sec(api/plans): stop leaking raw account UUID + DB error in plan-acco…
sec(api/plans): stop leaking raw account UUID + DB error in plan-acco…
sec(api/plans): stop leaking raw account UUID + DB error in plan-acco…