standardize GraphQL authorization errors - #3283
Draft
GregorShear wants to merge 2 commits into
Draft
Conversation
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description:
Standardizes terminal GraphQL authorization failures around runtime authorization requirements.
For caller-known scopes, the same requirement object is passed to the authorization evaluator and serialized into the GraphQL error, preventing the machine-readable contract from drifting from enforcement. Terminal denials include both the required capabilities and catalog prefixes:
{ "code": "PERMISSION_DENIED", "authorization": { "requirements": [ { "allOf": ["CreateInviteLink"], "catalogPrefixes": ["acmeCo/"] } ] } }For resources selected by opaque identifiers, the prefix remains internal.
deleteInviteLinknow returns the same client-visible response for a missing token and a terminal authorization denial, while still communicating the capability required by the operation:{ "code": "NOT_FOUND", "authorization": { "requirements": [ { "allOf": ["DeleteInviteLink"] } ] } }The underlying
ApiErrorremains attached as the non-serialized GraphQL error source. This preserves the existing stale-snapshot307refresh-and-retry flow and resolver behavior that intentionally downcasts selected permission denials.Workflow steps:
Clients make the operation normally and inspect
errors[].extensionsafter a terminal denial. Provisional denials continue through the existing retry response instead of returning a structured terminal error. For opaque resources, clients must not infer existence from the terminalNOT_FOUNDresponse.Documentation links affected:
None.
Notes for reviewers:
This PR is stacked on the invite-link capability PR. The opaque-resource test asserts that missing and denied errors are client-visible equivalents and that a sensitive internal prefix is absent from serialized output.
Validation:
cargo check -p control-plane-apigit diff --checkThe focused control-plane unit-test target is currently blocked by five unrelated missing SQLx offline cache entries in
service_accounts.rs.