[feat] Extend access controls and billing settings#4330
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR generalizes plan/role definitions from closed Python enums into runtime-configurable env vars (AGENTA_ACCESS_*, AGENTA_BILLING_*), splits the previous /admin/billing/usage/flush span retention endpoint into independent /admin/spans/flush and /admin/events/flush admin routers (each with its own service, DAO, cron, and Redis lock), and updates the frontend to treat plan slugs as plain strings while keeping a DefaultPlan enum for code-side conditionals. Backend Plan/WorkspaceRole enums are largely replaced with string slugs validated against the effective access-controls catalog at startup.
Changes:
- New
AccessControls/BillingSettingsenv layers parsed at startup with strict cross-reference validation; legacySTRIPE_PRICINGremoved and migration script provided. - New
Counter.EVENTSplusEventsService/EventsDAO/EventsRouter/SpansRouterandevents.shcron;BillingRouterno longer owns retention. - Frontend
Planwidened tostringwithDefaultPlanenum retained for known constants; updates to billing UI, banners, anduseEntitlements.
Reviewed changes
Copilot reviewed 67 out of 72 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| api/oss/src/utils/env.py | Adds AccessControls + BillingSettings env models with JSON loaders; drops StripeConfig.pricing. |
| api/ee/src/core/entitlements/types.py | Renames Plan→DefaultPlan, adds DefaultRole/Counter.EVENTS/Period; renames CATALOG/ENTITLEMENTS→DEFAULT_*. |
| api/ee/src/core/subscriptions/{settings,service,types}.py | New billing settings module with strict validation; service uses dynamic free/trial accessors; types use string plans. |
| api/ee/src/core/entitlements/{service,controls(*not in diff)}.py | Entitlements service consumes get_plan_entitlements. |
| api/ee/src/core/{events,tracing}/service.py | New EventsService.flush_events; TracingService.flush_spans iterates dynamic plans. |
| api/ee/src/dbs/postgres/events/{init,dao}.py | New EE retention DAO independent from OSS events DAO. |
| api/ee/src/apis/fastapi/{spans,events}/router.py | New independent admin routers replacing /admin/billing/usage/flush. |
| api/ee/src/apis/fastapi/billing/router.py | Drops tracing_service dep + flush endpoint; uses dynamic catalog/pricing/free-plan accessors. |
| api/ee/src/main.py | Wires new spans/events services and routers. |
| api/ee/src/services/{throttling_service,workspace_manager,db_manager_ee,converters,admin_manager}.py | Switch to controls accessors and string slugs. |
| api/ee/src/utils/{permissions,entitlements}.py | Resolve role permissions and entitlements via controls module. |
| api/ee/src/routers/workspace_router.py | Validates assigned role against effective workspace catalog. |
| api/ee/src/models/{db_models, api/api_models, api/workspace_models}.py | Org-member default role member→viewer; widens role types to str. |
| api/ee/src/core/workspaces/types.py | WorkspacePermission.role_name: str. |
| api/oss/src/core/{accounts,auth}/service.py, api/oss/src/routers/workspace_router.py | Remove enum coupling; validate plan/role via EE controls. |
| api/ee/src/dbs/postgres/subscriptions/mappings.py | Drop Plan enum coercion. |
| api/ee/databases/postgres/migrations/.../*.py | Inline literal FREE_PLAN constants; new migration to unify member→viewer. |
| api/ee/src/crons/{spans.sh,events.sh,events.txt}, api/ee/docker/Dockerfile.{dev,gh}, hosting/docker-compose/ee/* | Cron + image wiring for new events flush job and EE env examples. |
| api/ee/tests/pytest/unit/test_{access_controls,billing_settings,billing_router,controls_env_override,events_retention,admin_retention_routers}.py | New/updated tests for parsers, env wiring, retention services, and admin routers. |
| docs/docs/self-host/{02-configuration,04-dynamic-access-controls,05-dynamic-billing-settings}.mdx | Operator-facing documentation for the new env surface. |
| docs/designs/dynamic-access-and-billing/{research,gap,proposal,tasks,findings,migrate_stripe_pricing.py}.* | Design folder + legacy STRIPE_PRICING converter. |
| docs/designs/data-retention/*, docs/design/ee-self-hosting/research.md, docs/openapi-cleanup/endpoints.md | Updated to reference the split admin endpoints. |
| web/oss/src/lib/Types.ts, web/oss/src/lib/helpers/useEntitlements.ts | Plan enum renamed Plan→DefaultPlan; runtime plan typed as string. |
| web/ee/src/services/billing/types.d.ts, web/ee/src/components/SidebarBanners/state/atoms.ts, web/ee/src/components/pages/settings/Billing/* | Frontend updated to use DefaultPlan constants and string plan slugs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| `traces` and `events` are independent: each has its own counter, its own | ||
| retention period, its own admin flush endpoint (`/admin/spans/flush` and | ||
| `/admin/events/flush`), and its own cron schedule. Setting one does not | ||
| affect the other. The default for `events.retention` is `null` (kept | ||
| forever); opt in by setting it via overlay or full plan override. |
| ## `AGENTA_ACCESS_ROLES` | ||
|
|
||
| JSON **object** keyed by scope. Scope values are non-empty arrays of custom | ||
| role entries. The `owner` and `viewer` minima are platform-managed and | ||
| always synthesized for every scope — env can only **add** roles, never | ||
| redefine the minima. | ||
|
|
||
| ### Top-level shape | ||
|
|
||
| ```text | ||
| { | ||
| "<scope>": [<RoleEntry>, ...], | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| Recognized scopes: `organization`, `workspace`, `project`. Unknown scopes | ||
| fail startup. Omitted scopes keep their full code defaults. | ||
|
|
||
| ### `RoleEntry` fields | ||
|
|
||
| | Field | Type | Required | Description | | ||
| |-------|------|----------|-------------| | ||
| | `role` | string | yes | Slug; cannot be `owner` or `viewer` (reserved). | | ||
| | `description` | string | no | Human-readable description for UIs. | | ||
| | `permissions` | string[] | yes | `Permission` enum slugs, or `"*"` for full access. | | ||
|
|
||
| ### Platform minima (always present) | ||
|
|
||
| The platform always synthesizes `owner` and `viewer` in every scope. Their | ||
| permission sets are code-defined: | ||
|
|
||
| | Scope | `owner` | `viewer` | | ||
| |-------|---------|----------| | ||
| | `organization` | `["*"]` | `[]` (membership marker, no permissions) | | ||
| | `workspace` | `["*"]` | Read-only set (sourced from the code-default `WorkspaceRole.VIEWER`) | | ||
| | `project` | `["*"]` | Same read-only set | | ||
|
|
||
| Org-scope `viewer` having no permissions is intentional: organizations don't | ||
| have a permission concept today — `viewer` is purely a membership marker. | ||
|
|
||
| ### Example | ||
|
|
||
| Add a `reviewer` role at the project scope: | ||
|
|
||
| ```json | ||
| { | ||
| "project": [ | ||
| { | ||
| "role": "reviewer", | ||
| "description": "Can inspect runs and annotate traces.", | ||
| "permissions": ["read_system", "view_evaluation_runs", "edit_annotations"] | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| After applying that override, `/workspace/roles/` and member serialization | ||
| return `owner`, `viewer`, and `reviewer` for the project scope. Workspace | ||
| and organization scopes are untouched. | ||
|
|
||
| The `permissions` array entries must be valid `Permission` enum members or | ||
| the wildcard `"*"`. Unknown permissions fail startup. |
| OrganizationRole = Literal[ | ||
| "owner", | ||
| "member", | ||
| "viewer", | ||
| ] |
No description provided.