Skip to content

[Draft prototype] Known-tool policy catalog (Policy Store design) - #1

Draft
ChazGo wants to merge 51 commits into
mainfrom
chazgo-config-floor-prototype
Draft

ChazGo wants to merge 51 commits into
mainfrom
chazgo-config-floor-prototype

Conversation

@ChazGo

@ChazGo ChazGo commented Sep 14, 2026 •

Copy link
Copy Markdown
Owner

Draft prototype. Not for merge into microsoft/mxc. This PR lives on the ChazGo fork and prototypes the standalone known-tool policy catalog library described in the Policy Store design.

Summary

policy-catalog/ is a self-contained directory that is also laid out as its own repository (git filter-repo --subdirectory-filter policy-catalog). It contains "the policy catalog library" in three native implementations that behave identically:

  • TypeScript (src/, npm @mxc-prototype/policy-catalog)
  • Rust (rust/, crate mxc-policy-catalog, its own Cargo [workspace])
  • C#/.NET (dotnet/, NuGet Microsoft.Mxc.PolicyCatalog, net8.0)

Each language provides:

  • a versioned, integrity-checked catalog of known-tool candidate lower-bound SandboxPolicy requirements (embedded/bundled)
  • a resolver that takes one tool or an array of tools, composes every eligible matching entry and its dependencies into one policy, and can return diagnostics (getSandboxConfig / get_sandbox_config / GetSandboxConfig and the ...WithDiagnostics forms)
  • a separate metadata-only inspection API
  • a policy-catalog CLI with three commands: resolve | inspect | validate
  • unit + conformance tests over the shared conformance/fixtures/ and conformance/vectors/, and functional tests that run against the packaged artifact (npm tarball, .crate, .nupkg from a local feed) installed into a consumer outside the repository

A cross-language check runs the three CLIs with identical arguments and requires byte-identical normalized JSON. CI runs every language plus that check on Linux, macOS, and Windows, x64 and arm64.

Nothing imports from, or depends on, the MXC SDK or executors. The libraries never launch a sandbox, contact the network, run the candidate tool, or write consumer state.

Spec baseline

  • policy-catalog/docs/design.md is a verbatim copy of docs/mxc-policy-store.md, taken from Chaz's local worktree: base 34537f8 plus uncommitted edits as of 2026-09-29. The body is byte-identical to that file after git's CRLF-to-LF normalization, with no link rewrites (re-verified at this head). A short header above the body gives the source and lists absolute URLs for the four MXC-relative links.
  • Upstream proposal: docs: add MXC Policy Store feature spec microsoft/mxc#1309

Layout

.github/workflows/PolicyCatalog.Prototype.yml   runs every check while the directory is nested in MXC (6 OS x arch jobs)
policy-catalog/
  .github/workflows/ci.yml       the same checks for the standalone repository
  README.md  LICENSE.md  package.json  package-lock.json  tsconfig.json
  docs/design.md                 verbatim spec (authoritative, unchanged)
  docs/architecture.md           how the prototype implements the spec; failure codes; casing; language bindings
  docs/contributing.md           contribution flow, validation rules, per-language commands, test layout
  catalog/                       contract.v1.json, manifest.json, revisions/2026-09-29.1.json
  schema/                        JSON Schemas for revisions and the manifest
  conformance/fixtures/          language-neutral resolution cases (expected policy, warnings, {code, reason} errors)
  conformance/vectors/           generated path-normalization and canonical-JSON vectors
  src/                           TypeScript library + CLI
  tests/unit/  tests/functional/ TypeScript tests (functional: packed + installed tarball)
  rust/                          crate mxc-policy-catalog: src/, tests/, functional/ (packaged-crate consumer template)
  dotnet/                        Microsoft.Mxc.PolicyCatalog, .Cli, .Tests, functional/ (packaged-nupkg consumers), global.json, .slnx
  scripts/                       validate-catalog, digest, check-pack, package-smoke, check-extractable,
                                 rust-functional, dotnet-functional, cross-language-check, ci-ensure-rustup, generate-vectors

Decided

Decisions approved by Chaz on 2026-09-30 and implemented in all three languages:

  1. Weak invocation-name matching is off by default. Callers opt in per call (allowWeakIdentityFallback: true / allow_weak_identity_fallback / AllowWeakIdentityFallback, CLI --allow-weak). The catalog records strong evidence, but verifying that the binary about to run has that strong identity is the caller's job; the library cannot see the binary.

  2. Casing: Windows and macOS compare invocation names and paths case-insensitively; Linux compares them exactly (gh is not GH). Catalog validation's duplicate detection stays case-insensitive on every platform.

  3. Warnings stay plain strings. Errors map to existing MXC error codes, with a stable details.reason (documented in docs/architecture.md#failure-codes):

    code details.reason
    policy_validation invalid_catalog, composition_conflict
    malformed_request invalid_context
    unsupported_containment unsupported_host
    backend_error integrity, revision_unavailable
  4. Names: Rust crate mxc-policy-catalog, NuGet package Microsoft.Mxc.PolicyCatalog, and "the policy catalog library" overall.

Implemented vs deferred

Implemented (TypeScript, Rust, and C#/.NET):

  • all four version dimensions
  • canonical-digest integrity
  • immutable revisions, entry-revision monotonicity, and the --base-ref published-revision immutability check
  • additive strong/weak identity matching with opt-in weak fallback
  • the per-OS casing rule
  • platform/architecture variants: native system architecture default, exact-over-neutral selection, no cross-architecture fallback, and diagnostics warnings
  • deterministic, cycle-rejecting dependency closure
  • v1 filesystem-only composition across inputs and dependencies
  • the policy and diagnostics APIs (one tool or an array), catalog info, and metadata listing
  • MXC error codes + details.reason
  • the CLI (resolve | inspect | validate), output-identical across languages
  • packaged-artifact functional tests per language (npm tarball, .crate, .nupkg on a local feed)
  • the cross-language check (73 cases) and the OS x arch CI matrix
  • the validation pipeline, pack-content gate, offline install smoke, and an extractability gate that now also builds and tests Rust and .NET and runs the cross-language check

Deferred:

  • Publishing to npm, crates.io, or NuGet; signing; versioning policy. Packages are only built and consumed locally.
  • Validation of embedded policies against MXC's real released SandboxPolicy schemas. The prototype validates a catalog-supported subset.
  • Real-tool integration under an MXC sandbox.
  • Emulated-host verification (x64 code on ARM64). CI runs natively on ARM64 runners; emulation is covered with an injected host.
  • Private or enterprise overlays.
  • Named-role review enforcement.
  • Reviewed catalog data. tool:git, tool:node, and tool:npm are prototype-migration entries that have not been re-observed.

Ownership boundary

The catalog returns a candidate lower bound, never an authorization. Consumers own:

  • whether lookup is enabled at all
  • authorization, elevation, and ceilings
  • composition with their own layers
  • persistence, approval, and audit
  • sandbox creation
  • verifying the strong identity of the binary they are about to run

Absence (undefined / None / null, and null in the CLI) never means an empty policy. Library failures carry an MXC code and a stable details.reason (see Decided). A failure is never reported as absence.

Spec decisions and ambiguities

Changes in the uncommitted spec vs 34537f8, and how the prototype handles each:

  1. The API is getSandboxConfig / getSandboxConfigWithDiagnostics over one tool or an array. It replaces the singular resolveCatalogEntry. Implemented in all three languages. A single input is exactly a one-element array.
  2. Additive matching (§4.3): all eligible entries contribute, and a strong match does not suppress a weak one. Implemented. Diagnostics order is input order, then entryId, then predicate declaration order. A multi-match warning names the input and the entries.
  3. An omitted architecture uses the device's native system architecture, not the process architecture (§4.4). Implemented:
    • Windows reads the HKLM PROCESSOR_ARCHITECTURE.
    • macOS reads hw.optional.arm64.
    • Linux uses the kernel machine type (os.machine() / uname).
    • A detection failure is unsupported_containment/unsupported_host, never a guess.
    • Diagnostics warn that the tool's architecture was not verified, and they flag neutral fallback.
  4. Composition applies to every selected set, not just a dependency closure (§4.5). Implemented. Network and other fields are rejected across more than one entry.
  5. Unresolved required symbols return no policy plus diagnostics, never a partial policy. Implemented.
  6. Consumer persistence keeps attribution from diagnostics (§5.3). This is a consumer obligation, documented in the README.

Open items that are now decided (see Decided): the weak-identity default, invocation-name casing, and warning/error wording. Still open:

  • Unevaluated dependency versionRange. It is returned as metadata only, as the spec states.

Assumptions and deviations in this revision

  • .NET SDK pin is 10.0.401 while every project targets net8.0. SDK 8.0.425 can't read .slnx (MSB4068) or run MTP-mode dotnet test --solution (MSB1001). dotnet/global.json uses rollForward: latestFeature.
  • Test framework: xunit.v3 4.0.0, the same package and version as sdk/dotnet/Microsoft.Mxc.Sdk.Tests.
  • Rust dependencies: sha2 0.11 and libc 0.2 (unix only, for uname). The crate has its own JSON parser/serializer instead of serde_json so it can reproduce JavaScript semantics exactly: insertion order, duplicate keys, IEEE-double numbers, and Number::toString formatting. publish = false, edition 2021, toolchain channel 1.93.
  • .NET culture: .NET 8's invariant lower-casing uses Unicode 15 and Node 24's ICU uses a newer version. The C# implementation includes the differing mappings plus final-sigma handling, so casing matches exactly.
  • Bundled catalog location: each package reports where its own bundled catalog lives (npm package dir, the Rust source tree, the .NET output dir). The cross-language check normalizes catalogDir for validate without --catalog, and requires that it ends in catalog.
  • CI runners: macos-13 is no longer offered by GitHub-hosted runners (those jobs stayed queued), so macOS x64 runs on macos-15-intel. All jobs use GitHub-hosted runners; no upstream workflow was edited.
  • Windows tar: Git Bash's GNU tar comes first on PATH on Windows runners and can't handle C:/… paths, so the scripts call %SystemRoot%\System32\tar.exe on Windows.
  • Local NuGet: direct TLS to api.nuget.org fails on the dev machine, so local .NET functional runs set POLICY_CATALOG_NUGET_UPSTREAM to the machine's existing nuget.org proxy. The default, and CI, use nuget.org.
  • The parent MXC .gitignore ignores every [Bb]in/, so policy-catalog/.gitignore re-includes rust/src/bin/. This has no effect once the directory is extracted.

Proof / Validation

Final head b2fee47e57d592c2636979360eb75521c4bc2ad0. Windows: Node v24.20.0, Rust 1.93.1, .NET SDK 10.0.401 (net8.0). Commands run from policy-catalog/ unless noted.

Local (Windows): full suite 3 consecutive runs at the final head, all green

The earlier 3-run set at 44b2239 was also green. Every step passed in each run, with identical counts:

Step Command Result (each of 3 runs)
TS install npm ci OK
TS check npm run check (typecheck, unit, functional from the installed tarball, validate, pack, smoke) unit 83/83, functional 58/58
TS pack npm run check:pack OK
Rust fmt cargo fmt --check (in rust/) clean
Rust clippy cargo clippy --locked --all-targets --all-features -- -D warnings clean
Rust test cargo test --locked 49/49 (14 unit, 30 library, 4 vectors, 1 conformance over every fixture)
Rust package + functional node scripts/rust-functional.mjs (cargo package, extract the .crate outside the repo, build its binary, consumer crate tests) 12/12
.NET build dotnet build Microsoft.Mxc.PolicyCatalog.slnx -c Release 0 warnings (warnings as errors), 0 errors
.NET test dotnet test --solution Microsoft.Mxc.PolicyCatalog.slnx -c Release --no-build 157/157
.NET pack dotnet pack Microsoft.Mxc.PolicyCatalog/Microsoft.Mxc.PolicyCatalog.csproj -c Release Microsoft.Mxc.PolicyCatalog.0.0.0-prototype.nupkg
.NET functional node scripts/dotnet-functional.mjs (packed .nupkg on a local feed, consumers outside the repo) 51/51
Cross-language node scripts/cross-language-check.mjs --no-build 73 cases x 3 languages, 73 identical, 0 different
Extraction npm run check:extract (git archive HEAD:policy-catalog into a temp git repo outside the repo; TS check + Rust + .NET + cross-language there) OK
Lockfiles node scripts/versioning/check-package-lock-integrity.js (repo root) OK, 5 tracked lockfiles
Whitespace git diff --check origin/main...HEAD (repo root) clean

Other checks:

  • Workflow YAML: both workflows parse with PyYAML 6.0.1 (1 job, 6 matrix runners each).
  • Design copy: the body still equals the spec (design.md unchanged).
  • 8.3 temp path: the cross-language check passes with TEMP set to a short-path form.

Linux (WSL2 Ubuntu 24.04.5, kernel 6.18, Node 24.21.0, Rust 1.93.1, .NET 10.0.401)

On a copy of exactly the files git would commit:

Suite Result
npm ci + npm run check 83/83 unit, 58/58 functional
Rust fmt / clippy / test clean / clean / 49/49
Rust functional 12/12
.NET build / test 0 warnings / 157/157
.NET functional 51/51
Cross-language 73/73 identical

Case-sensitivity end to end (all three CLIs): on --platform linux, git resolves (weak-identity + neutral-variant warnings) and GIT returns no policy with input 0 ('GIT') matched no eligible catalog entry. On ext4, git and GIT exist as two distinct files.

Break-verify (tests fail when the guarded check is disabled, then revert)

For each check, the source was edited to if false && …, the packaged functional suite was run, the file was reverted with git checkout, and git diff --quiet returned exit 0.

Language Disabled check Result Failing tests
Rust digest comparison (rust/src/store.rs) 11 passed, 1 failed integrity_tamper_fails_resolve_inspect_and_validate
Rust cycle detection (rust/src/catalog.rs) 11 passed, 1 failed dependency_cycle_fails_validate_and_resolve
.NET digest comparison (CatalogStore.cs) 50 passed, 1 failed IntegrityTests.TamperedRevisionFailsIntegrityEverywhere
.NET cycle detection (Internal/Catalog.cs) 49 passed, 2 failed IntegrityTests.ValidateRejectsADependencyCycle, IntegrityTests.ResolveNeverReturnsAPolicyFromACyclicCatalog
TypeScript (earlier revision) cycle detection 2/58 failed both cycle tests
TypeScript (earlier revision) digest check 1/58 failed the tamper test

CI at b2fee47

CI fixes found along the way:

  • 44b2239: Windows jobs failed in Rust functional (GNU tar). Fixed in 435d8a8.
  • 435d8a8: windows-x64 had 4 cross-language validate --catalog mismatches, where the 8.3 vs long temp path differed only in catalogDir. Fixed in dfa598f.
  • Both earlier runs: macOS x64 never started on the retired macos-13 label. Fixed in b2fee47, and the stale runs were cancelled.

Chaz Gordish added 5 commits September 29, 2026 22:06
Prototype the known-tool policy catalog data from the MXC Policy Store spec (microsoft#1309) as a self-contained, extractable directory. Revision 2026-09-29.1 migrates the git/node/npm entries from the earlier config-floor prototype into per-platform variants with ordered identity and a published canonical SHA-256 digest.
Implements resolveCatalogEntry (runtime lookup) separately from getCatalogInfo/listCatalogEntries (metadata inspection), integrity-verified read-only revision store, strong/weak identity matching with opt-in weak fallback, exact-then-neutral architecture variant selection, deterministic cycle-rejecting dependency closure, and the v1 filesystem-only composition vocabulary. No imports from, or changes to, the MXC SDKs.
…smoke test

validate-catalog runs schema, integrity, semantic contract, entry-revision monotonicity, published-revision immutability against a base ref, deterministic resolution, package inclusion, and fixture coverage checks. package-smoke packs and installs the library offline. A path-filtered workflow runs them on Windows/Linux/macOS while nested; policy-catalog/.github carries the post-extraction workflow.
Line-ending conversion on checkout must not be reported as a published-revision edit.
@ChazGo
ChazGo force-pushed the chazgo-config-floor-prototype branch from 17070fb to e918cb1 Compare September 30, 2026 05:08
@ChazGo ChazGo changed the title [SDK][Feature] Prototype sandbox config floors [Draft prototype] Known-tool policy catalog (Policy Store spec) Sep 30, 2026
… latest design

Follow the current design proposal (docs/design.md): getSandboxConfig and getSandboxConfigWithDiagnostics accept one tool or an array and compose every eligible matching entry and dependency once; identity matching is additive rather than strongest-wins; omitted architecture uses the device's native system architecture with diagnostics; composition limits apply across all selected entries; entry-ID (not identity) uniqueness is validated.
@ChazGo ChazGo changed the title [Draft prototype] Known-tool policy catalog (Policy Store spec) [Draft prototype] Known-tool policy catalog (Policy Store design) Sep 30, 2026
Chaz Gordish and others added 20 commits September 29, 2026 23:28
…osal

Replace the link-rewritten copy with a byte-identical copy of the uncommitted docs/mxc-policy-store.md (base 34537f8 plus edits as of 2026-09-29), under a short provenance header that lists absolute URLs for the four MXC-relative links. The extractability check now requires each relative link in the verbatim body to have an absolute equivalent in that header instead of rewriting it, and no longer runs test:functional twice (check already includes it).
…and test the installed tarball

CLI: 'inspect' replaces 'info' and 'list'; 'validate' replaces 'verify' and adds --base-ref for the published-revision immutability check. The old names are usage errors (one canonical flow). src/validate.ts holds the directory validation and base-ref check shared by the CLI and scripts/validate-catalog.mjs (which accepts --base-ref=<ref> or POLICY_CATALOG_BASE_REF). An unknown or option-like ref fails instead of passing silently.

Tests: tests/unit and tests/functional each have their own tsconfig (compiled into <suite>/dist) and a run-tests.js using node --test --test-reporter spec --test-force-exit, mirroring MXC's sdk/node/tests/integration, behind the check-tests-present guard. The functional runner npm-packs the package, installs the tarball offline into a temp consumer outside the repo, and the tests load the library and bin from that install only.

Docs, the smoke and pack scripts, and both workflows use the new command names.
…ti-match, and selection warnings

Through the installed CLI and library: dependency cycles and a diamond on synthetic catalogs; digest tamper, missing revision, and invalid manifest on copied catalogs; --base-ref immutability, unknown refs, and empty bases; one input matching several entries with its warning; weak-identity opt-in on and off; unknown tools; composition conflicts (overlapping classes, network merge, mixed versions); unavailable revisions; exact vs neutral variants; and the arch-not-verified warning for windows/linux/macos x x64/arm64 via an injected host.

Break-checked: disabling cycle detection fails the two cycle tests (exit 0 where 1 expected); disabling the digest check fails the tamper test. Both breaks were reverted.
…ing rule

Errors now carry an MXC MxcError code (policy_validation, malformed_request, unsupported_containment, backend_error) plus a stable details.reason. Warnings stay plain strings. Path comparison now folds case on macOS as well as Windows, matching invocation-name matching; Linux stays exact. Tests cover macOS path folding and Linux gh vs GH.
…cross-language vectors

Adds conformance/vectors (generated by scripts/generate-vectors.mjs) and a unit suite that checks TypeScript against them. Also hardens symbol lookups against prototype keys and makes a malformed percent-encoded package URL invalid instead of throwing URIError.
Standalone Cargo workspace under policy-catalog/rust/ with get_sandbox_config, get_sandbox_config_with_diagnostics, catalog inspection, validation tooling, and a policy-catalog CLI (resolve | inspect | validate) matching the TypeScript CLI. Embeds the bundled catalog, passes the shared conformance fixtures and vectors, and adds functional tests that consume the packaged .crate from a consumer outside the repository.
net8.0 library, policy-catalog CLI, and xUnit v3 unit/conformance/vector tests under policy-catalog/dotnet/ (nullable enabled, warnings as errors). Functional tests consume the packed .nupkg from a local feed in a consumer outside the repository. global.json pins SDK 10.0.401 because SDK 8 cannot read .slnx or run MTP-mode dotnet test; all projects still target net8.0.
…hitecture

Adds scripts/cross-language-check.mjs (73 cases: resolve, inspect, validate, library failures, usage errors; byte-identical normalized JSON across the three CLIs), runs every language plus the check on linux/macos/windows x64 and arm64 GitHub-hosted runners in both the in-repo and standalone workflows, extends check:extract to the Rust and .NET toolchains, and documents the bindings.
GitHub-hosted Windows runners put Git Bash's GNU tar first on PATH; it treats C:/... as a remote host and cannot exec gzip, which failed the Rust functional step on windows-x64 and windows-arm64. Use %SystemRoot%\System32\tar.exe on Windows in rust-functional.mjs and check-extractable.mjs.
…n the cross-language check

On windows-latest the runner TEMP is an 8.3 short path; .NET's Path.GetFullPath keeps it while Node and Rust report the same directory differently, so validate --catalog cases differed only in catalogDir. Register the realpath of each synthetic catalog directory as a second placeholder spelling.
The macos-13 image is no longer offered by GitHub-hosted runners, so those jobs stayed queued. macos-15-intel is the current x64 macOS label.
…olicy

Rename the public resolver API to match the policy-store spec across all three implementations, with no behavior change:

- TypeScript: resolveSandboxPolicy / resolveSandboxPolicyWithDiagnostics
- Rust: resolve_sandbox_policy / resolve_sandbox_policy_with_diagnostics
- .NET: ResolveSandboxPolicy / ResolveSandboxPolicyWithDiagnostics

Tests, READMEs, scripts, conformance fixture comment, architecture doc and the copied design doc are updated. The design doc keeps the historical getSandboxConfigForTool reference in its prior-API table.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…cy_store

PROTOTYPE, pending API review. Move the Rust policy-catalog library and its V1 catalog, schemas, and conformance data into the MXC workspace as the mxc_policy_store crate, the single implementation every MXC SDK will use.

- catalog/ in the crate is the single source of truth; build.rs embeds it.
- The standalone CLI module and binary are dropped.
- Uses the workspace sha2 and libc, and workspace rustfmt.
- tests/catalog_validation.rs replaces the npm validate pipeline: integrity, contract, history, optional base-ref immutability (MXC_POLICY_STORE_BASE_REF), manifest listing, deterministic self-resolution, and conformance coverage.

No resolver behavior changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PROTOTYPE, pending API review. mxc_sdk::policy_store exposes resolve_sandbox_policy and resolve_sandbox_policy_with_diagnostics returning the SDK's own SandboxPolicy, plus get_catalog_info and list_catalog_entries over the bundled catalog.

The store's catalog-shaped policy converts to mxc_sdk::SandboxPolicy through its camelCase JSON; a value the SDK type cannot hold (a timeoutMs above u32) is a policy_validation error rather than a silent truncation.

mxc_policy_store gains request.rs, the strict JSON request envelope for bindings, and its fixture tests now parse through it. A hidden policy_store::binding module produces the JSON the FFI layer returns, and is checked against the bundled conformance fixtures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PROTOTYPE, pending API review. Adds mxc_resolve_sandbox_policy_json, mxc_resolve_sandbox_policy_with_diagnostics_json, mxc_policy_catalog_info_json, and mxc_list_policy_catalog_entries_json, each filling an MxcPolicyStoreResult (status, result JSON, stable failure reason, MxcErrorDetail) released by mxc_policy_store_result_free.

Store error codes map onto the existing MXC_STATUS_* values. The module is a csbindgen input so the C# SDK binds it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PROTOTYPE, pending API review. Adds resolveSandboxPolicy, resolveSandboxPolicyWithDiagnostics, getCatalogInfo, and listCatalogEntries to @microsoft/mxc-sdk. They call the mxc_ffi policy store entry points through koffi, return the SDK's own SandboxPolicy type, and surface failures as MxcError with the stable store reason in details.reason. The V1 catalog is compiled into mxc_ffi, so nothing is downloaded.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PROTOTYPE, pending API review. Adds MxcPolicyStore.ResolveSandboxPolicy, ResolveSandboxPolicyWithDiagnostics (single-tool and list overloads), GetCatalogInfo, and ListCatalogEntries to Microsoft.Mxc.Sdk over the mxc_ffi policy store entry points. Results deserialize strictly into the SDK's own SandboxPolicy, so a field the model cannot hold fails as policy_validation instead of narrowing the floor. Failures throw PolicyStoreException carrying the ErrorCode, the stable store reason, and the underlying MxcException.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d CLI

The prototype now ships only as APIs inside the existing MXC SDKs, so this drops the standalone TypeScript, Rust, and .NET packages, the policy-catalog CLIs, the npm contribution tooling, and the PolicyCatalog.Prototype workflow. Catalog validation runs as mxc_policy_store tests, and the conformance vectors are now frozen fixtures. The design docs move in the next commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…outcome

Moves the design proposal to docs/policy-store/design.md and updates it for the design review outcome: the store ships inside MXC as new APIs in the existing SDKs (no separate repository, standalone library, or CLI), is not part of MXC 1.0, bundles V1 data statically, returns a best-effort floor, is complementary to Learning Mode, and remains pending API review with the current names. Open questions now cover dropping "Sandbox" from the names, intent-aware lookup, and schema compatibility within MXC 1.x.

Folds the prototype architecture and contributing pages into docs/policy-store/README.md, adds prototype sections to the Node, Rust, and C# SDK READMEs and the mxc-sdk crate docs, and records the crate boundary in the Copilot instructions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Store

Drop the prototype PolicyStoreException. MxcPolicyStore now throws
MxcException directly, and MxcException gains a nullable Reason property
carrying the policy store's stable failure reason (for example
invalid_context). Reason is null for every other MXC failure, so existing
catch (MxcException) callers also catch policy-store failures.
MxcException stays sealed; Reason has an internal setter.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Chaz Gordish (Agent) and others added 7 commits October 2, 2026 15:15
The latest design (section 10) removes the separate catalog digest: V1 data
is compiled into the native library and inherits MXC package signing.
Remove the manifest sha256 field, its schema property, the runtime digest
check, the canonical_sha256 helper, and the sha2 dependency. Unreadable or
mislabelled bundled data is still an integrity error.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the vers module: parsing and ordering for the five entry version
schemes the design allows (npm, semver, pypi, nuget, intdot), and purl
vers range parsing, validation, containment, and overlap detection per
the VERS specification. The resolver adopts it in the next commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lution

Implement the entry model from the latest Policy Store design in
mxc_policy_store:

- Each entry has one unversioned default, additive platform/architecture
  overlays, at most one non-overlapping purl vers version variant, and
  named intents. A required root versionScheme (npm, semver, pypi, nuget,
  intdot) governs every range. Overlays may add access, dependencies, and
  intents; they can never remove or narrow anything.
- ToolCandidate gains an optional intent. Resolution reports per-pair
  version status (matched_default, matched_version, version_out_of_range,
  version_unparseable), intent selection, and tool_unmatched /
  intent_unsupported, with structured warnings. There is no wildcard
  fallback; an undefined intent contributes nothing.
- Composition across pairs: filesystem and positive outbound rules union
  to satisfy every requested pair; read-write supersedes read-only;
  catalog denies that conflict with a required grant are removed with a
  diagnostic; combinations the model cannot express fail.
- Build-time validation materializes every platform x architecture x
  version x intent effective policy, checks the default is a subset of
  each, and renders a reviewer view (catalog/views/).
- Catalog revision 2026-10-02.1 replaces the unreleased 2026-09-29.1 and
  adds a git entry (fetch/push/local, Windows programData/Git, an SSH
  dependency on push for 2.40-2.49, and a bundle-fetch intent from 2.50)
  plus an ssh entry. Conformance fixtures are regenerated with a new
  MXC_POLICY_STORE_UPDATE_FIXTURES mode and reviewed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Re-export the new resolution and metadata types from
mxc_sdk::policy_store, update its docs for the intent-aware candidate, and
cover version and intent selection through the SDK types and across the C
ABI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add ToolCandidate.intent, per-input status, version and intent selection,
structured ToolResolutionWarning entries, and the new entry metadata
(versionScheme, default, platform and version overlays) to the prototype
policy store types, and cover version-range and intent selection,
out-of-range / unparseable / unsupported pairs, and pair composition.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add ToolInput.Intent, per-input Status, VersionSelection and
IntentSelection, ResolutionWarning (a string or a structured per-input
warning, read by a strict converter), and the new entry metadata
(VersionScheme, Default, platform and version overlays). Failures still
throw MxcException with Reason; ambiguous_match is documented. The tests
replay the shared bundled-catalog conformance fixtures through the C#
surface and cover version and intent selection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the policy store docs and SDK READMEs for the implemented model:
one unversioned default per entry with additive platform, version (purl
vers), and intent overlays; per tool-and-intent statuses; composition that
satisfies every requested pair; ambiguous_match; build-time effective-policy
validation and the generated reviewer view. Examples now show a git fetch
and push with a detected version and intent. Still labeled a prototype
pending API review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
}
if let Err(p) = catch_unwind(|| {
// SAFETY: caller guarantees `r` points to a valid result.
let r = unsafe { &mut *r };
Chaz Gordish (Agent) and others added 18 commits October 5, 2026 10:57
Dependencies, overlays and composition now follow the pushed spec
(microsoft#1309 at 5a2c52c, docs/mxc-policy-store.md):

- Dependencies contribute the referenced entry's default plus platform
  base additions only. A reference may name intents
  ({ entryId, intents: [...] }); a named intent the dependency's default
  does not define fails catalog validation. Dependency diagnostics report
  intentSelection mode "none" or "named".
- Overlays use policyAdditions, intentAdditions (default intents only)
  and newIntents. The former overlay `intents` field is renamed to
  `newIntents` in the model, JSON schema, metadata and fixtures.
- A catalog egress deny that overlaps another requested pair's required
  egress allow is removed in full, with a diagnostic naming the full
  destination/port scope and the contributing entries. Non-overlapping
  denies stay. Overlapping denies are no longer composition_conflict.
- Network rule validation parses CIDRs, requires `except` blocks inside
  their peer, and rejects ports on icmp.
- The reviewer view adds an "Added to default" column per row.
- Catalog revision 2026-10-05.1 replaces 2026-10-02.1: git entryRevision
  2 moves the >=2.50 bundle-fetch intent to newIntents.
- New composition-catalog conformance fixture and library tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Rust SDK and C ABI re-export the core changes unchanged. Their tests
now assert that a plain dependency reports intentSelection mode "none"
with an empty selection, and that version-variant metadata exposes
newIntents.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IntentSelection.mode adds "none" for dependencies that contribute their
base only. Overlay metadata renames `intents` to `newIntents` to match
the catalog field. Tests assert both over the bundled catalog.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Overlay metadata records rename Intents to NewIntents (JSON newIntents).
IntentSelection documents mode "none" for dependencies that contribute
their base only. Tests assert both over the bundled catalog.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document newIntents, base-only dependencies with optional named intents
(mode "none"/"named"), full removal of overlapping catalog egress denies,
the reviewer view's "Added to default" column, catalog revision
2026-10-05.1, and the remaining gap for symbol defaults and discovery.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bring the prototype onto the MXC 1.0 SDKs: the consolidated mxc-sdk crate
(microsoft#1390), the v1 ContainerRequest surfaces in Rust, Node and .NET, exact
JSON FFI ingress, and Promise-based Node v1 APIs (microsoft#1398).

Shared files take upstream as-is. The previous SDK wiring (mxc-sdk
re-exports, mxc_ffi exports, Node and .NET wrappers, and their tests)
targeted the retired SandboxPolicy surfaces and is removed here; the
following commits port the store into mxc-sdk's internal policy_store
module and rebuild the bindings on the v1 requirements API from spec
f7a450c. The catalog crate under src/core/mxc_policy_store is left
outside the workspace until that port.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Spec f7a450c makes the policy store an internal `policy_store` module of
the consolidated mxc-sdk crate rather than a separate crate. Move the
sources to src/mxc-sdk/src/policy_store/, the bundled catalog, schemas
and conformance data to src/mxc-sdk/policy_store/, the catalog embedding
to build/build_policy_store.rs, and the tests to
tests/policy_store_*.rs. A doc-hidden `__policy_store` facade serves the
C ABI and the contribution tests.

No behavior change; the requirements API follows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Resolve to command-free ContainerRequirements (the v1 ContainerRequest
access fields) through mxc_sdk::v1::resolve_tool_requirements and
resolve_tool_requirements_with_diagnostics, with failures mapped to the
SDK Error.

- Catalog: default.requirements replaces sandboxPolicy; the root declares
  sdkContractVersion and the SDK owns the wire version. Revision
  2026-10-06.1 replaces 2026-10-05.1 and the reviewer view adds a
  requests bundle of the exact 1.0.0 documents it validates.
- PURL identity compares type, namespace and name only; invalid candidate
  PURLs are purl_invalid / tool_unmatched per pair and ignored components
  are reported as purl_components_ignored.
- Warnings are structured (per-input and detail kinds) with stable codes.
- Layers are de-duplicated per layer with owner attribution; dependency
  diagnostics carry inputIndexes.
- Symbols resolve from the caller, then host values and discovery, then
  contract defaults, reporting symbol_resolved.
- Filesystem object identity fails closed per pair
  (filesystem_identity_unresolved); alias paths are preserved and
  read-only aliases of writable paths are promoted.
- Every materialized and resolved floor is validated as an exact 1.0.0
  one-shot request.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore the prototype policy store C ABI over mxc-sdk's internal
policy_store module: mxc_resolve_tool_requirements_json and its
diagnostics variant return {"requirements"?} / {"requirements"?,
"diagnostics"} in the v1 ContainerRequirements shape, alongside the
catalog info and entry listing. Failures keep the status code and the
store's details.reason; panics stay contained. The request is a catalog
lookup rather than policy ingress, and the composed value is proven to
convert to the typed v1 sections before it crosses the boundary.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…c-sdk/v1

resolveToolRequirements and resolveToolRequirementsWithDiagnostics take
one ToolInput or an array and return Promises of ContainerRequirements
(Pick<ContainerRequest, "filesystem" | "network" | "ui" | "timeoutMs">)
and ToolRequirementsResolution. Resolution runs on Koffi's worker pool
because it examines host filesystem objects; getCatalogInfo (now with
sdkContractVersion) and listCatalogEntries stay synchronous. Warnings are
typed as the spec's discriminated unions, and failures reject with
MxcError carrying details.reason.

Labeled PROTOTYPE, pending API review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
….Sdk.V1

PROTOTYPE, pending API review. Adds MxcContainer.ResolveToolRequirements and
ResolveToolRequirementsWithDiagnostics (single-tool and list overloads, plus
Async Task forms), GetCatalogInfo, and ListCatalogEntries over the mxc_ffi
policy-store exports, per spec f7a450c section 5.1.

- Results map onto ContainerRequirements built from the existing v1 section
  types; ContainerRequest.FromRequirements adds the caller's command.
- Typed diagnostics, including structured ResolutionWarning subtypes parsed
  strictly (unknown codes or fields fail rather than being dropped).
- Failures throw MxcException with the new Reason property (null outside the
  policy store), restoring Chaz's earlier error-shape decision on top of the
  upstream MxcException.
- The lookup is excluded from the IContainerRunner mirror test: it is a
  catalog lookup, not container execution.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PROTOTYPE, pending API review.

- docs/policy-store/README.md: ContainerRequirements, the internal
  mxc-sdk policy_store module, the v1 entry points in each SDK (promise-based
  Node), per-input statuses, structured warnings, exact MXC 1.0.0 validation,
  failure reasons, and the catalog workflow with the current test names.
- docs/policy-store/design.md: replaced the drifting copy of the spec with
  implementation notes that point at microsoft#1309 and record the
  prototype's decisions and known gaps.
- src/mxc-sdk/policy_store/README.md and the Node, .NET, and Rust SDK READMEs:
  prototype sections with examples.
- .github/copilot-instructions.md: the policy_store module invariant.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PROTOTYPE, pending API review. Implements the catalog source layout in
design section 6.3:

- catalog/entries/{git,node,npm,ssh}.json hold each tool's full entry:
  identity, default, intents, every platform and version variant,
  dependencies, and provenance. They were split from 2026-10-06.1 without
  any data change.
- policy_store::assemble collects entry files recursively and assembles the
  revision in entryId order. It rejects duplicate entryIds and dependencies on
  entries that no file defines. Paths are used only in error messages.
- It is a checked generator, following the existing reviewer-view pattern:
  default_revision_matches_the_entry_sources fails when
  revisions/<defaultRevision>.json is stale, and
  MXC_POLICY_STORE_UPDATE_REVISION=1 regenerates it. The regenerated
  2026-10-06.1 snapshot is byte-identical to the existing one.
- Tests cover a duplicate entryId, a dangling dependency (including nested
  in an overlay), path independence, and deterministic output.
- The static, manifest-selected embedding and the public API are unchanged.
- The docs describe the authoring workflow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
microsoft#1309 at 5c2ba8e splits the caller-facing contract into
docs/mxc-policy-store-api.md and keeps the catalog design in
docs/mxc-policy-store.md. Section numbers in the design doc are unchanged.
Every API field, status, warning code, and error reason already matches.

- Node: export PlatformVariantSelector and EgressRule, which the API spec
  now names as exported types, and use them in the catalog metadata and
  NetworkRequirement types. The shapes are unchanged.
- Rust doc comments: point the old design §5 references at the matching
  API spec sections, and define both references in the module docs.
- docs/policy-store README and design.md: link both spec documents at
  5c2ba8e.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per-input diagnostics become {inputIndex, contributes, status, selection?}; contributes is true only for pairs that added access. Rust entry points take a ToolCandidate slice and Option<&ResolveContext>, with From<&str> for bare names. projectRoot and symbols.project_root both bind project_root (equal values accepted, different values fail invalid_context), caller symbols report symbol_resolved, and ui/timeoutMs compose from a single source or fail composition_conflict. Conformance fixtures regenerated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Map the 2c682f3 per-input diagnostics shape and reject malformed resolution shapes at the SDK boundary with backend_error.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ToolCandidate becomes a sealed class per the spec (null name throws ArgumentNullException, implicit conversion from string). ToolDiagnostics carries required Contributes and optional Selection; malformed results fail with backend_error. AOT smoke covers the new shapes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document the per-input diagnostics shape, projectRoot/symbols.project_root binding, single-source ui/timeoutMs, and the slice-based Rust signature.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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