Spec 430: Exchange PowerShell adapter contract slice 1. Validation was not rerun during PR creation handoff; branch contains implementation report and tests. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #497
184 lines
13 KiB
Markdown
184 lines
13 KiB
Markdown
# Implementation Report: Spec 430 - Exchange PowerShell Adapter Contract Slice 1
|
|
|
|
## Preflight
|
|
|
|
- **Active spec**: `specs/430-exchange-powershell-adapter-contract-slice-1/`
|
|
- **Branch**: `430-exchange-powershell-adapter-contract-slice-1`
|
|
- **HEAD before implementation**: `0e2cea30 spec: add Exchange Teams source-surface catalog adapter strategy (#496)`
|
|
- **Initial dirty state**: untracked active spec package only: `specs/430-exchange-powershell-adapter-contract-slice-1/`
|
|
- **Activated skills/gates**:
|
|
- `spec-kit-implementation-loop`: requested implementation loop.
|
|
- `.agent/workflows/spec-readiness-gate`: active Spec Kit implementation readiness check.
|
|
- `.agent/repo-contracts/workspace-scope-safety`: provider-connection and future execution handoff scope proof.
|
|
- `.agent/repo-contracts/provider-freshness-semantics`: provider permission/source-boundary metadata proof.
|
|
- `.agent/temporary-migrations/tcm-cutover-guard`: Coverage v2/source-contract no-promotion guard.
|
|
- `pest-testing`: focused Pest 4 test implementation and validation.
|
|
- **Hard-gate stop conditions checked**: no unrelated dirty files; no completed spec rewrite; no live provider execution; no evidence rows; no OperationRun creation; no UI/routes/navigation/Filament/Livewire changes; no migrations; no `tenant_id`; no fallback readers, legacy shims, dual writes, customer output, restore/certification/customer claim, or Exchange mini-platform required.
|
|
|
|
## Repo Truth And Path Decisions
|
|
|
|
- **Spec 429 source path**: `specs/429-exchange-teams-source-surface-catalog-adapter-strategy/implementation-report.md` identifies `new_exchange_powershell_adapter` as the recommended first Spec 430 adapter path and lists `transportRule`, `remoteDomain`, and `inboundConnector` as the first Exchange PowerShell slice candidates.
|
|
- **Runtime support path**: use the existing TenantConfiguration/Coverage v2 service path under `apps/platform/app/Services/TenantConfiguration/`.
|
|
- **Command contract support file**: `apps/platform/app/Services/TenantConfiguration/ExchangePowerShellCommandContracts.php`.
|
|
- **Resolver integration**: `apps/platform/app/Services/TenantConfiguration/CoverageSourceContractResolver.php`.
|
|
- **Registry metadata updates**: `apps/platform/app/Services/TenantConfiguration/ResourceTypeRegistry.php`, `SupportedScopeResolver.php`, and `CoverageIdentityStrategyRegistry.php` only where required for `inboundConnector` and the three included identity handoffs.
|
|
- **Fake runner boundary**: `apps/platform/tests/Support/TenantConfiguration/Spec430ExchangePowerShellFakeCommandRunner.php`; no production runner is introduced or wired.
|
|
- **Focused tests**: new Spec 430 Pest files under `apps/platform/tests/Unit/Support/TenantConfiguration/` and `apps/platform/tests/Feature/TenantConfiguration/`.
|
|
|
|
## Included And Excluded Types
|
|
|
|
- **Included**: `transportRule`, `remoteDomain`, `inboundConnector`.
|
|
- **Excluded/deferred**: `acceptedDomain`, `organizationConfig`, `mailboxPlan`, `outboundConnector`, `sharingPolicy`, Teams policy types including `appPermissionPolicy`, `appSetupPolicy`, `meetingPolicy`, `messagingPolicy`, `teamsUpdateManagementPolicy`, `teamsChannelsPolicy`, `externalAccessPolicy`, and the rest of Cohort 1.
|
|
|
|
## Implementation Summary
|
|
|
|
Implemented the first Exchange PowerShell adapter-contract slice as a structured, no-live-execution command contract boundary for:
|
|
|
|
- `transportRule` -> `Get-TransportRule`
|
|
- `remoteDomain` -> `Get-RemoteDomain`
|
|
- `inboundConnector` -> `Get-InboundConnector`
|
|
|
|
The contract boundary is metadata-only and fake-runner-testable. It does not introduce a production runner, shell execution, provider calls, Microsoft service calls, evidence promotion, OperationRun creation, compare/render/certification/restore/customer readiness, UI, routes, navigation, downloads, or customer-facing copy.
|
|
|
|
## Files Changed
|
|
|
|
Runtime:
|
|
|
|
- `apps/platform/app/Services/TenantConfiguration/ExchangePowerShellCommandContracts.php`
|
|
- `apps/platform/app/Services/TenantConfiguration/CoverageSourceContractResolver.php`
|
|
- `apps/platform/app/Services/TenantConfiguration/ClaimGuard.php`
|
|
- `apps/platform/app/Services/TenantConfiguration/CoverageIdentityStrategyRegistry.php`
|
|
- `apps/platform/app/Services/TenantConfiguration/ResourceTypeRegistry.php`
|
|
- `apps/platform/app/Services/TenantConfiguration/SupportedScopeResolver.php`
|
|
|
|
Tests:
|
|
|
|
- `apps/platform/tests/Support/TenantConfiguration/Spec430ExchangePowerShellFakeCommandRunner.php`
|
|
- `apps/platform/tests/Unit/Support/TenantConfiguration/Spec430ExchangePowerShellCommandAllowlistTest.php`
|
|
- `apps/platform/tests/Unit/Support/TenantConfiguration/Spec430TransportRuleCommandContractTest.php`
|
|
- `apps/platform/tests/Unit/Support/TenantConfiguration/Spec430RemoteDomainCommandContractTest.php`
|
|
- `apps/platform/tests/Unit/Support/TenantConfiguration/Spec430InboundConnectorCommandContractTest.php`
|
|
- `apps/platform/tests/Unit/Support/TenantConfiguration/Spec430ExchangePowerShellResolverTest.php`
|
|
- `apps/platform/tests/Unit/Support/TenantConfiguration/Spec430ExchangePowerShellMetadataTest.php`
|
|
- `apps/platform/tests/Feature/TenantConfiguration/Spec430ExchangePowerShellNoPromotionTest.php`
|
|
- Focused Spec 417/419/420/426/427 regression expectations updated for the verified-pending source-contract state and `inboundConnector` default-sync denominator.
|
|
|
|
Spec artifacts:
|
|
|
|
- `specs/430-exchange-powershell-adapter-contract-slice-1/implementation-report.md`
|
|
|
|
## Command Boundary And Allowlist Proof
|
|
|
|
- Only the three read-only command names are allowlisted: `Get-TransportRule`, `Get-RemoteDomain`, `Get-InboundConnector`.
|
|
- Mutation command families are rejected before fake-runner execution: `Set-*`, `New-*`, `Remove-*`, `Enable-*`, `Disable-*`, `Update-*`, `Start-*`, `Stop-*`, `Invoke-*`, `Search-*`, `Export-*`, and `Import-*`.
|
|
- Raw command strings, shell metacharacters, pipelines, script blocks, semicolon-separated commands, redirection, file writes, module installation fragments, unknown commands, and unknown parameters are rejected.
|
|
- The fake runner accepts only structured contract arrays and returns test-only structured results. No production runner was added.
|
|
|
|
## Resolver Proof
|
|
|
|
- `transportRule`, `remoteDomain`, and `inboundConnector` now resolve to:
|
|
- `source_contract_state`: `contract_verified_pending_capture`
|
|
- `provider_adapter_state`: `adapter_contract_available`
|
|
- `outcome`: `capture_blocked_missing_contract`
|
|
- `provider_calls_allowed`: `false`
|
|
- `execution_enabled`: `false`
|
|
- `evidence_promotion_allowed`: `false`
|
|
- `customer_claims_allowed`: `false`
|
|
- `restore_allowed`: `false`
|
|
- `certification_allowed`: `false`
|
|
- `CoverageSourceContractDecision::capturable()` remains false for these decisions because there is no source endpoint and the outcome is blocked pending capture.
|
|
- Excluded Exchange and Teams types remain blocked/deferred. No guessed Graph endpoint or fallback reader was added.
|
|
|
|
## Metadata Proof
|
|
|
|
- Permission metadata is `runtime_validation_pending`, includes `Exchange.ManageAsApp` only as a pending runtime validation note, and keeps Exchange RBAC validation deferred to a future execution spec.
|
|
- Response-shape metadata distinguishes empty collection, permission denied, command unavailable, adapter unavailable, malformed response, and unexpected object shape.
|
|
- Identity handoff rejects display-name-only identity and records stable/derived candidates per type.
|
|
- Redaction metadata forbids tokens, secrets, authorization headers, cookies, certificate private material, passwords, raw transcripts, raw shell stdout/stderr, mail body/content, mailbox content, file content, and Teams transcript/content.
|
|
- Protected configuration examples cover email/domain/rule-pattern fields for transport rules, domain fields for remote domains, and IP/certificate/routing metadata for inbound connectors.
|
|
- Provider-owned Exchange cmdlet and response-field details remain internal source-contract metadata, not customer vocabulary, platform-core ownership truth, or product surface copy.
|
|
- Future execution scope requires workspace, managed environment, and provider connection. Provider-native scope identifiers are metadata only and cannot bypass workspace/provider scope.
|
|
|
|
## Claim And Promotion Boundary
|
|
|
|
- The only allowed claim wording is the exact internal/operator-only statement: `Exchange PowerShell adapter contracts exist for transportRule, remoteDomain, and inboundConnector.`
|
|
- The same statement is blocked when not marked internal/operator-only.
|
|
- No customer claim, certification, restore, compare/render, content-backed evidence, or readiness promotion is introduced.
|
|
- No `TenantConfigurationResource`, `TenantConfigurationResourceEvidence`, or OperationRun record is created by this slice.
|
|
|
|
## Product Surface And Filament Close-Out
|
|
|
|
- Product Surface Impact: no rendered product surface changed.
|
|
- UI Surface Impact: none.
|
|
- Page archetype/surface budgets/Technical Annex/deep-link demotion/canonical status vocabulary: `N/A - no rendered UI surface changed`.
|
|
- Product Surface exceptions: none.
|
|
- Focused browser proof: `N/A - no rendered UI surface changed`.
|
|
- Human Product Sanity: `N/A - no product surface changed`.
|
|
- Visible complexity outcome: unchanged.
|
|
- No-legacy posture: no legacy shim, fallback reader, dual truth, v1 adapter, or mini-platform added.
|
|
- Livewire v4 compliance: no Livewire/Filament runtime code changed; repo baseline remains Livewire v4.
|
|
- Provider registration: no panel/provider changes; Laravel providers remain in `apps/platform/bootstrap/providers.php`.
|
|
- Global search: no Filament resource/global search surface changed.
|
|
- Destructive/high-impact actions: none added.
|
|
- Asset strategy: no assets registered; `filament:assets` is not required for this slice.
|
|
- Deployment impact: no env vars, migrations, queues, scheduler, storage, assets, or browser build required. Runtime default sync now adds `inboundConnector` to registry/scope defaults when `ResourceTypeRegistry::syncDefaults()` and `SupportedScopeResolver::syncDefaults()` are run; migration baseline stays historical at 32 resource rows.
|
|
|
|
## Validation
|
|
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec430 --compact`
|
|
- 64 passed, 479 assertions.
|
|
- Selected Spec 426 regressions:
|
|
- `Spec426ExchangeTeamsSourceContractResolverTest`
|
|
- `Spec426ExchangeTeamsCoreEvidenceReadinessTest`
|
|
- `Spec426ExchangeTeamsNoCertificationTest`
|
|
- `Spec426ExchangeTeamsNoRestoreTest`
|
|
- `Spec426ExchangeTeamsNoMiniPlatformTest`
|
|
- `Spec426ExchangeTeamsNoTenantIdTest`
|
|
- 11 passed, 123 assertions.
|
|
- Selected Spec 427 regressions:
|
|
- `Spec427ExchangeTeamsSourceContractStateTest`
|
|
- `Spec427ExchangeTransportRuleContractTest`
|
|
- `Spec427SourceContractIdentityHandoffTest`
|
|
- `Spec427SourceContractPermissionMetadataTest`
|
|
- `Spec427SourceContractRedactionTest`
|
|
- `Spec427SourceContractResponseShapeTest`
|
|
- `Spec427ExchangeTeamsNoEvidencePromotionTest`
|
|
- `Spec427ExchangeTeamsNoCompareRenderCertificationTest`
|
|
- `Spec427ExchangeTeamsNoCustomerRestoreClaimTest`
|
|
- `Spec427ExchangeTeamsNoMiniPlatformTest`
|
|
- `Spec427ExchangeTeamsNoTenantIdTest`
|
|
- 30 passed, 306 assertions.
|
|
- Registry/identity/capture outcome regressions:
|
|
- `Spec415CoverageCaptureOutcomeTest`
|
|
- `Spec419M365WorkloadRegistryTest`
|
|
- `Spec419M365RegistryExpansionTest`
|
|
- `TenantConfigurationResourceTypeRegistryTest`
|
|
- `Spec420M365CaptureEligibilityTest`
|
|
- `Spec417CoverageIdentityStrategyRegistryTest`
|
|
- 21 passed, 983 assertions, 1 PostgreSQL-only check skipped in the local driver.
|
|
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
|
- pass.
|
|
- `git diff --check`
|
|
- pass.
|
|
- `rg -- "- \[ \]" specs/430-exchange-powershell-adapter-contract-slice-1/tasks.md`
|
|
- no unchecked Spec 430 tasks remain.
|
|
- Broad parallel `Spec426`/`Spec427`/`Spec428` filter attempts were not used as final proof because Sail processes were killed with signal 9 under parallel load. Final proof uses serial direct-file runs listed above.
|
|
- Spec 428 executable test status: no `apps/platform/tests/**/Spec428*.php` files exist. Spec 428 remains a prepared no-op spec package; runtime no-evidence proof is covered by the Spec430 and selected Spec427 no-promotion tests above.
|
|
|
|
## Post-Implementation Analysis
|
|
|
|
- Iteration 1 finding: adding `capture_blocked_pending_capture` as a new `CaptureOutcome` enum value would have diverged from the historical evidence-table check constraint while this spec explicitly avoids migrations and does not persist blocked evidence.
|
|
- Fix applied: keep `contract_verified_pending_capture` as the resolver/source-contract state and use the existing `capture_blocked_missing_contract` capture outcome for non-capturable transient capture result rows.
|
|
- Post-fix validation: final Spec430, Spec426, Spec427, registry/identity/capture outcome, Pint, and `git diff --check` validations passed.
|
|
- Browser Smoke Test Gate: passed as N/A because no rendered UI surface changed.
|
|
- Remaining confirmed in-scope findings: none.
|
|
|
|
## Final Repository State
|
|
|
|
- Final dirty state is expected implementation work: runtime TenantConfiguration/Coverage v2 service updates, focused Spec 417/419/420/426/427 regression updates, new Spec 430 tests/support fake runner, and the active Spec 430 package.
|
|
- No unrelated dirty files were observed.
|
|
|
|
## Deferred Work
|
|
|
|
- A future spec must add any production Exchange PowerShell execution adapter, runtime RBAC/permission validation, provider connection handshake, command execution, capture normalization, evidence promotion, compare/render/certification/restore behavior, UI, or customer-facing claims.
|