Skip to content

feat(auth): environment-scoped grants #342

Open

Description

@PiquelChips

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/production plus B/staging is not {A, B} × {production, staging}.
  • Escalation: Grants::covers and Grants::may_grant treat an application-wide grant as covering an environment-scoped one, never the reverse. Grants::intersection keeps tokens at token ∩ 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, piquelctl grant and invite options, the API and OpenAPI, and the permissions and authorization docs.

Open decision: how a grant selects environments

  • By name (staging in 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


Written with Claude Opus 5.5 in Claude Code (via T3 Code).

Activity

  1. moved this from Needs Triage to Up Next in origin-src.devon Oct 30, 2026
  2. modified the milestones: 0.1, Later on Oct 30, 2026
  3. moved this from Up Next to Needs Triage in origin-src.devon Oct 30, 2026
  4. added this to the 0.2 milestone on Nov 3, 2026
  5. moved this from Needs Triage to Up Next in origin-src.devon Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions