Skip to content

refactor(provisioning): replace ALLOWED_PROVISIONING_SCOPES with app.scopes ceiling #60331

@MattBro

Description

@MattBro

Part of #60327 — implements RFC #1103.

Phase 1. Depends on #60329 (foundation + /authorize enforcement).

Scope

Drop _validate_scopes (ee/api/agentic_provisioning/views.py:2130) and ALLOWED_PROVISIONING_SCOPES (:2108, already contains llm_gateway:read at :2118). Apply request ∩ application.scopes (reject outside-ceiling) on all three issuance paths:

  1. Consent path — builds an /authorize URL (_build_authorize_url), already flows through I1's override. ✓
  2. Direct-mint_exchange_authorization_code creates the token by hand (views.py:995-1003, scope_str = " ".join(scopes) if scopes else StripeIntegration.SCOPES). Never calls OAuthValidator; needs explicit intersection here.
  3. Provisioning refresh_exchange_refresh_token re-creates the token with scope=old_scope and no intersection; add narrowing.

account_requests reads scopes at views.py:321.

Reconcile

The in-flight worktree-scope-update-service / scope-update-followup branches hydrate token scope at issuance/refresh (scope pinned to consent org). Reconcile this slice with that work before splitting code.

Validation

  • Rewrite/remove ee/api/agentic_provisioning/test_scope_validation.py (tests _validate_scopes).
  • New cases in test_account_requests.py: in/out-of-ceiling on consent + direct-mint; refresh narrowing on the provisioning refresh path.

Direct-mint bypass (load-bearing). PR #60477 enforces the ceiling at /authorize via an OAuthValidator.validate_scopes override. That override does NOT reach _exchange_authorization_code at ee/api/agentic_provisioning/views.py:997-1003, which creates the token by hand with OAuthAccessToken.objects.create(scope=scope_str, ...). The intersection (request ∩ application.scopes) has to land inline here just before the create() call, with the same OIDC carve-out (OIDC_SCOPES ∪ {"introspection"} always allowed). Same applies to _exchange_refresh_token. Three issuance paths total: consent path (already covered by /authorize override), direct-mint, refresh.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions