TenantAtlas/specs/061-provider-foundation/tasks.md
ahmido a0ed9e24c5 feat: unify provider connection actions and notifications (#73)
## Summary
- introduce the Provider Connection Filament resource (list/create/edit) with DB-only controls, grouped action dropdowns, and badge-driven status/health rendering
- wire up the provider foundation stack (migrations, models, policies, providers, operations, badges, and audits) plus the required spec docs/checklists
- standardize Inventory Sync notifications so the job no longer writes its own DB rows; terminal notifications now flow exclusively through OperationRunCompleted while the start surface still shows the queued toast

## Testing
- ./vendor/bin/sail php ./vendor/bin/pint --dirty
- ./vendor/bin/sail artisan test tests/Unit/Badges/ProviderConnectionBadgesTest.php
- ./vendor/bin/sail artisan test tests/Feature/ProviderConnections tests/Feature/Filament/ProviderConnectionsDbOnlyTest.php
- ./vendor/bin/sail artisan test tests/Feature/Inventory/RunInventorySyncJobTest.php tests/Feature/Inventory/InventorySyncStartSurfaceTest.php

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #73
2026-01-25 01:01:37 +00:00

17 KiB
Raw Blame History

description
Task list for Provider Foundation v1

Tasks: Provider Foundation v1 (Microsoft-first, Security-first)

Input: Design documents from /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/
Prerequisites: /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/plan.md (required), /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/spec.md (required), /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/research.md, /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/data-model.md, /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/contracts/, /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/quickstart.md

Tests: REQUIRED (Pest) for runtime behavior changes
Operations: Provider operations MUST create/reuse a canonical OperationRun, be enqueue-only, and keep Monitoring/ProviderConnections pages DB-only at render/poll time
Badges: If ProviderConnection status/health is rendered as a badge, use BadgeCatalog / BadgeRenderer (BADGE-001) and add mapping tests

Organization: Tasks are grouped by user story (US1, US2, US3) to enable independent delivery.

Phase 1: Setup (Shared Infrastructure)

Purpose: Prepare local environment + validate baseline

  • T001 Start containers with ./vendor/bin/sail up -d (script: ./vendor/bin/sail)
  • T002 Run baseline Ops-UX DB-only tests with ./vendor/bin/sail artisan test tests/Feature/Monitoring/OperationsDbOnlyTest.php (test: tests/Feature/Monitoring/OperationsDbOnlyTest.php)
  • T003 [P] Review existing idempotency + run tracking patterns in app/Services/OperationRunService.php and app/Jobs/Middleware/TrackOperationRun.php

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Core provider foundation that all stories depend on (schema, models, policies, ops primitives)

Checkpoint: Migrations + models + policies exist; provider operation types are registered; shared run-gating utilities exist

  • T004 Create provider connections migration in database/migrations/2026_01_24_000001_create_provider_connections_table.php
  • T005 Create provider credentials migration in database/migrations/2026_01_24_000002_create_provider_credentials_table.php
  • T005a Add DB-level invariant: partial unique index ensuring only one default per (tenant_id, provider) (example: unique (tenant_id, provider) WHERE is_default = true; ensure default flipping is atomic/transactional)
  • T006 [P] Create App\Models\ProviderConnection in app/Models/ProviderConnection.php (relations, casts, default-connection invariant)
  • T007 [P] Create App\Models\ProviderCredential in app/Models/ProviderCredential.php (encrypted payload cast, hidden attributes, 1:1 relation)
  • T008 [P] Add tenant relationship for connections in app/Models/Tenant.php (e.g., providerConnections() / providerCredentials() as needed)
  • T009 [P] Add factories in database/factories/ProviderConnectionFactory.php and database/factories/ProviderCredentialFactory.php
  • T010 Create authorization policy + gates for provider.view, provider.manage, provider.run (capabilities-first; tenant-scoped). Map roles to capabilities: Owner/Manager=view+manage+run; Operator=view+run; Readonly=view only. No role == X checks in feature code.
  • T010b [P] Add RBAC capability tests in tests/Feature/ProviderConnections/ProviderRbacCapabilitiesTest.php (Operator can start operations but cannot manage; Readonly is view-only)
  • T011 Register the policy + gates in app/Providers/AuthServiceProvider.php (create it and register in bootstrap/providers.php if missing; otherwise use the projects canonical policy registration provider)
  • T012 Add provider operation labels in app/Support/OperationCatalog.php using canonical operation types: provider.connection.check, inventory.sync, compliance.snapshot (ensure UI/actions/jobs use these exact strings; update tests/Feature/OpsUx/OperationCatalogCoverageTest.php to detect multi-dot types)
  • T013 Add provider related links in app/Support/OperationRunLinks.php (link provider runs to Provider Connections pages when context.provider_connection_id exists)
  • T014 Create provider operation registry in app/Services/Providers/ProviderOperationRegistry.php (central allowlist + metadata for v1 operations)
  • T014a [P] Define provider capability interfaces + DTOs in app/Services/Providers/Contracts/ProviderHealthCheck.php, app/Services/Providers/Contracts/HealthResult.php, app/Services/Providers/Contracts/ProviderInventoryCollector.php, app/Services/Providers/Contracts/ProviderComplianceCollector.php, app/Services/Providers/Contracts/ProviderDirectoryCollector.php, app/Services/Providers/Contracts/ProviderScriptExecutor.php
  • T014b [P] Implement credential retrieval/rotation service in app/Services/Providers/CredentialManager.php (reads provider_credentials, validates required keys, never logs decrypted payload)
  • T014c [P] Implement provider gateway in app/Services/Providers/ProviderGateway.php (build Graph request context from ProviderConnection + CredentialManager, centralize correlation IDs + failure mapping, call GraphClientInterface)
  • T014d Enable Graph client binding for per-request credentials in config/graph.php and app/Providers/AppServiceProvider.php (e.g., GRAPH_ENABLED override; do not require env client_secret for binding when ProviderGateway supplies request context)
  • T014e [P] Add unit tests for provider gateway + credential manager in tests/Unit/Providers/CredentialManagerTest.php and tests/Unit/Providers/ProviderGatewayTest.php
  • T015 Create run gating service in app/Services/Providers/ProviderOperationStartGate.php (DB transaction + lockForUpdate() on ProviderConnection; dedupe same-operation; block different-operation as “scope busy”; returns active-run link)
  • T016 [P] Extend failure sanitization in app/Support/OpsUx/RunFailureSanitizer.php (provider auth/throttling/outage reason codes + stronger secret redaction)
  • T017 [P] Add unit tests for failure sanitization in tests/Unit/OpsUx/RunFailureSanitizerTest.php
  • T018 [P] Add unit tests for run gating in tests/Unit/Providers/ProviderOperationStartGateTest.php
  • T019 Run foundational tests with ./vendor/bin/sail artisan test tests/Unit/OpsUx/RunFailureSanitizerTest.php (test: tests/Unit/OpsUx/RunFailureSanitizerTest.php)

Phase 3: User Story 1 — Set up a provider connection safely (Priority: P1) 🎯 MVP

Goal: Owner/Manager can create/manage Microsoft provider connections, attach credentials, set a default connection, and never expose secrets.

Independent Test: An Owner/Manager can create a connection + credentials, later view/edit it, and no secret values are displayed or leaked; pages remain DB-only at render/poll time.

Tests for User Story 1

  • T020 [P] [US1] Add DB-only render test for Provider Connections in tests/Feature/Filament/ProviderConnectionsDbOnlyTest.php
  • T021 [P] [US1] Add role authorization test in tests/Feature/ProviderConnections/ProviderConnectionAuthorizationTest.php
  • T022 [P] [US1] Add credential encryption/non-disclosure test in tests/Feature/ProviderConnections/ProviderCredentialSecurityTest.php
  • T022b [P] [US1] Add credential leak guard test in tests/Feature/ProviderConnections/CredentialLeakGuardTest.php (assert no secrets appear in OperationRun failure records or captured logs; forbidden substrings: client_secret, Bearer , access_token, refresh_token, Authorization)

Implementation for User Story 1

  • T023 [US1] Create Filament resource skeleton in app/Filament/Resources/ProviderConnectionResource.php
  • T024 [P] [US1] Create pages in app/Filament/Resources/ProviderConnectionResource/Pages/ListProviderConnections.php, app/Filament/Resources/ProviderConnectionResource/Pages/CreateProviderConnection.php, app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php
  • T025 [US1] Implement list/table + filters in app/Filament/Resources/ProviderConnectionResource.php (tenant-scoped; DB-only)
  • T026 [US1] Implement create/edit forms in app/Filament/Resources/ProviderConnectionResource.php (provider=microsoft, entra_tenant_id, display_name, is_default, status/health read-only fields)
  • T027 [US1] Implement credential upsert action (Owner/Manager only; secrets never shown) in app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php
  • T028 [US1] Implement disable connection action with confirmation + audit log in app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php
  • T029 [US1] Write audit log entries for connection + credential changes using app/Services/Intune/AuditLogger.php (called from app/Filament/Resources/ProviderConnectionResource/Pages/CreateProviderConnection.php and app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php)
  • T030 [US1] Run story tests with ./vendor/bin/sail artisan test tests/Feature/ProviderConnections/ProviderConnectionAuthorizationTest.php (test: tests/Feature/ProviderConnections/ProviderConnectionAuthorizationTest.php)

Phase 4: User Story 2 — Verify connection health without blocking the UI (Priority: P2)

Goal: Owner/Manager/Operator can enqueue a health check that creates an OperationRun, updates health state, and shows stable reason codes/messages on failure.

Independent Test: Clicking “Check connection” enqueues exactly one run (dedupe), never calls Graph in the request cycle, and produces a visible run outcome + updates connection health.

Tests for User Story 2

  • T031 [P] [US2] Add start-surface test (no Graph in request; job queued; run created) in tests/Feature/ProviderConnections/ProviderConnectionHealthCheckStartSurfaceTest.php
  • T032 [P] [US2] Add job behavior test (success + categorized failure) in tests/Feature/ProviderConnections/ProviderConnectionHealthCheckJobTest.php
  • T032b [P] [US2] Assert OperationRun context contract for connection health checks in tests/Feature/ProviderConnections/ProviderConnectionHealthCheckStartSurfaceTest.php (context.provider, context.module, context.provider_connection_id, context.target_scope.entra_tenant_id)

Implementation for User Story 2

  • T033 [US2] Add “Check connection” Filament action (enqueue-only) in app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php (MUST call ProviderOperationStartGate first: same-operation returns existing active run; different-operation for same scope blocks “scope busy” + link to active run)
  • T034 [US2] Create queued job in app/Jobs/ProviderConnectionHealthCheckJob.php (uses app/Jobs/Middleware/TrackOperationRun.php, updates provider_connections health fields, updates operation_runs)
  • T035 [US2] Create health check module in app/Services/Providers/MicrosoftProviderHealthCheck.php (implements app/Services/Providers/Contracts/ProviderHealthCheck.php, uses ProviderGateway, maps failures to reason codes via app/Support/OpsUx/RunFailureSanitizer.php)
  • T035b [P] [US2] Ensure health check uses ProviderConnection context (entra_tenant_id) and obtains tokens via ProviderGateway/CredentialManager (ProviderGateway is the only decryptor; no secrets in config/env beyond bootstrap)
  • T036 [US2] Run story tests with ./vendor/bin/sail artisan test tests/Feature/ProviderConnections/ProviderConnectionHealthCheckStartSurfaceTest.php (test: tests/Feature/ProviderConnections/ProviderConnectionHealthCheckStartSurfaceTest.php)

Phase 5: User Story 3 — Run provider operations with safety and observability (Priority: P3)

Goal: Owner/Manager/Operator can run provider operations (inventory + compliance snapshot) as observable runs, with per-scope concurrency rules (dedupe vs scope-busy) and summary counts.

Independent Test: Starting inventory/compliance creates runs, obeys dedupe/scope-busy rules, never calls Graph in the request cycle, and writes summary counts + failures safely.

Tests for User Story 3

  • T037 [P] [US3] Add scope-busy + dedupe behavior tests in tests/Feature/ProviderConnections/ProviderOperationConcurrencyTest.php
  • T038 [P] [US3] Add compliance snapshot summary_counts tests in tests/Feature/ProviderConnections/ProviderComplianceSnapshotJobTest.php
  • T038b [P] [US3] Assert OperationRun context contract for inventory/compliance runs in tests/Feature/ProviderConnections/ProviderOperationConcurrencyTest.php and tests/Feature/ProviderConnections/ProviderComplianceSnapshotJobTest.php (context.provider, context.module, context.provider_connection_id, context.target_scope.entra_tenant_id)

Implementation for User Story 3

  • T039 [US3] Add managed devices contract entry for compliance snapshot in config/graph_contracts.php (resource deviceManagement/managedDevices, select includes compliance state)
  • T040 [US3] Add allowed summary keys for compliance counts in app/Support/OpsUx/OperationSummaryKeys.php (add compliant, noncompliant, unknown)
  • T041 [US3] Create compliance snapshot collector in app/Services/Providers/MicrosoftComplianceSnapshotService.php (implements app/Services/Providers/Contracts/ProviderComplianceCollector.php, uses ProviderGateway, Graph list + count compliance states)
  • T042 [US3] Create queued job in app/Jobs/ProviderComplianceSnapshotJob.php (writes OperationRun context + summary_counts; updates failures with sanitized reason codes)
  • T043 [US3] Add “Compliance snapshot” Filament action (enqueue-only) in app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php (MUST call ProviderOperationStartGate first: same-operation returns existing active run; different-operation for same scope blocks “scope busy” + link to active run)
  • T044 [US3] Create minimal inventory collector in app/Services/Providers/MicrosoftProviderInventoryCollector.php (implements app/Services/Providers/Contracts/ProviderInventoryCollector.php, uses ProviderGateway, contract-backed listing + summary counts only)
  • T045 [US3] Create queued job in app/Jobs/ProviderInventorySyncJob.php (writes OperationRun context + summary_counts; obeys scope-busy rules via start gate)
  • T046 [US3] Add “Inventory sync” Filament action (enqueue-only) in app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php (MUST call ProviderOperationStartGate first: same-operation returns existing active run; different-operation for same scope blocks “scope busy” + link to active run)
  • T047 [US3] Run story tests with ./vendor/bin/sail artisan test tests/Feature/ProviderConnections/ProviderOperationConcurrencyTest.php (test: tests/Feature/ProviderConnections/ProviderOperationConcurrencyTest.php)

Phase 6: Polish & Cross-Cutting Concerns

Purpose: Reduce regressions and improve consistency across stories

  • T048 [P] Ensure provider operations set context.target_scope.entra_tenant_id and context.target_scope.entra_tenant_name in app/Jobs/ProviderConnectionHealthCheckJob.php, app/Jobs/ProviderComplianceSnapshotJob.php, and app/Jobs/ProviderInventorySyncJob.php
  • T049 [P] If ProviderConnection status/health is shown as badges, add a badge mapper + tests in app/Support/Badges/Domains/ and tests/Unit/Badges/
  • T050 Run formatting with ./vendor/bin/sail php ./vendor/bin/pint --dirty (script: ./vendor/bin/pint)
  • T051 Run focused feature tests with ./vendor/bin/sail artisan test tests/Feature/ProviderConnections (folder: tests/Feature/ProviderConnections)

Dependencies & Execution Order

User Story Dependency Graph

Phase 1 (Setup)
  ↓
Phase 2 (Foundation: schema/models/policy + ops primitives)
  ↓
US1 (Connections + credentials UI) ─┬─→ US2 (Health check run)
                                   └─→ US3 (Inventory + compliance runs)

Parallel Opportunities

  • Phase 2 tasks marked [P] can be done in parallel (different files).
  • Within each user story phase, [P] tests can be written in parallel.
  • Caution: US2 and US3 both extend app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php (avoid parallel edits to that file unless coordinated).

Parallel Example: User Story 1

Task: "Add DB-only render test for Provider Connections in tests/Feature/Filament/ProviderConnectionsDbOnlyTest.php"
Task: "Add role authorization test in tests/Feature/ProviderConnections/ProviderConnectionAuthorizationTest.php"
Task: "Add credential encryption/non-disclosure test in tests/Feature/ProviderConnections/ProviderCredentialSecurityTest.php"

Implementation Strategy

MVP First (User Story 1)

  1. Complete Phase 1 + Phase 2
  2. Complete US1 (Provider Connections + credentials management)
  3. Validate with tests/Feature/ProviderConnections/* and DB-only render checks

Incremental Delivery

  1. US1 → demo/manage connections safely (no provider calls)
  2. US2 → add health check (first real provider call, but enqueue-only + observable)
  3. US3 → add inventory + compliance snapshot operations (summary counts + scope-busy rules)