TenantAtlas/specs/339-provider-connection-scope-hardening/tasks.md
ahmido fcb03d2aee feat: harden provider connection authority resolution (339) (#410)
## Summary
- harden Provider Connection authority so workspace scope comes only from explicit workspace context and record ownership
- require explicit `environment_id` for Provider Connection create flows and remove remembered-environment or Filament-tenant fallback authority
- keep legacy query aliases such as `tenant`, `tenant_id`, and `managed_environment_id` inert for Provider Connection access
- add targeted Spec 339 feature coverage for create authority, workspace authority, and wrong-workspace / legacy-query denial behavior
- include Spec 339 artifacts (`spec.md`, `plan.md`, `tasks.md`) for the hardening slice

## Validation
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections --filter=ScopeHardening`

## Notes
- no new uncommitted workspace changes were present to commit in this turn; the branch already contained the feature commits
- Livewire v4 compliance unchanged
- Filament provider registration remains in `bootstrap/providers.php`
- no migrations, new assets, or route-family restructures

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #410
2026-05-31 11:59:41 +00:00

6.9 KiB

Tasks: Spec 339 - Provider Connection Scope Hardening

  • Input: specs/339-provider-connection-scope-hardening/spec.md, specs/339-provider-connection-scope-hardening/plan.md
  • Preparation status: implementation-ready.

Tests: Required. This spec hardens credential-adjacent scope/authorization semantics.

Test Governance Checklist

  • Lane assignment is explicit and narrowest sufficient (Feature).
  • No new default-heavy helpers/factories/seeds are introduced.
  • Scope/authority changes are guarded by deterministic tests before refactors.
  • Any exception resolves as document-in-feature, follow-up-spec, or reject-or-split.

Phase 1: Preparation And Repo Truth (blocks runtime changes)

Purpose: Confirm repo truth and identify the exact forbidden fallback seams before changing behavior.

  • T001 Re-read spec.md + plan.md + this tasks.md.
  • T002 Confirm working tree intent and record baseline commit (git status, git log -1).
  • T003 Inspect the confirmed authority seams:
    • apps/platform/app/Policies/ProviderConnectionPolicy.php:
      • currentWorkspace() (forbidden fallback via Filament::getTenant()).
      • resolveCreateTenant() (forbidden fallbacks via remembered environment + Filament tenant).
      • record-derived checks for workspace/environment ownership (ensure these remain the canonical authority for view/edit/actions).
    • apps/platform/app/Filament/Resources/ProviderConnectionResource.php:
      • applyMembershipScope() (must not infer workspace via tenant context).
      • resolveRequestedEnvironment() / WorkspaceHubEnvironmentFilter use (explicit environment_id only).
    • apps/platform/app/Support/Workspaces/WorkspaceContext.php:
      • lastEnvironmentId() and remembered-environment helpers (navigation-only; must not grant create authority).
  • T004 Inventory existing ProviderConnections tests and identify the best location for new regression tests:
    • apps/platform/tests/Feature/ProviderConnections/ProviderConnectionListAuthorizationTest.php
    • apps/platform/tests/Feature/ProviderConnections/ProviderConnectionsWorkspaceHubContractTest.php
    • apps/platform/tests/Feature/ProviderConnections/AuthorizationSemanticsTest.php
    • apps/platform/tests/Feature/ProviderConnections/RequiredFiltersTest.php

Phase 2: Add failing contract tests first

Purpose: Make authority changes reviewable and regression-proof.

  • T005 Add a new Spec 339 test proving create requires explicit environment_id:
    • Create is denied when /admin/provider-connections/create is requested without environment_id,
    • even if a remembered environment exists in session (WorkspaceContext::lastEnvironmentId).
    • Implemented via: apps/platform/tests/Feature/ProviderConnections/ScopeHardeningAuthoritySourcesTest.php
  • T006 Add a test proving workspace authority does not fall back to Filament tenant:
    • When workspace context is missing, Provider Connection access is deny-as-not-found (404),
    • even if Filament::getTenant() is set.
    • Implemented via:
      • apps/platform/tests/Feature/ProviderConnections/ScopeHardeningPolicyWorkspaceAuthorityTest.php
      • apps/platform/tests/Feature/ProviderConnections/ScopeHardeningResourceWorkspaceAuthorityTest.php
  • T007 Add a test proving legacy query aliases do not grant authority:
    • ?managed_environment_id=..., ?tenant=..., ?tenant_id=... must not widen list scope or unlock create.
    • Implemented via: apps/platform/tests/Feature/ProviderConnections/ScopeHardeningAuthoritySourcesTest.php
  • T008 Add a test proving wrong-workspace environment IDs deny as 404:
    • environment_id from another workspace must not authorize create or list filtering.

Phase 3: Policy authority hardening (Spec 339 contract)

Purpose: Remove forbidden authority fallbacks and enforce the 404/403 semantics contract.

  • T009 Update apps/platform/app/Policies/ProviderConnectionPolicy.php::currentWorkspace():
    • remove Filament::getTenant() as an authority source for workspace selection,
    • keep workspace membership validation,
    • keep deny-as-not-found (404) behavior when workspace context is missing.
  • T010 Update apps/platform/app/Policies/ProviderConnectionPolicy.php::resolveCreateTenant():
    • require explicit environment_id,
    • remove remembered-environment fallback and Filament-tenant fallback,
    • ensure wrong-workspace environment_id denies as 404.
  • T011 Confirm 404 vs 403 semantics for all policy methods:
    • non-member / out-of-scope record → 404,
    • member missing capability → 403.

Phase 4: Resource scoping hardening (no hidden context authority)

Purpose: Ensure list/query and record surfaces do not infer authority from hidden context.

  • T012 Update apps/platform/app/Filament/Resources/ProviderConnectionResource.php::applyMembershipScope():
    • remove fallback that infers workspace ID from tenant context when session workspace is missing,
    • keep query empty (no results) when workspace context is missing.
  • T013 Confirm Provider Connections list filtering uses explicit environment_id only:
    • validate environment_id against current workspace and access scope,
    • ignore legacy query aliases as authority.
  • T014 Confirm record pages and action dispatchers use record-derived tenant/workspace authority, not remembered environment or Filament tenant.

Phase 5: Credential-adjacent actions audit

Purpose: Ensure high-risk actions remain safe and record-scoped.

  • T015 Audit all actions on ProviderConnectionResource (edit + dedicated credential actions + provider operations):
    • confirm policy methods are used consistently,
    • confirm destructive-like actions retain ->requiresConfirmation(),
    • confirm record ownership controls scope for all actions.
  • T016 Confirm audit posture remains intact for credential-adjacent mutations:
    • no new audit event families are introduced in this slice,
    • existing audit logging remains correct and record-scoped.

Phase 6: Optional UX clarification (only if needed)

  • T017 If create is denied without environment_id, ensure the list empty state or guidance makes the required next step obvious (filter/select an environment first) without introducing a new picker or redesign. (No changes needed.)

Phase 7: Validation

  • T018 Run narrow tests first:
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections --filter=ScopeHardening
  • T019 Run formatting and patch checks:
    • cd apps/platform && ./vendor/bin/sail pint --dirty --format agent
    • git diff --check

Explicit Non-Goals

  • NT001 Do not add migrations, new tables, or new persisted truth.
  • NT002 Do not redesign Provider Connections UX or navigation placement.
  • NT003 Do not introduce a new scope/authority abstraction framework.
  • NT004 Do not reopen provider-neutral target-scope/identity refactors (Spec 281 family).