Skip to content

Publish the mxc-sdk crate closure to crates.io - #716

Draft
Darren Hoehna (dhoehna) wants to merge 40 commits into
microsoft:mainfrom
dhoehna:user/dahoehna/crates-esrp-release
Draft

Publish the mxc-sdk crate closure to crates.io#716
Darren Hoehna (dhoehna) wants to merge 40 commits into
microsoft:mainfrom
dhoehna:user/dahoehna/crates-esrp-release

Conversation

@dhoehna

@dhoehna Darren Hoehna (dhoehna) commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

What this does

Adds a dedicated pipeline that packages the mxc-sdk crate closure — 21 crates — and publishes them to crates.io through ESRP Release, one crate at a time in leaf-first order. Publishing is manual and gated on a release ref, so nothing reaches crates.io until a release is deliberately cut.

Running a release

The pipeline is MXC-Release-Crates, definition 198954: https://microsoft.visualstudio.com/Dart/_build?definitionId=198954

Push a release ref to microsoft/mxc and pick it in the Run dialog's branch/tag selector. Validate_Release_Ref accepts exactly two shapes and fails the run on anything else:

  • a release branch, refs/heads/release/* — for example release/v0.8.0
  • a version tag, refs/tags/v* — for example v0.8.0

The gate carries isSkippable: false, so it cannot be switched off in the "Stages to run" panel, and both Package_Crates_For_Release and Publish_to_CratesIo depend on it. The definition carries no triggers, so a pipeline that publishes to a public registry cannot fire on a push.

Two things worth knowing before the first run. The ref must exist on microsoft/mxc — the Run dialog enumerates that repository only, so a branch pushed to a fork will not appear. And a release branch is not immutable on its own: the gate proves where a run came from, not that the ref cannot move. Freeze it with a GitHub ruleset (Settings → Rules → Rulesets) blocking pushes, force-pushes, and deletion, or use a tag.

dryRun defaults to true: it packages the closure and checks the publish order, then skips the publish stage entirely — the run reports that stage as Skipped rather than green, so a rehearsal is distinguishable from a publish at a glance. Set it to false to publish for real. It is the only field in the Run dialog. The ESRP owner and approver are not fields: an email is not a decision the person clicking Run should make, and a typo submits the release to the wrong owner. Both are fixed in the YAML to $(Build.RequestedForEmail), which is what a default run already used. A runtime guard in the gate stage fails the run if that variable resolves empty, which it can for a run queued by a service identity rather than a person.

The pipeline needs no crates.io network access: the 1ES pool's CFSClean isolation blocks crates.io, dependency resolution stays on the private Mxc-Azure-Feed, and ESRP owns the publishing credentials. Operator steps are documented in docs/crates-release.md.

How it works

  • Packaging runs natively on three agentswindows-2022, ubuntu-latest, and macOS-15-arm64 — each executing the same cargo package call with one -p flag per crate against --registry Mxc-Azure-Feed. A crate that no longer compiles on Linux or macOS therefore fails at package time, before anything is published, instead of after. The publish stage depends on all three legs, so any red platform stops the release. Cargo's verification build stays on, so a mismatched sibling version requirement fails packaging. The registry override works around A bug about cargo publish --workspace --registry crates-io rust-lang/cargo#17196, under which just-packaged workspace siblings are otherwise looked up in the wrong source and not found.
  • The Windows leg additionally runs check-template, copies the release script into the artifact, and publishes it. Linux and macOS package only, so a template drift failure surfaces on Windows while the other two legs stay green.
  • The publish order is computed, not maintained. CRATES in crates_release.py is an unordered set of package names; the order is a leaf-first topological sort of the workspace dependency graph derived from cargo metadata, with alphabetical tie-breaking. Packaging derives it live; the template's crateOrder is a pasted copy of the same computation, because ${{ each }} expands before any script runs. A pasted copy can drift, and drifting failed silently: verify-order accepts an ordered subset on purpose, since that is how a part-published release resumes, so a template missing a newly-added crate passed and the crate was simply never published. check-template now recomputes the order on every PR and fails the build unless the template matches exactly. Adding a crate is: add the name, run crates_release.py order, paste the output — and CI fails if you forget the last step.
  • The order and a per-crate SHA-256 are recorded in release-order.json. Each staged .crate is re-checked against that digest before ESRP submission, and staging fails closed if the digest is missing or disagrees. verify-order accepts an ordered subset of the packaged closure, which is what makes resuming a partly-published release possible.
  • The official build gains an opt-in packageCrates parameter (default false) that runs the same packaging as a merge-time canary; it produces the artifact but never publishes.
  • src/Cargo.toml sets repository under [workspace.package] and pins version = "0.7.0" on the first-party path dependencies so they are publishable.

Depends on #782

process_security_environment_spec has to be publishable or the closure cannot be packaged at all. Cargo writes a .crate for a publish = false workspace member but does not add it to the temporary registry its siblings resolve against (src/ops/cargo_package/mod.rs), which blocks appcontainer_common, mxc_engine, and mxc-sdk. #782 makes that crate publishable on main. This branch carries the same flag so the pipeline can be exercised before #782 merges, and matches its provenance wording so the two merge cleanly.

Validation

  • Release run 154278010, dryRun: true — all three legs green, 21 of 21 crates packaged on each of Windows, Linux, and macOS, and Publish Crates.io Packages reported Skipped.
  • Release run 154277340check-template failed the release against a template missing a newly-added crate. That is the drift the gate exists to catch, caught on a real release run.
  • crates_release.py check-template and crates_release.py order — exit 0, 21 crates, template matching the computed order.
  • check-psec-codegen.js — schema matches provenance, 12 files regenerated with the pinned flatc 25.12.19 and no drift, crate compiles.
  • Ref gate logic exercised against 10 refs — accepts release/* branches and v* tags, rejects main, user/*, a bare refs/heads/release, and the case variants Release/v0.8.0 and V1. The gate uses PowerShell -clike rather than -like, because -like is case-insensitive and would admit refs the release/* ruleset does not freeze.

Still open

  • hyperlight_common cannot publish under that name. It normalizes to hyperlight-common, already taken on crates.io by hyperlight-dev (v0.16.0), and crates.io treats - and _ as equivalent. A broader mxc_ prefix policy for the whole closure is under discussion, and would supersede a single rename.
  • ESRP Rust content-type enablement for the MXC client ID, OSPO open-source release registration, and a crates.io PublishNew rate-limit override all remain to be requested. ESRP does support Rust and crates.io publishing; what is missing is per-client-ID enablement.
  • No ESRP crates.io publish has ever run, so that destination is unproven. A dryRun: true run stops after packaging — it deliberately does not execute the publish job, so artifact download, verify-order, staging, and ESRP submission are all still unexercised.
  • What "verified on three platforms" does and does not mean. Four crates in the closure are Windows-only by design, and gating them does not give them Linux or macOS functionality — it makes them compile to an empty library there instead of failing the build. isolation_session_bindings, isolation_session_common, and appcontainer_common expose nothing off Windows, and nanvix_runner exposes nothing on macOS: its cfg mirrors the pre-existing gate on wxc_common::microvm_staging, which its core logic depends on and which does not exist there. That is the correct shape for crates.io, where a package must resolve on every platform even when it does nothing there, and it is what the verification proves: the closure builds everywhere, not that every crate is useful everywhere. mxc_telemetry is partially gated the same way, which predates this change.

Make the mxc-sdk crate closure publishable and add official-build packaging plus a guarded ESRP release flow with dependency ordering, checksum verification, propagation waits, and safe retries.

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

Copilot-Session: f199a77f-51ec-4441-baa5-b87df8177b83
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: f199a77f-51ec-4441-baa5-b87df8177b83
Copilot AI balanced review requested due to automatic review settings July 30, 2026 21:47
@dhoehna
Darren Hoehna (dhoehna) requested a review from a team as a code owner July 30, 2026 21:47

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.

Pull request overview

Adds opt-in packaging and ESRP publication of the mxc-sdk crate dependency closure to crates.io.

Changes:

  • Adds publishable metadata and versioned internal dependencies for 18 crates.
  • Adds packaging, dependency-order validation, checksum verification, and retry-safe publishing.
  • Keeps crate packaging disabled pending Cargo #17196 resolution.

Reviewed changes

Copilot reviewed 24 out of 25 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Cargo.toml Adds repository metadata and dependency versions.
src/mxc_telemetry/Cargo.toml Adds repository metadata.
src/core/wxc_common/Cargo.toml Adds package metadata and NanVix version.
src/core/mxc-sdk/Cargo.toml Adds repository metadata.
src/core/mxc_pty/Cargo.toml Adds publishable metadata.
src/core/mxc_engine/Cargo.toml Adds repository metadata.
src/core/generated/base_container_specification/Cargo.toml Makes generated bindings publishable.
src/backends/wslc/common/Cargo.toml Adds publishable metadata.
src/backends/windows_sandbox/lifecycle/Cargo.toml Adds license and package metadata.
src/backends/windows_sandbox/common/Cargo.toml Adds publishable metadata.
src/backends/seatbelt/common/Cargo.toml Adds publishable metadata.
src/backends/nanvix/runner/Cargo.toml Adds metadata and dependency version.
src/backends/nanvix/common/Cargo.toml Adds repository metadata.
src/backends/lxc/common/Cargo.toml Adds publishable metadata.
src/backends/isolation_session/common/Cargo.toml Adds publishable metadata.
src/backends/isolation_session/bindings/Cargo.toml Makes bindings publishable.
src/backends/hyperlight/common/Cargo.toml Adds publishable metadata.
src/backends/bubblewrap/common/Cargo.toml Adds publishable metadata.
src/backends/appcontainer/common/Cargo.toml Adds publishable metadata.
.azure-pipelines/templates/Publish.CratesIo.Job.yml Defines ordered ESRP publication workflow.
.azure-pipelines/templates/Package.Crates.Job.yml Packages the crate closure as an artifact.
.azure-pipelines/templates/1ES.Build.Stages.yml Adds the opt-in packaging stage.
.azure-pipelines/scripts/crates_release.py Validates, stages, and verifies crate releases.
.azure-pipelines/1ES.Release.yml Adds selectable npm and crates.io release stages.
.azure-pipelines/1ES.Build.Official.yml Exposes the crate-packaging parameter.

default: false

jobs:
- deployment: publish_crates

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch - this was correct and would have failed validation before any step ran.

Confirmed against the 1ES release-job docs, whose deployment-job example annotates the field as required verbatim: environment: MyEnvironment # Required, name of the environment.

Fixed in d408846 by taking your second suggestion: converted to a standard job with templateContext.type: releaseJob and flattened strategy.runOnce.deploy.steps into plain steps:. That matches the NPM release job already working in 1ES.Release.yml, and it avoids provisioning an ADO Environment (and the approval gates that come with it) purely to satisfy the schema. The 1ES docs show the standard-job form for release jobs in four of their five examples, so it is the better-trodden path here.

@dhoehna
Darren Hoehna (dhoehna) marked this pull request as draft July 30, 2026 22:06
Two independent blockers prevented the crates.io release path from working.

B1 - packaging. With `[source.crates-io] replace-with = "Mxc-Azure-Feed"`
active, `cargo package` resolves a just-packaged sibling through the
replacement feed instead of its own in-memory overlay, so the sibling 404s
(rust-lang/cargo#17196): cargo registers the overlay under the pre-replacement
SourceId but looks it up under the post-replacement one.

Pass `--registry Mxc-Azure-Feed` so the source override is not consulted. The
resulting .crate is byte-identical to a no-replacement baseline, so no feed URL
leaks into the published artifact. `--registry` defaults to `crates-io`, leaving
local and developer builds unchanged.

B2 - releasing. The release job made four reads of index.crates.io (probe,
status, verify-dependencies, wait). The 1ES CFSClean isolation policy denies
that host, so the job could not succeed on the pool regardless of the artifacts.
Those reads are removed; ESRP publishes server-side and is unaffected.
Correctness is preserved by three existing layers:

  1. sibling version-req match is enforced by `cargo package` itself (exit 101)
  2. leaf-first ordering is validated offline by _validate_release_graph
  3. dependency name existence is enforced server-side by crates.io via a
     Postgres lookup on the crates table, so index propagation never gates
     sequential publishing

`verify-order` now accepts a correctly ordered subset of the packaged order, so
a partially failed release can be resumed by narrowing `crateOrder`; it emits
warnings naming every dependency it therefore assumes is already published.
release-order.json records sha256 per crate for out-of-band auditing.

packageCrates and publishCrates still default to false.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f199a77f-51ec-4441-baa5-b87df8177b83
Copilot AI review requested due to automatic review settings August 3, 2026 16:21

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.

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

.azure-pipelines/templates/Publish.CratesIo.Job.yml:27

  • The PR description promises automatic crates.io checksum/existence checks and checksum-aware reruns, but this implementation explicitly performs no registry reads and requires operators to remove crates manually. That means a resumed run can publish dependents based only on an unchecked operator assertion, and an unchanged rerun is not safe as described. Either restore the advertised preflight/ledger behavior in a network-capable stage or update the release design and PR description to make this manual safety boundary explicit.
# RESUMING A FAILED RELEASE: crates.io rejects a duplicate version, so simply
# re-running this job unchanged fails on the first crate that already landed.
# The pool cannot ask crates.io what landed, and 1ES forbids `checkout` in a
# release job, so there is no automated ledger. Instead the operator re-queues
# the release with the already-published crates removed from `crateOrder`.
# `verify-order` accepts that subset only if it is still in packaged leaf-first
# order, and logs every dependency it is consequently assuming is already live.

.azure-pipelines/scripts/crates_release.py:229

  • This disables Cargo's only check that each generated archive can compile after workspace path dependencies are rewritten to registry dependencies. A successful workspace build does not cover missing packaged files or normalized-manifest problems, so the release can publish crates that consumers cannot build. Remove --no-verify (the private-registry workaround should also support verification), or add an equivalent build-from-archive gate before this stage is enabled.
        "--no-verify",

Comment on lines +357 to +361
source = _crate_file(args.order_file, entry)
if not os.path.isfile(source):
print(f"Crate file not found: {source}")
return 1
shutil.copy2(source, os.path.join(out_dir, entry["file"]))
Copilot AI review requested due to automatic review settings August 3, 2026 16:24
The crates release job was a `deployment` job with no `environment:`. 1ES
documents `environment` as required for the deployment form of a release job
("environment: MyEnvironment # Required, name of the environment"), so the
stage would have failed YAML validation before any step ran.

Convert it to a standard `job` with `templateContext.type: releaseJob` and
flatten the `strategy.runOnce.deploy.steps` block into plain `steps:`. This
matches the NPM release job already working in 1ES.Release.yml, and avoids
provisioning an ADO Environment (and its approval gates) purely to satisfy the
schema.

Reported by the Copilot PR reviewer on microsoft#716.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f199a77f-51ec-4441-baa5-b87df8177b83
@dhoehna

Copy link
Copy Markdown
Contributor Author

Two outstanding items that need a decision

Both are external to this PR - no amount of code review resolves them, and both have lead time, so they are worth starting now rather than at release time.

1. hyperlight_common name collision on crates.io

hyperlight_common normalizes to hyperlight-common, which is already taken on crates.io by the hyperlight-dev project (currently v0.16.0, actively maintained). crates.io treats - and _ as equivalent for uniqueness, so neither spelling is available to us. Re-verified 2026-08-03; the other 17 names in the closure are free.

This is a hard stop for that one crate - it is not a "retry later" situation, and it will not free up on its own.

Options:

  1. Rename before first publish (e.g. mxc_hyperlight_common). Cheapest and fully under our control, but it becomes a permanent public name.
  2. Request co-ownership or a transfer from hyperlight-dev. Possibly viable given the shared Microsoft context, but it is a negotiation with unknown latency.
  3. Exclude it from the published closure - only viable if nothing else we publish depends on it, which needs checking.

This is a naming/ownership call rather than an engineering one. Gudge (@MGudgin) - flagging for you and Anis; I am sending you both the details separately by email.

2. crates.io publish rate limit for 18 new crates

Publishing a new crate is rate-limited separately from publishing a new version of an existing one. Per the crates.io source defaults, the new-crate bucket is a burst of 5 with a refill of 1 per 10 minutes, so an 18-crate first release stalls at crate #6 and then trickles - roughly two hours of pure waiting.

Caveat worth stating: those are the defaults in the crates.io source. I have not been able to confirm the values actually configured in production, so treat the two-hour figure as an estimate rather than a measurement.

This only affects the first release; subsequent version bumps use the much more generous update bucket.

Options:

  1. Request an override via help@crates.io. They maintain a per-publisher override table for exactly this case (bulk onboarding of a crate family). Needs lead time.
  2. Accept the serial ~2h release. Workable, but it makes the first run long and therefore more likely to be interrupted - see the resume procedure in the PR description.

Not blocking, but worth knowing

MXC has never executed an ESRP crates.io publish - not once. Whether ESRP is onboarded for crates.io as a destination for this product is an open question for the ESRP team. The credentials themselves are proven (the same ESRPInfo bundle already drives our NPM release and Mac/Rust signing); it is specifically the crates.io destination that is unverified.

Relatedly, the packaging fix in this PR has been proven on 2-crate probes in the identical sibling shape but not against the real 18-crate closure. packageCrates deliberately stays false. I would recommend one opt-in packageCrates: true run on the official build as the next step - it validates the fix at full scale and publishes nothing.


Branden Bonaby (@bbonaby) - could you take a look? The parts most worth your attention are the deletion of the four crates.io reads in Publish.CratesIo.Job.yml and the three-layer safety argument in the PR description that justifies it, since that is where I would most want a second opinion on whether anything is actually lost.

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.

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated no new comments.

Suppressed comments (2)

.azure-pipelines/templates/Publish.CratesIo.Job.yml:94

  • The release starts the next dependent crate immediately after ESRP reports completion, but crates.io index updates are asynchronous; the new dependency may not yet be resolvable, causing the next publish to fail with “dependency does not exist.” The PR’s Safety section says propagation is awaited, but this loop has no delay or retry. Add a supported propagation gate after each publish (preferably polling the sparse index from a network-enabled job, or a conservative wait if this pool must remain isolated).
            - task: EsrpRelease@12

.azure-pipelines/templates/Publish.CratesIo.Job.yml:30

  • This explicitly contradicts the PR’s Safety claim that reruns skip versions already published with the matching checksum. The implementation instead fails on duplicates and asks an operator to remove entries without verifying the published checksum, so a partial release is neither automatically resumable nor checksum-safe as described. Restore the live checksum/idempotency check (for example in a permitted network-enabled gate or trusted publication ledger), or revise the stated release guarantees before relying on this workflow.
# RESUMING A FAILED RELEASE: crates.io rejects a duplicate version, so simply
# re-running this job unchanged fails on the first crate that already landed.
# The pool cannot ask crates.io what landed, and 1ES forbids `checkout` in a
# release job, so there is no automated ledger. Instead the operator re-queues
# the release with the already-published crates removed from `crateOrder`.

Copilot AI review requested due to automatic review settings August 3, 2026 16:55
Releasing crates previously took two queued runs: MXC-Official-Build with
packageCrates to produce the artifact, then MXC-Official-Release with
publishCrates to consume it. The intent is that releasing is one click.

1ES forbids `checkout` in a release JOB, but a regular job in the same PIPELINE
may check out and build - 1ES documents this pattern explicitly, wiring a
release job to a sibling build job's artifact via `input: pipelineArtifact` with
`artifact:` rather than a cross-pipeline `pipeline:`/`artifactName:` pair.

Add a Package_Crates_For_Release stage to 1ES.Release.yml that runs
Package.Crates.Job.yml, and make Publish_to_CratesIo depend on it. The release
job's artifact input switches from the cross-pipeline form to the same-run form.

Queueing 1ES.Release.yml with publishCrates now packages the closure and then
publishes it in one run. cratesDryRun packages and verifies while skipping ESRP,
which is the cheap way to exercise the full 18-crate closure without publishing.

The npm release is unchanged and still consumes mxc-npm-sdk-package from
MXC-Official-Build.

packageCrates on the official build is retained as a CI canary: it detects
packaging breakage at merge time without requiring a release run.

Note: the packaging job now runs CargoAuthenticate against Mxc-Azure-Feed from
the release pipeline rather than the build pipeline. Both run in the same ADO
project and so should share a build service identity, but that is unverified -
a cratesDryRun run exercises exactly this path and publishes nothing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f199a77f-51ec-4441-baa5-b87df8177b83

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.

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated 2 comments.

Comment on lines +220 to +229
package_args = [
"cargo",
"package",
"--no-verify",
"--allow-dirty",
"--registry",
args.registry,
"--manifest-path",
manifest,
]
Comment thread .azure-pipelines/1ES.Release.yml Outdated
pipeline: MXC
targetPath: '$(Pipeline.Workspace)/packages'
artifactName: mxc-npm-sdk-package
- ${{ if parameters.publishNpm }}:
Select the release in the Run dialog's "Pipeline version" picker instead of
typing a tag into a parameter.  The ref the run is queued against now supplies
both the pipeline definition and the packaged source, so a release is
immutable: changing anything about how a release is built, including this
pipeline, requires cutting a new tag.

A new Validate_Release_Ref stage fails the run unless Build.SourceBranch
matches refs/tags/release/*, and the package and publish stages depend on it,
so nothing is checked out or published from a branch, a bare version tag, or a
raw commit.  The check has to run at runtime because Build.SourceBranch is not
available to compile-time template expressions.  The stage is marked
isSkippable: false so it cannot be deselected in the Run dialog's "Stages to
run" panel, which would otherwise make the guard advisory.

Re-enable cargo package verification.  Passing --registry resolves workspace
siblings against the temporary package registry, so rust-lang/cargo#17196 does
not apply and --no-verify is unnecessary.  --allow-dirty is likewise dropped:
the only file the pipeline modifies is the workspace .cargo/config.toml, which
lies outside every package directory, so a dirty-tree failure now means a
crate source really was modified.  The script's --registry default moves to
Mxc-Azure-Feed to match, since the old crates-io default was only harmless
while verification was off.

Verify each staged .crate against the sha256 recorded at packaging time before
handing it to ESRP, failing closed on a missing or mismatched digest.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7cf82d0d-a130-47ee-8e7c-409209a3b4f9
Copilot AI review requested due to automatic review settings August 3, 2026 23:08

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.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated no new comments.

Suppressed comments (2)

docs/crates-release.md:67

  • The release procedure will break on the next version bump. These newly versioned path dependencies keep literal 0.7.0 requirements (including the two direct nanvix_common dependencies), so changing only [workspace.package].version makes the local 0.8.0 siblings fail the 0.7.0 requirements; scripts/check-version-sync.js does not update or validate them. The instructions must require updating every first-party dependency requirement in lockstep (and the SDK versions checked by the existing sync gate).
1. Bump the version in `src/Cargo.toml`.

.azure-pipelines/1ES.Release.Crates.yml:80

  • The release entry point advertised in the PR description is not present: this new pipeline exposes cratesDryRun, while the existing 1ES.Release.yml has no publishCrates parameter or crates stages. Queueing MXC-Official-Release with publishCrates: true therefore cannot perform the documented release. Either integrate these stages into that pipeline or update the PR description to direct operators to the separately registered 1ES.Release.Crates.yml pipeline.
parameters:
  - name: cratesDryRun
    displayName: 'Dry run — package and verify order but skip ESRP publish'
    type: boolean
    default: false

Resolves a textual conflict in src/Cargo.toml.  Upstream added the
learning_mode_core workspace member and its path dependency while this
branch added version fields to the dependencies the crates.io release
publishes.  Both sides are kept.  learning_mode_core stays unversioned
because it is not in the current 18-crate publish list.
Copilot AI review requested due to automatic review settings August 4, 2026 19:27

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.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.

Suppressed comments (2)

docs/crates-release.md:156

  • This resume procedure repackages the remaining crates from a new commit rather than the original release tag/artifact. If main has advanced, Cargo verifies against the new local sibling sources while consumers resolve already-published siblings from the old tag, allowing an incompatible mixed closure under one version; even a pipeline-only commit changes Cargo's packaged VCS provenance/checksum. Resume from the original artifact/tag while supplying only the remaining order, rather than tagging a new main commit.
2. Edit the `crateOrder` default in `.azure-pipelines/1ES.Release.Crates.yml`,
   removing the already-published crates, and merge that change to `main`.
   `crateOrder` is an `object` parameter; changing it means editing the
   pipeline file.
3. Cut a **new** release tag containing that edit (for example

docs/crates-release.md:62

  • This release step is incomplete now that the PR adds literal version = "0.7.0" requirements for first-party dependencies in the workspace and crate-local manifests. Changing only workspace.package.version to 0.8.0 leaves packages requiring ^0.7.0 siblings, so cargo package will reject the next release. Include those dependency requirements in the version bump instructions.
1. Bump the version in `src/Cargo.toml`.

"bwrap_common",
"seatbelt_common",
"sandbox_spec",
"appcontainer_common",
Comment thread .azure-pipelines/1ES.Release.Crates.yml Outdated
Comment on lines +77 to +80
- name: cratesDryRun
displayName: 'Dry run — package and verify order but skip ESRP publish'
type: boolean
default: false
Copilot AI review requested due to automatic review settings August 7, 2026 22:37
@dhoehna
Darren Hoehna (dhoehna) marked this pull request as draft August 7, 2026 22:38

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.

Pull request overview

Copilot reviewed 36 out of 37 changed files in this pull request and generated 1 comment.

Suppressed comments (4)

.azure-pipelines/scripts/crates_release.py:623

  • A RESUME-SUBSET marker is accepted unconditionally, including when check-template is invoked by the GitHub Versioning Checks workflow. Consequently, a PR into main can carry the marker plus a shortened order and this branch returns success, contrary to the documented backstop at docs/crates-release.md:323-327; the next normal release would silently omit crates. Keep the default CI mode strict and require an explicit allow-resume option only from the release pipeline.
    if resume_reason is not None:
        unknown = [name for name in actual if name not in expected]
        if unknown:
            print(f"FAIL  {args.template_path} declares a resume subset naming unknown crates: {unknown}")
            return 1
        if actual != [name for name in expected if name in set(actual)]:

docs/crates-release.md:108

  • These instructions describe the workspace version as the only value to bump, but this PR adds explicit version = "0.7.0" requirements for first-party path dependencies in three manifests. Following the documented 0.8.0 example while changing only [workspace.package].version leaves ^0.7.0 requirements that reject the local 0.8.0 siblings during packaging. Document updating those dependency requirements as part of every incompatible version bump.
## How versions are determined

All crates declare `version.workspace = true` in their own `Cargo.toml`, so the
single `version` field in `src/Cargo.toml` (currently `0.7.0`) is the version
that ships. The pipeline does not set or override the version — it packages
whatever `src/Cargo.toml` contains at the tagged commit. To release a new
version:

1. Bump the version in `src/Cargo.toml`.

docs/crates-release.md:403

  • This prerequisite is already resolved according to the PR metadata: the pipeline is registered as definition 198954, and the variable group and service connection are authorized. Leaving it under “must be resolved before the first real publish” gives operators stale release readiness information; remove it or replace it with any authorization work that actually remains.
5. **Pipeline registration** — `.azure-pipelines/1ES.Release.Crates.yml` is new
   and must be registered as a pipeline in Azure DevOps, and that pipeline must
   be authorized to use the `MXC-ESRP-Signing` variable group.

.azure-pipelines/templates/Publish.CratesIo.Job.yml:33

  • verify-order does not catch every stale copy: it intentionally accepts an ordered subset, so a template that omits a newly added crate passes. The full-list drift check is check-template; update this comment so maintainers do not rely on the weaker publish-time guard.
  # Static YAML because ${{ each }} expands at compile time.  verify-order
  # catches a stale copy at run time, before anything is published.

"sandbox_spec",
"learning_mode_core",
"learning_mode_windows",
"appcontainer_common",
Packaging ran as one Windows job that added two rustup targets and passed
three --target flags to a single cargo package call. The .crate archive is
the crate's source and is target-independent, so the extra targets bought
verification, not different artifacts.

Fan the job across the windows, linux, and macOS pools with the matrix
pattern Lint.Job.yml already uses, and package for each agent's own triple.
Build scripts now run on the OS they are verifying rather than all on
Windows. Only the Windows leg publishes the artifact, so the artifact name
the release job consumes is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ab22cd6f-f3d9-4325-8397-9e998aa058c3
Copilot AI review requested due to automatic review settings August 7, 2026 22:53
The three-target verify list carried this invariant in its comment and went
away with it when packaging moved to native per-OS agents.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ab22cd6f-f3d9-4325-8397-9e998aa058c3

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.

Pull request overview

Copilot reviewed 36 out of 37 changed files in this pull request and generated 1 comment.

Suppressed comments (6)

.azure-pipelines/scripts/crates_release.py:100

  • process_security_environment_spec is missing from the release closure even though appcontainer_common has it as a normal Windows path dependency (src/backends/appcontainer/common/Cargo.toml:30). _validate_release_graph rejects every check-template/package run with “local dependency is missing from CRATES”; moreover, the dependency still has publish = false, so appcontainer_common could not resolve from crates.io. Add this crate to the publishable closure (including its metadata/order/docs) or remove/vendor the dependency before publishing.
    "sandbox_spec",

.azure-pipelines/templates/Package.Crates.Job.yml:34

  • This implementation materially differs from the PR description: it creates three native-agent jobs, while crates_release.py package passes no --target flags. The description instead claims the entire pipeline runs on Windows, one cargo package invocation verifies three targets, and the helper validates all targets are installed. Either implement those guarantees or update the release/validation description to reflect the native matrix.
  - name: matrix
    type: object
    default:
      - name: windows_x64
        os: windows
        triplet: x86_64-pc-windows-msvc
      - name: linux_x64
        os: linux
        triplet: x86_64-unknown-linux-gnu
      - name: macos_arm64
        os: macos
        triplet: aarch64-apple-darwin

docs/crates-release.md:114

  • The runbook's single version bump does not work for its 0.8.0 example: first-party path dependencies are pinned to version = "0.7.0" in src/Cargo.toml:110-135 and two crate manifests, so Cargo rejects a 0.8 sibling as outside ^0.7.0. The repository's version-sync check also requires the npm and C# SDK versions to match. Document all required updates so following the release procedure does not fail during packaging/CI.
1. Bump the version in `src/Cargo.toml`.
2. Commit and push.
3. Cut a release branch named `release/v<major>.<minor>.<patch>[-rc<n>]` (for
   example `release/v0.8.0`) from the commit you are releasing, and confirm
   the `release/*` ruleset has frozen it — see
   [Choosing the release ref](#choosing-the-release-ref).
4. Run the pipeline against that branch.

.azure-pipelines/templates/Publish.CratesIo.Job.yml:33

  • This comment is incorrect: verify-order deliberately accepts a subset, so it cannot detect a stale template that merely omits a crate. The new check-template step is the guard that detects stale copies; naming the wrong guard obscures the release safety model documented elsewhere in this PR.
  # Static YAML because ${{ each }} expands at compile time.  verify-order
  # catches a stale copy at run time, before anything is published.

docs/crates-release.md:403

  • This is no longer an unresolved prerequisite according to the PR description: definition 198954 is registered, and both the variable group and service connection are authorized. Leaving it in “known blockers” gives operators an incorrect pre-release checklist; remove it or rewrite it as a verification step with the current resources.
5. **Pipeline registration** — `.azure-pipelines/1ES.Release.Crates.yml` is new
   and must be registered as a pipeline in Azure DevOps, and that pipeline must
   be authorized to use the `MXC-ESRP-Signing` variable group.

.azure-pipelines/templates/1ES.Build.Stages.yml:100

  • The official-build artifact is not consumed by 1ES.Release.Crates.yml; that pipeline checks out its selected release ref and runs this packaging template again. Describe this stage as the opt-in merge-time canary/artifact instead, otherwise maintainers may assume the release uses a previously built immutable artifact.
    # Source-only (no binaries), so it does not depend on Build_Binaries. Produces
    # the `mxc-crates-package` artifact consumed by 1ES.Release.Crates.yml for ESRP-based
    # crates.io publishing. Isolated in its own stage so it never gates npm
    # packaging or the integration tests that depend on Package_MXC.

Comment on lines +141 to +144
// `system_dir` is Windows-only, and Windows Sandbox does not exist on the
// other targets the crates.io release packages for.
#[cfg(not(windows))]
let sandbox_exe = std::path::PathBuf::from("WindowsSandbox.exe");
Copilot AI review requested due to automatic review settings August 7, 2026 23:02

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.

Pull request overview

Copilot reviewed 36 out of 37 changed files in this pull request and generated no new comments.

Suppressed comments (5)

.azure-pipelines/scripts/crates_release.py:606

  • This returns success for a resume subset in every caller, including the GitHub Versioning Checks workflow. Consequently, a PR can merge a shortened crateOrder plus the marker into main, even though the release guide says that CI rejects this state; later releases can silently omit those crates. Make resume subsets opt-in only for the release-ref packaging invocation, while the PR check requires the complete order.
    if resume_reason is not None:

.azure-pipelines/scripts/crates_release.py:103

  • appcontainer_common has a path dependency on process_security_environment_spec, but that package is absent from CRATES and still has publish = false. _validate_release_graph will therefore reject this closure with “local dependency is missing from CRATES” before cargo package runs. Publish/include that generated crate as well, or remove the registry dependency from the published closure.
    "appcontainer_common",

.azure-pipelines/templates/Package.Crates.Job.yml:38

  • The PR description and validation section say packaging is one Windows job with three --target flags, but this implementation runs three native OS jobs and cmd_package passes no --target. Update the PR description/validation to reflect the actual matrix so reviewers and release operators know which execution path was tested.
  - ${{ each item in parameters.matrix }}:
    - job: package_crates_${{ item.name }}

docs/crates-release.md:108

  • This release instruction is incomplete: scripts/check-version-sync.js requires the npm and C# SDK versions to match, and the first-party path dependency requirements are hard-coded to 0.7.0 in src/Cargo.toml and two crate manifests. Following only this step for the documented 0.8.0 example will fail CI/package validation. List all required version updates here.
1. Bump the version in `src/Cargo.toml`.

docs/crates-release.md:403

  • This prerequisite is already resolved according to the PR description: the pipeline is registered as definition 198954, and the variable group/service connection are authorized. Leaving it under “must be resolved” gives release operators stale blocking guidance; remove this item.
5. **Pipeline registration** — `.azure-pipelines/1ES.Release.Crates.yml` is new
   and must be registered as a pipeline in Azure DevOps, and that pipeline must
   be authorized to use the `MXC-ESRP-Signing` variable group.

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

Copilot-Session: ab22cd6f-f3d9-4325-8397-9e998aa058c3
Cargo keeps a path dependency in the published manifest whenever it carries a version, so the version-less form is what lets a dev-dependency on an unpublished crate be stripped at package time.  The release validator and the order computation now apply that same rule.

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

Copilot-Session: ab22cd6f-f3d9-4325-8397-9e998aa058c3
Copilot AI review requested due to automatic review settings August 8, 2026 03:05

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.

Pull request overview

Copilot reviewed 36 out of 37 changed files in this pull request and generated no new comments.

Suppressed comments (4)

.azure-pipelines/scripts/crates_release.py:103

  • appcontainer_common still has a versioned Windows path dependency on process_security_environment_spec, but that package is absent from CRATES and its manifest still has publish = false. Because _survives_publish treats this dependency as publishable, _validate_release_graph will report appcontainer_common -> process_security_environment_spec: local dependency is missing from CRATES, so both check-template and every packaging job stop before cargo package. Make that generated crate publishable and add it throughout the release closure, or remove the registry dependency by packaging the bindings into a publishable crate.
    "appcontainer_common",

docs/crates-release.md:109

  • The documented version-bump procedure is incomplete now that publishable path dependencies have literal version = "0.7.0" requirements. Bumping only [workspace.package].version to 0.8.0 leaves the requirements in src/Cargo.toml, core/wxc_common/Cargo.toml, and backends/nanvix/runner/Cargo.toml at ^0.7.0; the packaging verification will then reject the 0.8.0 workspace siblings. Include all first-party dependency requirements in the bump procedure (and ideally add a parity check) rather than describing the workspace package field as the only version to change.
1. Bump the version in `src/Cargo.toml`.
2. Commit and push.

.azure-pipelines/templates/Package.Crates.Job.yml:34

  • This implementation contradicts the PR description's platform-validation contract. The description says the entire pipeline runs on Windows and one cargo package call receives all three --target flags, with the helper checking that all targets are installed; this template instead creates three native-OS jobs, and cmd_package passes no --target. Update the PR description and validation evidence to describe the native matrix, or restore the single Windows cross-target implementation, so reviewers and release operators know what was actually validated.
  - name: matrix
    type: object
    default:
      - name: windows_x64
        os: windows
        triplet: x86_64-pc-windows-msvc
      - name: linux_x64
        os: linux
        triplet: x86_64-unknown-linux-gnu
      - name: macos_arm64
        os: macos
        triplet: aarch64-apple-darwin

docs/crates-release.md:403

  • This is no longer an open prerequisite: the PR description says pipeline definition 198954 is registered and that MXC-ESRP-Signing is authorized, with successful runs allocating agents. Leaving it under “must be resolved” gives release operators stale setup instructions; remove this item or move it to a completed-prerequisites section.
5. **Pipeline registration** — `.azure-pipelines/1ES.Release.Crates.yml` is new
   and must be registered as a pipeline in Azure DevOps, and that pipeline must
   be authorized to use the `MXC-ESRP-Signing` variable group.

Darren Hoehna (dhoehna) and others added 2 commits August 7, 2026 20:45
appcontainer_common takes a normal dependency on this crate under
cfg(target_os = "windows"), so cargo keeps the dependency and its version
when packaging.  While the crate was publish = false, cargo refused to
substitute the locally packaged copy, and packaging appcontainer_common
failed with "no matching package named process_security_environment_spec".
mxc_engine and mxc-sdk failed behind it.

The crate's schema carries an MIT header and is already committed to the
public repository, and the "not publicly redistributable" note in its
README refers to the internal OS tree it was vendored from rather than to
the schema text.  Nothing found restricts the generated bindings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ab22cd6f-f3d9-4325-8397-9e998aa058c3
The README said the vendored schema "is not publicly redistributable",
which reads as a restriction on the schema itself.  The restriction is on
the internal OS tree it was taken from: the schema text carries an MIT
header and has been committed to this public repository since microsoft#739.

Add the repository field so the published crate carries a source link.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ab22cd6f-f3d9-4325-8397-9e998aa058c3
Copilot AI review requested due to automatic review settings August 8, 2026 03: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.

Pull request overview

Copilot reviewed 36 out of 39 changed files in this pull request and generated 1 comment.

Suppressed comments (3)

docs/crates-release.md:105

  • Bumping only [workspace.package].version is insufficient for a minor/major release. The newly added first-party dependency requirements in src/Cargo.toml (plus the direct nanvix_common pins) remain 0.7.0; for the documented 0.8.0 example, Cargo will reject the packaged 0.8.0 siblings because 0.7.0 means ^0.7.0. Add updating all first-party dependency version requirements to the release steps.
All crates declare `version.workspace = true` in their own `Cargo.toml`, so the
single `version` field in `src/Cargo.toml` (currently `0.7.0`) is the version
that ships. The pipeline does not set or override the version — it packages
whatever `src/Cargo.toml` contains at the tagged commit. To release a new

docs/crates-release.md:10

  • The release closure is now 21 crates: CRATES includes process_security_environment_spec, but this overview still says 20 and the crate list below omits it (with additional “20” references later in this document). Update the count and list so the operator documentation matches what the pipeline packages.
The **1ES.Release.Crates** pipeline (`.azure-pipelines/1ES.Release.Crates.yml`)
packages and publishes the 20-crate release closure from the MXC Rust workspace
in a single pipeline run:

src/backends/learning_mode/windows/Cargo.toml:20

  • This comment is now incorrect: the same change makes process_security_environment_spec publishable and adds it to CRATES. The dependency remains path-only because it is a development dependency that Cargo removes from the published manifest, not because the target crate is unavailable on crates.io.
# Path-only so cargo strips it when publishing; the crate is not on crates.io.

- mxc_pty
- mxc_telemetry
- nanvix_common
- sandbox_spec
Making process_security_environment_spec publishable added it to CRATES in
crates_release.py, but the crateOrder default in Publish.CratesIo.Job.yml is
a second, independent list.  The check-template gate on the Windows leg of
build 154277340 caught the drift and failed the release, which is what that
gate is for.

Without this the crate would be packaged and never published, and every
crate that depends on it would fail to resolve against a registry that does
not have it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ab22cd6f-f3d9-4325-8397-9e998aa058c3

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.

Pull request overview

Copilot reviewed 36 out of 39 changed files in this pull request and generated no new comments.

Suppressed comments (6)

.azure-pipelines/scripts/crates_release.py:620

  • A RESUME-SUBSET marker with the full order currently succeeds, although the release guide states that a marker left on main fails check-template. Besides contradicting the documented backstop, a forgotten marker silently authorizes future order omissions as deliberate resumes. Reject the marker unless actual is a strict subset of expected.
    if resume_reason is not None:

docs/crates-release.md:108

  • Bumping only [workspace.package].version is insufficient for the documented 0.8.0 release: src/Cargo.toml now contains explicit version = "0.7.0" requirements on the first-party path dependencies, and Cargo will reject local 0.8.0 packages against those ^0.7.0 constraints. Include updating all first-party dependency requirements (or an automation command that does so) in the release procedure.
All crates declare `version.workspace = true` in their own `Cargo.toml`, so the
single `version` field in `src/Cargo.toml` (currently `0.7.0`) is the version
that ships. The pipeline does not set or override the version — it packages
whatever `src/Cargo.toml` contains at the tagged commit. To release a new
version:

1. Bump the version in `src/Cargo.toml`.

.azure-pipelines/scripts/crates_release.py:545

  • This substring check treats any mention of RESUME-SUBSET as authorization for a partial release—for example, # Do not add a RESUME-SUBSET marker would activate resume mode. Because resume mode bypasses the exact-order drift gate, recognize only the documented marker syntax instead of any occurrence.
        if RESUME_MARKER in raw and not found_default:
            resume_reason = raw.split(RESUME_MARKER, 1)[1].lstrip(" :#").strip() or "(no reason given)"

src/backends/learning_mode/windows/Cargo.toml:21

  • process_security_environment_spec is now explicitly publishable and included in CRATES, so this comment is stale. Keeping this dependency path-only makes Cargo strip it from the published manifest, leaving the packaged examples/lm_capture.rs unable to resolve the crate on Windows. Preserve the versioned workspace dev-dependency instead.
# Path-only so cargo strips it when publishing; the crate is not on crates.io.
process_security_environment_spec = { path = "../../../core/generated/process_security_environment_specification" }

docs/crates-release.md:10

  • The release helper and publish template contain 21 crates, including process_security_environment_spec, but this guide says 20 and omits that crate from the list below. The other “20”/“19” counts in this guide are consequently stale as well; update the operator documentation to reflect the actual closure.
The **1ES.Release.Crates** pipeline (`.azure-pipelines/1ES.Release.Crates.yml`)
packages and publishes the 20-crate release closure from the MXC Rust workspace
in a single pipeline run:

.azure-pipelines/templates/Package.Crates.Job.yml:34

  • The PR description says the whole pipeline runs on Windows and one cargo package invocation verifies three --target values in parallel. This template instead creates three native-OS jobs, and the package command supplies no --target. Update the PR’s implementation/validation claims or restore the described single-Windows multi-target design so reviewers and release operators have an accurate security and build model.
  - name: matrix
    type: object
    default:
      - name: windows_x64
        os: windows
        triplet: x86_64-pc-windows-msvc
      - name: linux_x64
        os: linux
        triplet: x86_64-unknown-linux-gnu
      - name: macos_arm64
        os: macos
        triplet: aarch64-apple-darwin

Richie Gomez opened PR 782 to make process_security_environment_spec
publishable, which is the same change this branch already carried.  He owns
the schema and he set the original publish = false, so his wording is the
authoritative one and this branch should not carry a second version of it.

Take his text verbatim in the crate README and in the provenance file, and
drop the comment that justified the flag here.  PR 782 is now the decision
record, so repeating the reasoning in the manifest would only leave a stale
copy of it.

The provenance file was missed entirely when this branch first made the
crate publishable.  It still claimed the schema was not publicly
redistributable, which is the sentence PR 782 removes.

repository.workspace = true stays.  All twenty-one crates in the release
closure set it and PSEC was the only one that did not, so without it PSEC
would be the lone exception once PR 782 merges.  PR 782 does not touch that
line, so the two changes merge cleanly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ab22cd6f-f3d9-4325-8397-9e998aa058c3

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.

Pull request overview

Copilot reviewed 37 out of 40 changed files in this pull request and generated no new comments.

Suppressed comments (7)

.azure-pipelines/templates/Publish.CratesIo.Job.yml:52

  • A real release still includes hyperlight_common, even though this PR documents that crates.io normalizes it to the already-owned hyperlight-common name. Because eight crates are published before this entry, clearing dryRun can irreversibly publish a partial release and then fail here. Block real publishing until the name/ownership issue is resolved, or rename the crate and update the dependency graph/order first.
    - hyperlight_common

docs/crates-release.md:108

  • This instruction is incomplete for a minor-version release such as the documented 0.8.0 example. The PR adds first-party path dependency requirements pinned to 0.7.0; changing only [workspace.package].version to 0.8.0 leaves those requirements incompatible, so cargo package fails. Include updating all first-party dependency version requirements (ideally via an automated version-bump/check command).
1. Bump the version in `src/Cargo.toml`.

src/backends/windows_sandbox/lifecycle/src/vm.rs:144

  • This non-Windows fallback undoes the executable-search-order protection described immediately above: vm and its public launch_managed_vm remain exported off Windows, so reaching that API executes the first WindowsSandbox.exe found via the host's search path. The unsupported-target implementation should fail immediately, or the host-side lifecycle crate/module should compile empty off Windows, rather than launching an untrusted relative executable.
    // `system_dir` is Windows-only, and Windows Sandbox does not exist on the
    // other targets the crates.io release packages for.
    #[cfg(not(windows))]
    let sandbox_exe = std::path::PathBuf::from("WindowsSandbox.exe");

.azure-pipelines/templates/Package.Crates.Job.yml:34

  • The PR description says packaging runs wholly on Windows in one cargo package invocation with three --target arguments, but this template creates three native-agent jobs, and the helper passes no --target. Update either the implementation or the PR's design and validation claims; the stated single-invocation/60-target-cell validation does not describe the pipeline being merged.
      - name: windows_x64
        os: windows
        triplet: x86_64-pc-windows-msvc
      - name: linux_x64
        os: linux
        triplet: x86_64-unknown-linux-gnu
      - name: macos_arm64
        os: macos
        triplet: aarch64-apple-darwin

.azure-pipelines/scripts/crates_release.py:101

  • Including process_security_environment_spec makes this a 21-crate closure, while the PR description and docs/crates-release.md repeatedly say 20 and the documented crate list omits this package. Update the release documentation and PR description so operators know the complete public package set.
    "process_security_environment_spec",

.azure-pipelines/templates/1ES.Build.Stages.yml:100

  • This comment says the official-build artifact is consumed by 1ES.Release.Crates.yml, but that pipeline runs Package.Crates.Job.yml itself and publishes the artifact from its own Windows matrix leg. The official-build option is only a canary, so describing this artifact as release input can cause operators to assume the release uses previously built artifacts.
    # Source-only (no binaries), so it does not depend on Build_Binaries. Produces
    # the `mxc-crates-package` artifact consumed by 1ES.Release.Crates.yml for ESRP-based
    # crates.io publishing. Isolated in its own stage so it never gates npm
    # packaging or the integration tests that depend on Package_MXC.

docs/crates-release.md:403

  • The PR description says pipeline definition 198954 is already registered and both the variable group and service connection are authorized, so listing registration/authorization as an unresolved prerequisite is stale. Remove this blocker or replace it with an accurate remaining prerequisite.
5. **Pipeline registration** — `.azure-pipelines/1ES.Release.Crates.yml` is new
   and must be registered as a pipeline in Azure DevOps, and that pipeline must
   be authorized to use the `MXC-ESRP-Signing` variable group.

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.

Pull request overview

Copilot reviewed 37 out of 40 changed files in this pull request and generated no new comments.

Suppressed comments (4)

.azure-pipelines/scripts/crates_release.py:620

  • check-template is also invoked by the GitHub Versioning Checks workflow, but this branch returns success for any marked subset. As a result, a release branch PR can merge a shortened crateOrder plus RESUME-SUBSET into main, even though the operator guide says that PR must fail; later releases would then silently omit those crates. Make resume-subset acceptance an explicit option used only by the release pipeline, while CI requires the complete order.
    if resume_reason is not None:

docs/crates-release.md:109

  • These instructions are incomplete now that publishable path dependencies carry literal version = "0.7.0" requirements. Following the documented single-field bump to 0.8.0 leaves ^0.7.0 constraints that reject the 0.8.0 sibling crates, so release packaging fails. Include updating every publishable first-party path-dependency requirement (ideally with a sync check) in the release procedure.
All crates declare `version.workspace = true` in their own `Cargo.toml`, so the
single `version` field in `src/Cargo.toml` (currently `0.7.0`) is the version
that ships. The pipeline does not set or override the version — it packages
whatever `src/Cargo.toml` contains at the tagged commit. To release a new
version:

1. Bump the version in `src/Cargo.toml`.
2. Commit and push.

docs/crates-release.md:10

  • The release closure now contains 21 crates, and process_security_environment_spec appears in both CRATES and crateOrder. This guide still says 20 throughout and omits that crate from the list, so the documented release inventory and blocker counts are stale.
The **1ES.Release.Crates** pipeline (`.azure-pipelines/1ES.Release.Crates.yml`)
packages and publishes the 20-crate release closure from the MXC Rust workspace
in a single pipeline run:

src/backends/learning_mode/windows/Cargo.toml:20

  • This comment now contradicts this PR: process_security_environment_spec is included in the 21-crate crates.io publish order and its manifest sets publish = true. Retain only the explanation that the versionless dev-dependency is stripped from the published manifest.
# Path-only so cargo strips it when publishing; the crate is not on crates.io.

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.

Pull request overview

Copilot reviewed 37 out of 40 changed files in this pull request and generated no new comments.

Suppressed comments (8)

.azure-pipelines/scripts/crates_release.py:635

  • check-template accepts any RESUME-SUBSET unconditionally, so the GitHub versioning check also returns success for a trimmed resume list. That contradicts the documented backstop in docs/crates-release.md and allows such a list to merge to main, causing later releases to silently omit crates. Require an explicit allow-resume option that is passed only by release-ref packaging; CI on main should reject the marker/subset.
    if resume_reason is not None:
        unknown = [name for name in actual if name not in expected]
        if unknown:
            print(f"FAIL  {args.template_path} declares a resume subset naming unknown crates: {unknown}")
            return 1
        if actual != [name for name in expected if name in set(actual)]:
            print(f"FAIL  {args.template_path} declares a resume subset that is out of dependency order.")
            print(f"    template : {actual}")
            print(f"    required : {[n for n in expected if n in set(actual)]}")
            return 1
        skipped = [name for name in expected if name not in actual]
        print(f"RESUME SUBSET declared in {args.template_path}: {resume_reason}")
        print(f"  publishing {len(actual)} of {len(expected)} crates, in valid dependency order.")
        print(f"  assumed ALREADY PUBLISHED and skipped: {skipped or '(none)'}")
        print("  Remove the RESUME-SUBSET marker and restore the full list on main once the release completes.")
        return 0

docs/crates-release.md:42

  • process_security_environment_spec is in the release closure but is missing from this purported complete alphabetical crate list.
- `sandbox_spec`

docs/crates-release.md:276

  • The closure has 21 crates now, so this resume example uses the old total.
(e.g. crate 7 of 20 fails for a transient reason), crates 1–6 are already

docs/crates-release.md:394

  • With process_security_environment_spec added, there are 21 names in the closure; if only hyperlight_common is taken, the remaining count is 20.
   github.com/hyperlight-dev/hyperlight.  It is the only one of the 20 names
   that is taken today; the other 19 are unregistered.  The crate must be

docs/crates-release.md:399

  • The first release now submits 21 new crate versions, not 20, so the rate-limit estimate should use the current closure size.
   plus 1 per 10 minutes.  A 20-crate first release will be throttled.  An

src/backends/learning_mode/windows/Cargo.toml:21

  • This path-only dev dependency is stripped from the published manifest, but the packaged examples/lm_capture.rs imports it. As a result, consumers of the published crate cannot build the documented example (or run all-target checks). The dependency is now part of this crates.io closure, so retain its workspace version.
# Path-only so cargo strips it when publishing; the crate is not on crates.io.
process_security_environment_spec = { path = "../../../core/generated/process_security_environment_specification" }

.azure-pipelines/templates/Publish.CratesIo.Job.yml:33

  • This comment is incorrect: verify-order intentionally accepts an ordered subset, so it does not catch a stale template that omits a crate. The new check-template step is the drift backstop.
  # Static YAML because ${{ each }} expands at compile time.  verify-order
  # catches a stale copy at run time, before anything is published.

docs/crates-release.md:9

  • The release closure now contains 21 crates (CRATES and crateOrder both include process_security_environment_spec), so the overview count is stale.

This issue also appears in the following locations of the same file:

  • line 42
  • line 276
  • line 393
  • line 399
packages and publishes the 20-crate release closure from the MXC Rust workspace

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.

3 participants