Skip to content

Commit f2bb2c2

Browse files
committed
fix(ci): extract provider dispatch and account check to reduce revoke complexity; regenerate permissions on PR #804
1 parent d5975fc commit f2bb2c2

2 files changed

Lines changed: 28 additions & 12 deletions

File tree

‎frontend/src/permissions.generated.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const USER_PERMS: ReadonlySet<string> = new Set([
2525
'create:plans',
2626
'delete:plans',
2727
'retry-own:purchases',
28+
'revoke-own:purchases',
2829
'update:plans',
2930
'update:purchases',
3031
'view:history',

‎internal/api/handler_purchases_revoke.go‎

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ func (h *Handler) revokePurchase(ctx context.Context, req *events.LambdaFunction
9999
}, nil
100100
}
101101

102+
return h.dispatchProviderRevoke(ctx, record)
103+
}
104+
105+
// dispatchProviderRevoke routes a revocation request to the correct
106+
// provider-specific implementation. Extracted from revokePurchase to keep
107+
// that function's cyclomatic complexity within the project limit.
108+
func (h *Handler) dispatchProviderRevoke(ctx context.Context, record *config.PurchaseHistoryRecord) (any, error) {
102109
switch record.Provider {
103110
case "azure":
104111
return h.revokeAzurePurchase(ctx, record)
@@ -136,18 +143,26 @@ func (h *Handler) authorizeSessionRevoke(ctx context.Context, session *Session,
136143
return NewClientError(403, "permission denied: requires revoke-any or revoke-own on purchases")
137144
}
138145

139-
// revoke-own ownership check: the purchase must be in an account the
140-
// session user can access. Purchase history rows pre-date
141-
// created_by_user_id; ownership is via account access (same model as
142-
// the per-account-perms middleware used elsewhere in the history view).
143-
if record.CloudAccountID != nil && *record.CloudAccountID != "" {
144-
allowed, err := h.auth.GetAllowedAccountsAPI(ctx, session.UserID)
145-
if err != nil {
146-
return fmt.Errorf("account access check failed: %w", err)
147-
}
148-
if len(allowed) > 0 && !stringInSlice(*record.CloudAccountID, allowed) {
149-
return NewClientError(403, "permission denied: purchase is in an account you do not have access to")
150-
}
146+
return h.checkRevokeOwnAccountAccess(ctx, session.UserID, record)
147+
}
148+
149+
// checkRevokeOwnAccountAccess enforces the account-scope ownership constraint
150+
// for revoke-own: the purchase must be in a cloud account the session user
151+
// is allowed to access. Extracted from authorizeSessionRevoke to keep that
152+
// function's cyclomatic complexity within the project limit.
153+
func (h *Handler) checkRevokeOwnAccountAccess(ctx context.Context, userID string, record *config.PurchaseHistoryRecord) error {
154+
// Purchase history rows pre-date created_by_user_id; ownership is via
155+
// account access (same model as the per-account-perms middleware used
156+
// elsewhere in the history view).
157+
if record.CloudAccountID == nil || *record.CloudAccountID == "" {
158+
return nil
159+
}
160+
allowed, err := h.auth.GetAllowedAccountsAPI(ctx, userID)
161+
if err != nil {
162+
return fmt.Errorf("account access check failed: %w", err)
163+
}
164+
if len(allowed) > 0 && !stringInSlice(*record.CloudAccountID, allowed) {
165+
return NewClientError(403, "permission denied: purchase is in an account you do not have access to")
151166
}
152167
return nil
153168
}

0 commit comments

Comments
 (0)