You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(augment): expand permissions scope and make admin fallback opt-in
Address second round of PR review feedback on fine-grained permissions proposal:
- Add 5 infrastructure resource permissions (vectorstore, document, mcp, prompt,
model) as basic permissions, expanding total from 16 to 21. These enable
deployers to grant targeted access instead of all-or-nothing augment.admin.
- Add corresponding route authorization requirements for all 5 infrastructure
categories, including closing the gap where MCP tool creation was ungated.
- Change augment.admin fallback from default-on to opt-in via
permissions.legacyAdminFallback config flag. Dev preview means no backward
compatibility guarantees — opt-in avoids the "temporary becomes permanent"
problem where removing the fallback later becomes the breaking change it was
meant to prevent. Existing deployments can enable the flag during migration.
- Update authorization-middleware spec with fallback-disabled scenarios and
config-gated fallback behavior in authorizeLifecycleAction and
authorizeBasicWithFallback.
- Update design.md context, goals, Decision 2, and risk mitigations to reflect
broader scope and opt-in fallback rationale.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: gabemontero <gmontero@redhat.com>
Copy file name to clipboardExpand all lines: workspaces/augment/openspec/changes/fine-grained-backstage-permissions/design.md
+9-9Lines changed: 9 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
## Context
4
4
5
-
The augment plugin currently enforces 12+ authorization decisions via custom inline guards in route handlers — `checkIsAdmin`, `createdBy` comparisons, lifecycle stage checks, and self-approval prevention. These bypass Backstage's permission framework entirely. Only two coarse permissions exist (`augment.access` for read, `augment.admin` for admin operations), making fine-grained RBAC impossible.
5
+
The augment plugin currently enforces 12+ authorization decisions via custom inline guards in route handlers — `checkIsAdmin`, `createdBy` comparisons, lifecycle stage checks, and self-approval prevention. These bypass Backstage's permission framework entirely. Only two coarse permissions exist (`augment.access` for read, `augment.admin` for admin operations), making fine-grained RBAC impossible. Additionally, all infrastructure operations (vector stores, documents, MCP connections, prompts, models) are gated by the single `augment.admin` permission, preventing deployers from granting targeted access to specific resource categories.
6
6
7
7
Backstage provides a permission framework (`@backstage/plugin-permission-node`) supporting basic permissions, resource-based permissions with conditional rules, and policy evaluation via the permission backend. The `extensions-backend` plugin in this workspace already follows this pattern and serves as a reference implementation.
8
8
@@ -13,15 +13,15 @@ These permissions are independent of AgenticProvider authorization. Kagenti's pe
13
13
**Goals:**
14
14
15
15
- Replace all 12+ inline authorization decisions with Backstage permission framework calls
16
-
- Enable deployers to configure fine-grained RBAC policies for agent and tool lifecycle operations
17
-
-Maintain full backward compatibility — existing `augment.access` + `augment.admin`policies continue to work unchanged
16
+
- Enable deployers to configure fine-grained RBAC policies for agent and tool lifecycle operations and targeted access to infrastructure resources (vector stores, documents, MCP connections, prompts, models)
17
+
-Provide an opt-in legacy fallback (`permissions.legacyAdminFallback`) so existing deployments using `augment.access` + `augment.admin`can migrate incrementally
18
18
- Support conditional permission rules for ownership checks, self-approval prevention, and lifecycle stage gating
- Emit structured audit log entries for all authorization decisions — recording the user, action, resource, outcome (allow/deny), and whether the `augment.admin` fallback was used. The authorization middleware is the single point through which all permission decisions flow, making it the natural place for audit logging.
21
21
22
22
**Non-Goals:**
23
23
24
-
- Modifying `augment.access` or `augment.admin` behavior or semantics
24
+
- Modifying `augment.access` or `augment.admin` behavior or semantics (though `augment.admin` is no longer the default gate for lifecycle/infrastructure operations)
25
25
- Adding permissions for AgenticProvider-level operations (Kagenti API calls, OpenAI API calls)
- Custom permission policy plugins (works with standard Backstage RBAC)
@@ -35,13 +35,13 @@ Define `augment-agent` and `augment-tool` as distinct resource types rather than
35
35
36
36
**Alternative considered:** Single `augment-resource` type with a discriminator field. Rejected because it conflates two domain objects that are independently routed and independently targetable by policy.
37
37
38
-
### Decision 2: Two-tier authorization with backward-compatible fallback
38
+
### Decision 2: Opt-in legacy fallback to `augment.admin`
39
39
40
-
`authorizeLifecycleAction` checks the fine-grained permission first. If DENY (the default when no policy exists), it falls back to checking `augment.admin`. This means deployments that haven't configured fine-grained policies get identical behavior to today.
40
+
When `permissions.legacyAdminFallback` is enabled in the plugin config, `authorizeLifecycleAction` checks the fine-grained permission first. If DENY, it falls back to checking `augment.admin`. When the config flag is absent or false (the default), only fine-grained permissions are evaluated — no fallback occurs.
41
41
42
-
**Why backward compatibility matters for a "new" plugin:**Although the augment plugin is still in active development, there are external consumers already running it with RBAC policies configured around `augment.access` + `augment.admin`. From their perspective, a new drop that requires policy reconfiguration to maintain existing access is a cross-release breaking change. The fallback ensures these deployments continue to work on upgrade, while giving them the option to adopt fine-grained policies incrementally.
42
+
**Why opt-in rather than default-on:**The augment plugin is in dev preview, which means no backward compatibility guarantees. Making the fallback default-on risks the "temporary becomes permanent" problem — once deployments rely on `augment.admin` as a catch-all, removing the fallback later becomes the very breaking change it was meant to prevent. Opt-in gives existing consumers a migration path (enable the flag, then incrementally adopt fine-grained policies, then disable the flag) without baking the fallback into every deployment's baseline.
43
43
44
-
**Alternative considered:**Requiring all deployments to update their RBAC policies. Rejected because it would break existing augment deployments on upgrade — deployers would need to add fine-grained policy entries before the upgrade or lose access to lifecycle operations.
44
+
**Alternative considered:**Default-on fallback for all deployments. Rejected because it creates invisible load-bearing behavior that becomes difficult to remove — every release the fallback ships as default makes removal harder, not easier. Dev preview is the right time to establish the clean model.
45
45
46
46
**Alternative considered:** OR-combining fine-grained and admin in a single policy evaluation. Rejected because Backstage's permission framework evaluates permissions individually — the fallback must be explicit in code.
-**Policy migration complexity** → Deployers who want fine-grained control must write new RBAC policies. Mitigated by the fallback mechanism — no action required to maintain current behavior.
66
+
-**Policy migration complexity** → Deployers must configure fine-grained RBAC policies. Existing deployments can enable `permissions.legacyAdminFallback`to preserve current `augment.admin`behavior during migration.
67
67
-**Conditional evaluation overhead** → Resource-based permissions require loading the resource to evaluate conditions. Mitigated by keeping list operations as basic permissions and only using resource-based permissions for mutation routes where the resource is already loaded.
68
68
-**Rule mismatch on upgrade** → If a deployer configures a fine-grained policy with a `HAS_LIFECYCLE_STAGE` condition referencing a stage name that changes, the rule silently denies. Mitigated by documenting stage names as part of the permission contract.
69
69
-**Defense-in-depth dual check** → The self-approval hard-coded check and `IS_NOT_CREATOR` rule are redundant by design. If one is relaxed without updating the other, behavior may be confusing. Mitigated by documenting this clearly.
Copy file name to clipboardExpand all lines: workspaces/augment/openspec/changes/fine-grained-backstage-permissions/specs/authorization-middleware/spec.md
+24-14Lines changed: 24 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,40 +2,45 @@
2
2
3
3
Augment-specific authorization middleware that integrates Backstage's permission framework with the plugin's domain model (agents, tools, lifecycle stages, ownership). This is NOT a reimplementation of RBAC policy evaluation — the RBAC plugin handles that. This middleware provides:
4
4
5
-
1.**Two-tier fallback logic** — check fine-grained permission first, fall back to `augment.admin` for backward compatibility during migration. This is augment-specific business logic that the RBAC plugin cannot provide, since the fallback semantics (which coarse permission to check, when to check it) are domain decisions.
5
+
1.**Opt-in legacy fallback logic** — when `permissions.legacyAdminFallback` is enabled, check fine-grained permission first, then fall back to `augment.admin` for backward compatibility during migration. When disabled (the default), only fine-grained permissions are evaluated. This is augment-specific business logic that the RBAC plugin cannot provide, since the fallback semantics (which coarse permission to check, when to check it) are domain decisions.
6
6
2.**Conditional evaluation against augment resource types** — `matchesAgentConditions` and `matchesToolConditions` evaluate Backstage CONDITIONAL results against augment's domain objects (agents/tools with `createdBy`, lifecycle stages). The RBAC plugin evaluates policies; these utilities evaluate the resulting conditions against augment-specific resource shapes.
7
7
3.**RouteContext integration** — exposing authorization functions on the route context so handlers can call them without importing permission utilities directly.
8
8
9
9
### Relationship to existing permissions
10
10
11
11
-**`augment.access`** remains unchanged — it is a plugin-level visibility gate (can the user access the augment plugin at all?) and is orthogonal to fine-grained lifecycle permissions.
12
-
-**`augment.admin`** continues to gate admin-only routes (config, documents, vector stores, models, evaluations, workflows, dev spaces) that are not covered by the fine-grained permissions. For agent/tool lifecycle operations, it serves as a backward-compatible fallback: existing deployments that only have `augment.admin` policies continue to work without reconfiguration. Deployers who adopt fine-grained permissions can remove the `augment.admin` grant for lifecycle operations — the fallback is a migration aid, not a permanent override.
12
+
-**`augment.admin`** continues to gate admin-only routes (evaluations, workflows, dev spaces) that are not yet covered by fine-grained permissions. For agent/tool lifecycle operations and infrastructure resources (vector stores, documents, MCP, prompts, models), it can serve as a backward-compatible fallback when `permissions.legacyAdminFallback` is enabled in the plugin config. By default, only fine-grained permissions are evaluated — deployments must configure the appropriate fine-grained RBAC policies.
13
13
14
14
## ADDED Requirements
15
15
16
16
### Requirement: authorizeLifecycleAction function
17
17
18
-
The system SHALL provide an `authorizeLifecycleAction(req, permission, resource?)` function that implements two-tier authorization:
18
+
The system SHALL provide an `authorizeLifecycleAction(req, permission, resource?)` function that implements authorization with opt-in legacy fallback:
19
19
20
20
1. Evaluate the fine-grained permission (with conditional rules if resource-based)
21
21
2. If ALLOW, grant access
22
-
3. If DENY, fall back to checking `augment.admin`
23
-
4. If `augment.admin` is ALLOW, grant access
22
+
3. If DENY and `permissions.legacyAdminFallback` is enabled, fall back to checking `augment.admin`
23
+
4. If fallback is enabled and `augment.admin` is ALLOW, grant access
24
24
5. Otherwise, deny access
25
25
26
26
#### Scenario: Fine-grained permission allows
27
27
28
28
-**WHEN**`authorizeLifecycleAction` is called and the fine-grained permission evaluates to ALLOW
29
29
-**THEN** access SHALL be granted without checking `augment.admin`
30
30
31
-
#### Scenario: Fine-grained denies but admin allows
-**WHEN**`authorizeLifecycleAction` is called, the fine-grained permission evaluates to DENY, and `augment.admin` evaluates to ALLOW
33
+
-**WHEN**`authorizeLifecycleAction` is called, the fine-grained permission evaluates to DENY, `permissions.legacyAdminFallback` is enabled, and `augment.admin` evaluates to ALLOW
34
34
-**THEN** access SHALL be granted via the fallback
-**WHEN**`authorizeLifecycleAction` is called and both the fine-grained permission and `augment.admin` evaluate to DENY
38
+
-**WHEN**`authorizeLifecycleAction` is called, the fine-grained permission evaluates to DENY, and `permissions.legacyAdminFallback` is not enabled
39
+
-**THEN** access SHALL be denied without checking `augment.admin`
40
+
41
+
#### Scenario: Both deny with fallback enabled
42
+
43
+
-**WHEN**`authorizeLifecycleAction` is called, `permissions.legacyAdminFallback` is enabled, and both the fine-grained permission and `augment.admin` evaluate to DENY
@@ -50,21 +55,26 @@ When `authorizeLifecycleAction` receives a CONDITIONAL result from the permissio
50
55
#### Scenario: Conditional result with non-matching resource
51
56
52
57
-**WHEN** the permission framework returns CONDITIONAL with an `IS_OWNER` condition, and the resource's `createdBy` does not match the requesting user
53
-
-**THEN**`authorizeLifecycleAction` SHALL evaluate the condition to DENY and fall back to `augment.admin`
58
+
-**THEN**`authorizeLifecycleAction` SHALL evaluate the condition to DENY and, if `permissions.legacyAdminFallback` is enabled, fall back to `augment.admin`
54
59
55
60
### Requirement: authorizeBasicWithFallback function
56
61
57
-
The system SHALL provide an `authorizeBasicWithFallback(req, permission)` function for basic (non-resource) permissions that checks the given permission first, then falls back to `augment.admin` on DENY.
62
+
The system SHALL provide an `authorizeBasicWithFallback(req, permission)` function for basic (non-resource) permissions that checks the given permission first. If DENY and `permissions.legacyAdminFallback` is enabled, it falls back to `augment.admin`.
58
63
59
64
#### Scenario: Basic permission allows
60
65
61
66
-**WHEN**`authorizeBasicWithFallback` is called and the basic permission evaluates to ALLOW
62
67
-**THEN** access SHALL be granted
63
68
64
-
#### Scenario: Basic permission denies with admin fallback
-**WHEN**`authorizeBasicWithFallback` is called, the basic permission evaluates to DENY, and `augment.admin` evaluates to ALLOW
67
-
-**THEN** access SHALL be granted
71
+
-**WHEN**`authorizeBasicWithFallback` is called, the basic permission evaluates to DENY, `permissions.legacyAdminFallback` is enabled, and `augment.admin` evaluates to ALLOW
72
+
-**THEN** access SHALL be granted via the fallback
Copy file name to clipboardExpand all lines: workspaces/augment/openspec/changes/fine-grained-backstage-permissions/specs/permission-definitions/spec.md
+29-4Lines changed: 29 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,11 +2,12 @@
2
2
3
3
Fine-grained permission constants, resource types, and permission rule definitions for augment agent and tool governance.
4
4
5
-
### Scope: Why agents and tools first
5
+
### Scope
6
6
7
-
This spec defines fine-grained permissions for **agent and tool lifecycle operations** because these are the authorization decisions with the most nuanced requirements — ownership scoping, self-approval prevention, lifecycle stage gating, and filtered visibility. These are currently enforced via inline checks (`checkIsAdmin`, `createdBy` comparisons) that bypass the Backstage permission framework entirely.
7
+
This spec defines two tiers of fine-grained permissions:
8
8
9
-
Other admin-only operations (config CRUD, document management, vector stores, models, evaluations, workflows, dev spaces) remain gated by the existing `augment.admin` permission. These are genuinely admin-only operations without ownership or conditional logic — the coarse gate is appropriate and adding fine-grained permissions for them today would increase surface area without clear demand. They are candidates for future fine-grained permissions if deployer requirements emerge (e.g., separating "can manage documents" from "can manage evaluations").
9
+
1.**Resource-based permissions** for agents and tools — these have the most nuanced authorization requirements (ownership scoping, self-approval prevention, lifecycle stage gating, filtered visibility) and support conditional rules (`IS_OWNER`, `IS_NOT_CREATOR`, `HAS_LIFECYCLE_STAGE`).
10
+
2.**Basic permissions** for infrastructure resources (vector stores, documents, MCP connections, prompts, models) — these are currently admin-only operations without ownership or lifecycle logic. Defining permissions for them now enables deployers to grant targeted access (e.g., "this team can manage vector stores but not MCP connections") instead of the all-or-nothing `augment.admin`. These can be upgraded to resource-based permissions later if ownership tracking is added.
10
11
11
12
## ADDED Requirements
12
13
@@ -83,9 +84,33 @@ The system SHALL define `augment.kagenti.admin` as a basic permission with actio
83
84
-**WHEN** the `augment-common` package is loaded
84
85
-**THEN**`augment.kagenti.admin` SHALL be a basic permission with action `update`
|`augment.prompt.manage`| update | System prompt generation and configuration |
97
+
|`augment.model.manage`| update | Model listing, testing, and selection configuration |
98
+
99
+
These are basic permissions without conditional rules. Each gates a category of admin operations, enabling deployers to grant targeted access without granting full `augment.admin`.
100
+
101
+
#### Scenario: All infrastructure permissions defined
102
+
103
+
-**WHEN** the `augment-common` package is loaded
104
+
-**THEN** all 5 infrastructure permissions SHALL be defined as basic permissions with action `update`
105
+
106
+
#### Scenario: Infrastructure permissions independent of augment.admin
107
+
108
+
-**WHEN** a user has `augment.vectorstore.manage` but not `augment.admin`
109
+
-**THEN** the user SHALL be able to manage vector stores but not other admin operations
110
+
86
111
### Requirement: Existing permissions preserved
87
112
88
-
The existing `augmentAccessPermission` (`augment.access`) and `augmentAdminPermission` (`augment.admin`) SHALL remain unchanged. All 16 new permissions SHALL be added to the `augmentPermissions` array alongside the existing ones.
113
+
The existing `augmentAccessPermission` (`augment.access`) and `augmentAdminPermission` (`augment.admin`) SHALL remain unchanged. All 21 new permissions SHALL be added to the `augmentPermissions` array alongside the existing ones. `augment.admin` continues to gate routes not yet covered by fine-grained permissions (evaluations, workflows, dev spaces) and serves as an opt-in fallback for fine-grained operations when `permissions.legacyAdminFallback` is enabled.
0 commit comments