TenantAtlas/specs/090-action-surface-contract-compliance/spec.md
ahmido 90bfe1516e feat(spec-090): action surface contract compliance (#108)
Implements Spec 090 (Action Surface Contract Compliance & RBAC Hardening).

Highlights:
- Adds/updates action surface declarations and shrinks baseline exemptions.
- Standardizes Filament action grouping/order and empty-state CTAs.
- Enforces RBAC UX semantics (non-member -> 404, member w/o capability -> disabled + tooltip, server-side 403).
- Adds audit logging for successful side-effect actions.
- Fixes Provider Connections list context so header create + row actions resolve tenant correctly.

Tests (focused):
- vendor/bin/sail artisan test --compact tests/Feature/090/
- vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php
- vendor/bin/sail bin pint --dirty

Livewire/Filament:
- Filament v5 + Livewire v4 compliant.
- No panel provider registration changes (Laravel 11+ registration remains in bootstrap/providers.php).

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #108
2026-02-13 01:30:22 +00:00

18 KiB
Raw Blame History

Feature Specification: Action Surface Contract Compliance & RBAC Hardening

Feature Branch: 090-action-surface-contract-compliance
Created: 2026-02-12
Status: Draft
Input: User description: "Action Surface Contract Compliance & RBAC Hardening"

Clarifications

Session 2026-02-12

  • Q: Should BackupSchedule retention (soft delete / restore / force delete) be included in Spec 090? → A: Defer it to a separate follow-up spec (Spec 090 covers only P0/P1 + empty-state CTAs).
  • Q: Should the system record audit trail entries for denied/cancelled attempts, or only for successful executions? → A: Audit successful executions only.
  • Q: Should row-click navigation be removed, or kept while adding an inspection affordance? → A: Keep row-click navigation where it exists; the inspection affordance may be clickable rows, a primary linked column, or a dedicated “View” action (avoid rendering a lone “View” row action button on read-only lists).

User Scenarios & Testing (mandatory)

User Story 1 - Safe admin actions (Priority: P1)

As an admin, I can only execute actions that create changes or side-effects when I am entitled to the scope (tenant/workspace) and have the required capability.

Why this priority: Prevents unauthorized changes and accidental destructive operations; closes RBAC gaps.

Independent Test: Can be fully tested by attempting a small set of in-scope actions as (a) non-member, (b) member without capability, (c) member with capability.

Acceptance Scenarios:

  1. Given I am not a member of the tenant/workspace scope, When I try to access pages or execute actions in that scope, Then I receive a not found result (deny-as-not-found).
  2. Given I am a member of the tenant/workspace scope but I lack the capability for an action with side-effects, When I attempt the action, Then the UI communicates it is unavailable and direct execution is denied.
  3. Given I am a member of the tenant/workspace scope and I have the capability, When I execute the action, Then the action completes and an audit trail entry is recorded.

User Story 2 - Consistent action surfaces (Priority: P2)

As an admin, I can reliably discover how to inspect and manage records across the admin panel because each list/table provides a visible inspection affordance and consistent action grouping and ordering.

Why this priority: Improves enterprise UX consistency, accessibility, and reduces operator error.

Independent Test: Can be tested by reviewing targeted list/table screens for a clear inspection affordance, consistent ordering, and consistent “More” grouping.

Acceptance Scenarios:

  1. Given a record list/table for an in-scope resource, When I view the tables inspection affordance, Then I can navigate to a record detail page using at least one of: clickable row navigation, a primary linked column, or a dedicated “View” action.
  2. Given a record list/table has row-click navigation, When I cannot (or prefer not to) use row-click navigation, Then I can still navigate to record details using a visible alternative inspection affordance (a primary linked column and/or a dedicated “View” action).
  3. Given a list/table is read-only and “View” would be the only row action, When the UI is rendered, Then it SHOULD avoid rendering a lone “View” row action button and instead use clickable rows or a primary linked column.

User Story 3 - Productive empty states (Priority: P3)

As an admin, when a resource has no records yet, the empty state clearly indicates what to do next and offers a “New …” call-to-action when I am allowed to create records.

Why this priority: Reduces onboarding friction and “dead-end” screens.

Independent Test: Can be tested by visiting empty list/table screens for user-created resources and verifying the create call-to-action is present only when permitted.

Acceptance Scenarios:

  1. Given there are no workspaces yet, When I open the workspaces list, Then I see a create call-to-action if I am allowed to create.
  2. Given there are no backup schedules yet, When I open the backup schedules list, Then I see a create call-to-action if I am allowed to create.

Edge Cases

  • A user attempts to execute a side-effect action via a direct request while the UI action is disabled.
  • Bulk actions: mixed selection where some records are outside scope or not authorized.
  • A destructive action is triggered unintentionally; confirmation must prevent accidental execution.
  • Accessibility: users who cannot use row-click navigation must still discover a usable inspection affordance.
  • Two admins attempt the same side-effect action concurrently; the system must behave predictably (no partial execution without an audit trail).

Requirements (mandatory)

Constitution alignment (required): If this feature introduces any Microsoft Graph calls, any write/change behavior, or any long-running/queued/scheduled work, the spec MUST describe contract registry updates, safety gates (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.

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),
  • ensure any cross-plane access is deny-as-not-found (404),
  • explicitly define 404 vs 403 semantics:
    • non-member / not entitled to workspace scope OR tenant scope → 404 (deny-as-not-found)
    • 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) on /auth/* endpoints without an OperationRun. This MUST NOT be used for Monitoring/Operations pages.

Constitution alignment (BADGE-001): If this feature changes status-like badges (status/outcome/severity/risk/availability/boolean), the spec MUST describe how badge semantics stay centralized (no ad-hoc mappings) and which tests cover any new/changed values.

Constitution alignment (Filament Action Surfaces): If this feature adds or modifies any Filament Resource / RelationManager / Page, the spec MUST include a “UI Action Matrix” (see below) and explicitly state whether the Action Surface Contract is satisfied. If the contract is not satisfied, the spec MUST include an explicit exemption with rationale.

Functional Requirements

  • FR-001 (Scope boundaries): The system MUST preserve deny-as-not-found for tenant/workspace scope boundaries: non-members or not-entitled users MUST receive a not found result for pages and actions in that scope.
  • FR-002 (403 semantics): When a user is a member of the tenant/workspace scope but lacks a required capability, the system MUST deny execution of the action with a forbidden result.
  • FR-003 (UI communication): For members without required capability, the UI MUST communicate that the action is unavailable (disabled state + explanatory hint).
  • FR-004 (Side-effect protection): Any action that creates/updates/deletes data or triggers external side-effects MUST require capability-first gating and MUST be enforced server-side.
  • FR-005 (Destructive confirmations): Destructive actions (archive, deactivate, delete, force delete) MUST require an explicit confirmation step.
  • FR-006 (Inspect affordance): Each in-scope list/table MUST provide a record inspection affordance per record. Accepted forms: clickable row navigation, a primary linked column, or a dedicated “View” action. Where row-click navigation already exists, it SHOULD be preserved; any dedicated “View” action is additive for accessibility and discoverability.
  • FR-007 (Action order and grouping): Row actions MUST follow the baseline order “View → Edit → Secondary → Destructive (last)”, and secondary actions MUST be grouped under a consistently labeled “More” group.
  • FR-008 (Presentation semantics): Sync/run-style actions MUST NOT be presented as destructive.
  • FR-009 (Empty-state CTAs): User-created resources in scope MUST provide an empty-state create call-to-action when the user is allowed to create.
  • FR-010 (Auditability): For every executed side-effect action in scope, the system MUST record an audit trail entry including who performed it, what was attempted, the scope (tenant/workspace), and the outcome.
  • FR-011 (Audit scope): Denied or cancelled attempts MUST NOT be required to create audit trail entries for this feature.

In-scope hotspots

The following hotspots MUST be brought into compliance:

  • Policy “Capture snapshot” action: requires Tenant Sync capability and must be treated as a side-effect action.
  • Workspace CRUD actions: capability-first gating across create/edit and related header actions.
  • Tenant archive/deactivate: destructive confirmation compliance.
  • Provider connections: ensure a visible inspection affordance and consistent “More” grouping/order.
  • Directory groups (Entra groups) and inventory items: verify they remain compliant with the inspection-affordance rule (clickable rows) and do not regress.
  • Findings list: action ordering consistency (View first).

Canonical Capability Mapping (Spec 090)

All capability checks in this feature MUST use constants from App\Support\Auth\Capabilities:

Hotspot / Surface Required capability constant(s)
Policy list + view: “Sync from Intune”, “Capture snapshot” Capabilities::TENANT_SYNC
Findings acknowledge actions (row, bulk, list-header mass acknowledge) Capabilities::TENANT_FINDINGS_ACKNOWLEDGE
Backup schedules: create/edit/delete Capabilities::TENANT_BACKUP_SCHEDULES_MANAGE
Backup schedules: run/retry (row + bulk) Capabilities::TENANT_BACKUP_SCHEDULES_RUN
Provider connections: create/edit/credentials/default/enable/disable Capabilities::PROVIDER_MANAGE
Provider connections: check connection / inventory sync / compliance snapshot Capabilities::PROVIDER_RUN
Tenants: edit/admin consent Capabilities::TENANT_MANAGE
Tenants: deactivate/force delete/restore Capabilities::TENANT_DELETE
Tenants: sync Capabilities::TENANT_SYNC
Workspaces: create/edit Capabilities::WORKSPACE_MANAGE

UI Action Matrix (mandatory when Filament is changed)

If this feature adds/modifies any Filament Resource / RelationManager / Page, fill out the matrix below.

For each surface, list the user-facing actions (intent) and note the label when it is explicitly customized. Do not rely on framework-default labels being stable across versions.

Also capture whether actions are destructive (confirmation? typed confirmation?), RBAC gating (capability + enforcement helper), and whether the mutation writes an audit log.

| Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions | |---|---|---|---|---|---|---|---|---|---| | Policies (list) | Tenant panel (tenant scope) | “Sync from Intune” | Dedicated “View” row action | Visible: “View”; Group: “More” → “Ignore” / “Restore” / “Sync” / “Export to Backup” | Group: “More” → “Ignore Policies” / “Restore Policies” / “Sync Policies” / “Export to Backup” | “Sync from Intune” (same as header) | — | — | Yes | Sync/run-style actions must not be presented as destructive; side-effect actions are capability-gated and enforced server-side. | Policy (view) | Tenant panel (tenant scope) | — | — (view page) | — | — | — | “Capture snapshot” (confirmation) | — | Yes | Capture snapshot is treated as a side-effect action. | Workspaces (list + CRUD) | Admin panel (workspace scope) | Create workspace (Create action) | Dedicated “View” row action | Visible: “View” / “Edit” | — | (If table is empty) Create workspace | — | Save + Cancel | Yes | Ensure capability-first gating for create/edit and consistent action ordering. | Tenants (list) | Admin panel (platform scope) | — | Dedicated “View” row action (label: “View”) | Action group (ellipsis) containing: “View” / “Sync” / “Open” / “Edit” / “Restore” / “Admin consent” / “Open in Entra” / “Verify configuration” / “Deactivate” / “Force delete” | “Sync selected” | — | — | Save + Cancel | Yes | Destructive actions (“Deactivate”, “Force delete”) require confirmation; side-effect actions (“Sync”, “Verify configuration”) require capability gating. | Provider connections (list) | Admin panel (platform scope; tenant-filtered) | Create provider connection (Create action) | Clickable rows (record URL to view) | Action group (target label: “More”) containing: “Edit” / “Check connection” / “Inventory sync” / “Compliance snapshot” / “Set as default” / “Update credentials” / “Enable connection” / “Disable connection” | — | (If table is empty) Create provider connection | — | Save + Cancel | Yes | Current code uses a group label “Actions”; normalize to “More” to match FR-007. | Directory groups (Entra groups list) | Admin panel (tenant scope) | None (intentionally) | Clickable rows (record URL) | None (read-only list) | None | None | — | — | No | Inspection affordance is clickable rows; no row actions. | Inventory items (list) | Admin panel (tenant scope) | None (intentionally) | Clickable rows (record URL) | None (read-only list) | None | None | — | — | No | Inspection affordance is clickable rows; no row actions. | Findings (list) | Tenant panel (tenant scope) | — | Dedicated “View” row action | Visible: “View”; Secondary: “Acknowledge” (confirmation) | Group: “Acknowledge selected” (confirmation) | — | — | — | Yes | Action ordering must match baseline (View first; secondary actions grouped). | Backup schedules (list) | Tenant panel (tenant scope) | Create backup schedule (Create action) | “Edit” (opens record details/edit form) | Action group (ellipsis) containing: “Run now” / “Retry” / “Edit” / “Delete” | Group: “Run now” / “Retry” / “Delete” | (If table is empty) Create backup schedule | — | Save + Cancel | Yes | Retention/archival is deferred; destructive actions (“Delete”, bulk delete) require confirmation.

Key Entities (include if feature involves data)

  • Capability: A named permission that grants access to a class of actions (e.g., “Tenant Sync”, “Workspace Manage”).
  • Scope entitlement: Whether a user is a member of / entitled to a tenant or workspace.
  • Admin action surface: Where a user can discover and trigger an action (header, row actions, bulk actions, empty state).
  • Destructive action: An action that archives, deactivates, deletes, or force deletes data.
  • Audit trail entry: A record of an attempted or completed action, including actor, scope, and outcome.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001 (Contract compliance): 100% of the in-scope resources satisfy Action Surface Contract v1 (clear inspection affordance, consistent “More” group, correct action ordering).
  • SC-002 (RBAC hardening): 100% of in-scope side-effect actions are denied for members without capability and are deny-as-not-found for non-members.
  • SC-003 (Confirmation compliance): 100% of in-scope destructive actions require confirmation prior to execution.
  • SC-004 (Discoverability): For each in-scope list/table, at least one inspection affordance is clearly visible and usable to access record details (clickable rows, a primary linked column, and/or a dedicated “View” action).
  • SC-005 (Auditability): 100% of executed in-scope side-effect actions produce an audit trail entry with actor + scope + outcome.

Assumptions

  • Capability names used in this spec map to the canonical capability registry.
  • “Capture snapshot” is considered a side-effect action and therefore requires both confirmation and capability gating.
  • BackupSchedule retention (soft delete / restore / force delete) is explicitly deferred to a follow-up spec.
  • Existing row-click navigation patterns should remain unchanged; this feature ensures a clear inspection affordance (clickable rows, primary linked columns, or a dedicated “View” action where appropriate).

Out of Scope

  • Navigation or information architecture redesign.
  • Broad refactors of policies/capabilities outside the listed hotspots.
  • Changing the established 404 vs 403 boundary semantics.
  • BackupSchedule retention behavior changes (soft delete, restore, force delete).

Rollout Notes

  • This change primarily affects user experience and authorization enforcement; it should be safe to roll out behind existing access controls.
  • Optional retention/archival behavior (if introduced later) requires a separate rollout decision.

Testing Notes

  • Add at least one positive and one negative authorization test per critical hotspot.
  • Add regression assertions that each in-scope list/table has a clear inspection affordance and consistent ordering.
  • Verify that denied attempts do not create audit trail entries for this feature.