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

115 lines
6.9 KiB
Markdown

# 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
- [x] Lane assignment is explicit and narrowest sufficient (Feature).
- [x] No new default-heavy helpers/factories/seeds are introduced.
- [x] Scope/authority changes are guarded by deterministic tests before refactors.
- [x] 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.
- [x] T001 Re-read `spec.md` + `plan.md` + this `tasks.md`.
- [x] T002 Confirm working tree intent and record baseline commit (`git status`, `git log -1`).
- [x] 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).
- [x] 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.
- [x] 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`
- [x] 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`
- [x] 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`
- [x] 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.
- [x] 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.
- [x] 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.
- [x] 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.
- [x] 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.
- [x] 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.
- [x] 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.
- [x] 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.
- [x] 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)
- [x] 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
- [x] T018 Run narrow tests first:
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections --filter=ScopeHardening`
- [x] T019 Run formatting and patch checks:
- `cd apps/platform && ./vendor/bin/sail pint --dirty --format agent`
- `git diff --check`
## Explicit Non-Goals
- [x] NT001 Do not add migrations, new tables, or new persisted truth.
- [x] NT002 Do not redesign Provider Connections UX or navigation placement.
- [x] NT003 Do not introduce a new scope/authority abstraction framework.
- [x] NT004 Do not reopen provider-neutral target-scope/identity refactors (Spec 281 family).