Skip to content

Commit ed0262c

Browse files
committed
Fix cargo-dist bootstrap portability
1 parent 08ba8ab commit ed0262c

11 files changed

Lines changed: 47 additions & 26 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ jobs:
7878
persist-credentials: false
7979
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
8080
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
81+
- name: Verify cargo-dist bootstrap on the native host
82+
shell: bash
83+
run: scripts/install-cargo-dist.sh
8184
- run: cargo test --all-targets --all-features --locked
8285
- run: cargo build --profile dist --locked
8386
- name: Verify Unix host and binary

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sno"
3-
version = "0.1.2"
3+
version = "0.1.3"
44
edition = "2024"
55
rust-version = "1.85"
66
description = "The unified command-line interface for SNO"

ai-doc/ACTIVE/PRD/sno-cli-initial-release.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ Scope: Create the unified Rust `sno` CLI, migrate the legacy Nodix operator comm
77

88
## Decision Summary
99

10-
SNO ships one Rust binary named `sno`. Version `0.1.0` established the functional crate rather than a placeholder: it includes the existing Nodix identity workflows under `sno account machine ...`, its local telemetry workflows under `sno station ...`, top-level help/version behavior, a `sno starport` noun scaffold, and Git-style external subcommand dispatch for executables named `sno-<name>` on `PATH`. Version `0.1.1` preserved that implementation on crates.io, but its GitHub workflow failed closed before artifact creation. Version `0.1.2` is the forward-only synchronized production-distribution release that adds verified native artifacts without changing the command contract.
10+
SNO ships one Rust binary named `sno`. Version `0.1.0` established the functional crate rather than a placeholder: it includes the existing Nodix identity workflows under `sno account machine ...`, its local telemetry workflows under `sno station ...`, top-level help/version behavior, a `sno starport` noun scaffold, and Git-style external subcommand dispatch for executables named `sno-<name>` on `PATH`. Versions `0.1.1` and `0.1.2` preserved that implementation on crates.io, but their GitHub workflows failed closed before artifact hosting. Version `0.1.3` is the forward-only synchronized production-distribution release that adds verified native artifacts without changing the command contract.
1111

12-
The GitHub repository is public before downloadable binaries are released. Publishing to crates.io is allowed only after package inspection, dry-run success, and full review. The owner has authorized forward-only publication through `0.1.2` after those gates pass. The Rust source included in the `.crate` archive is public regardless of GitHub repository visibility.
12+
The GitHub repository is public before downloadable binaries are released. Publishing to crates.io is allowed only after package inspection, dry-run success, and full review. The owner has authorized forward-only publication through `0.1.3` after those gates pass. The Rust source included in the `.crate` archive is public regardless of GitHub repository visibility.
1313

1414
## Problem
1515

@@ -31,7 +31,7 @@ The source snapshot is `nodix-private` commit `4256aa66aae2dc95edc71f788b456874a
3131
- The user-visible command layer is about 800 source lines. The directly required SDK implementation spans identity, consent, buffer, export, diagnostics, registration, claim, and audit code; a correct port is not a parser-only translation.
3232
- The archived May 2026 CLI specification describes the existing behavior but is reference material only. Its old top-level naming and Node-only packaging decisions are superseded by this PRD.
3333
- The draft “Nodix CLI as the Unified Local AI Setup Entry” is not authoritative. Its memory/gateway/scale wizard remains future product work.
34-
- Current release state on 2026-07-15 PDT: crates.io packages `sno` `0.1.0` and `0.1.1` are public under `SnoInfo`; GitHub repository `sno-ai/sno-cli` is public with immutable releases enabled; no GitHub binary release exists yet.
34+
- Current release state on 2026-07-15 PDT: crates.io packages `sno` `0.1.0`, `0.1.1`, and `0.1.2` are public under `SnoInfo`; GitHub repository `sno-ai/sno-cli` is public with immutable releases enabled; no GitHub binary release exists yet. The `0.1.2` workflow failed closed during cross-platform bootstrap before hosting assets, and its tag remains fixed.
3535

3636
Probe evidence is recorded in `ai-doc/ACTIVE/PRD/PROBE-RESULTS-sno-cli-initial-release.md`.
3737

@@ -46,7 +46,7 @@ Probe evidence is recorded in `ai-doc/ACTIVE/PRD/PROBE-RESULTS-sno-cli-initial-r
4646

4747
### PRD-GOAL-1 — Canonical Rust CLI
4848

49-
Maintain crate `sno` with binary `sno`, built with Rust and `clap`. `sno --version` and `sno --help` must work from a clean installation. Release `0.1.2` synchronizes crates.io source, the Git tag, and GitHub binary assets.
49+
Maintain crate `sno` with binary `sno`, built with Rust and `clap`. `sno --version` and `sno --help` must work from a clean installation. Release `0.1.3` synchronizes crates.io source, the Git tag, and GitHub binary assets.
5050

5151
### PRD-GOAL-2 — Functional Account and Station Namespaces
5252

@@ -78,7 +78,7 @@ Expose built-in noun commands `sno account`, `sno station`, and `sno starport`.
7878

7979
Prepare and publish only the real Rust implementation:
8080

81-
- crates.io: `sno` `0.1.2`, owned by company account `SnoInfo`; `0.1.0` and the registry-only `0.1.1` remain valid published predecessors.
81+
- crates.io: `sno` `0.1.3`, owned by company account `SnoInfo`; `0.1.0`, `0.1.1`, and the registry-only `0.1.2` remain valid published predecessors.
8282
- GitHub Releases: native archives, Shell and PowerShell installers, Cargo Binstall metadata, SHA-256 checksums, and available GitHub artifact attestations.
8383

8484
The five formally supported operating-system and architecture families are Linux x64/ARM64, macOS Intel/Apple Silicon, and Windows x64. Linux additionally ships static musl variants for x64 and ARM64, producing seven target archives:
@@ -107,7 +107,7 @@ After the Rust implementation passes parity and production-shaped checks, retire
107107

108108
### PRD-AUTH-1 — Human Publish Authority
109109

110-
No crates.io publish occurs before the exact package contents, review report, and required gates are inspected. The owner has explicitly authorized forward-only publication through `0.1.2` after those gates pass; a new approval is required only if the package scope or settled release contract changes. GitHub creates only a mutable draft after local archive and installer checks; it publishes and freezes that draft only after the GitHub-downloaded assets pass, and the release is not declared green until anonymous public Shell and PowerShell checks also pass.
110+
No crates.io publish occurs before the exact package contents, review report, and required gates are inspected. The owner has explicitly authorized forward-only publication through `0.1.3` after those gates pass; a new approval is required only if the package scope or settled release contract changes. GitHub creates only a mutable draft after local archive and installer checks; it publishes and freezes that draft only after the GitHub-downloaded assets pass, and the release is not declared green until anonymous public Shell and PowerShell checks also pass.
111111

112112
### PRD-AUTH-2 — Local Identity Authority
113113

@@ -228,7 +228,7 @@ Always:
228228

229229
Ask:
230230

231-
- Before publishing if the reviewed package scope or settled release contract changes; forward-only `0.1.2` is already authorized after its gates pass.
231+
- Before publishing if the reviewed package scope or settled release contract changes; forward-only `0.1.3` is already authorized after its gates pass.
232232
- Before changing a settled command, state, auth, or JSON contract.
233233
- Before weakening or deferring any Release Green-Light criterion.
234234

@@ -250,7 +250,7 @@ Every item is `risky: true` and requires recorded evidence.
250250
- `PRD-GL-4`: Security tests prove no secret output, HTTPS enforcement, direct external process execution, owner-only identity permissions, and package archive cleanliness.
251251
- `PRD-GL-5`: GitHub repository `sno-ai/sno-cli` is public before binary publication, CI is green, release immutability is enabled, Apache-2.0 and repository metadata are present, and the naming guardrail is documented.
252252
- `PRD-GL-6`: `cargo fmt --check`, `cargo clippy --all-targets --all-features -- -D warnings`, `cargo test --all-targets --all-features`, `cargo package --list`, and `cargo publish --dry-run` pass from a clean tree.
253-
- `PRD-GL-7`: The exact `.crate` contents and final source review are presented to the owner; the synchronized release publishes `sno` `0.1.2` under `SnoInfo` and tags the same reviewed source version.
253+
- `PRD-GL-7`: The exact `.crate` contents and final source review are presented to the owner; the synchronized release publishes `sno` `0.1.3` under `SnoInfo` and tags the same reviewed source version.
254254
- `PRD-GL-8`: Seven GitHub target archives are published only after native build, real-binary execution, clean extraction, and local-Station smoke; musl assets additionally pass pinned-Alpine execution.
255255
- `PRD-GL-9`: Shell and PowerShell installers, Cargo Binstall metadata, SHA-256 checksums, and available GitHub artifact attestations match the exact released version and assets.
256256
- `PRD-GL-10`: The old TypeScript CLI is retired and active callers/docs are updated after parity passes; immutable archives remain unchanged.

openspec/changes/rust-binary-distribution/design.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Shell and PowerShell installers are first executed against the exact staged arch
3939

4040
### Publish a synchronized patch release from a semantic version tag
4141

42-
Version `0.1.0` is already immutable on crates.io and cannot be republished. Version `0.1.1` was reviewed and published byte-identically, but its GitHub workflow failed closed before building or hosting assets because the immutable-release settings endpoint requires repository Administration read permission that a standard workflow token cannot receive. The tag remains fixed at its reviewed commit. The forward-only recovery is `0.1.2`: the workflow accepts `v<crate-version>` tags only, and the crate plus tag identify the same repaired reviewed source.
42+
Version `0.1.0` is already immutable on crates.io and cannot be republished. Version `0.1.1` was reviewed and published byte-identically, but its GitHub workflow failed closed before building or hosting assets because the immutable-release settings endpoint requires repository Administration read permission that a standard workflow token cannot receive. Version `0.1.2` was also published byte-identically, but its workflow failed closed during cross-platform cargo-dist bootstrap: standard macOS rejected GNU-only checksum flags and Windows rejected ZIP extraction through tar. Both tags remain fixed at their reviewed commits. The forward-only recovery is `0.1.3`: the workflow accepts `v<crate-version>` tags only, and the crate plus tag identify the same repaired reviewed source.
4343

4444
### Use checksums, provenance, and immutable releases
4545

@@ -77,8 +77,8 @@ Environment parity:
7777
3. Run a non-publishing workflow on every final runner label; each job records its observed architecture and passes the real-binary smoke before the matrix is frozen.
7878
4. Merge one reviewed candidate commit and wait for all local, native, archive, staged-installer, and release-policy checks to pass.
7979
5. Make the repository public and enable immutable releases. Create an active tag ruleset for `refs/tags/v*` that restricts creation, update, and deletion to organization administrators. `scripts/authorize-release.sh` then verifies public visibility, immutable releases, that ruleset, the remote `main` commit, and a successful CI run before writing the reviewed commit to repository variable `SNO_RELEASE_AUTHORIZED_SHA`. The workflow receives no administration token.
80-
6. From a clean checkout of the reviewed commit, package and publish crate `0.1.2`; download the registry archive and require its SHA-256 to match the local package archive.
81-
7. Create tag `v0.1.2` at that exact reviewed commit. The tag-triggered workflow requires public visibility and the commit-bound administrator receipt, repeatedly checks that the remote tag still resolves to the event commit, tests every extracted archive and staged installer, downloads and retests a GitHub draft, anonymously tests the same bytes through a one-use public candidate, deletes that candidate, and publishes the final draft. Immutable-state verification uses bounded retries: confirmed mutable state triggers release cleanup, while an unavailable or ambiguous API result retains the release and blocks for operator inspection. A confirmed final anonymous-installer failure deletes the release. Every cleanup preserves the final version tag and requires a forward patch.
80+
6. From a clean checkout of the reviewed commit, package and publish crate `0.1.3`; download the registry archive and require its SHA-256 to match the local package archive.
81+
7. Create tag `v0.1.3` at that exact reviewed commit. The tag-triggered workflow requires public visibility and the commit-bound administrator receipt, repeatedly checks that the remote tag still resolves to the event commit, tests every extracted archive and staged installer, downloads and retests a GitHub draft, anonymously tests the same bytes through a one-use public candidate, deletes that candidate, and publishes the final draft. Immutable-state verification uses bounded retries: confirmed mutable state triggers release cleanup, while an unavailable or ambiguous API result retains the release and blocks for operator inspection. A confirmed final anonymous-installer failure deletes the release. Every cleanup preserves the final version tag and requires a forward patch.
8282
8. After installer checks pass, record a release-identity receipt containing the reviewed commit, tag commit, local and registry crate hashes, target archive hashes, and GitHub workflow run.
8383

8484
Rollback is forward-only after an immutable release: yank or deprecate the affected version where supported, fix the workflow, increment the crate version, and publish a new tag. Never replace an existing asset or move a released tag.

openspec/changes/rust-binary-distribution/evidence/reviews/test-writer-final.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| Registration, claim, retry, authentication, and server-error contracts cross a real network boundary | `tests/cli.rs` with `tests/support/sno_service_server.rs` | Integration | Real child process, TCP listener, HTTP bytes, filesystem, and SQLite | Request method, path, headers, body, retry count, error code, and persisted identity | PASS |
1616
| Concurrent consent and account operations preserve state | `tests/cli.rs` and `src/state.rs` tests | Integration | Real processes, operating-system locks, files, and SQLite transactions | Latest committed value persists, rollback is atomic, and duplicate ownership is rejected | PASS |
1717
| Handler and protocol assertion failures cannot produce a green test | `sno_service_server::tests::dropped_server_propagates_handler_panic` | Regression | Real worker thread and TCP connection | The enclosing test observes the worker panic even without explicit fixture finalization | PASS |
18-
| Unsupported release paths and test substitutes fail closed | Release and substitute policy self-tests | Mutation | Real Git repositories, tracked files, shell scripts, and policy checkers | 29 forbidden mutations are rejected and the repository is accepted | PASS |
18+
| Unsupported release paths and test substitutes fail closed | Release and substitute policy self-tests | Mutation | Real Git repositories, tracked files, shell scripts, and policy checkers | 31 forbidden mutations are rejected and the repository is accepted | PASS |
1919
| All supported target families execute real binaries | CI run 29407013123 | End-to-end | Five native runners and two architecture-matched pinned Alpine containers | Each job builds and executes version, help, and fresh-profile Station consent | PASS |
2020

2121
### Mock Inventory
@@ -28,5 +28,5 @@
2828
- `cargo clippy --all-targets --all-features --locked -- -D warnings` -> proves changed Rust test code has no compiler or lint blocker.
2929
- `scripts/test-test-substitute-policy.sh` -> proves 9 forbidden substitute mutations fail and the repository remains substitute-free.
3030
- `scripts/test-release-surface-policy.sh` -> proves 7 forbidden release-surface mutations fail, including local actions and ordinary helper scripts.
31-
- `scripts/test-release-workflow-policy.sh` -> proves 13 release-workflow security mutations fail.
31+
- `scripts/test-release-workflow-policy.sh` -> proves 15 release-workflow security mutations fail.
3232
- `gh run view 29407013123 --repo sno-ai/sno-cli` -> proves the quality job and all seven target-family jobs passed on GitHub-hosted runners.

openspec/changes/rust-binary-distribution/specs/rust-binary-distribution/spec.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Every release archive SHALL be extracted into a clean directory and the extracte
3737
- **THEN** the release workflow fails before creating a GitHub Release
3838

3939
### Requirement: Version and tag integrity
40-
The production binary release SHALL use forward-only version `0.1.2` after the `0.1.1` workflow failed closed before artifact creation. The release workflow SHALL accept only semantic version tags matching the crate version and SHALL use the committed lockfile for all builds. The crates.io package and GitHub tag SHALL identify the same reviewed source version. The existing `v0.1.1` tag MUST NOT be moved.
40+
The production binary release SHALL use forward-only version `0.1.3` after the `0.1.1` workflow failed closed before artifact creation and the `0.1.2` workflow failed closed during cross-platform bootstrap before artifact hosting. The release workflow SHALL accept only semantic version tags matching the crate version and SHALL use the committed lockfile for all builds. The crates.io package and GitHub tag SHALL identify the same reviewed source version. The existing `v0.1.1` and `v0.1.2` tags MUST NOT be moved.
4141

4242
#### Scenario: Tag and crate version differ
4343
- **WHEN** a release tag does not select the exact version in `Cargo.toml`

openspec/changes/rust-binary-distribution/tasks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
- [x] 4.3 Push `main`, wait for every native CI job to pass, then make the repository public and enable immutable releases; capture both GitHub API results as the pre-tag receipt.
2929
- [ ] 4.4 Protect `refs/tags/v*` with an active organization-administrator-only creation/update/deletion ruleset; require a commit-bound `SNO_RELEASE_AUTHORIZED_SHA` receipt after live repository, immutability, ruleset, remote-main, and CI checks; verify anonymous installers against a one-use public candidate before final publication; and clean up failed candidate or final publication attempts.
3030
- [x] 4.5 From a clean checkout of the reviewed commit, publish crate `0.1.1`, download the registry archive, and require byte-identical SHA-256 against the local package archive.
31-
- [ ] 4.6 Preserve the failed `v0.1.1` attempt without moving its tag, publish the forward-only `0.1.2` crate from the repaired reviewed commit, then verify all seven archives, installers, checksums, manifests, and available attestations from the immutable `v0.1.2` GitHub Release.
31+
- [ ] 4.6 Preserve the failed `v0.1.1` and `v0.1.2` attempts without moving their tags, publish the forward-only `0.1.3` crate from the repaired reviewed commit, then verify all seven archives, installers, checksums, manifests, and available attestations from the immutable `v0.1.3` GitHub Release.
3232
- [ ] 4.7 Record reviewed commit, tag commit, local and registry crate hashes, target archive hashes, and workflow run in one release-identity receipt.
3333

3434
## Test Design Gate

scripts/check-release-workflow.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ rg -q 'inputs\.mode.*candidate' "$installer_verify" || fail "shared verifier doe
105105
rg -q 'fb8dbee9f182173e062a64a387b21a0badc6fab8b2abf9294973f012972bf6d8' "$sbom" || fail "SBOM generator hash is not repository-pinned"
106106
[[ "$(rg -c 'expected="[0-9a-f]{64}"' "$bootstrap")" -eq 5 ]] || fail "cargo-dist host hashes are incomplete"
107107
rg -q 'shasum -a 256' "$bootstrap" || fail "macOS-compatible cargo-dist hash verification is missing"
108+
rg -q 'unzip -q' "$bootstrap" || fail "Windows-compatible cargo-dist ZIP extraction is missing"
108109
rg -q 'vars\.SNO_RELEASE_AUTHORIZED_SHA' "$preflight" || fail "preflight does not consume the commit-bound administrator authorization receipt"
109110
rg -Fq 'test "${RELEASE_AUTHORIZED_SHA}" = "${GITHUB_SHA}"' "$preflight" || fail "preflight does not bind administrator authorization to the release commit"
110111
if rg -q 'repos/.*immutable-releases' "$preflight"; then

0 commit comments

Comments
 (0)