TenantAtlas/specs/431-exchange-powershell-invocation-operation-registration-gate/spec.md
ahmido 9374260ae1 feat: add Exchange PowerShell invocation gate (#498)
## Summary
- Adds the Spec 431 Exchange PowerShell invocation gate and operation registration slice.
- Introduces trusted provider operation start handling and read-only Exchange PowerShell runner abstractions.
- Updates provider capability/readiness evaluation and coverage for Exchange PowerShell invocation safety.

## Verification
- `cd apps/platform && ./vendor/bin/sail artisan test tests/Feature/Providers/ProviderCapabilityEvaluationTest.php tests/Feature/Providers/ProviderOperationCapabilityGateTest.php tests/Feature/TenantConfiguration/Spec431ExchangePowerShellInvocationGateTest.php tests/Unit/Providers/ProviderCapabilityRegistryTest.php tests/Unit/Providers/ProviderOperationStartGateTest.php tests/Unit/Support/TenantConfiguration/Spec430ExchangePowerShellCommandAllowlistTest.php tests/Unit/Support/TenantConfiguration/Spec431ExchangePowerShellOperationRegistrationTest.php tests/Unit/Verification/ManagedEnvironmentPermissionCapabilityMappingTest.php`
- Result: 80 passed, 685 assertions.

## Product Surface / Ops
- Rendered UI surface changed: N/A.
- Filament/Livewire surface changed: N/A.
- Deployment impact: config/runtime service changes only; no migrations, queues, or assets added.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #498
2026-07-07 15:23:29 +00:00

34 KiB

Feature Specification: Exchange PowerShell Invocation Operation Registration and Execution Gate

Feature Branch: 431-exchange-powershell-invocation-operation-registration-gate
Created: 2026-07-05
Status: Draft
Input: User-provided Spec 431 draft for Exchange PowerShell invocation operation registration, capability gating, and fake-runner proof.

Preparation Selection

  • Selected candidate: Spec 431 - Exchange PowerShell Invocation Operation Registration and Execution Gate.
  • Source location: Direct user-provided candidate in the July 5, 2026 preparation request.
  • Why selected: The active auto-prep queue in docs/product/spec-candidates.md is empty, but the user explicitly supplied a manual candidate that follows completed Spec 430 and narrows the next Exchange PowerShell step to operation registration and gated fake invocation only.
  • Roadmap relationship: Builds on Coverage v2, OperationRun observability, provider operation/capability wiring, and the Spec 429/430 Exchange PowerShell sequence without promoting Exchange evidence or customer claims.
  • Completed-spec guardrail result: Specs 429 and 430 are completed implementation context and were not modified. Spec 430's implementation report proves transportRule, remoteDomain, and inboundConnector command contracts and explicitly leaves OperationRun invocation, provider execution, evidence, UI, migrations, and customer claims out of scope. No existing specs/431-* package existed before this preparation.
  • Smallest viable implementation slice: Register one canonical OperationRun invocation type, one provider operation, one internal provider capability, one capability resolver mapping, one gate, and a structured fake-runner path for exactly transportRule, remoteDomain, and inboundConnector.
  • Feature description fed into Spec Kit: Prepare a safe OperationRun-owned Exchange PowerShell invocation path for the three Spec 430 contracts, with provider/capability registration, summary/failure sanitization, fake-runner proof, production execution disabled, no evidence, no UI, no migration, and no customer claims.

Spec Candidate Check (mandatory - SPEC-GATE-001)

  • Problem: Spec 430 proves safe command contracts but the operation/provider/capability path does not yet know how to represent or gate an Exchange PowerShell invocation attempt.
  • Today's failure: A later evidence spec would either have to bypass OperationRun/provider registries or invent execution plumbing while also trying to promote evidence, increasing risk of provider calls, raw output persistence, missing capability checks, or false customer readiness claims.
  • User-visible improvement: Operators and reviewers gain an auditable internal truth: an Exchange PowerShell invocation attempt can be represented, started, blocked, failed, and summarized through existing operation/provider guardrails without claiming capture or evidence readiness.
  • Smallest enterprise-capable version: One canonical operation type, one catalog entry, one provider operation, one internal provider capability, one resolver mapping, safe summary/failure plumbing, a single gate service, a structured runner interface, and a fake runner for the three Spec 430 commands.
  • Explicit non-goals: No live Exchange Online execution, no PowerShell process, no Microsoft service calls, no evidence rows, no content-backed/comparable/renderable/certified/restore/customer state, no UI, no routes, no jobs, no scheduled capture, no migration, no tenant_id, no Exchange mini-platform.
  • Permanent complexity imported: Adds one OperationRun type, catalog entry, provider operation entry, provider capability entry, capability mapping, invocation gate service, runner interface, fake runner, failure mappings, and focused tests. No new tables, persisted status framework, UI taxonomy, customer claim state, or evidence subsystem.
  • Why now: Spec 430's contract slice is complete and the next safe step before evidence promotion is proving that invocation attempts are OperationRun-owned, capability-gated, provider-scoped, and fake-runner-testable.
  • Why not local: This cannot be only local to a later capture service because remote/provider work must be observable through OperationRun, registered in provider operation/capability registries, sanitized by central OperationRun UX plumbing, and blocked by shared capability/scope gates.
  • Approval class: Core Enterprise.
  • Red flags triggered: New operation type, registry entries, capability mapping, interface, and service. Defense: each extension attaches to an existing repo mechanism required for OperationRun observability, RBAC/provider scope safety, and no-provider-call proof; no new persisted truth or broad platform framework is introduced.
  • Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 1 | Wiederverwendung: 2 | Gesamt: 10/12
  • Decision: approve as a narrow operation-registration and fake-runner gate slice.

Spec Scope Fields (mandatory)

  • Scope: canonical-view / environment-bound operation start path.
  • Primary Routes: N/A - no routes or rendered UI surfaces.
  • Data Ownership: No new persisted entity. OperationRun rows remain existing operation truth and must use existing workspace_id plus managed_environment_id; provider_connection_id is safe context only.
  • RBAC: Workspace and managed-environment membership required; non-member or non-entitled scope returns 404. Member without invocation capability returns 403. Readonly cannot invoke. Provider connection must belong to the same workspace and managed environment.

For canonical-view specs:

  • Default filter behavior when tenant-context is active: N/A - no rendered canonical view changed.
  • Explicit entitlement checks preventing cross-tenant leakage: Invocation service must require workspace, managed environment, provider connection, actor/context, and operation type; cross-workspace/cross-environment provider connections are rejected before any runner call.

No Legacy / No Backward Compatibility Constraint (mandatory)

TenantPilot is pre-production unless this spec explicitly records a compatibility exception.

  • Compatibility posture: canonical addition only.
  • Legacy aliases, fallback readers, hidden routes, duplicate UI, old labels, or historical fixtures kept?: no.
  • Why clean replacement is safe now: This is a new operation path for a previously unregistered invocation type. No production data, external API consumer, or legacy operation value depends on it.

UI Surface Impact (mandatory - UI-COV-001)

Does this spec add, remove, rename, or materially change any reachable UI surface?

  • No UI surface impact
  • Existing page changed
  • New page/route added
  • Navigation changed
  • Filament panel/provider surface changed
  • New modal/drawer/wizard/action added
  • New table/form/state added
  • Customer-facing surface changed
  • Dangerous action changed
  • Status/evidence/review presentation changed
  • Workspace/environment context presentation changed

UI/Productization Coverage (mandatory when UI Surface Impact is not "No UI surface impact"; otherwise write N/A - no reachable UI surface impact plus rationale)

N/A - no reachable UI surface impact. This spec registers and gates a backend operation path only. It forbids routes, Filament pages, Livewire components, navigation, global search changes, asset changes, execution buttons, capture buttons, dashboard badges, report output, and Review Pack output.

Product Surface Impact (mandatory for UI-affecting specs; otherwise write N/A - no rendered product surface changed plus rationale)

Reference: docs/product/standards/product-surface-contract.md.

  • Product Surface Contract applies?: no - no rendered product surface changed.
  • Page archetype: N/A.
  • Primary user question: N/A.
  • Primary action: N/A.
  • Surface budget result: N/A.
  • Technical Annex / deep-link demotion: N/A - no default product view changed. OperationRun remains an internal/audit truth only.
  • Canonical status vocabulary: N/A - no product-facing statuses changed.
  • Visible complexity impact: neutral.
  • Product Surface exceptions: none.

Browser Verification Plan (mandatory)

  • Browser proof required?: no.
  • No-browser rationale: N/A - no rendered UI surface changed.
  • Focused path when required: N/A.
  • Primary interaction to execute: N/A.
  • Console, Livewire, Filament, network, and 500-error checks: N/A.
  • Full-suite failure triage: N/A.

Human Product Sanity Check (mandatory)

  • Required?: no.
  • No-human-sanity rationale: N/A - no product surface changed.
  • Reviewer questions: N/A.
  • Planned result location: implementation-report.md.

Product Surface Merge Gate Checklist (mandatory)

  • No-legacy posture or approved exception recorded.
  • Product Surface Impact is completed or N/A is justified.
  • Browser proof is completed or N/A - no rendered UI surface changed is justified.
  • Human Product Sanity is completed or not applicable with rationale.
  • Product Surface exceptions are documented or none.
  • Implementation report will state Livewire v4 compliance, provider registration location, global search posture, destructive/high-impact action posture, asset strategy, tests/browser result, deployment impact, and visible complexity outcome.

Cross-Cutting / Shared Pattern Reuse (mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write N/A - no shared interaction family touched)

  • Cross-cutting feature?: yes.
  • Interaction class(es): OperationRun lifecycle and operation/provider gate summaries.
  • Systems touched: OperationRunType, OperationCatalog, OperationRunService, ProviderOperationRegistry, ProviderCapabilityRegistry, OperationRunCapabilityResolver, OperationSummaryKeys, SummaryCountsNormalizer, RunFailureSanitizer, ProviderOperationStartGate or a composed equivalent.
  • Existing pattern(s) to extend: existing OperationRun architecture, provider operation registry, provider capability registry, OperationRun capability resolver, summary/failure sanitizer path.
  • Shared contract / presenter / builder / renderer to reuse: OperationRun lifecycle and provider operation/capability contracts. No UI presenter is added.
  • Why the existing shared path is sufficient or insufficient: Existing paths provide operation truth, provider binding, summary normalization, and provider connection context. They need one bounded operation/capability addition and a gate because Spec 430 intentionally did not start runs.
  • Allowed deviation and why: none planned. ExchangePowerShellInvocationGate is the sole public invocation entry point for Spec 431. It may compose with ProviderOperationStartGate internally, but feature code and tests must not call the runner or ProviderOperationStartGate directly for this Exchange PowerShell invocation.
  • Consistency impact: Invocation attempts must use existing OperationRun status/outcome transitions, flat numeric summary counts, sanitized reason codes/messages, and provider connection context shape.
  • Review focus: Verify no direct runner invocation, direct shell/process execution, raw PowerShell command strings, or OperationRun status/outcome updates outside OperationRunService.
  • Touches OperationRun start/completion/link UX?: yes, backend OperationRun creation and lifecycle only; no rendered UX surface or deep link is added.
  • Shared OperationRun UX contract/layer reused: Existing OperationRun lifecycle and summary/failure sanitizer path. No local UI messages, toasts, links, or browser events.
  • Delegated start/completion UX behaviors: N/A - no start surface, toast, DB notification policy change, run link, artifact link, or browser event.
  • Local surface-owned behavior that remains: none.
  • Queued DB-notification policy: N/A - no queued DB notification opt-in.
  • Terminal notification path: central lifecycle mechanism if OperationRun reaches terminal status. Tests must prove no feature-local completion notification is introduced.
  • Exception required?: none.

Provider Boundary / Platform Core Check (mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write N/A - no shared provider/platform boundary touched)

  • Shared provider/platform boundary touched?: yes.
  • Boundary classification: mixed, with provider-owned Exchange PowerShell command semantics behind platform-core operation/provider registries.
  • Seams affected: provider operation registry, provider capability registry, OperationRun capability resolver, OperationRun context provider connection metadata, Exchange PowerShell command contracts.
  • Neutral platform terms preserved or introduced: operation, provider connection, managed environment, workspace, capability, source contract, runner mode, summary counts, failure reason.
  • Provider-specific semantics retained and why: Exchange command names and target types are retained inside provider-owned command contracts because the current slice is explicitly Exchange PowerShell only.
  • Why this does not deepen provider coupling accidentally: Platform-core registries only receive one operation/capability entry and do not adopt Exchange payloads, command vocabulary, or provider-native tenant identifiers as platform ownership truth.
  • Follow-up path: document-in-feature; production runtime hardening and evidence promotion remain follow-up specs.

UI / Surface Guardrail Impact (mandatory when operator-facing surfaces are changed; otherwise write N/A)

N/A - no operator-facing surface change.

Proportionality Review (mandatory when structural complexity is introduced)

Spec 431 introduces structural runtime concepts and must justify each before implementation.

Concept Existing mechanism extended Why needed now Narrowness control
OperationRunType value OperationRunType, OperationCatalog Invocation attempts need canonical operation truth before any later evidence spec can start work safely. One value only: tenant_configuration.exchange_powershell_invocation unless repo convention forces a documented equivalent.
Provider operation entry ProviderOperationRegistry Provider work must be explicitly registered and bound before it can be started or blocked. One operation mapped to the canonical OperationRun type.
Provider capability ProviderCapabilityRegistry Provider readiness and permissions must fail closed and stay internal. One internal capability such as exchange_powershell_invoke; no customer readiness semantics.
Capability resolver mapping OperationRunCapabilityResolver and App\Support\Auth\Capabilities::PROVIDER_RUN Actor execution authorization must be resolved consistently for the operation. Reuse the existing provider-run actor capability unless implementation stops and amends the spec for a narrower dedicated actor capability; no new capability framework.
Summary/failure additions OperationSummaryKeys, SummaryCountsNormalizer, RunFailureSanitizer Invocation runs must preserve safe counts and sanitize blockers/failures. Reuse existing keys by default; add keys only if tests prove unavoidable.
Invocation gate service Existing service/action pattern and provider gates Prevents direct runner calls and centralizes command, scope, feature, credential, and capability gates. One service only; no Exchange mini-platform.
Runner interface Service boundary for structured fake execution Required to fake test execution outcomes without provider calls or shell execution. Structured command contract only; no raw command strings or pipelines.
Fake runner Test support Required proof for success/failure/shape paths with no Microsoft calls. Test-only behavior; no production provider execution.
Disabled production runner Optional boundary Only allowed if it returns blocked by default. No PowerShell binary, module install, or Exchange Online connection.

Answers required by BLOAT-001:

  1. Current operator problem: The platform cannot honestly claim an auditable Exchange invocation path exists, and later evidence work would risk bypassing OperationRun/provider safety.
  2. Why existing structure is insufficient: Existing OperationRun/provider registries have no Exchange invocation operation/capability mapping and Spec 430 explicitly disabled OperationRun invocation.
  3. Narrowest correct implementation: Register and fake-prove one internal invocation operation for three already verified command contracts.
  4. Ownership cost: Maintains one operation/capability/gate/runner test surface that future Exchange evidence specs must respect.
  5. Rejected alternative: Directly invoking a runner from a capture service or implementing live Exchange execution in the evidence spec.
  6. Current-release truth or future-release preparation: Current-release safety truth for the next Exchange evidence slice; not customer-facing readiness.

Forbidden proportionality outcomes:

  • no new persisted status framework
  • no new operation table family
  • no Exchange mini-platform
  • no provider subsystem unrelated to existing registries
  • no UI surface
  • no migration for provider_connection_id
  • no evidence persistence
  • no customer claim state

User Stories & Tests (mandatory)

User Story 1 - Registered Operation Path (Priority: P1)

As a platform reviewer, I need the Exchange PowerShell invocation operation to be registered in OperationRun and provider registries so any future invocation attempt is governed by canonical operation truth instead of ad-hoc service code.

Independent Test: Unit tests prove the OperationRun type exists, OperationCatalog resolves it, ProviderOperationRegistry maps it, ProviderCapabilityRegistry contains the required capability, and OperationRunCapabilityResolver resolves the required actor capability.

Acceptance Scenarios:

  1. Given tenant_configuration.exchange_powershell_invocation, When OperationCatalog resolves it, Then it returns a known internal operation label and does not expose customer-facing claims.
  2. Given the provider operation registry, When the invocation operation is requested, Then it resolves to the canonical OperationRun type and internal provider capability.
  3. Given a member without the required execution capability, When the operation is evaluated, Then execution fails closed with a sanitized missing-capability blocker.

User Story 2 - Gated Fake Invocation (Priority: P1)

As an implementation reviewer, I need a fake-runner invocation path that creates an OperationRun before execution and proves success, block, failure, and malformed-output behavior without any provider or shell calls.

Independent Test: Feature/unit tests invoke the gate in fake-runner mode for transportRule, remoteDomain, and inboundConnector, proving safe OperationRun context, safe summaries, sanitized failures, and no evidence.

Acceptance Scenarios:

  1. Given an authorized actor, same-scope provider connection, enabled test feature gate, fake-runner mode, verified Spec 430 contract, and allowlisted command, When the gate runs, Then an OperationRun is created before runner invocation and only safe summary counts are persisted.
  2. Given a missing credential reference in non-fake mode, When invocation is requested, Then it is blocked with execution_blocked_missing_credential_reference or a repo-equivalent sanitized code before runner execution.
  3. Given malformed scalar/text fake output, When shape validation runs, Then the operation fails safely as execution_failed_shape_unsafe or a repo-equivalent sanitized code and is not treated as empty success.

User Story 3 - No Promotion or Product Surface (Priority: P1)

As a release reviewer, I need the invocation operation to remain internal and no-promotion only so it cannot be interpreted as Exchange evidence readiness.

Independent Test: Guard/feature tests prove no evidence rows, no content-backed/comparable/renderable/certified/restore/customer states, no routes/UI/assets/global search changes, no tenant_id, and no raw output/provider payload persisted.

Acceptance Scenarios:

  1. Given any successful fake invocation, When persistence is inspected, Then no tenant_configuration_resource_evidence row or normalized evidence payload exists.
  2. Given OperationRun context after a fake invocation, When it is inspected, Then provider_connection_id appears only as sanitized context and no raw stdout/stderr/provider payload/token/secret/certificate material is present.
  3. Given the codebase after implementation, When route/UI/Filament/Livewire/assets/search surfaces are scanned, Then no rendered product surface changed.

Functional Requirements

  • FR-431-001: The implementation MUST include exactly transportRule, remoteDomain, and inboundConnector as invocation targets.
  • FR-431-002: The only command contracts in scope MUST be Get-TransportRule, Get-RemoteDomain, and Get-InboundConnector.
  • FR-431-003: The implementation MUST add one canonical OperationRun type, recommended as tenant_configuration.exchange_powershell_invocation unless repo convention requires a documented equivalent.
  • FR-431-004: The operation MUST be registered in OperationCatalog with internal/operator-only semantics and no customer claim language.
  • FR-431-005: The operation MUST be registered in ProviderOperationRegistry and mapped to the canonical OperationRun type.
  • FR-431-006: The implementation MUST add or map one internal provider capability for Exchange PowerShell invocation, recommended as exchange_powershell_invoke or repo-canonical equivalent.
  • FR-431-007: OperationRunCapabilityResolver MUST resolve the required actor execution capability for the invocation operation to App\Support\Auth\Capabilities::PROVIDER_RUN, unless implementation stops and amends this spec for a narrower dedicated actor capability. Unresolved or unknown capability MUST fail closed.
  • FR-431-008: Summary counts MUST use allowed OperationSummaryKeys only. Preferred mapping is total, processed, succeeded, failed, skipped, and items.
  • FR-431-009: Tests MUST prove emitted summary keys are preserved and unknown summary keys remain dropped.
  • FR-431-010: Invocation blocker/failure reasons MUST normalize through RunFailureSanitizer or a repo-equivalent central path without leaking raw exception text.
  • FR-431-011: The implementation MUST provide one invocation gate service under the repo-canonical TenantConfiguration/provider operation service path.
  • FR-431-012: The gate MUST require verified Spec 430 source contracts, allowlisted commands, contract-defined parameters, a registered OperationRun type, registered provider operation, registered provider capability, actor capability Capabilities::PROVIDER_RUN, provider scope, feature gate tenant_configuration.exchange_powershell_invocation backed by tenantpilot.features.exchange_powershell_invocation, runner mode, redaction policy, and existing provider identity/credential resolution through ProviderIdentityResolver, ProviderConnection::credential, and ProviderCredential unless explicitly in fake-runner-only test mode.
  • FR-431-013: The runner interface MUST accept structured command contracts and structured invocation context only.
  • FR-431-014: The runner interface MUST reject raw command strings, script blocks, pipelines, arbitrary parameters, shell fragments, semicolon-separated commands, redirection, file writes, and module installation commands.
  • FR-431-015: A fake runner MUST support success, empty success, authentication failure, authorization failure, permission failure, timeout, throttling, module unavailable, command unavailable, malformed result, and unexpected exception.
  • FR-431-016: Any production runner boundary MUST be disabled/inert by default and return a sanitized blocked result without PowerShell execution or Microsoft calls.
  • FR-431-017: The implementation MUST create OperationRuns before fake invocation and route status/outcome transitions through OperationRunService.
  • FR-431-018: provider_connection_id MUST remain in sanitized OperationRun context and MUST NOT be added as an operation_runs column.
  • FR-431-019: OperationRun context MUST NOT persist raw provider payload, raw stdout, raw stderr, transcripts, raw exception text, tokens, secrets, cookies, authorization headers, certificate material, mail body, message content, mailbox content, or file content.
  • FR-431-020: Shape validation MUST distinguish structured collections, valid empty collections, permission failures, command/module failures, malformed output, and missing identity candidate fields.
  • FR-431-021: Workspace, managed-environment, and provider-connection scope MUST be enforced server-side; non-member/not-entitled scope is 404 and member-without-capability is 403.
  • FR-431-022: The feature gate for invocation MUST use logical key tenant_configuration.exchange_powershell_invocation, repo config path tenantpilot.features.exchange_powershell_invocation, and default disabled outside controlled test/service contexts.
  • FR-431-023: The implementation MUST prove no evidence, normalized evidence, content-backed, comparable, renderable, certified, restore-ready, customer-ready, report, Review Pack, UI, route, job, scheduled capture, or global search promotion.
  • FR-431-024: The implementation MUST introduce no tenant_id, legacy shim, fallback reader, dual-write path, or Exchange-specific evidence table.

Non-Functional Requirements

  • NFR-431-001: Use existing Laravel service and dependency-injection patterns; avoid broad provider frameworks.
  • NFR-431-002: All persisted summaries are flat numeric counts after SummaryCountsNormalizer.
  • NFR-431-003: Failure messages and codes are safe, bounded, and redacted.
  • NFR-431-004: Tests must use fake runners and must not start a PowerShell process or call Microsoft services.
  • NFR-431-005: No new runtime dependency, container image requirement, Dokploy runtime requirement, environment variable, scheduler, or queue worker requirement is introduced.

Data / Truth Source Requirements

  • Execution truth: Existing OperationRun rows.
  • Provider scope truth: Existing ProviderConnection scoped by workspace_id and managed_environment_id.
  • Provider credential truth: Existing ProviderIdentityResolver, ProviderConnection::credential, ProviderCredential, and existing credential-source metadata. Spec 431 MUST NOT create a new credential source; if the existing resolver path cannot prove a non-fake credential/identity reference, non-fake mode blocks.
  • Actor capability truth: Existing App\Support\Auth\Capabilities::PROVIDER_RUN unless a spec amendment approves a narrower dedicated actor capability.
  • Feature gate truth: Logical gate tenant_configuration.exchange_powershell_invocation, implemented through tenantpilot.features.exchange_powershell_invocation, default false.
  • Source contract truth: Existing ExchangePowerShellCommandContracts and CoverageSourceContractResolver states from Spec 430.
  • Evidence truth: N/A - no evidence is created or promoted.
  • Customer claim truth: N/A - no customer claim is enabled.
  • Migration impact: none.

RBAC / Security Requirements

  • Non-member workspace or managed-environment access MUST deny as not found.
  • Member missing Capabilities::PROVIDER_RUN MUST fail as forbidden. If implementation determines provider.run is too broad for this operation, it MUST stop and amend this spec before adding a new actor capability or role mapping.
  • Readonly role MUST NOT invoke.
  • Provider connection MUST belong to the same workspace and managed environment.
  • Non-fake invocation MUST validate the existing provider identity/credential resolver path without persisting credential material in OperationRun context.
  • Credential material MUST NOT be persisted in OperationRun context, audit metadata, logs, summaries, or tests.
  • Unsupported, expired, or missing credential references MUST block safely.
  • Missing permission evidence MUST block or remain explicitly unvalidated; it MUST NOT be silently treated as least-privilege proof.

Auditability / Observability Requirements

  • Invocation attempts MUST be represented by OperationRun before runner execution.
  • OperationRun lifecycle transitions MUST be service-owned.
  • OperationRun summary counts MUST be safe and allowed.
  • OperationRun reason codes/messages MUST be sanitized.
  • No new UI notification, toast, browser event, or DB notification policy is introduced by this spec.

Out of Scope

  • Live Exchange Online provider execution.
  • Connect-ExchangeOnline or any PowerShell binary/process execution.
  • Installing or configuring ExchangeOnlineManagement.
  • Runtime/container/Dokploy hardening for PowerShell.
  • Evidence persistence, normalized evidence, content-backed promotion, compare/render/certification, restore, customer claims, customer reports, PDFs, Review Pack output.
  • UI, routes, Filament pages, Livewire components, navigation, global search, assets.
  • Scheduled capture, queue-triggered live execution, provider clients, Teams, Exchange Admin API, outboundConnector, acceptedDomain, organizationConfig, mailboxPlan, sharingPolicy.
  • New migration, provider_connection_id column on operation_runs, tenant_id, fallback readers, legacy shims, dual writes.

Claim Guard

Allowed internal statement after implementation:

Exchange PowerShell invocation operation is registered and fake-runner proven for transportRule, remoteDomain, and inboundConnector.

Allowed only with this boundary:

OperationRun-gated invocation path, production execution disabled, no evidence promotion.

Forbidden claims:

Exchange evidence ready
Exchange content-backed
Exchange comparable
Exchange renderable
Exchange certified
Exchange restore-ready
Exchange customer-ready
M365 ready
provider data captured
live Exchange capture works

Acceptance Criteria

AB1 - Spec Package

  • spec.md, plan.md, tasks.md, checklists/requirements.md, and implementation-report.md exist.

AB2 - Operation Registration

  • OperationRun type, OperationCatalog entry, ProviderOperationRegistry entry, ProviderCapabilityRegistry capability, and OperationRunCapabilityResolver mapping exist and are tested.

AB3 - Summary Counts

  • Existing allowed keys are reused or new keys are explicitly added with tests.
  • Unknown keys remain dropped.
  • No raw output appears in summary counts.

AB4 - Failure Sanitization

  • Known blockers, known failures, unknown failures, raw exception text, token-like text, and stderr-like text sanitize safely.

AB5 - Invocation Gate

  • Single gate exists and requires verified contract, allowlisted command, OperationRun, provider scope, capability, feature gate, redaction, and credential/fake-mode policy.

AB6 - Runner Safety

  • Structured runner interface and fake runner exist.
  • Production runner remains disabled/inert.
  • Raw commands, mutation commands, unknown parameters, shell constructs, and arbitrary execution are rejected.

AB7 - OperationRun Safety

  • OperationRun is created before fake invocation.
  • Status/outcome transitions go through OperationRunService.
  • Context is sanitized and contains provider_connection_id only as context.
  • No raw provider output or secret material is persisted.

AB8 - No Evidence / No Product Promotion

  • No evidence rows, raw evidence payload, normalized evidence payload, content-backed/comparable/renderable/certified/restore/customer state, report output, or Review Pack output exists.

AB9 - No Product Surface

  • No routes, Filament pages, Livewire components, navigation, global search, or assets are added or changed.

AB10 - Architecture

  • Existing OperationRun and provider operation/capability architecture is extended narrowly.
  • Coverage v2 source contract architecture remains the source for contract verification.
  • No tenant_id, migration, mini-platform, legacy shim, or fallback reader.

AB11 - Validation

  • Focused unit and feature tests pass.
  • Required Spec 430/426/427/417/419/420 regressions pass or exact unavailable tests are documented.
  • Pint and git diff --check pass.
  • git status --short is documented.

Follow-up Spec Candidates

  • Spec 432 - Exchange PowerShell runtime execution hardening, only if production runner/container/Dokploy/credential validation remains blocked.
  • Spec 433 - Exchange content-backed evidence promotion slice 1, only after Spec 431 proves operation/provider/capability gates.
  • Teams PowerShell invocation/evidence slice, explicitly separate and not included here.

Candidate Selection Gate

PASS. The selected candidate was directly provided by the user, follows completed Spec 430, is not covered by an existing active/completed Spec 431, aligns with the Exchange/Teams sequence, and is narrowed to operation registration plus fake-runner proof with adjacent concerns deferred.

Spec Readiness Gate

PASS for preparation. spec.md, plan.md, tasks.md, checklists/requirements.md, and implementation-report.md define a bounded, testable package for a later implementation loop. No application implementation has been performed.