Skip to content

Add caller-owned policy preparation - #1718

Open
Ross Nichols (rossnichols) wants to merge 5 commits into
mainfrom
user/rnichols/caller-owned-policy-feedback
Open

Ross Nichols (rossnichols) wants to merge 5 commits into
mainfrom
user/rnichols/caller-owned-policy-feedback

Conversation

@rossnichols

@rossnichols Ross Nichols (rossnichols) commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

📖 Description

When Windows refuses a container request because it exceeds administrative
policy, an application needs to understand the refusal and decide whether a
more restricted request still serves its task. For example, a caller requesting
write access may be willing to accept read-only access, but MXC must not make
that acceptance decision or run the workload on its behalf.

This implements the caller-owned preparation design across Rust, .NET and Node:

  • Strict creation returns owned, structured policy observations when Windows
    supplies them, preserving the original error category, operation and HRESULT.
    Resource details remain separate from ordinary error text and default
    diagnostic inspection, while remediation remains visible to callers.
  • Additive V1.Dev preparation accepts complete MXC request JSON, required
    PolicyFailures and separate PolicyPreparationOptions. It returns a
    PreparedPolicyRequest containing candidate JSON and ordered before/after
    changes, without creating a container or launching a workload.
  • The caller can inspect, reject, edit or accept the candidate, then submit its
    chosen JSON through ordinary strict creation. Storage and merge helpers keep
    observations lossless and bounded; the caller owns persistence and retry
    limits.

Preparation proves supported capability, network/capture and filesystem
reductions against the current request, preserves unrelated permissions and
workload settings, and rejects unsafe or unsupported changes. Published V1
creation signatures and options remain unchanged. Creation never accepts
observations, modifies a request or retries automatically.

Native preparation is Windows ProcessContainer-only. Availability is determined
through runtime API and capture-support checks, not an inferred minimum Windows
build. Other backends cannot silently accept preparation or obtain a fallback.
SDK references, backend guidance and scheduled validation requirements are
updated alongside the implementation.

🔗 References

Refs #1634 (feature-accepted; remains open for validation coordination).

Approved design and API proposal: #1635, merged into main.

🔍 Validation

Backend tests exercise restrictive changes and unsafe observations, including
network/capture interactions, filesystem ceilings and unchanged caller inputs.
Preparation tests check that candidates and change reports are owned and that
preparation does not launch a workload. SDK tests cover error transport and
diagnostic inspection, keeping remediation visible while details remain
redacted. They also cover storage/merge bounds, duplicate change values, large
values and text, and compatibility with strict creation.

Injected backend tests use fake PSEC creation and startup attributes while
exercising strict request submission and a fixed child-process fixture.
Filesystem-preservation fixtures resolve temporary-directory aliases before
constructing literal grants; production alias-safety checks remain active.

The managed native-success rows require the established capable-host opt-in;
pure storage rows remain runnable without it. Bundle discovery requires the
native rows, and scheduled validation rejects missing or skipped required
tests. The actual managed runner was exercised both with and without opt-in;
negative discovery and result fixtures verify that omitted native rows cannot
produce a passing gate.

Executed local checks and results
Working directory Command Result
src cargo fmt --all -- --check Passed
src cargo clippy --locked -p mxc-sdk --all-targets -- -D warnings Passed
src cargo test --locked -p mxc-sdk --lib policy_ 171 passed with TEMP and TMP set to an 8.3 short-name path
src cargo test --locked -p mxc-sdk --lib startup_info_attaches_security_environment_attribute 1 passed
src cargo test -p mxc-sdk --test dev_compatibility 1 passed
sdk\node npm test 494 tests: 472 passed, 22 skipped, 0 failed
sdk\node npm run typecheck Passed, including packed integration compilation
Repository root dotnet build .\sdk\dotnet\Microsoft.Mxc.Sdk.Tests\Microsoft.Mxc.Sdk.Tests.csproj -f net10.0 -v:q Passed, no warnings or errors
Repository root .\scripts\ci\test-policy-preparation-test-results.ps1 16 cases passed

The review-fix regressions were also run directly. From the repository root:

& '.\sdk\dotnet\Microsoft.Mxc.Sdk.Tests\bin\Debug\net10.0\Microsoft.Mxc.Sdk.Tests.exe' `
    -method '*PreparedPolicyStorageRejectsDuplicateChangeValuesButPreservesRequestAnnotations'

Result: 1 passed; duplicate properties in both stored change values are
rejected, and duplicate annotations in RequestJson round-trip.

From src:

cargo test -p mxc-sdk --test streaming_processcontainer `
    dev_json_processcontainer_policy_feedback_restricts_current_request `
    -- --ignored --nocapture

Result: 1 passed, with success markers for 0.9.0-alpha, 1.0.0 and
1.1.0-alpha.

The result-gate fixtures separately omit each nativePreparation: True row
while its pure-storage False row passes.

The rebuilt self-running xUnit executable was used, rather than treating a
successful build or zero-test invocation as execution:

$runner = '.\sdk\dotnet\Microsoft.Mxc.Sdk.Tests\bin\Debug\net10.0\Microsoft.Mxc.Sdk.Tests.exe'
& $runner -class '*.DevEntryPointTests' `
    -class '*.NativeErrorTests' -class '*.MxcExceptionTests'

Result with MXC_E2E_PSEC_CAPABLE_HOST=1: 45 passed, none skipped or failed.

The native-preparation gate was also exercised with these selectors:

& $runner -method '*PolicyPreparationReturnsOwnedNativeRequestsWithoutLaunching' `
    -method '*PolicyPreparationStoragePreservesLargeTextWithoutHtmlExpansion' `
    -method '*PolicyPreparationStoragePreservesDuplicateCommentMembers'

With the opt-in unset, both pure-storage rows passed and the three native rows
skipped. With opt-in set to 1, all five passed. The scheduled result gate
accepted the enabled result and rejected the native skips.

& $runner -list full -preEnumerateTheories `
    -class '*.MxcProcessTests' -class '*.DevEntryPointTests'

Discovery selected all required native rows. Removing each required row
independently caused its discovery check to reject the listing.

Additional checks passed on unchanged FFI/code-generation inputs:

Working directory Command Result
src cargo test -p mxc_ffi policy_preparation 3 unit tests passed; not counted as integration execution
Repository root node scripts\versioning\check-psec-codegen.js Schema provenance and regeneration checks passed; 26 generated files had no drift

Not run on this final candidate: the full scheduled host suite, a real governed
Windows refusal, Linux/macOS runtime suites, or a fresh Native AOT publication.
Governed-refusal CI provisioning remains separate agreed work; the host opt-in,
unit fixtures and preparation-success checks do not replace that coverage.

✅ Checklist

  • Signed the Contributor License Agreement
  • Linked to an issue
  • For features or changes requiring a spec: linked the issue with maintainer-applied feature-accepted
  • For implementation: linked the required approved and merged design/API spec, or explained why no spec is required
  • Feature issue remains open unless this PR completes all agreed implementation, validation, and documentation
  • Updated documentation (if applicable)
  • Updated Copilot instructions (if build, architecture, or conventions changed)
  • If this PR changes Cargo.lock, the dependency-feed-check check passes (see pull request builds)

The final two conditional items do not apply: no new build/architecture
conventions and no Cargo.lock changes.

📋 Issue Type

  • Bug fix
  • Feature
  • Task
Microsoft Reviewers: Open in CodeFlow

Return structured policy refusals and prepare restricted candidates without creation. Preserve V1 creation APIs; callers own acceptance, storage and retries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@rossnichols
Ross Nichols (rossnichols) requested a review from a team November 10, 2026 01:37
@rossnichols
Ross Nichols (rossnichols) requested a review from a team as a code owner November 10, 2026 01:37
Copilot AI balanced review requested due to automatic review settings November 10, 2026 01:37
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The validation gate can incorrectly pass when native-preparation theory results are absent because passing pure-storage rows with the same method names satisfy its checks.

1 open issue
What changed in this PR

Implements the caller-owned policy preparation design from #1635 for Windows ProcessContainer. Applications can inspect proposed permission reductions before submitting their chosen request through ordinary strict creation.

Changes:

  • Adds V1.Dev preparation APIs and candidate-storage helpers across Rust, .NET, and Node.
  • Preserves structured native policy observations across SDK boundaries while keeping resource details out of default error formatting.
  • Adds compatibility, ownership, preparation, and enforcement coverage, with scheduled validation checks and updated documentation.
File Description
src/​mxc-sdk/​tests/​streaming_processcontainer.rs Tests preparation, acceptance, filesystem enforcement, and request reuse.
src/​mxc-sdk/​tests/​dev_compatibility.rs Checks existing V1.Dev options and creation signatures.
src/​mxc-sdk/​src/​lib.rs Exposes bounded observation decoding for FFI.
src/​mxc-sdk/​src/​dev.rs Adds preparation APIs, exports, and storage helpers.
src/​mxc-sdk/​src/​core/​process_security_environment_spec/​README.md Documents policy-result schema provenance and regeneration.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​mod.rs Registers generated policy-result bindings.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​value_kind_generated.rs Adds generated value-kind constants.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​resource_kind_generated.rs Adds generated resource-kind constants.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​required_action_generated.rs Adds generated restriction-action constants.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​policy_result_version_generated.rs Adds generated result-version constants.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​policy_result_limit_generated.rs Adds generated diagnostic limits.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​policy_result_flags_generated.rs Adds generated result flags.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​policy_outcome_generated.rs Adds generated policy outcomes.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​policy_access_generated.rs Adds generated filesystem access values.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​failure_reason_generated.rs Adds generated refusal reasons.
src/​mxc-sdk/​src/​core/​process_security_environment_policy_result/​experimental_process_security_environment_policy_result/​failure_class_generated.rs Adds generated policy-failure classes.
src/​mxc-sdk/​src/​core/​mxc_engine/​policy_preparation.rs Validates and routes preparation to ProcessContainer.
src/​mxc-sdk/​src/​core/​mxc_engine/​policy_preparation_tests.rs Tests invalid inputs, limits, and safe error text.
src/​mxc-sdk/​src/​core/​mxc_engine/​mod.rs Registers engine preparation support.
src/​mxc-sdk/​src/​core/​mxc_engine/​error.rs Documents and tests structured error preservation.
src/​mxc-sdk/​src/​core/​mxc_engine/​dispatch.rs Uses shared structured spawn-error conversion.
src/​mxc-sdk/​src/​core/​mxc_common/​splice.rs Preserves unchanged JSON members verbatim.
src/​mxc-sdk/​src/​core/​mxc_common/​script_runner.rs Emits structured backend error envelopes.
src/​mxc-sdk/​src/​core/​mxc_common/​mxc_error.rs Redacts diagnostic details and restores structured errors.
src/​mxc-sdk/​src/​core/​mxc_common/​mod.rs Registers shared observation and preparation models.
src/​mxc-sdk/​src/​core/​mod.rs Registers the private policy-result module.
src/​mxc-sdk/​src/​backends/​process_container/​common/​working_directory.rs Adds fallible working-directory resolution for preparation.
src/​mxc-sdk/​src/​backends/​process_container/​common/​secenv_policy.rs Decodes bounded native results and recognizes restrictions.
src/​mxc-sdk/​src/​backends/​process_container/​common/​network_policy_helpers.rs Shares capture-related capability selection.
src/​mxc-sdk/​src/​backends/​process_container/​common/​native_capture.rs Allows capture initialization from an existing environment.
src/​mxc-sdk/​src/​backends/​process_container/​common/​mod.rs Registers backend preparation modules.
src/​mxc-sdk/​src/​backends/​process_container/​common/​launch_diagnostics.rs Adds administrative-policy refusal guidance.
src/​mxc-sdk/​src/​backends/​process_container/​common/​base_container_helpers.rs Centralizes effective capability calculation.
src/​mxc-sdk/​README.md Explains Rust caller-owned preparation.
src/​mxc-sdk/​examples/​policy_feedback.rs Demonstrates explicit approval, storage, and bounded retries.
src/​mxc-sdk/​Cargo.toml Enables tests for the preparation example.
src/​ffi/​mxc_ffi/​tests/​ffi.rs Checks initialization of the new error-details field.
src/​ffi/​mxc_ffi/​src/​policy_preparation_tests.rs Tests FFI validation and allocation ownership.
src/​ffi/​mxc_ffi/​src/​lib.rs Adds the preparation entry point and shared JSON-result handling.
src/​ffi/​mxc_ffi/​src/​error_detail.rs Transports and frees structured error JSON.
sdk/​node/​tests/​unit/​streaming-binding.test.ts Tests structured creation errors and cleanup.
sdk/​node/​tests/​unit/​inprocess-run.test.ts Verifies creation options reject policy observations.
sdk/​node/​tests/​integration/​windows-process-container.test.ts Reuses private Windows fixture creation.
sdk/​node/​tests/​integration/​test-helpers.ts Adds a reusable private Windows directory helper.
sdk/​node/​tests/​integration/​dev-api.ts Checks packaged preparation APIs and caller acceptance.
sdk/​node/​src/​v1/​errors.ts Hides structured details from default inspection.
sdk/​node/​src/​v1/​dev/​policy-preparation.ts Defines preparation models and checked storage helpers.
sdk/​node/​src/​v1/​dev/​json-duplicate-keys.ts Detects duplicate JSON object keys.
sdk/​node/​src/​v1/​dev/​index.ts Exports observation helpers and the preparation API.
sdk/​node/​src/​bindings/​streaming.ts Initializes complete native error structures.
sdk/​node/​src/​bindings/​state-aware.ts Initializes structured lifecycle errors.
sdk/​node/​src/​bindings/​run.ts Initializes complete native execution results.
sdk/​node/​src/​bindings/​pty.ts Initializes structured terminal errors.
sdk/​node/​src/​bindings/​probe.ts Initializes structured probe errors.
sdk/​node/​src/​bindings/​policy-preparation.ts Adds asynchronous native preparation with cleanup.
sdk/​node/​src/​bindings/​native-error.ts Decodes structured backend error details.
sdk/​node/​README.md Documents preparation, storage, and sensitive error details.
sdk/​dotnet/​README.md Documents preparation and explicit caller acceptance.
sdk/​dotnet/​Microsoft.Mxc.Sdk/​V1/​MxcException.cs Adds independently owned backend details.
sdk/​dotnet/​Microsoft.Mxc.Sdk/​V1/​Dev/​PreparedPolicyRequest.cs Adds candidate models and checked JSON storage.
sdk/​dotnet/​Microsoft.Mxc.Sdk/​V1/​Dev/​PolicyPreparationOptions.cs Defines separate preparation controls.
sdk/​dotnet/​Microsoft.Mxc.Sdk/​V1/​Dev/​MxcContainer.cs Adds synchronous and asynchronous preparation APIs.
sdk/​dotnet/​Microsoft.Mxc.Sdk/​PolicyFailureValueJsonConverter.cs Preserves unsigned 64-bit values as decimal strings.
sdk/​dotnet/​Microsoft.Mxc.Sdk/​Native/​NativeError.cs Converts native structured details into managed exceptions.
sdk/​dotnet/​Microsoft.Mxc.Sdk/​MxcJsonSerialization.cs Registers JSON types and duplicate-property validation.
sdk/​dotnet/​Microsoft.Mxc.Sdk.Tests/​V1/​V1ApiSurfaceTests.cs Checks preparation types and signatures.
sdk/​dotnet/​Microsoft.Mxc.Sdk.Tests/​V1/​MxcContainerTests.cs Tests structured probe-error transport.
sdk/​dotnet/​Microsoft.Mxc.Sdk.Tests/​NativeErrorTests.cs Tests detail ownership, extraction, and safe formatting.
sdk/​dotnet/​Microsoft.Mxc.Sdk.Tests/​MxcExceptionTests.cs Verifies details survive JSON-document disposal.
sdk/​dotnet/​Microsoft.Mxc.Sdk.AotSmokeTest/​Program.cs Adds preparation and observation serialization coverage.
scripts/​ci/​test-policy-preparation-test-results.ps1 Adds positive and negative result-check fixtures.
scripts/​ci/​run_backend_validation_tests.ps1 Runs preparation scenarios in Windows validation.
scripts/​ci/​lib/​TestSuiteResults.ps1 Adds required-output checks for test results.
scripts/​ci/​build-windows-sdk-test-bundle.ps1 Requires preparation test discovery in bundles.
external/​windows-sdk/​ProcessSecurityEnvironment.provenance.toml Pins the policy-result schema source and hash.
external/​windows-sdk/​ExperimentalProcessSecurityEnvironmentPolicyResult.fbs Defines the native refusal-diagnostics contract.
docs/​development/​guides/​process-container-adding-os-features.md Documents native diagnostics and preparation invariants.
docs/​development/​build-and-test/​ci-validation-infrastructure.md Documents preparation scenarios and validation requirements.
docs/​development/​architecture/​designs/​1634-creation-policy-correction/​README.md Removes the superseded prototype note.
docs/​development/​architecture/​designs/​1634-creation-policy-correction/​api.md Links the implemented example and SDK references.
docs/​backends/​nvx/​nvx.md Documents recovery details now exposed through managed SDKs.
docs/​api-reference/​rust/​v1/​types.md Clarifies error redaction and observation extraction.
docs/​api-reference/​rust/​v1/​README.md Updates the Dev API link label.
docs/​api-reference/​rust/​v1/​api.md Identifies preparation in the Dev API link.
docs/​api-reference/​node/​v1/​types.md Documents structured details and logging precautions.
docs/​api-reference/​node/​v1/​README.md Updates the Dev API link label.
docs/​api-reference/​node/​v1/​api.md Identifies preparation in the Dev API link.
docs/​api-reference/​dotnet/​v1/​types.md Documents owned exception details.
docs/​api-reference/​dotnet/​v1/​README.md Introduces preparation and AOT-compatible storage.
docs/​api-reference/​dotnet/​v1/​api.md Identifies preparation in the Dev API link.

Review effort: Balanced

Require each native storage theory row to pass in scheduled validation, and cover missing native rows when the pure-storage rows pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings November 10, 2026 16:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Windows-specific refusal capture and restrictive filesystem preparation require capable-host validation beyond this review environment, with a full scheduled-host run, a real governed-policy refusal, and fresh Native AOT execution still unverified.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Compile the request projection helper only on Windows. Keep injected policy tests independent of native PSEC attribute support and use canonical fixture paths when testing literal filesystem restrictions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings November 10, 2026 17:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Windows-specific refusal capture and policy enforcement remain unverified because the final candidate lacks capable-host validation through the full scheduled suite and a real governed refusal.

No open issues 🎉

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved issues can break the scheduled test on aliased temporary paths, hide SDK remediation guidance, and allow policy-change serialization to produce saved candidates that cannot be restored.

4 open issues

Review effort: Max

Comment thread sdk/node/src/v1/errors.ts Resolved
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI max review requested due to automatic review settings November 10, 2026 18:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed to weigh how masking native-library loading and missing-symbol diagnostics affects troubleshooting installation and version mismatches.

No open issues 🎉

4 resolved since last review

Review effort: Max

Keep loader and missing-symbol errors actionable without exposing policy payload failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI max review requested due to automatic review settings November 10, 2026 18:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Security-sensitive Windows policy enforcement and cross-SDK ABI changes require maintainer review because the final candidate lacks governed-refusal testing, a full scheduled-host run, and fresh Native AOT publication.

No open issues 🎉

Review effort: Max

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants