TenantAtlas/specs/432-exchange-powershell-production-runner-boundary-runtime-gate/spec.md
ahmido f4e342121a feat: add Exchange PowerShell production runner gate (#499)
Spec 432: Exchange PowerShell production runner boundary and runtime gate. Validation: php artisan test --filter=Spec432 --compact; ./vendor/bin/pint --dirty --test --format agent; git diff --check.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #499
2026-07-07 18:34:18 +00:00

41 KiB

Feature Specification: Exchange PowerShell Production Runner Boundary and Runtime Gate

Feature Branch: 432-exchange-powershell-production-runner-boundary-runtime-gate Created: 2026-07-07 Status: Implemented / Validated Input: User-provided Spec 432 draft for an Exchange PowerShell production-runner boundary and runtime gate.

Preparation Selection

  • Selected candidate: Spec 432 - Exchange PowerShell Production Runner Boundary and Runtime Gate.
  • Source location: User-provided attachment pasted-text.txt, titled Spec 432 - Exchange PowerShell Production Runner Boundary & Runtime Gate.
  • Why selected: docs/product/spec-candidates.md states that the active automatic next-best-prep queue is empty, but the user supplied an explicit P0 manual candidate. The candidate is the narrow next step after implemented Specs 430 and 431 and prevents future evidence work from bypassing OperationRun, provider-scope, credential, runtime, and redaction gates.
  • Roadmap relationship: Continues the Exchange/Teams Coverage v2 sequence after Spec 429, Spec 430, and Spec 431. It prepares the production-runner safety boundary before any Exchange evidence, compare, render, certification, restore, or customer claim promotion.
  • Completed-spec guardrail result: Specs 430 and 431 are completed implementation context and were not modified. Spec 430 proves the command-contract slice for transportRule, remoteDomain, and inboundConnector. Spec 431 proves OperationRun/provider operation registration, capability gating, fake-runner behavior, disabled default runner, no evidence, no UI, no migration, and no tenant_id. No existing specs/432-* package existed before this preparation.
  • Smallest viable implementation slice: Define a production-runner boundary that remains disabled by default and can only proceed after explicit config, runtime readiness, supported credential reference, verified Exchange permission evidence, provider scope, OperationRun invocation, command-construction, process-executor, output, timeout, concurrency, and redaction gates all pass. A valid implementation may still block live invocation because credential or permission proof is absent.
  • Feature description fed into Spec Kit: Prepare the Exchange PowerShell production-runner boundary and runtime gate for the three Spec 430 contracts, preserving disabled default behavior, adding explicit production-runner config and safety gates, proving non-invasive runtime and process execution boundaries, and forbidding evidence promotion, product claims, UI, routes, jobs, schedules, listeners, migrations, and tenant_id.

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

  • Problem: TenantPilot now has Exchange PowerShell command contracts and an OperationRun-owned fake invocation path, but it does not yet have a production-runner boundary that proves real process execution cannot be accidentally enabled, unsafe, or mistaken for Exchange evidence readiness.
  • Today's failure: A later evidence or capture spec could accidentally turn the disabled runner into live PowerShell execution without proving runtime readiness, credential kind handling, Exchange permission evidence, no-shell command construction, output safety, timeout/concurrency cleanup, OperationRun redaction, and no-promotion boundaries.
  • User-visible improvement: Operators and reviewers gain a trustworthy internal safety claim: Exchange PowerShell production execution is either gated by all required controls or blocked safely with sanitized OperationRun state. TenantPilot does not falsely imply Exchange evidence readiness.
  • Smallest enterprise-capable version: Add only the runner-boundary and runtime gates around the existing Spec 431 invocation path for transportRule, remoteDomain, and inboundConnector. Live invocation may remain blocked until a later credential/permission evidence spec proves support.
  • Explicit non-goals: No evidence rows, no provider output persistence, no content-backed/comparable/renderable/certified/restore/customer state, no UI, no routes, no Filament or Livewire components, no jobs, no schedules, no listeners that can invoke the runner, no migrations, no Teams, no Exchange Admin API, no mutation commands, no customer report, and no tenant_id.
  • Permanent complexity imported: Likely adds a production runner class, runtime readiness checker, credential reference resolver/evaluator, permission evidence evaluator, process executor abstraction, command builder, runtime policy object, sanitizer mappings, and focused tests. No new tables or customer-facing semantic framework are planned.
  • Why now: Spec 431 closed the internal OperationRun/fake-runner gate. The next safe prerequisite before any Exchange evidence promotion is proving that a production runner cannot be selected or execute unless all runtime, credential, permission, scope, and output gates pass.
  • Why not local: This cannot live only inside a later capture service because the runner-selection, credential, runtime, provider-scope, process, output, and OperationRun redaction boundaries must protect every future live invocation path.
  • Approval class: Core Enterprise.
  • Red flags triggered: New abstractions and new failure/state vocabulary. Defense: the abstractions are security/runtime boundaries required to prevent shell execution, credential leakage, provider-scope bypass, and false evidence claims. Failure states have execution consequences and remain bounded to the runner gate.
  • Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 1 | Wiederverwendung: 2 | Gesamt: 10/12
  • Decision: approve as a narrow production-runner boundary and runtime-gating slice.

Spec Scope Fields (mandatory)

  • Scope: canonical-view / environment-bound operation execution boundary.
  • Primary Routes: N/A - no routes or rendered UI surfaces.
  • Data Ownership: Existing OperationRun remains execution truth with existing workspace and managed-environment ownership. provider_connection_id remains sanitized context metadata only. No new persisted entity or migration.
  • RBAC: Workspace and managed-environment entitlement are required. Non-member or non-entitled scope returns 404. Member without the required invocation capability returns 403 or the repo-equivalent authorization failure. Readonly actors cannot invoke. Provider connection and permission evidence 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: Production-runner gating must reject cross-workspace provider connections, cross-environment provider connections, and wrong-scope Exchange permission evidence before any process execution.

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: Live Exchange PowerShell production execution is not shipped. The default binding is disabled, and no production data or external API consumer depends on a previous production runner.

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 explicitly forbids routes, Filament pages, Livewire components, navigation, buttons, dashboards, readiness badges, customer routes, reports, Review Pack output, global search changes, and asset changes. Service-provider binding changes are backend service-container behavior only and must not change panel provider registration or rendered product access.

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 internal/audit truth and no new links are added.
  • Canonical status vocabulary: N/A - no product-facing statuses changed.
  • Visible complexity impact: neutral for product surfaces.
  • 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, visible complexity outcome, and no completed-spec rewrite assertion.

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 provider-operation execution safety. No rendered interaction family is changed.
  • Systems touched: ExchangePowerShellInvocationGate, ExchangePowerShellCommandRunner, DisabledExchangePowerShellCommandRunner, OperationRunService, ProviderOperationTrustedStarter, ProviderCapabilityEvaluator, OperationSummaryKeys, SummaryCountsNormalizer, RunFailureSanitizer, ProviderConnection, provider credential infrastructure, and config binding under tenantpilot.features.
  • Existing pattern(s) to extend: Existing OperationRun/provider operation/capability architecture, summary normalization, failure sanitizer, disabled runner default binding, provider credential/identity resolution, and Coverage v2 command contracts.
  • Shared contract / presenter / builder / renderer to reuse: OperationRun lifecycle and provider operation/capability contracts. No UI presenter or renderer is added.
  • Why the existing shared path is sufficient or insufficient: Existing paths provide operation truth, provider scope, capability gating, and disabled/fake-runner boundaries. They are insufficient for production execution because they do not yet prove runtime readiness, credential kind handling, permission evidence, process execution, output guards, timeout/concurrency cleanup, or production-runner selection rules.
  • Allowed deviation and why: A narrow production runner, runtime checker, process executor, command builder, and credential/permission evaluators are allowed because shell/process execution and credential safety require explicit testable boundaries.
  • Consistency impact: Invocation continues to use the Spec 431 OperationRun path; summary counts remain flat numeric allowed keys; failure reasons remain sanitized; provider connection remains scoped context; no customer claim is added.
  • Review focus: Verify no raw shell strings, no mutation commands, no provider payload persistence, no credential material logging, no evidence promotion, and no route/job/schedule/listener trigger.
  • Touches OperationRun start/completion/link UX?: yes, backend OperationRun lifecycle and sanitized context only. No rendered start surface or deep link is added.
  • Shared OperationRun UX contract/layer reused: Existing OperationRun lifecycle, OperationRunService, OperationSummaryKeys, SummaryCountsNormalizer, RunFailureSanitizer, and Spec 431 invocation gate path.
  • Delegated start/completion UX behaviors: N/A - no toast, DB notification policy change, browser event, run link, artifact link, or rendered surface.
  • 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 a run reaches terminal status; feature-local completion notifications are forbidden.
  • 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. Exchange PowerShell command/runtime semantics are provider-owned; OperationRun, provider connection, capability, scope, and summary/failure safety are platform-core seams.
  • Seams affected: service binding, runner interface, runtime readiness, credential reference evaluation, Exchange permission evidence evaluation, provider operation/capability gating, OperationRun context, failure reason mapping, process execution, and command construction.
  • Neutral platform terms preserved or introduced: operation, provider connection, managed environment, workspace, capability, runtime readiness, credential reference, permission evidence, process executor, summary counts, failure reason, runner mode.
  • Provider-specific semantics retained and why: Exchange command names, ExchangeOnlineManagement module checks, and Exchange permission evidence are retained inside the provider-owned runner boundary because this slice is explicitly Exchange PowerShell only.
  • Why this does not deepen provider coupling accidentally: Platform-core remains limited to operation/provider/capability/summary/sanitizer integration. Exchange-specific command and runtime details remain in TenantConfiguration runner-boundary services and are not promoted into customer vocabulary, compare semantics, or platform ownership truth.
  • Follow-up path: document-in-feature. Credential/permission evidence support, evidence promotion, compare/render/certification, Teams runtime, and customer output are 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 432 introduces structural runtime safety boundaries. These are allowed only as the narrowest safe shape for production process execution.

Concept Existing mechanism extended Why needed now Narrowness control
Production runner service ExchangePowerShellCommandRunner binding Proves a production boundary can exist without becoming default or unsafe. Disabled runner remains default; production runner selected only by explicit gates.
Runtime readiness checker Existing config/service path Prevents live process execution when PowerShell, module, environment, timeout, executor, or temp policy is unsafe. Non-invasive checks only; no Microsoft connection, no module install, no env dump.
Credential reference resolver Existing provider credential/identity infrastructure Prevents unsupported or unsafe credential kinds from reaching process execution. Reference-only metadata; client secret blocks by default; no credential material returned.
Permission evidence evaluator Existing provider capability/permission evidence path Prevents admin-consent-only from implying Exchange PowerShell runtime permission. If a repo-canonical verified Exchange permission evidence source exists, verified evidence may advance only to the next gate. If no source exists, the evaluator must fail closed until Spec 433; no new evidence persistence required.
Process executor abstraction Runner interface/test fake path Makes command execution fake-testable and blocks shell-string construction. Argument vectors only; no generic scripting platform.
Command builder/runtime policy Spec 430 command contracts Prevents mutation commands, unknown parameters, shell tokens, and arbitrary command text. Exactly three command contracts.
Output/timeout/concurrency guards OperationRun/failure sanitizer path Prevents raw stdout/stderr, binary/scalar output, runaway processes, and parallel execution leaks. Bounded failures and locks only; no provider payload persistence.
Failure reason mappings RunFailureSanitizer and provider reason codes Gives actionable, sanitized OperationRun blockers. Add only behavior-changing runner-boundary reasons when existing codes cannot express them.

Answers required by BLOAT-001:

  1. Current operator problem: TenantPilot must not imply Exchange runtime or evidence readiness until live execution is safely gated and blocked by default.
  2. Why existing structure is insufficient: Spec 431 has a disabled/fake runner but no production process, runtime readiness, credential kind, permission evidence, no-shell, output, timeout, or concurrency proof.
  3. Narrowest correct implementation: Add a safely blocked production-runner boundary for the three existing contracts only.
  4. Ownership cost: Maintains focused runner-boundary services and tests that future Exchange evidence specs must use.
  5. Rejected alternative: Implement live capture/evidence promotion directly in the next evidence spec or enable the production runner based on admin consent alone.
  6. Current-release truth or future-release preparation: Current-release safety truth required before any live Exchange evidence capture.

Forbidden proportionality outcomes:

  • no new persisted entity or table
  • no Exchange evidence table
  • no Exchange mini-platform
  • no broad provider framework
  • no UI surface or customer readiness state
  • no live invocation default
  • no compatibility shim or fallback reader

Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)

  • Test purpose / classification: Unit tests for runtime readiness, credential/permission evaluators, command builder, process executor, output guards, summary/failure/redaction; Feature tests for service binding, OperationRun safety, provider scope/RBAC, no evidence, no UI/trigger, no migration, and no tenant_id.
  • Validation lane(s): fast-feedback and confidence focused Pest lanes; selected Spec 430/431/426/427/417/419/420 regressions; browser N/A.
  • Why this classification and these lanes are sufficient: The change is backend service/runtime safety behavior with no rendered UI and no database schema.
  • New or expanded test families: New Spec 432 unit and feature families under existing TenantConfiguration/provider/OpsUx test locations.
  • Fixture / helper cost impact: May require explicit workspace, managed environment, provider connection, credential reference, permission evidence, fake process executor, and OperationRun setup. Helpers must stay feature-local or opt-in.
  • Heavy-family visibility / justification: No browser or heavy-governance family planned. If implementation requires PostgreSQL-only locking proof, it must be named explicitly in the implementation report.
  • Special surface test profile: N/A - no rendered UI surface changed.
  • Standard-native relief or required special coverage: backend-only; browser and Human Product Sanity N/A.
  • Reviewer handoff: Reviewers must confirm lane fit, no hidden browser/surface cost, no broad helper defaults, and exact validation commands/pass counts in the implementation report.
  • Budget / baseline / trend impact: none expected unless process/locking tests materially expand runtime.
  • Escalation needed: reject-or-split if implementation attempts evidence promotion, UI, route/job/schedule/listener triggers, migrations, broader command types, or live invocation without credential and permission proof.
  • Active feature PR close-out entry: Guardrail / backend runner-boundary safety / no rendered UI surface changed.
  • Planned validation commands:
    • cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
    • cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec432 --compact
    • selected Spec 431 and Spec 430 regressions
    • selected Spec 426/427/417/419/420 no-promotion, identity, registry, and generic evidence regressions
    • git diff --check

User Scenarios & Testing (mandatory)

User Story 1 - Disabled Default and Explicit Production Gate (Priority: P1)

As a platform reviewer, I need the disabled Exchange PowerShell runner to remain the default and any production runner to require explicit config plus invocation gates, so production execution cannot be enabled by accident.

Why this priority: Runner selection is the root safety boundary. If the production runner can activate by default, every other gate is weaker.

Independent Test: Binding/config tests prove default binding remains disabled, production flag defaults false, invocation flag false blocks, production flag false blocks, and repo-canonical config-cache proof preserves the disabled default. Use actual config:cache when viable in the lane; otherwise use a service-container/config-resolved simulation and document the choice.

Acceptance Scenarios:

  1. Given default config, When the service container resolves ExchangePowerShellCommandRunner, Then it resolves the disabled runner or returns execution_blocked_runner_disabled.
  2. Given production-runner config is false, When invocation is requested, Then production execution does not start.
  3. Given production-runner config is true but credential or permission evidence is missing, When invocation is requested, Then live execution remains blocked.

User Story 2 - Runtime, Credential, and Permission Gates (Priority: P1)

As a security reviewer, I need runtime readiness, credential kind, and Exchange permission evidence gates before any process execution, so client secrets, admin consent alone, wrong scope, stale evidence, or unsafe runtime cannot invoke Exchange PowerShell.

Why this priority: These gates prevent credential leakage, false readiness, wrong-scope provider calls, and unsafe production host execution.

Independent Test: Unit and feature tests prove non-invasive readiness checks, unsupported credential blocking, missing/wrong/stale permission evidence blocking, and verified evidence allowing only the next gate when a repo-canonical verified evidence source exists. If no source exists, tests prove fail-closed permission evaluation and document Spec 433 follow-up.

Acceptance Scenarios:

  1. Given only admin consent evidence, When Exchange PowerShell invocation is evaluated, Then it blocks as unvalidated or missing Exchange permission evidence.
  2. Given a client-secret credential reference, When the production runner gate evaluates credentials, Then it blocks by default.
  3. Given PowerShell or ExchangeOnlineManagement readiness is missing or unknown, When readiness is checked, Then the check does not connect to Microsoft or install modules and returns a sanitized blocked/unknown state.
  4. Given no repo-canonical verified Exchange permission evidence source exists, When permission evidence is evaluated, Then the evaluator fails closed and records Spec 433 as the follow-up instead of fabricating evidence.

User Story 3 - No-Shell Process Boundary and Output Safety (Priority: P1)

As an implementation reviewer, I need command execution represented as an argument-vector process boundary with fake process tests, output guards, timeouts, concurrency locks, and redaction, so no raw shell string, transcript, binary output, or oversized output can leak or become evidence.

Why this priority: Any future live invocation must prove process execution is safe before evidence promotion can be considered.

Independent Test: Unit tests use a fake process executor to simulate success, empty output, warning-prefixed output, non-zero exit with stdout, timeout, oversized stdout/stderr, binary/non-UTF8 output, scalar output, and unexpected exceptions.

Acceptance Scenarios:

  1. Given a mutation command or raw shell token, When command construction runs, Then it rejects the request before process execution and persists only sanitized counts/reasons.
  2. Given non-zero process exit with stdout, When output handling runs, Then the invocation fails safely and raw stdout is not persisted.
  3. Given a timeout or concurrency conflict, When execution is attempted, Then the process is terminated or blocked, locks are cleaned up, and OperationRun receives a sanitized failure.

User Story 4 - OperationRun Safety and No Product Promotion (Priority: P1)

As a release reviewer, I need the production-runner boundary to remain internal and no-promotion only, so a safe runner boundary cannot be mistaken for Exchange evidence, readiness, compare, render, restore, or customer claims.

Why this priority: The correct PASS state may still block live invocation. The product must not treat boundary existence as provider evidence.

Independent Test: Feature/guard tests prove no evidence rows, no raw/normalized payload persistence, no content-backed/comparable/renderable/certified/restore/customer state, no UI/routes/jobs/schedules/listeners, no migration, and no tenant_id in changed runtime artifacts.

Acceptance Scenarios:

  1. Given a blocked or successful gated runner attempt, When persistence is inspected, Then no evidence rows or raw provider payloads exist.
  2. Given OperationRun context, When redaction tests inspect it, Then it contains only safe runtime, credential, permission, runner, target type, summary, and provider connection metadata.
  3. Given the codebase after implementation, When route/UI/job/schedule/listener scans run, Then no product or trigger surface can start the production runner.

Edge Cases

  • Missing production-runner config flag or false value.
  • Invocation feature flag false even when production-runner flag is true.
  • Unsupported runtime environment.
  • PowerShell executable missing.
  • ExchangeOnlineManagement module missing or unknown.
  • Timeout policy missing or invalid.
  • Process executor unavailable.
  • Client secret credential reference.
  • Certificate credential missing, expired, inaccessible, or unsupported.
  • Federated or managed-identity credential unsupported by repo/deployment.
  • Admin consent without Exchange-specific permission evidence.
  • Permission evidence scoped to the wrong workspace, managed environment, or provider connection.
  • Warning text before structured payload.
  • Non-JSON, scalar, binary, non-UTF8, or oversized output.
  • Non-zero exit with stdout.
  • Timeout, stale lock, concurrency conflict, and cleanup failure.
  • Secret-like strings in exception messages, stdout/stderr fixtures, context, or logs.

Requirements (mandatory)

Functional Requirements

  • FR-001: System MUST preserve the disabled Exchange PowerShell runner as the default service binding.
  • FR-002: System MUST add an explicit production-runner config gate that defaults disabled and is separate from the existing invocation feature flag.
  • FR-003: System MUST require both invocation and production-runner gates before a production runner can be selected or reached.
  • FR-004: System MUST allow a valid PASS state where the production boundary exists but live invocation remains blocked due to missing supported credential evidence or missing verified Exchange permission evidence.
  • FR-005: System MUST add a non-invasive runtime readiness check for configured PowerShell availability, Exchange module availability or unknown/missing state, runtime environment allowlist, timeout policy, process executor availability, and temp policy if temp files are used. Automated tests for readiness MUST use fake executor/path-check seams and must not depend on host PowerShell or ExchangeOnlineManagement availability.
  • FR-006: Runtime readiness MUST NOT connect to Microsoft, run Connect-ExchangeOnline, import a tenant session, install modules, download modules, dump environment variables, run interactive prompts, execute arbitrary shell strings, or create evidence.
  • FR-007: System MUST resolve credentials by safe reference metadata only and MUST NOT expose credential material to OperationRun context, logs, exceptions, runner envelopes, process input, or test fixtures.
  • FR-008: Client-secret credentials MUST block Exchange PowerShell production invocation by default unless the spec is amended with explicit secure support.
  • FR-009: Certificate, federated, managed-identity, missing, expired, inaccessible, unsupported, and unknown credential states MUST be tested separately and block unless repo support is explicitly implemented and proven.
  • FR-010: System MUST require verified Exchange-specific permission evidence before live invocation. Admin consent alone MUST NOT evaluate as sufficient. If no repo-canonical verified evidence source exists, the only valid Spec 432 behavior is fail-closed evaluation, not synthesized or newly persisted evidence.
  • FR-011: Permission evidence MUST be scoped to the same workspace, managed environment, and provider connection; missing, unvalidated, stale, wrong-scope, and unsupported evidence MUST block.
  • FR-012: System MUST use a process executor abstraction so tests never invoke real PowerShell.
  • FR-013: Process execution MUST use argument vectors or structured process calls and MUST reject raw shell strings, pipes, script fragments, redirection, semicolon command chaining, aliases, operator-supplied command text, profile loading, and file-write tokens.
  • FR-014: Command construction MUST be generated only from Spec 430 command contracts and must allow only Get-TransportRule, Get-RemoteDomain, and Get-InboundConnector.
  • FR-015: Mutation command families such as Set-*, New-*, Remove-*, Enable-*, Disable-*, Update-*, Start-*, Stop-*, Invoke-*, Search-*, Export-*, and Import-* MUST be rejected.
  • FR-016: Invalid parameter names MUST NOT be persisted raw; only safe counts and sanitized reason codes may persist.
  • FR-017: Output handling MUST enforce stdout/stderr byte limits, item limits, UTF-8 validation, structured payload validation, warning-prefix handling, non-zero exit handling, timeout handling, binary output handling, and scalar/text output handling.
  • FR-018: Timeout and concurrency controls MUST prevent unbounded execution and must clean up locks/processes after success, failure, timeout, and unexpected exceptions.
  • FR-019: OperationRun context MUST store only safe metadata: runner mode, runtime readiness state, credential state, permission evidence state, requested resource types, requested command contracts, provider connection id as context-only metadata, duration, safe summary counts, and sanitized failure categories.
  • FR-020: OperationRun context, summary counts, failure context, runner envelopes, process output, exception messages, and logs MUST redact secrets, tokens, credential material, raw stdout/stderr, PowerShell transcripts, raw provider payloads, mail/message/file content, and other secret-like strings.
  • FR-021: Summary counts MUST use existing allowed keys where possible. Any new key must be added deliberately to OperationSummaryKeys::all() and covered by tests proving preservation and unknown-key drop behavior.
  • FR-022: Public invocation MUST return or reference an OperationRun or safe blocker and must keep transient provider envelopes inside service/test boundaries.
  • FR-023: Server-side provider scope/RBAC checks MUST reject non-member workspace access as 404, missing managed-environment entitlement as 404, missing execution capability as 403 or repo-equivalent, readonly actors, cross-workspace providers, cross-environment providers, and wrong-scope permission evidence.
  • FR-024: System MUST create no evidence rows, raw evidence payload, normalized evidence payload, content-backed state, comparable state, renderable state, certified state, restore-ready state, customer-ready state, report output, or Review Pack output.
  • FR-025: System MUST add no route, Filament page, Livewire component, navigation item, UI action, dashboard/readiness badge, global search change, asset, job trigger, schedule trigger, or listener trigger that can invoke the production runner.
  • FR-026: System MUST add no migration, operation_runs.provider_connection_id column, Exchange-specific evidence table, tenant_id, legacy shim, fallback reader, dual write, or Exchange mini-platform.

Non-Functional Requirements

  • NFR-001: All runtime gates must fail closed with sanitized reason codes/messages.
  • NFR-002: Tests must use fake process execution and must not call Microsoft, Exchange Online, or real PowerShell modules.
  • NFR-003: Any temporary file use must be avoided by default. If unavoidable, temp files must contain no secrets/provider payloads, use a safe configured directory, and be cleaned on success, failure, timeout, and exception.
  • NFR-004: Runner-boundary tests must stay focused and avoid creating heavy shared fixture defaults.
  • NFR-005: Deployment defaults must keep the production runner disabled in local, staging, and production unless explicitly configured after validation.

UI Action Matrix (mandatory when Filament is changed)

N/A - no Filament Resource, RelationManager, Page, action, table, form, panel provider, or rendered UI surface is changed.

Key Entities / Runtime Concepts

  • ExchangePowerShellCommandRunner: Existing runner interface. Default binding remains disabled; production runner may be introduced only behind explicit gates.
  • ExchangePowerShellProductionRunner: Proposed gated production runner boundary. It may execute only after all runtime, credential, permission, scope, command, process, output, timeout, concurrency, and redaction gates pass.
  • ExchangePowerShellRuntimeReadinessChecker: Proposed non-invasive readiness checker for runtime availability and policy.
  • ExchangePowerShellCredentialReferenceResolver: Proposed safe metadata-only credential reference evaluator.
  • ExchangePowerShellPermissionEvidenceEvaluator: Proposed evaluator for Exchange-specific permission proof, allowed to fail closed until a later spec adds verified evidence support.
  • ExchangePowerShellProcessExecutor: Proposed argument-vector process abstraction with a fake executor for tests.
  • ExchangePowerShellProcessCommandBuilder: Proposed builder that maps Spec 430 contracts to safe process arguments without raw shell strings.
  • OperationRun: Existing execution truth. It stores only sanitized context/summary/failure metadata and never provider payloads.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: Default service binding resolves to the disabled runner or returns execution_blocked_runner_disabled with default config.
  • SC-002: Focused tests prove production runner selection requires both invocation and production-runner gates plus runtime, credential, permission, provider, OperationRun, command, process, output, timeout, concurrency, and redaction gates.
  • SC-003: Focused tests prove client-secret credentials, admin consent alone, missing/wrong/stale permission evidence, unsafe runtime, raw shell strings, mutation commands, unsafe output, timeout, and concurrency conflicts block safely.
  • SC-004: Focused tests prove no raw stdout/stderr/provider payload/secrets persist in OperationRun context, summaries, failures, logs, or temporary artifacts.
  • SC-005: Guard tests prove no evidence rows, no product promotion, no UI/routes/jobs/schedules/listeners, no migrations, no tenant_id, and no Exchange mini-platform are introduced.
  • SC-006: Implementation report records branch/HEAD, dirty state, prerequisite proof, runner matrices, validation commands, pass counts, deferred work, Product Surface N/A, and deployment impact.

Acceptance Criteria

AC1. Runner Binding

  • Disabled runner remains default.
  • Production runner is never selected by default.
  • Production runner requires explicit config and invocation gate.
  • Production runner blocks without supported credential reference.
  • Production runner blocks without verified Exchange permission evidence.

AC2. Runtime Readiness

  • Runtime readiness checker exists.
  • Readiness checks are non-invasive.
  • No Microsoft connection, tenant session import, module installation, or env dump occurs.
  • Missing/unknown runtime, module, timeout policy, process executor, temp policy, or environment allowlist blocks safely.

AC3. Credential and Permission Evidence

  • Credential resolver is reference-only.
  • Client secret blocks by default.
  • Certificate/federated/managed-identity states are tested and block unless explicitly supported.
  • Admin consent alone is not sufficient.
  • Missing, unvalidated, stale, wrong-scope, and unsupported Exchange permission evidence blocks.

AC4. Process and Command Safety

  • Process executor abstraction exists.
  • Tests use fake executor.
  • Execution uses argument vector / structured process calls.
  • Raw shell strings, pipes, script fragments, redirection, aliases, profile loading, operator-supplied command text, mutation commands, and unknown parameters are rejected.

AC5. Output / Timeout / Concurrency

  • Oversized stdout/stderr, scalar/text output, warning-prefixed unsafe output, binary/non-UTF8 output, non-zero exit with stdout, timeout, and unexpected exceptions fail safely.
  • Per-provider and per-workspace concurrency locks block conflicting execution and clean up on success, failure, timeout, and exception.

AC6. OperationRun / Redaction / No Promotion

  • Public invocation returns OperationRun or safe blocker.
  • OperationRun context is sanitized.
  • provider_connection_id remains context-only.
  • No raw output, secrets, provider payloads, evidence rows, product promotion, UI, trigger surface, migration, tenant_id, fallback reader, or Exchange mini-platform appears.

Risks

  • Production-runner selection could accidentally bypass disabled defaults if config binding is too eager.
  • Credential evidence could be confused with provider admin consent or existing generic provider readiness.
  • Runtime readiness could become invasive if implemented with module import or connection commands.
  • Process executor abstractions could drift into a generic scripting platform.
  • Output guards could accidentally treat malformed or warning-prefixed output as success.
  • Summary/failure reason additions could become unbounded status vocabulary.

Assumptions

  • Spec 431 remains implemented and merged in current repo truth.
  • tenant_configuration.exchange_powershell_invocation is the canonical operation type.
  • ExchangePowerShellCommandRunner stays the runner interface unless implementation discovers a repo-canonical equivalent.
  • The implementation may choose a fail-closed permission evaluator that never returns verified evidence until a later Spec 433 adds real evidence support. In that path, verified-evidence pass-through proof is explicitly N/A and the implementation report must point to the fail-closed tests instead.
  • No live Microsoft tenant or Exchange Online credentials are required for Spec 432 validation.

Open Questions

  • None blocking preparation. Implementation must verify whether the repo already has a canonical credential-kind metadata shape and permission evidence source to reuse; if not, Spec 432 should implement a fail-closed evaluator and defer verified evidence to Spec 433.

Follow-up Spec Candidates

  • Spec 433 - Exchange Credential / Permission Evidence Support, if verified evidence cannot be produced safely in Spec 432.
  • Exchange content-backed evidence promotion for the three included types.
  • Exchange comparable/renderable promotion.
  • Teams PowerShell adapter contract and invocation/evidence slice.
  • M365 customer output and claim guard after evidence and compare semantics are proven.