Repository navigation
Open
Labels
enhancementNew feature or requestNew feature or request
Milestone
Description
Phase 4 of sourceorigin-dev/infra#7 (#348): needed once a second person needs access.
Problem
A grant's scope is every application or a list of applications, and a grant on an application covers all of its environments and previews. A QA tester can't be given staging without also getting production, and there is no way to say "staging of every application, including ones created later".
Proposed solution
Grants can narrow their scope to environments as well as applications.
- First version: environment scopes are allowed only on
apps:access(feat(ingress): private routes need an environment grant #346). Every other permission, reads included, stays application-wide: environment-scoped manifest edits, secrets and promotions would each need their own rules, and scoped reads need every read endpoint audited. Nobody needs them yet. Creating such a grant is refused. - Scope: an environment-scoped grant covers the selected environments of its applications (every application, or a list). An application-wide grant still covers every environment and preview. Unmatched environments are denied.
- Pairing: grants for one permission merge without crossing pairs:
A/productionplusB/stagingis not{A, B} × {production, staging}. - Escalation:
Grants::coversandGrants::may_granttreat an application-wide grant as covering an environment-scoped one, never the reverse.Grants::intersectionkeeps tokens attoken ∩ account. - Wire compatibility: today an unknown field is ignored and a missing restriction means unrestricted, so an older client or server could silently widen an environment-scoped grant. The API must make older servers reject the new scope, and older clients unable to resubmit a grant without it.
- Surfaces: the grant editor in the dashboard,
piquelctlgrant and invite options, the API and OpenAPI, and the permissions and authorization docs.
Open decision: how a grant selects environments
- By name (
stagingin every application): nothing new to declare, and a typo denies rather than widens. Names are free-form, so a second staging environment falls outside the grant. - By label (an environment declares
label = "staging"): explicit and shared across applications, but relabelling production would grant QA production. Label changes then need authority over both the old and the new selection.
Later
- Scoped reads: an account holding only environment-scoped grants sees the application, but only its selected environments. Every read endpoint is checked for this: manifests, logs, builds, deployments, events and their streams, secret metadata. Until then, QA testers find their applications through feat(ingress): private routes need an environment grant #346's "your private applications" list.
Validation
Property tests for covers, may_grant, intersection and merging with mixed scopes; authorization tests for an account holding only environment-scoped grants; a compatibility test against the previous API shape.
Related
- feat(auth): reusable roles #160: roles would bundle these grants.
- feat(ingress): private routes need an environment grant #346: the
apps:accesspermission and theqapreset.
Written with Claude Opus 5.5 in Claude Code (via T3 Code).
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Type
Projects
- StatusShow more project fieldsUp Next
Activity