TenantAtlas/specs/276-support-access-governance/plan.md
Ahmed Darrazi 37105653a1
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m29s
feat(spec-276): implement support access governance — commit all changes
2026-05-05 22:17:14 +02:00

23 KiB
Raw Blame History

Implementation Plan: Enterprise Access Boundary & Support Access Governance v1

Branch: 276-support-access-governance | Date: 2026-05-05 | Spec: spec.md Input: Feature specification from specs/276-support-access-governance/spec.md

Summary

Prepare one bounded support-access governance slice on top of the repos current system support and recovery seams. The narrow implementation path is to introduce one workspace-owned support-access grant history with exactly two scopes, reuse the current system workspace detail page as the request and active-state surface, reuse workspace settings as the owner-approval surface, extend existing system and admin audit views for support-access history, and harden the existing owner-repair utility so it requires both active break-glass and an active recovery-scoped support grant.

This slice stays explicitly narrow. Filament remains v5 on Livewire v4, panel-provider registration stays in apps/platform/bootstrap/providers.php, no new globally searchable resource is introduced, and no asset registration change is expected. The plan does not create impersonation, a delegated admin browsing bridge, SCIM, or a second support console.

Inherited Baseline / Explicit Delta

Inherited baseline

  • BreakGlassSession, the system dashboard break-glass actions, and the current system break-glass banner already provide a global emergency recovery control with TTL and audit.
  • RepairWorkspaceOwners already exposes the current owner-repair utility and audit behavior, but today it only requires platform capability plus active break-glass.
  • ViewWorkspace already acts as the system-plane workspace detail surface and already owns bounded workspace-scoped admin actions.
  • WorkspaceSettings already acts as the admin-plane workspace singleton page and already supports workspace-owner-only actions.
  • AuditLog already acts as the admin-plane customer-visible history surface.
  • AccessLogs already acts as the system security history surface for platform auth and break-glass events.

Explicit delta in this plan

  • Add one workspace-owned support-access grant history with bounded lifecycle and expiry.
  • Add one support-scope catalog with exactly audit_view and workspace_recovery.
  • Add one shared SupportAccessGrantResolver or manager so current detail, settings, recovery, and history surfaces consume the same support-access truth.
  • Add a request and end flow on ViewWorkspace.
  • Add owner approval or denial for workspace_recovery on WorkspaceSettings.
  • Extend AuditLog with a support-access filter and export path.
  • Extend AccessLogs with support-access lifecycle events.
  • Refactor RepairWorkspaceOwners so owner repair requires both active break-glass and an active recovery-scoped support grant for the chosen workspace.

Technical Context

Language/Version: PHP 8.4, Laravel 12
Primary Dependencies: Filament v5, Livewire v4, Pest v4, existing BreakGlassSession, existing audit infrastructure, existing workspace settings and system workspace detail surfaces
Storage: PostgreSQL via a new workspace-owned support_access_grants table plus existing audit_logs and current session-backed break-glass state
Testing: Pest v4 Unit plus focused Feature coverage
Validation Lanes: fast-feedback, confidence Target Platform: Laravel monolith in apps/platform, reusing existing admin and system Filament pages
Project Type: Web application (Laravel monolith with Filament panels)
Performance Goals: no new queue family, no Graph calls, and DB-only support-access resolution on current detail, settings, and history surfaces
Constraints: no impersonation, no delegated admin browsing bridge, no SCIM, no new support console, no new global-search resource, and no asset registration changes
Scale/Scope: 1 new workspace-owned entity, 1 bounded resolver or manager, 4 existing page families, and focused extensions to existing auth or audit tests

Likely Affected Repo Surfaces

  • apps/platform/app/Models/SupportAccessGrant.php as the new workspace-owned grant model.
  • apps/platform/database/migrations/*_create_support_access_grants_table.php for new persistence.
  • apps/platform/database/factories/SupportAccessGrantFactory.php for bounded test setup.
  • apps/platform/app/Services/Auth/SupportAccessGrantResolver.php and SupportAccessGrantManager.php as the shared lifecycle and mutation layer.
  • apps/platform/app/Filament/System/Pages/Directory/ViewWorkspace.php for request, end, and active-state summary.
  • apps/platform/app/Filament/System/Pages/RepairWorkspaceOwners.php for the combined support-access plus break-glass recovery boundary.
  • apps/platform/app/Filament/System/Pages/Security/AccessLogs.php for system-side support-access history.
  • apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.php for owner approval or denial and a current support-access summary.
  • apps/platform/app/Filament/Pages/Monitoring/AuditLog.php for the support-access filter and export path.
  • apps/platform/app/Support/Auth/PlatformCapabilities.php for new bounded platform-side support-access manage capability.
  • apps/platform/app/Support/Audit/AuditActionId.php, WorkspaceAuditLogger, and SystemConsoleAuditLogger for stable support-access audit action IDs and structured metadata.
  • apps/platform/tests/Unit/System/SupportAccessGrantResolverTest.php plus focused system, auth, settings, monitoring, and access-log feature tests.

Support Access Fit

  • Treat support access as a workspace-owned governance truth, not as an extension of BreakGlassSession.
  • Keep exactly two scopes in v1 so the slice stays on current repo-real support work:
    • audit_view
    • workspace_recovery
  • Keep support-access lifecycle distinct from break-glass lifecycle.
  • Keep owner repair as the one high-risk mutation that requires both active break-glass and active recovery-scoped support access.
  • Keep admin history export on the current audit surface rather than adding a second support-history page.

UI / Filament & Livewire Fit

  • Existing operator-facing surfaces remain native Filament surfaces under Livewire v4.
  • No new Filament resource or globally searchable resource is required; current pages are sufficient.
  • ViewWorkspace keeps one dominant support-access action family: request or end support access.
  • WorkspaceSettings keeps approval scoped to pending workspace_recovery requests and must not become a second platform-control plane.
  • AuditLog and AccessLogs stay read-only history surfaces and only expand their filter or event scope.
  • Provider registration remains unchanged in apps/platform/bootstrap/providers.php, and no new asset strategy is planned. If a later shared asset becomes necessary, deployment remains the standard cd apps/platform && php artisan filament:assets path.

RBAC / Policy Fit

  • Workspace and tenant membership remain the primary admin-plane isolation boundaries. Wrong-plane or non-member requests stay 404; in-scope actors missing capability stay 403.
  • Platform-side request and end actions should use one new bounded PlatformCapabilities::SUPPORT_ACCESS_MANAGE capability instead of reusing broad console visibility alone.
  • Workspace-owner approval should remain on WorkspaceSettings and should reuse existing owner-level manage semantics rather than adding a separate customer support role.
  • AuditLog export remains tied to the current admin-plane audit view capability.
  • Business-state blocking on the recovery page must remain distinguishable from authorization failure.

Audit / Logging Fit

  • Every support-access request, approval, denial, activation, expiry, end, and ownerless waiver must write a stable audit action ID with structured metadata.
  • AuditLog remains the customer-visible history substrate.
  • AccessLogs remains the system-side security history substrate and expands to include support-access events.
  • No second audit subsystem is needed.

Data & Query Fit

  • support_access_grants.workspace_id must be NOT NULL and indexed.
  • Prevent overlapping requested or active grants for the same workspace, platform actor, and scope.
  • Keep the v1 table bounded to the fields in data-model.md; do not add broad ticketing, provider, or impersonation fields.
  • SupportAccessGrantResolver should expose a single current summary for the active workspace plus current page context.
  • RepairWorkspaceOwners should query only the targeted workspaces active recovery grant, not scan across workspaces.

UI / Surface Guardrail Plan

  • Guardrail scope: changed surfaces
  • Native vs custom classification summary: native Filament
  • Shared-family relevance: system detail summaries, workspace settings approvals, audit-history filters, system security history, and recovery state messaging
  • State layers in scope: page, detail
  • Audience modes in scope: operator-MSP, support-platform
  • Decision/diagnostic/raw hierarchy plan: decision-first, diagnostics-second, support-raw-third
  • Raw/support gating plan: raw audit detail remains on existing history surfaces; default-visible content stays on current support posture and approval need
  • One-primary-action / duplicate-truth control: ViewWorkspace remains the one place to start or end support access; WorkspaceSettings remains the one place to approve or deny risky recovery; history pages explain rather than re-decide
  • Handling modes by drift class or surface: review-mandatory
  • Repository-signal treatment: review-mandatory now; future hard-stop candidate if a second support console or impersonation bridge appears inside this slice
  • Special surface test profiles: standard-native-filament, shared-detail-family, monitoring-state-page, exception-coded-surface
  • Required tests or manual smoke: functional-core, state-contract, exception-fallback
  • Exception path and spread control: the recovery page remains the named separately governed exception and must not spread its combined prerequisite logic to unrelated surfaces
  • Active feature PR close-out entry: Guardrail

Shared Pattern & System Fit

  • Cross-cutting feature marker: yes
  • Systems touched: ViewWorkspace, WorkspaceSettings, AuditLog, AccessLogs, RepairWorkspaceOwners, BreakGlassSession, audit action IDs, and current audit loggers
  • Shared abstractions reused: current system detail pattern, current singleton settings pattern, current admin audit history, current system access logs, and current audit infrastructure
  • New abstraction introduced? why?: one bounded SupportAccessGrantResolver or manager, because current repo truth has no support-access lifecycle abstraction and several surfaces need the same grant state and dedupe rules
  • Why the existing abstraction was sufficient or insufficient: current break-glass and audit abstractions are sufficient for emergency recovery and history rendering, but insufficient for one workspace-scoped ordinary support-access lifecycle with approval and expiry
  • Bounded deviation / spread control: no local page-specific support-access helper is allowed outside the shared resolver or manager path

OperationRun UX Impact

  • Touches OperationRun start/completion/link UX?: no
  • Central contract reused: N/A
  • Delegated UX behaviors: N/A
  • Surface-owned behavior kept local: request or approval inputs only
  • Queued DB-notification policy: N/A
  • Terminal notification path: N/A
  • Exception path: none

Provider Boundary & Portability Fit

  • Shared provider/platform boundary touched?: no
  • Provider-owned seams: none in this slice
  • Platform-core seams: support-access grant truth, approval flow, break-glass separation, and workspace-scoped history
  • Neutral platform terms / contracts preserved: support access, break-glass, workspace recovery, audit trail review
  • Retained provider-specific semantics and why: none
  • Bounded extraction or follow-up path: future delegated support or impersonation only if promoted by a separate spec

Constitution Check

GATE: Must pass before implementation begins and again before merge.

  • Inventory-first / snapshot truth: PASS. This slice does not change tenant inventory or snapshot semantics.
  • Read/write separation: PASS. Every mutation is bounded, confirmation-protected where high risk, and audit-backed.
  • Graph contract path: PASS. No Graph or provider calls are introduced.
  • Deterministic capabilities: PASS. Existing canonical capability registries remain authoritative.
  • Workspace and tenant isolation: PASS. Workspace context and wrong-plane 404 remain unchanged.
  • RBAC-UX plane separation: PASS. /system handles request or end; /admin handles approval or history.
  • Destructive action discipline: PASS. High-risk approval and recovery remain confirmation-aware.
  • Global search safety: PASS. No new searchable resource is added.
  • OperationRun / Ops-UX: PASS. No new run family or OperationRun start surface is introduced.
  • Data minimization: PASS. The new entity stores bounded support-access truth only.
  • Test governance: PASS. Proof remains in one new unit family plus focused feature families.
  • Proportionality / no premature abstraction: PASS. One new entity and one bounded resolver or manager are the narrowest viable path.
  • Persisted truth: PASS. The new table represents independent product truth with its own lifecycle and audit need.
  • Behavioral state: PASS. Grant status and approval mode change recovery behavior, expiry, and audit outcomes.
  • Shared pattern first / UI semantics / Filament-native UI: PASS. Existing detail, settings, recovery, and history surfaces remain authoritative.
  • Provider boundary: PASS. No provider-specific vocabulary or dependency is added.
  • Filament / Laravel planning contract: PASS. Filament stays v5 on Livewire v4, provider registration remains in apps/platform/bootstrap/providers.php, no globally searchable resource is added, and no asset registration change is planned.

Gate evaluation: PASS.

Post-design re-check: PASS. research.md, data-model.md, quickstart.md, contracts/workspace-support-access-governance.logical.openapi.yaml, checklists/requirements.md, and tasks.md are present and aligned with the package.

Test Governance Check

  • Test purpose / classification by changed surface: Unit for grant lifecycle, expiry, and dedupe rules; Feature for system detail request flow, owner approval, recovery boundary, and history surfaces
  • Affected validation lanes: fast-feedback, confidence
  • Why this lane mix is the narrowest sufficient proof: the slice reuses native Filament and current audit surfaces, so focused unit and feature tests can prove the new truth without browser automation
  • Narrowest proving command(s):
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/System/SupportAccessGrantResolverTest.php
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/System/SupportAccessRequestFlowTest.php tests/Feature/System/SupportAccessRecoveryBoundaryTest.php tests/Feature/Auth/BreakGlassModeTest.php tests/Feature/Auth/BreakGlassWorkspaceOwnerRecoveryTest.php tests/Feature/System/Spec114/AccessLogsTest.php
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/Settings/WorkspaceSupportAccessApprovalTest.php tests/Feature/Monitoring/AuditLogSupportAccessHistoryTest.php
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
  • Fixture / helper / factory / seed / context cost risks: moderate but contained; one new factory is needed, but existing platform user, workspace, membership, and audit fixtures can be reused
  • Expensive defaults or shared helper growth introduced?: no
  • Heavy-family additions, promotions, or visibility changes: none planned
  • Surface-class relief / special coverage rule: standard-native-filament relief for detail, settings, and history surfaces; exception-coded coverage for the recovery boundary
  • Closing validation and reviewer handoff: reviewers should rely on the exact commands above, confirm that no impersonation bridge or second console appears, verify that recovery still needs active break-glass plus active recovery support access, and verify that support history export remains workspace-safe
  • Budget / baseline / trend follow-up: none expected beyond a small feature-local increase
  • Review-stop questions: did the slice add more than two support scopes, did it bypass break-glass on recovery, did it create a second history surface, and did it let admin history leak outside the workspace scope
  • Escalation path: document-in-feature for contained naming drift; reject-or-split if the slice widens into impersonation, SCIM, or a second support console
  • Active feature PR close-out entry: Guardrail
  • Why no dedicated follow-up spec is needed: routine support-access upkeep should stay inside this feature unless future delegated support or impersonation is explicitly promoted as a separate slice
  • Test-governance outcome: keep

Review Checklist Status

  • Review checklist artifact: checklists/requirements.md
  • Review outcome class: acceptable-special-case
  • Workflow outcome: keep
  • Test-governance outcome: keep
  • Escalation rule: if implementation adds admin-plane browsing, impersonation, SCIM, or a second support console, flip the workflow outcome to split before continuing

Rollout Considerations

  • Land persistence and shared resolver or manager first.
  • Add workspace detail request or end flow next.
  • Add workspace-owner approval next.
  • Harden recovery enforcement only after support-access truth exists.
  • Add history filter and export last so the customer-visible trail reflects the final lifecycle semantics.
  • Keep Filament v5 on Livewire v4, provider registration in apps/platform/bootstrap/providers.php, global search unchanged, and assets unchanged.

Risk Controls

  • Reject any implementation that adds impersonation or delegated admin browsing.
  • Reject any implementation that lets workspace_recovery proceed without active break-glass.
  • Reject any implementation that adds more than the two scoped support capabilities in this slice.
  • Reject any implementation that creates a second support history or approval surface outside the current detail, settings, and audit pages.
  • Reject browser-heavy proof as the default validation lane.

Research & Design Outputs

  • research.md resolves the key design choices: workspace-scoped grants, two-scope catalog, recovery plus break-glass coupling, existing-surface reuse, and admin history export.
  • data-model.md records the new grant entity, state and approval semantics, dedupe rule, and derived summary shape.
  • quickstart.md provides the bounded reviewer flow, explicit approval and waiver expectations, and focused validation commands.
  • contracts/workspace-support-access-governance.logical.openapi.yaml captures the logical route and action boundaries for request, approval, end, history, export, and recovery gating.
  • checklists/requirements.md records the prep-time review outcome, workflow outcome, and test-governance outcome.
  • tasks.md keeps implementation bounded to current support and recovery surfaces.

Project Structure

Documentation (this feature)

specs/276-support-access-governance/
├── checklists/
│   └── requirements.md
├── contracts/
│   └── workspace-support-access-governance.logical.openapi.yaml
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
└── tasks.md

Source Code (expected implementation surfaces)

apps/platform/
├── app/
│   ├── Filament/
│   │   ├── Pages/
│   │   │   ├── Monitoring/
│   │   │   │   └── AuditLog.php
│   │   │   └── Settings/
│   │   │       └── WorkspaceSettings.php
│   │   └── System/Pages/
│   │       ├── Directory/
│   │       │   └── ViewWorkspace.php
│   │       ├── RepairWorkspaceOwners.php
│   │       └── Security/
│   │           └── AccessLogs.php
│   ├── Models/
│   │   └── SupportAccessGrant.php
│   ├── Services/
│   │   ├── Audit/
│   │   │   └── WorkspaceAuditLogger.php
│   │   ├── Auth/
│   │   │   ├── BreakGlassSession.php
│   │   │   ├── SupportAccessGrantManager.php
│   │   │   └── SupportAccessGrantResolver.php
│   │   └── SystemConsole/
│   │       └── SystemConsoleAuditLogger.php
│   └── Support/
│       ├── Audit/
│       │   └── AuditActionId.php
│       └── Auth/
│           └── PlatformCapabilities.php
├── database/
│   ├── factories/
│   │   └── SupportAccessGrantFactory.php
│   └── migrations/
│       └── *_create_support_access_grants_table.php
└── tests/
    ├── Feature/
    │   ├── Auth/
    │   │   ├── BreakGlassModeTest.php
    │   │   └── BreakGlassWorkspaceOwnerRecoveryTest.php
    │   ├── Filament/Settings/
    │   │   └── WorkspaceSupportAccessApprovalTest.php
    │   ├── Monitoring/
    │   │   └── AuditLogSupportAccessHistoryTest.php
    │   └── System/
    │       ├── Spec114/AccessLogsTest.php
    │       ├── SupportAccessRecoveryBoundaryTest.php
    │       └── SupportAccessRequestFlowTest.php
    └── Unit/
        └── System/
            └── SupportAccessGrantResolverTest.php

Complexity Tracking

Violation Why Needed Simpler Alternative Rejected Because
New persisted support-access entity Support access now needs its own lifecycle, expiry, and approval lineage Session-only or audit-log-only approaches could not gate recovery and customer-visible approval safely

Proportionality Review

  • Current operator problem: current support and recovery seams lack one bounded workspace-scoped support lifecycle that is both customer-visible and strong enough to gate recovery
  • Existing structure is insufficient because: BreakGlassSession is global and current pages can only infer support state indirectly through scattered audit events
  • Narrowest correct implementation: one grant history table plus one shared resolver or manager, added to the current system detail, settings, history, and recovery pages only
  • Ownership cost: one new entity, one new resolver or manager, one new factory, one migration, and focused tests
  • Alternative intentionally rejected: break-glass-only governance and broad impersonation bridge
  • Release truth: current-release truth with bounded future preparation only