344 lines
31 KiB
Markdown
344 lines
31 KiB
Markdown
# Implementation Plan: Exchange Credential and Permission Evidence Support
|
|
|
|
**Branch**: `433-exchange-credential-permission-evidence-support` | **Date**: 2026-07-07 | **Spec**: `specs/433-exchange-credential-permission-evidence-support/spec.md`
|
|
**Input**: Feature specification from `specs/433-exchange-credential-permission-evidence-support/spec.md`
|
|
|
|
## Summary
|
|
|
|
Refine Exchange PowerShell credential and permission evidence readiness for the existing Spec 432 production runner gate and existing provider capability/readiness evaluation. The implementation should make credential evidence explicit, provider-scoped, workspace-scoped, managed-environment-scoped, current, auditable, and redaction-safe; make `Exchange.ManageAsApp` permission evidence current and scoped; introduce or reuse a combined readiness result; and ensure `exchange_powershell_invoke` is Supported only when both credential and permission evidence pass. No Exchange calls, PowerShell execution, content-backed evidence, new UI/routes/navigation/assets/global search, jobs, schedules, listeners, reports, customer claims, or `tenant_id` are in scope. Existing provider capability/readiness surfaces can render changed status output through existing code paths and must be browser-checked.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: PHP 8.4 / Laravel 12
|
|
**Primary Dependencies**: Existing Laravel monolith, Filament v5 / Livewire v4 baseline unchanged
|
|
**Storage**: PostgreSQL. Default is no new table; possible minimal provider-agnostic migration only if existing metadata is insufficient.
|
|
**Testing**: Pest 4 focused unit and feature tests
|
|
**Validation Lanes**: fast-feedback/confidence focused tests; PostgreSQL lane if migration/JSONB/index behavior changes; focused read-only browser proof for existing provider capability/readiness surfaces
|
|
**Target Platform**: Laravel Sail local; Dokploy staging/production with Exchange production runner disabled by default
|
|
**Project Type**: Laravel monolith under `apps/platform`
|
|
**Performance Goals**: Readiness checks must be local DB/config evaluation only; no provider calls, process execution, or render-time work
|
|
**Constraints**: No secrets/raw payloads in context/logs/tests; no Exchange execution; no new UI/routes/navigation/assets/global search; no customer claims; no `tenant_id`
|
|
**Scale/Scope**: Existing Exchange PowerShell invocation operation and `exchange_powershell_invoke` capability for Spec 430 target slice only
|
|
|
|
## Preflight Findings
|
|
|
|
- Current branch before Spec Kit execution: `platform-dev`.
|
|
- HEAD before Spec Kit execution: `f4e34212 feat: add Exchange PowerShell production runner gate (#499)`.
|
|
- Initial dirty state before Spec Kit execution: clean.
|
|
- Spec Kit helper created branch: `433-exchange-credential-permission-evidence-support`.
|
|
- No existing `specs/433-*` directory or `*433*` branch was found before preparation.
|
|
- Spec 431's historical "Spec 433" label for content-backed evidence promotion is superseded by the Spec 432 follow-up decision; content-backed promotion is now Spec 434.
|
|
- `docs/product/spec-candidates.md` marks the automatic next-best-prep queue empty/manual-only; this spec is selected because the user directly provided a P0 draft.
|
|
- Spec 432 implementation report records PASS and proves the runner boundary, disabled default, production config gate, runtime checker, credential resolver, permission evaluator, process executor, command builder/output guards, OperationRun context sanitization, no evidence, no UI, no migration, and no `tenant_id`.
|
|
- Current `apps/platform/config/tenantpilot.php` includes:
|
|
- `tenantpilot.features.exchange_powershell_invocation`
|
|
- `tenantpilot.features.exchange_powershell_production_runner`
|
|
- `tenantpilot.exchange_powershell.credentials.supported_reference_kinds`
|
|
- runtime knobs under `tenantpilot.exchange_powershell.runtime`
|
|
- Current `ProviderCredential` has `provider_connection_id`, `type`, `credential_kind`, `source`, encrypted hidden `payload`, `last_rotated_at`, and `expires_at`.
|
|
- Current `ProviderCredentialKind` has `client_secret`, `certificate`, and `federated`; managed identity is not a first-class enum case.
|
|
- Current `ManagedEnvironmentPermission` has `workspace_id`, `managed_environment_id`, `permission_key`, `status`, `last_checked_at`, and JSONB `details`; current persistence is unique by `managed_environment_id` + `permission_key`, with provider-connection scope represented only through `details`.
|
|
- Current `ExchangePowerShellCredentialReferenceResolver` blocks missing credentials, client-secret credentials, expired certificates, unsupported certificate/federated/managed-identity states, and unknown kinds, but does not yet prove all first-class accessibility/wrong-scope/source/currentness states from the draft.
|
|
- Current `ExchangePowerShellPermissionEvidenceEvaluator` uses `Exchange.ManageAsApp`, `last_checked_at`, and scoped details with a hard-coded 30-day threshold.
|
|
- Current `ProviderCapabilityRegistry` defines `exchange_powershell_invoke` with provider requirement keys `provider.exchange_powershell_invocation` and `permissions.admin_consent`.
|
|
- Current `ProviderCapabilityEvaluator` has a stored Exchange permission fallback and hard-coded 30-day currentness behavior.
|
|
|
|
## UI / Surface Guardrail Plan
|
|
|
|
- **Guardrail scope**: existing provider capability/readiness status presentation only.
|
|
- **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: existing Provider Connection capability/readiness presentation, existing Environment Required Permissions provider-capability section, and existing verification-assist provider-capability presentation where they render provider capability/readiness output.
|
|
- **No-impact class, if applicable**: no new route, page, component, navigation, action, asset, global-search behavior, report, dashboard, or customer surface is introduced.
|
|
- **Native vs custom classification summary**: reuse existing Filament/Blade rendering and existing provider capability/readiness status vocabulary; do not add a runtime Product Surface framework.
|
|
- **Shared-family relevance**: provider capability/readiness and OperationRun context; existing rendered provider-readiness family must remain canonical and redacted.
|
|
- **State layers in scope**: credential evidence state, permission evidence state, combined readiness state, provider capability status, runner-gate blocker state, OperationRun context.
|
|
- **Audience modes in scope**: internal operator/reviewer through existing provider readiness/capability surfaces; no customer/read-only claim surface.
|
|
- **Decision/diagnostic/raw hierarchy plan**: default surfaces show only canonical readiness/capability result and safe high-level blocker labels. Raw credential details, permission `details`, provider payloads, OperationRun context, stdout/stderr, IDs used only for scope checks, and support diagnostics stay demoted from default views.
|
|
- **Raw/support gating plan**: Raw credential material, raw permission payloads, raw provider payloads, and sensitive exception messages are forbidden from context/loggable output and default rendered surfaces.
|
|
- **One-primary-action / duplicate-truth control**: no new primary action; provider capability and runner gate must consume the same readiness truth.
|
|
- **Handling modes by drift class or surface**: status-only change on existing surfaces; any new UI file, route, or action requires spec/plan amendment before implementation continues.
|
|
- **Repository-signal treatment**: Filament/provider panel file changes are out of scope unless the spec is amended. Service/provider binding changes are product-surface relevant when their output is rendered by existing surfaces.
|
|
- **Special surface test profiles**: focused read-only browser smoke for existing provider capability/readiness surfaces.
|
|
- **Required tests or manual smoke**: focused browser proof plus Human Product Sanity for the existing provider capability/readiness surfaces after implementation.
|
|
- **Exception path and spread control**: none.
|
|
- **Active feature PR close-out entry**: credential and permission evidence readiness guardrail, existing provider capability/readiness surfaces browser-checked, no new rendered UI surface introduced.
|
|
- **UI/Productization coverage decision**: existing page/status presentation changed.
|
|
- **Coverage artifacts to update**: implementation report only.
|
|
- **No-impact rationale**: N/A - existing rendered provider readiness/capability surfaces are affected by evaluator output.
|
|
- **Navigation / Filament provider-panel handling**: no panel/provider registration changes; Laravel panel providers remain in `apps/platform/bootstrap/providers.php`.
|
|
- **Screenshot or page-report need**: focused browser screenshot/proof for the existing affected surfaces.
|
|
|
|
## Product Surface Contract Plan
|
|
|
|
- **Product Surface Contract reference**: `docs/product/standards/product-surface-contract.md`.
|
|
- **No-legacy posture**: canonical addition/replacement only; no aliases, fallback readers, duplicate UI, hidden routes, or historical fixtures.
|
|
- **Page archetype and surface budget plan**: existing provider readiness/capability surfaces; no new panel, table, action, or diagnostic drawer.
|
|
- **Technical Annex and deep-link demotion plan**: OperationRun remains internal execution truth and is not customer proof. Raw evidence, credential details, permission `details`, provider diagnostics, and logs are not default-visible.
|
|
- **Canonical status vocabulary plan**: reuse existing `ProviderCapabilityStatus` and provider-readiness vocabulary unless a new behavior-backed state passes proportionality review.
|
|
- **Product Surface exceptions**: none.
|
|
- **Browser verification plan**: focused read-only smoke for existing provider capability/readiness surfaces.
|
|
- **Human Product Sanity plan**: required for existing provider readiness/capability status presentation.
|
|
- **Visible complexity outcome target**: neutral-to-reduced; more truthful readiness without extra default-visible technical detail.
|
|
- **Implementation report target**: `specs/433-exchange-credential-permission-evidence-support/implementation-report.md`.
|
|
|
|
## Filament / Livewire / Deployment Posture
|
|
|
|
- **Livewire v4 compliance**: repo baseline remains Livewire v4; no Livewire runtime code planned.
|
|
- **Panel provider registration location**: no panel/provider change; Laravel panel providers remain in `apps/platform/bootstrap/providers.php`.
|
|
- **Global search posture**: no Filament resource or global search behavior changed.
|
|
- **Destructive/high-impact action posture**: no UI action added. Backend runner readiness remains read-only gating. Any live invocation remains controlled by existing Spec 432 gates and provider-run authorization.
|
|
- **Asset strategy**: no assets; `filament:assets` is not required for this slice.
|
|
- **Testing plan**: no pages/widgets/relation managers/actions are added; focused browser proof covers existing provider capability/readiness surfaces because evaluator output is rendered there.
|
|
- **Deployment impact**: possible new fail-closed config key for permission currentness only; possible provider-agnostic migration only if existing metadata is insufficient. No queues, schedules, storage, assets, or browser build impact.
|
|
|
|
## Shared Pattern & System Fit
|
|
|
|
- **Cross-cutting feature marker**: yes.
|
|
- **Systems touched**:
|
|
- `apps/platform/app/Services/TenantConfiguration/ExchangePowerShellCredentialReferenceResolver.php`
|
|
- `apps/platform/app/Services/TenantConfiguration/ExchangePowerShellPermissionEvidenceEvaluator.php`
|
|
- `apps/platform/app/Services/TenantConfiguration/ExchangePowerShellProductionRunner.php`
|
|
- `apps/platform/app/Services/TenantConfiguration/ExchangePowerShellInvocationGate.php`
|
|
- possible new `ExchangePowerShellInvocationReadinessEvaluator.php`
|
|
- `apps/platform/app/Support/Providers/Capabilities/ProviderCapabilityEvaluator.php`
|
|
- `apps/platform/app/Support/Providers/Capabilities/ProviderCapabilityRegistry.php` only if requirement keys/status behavior need adjustment
|
|
- `apps/platform/app/Models/ProviderCredential.php`
|
|
- `apps/platform/app/Support/Providers/ProviderCredentialKind.php` only if managed identity becomes first-class
|
|
- `apps/platform/app/Models/ManagedEnvironmentPermission.php`
|
|
- `apps/platform/config/tenantpilot.php`
|
|
- **Shared abstractions reused**: provider credential/reference model, managed-environment permission rows, provider capability evaluator/registry, OperationRun lifecycle/context safety, Spec 432 runner gate.
|
|
- **New abstraction introduced? why?**: A combined readiness evaluator may be introduced so provider capability and runner gate consume one evidence truth. This is justified by security/readiness correctness and avoids duplicated local checks.
|
|
- **Why the existing abstraction was sufficient or insufficient**: Existing resolvers/evaluators already block many unsafe cases, but readiness is split between credential resolver, permission evaluator, provider capability fallback, and production runner. Spec 433 should remove drift and add missing evidence metadata/currentness/accessibility proof.
|
|
- **Bounded deviation / spread control**: No generic provider readiness framework, no Exchange mini-platform, no UI pattern, no evidence writer, no customer-output path.
|
|
|
|
## OperationRun UX Impact
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: yes, backend context safety only.
|
|
- **Central contract reused**: existing Spec 432 invocation path and `OperationRunService`.
|
|
- **Delegated UX behaviors**: N/A - no toast, run link, artifact link, browser event, queued DB notification, dedupe messaging, or surface-owned URL resolution.
|
|
- **Surface-owned behavior kept local**: none.
|
|
- **Queued DB-notification policy**: N/A.
|
|
- **Terminal notification path**: unchanged central lifecycle mechanism.
|
|
- **Exception path**: none.
|
|
|
|
## Provider Boundary & Portability Fit
|
|
|
|
- **Shared provider/platform boundary touched?**: yes.
|
|
- **Provider-owned seams**: Exchange PowerShell credential support, `Exchange.ManageAsApp`, Exchange invocation readiness, Exchange-specific blocker naming where bounded.
|
|
- **Platform-core seams**: provider connection scope, credential-reference metadata, managed-environment permission evidence, provider capability, OperationRun context, currentness/source metadata, redaction.
|
|
- **Neutral platform terms / contracts preserved**: provider connection, credential reference, permission evidence, currentness, observed/verified/source metadata, readiness, workspace, managed environment, blocker reason.
|
|
- **Retained provider-specific semantics and why**: `Exchange.ManageAsApp` and Exchange PowerShell invocation are retained because this is an Exchange runner readiness spec, not a multi-provider abstraction.
|
|
- **Bounded extraction or follow-up path**: document-in-feature. If evidence metadata proves generally useful, it must remain provider-agnostic. Content-backed evidence promotion remains Spec 434.
|
|
|
|
## Constitution Check
|
|
|
|
- Inventory-first: no inventory, snapshot, backup, or tenant configuration evidence truth is created.
|
|
- Read/write separation: no provider writes, no Exchange calls, no PowerShell execution. Gating remains read-only local evaluation.
|
|
- Graph contract path: no Graph calls are added and no Graph contract path changes.
|
|
- Deterministic capabilities: `exchange_powershell_invoke` must be deterministically evaluated from readiness evidence and tested.
|
|
- RBAC-UX: implementation must preserve workspace/environment entitlement and provider-run capability behavior from Spec 432; non-member/wrong scope 404; member missing capability 403 or repo-equivalent.
|
|
- Workspace isolation: provider connection, credential reference, permission evidence, and readiness must all resolve within the same workspace.
|
|
- Tenant/managed-environment isolation: environment-owned permission evidence must match `managed_environment_id`; provider connection must belong to the same environment.
|
|
- OperationRun truth: OperationRun remains execution truth only and cannot become evidence/customer proof.
|
|
- OperationRun context: safe readiness/blocker state only; no credential material, raw permission payload, raw provider output, or sensitive exceptions.
|
|
- Ops-UX summary counts: no new summary count key expected. If one is unavoidable, update `OperationSummaryKeys::all()` and test.
|
|
- Provider freshness semantics: stale permission evidence blocks and is not labeled ready.
|
|
- Evidence anchor contract: no tenant configuration evidence rows or evidence anchors are created.
|
|
- Product Surface Contract: applies because existing provider capability/readiness surfaces render changed evaluator output; no new UI surface is introduced.
|
|
- Test governance: focused unit/feature tests; PostgreSQL lane if schema changes; focused browser lane for existing provider capability/readiness surfaces.
|
|
- Proportionality: any new metadata, state, or evaluator must solve current safety risk and be narrower than a generic provider framework.
|
|
- No premature abstraction: no generic PowerShell/provider readiness framework until more real cases require it.
|
|
- Persisted truth: migration only if evidence metadata must outlive the originating run and cannot be safely represented today.
|
|
- Behavioral state: each new state must block/allow execution, change capability support, drive audit/readiness proof, or protect redaction.
|
|
- Provider boundary: provider-specific Exchange terms stay in provider-owned seams and do not become platform-core ownership truth.
|
|
- Pre-production lean doctrine: replace ambiguous readiness behavior cleanly; no compatibility aliases or fallback readers.
|
|
|
|
## Test Governance Check
|
|
|
|
- **Test purpose / classification by changed surface**: Unit tests for pure readiness/evaluator behavior; Feature tests for provider capability, runner-gate integration, OperationRun context safety, no-promotion guards, and migration/no-migration proof.
|
|
- **Affected validation lanes**: fast-feedback/confidence; PostgreSQL if migration/JSONB/index behavior changes; focused read-only browser proof for existing provider capability/readiness surfaces.
|
|
- **Why this lane mix is the narrowest sufficient proof**: The change is evidence-readiness and local gate evaluation with no live provider calls; focused browser proof is needed because provider capability/readiness output is rendered by existing surfaces.
|
|
- **Narrowest proving command(s)**:
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec433 --compact`
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec432 --compact`
|
|
- selected Spec 431/430/426/427/417/419/420 and provider capability regressions
|
|
- PostgreSQL lane if migration is added
|
|
- focused read-only browser proof for existing provider capability/readiness surfaces
|
|
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
|
- `git diff --check`
|
|
- **Fixture / helper / factory / seed / context cost risks**: workspace, managed environment, provider connection, provider credential, permission evidence, currentness thresholds, OperationRun context. Keep setup explicit and opt-in.
|
|
- **Expensive defaults or shared helper growth introduced?**: no planned defaults.
|
|
- **Heavy-family additions, promotions, or visibility changes**: focused browser proof for existing provider capability/readiness surfaces; PostgreSQL validation only if migration requires it.
|
|
- **Surface-class relief / special coverage rule**: no new rendered surface, but existing rendered readiness status requires browser proof and Human Product Sanity.
|
|
- **Closing validation and reviewer handoff**: implementation report must list exact commands, pass/fail counts, dirty state, and any safe residual conditions.
|
|
- **Budget / baseline / trend follow-up**: none expected.
|
|
- **Review-stop questions**: verify no Exchange call, no PowerShell execution, no evidence rows, no new UI, no trigger surface, no credential material, no raw permission payload, no `tenant_id`, no Exchange-specific table, no provider capability overclaim, and no raw details on existing provider readiness surfaces.
|
|
- **Escalation path**: reject-or-split if implementation attempts content-backed capture, live invocation, UI/routes/jobs/schedules/listeners, customer output, broad metadata framework, or Exchange-specific persistence.
|
|
- **Active feature PR close-out entry**: credential and permission evidence readiness guardrail with existing provider capability/readiness surfaces browser-checked and no new rendered UI surface introduced.
|
|
- **Why no dedicated follow-up spec is needed**: Routine readiness hardening belongs in Spec 433. Content-backed Exchange evidence and customer output are separate later specs.
|
|
|
|
## Project Structure
|
|
|
|
### Documentation (this feature)
|
|
|
|
```text
|
|
specs/433-exchange-credential-permission-evidence-support/
|
|
|-- spec.md
|
|
|-- plan.md
|
|
|-- tasks.md
|
|
|-- checklists/
|
|
| `-- requirements.md
|
|
`-- implementation-report.md # created by later implementation loop
|
|
```
|
|
|
|
### Source Code (likely affected by later implementation)
|
|
|
|
```text
|
|
apps/platform/app/Models/ProviderCredential.php
|
|
apps/platform/app/Models/ManagedEnvironmentPermission.php
|
|
apps/platform/app/Support/Providers/ProviderCredentialKind.php
|
|
apps/platform/app/Support/Providers/Capabilities/ProviderCapabilityEvaluator.php
|
|
apps/platform/app/Support/Providers/Capabilities/ProviderCapabilityRegistry.php
|
|
apps/platform/app/Services/TenantConfiguration/ExchangePowerShellCredentialReferenceResolver.php
|
|
apps/platform/app/Services/TenantConfiguration/ExchangePowerShellPermissionEvidenceEvaluator.php
|
|
apps/platform/app/Services/TenantConfiguration/ExchangePowerShellProductionRunner.php
|
|
apps/platform/app/Services/TenantConfiguration/ExchangePowerShellInvocationGate.php
|
|
apps/platform/app/Services/TenantConfiguration/ExchangePowerShellInvocationReadinessEvaluator.php
|
|
apps/platform/config/tenantpilot.php
|
|
apps/platform/tests/Unit/Support/TenantConfiguration/
|
|
apps/platform/tests/Feature/TenantConfiguration/
|
|
apps/platform/tests/Feature/Providers/
|
|
```
|
|
|
|
Possible migration files only if existing metadata is insufficient:
|
|
|
|
```text
|
|
apps/platform/database/migrations/*_add_provider_credential_evidence_metadata.php
|
|
apps/platform/database/migrations/*_add_managed_environment_permission_evidence_metadata.php
|
|
```
|
|
|
|
Forbidden source changes:
|
|
|
|
```text
|
|
apps/platform/routes/**
|
|
apps/platform/app/Filament/**
|
|
apps/platform/app/Livewire/**
|
|
apps/platform/resources/views/**
|
|
apps/platform/app/Jobs/**
|
|
apps/platform/app/Listeners/**
|
|
apps/platform/app/Console/**
|
|
customer report/review-pack/PDF output code
|
|
new Exchange-specific credential or permission tables
|
|
tenant_id ownership columns
|
|
legacy shim or fallback reader paths
|
|
```
|
|
|
|
**Structure Decision**: Use the existing TenantConfiguration service path and provider capability/readiness paths. Do not create a new Exchange subsystem or base folder without amending the spec.
|
|
|
|
## Complexity Tracking
|
|
|
|
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
|
| --- | --- | --- |
|
|
| Combined readiness evaluator | Capability and runner gate must share one readiness truth. | Keeping separate local checks risks Supported capability while runner blocks, or runner pass while capability is unknown. |
|
|
| New credential/permission blocker states | Each state changes execution/capability behavior and redaction/audit interpretation. | Collapsing to `unknown` hides missing vs expired vs inaccessible vs wrong-scope safety conditions. |
|
|
| Possible provider-agnostic metadata migration | Only if current fields cannot safely represent source/observed/verified/accessibility/currentness. | Exchange-specific tables or free-form implicit details would deepen provider coupling or weaken query/audit safety. |
|
|
|
|
## Proportionality Review
|
|
|
|
- **Current operator problem**: Prevent false readiness and unsafe live invocation for Exchange PowerShell before evidence capture is allowed.
|
|
- **Existing structure is insufficient because**: Current code blocks many cases, but readiness is split across resolvers/evaluators and some evidence metadata is implicit or hard-coded.
|
|
- **Narrowest correct implementation**: Refine existing provider credential, permission evidence, capability, and runner gate paths. Add one combined readiness result if needed.
|
|
- **Ownership cost created**: Focused service/test surface and possible small provider-agnostic metadata upkeep.
|
|
- **Alternative intentionally rejected**: Admin-consent-only support, client-secret support, Exchange-specific persistence, UI readiness labels, and evidence promotion.
|
|
- **Release truth**: Current-release safety prerequisite for Spec 434.
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 0 - Preflight
|
|
|
|
- Capture branch, HEAD, and dirty state.
|
|
- Confirm Spec 432 implementation report remains PASS with no open merge-blocking runner safety findings.
|
|
- Confirm current code paths for credential resolver, permission evaluator, capability evaluator, runner gate, credential model, permission model, and config.
|
|
- Confirm no Exchange calls, PowerShell execution, evidence promotion, new UI, trigger surface, customer output, migration, or `tenant_id` is planned before the data-model decision.
|
|
- Confirm the existing provider capability/readiness surfaces that render `ProviderCapabilityEvaluator`/registry output and will need focused browser proof after implementation.
|
|
|
|
### Phase 1 - Data Model Decision
|
|
|
|
- Inspect `ProviderCredential`, `ProviderCredentialKind`, `ManagedEnvironmentPermission`, current migrations, and current evaluator behavior.
|
|
- Decide no-migration versus minimal provider-agnostic metadata migration.
|
|
- If no migration, document how current fields/details safely represent accessibility, source, observed, verified, currentness, and scope, including the current `managed_environment_id` + `permission_key` uniqueness and provider-connection matching through `details`.
|
|
- If no migration, prove nonmatching or missing `details.provider_connection_id` fails closed and no fallback-to-latest/admin-consent-only behavior exists.
|
|
- If migration is required, stop runtime implementation and update `spec.md` plus this `plan.md` with exact fields, ownership semantics, constraints/indexes, rollback posture, and proportionality review before adding schema code.
|
|
- After an approved migration amendment, add tests proving provider-agnostic fields, reversibility where practical, no secret material, no raw payloads, no Exchange-specific table, and no `tenant_id`.
|
|
|
|
### Phase 2 - Credential Evidence
|
|
|
|
- Extend or refactor `ExchangePowerShellCredentialReferenceResolver` to return explicit credential evidence states and safe context.
|
|
- Keep client-secret blocked.
|
|
- Add distinct inaccessible state only when observable from repo-owned fields or an approved metadata migration; otherwise collapse to a safe fail-closed state with tests.
|
|
- Add wrong-scope/unvalidated/currentness states when supported by repo truth; do not invent fake precision from unavailable credential metadata.
|
|
- Decide certificate support versus explicit safe block.
|
|
- Decide federated support versus explicit safe block.
|
|
- Decide managed identity support versus explicit safe block and whether a first-class enum case is warranted.
|
|
- Add redaction tests for credential payloads, references, exception messages, and OperationRun/loggable output.
|
|
|
|
### Phase 3 - Permission Evidence
|
|
|
|
- Extend or refactor `ExchangePowerShellPermissionEvidenceEvaluator` to make `Exchange.ManageAsApp` source/currentness/scope metadata first-class enough for the gate.
|
|
- Make currentness threshold configurable or explicitly justify/test the fixed 30-day threshold.
|
|
- Enforce workspace, managed environment, provider connection, provider, status, source/observed/verified, and staleness rules.
|
|
- Decide and test the current no-migration one-row-per-environment/permission-key behavior versus a spec-approved provider-connection-specific migration.
|
|
- Preserve admin-consent-not-sufficient behavior.
|
|
- Ensure manual/admin assertions cannot pass unless explicitly verified by repo policy and tested; default fail-closed.
|
|
|
|
### Phase 4 - Combined Readiness
|
|
|
|
- Add `ExchangePowerShellInvocationReadinessEvaluator` or repo-canonical equivalent if needed.
|
|
- Require credential readiness and permission evidence readiness.
|
|
- Return safe pass/blocker states with no raw material.
|
|
- Ensure `ProviderCapabilityEvaluator` and `ExchangePowerShellProductionRunner` use the same readiness truth or equivalent shared result.
|
|
|
|
### Phase 5 - Provider Capability Integration
|
|
|
|
- Update provider capability evaluation so `exchange_powershell_invoke` is Supported only when combined readiness passes.
|
|
- Prove admin consent, client secret, missing credential, missing permission, stale permission, wrong-scope permission, unsupported provider, and unknown evidence do not produce Supported.
|
|
- Keep capability status values within existing `ProviderCapabilityStatus` unless a new status has a direct behavioral need and proportionality review.
|
|
- Record the expected rendered impact on existing provider capability/readiness surfaces and keep default output canonical/redacted.
|
|
|
|
### Phase 6 - Runner Gate Integration
|
|
|
|
- Wire Spec 432 runner gate to combined readiness before runtime/process execution.
|
|
- Store only safe readiness/blocker state in OperationRun context.
|
|
- Do not create a new OperationRun type unless explicitly justified; current expectation is reuse `tenant_configuration.exchange_powershell_invocation`.
|
|
- Preserve disabled default and production-runner config gates from Spec 432.
|
|
|
|
### Phase 7 - No-Promotion and Surface Guard
|
|
|
|
- Add tests/guard scans proving no tenant configuration evidence rows, raw/normalized Exchange payloads, content-backed/comparable/renderable/certified/restore/customer states, new UI/routes/assets/global search, jobs/schedules/listeners, Exchange-specific tables, legacy shims, fallback readers, or `tenant_id`.
|
|
- Add product-surface guard proof that existing provider readiness/capability surfaces do not show raw credential, permission, provider, OperationRun, stdout/stderr, or scope-diagnostic payloads by default.
|
|
|
|
### Phase 8 - Validation and Report
|
|
|
|
- Run focused Spec 433 tests.
|
|
- Run Spec 432/431/430 and selected no-promotion/provider regressions.
|
|
- Run migration/PostgreSQL lane if schema changes.
|
|
- Run focused browser proof and Human Product Sanity for existing provider capability/readiness surfaces.
|
|
- Run Pint and `git diff --check`.
|
|
- Create implementation report with matrices for credential kinds, permission evidence, migration/no-migration, no-promotion, validation, deployment impact, Product Surface proof, browser/Human Product Sanity result, and no completed-spec rewrite proof.
|
|
|
|
## Rollout and Deployment Considerations
|
|
|
|
- No runtime enablement is planned by this spec. Existing production-runner feature flags remain disabled by default.
|
|
- If a permission-currentness config key is added, default it fail-closed or preserve existing 30-day behavior with explicit tests.
|
|
- If migration is added, it must be safe for staging validation and must not add secret material, raw payloads, Exchange-specific tables, or `tenant_id`.
|
|
- No queue, scheduler, storage, asset, browser build, or `filament:assets` deployment impact is expected.
|
|
- Dokploy staging must validate any migration/config change before production.
|
|
|
|
## Risk Controls
|
|
|
|
- Hard stop if client-secret credentials can pass Exchange PowerShell readiness.
|
|
- Hard stop if admin consent alone makes `exchange_powershell_invoke` Supported.
|
|
- Hard stop if stale, missing, unvalidated, or wrong-scope permission evidence passes.
|
|
- Hard stop if credential material or raw permission/provider payloads enter context, logs, tests, or persisted metadata.
|
|
- Hard stop if Exchange provider calls, PowerShell execution, evidence rows, new UI/routes/jobs/schedules/listeners, customer output, Exchange-specific tables, or `tenant_id` are introduced.
|
|
- Hard stop if existing rendered provider capability/readiness surfaces are changed without the Product Surface proof, browser proof, and Human Product Sanity required by this plan.
|