Skip to content

Commit 4db6258

Browse files
committed
Grant draft verification push access
1 parent 9b43733 commit 4db6258

13 files changed

Lines changed: 42 additions & 21 deletions

File tree

.github/workflows/release-draft-installer-smoke.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ permissions:
1717

1818
jobs:
1919
verify:
20+
permissions:
21+
contents: write
2022
uses: ./.github/workflows/release-installer-verify.yml
2123
with:
2224
mode: draft

.github/workflows/release-installer-verify.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ on:
1818
default: ""
1919
type: string
2020

21-
permissions:
22-
contents: read
23-
2421
jobs:
2522
installer:
2623
name: ${{ inputs.mode }} installer (${{ matrix.name }})

.github/workflows/release.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ jobs:
340340
needs:
341341
- plan
342342
- host
343+
permissions:
344+
contents: write
343345
uses: ./.github/workflows/release-draft-installer-smoke.yml
344346
with:
345347
plan: ${{ needs.plan.outputs.val }}

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.5"
3+
version = "0.1.6"
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`. Versions `0.1.1` through `0.1.4` preserved that implementation on crates.io, but their GitHub workflows failed closed before public artifact hosting. Version `0.1.5` 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` through `0.1.5` preserved that implementation on crates.io, but their GitHub workflows failed closed before public artifact hosting. Version `0.1.6` 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.5` 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.6` 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` through `0.1.4` are public under `SnoInfo`; GitHub repository `sno-ai/sno-cli` is public with immutable releases enabled; no GitHub binary release exists yet. Versions `0.1.1` through `0.1.3` stopped before draft hosting; `0.1.4` created a draft after every build, archive, software-bill-of-materials, and staged-installer check passed, then failed closed because tag-based draft download is unsupported. Cleanup deleted the draft, and every version tag remains fixed.
34+
- Current release state on 2026-07-15 PDT: crates.io packages `sno` `0.1.0` through `0.1.5` are public under `SnoInfo`; GitHub repository `sno-ai/sno-cli` is public with immutable releases enabled; no GitHub binary release exists yet. Versions `0.1.1` through `0.1.3` stopped before draft hosting. Version `0.1.4` failed closed because tag-based draft download is unsupported. Version `0.1.5` passed all builds, archive checks, software-bill-of-materials generation, and staged installers, then its five draft installer jobs received HTTP 403 because the nested workflow chain had only read access to unpublished assets. Cleanup deleted each draft, and every version 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.5` 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.6` 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.5`, owned by company account `SnoInfo`; `0.1.0` through the registry-only `0.1.4` remain valid published predecessors.
81+
- crates.io: `sno` `0.1.6`, owned by company account `SnoInfo`; `0.1.0` through the registry-only `0.1.5` 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.5` 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.6` 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.5` is already authorized after its gates pass.
231+
- Before publishing if the reviewed package scope or settled release contract changes; forward-only `0.1.6` 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.5` 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.6` 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. 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. Version `0.1.3` passed all seven builds but failed closed before hosting when strict platform-specific checksum parsers rejected cargo-dist's valid trailing blank line. Version `0.1.4` passed the corrected builds, archive checks, software bill of materials, and staged installers, created a draft, then failed closed because GitHub CLI cannot download an unpublished draft by tag; cleanup deleted the draft. All tags remain fixed at their reviewed commits. The forward-only recovery is `0.1.5`: the workflow carries the exact numeric draft release ID through authenticated download, candidate copying, publication, and cleanup.
42+
Version `0.1.0` is already immutable on crates.io and cannot be republished. Version `0.1.1` failed closed before builds because a standard workflow token cannot read the administration-only immutable-release setting. Version `0.1.2` failed during cross-platform cargo-dist bootstrap. Version `0.1.3` failed during strict checksum parsing. Version `0.1.4` passed builds and staged checks, then failed because GitHub CLI cannot download an unpublished draft by tag. Version `0.1.5` carried the exact numeric draft ID and again passed every pre-draft check, but the nested draft-verification workflow received only read access and GitHub denied unpublished-asset access with HTTP 403. Cleanup deleted every draft. All tags remain fixed at their reviewed commits. The forward-only recovery is `0.1.6`: only the nested draft-download call chain receives `contents: write`; staged, candidate, and public installer verification remain read-only.
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.5`; download the registry archive and require its SHA-256 to match the local package archive.
81-
7. Create tag `v0.1.5` 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 by its exact numeric release ID, anonymously tests the same bytes through a one-use public candidate, deletes that candidate, and publishes the final draft by that ID. 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.6`; download the registry archive and require its SHA-256 to match the local package archive.
81+
7. Create tag `v0.1.6` 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 by its exact numeric release ID, anonymously tests the same bytes through a one-use public candidate, deletes that candidate, and publishes the final draft by that ID. 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 | 33 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 | 35 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 17 release-workflow security mutations fail.
31+
- `scripts/test-release-workflow-policy.sh` -> proves 19 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.5` after the `0.1.1` workflow failed closed before artifact creation, `0.1.2` failed during cross-platform bootstrap, `0.1.3` failed during checksum-file parsing, and `0.1.4` deleted its draft after tag-based draft download failed. 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` through `v0.1.4` tags MUST NOT be moved.
40+
The production binary release SHALL use forward-only version `0.1.6` after versions `0.1.1` through `0.1.5` failed closed at successive release gates. 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. Only the nested draft-asset verification chain SHALL receive `contents: write`; staged, candidate, and public verification SHALL remain read-only. The existing `v0.1.1` through `v0.1.5` 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`

0 commit comments

Comments
 (0)