Merge remote-tracking branch 'origin/dev' into 066-rbac-ui-enforcement-helper
This commit is contained in:
commit
b18b2280ef
@ -1,17 +1,18 @@
|
|||||||
<!--
|
<!--
|
||||||
Sync Impact Report
|
Sync Impact Report
|
||||||
|
|
||||||
- Version change: 1.4.0 → 1.5.0
|
- Version change: 1.5.0 → 1.6.0
|
||||||
- Modified principles:
|
- Modified principles:
|
||||||
- Tenant Isolation is Non-negotiable (added deny-as-not-found requirement)
|
- Tenant Isolation is Non-negotiable (clarified 404 vs 403 semantics)
|
||||||
|
- RBAC guidance consolidated (RBAC model rules merged into RBAC-UX)
|
||||||
- Added sections:
|
- Added sections:
|
||||||
- RBAC Standard (RBAC-001..RBAC-009)
|
- RBAC & UI Enforcement Standards (RBAC-UX)
|
||||||
- Removed sections: None
|
- Removed sections: None (RBAC-001..009 content consolidated into RBAC-UX)
|
||||||
- Templates requiring updates:
|
- Templates requiring updates:
|
||||||
- ✅ .specify/templates/plan-template.md
|
- ✅ .specify/templates/plan-template.md
|
||||||
- ✅ .specify/templates/spec-template.md
|
- ✅ .specify/templates/spec-template.md
|
||||||
- ✅ .specify/templates/tasks-template.md
|
- ✅ .specify/templates/tasks-template.md
|
||||||
- N/A: .specify/templates/commands/ (directory not present)
|
- N/A: .specify/templates/commands/ (directory not present in this repo)
|
||||||
- Follow-up TODOs: None
|
- Follow-up TODOs: None
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -43,58 +44,72 @@ ### Tenant Isolation is Non-negotiable
|
|||||||
- Every read/write MUST be tenant-scoped.
|
- Every read/write MUST be tenant-scoped.
|
||||||
- Cross-tenant views (MSP/Platform) MUST be explicit, access-checked, and aggregation-based (no ID-based shortcuts).
|
- Cross-tenant views (MSP/Platform) MUST be explicit, access-checked, and aggregation-based (no ID-based shortcuts).
|
||||||
- Prefer least-privilege roles/scopes; surface warnings when higher privileges are selected.
|
- Prefer least-privilege roles/scopes; surface warnings when higher privileges are selected.
|
||||||
- A non-member attempting to access a tenant route MUST be deny-as-not-found (404).
|
- Tenant membership is an isolation boundary. If the actor is not entitled to the tenant scope, the system MUST respond as
|
||||||
|
deny-as-not-found (404).
|
||||||
|
|
||||||
### RBAC Standard (RBAC-001)
|
### RBAC & UI Enforcement Standards (RBAC-UX)
|
||||||
|
|
||||||
RBAC-001 Two Planes
|
RBAC Context — Planes, Roles, and Auditability
|
||||||
- The platform MUST maintain two strictly separated authorization planes:
|
- The platform MUST maintain two strictly separated authorization planes:
|
||||||
- Tenant plane (`/admin/t/{tenant}`): authenticated Entra users (`users`), authorization is tenant-scoped.
|
- Tenant plane (`/admin/t/{tenant}`): authenticated Entra users (`users`), authorization is tenant-scoped.
|
||||||
- Platform plane (`/system`): authenticated platform users (`platform_users`), authorization is platform-scoped.
|
- Platform plane (`/system`): authenticated platform users (`platform_users`), authorization is platform-scoped.
|
||||||
- Cross-plane access MUST be deny-as-not-found (404) (not 403) to avoid route enumeration.
|
- Cross-plane access MUST be deny-as-not-found (404) (not 403) to avoid route enumeration.
|
||||||
|
- Tenant role semantics MUST remain least-privilege:
|
||||||
RBAC-002 Capabilities-first Authorization
|
|
||||||
- Feature code MUST NOT check raw roles directly (e.g. string role comparisons).
|
|
||||||
- Feature code MUST check capabilities via Gates/Policies only.
|
|
||||||
- A canonical capability registry MUST exist as the single source of truth (e.g. `TenantCapabilities` / `PlatformCapabilities`).
|
|
||||||
- Role → capability mapping MUST reference only registry entries.
|
|
||||||
|
|
||||||
RBAC-003 Least Privilege Role Semantics
|
|
||||||
- Tenant roles MUST follow least-privilege semantics:
|
|
||||||
- Readonly: view-only; MUST NOT start operations and MUST NOT mutate data.
|
- Readonly: view-only; MUST NOT start operations and MUST NOT mutate data.
|
||||||
- Operator: MAY start allowed tenant operations; MUST NOT manage credentials, settings, members, or perform destructive actions.
|
- Operator: MAY start allowed tenant operations; MUST NOT manage credentials, settings, members, or perform destructive actions.
|
||||||
- Manager: MAY manage tenant configuration and start operations; MUST NOT manage tenant memberships (Owner-only).
|
- Manager: MAY manage tenant configuration and start operations; MUST NOT manage tenant memberships (Owner-only).
|
||||||
- Owner: MAY manage memberships and all tenant configuration; Owner-only “danger zone” actions MUST remain Owner-only.
|
- Owner: MAY manage memberships and all tenant configuration; Owner-only “danger zone” actions MUST remain Owner-only.
|
||||||
|
|
||||||
RBAC-004 UI is not Security
|
|
||||||
- Hiding UI elements is NOT sufficient.
|
|
||||||
- Every mutation endpoint and action MUST enforce authorization server-side (Policy/Gate).
|
|
||||||
|
|
||||||
RBAC-005 Destructive Actions Gate
|
|
||||||
- All destructive actions (delete / force delete / irreversible operations) MUST:
|
|
||||||
- require an explicit confirmation (e.g., `requiresConfirmation()` or equivalent),
|
|
||||||
- be protected by a Policy/Gate,
|
|
||||||
- have at least one regression test asserting the action is forbidden for non-authorized roles.
|
|
||||||
|
|
||||||
RBAC-006 Membership Safety Rule
|
|
||||||
- The system MUST prevent removing or demoting the last remaining Owner of a tenant.
|
- The system MUST prevent removing or demoting the last remaining Owner of a tenant.
|
||||||
|
- All access-control relevant changes MUST write `AuditLog` entries with stable action IDs, and MUST be redacted (no secrets).
|
||||||
|
|
||||||
RBAC-007 Tenant Isolation
|
RBAC-UX-001 — Server-side is the source of truth
|
||||||
- All tenant-plane queries MUST be tenant-scoped.
|
- UI visibility / disabled state is never a security boundary.
|
||||||
- A non-member attempting to access a tenant route MUST be deny-as-not-found (404).
|
- Every mutating action (create/update/delete/restore/archive/force-delete), every operation start, and every credential/
|
||||||
|
config change MUST enforce authorization server-side via `Gate::authorize(...)` or a Policy method.
|
||||||
|
- Any missing server-side authorization is a P0 security bug.
|
||||||
|
|
||||||
RBAC-008 Auditing
|
RBAC-UX-002 — Deny-as-not-found for non-members
|
||||||
- All access-control relevant changes MUST write `AuditLog` entries with stable action IDs, including:
|
- Tenant membership (and plane membership) is an isolation boundary.
|
||||||
- membership add / role change / remove
|
- If the current actor is not a member of the current tenant (or otherwise not entitled to the tenant scope), the system MUST
|
||||||
- provider credential rotation / connection disable
|
respond as 404 (deny-as-not-found) for tenant-scoped routes/actions/resources.
|
||||||
- break-glass enter / exit / expire (platform plane)
|
- This applies to Filament resources/pages under tenant routing (`/admin/t/{tenant}/...`), Global Search results, and all
|
||||||
- `AuditLog` entries MUST be redacted (no secrets/tokens, minimal identity fields).
|
action endpoints (Livewire calls included).
|
||||||
|
|
||||||
RBAC-009 Testability Gate
|
RBAC-UX-003 — Capability denial is 403 (after membership is established)
|
||||||
- Any new feature that introduces or changes authorization MUST include:
|
- Within an established tenant scope, missing permissions are authorization failures.
|
||||||
- at least one positive test (authorized user can do it),
|
- If the actor is a tenant member, but lacks the required capability for an action, the server MUST fail with 403.
|
||||||
- at least one negative test (unauthorized user cannot do it),
|
- The UI may render disabled actions, but the server MUST still enforce 403 on execution.
|
||||||
- and MUST NOT introduce role-string checks outside the central mapping/registry.
|
|
||||||
|
RBAC-UX-004 — Visible vs disabled UX rule
|
||||||
|
- For tenant members: actions SHOULD be visible but disabled when capability is missing.
|
||||||
|
- Disabled actions MUST provide helper text explaining the missing permission.
|
||||||
|
- For non-members: actions MUST behave as not found (404) and SHOULD NOT leak resource existence.
|
||||||
|
- Exception: highly sensitive controls (e.g., credential rotation) MAY be hidden even for members without permission.
|
||||||
|
|
||||||
|
RBAC-UX-005 — Destructive confirmation standard
|
||||||
|
- All destructive-like actions MUST require confirmation.
|
||||||
|
- Delete/force-delete/archive/restore/remove membership/role downgrade/credential rotation/break-glass enter/exit MUST use
|
||||||
|
`->requiresConfirmation()` and SHOULD include clear warning text.
|
||||||
|
- Confirmation is UX only; authorization still MUST be server-side.
|
||||||
|
|
||||||
|
RBAC-UX-006 — Capability registry is canonical
|
||||||
|
- Capabilities MUST be centrally defined in a single canonical registry (constants/enum).
|
||||||
|
- Feature code MUST reference capabilities only via the registry (no raw string literals).
|
||||||
|
- Role → capability mapping MUST reference only registry entries.
|
||||||
|
- CI MUST fail if unknown/unregistered capabilities are used.
|
||||||
|
|
||||||
|
RBAC-UX-007 — Global search must be tenant-safe
|
||||||
|
- Global search results MUST be scoped to the current tenant.
|
||||||
|
- Non-members MUST never learn about resources in other tenants (no results, no hints).
|
||||||
|
- If a result exists but is not accessible, it MUST be treated as not found (404 semantics).
|
||||||
|
|
||||||
|
RBAC-UX-008 — Regression guards are mandatory
|
||||||
|
- The repo MUST include RBAC regression tests asserting at least:
|
||||||
|
- Readonly cannot mutate or start operations.
|
||||||
|
- Operator can run allowed operations but cannot manage configuration.
|
||||||
|
- Manager/Owner behave according to the role matrix.
|
||||||
|
- The repo SHOULD include an automated “no ad-hoc authorization” guard that blocks new status/permission mappings sprinkled
|
||||||
|
across `app/Filament/**`, pushing patterns into central helpers.
|
||||||
|
|
||||||
### Operations / Run Observability Standard
|
### Operations / Run Observability Standard
|
||||||
- Every long-running or operationally relevant action MUST be observable, deduplicated, and auditable via Monitoring → Operations.
|
- Every long-running or operationally relevant action MUST be observable, deduplicated, and auditable via Monitoring → Operations.
|
||||||
@ -159,4 +174,4 @@ ### Versioning Policy (SemVer)
|
|||||||
- **MINOR**: new principle/section or materially expanded guidance.
|
- **MINOR**: new principle/section or materially expanded guidance.
|
||||||
- **MAJOR**: removing/redefining principles in a backward-incompatible way.
|
- **MAJOR**: removing/redefining principles in a backward-incompatible way.
|
||||||
|
|
||||||
**Version**: 1.5.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-01-27
|
**Version**: 1.6.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-01-28
|
||||||
|
|||||||
@ -35,7 +35,9 @@ ## Constitution Check
|
|||||||
- Read/write separation: any writes require preview + confirmation + audit + tests
|
- Read/write separation: any writes require preview + confirmation + audit + tests
|
||||||
- Graph contract path: Graph calls only via `GraphClientInterface` + `config/graph_contracts.php`
|
- Graph contract path: Graph calls only via `GraphClientInterface` + `config/graph_contracts.php`
|
||||||
- Deterministic capabilities: capability derivation is testable (snapshot/golden tests)
|
- Deterministic capabilities: capability derivation is testable (snapshot/golden tests)
|
||||||
- RBAC Standard: two planes (/admin vs /system) remain separated; cross-plane is 404; authorization checks use Gates/Policies + capability registries (no role-string checks)
|
- RBAC-UX: two planes (/admin vs /system) remain separated; cross-plane is 404; non-member tenant access is 404; member-but-missing-capability is 403; authorization checks use Gates/Policies + capability registries (no raw strings, no role-string checks)
|
||||||
|
- RBAC-UX: destructive-like actions require `->requiresConfirmation()` and clear warning text
|
||||||
|
- RBAC-UX: global search is tenant-scoped; non-members get no hints; inaccessible results are treated as not found (404 semantics)
|
||||||
- Tenant isolation: all reads/writes tenant-scoped; cross-tenant views are explicit and access-checked
|
- Tenant isolation: all reads/writes tenant-scoped; cross-tenant views are explicit and access-checked
|
||||||
- Run observability: long-running/remote/queued work creates/reuses `OperationRun`; start surfaces enqueue-only; Monitoring is DB-only; DB-only <2s actions may skip runs but security-relevant ones still audit-log; auth handshake exception OPS-EX-AUTH-001 allows synchronous outbound HTTP on `/auth/*` without `OperationRun`
|
- Run observability: long-running/remote/queued work creates/reuses `OperationRun`; start surfaces enqueue-only; Monitoring is DB-only; DB-only <2s actions may skip runs but security-relevant ones still audit-log; auth handshake exception OPS-EX-AUTH-001 allows synchronous outbound HTTP on `/auth/*` without `OperationRun`
|
||||||
- Automation: queued/scheduled ops use locks + idempotency; handle 429/503 with backoff+jitter
|
- Automation: queued/scheduled ops use locks + idempotency; handle 429/503 with backoff+jitter
|
||||||
|
|||||||
@ -82,12 +82,17 @@ ## Requirements *(mandatory)*
|
|||||||
(preview/confirmation/audit), tenant isolation, run observability (`OperationRun` type/identity/visibility), and tests.
|
(preview/confirmation/audit), tenant isolation, run observability (`OperationRun` type/identity/visibility), and tests.
|
||||||
If security-relevant DB-only actions intentionally skip `OperationRun`, the spec MUST describe `AuditLog` entries.
|
If security-relevant DB-only actions intentionally skip `OperationRun`, the spec MUST describe `AuditLog` entries.
|
||||||
|
|
||||||
**Constitution alignment (RBAC Standard):** If this feature introduces or changes authorization behavior, the spec MUST:
|
**Constitution alignment (RBAC-UX):** If this feature introduces or changes authorization behavior, the spec MUST:
|
||||||
- state which authorization plane(s) are involved (tenant `/admin/t/{tenant}` vs platform `/system`),
|
- state which authorization plane(s) are involved (tenant `/admin/t/{tenant}` vs platform `/system`),
|
||||||
- ensure any cross-plane access is deny-as-not-found (404),
|
- ensure any cross-plane access is deny-as-not-found (404),
|
||||||
- describe how authorization is enforced server-side (Gates/Policies),
|
- explicitly define 404 vs 403 semantics:
|
||||||
- reference the canonical capability registry (no role-string checks in feature code),
|
- non-member / not entitled to tenant scope → 404 (deny-as-not-found)
|
||||||
- include at least one positive and one negative authorization test.
|
- member but missing capability → 403
|
||||||
|
- describe how authorization is enforced server-side (Gates/Policies) for every mutation/operation-start/credential change,
|
||||||
|
- reference the canonical capability registry (no raw capability strings; no role-string checks in feature code),
|
||||||
|
- ensure global search is tenant-scoped and non-member-safe (no hints; inaccessible results treated as 404 semantics),
|
||||||
|
- ensure destructive-like actions require confirmation (`->requiresConfirmation()`),
|
||||||
|
- include at least one positive and one negative authorization test, and note any RBAC regression tests added/updated.
|
||||||
|
|
||||||
**Constitution alignment (OPS-EX-AUTH-001):** OIDC/SAML login handshakes may perform synchronous outbound HTTP (e.g., token exchange)
|
**Constitution alignment (OPS-EX-AUTH-001):** OIDC/SAML login handshakes may perform synchronous outbound HTTP (e.g., token exchange)
|
||||||
on `/auth/*` endpoints without an `OperationRun`. This MUST NOT be used for Monitoring/Operations pages.
|
on `/auth/*` endpoints without an `OperationRun`. This MUST NOT be used for Monitoring/Operations pages.
|
||||||
|
|||||||
@ -16,7 +16,12 @@ # Tasks: [FEATURE NAME]
|
|||||||
without an `OperationRun`.
|
without an `OperationRun`.
|
||||||
**RBAC**: If this feature introduces or changes authorization, tasks MUST include:
|
**RBAC**: If this feature introduces or changes authorization, tasks MUST include:
|
||||||
- explicit Gate/Policy enforcement for all mutation endpoints/actions,
|
- explicit Gate/Policy enforcement for all mutation endpoints/actions,
|
||||||
- capability registry usage (no role-string checks in feature code),
|
- explicit 404 vs 403 semantics:
|
||||||
|
- non-member / not entitled to tenant scope → 404 (deny-as-not-found)
|
||||||
|
- member but missing capability → 403,
|
||||||
|
- capability registry usage (no raw capability strings; no role-string checks in feature code),
|
||||||
|
- tenant-safe global search scoping (no hints; inaccessible results treated as 404 semantics),
|
||||||
|
- destructive-like actions use `->requiresConfirmation()` (authorization still server-side),
|
||||||
- cross-plane deny-as-not-found (404) checks where applicable,
|
- cross-plane deny-as-not-found (404) checks where applicable,
|
||||||
- at least one positive + one negative authorization test.
|
- at least one positive + one negative authorization test.
|
||||||
**Badges**: If this feature changes status-like badge semantics, tasks MUST use `BadgeCatalog` / `BadgeRenderer` (BADGE-001),
|
**Badges**: If this feature changes status-like badge semantics, tasks MUST use `BadgeCatalog` / `BadgeRenderer` (BADGE-001),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user