From 2431aee1eb73acdb96bb94cbfd5f2ec87fb1971a Mon Sep 17 00:00:00 2001 From: konojunya Date: Sat, 5 Sep 2026 18:20:06 +0900 Subject: [PATCH] Activate v0.4.0 distribution channels --- .github/workflows/ci.yaml | 7 ++++++- README.md | 8 ++++---- SECURITY.md | 2 +- aqua/README.md | 2 +- distribution/distribution-contract.json | 2 +- docs/completions.md | 2 +- docs/distribution.md | 20 ++++++++++---------- docs/self-update.md | 2 +- scripts/aqua-registry.test.mjs | 7 ++++++- scripts/distribution-contract.test.mjs | 13 +++++++++++++ scripts/validate-distribution-contract.mjs | 5 +++-- tests/aqua/aqua-checksums.json | 16 ++++++++-------- tests/aqua/aqua.yaml | 2 +- 13 files changed, 56 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b73b782..4719894 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -57,11 +57,16 @@ jobs: smoke_directory="$RUNNER_TEMP/aqua-smoke" mkdir -p "$smoke_directory" AQUA_ROOT_DIR="$native_root" aqua install - "$native_root/bin/stack" --version + expected_version=$(node -e 'process.stdout.write(JSON.parse(require("fs").readFileSync("distribution/distribution-contract.json", "utf8")).product.currentSourceVersion)') + test "$("$native_root/bin/stack" --version)" = "stack $expected_version" "$native_root/bin/stack" init -o "$smoke_directory/diagram.stack" "$native_root/bin/stack" check "$smoke_directory/diagram.stack" "$native_root/bin/stack" render "$smoke_directory/diagram.stack" -o "$smoke_directory/diagram.svg" test -s "$smoke_directory/diagram.svg" + "$native_root/bin/stack" completions bash | cmp distribution/generated/share/bash-completion/completions/stack - + "$native_root/bin/stack" completions zsh | cmp distribution/generated/share/zsh/site-functions/_stack - + "$native_root/bin/stack" completions fish | cmp distribution/generated/share/fish/vendor_completions.d/stack.fish - + "$native_root/bin/stack" manpage | cmp distribution/generated/share/man/man1/stack.1 - - name: Validate release supply chain run: | node --check scripts/create-supply-chain-smoke-fixture.mjs diff --git a/README.md b/README.md index dc30187..15d307c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ `stack-sh/cli` is the open-source native Rust `stack` command for Stack architecture diagrams. -The repository contains native validation, formatting, and rendering commands. [Stack CLI 0.3.0](https://github.com/stack-sh/cli/releases/tag/v0.3.0) is the first supported native binary release for macOS 13 or newer and glibc-based Linux 2.31 or newer, on arm64 and x86_64. GitHub Releases, Homebrew, and the owner-maintained Aqua registry are available; Cargo and self-update are still planned. The target matrix, artifact names, verification material, channel ownership, and rollback rules are defined by the [distribution contract](./docs/distribution.md), with signing and verification procedures in the [supply-chain guide](./docs/supply-chain.md). +The repository contains native validation, formatting, and rendering commands. [Stack CLI 0.4.0](https://github.com/stack-sh/cli/releases/tag/v0.4.0) is the supported native binary release for macOS 13 or newer and glibc-based Linux 2.31 or newer, on arm64 and x86_64. GitHub Releases, Homebrew, and the owner-maintained Aqua registry are available; Cargo and self-update are still planned. The target matrix, artifact names, verification material, channel ownership, and rollback rules are defined by the [distribution contract](./docs/distribution.md), with signing and verification procedures in the [supply-chain guide](./docs/supply-chain.md). ## Install @@ -21,7 +21,7 @@ aqua install stack --version ``` -For a direct installation, download the archive for your target and its verification material from [GitHub Releases](https://github.com/stack-sh/cli/releases/tag/v0.3.0). Verify the checksum signature and both attestations by following the [supply-chain guide](./docs/supply-chain.md), then follow the [direct installation steps](./docs/distribution.md#direct-installation). The macOS artifacts are reproducibly ad-hoc signed, not Apple-notarized; Sigstore and GitHub attestations provide the publisher-identity check. +For a direct installation, download the archive for your target and its verification material from [GitHub Releases](https://github.com/stack-sh/cli/releases/tag/v0.4.0). Verify the checksum signature and both attestations by following the [supply-chain guide](./docs/supply-chain.md), then follow the [direct installation steps](./docs/distribution.md#direct-installation). The macOS artifacts are reproducibly ad-hoc signed, not Apple-notarized; Sigstore and GitHub attestations provide the publisher-identity check. ## Commands @@ -61,9 +61,9 @@ stack manpage `stack lsp` runs a native [Language Server Protocol 3.18 adapter](./docs/language-server.md) over standard input and output. It provides incremental document synchronization, versioned diagnostics, completion, hover, hierarchical document symbols, and whole-document formatting for `.stack` files. The adapter negotiates UTF-8, UTF-16, or UTF-32 positions and delegates language semantics and formatting to the pinned compiler and engine rather than reimplementing them. Standard output is reserved for framed JSON-RPC messages. -`stack update` is implemented for future receipted direct installations, with `--check`, exact-version selection, authenticated release-manifest and archive verification, and rollback-aware atomic replacement. It refuses Homebrew, Aqua, Cargo, and unknown ownership. The published 0.3.0 binary does not contain this command and its manual installation has no receipt, so the self-update channel remains planned. See the [self-update contract](./docs/self-update.md). +`stack update` is included in 0.4.0 for future receipted direct installations, with `--check`, exact-version selection, authenticated release-manifest and archive verification, and rollback-aware atomic replacement. It refuses Homebrew, Aqua, Cargo, and unknown ownership. The 0.4.0 release manifest does not activate `self-update`, and the documented manual installation creates no receipt, so the channel remains planned. See the [self-update contract](./docs/self-update.md). -`stack completions ` and `stack manpage` generate deterministic shell integration and an offline roff manual from the CLI command metadata. Future release archives carry the exact generated files; Homebrew installs them into its managed completion and manual paths, while direct, Aqua, and future Cargo users can generate them into user-owned locations without modifying shell startup files. See the [completion and manual guide](./docs/completions.md). +`stack completions ` and `stack manpage` generate deterministic shell integration and an offline roff manual from the CLI command metadata. The 0.4.0 release archives carry the exact generated files; Homebrew installs them into its managed completion and manual paths, while direct, Aqua, and future Cargo users can generate them into user-owned locations without modifying shell startup files. See the [completion and manual guide](./docs/completions.md). `stack icons list [PROVIDER] [QUERY]` searches the asset-free catalog by ID, product name, or category. The catalog currently contains 1,051 IDs: 305 AWS, 45 Google Cloud, 639 Azure, and 62 curated developer and collaboration tool icons. This command reads only metadata embedded in the CLI. diff --git a/SECURITY.md b/SECURITY.md index 316cb09..fb384b7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Supported versions -Stack CLI 0.3.0 is the supported stable binary release. Before 1.0, only the latest stable release receives release support; `main` is an unreleased development revision. Download supported binaries and their verification material from the [v0.3.0 GitHub Release](https://github.com/stack-sh/cli/releases/tag/v0.3.0). +Stack CLI 0.4.0 is the supported stable binary release. Before 1.0, only the latest stable release receives release support; `main` is an unreleased development revision. Download supported binaries and their verification material from the [v0.4.0 GitHub Release](https://github.com/stack-sh/cli/releases/tag/v0.4.0). ## Reporting a vulnerability diff --git a/aqua/README.md b/aqua/README.md index 32d2d58..54faaba 100644 --- a/aqua/README.md +++ b/aqua/README.md @@ -22,7 +22,7 @@ done `aqua update` must leave the pinned fixture unchanged until a newer stable release exists. `aqua update-checksum` must then reproduce `tests/aqua/aqua-checksums.json` exactly. The file locks all four release archives to the SHA-256 values obtained from the release checksum asset after Aqua verifies its Sigstore bundle. -On the native host, repeat without `--test` in an isolated `AQUA_ROOT_DIR`, then run `stack --version`, `stack init`, `stack check`, and `stack render`. +On the native host, repeat without `--test` in an isolated `AQUA_ROOT_DIR`, then run `stack --version`, `stack init`, `stack check`, and `stack render`. Generate bash, zsh, and fish completions plus the manual and compare every byte with the tracked release assets. ## Publish an update diff --git a/distribution/distribution-contract.json b/distribution/distribution-contract.json index 95ffb3c..ae20275 100644 --- a/distribution/distribution-contract.json +++ b/distribution/distribution-contract.json @@ -11,7 +11,7 @@ }, "availability": { "state": "available", - "message": "Stack CLI 0.3.0 is available from GitHub Releases, Homebrew, and the owner-maintained Aqua registry. Cargo and self-update remain planned." + "message": "Stack CLI 0.4.0 is available from GitHub Releases, Homebrew, and the owner-maintained Aqua registry. Cargo and self-update remain planned." }, "versioning": { "scheme": "Semantic Versioning", diff --git a/docs/completions.md b/docs/completions.md index ab03fe3..64eaf52 100644 --- a/docs/completions.md +++ b/docs/completions.md @@ -18,7 +18,7 @@ The published release archive stores the exact same bytes at these paths: | fish | `share/fish/vendor_completions.d/stack.fish` | | manual | `share/man/man1/stack.1` | -The source tree after Stack CLI 0.3.0 contains these commands and assets. The immutable 0.3.0 archives predate them; do not infer that an older installed binary can generate them. +Stack CLI 0.4.0 is the first published release containing these commands and assets. Older installed binaries cannot generate them. ## Homebrew diff --git a/docs/distribution.md b/docs/distribution.md index bcaca06..f29b8fe 100644 --- a/docs/distribution.md +++ b/docs/distribution.md @@ -2,7 +2,7 @@ This document defines the shared release contract for the Stack CLI. It is normative for GitHub Releases, Homebrew, Cargo, Aqua, and `stack` self-update implementations. The machine-readable source is [`distribution/distribution-contract.json`](../distribution/distribution-contract.json). -[Stack CLI 0.3.0](https://github.com/stack-sh/cli/releases/tag/v0.3.0) is available as a supported GitHub Release for every target below, through the owner-maintained Homebrew tap for the hosts marked below, and through the checksum-locked owner Aqua registry. Cargo and self-update remain **planned** and have no supported install command yet. +[Stack CLI 0.4.0](https://github.com/stack-sh/cli/releases/tag/v0.4.0) is available as a supported GitHub Release for every target below, through the owner-maintained Homebrew tap for the hosts marked below, and through the checksum-locked owner Aqua registry. Cargo and self-update remain **planned** and have no supported install command yet. ## Supported platform matrix @@ -81,7 +81,7 @@ brew uninstall stack-sh/tap/stack For releases carrying the generated assets, the formula installs bash, zsh, and fish completions plus `stack.1` through Homebrew's standard path helpers. It does not edit shell startup files. The formula does not remove or replace Stack configuration and icon stores during an upgrade or uninstall. Formula updates verify release checksums, provenance, and SBOM attestations before changing the archive mapping. The fail-closed update and recovery procedure is maintained in the tap's [maintainer guide](https://github.com/stack-sh/homebrew-tap/blob/main/docs/maintaining.md). -Homebrew was activated after the immutable `v0.3.0` release assets were published. The release manifest therefore remains the publication-time record, while this contract and the tap CI record the later channel activation; release assets are not replaced to retrofit that state. +The Homebrew v0.4.0 formula was activated after the immutable release assets were published. Its macOS ARM64, Linux ARM64, and Linux x86_64 lifecycle tests verify the archived completion and manual bytes during install, upgrade, and uninstall. The release manifest remains the publication-time record with only `github-release` in `verifiedChannels`; this contract and the tap CI record the later channel verification without replacing any release asset. ## Aqua installation @@ -101,7 +101,7 @@ registries: ref: 42702cda91a4156901b9a601bd143c43dcf05766 path: aqua/registry.yaml packages: - - name: stack-sh/cli@v0.3.0 + - name: stack-sh/cli@v0.4.0 registry: stack-sh ``` @@ -132,24 +132,24 @@ stack --version Commit `aqua-checksums.json` with the configuration. To upgrade after a new stable Stack release, run `aqua update`, review the version change, then run `aqua update-checksum` and `aqua install`. Aqua owns the replacement; `stack` self-update must refuse to overwrite it. The registry maintainer procedure and four-target test command are in [`aqua/README.md`](../aqua/README.md). -Aqua installs the executable declared by its registry mapping and does not own shell startup files or a global manual database. On a release that includes the generator, use `stack completions` and `stack manpage` to write the desired user-owned files as documented in the [completion guide](./completions.md). +Aqua installs the executable declared by its registry mapping and does not own shell startup files or a global manual database. Stack CLI 0.4.0 includes the generators; use `stack completions` and `stack manpage` to write the desired user-owned files as documented in the [completion guide](./completions.md). -Aqua was activated after the immutable `v0.3.0` release assets were published. The release manifest remains the publication-time record; the pinned registry commit, generated checksum lock, contract, and CI runs are the later activation evidence. No release asset is replaced. +The Aqua v0.4.0 pin was activated after the immutable release assets were published. CI verifies all four target mappings without executing foreign binaries, then installs the native archive and compares all completion and manual generator bytes. The release manifest remains the publication-time record; the pinned registry commit, generated checksum lock, contract, and CI runs are the later verification evidence. No release asset is replaced. ## Direct installation -Download [Stack CLI 0.3.0](https://github.com/stack-sh/cli/releases/tag/v0.3.0), select the archive whose target matches the supported platform table, and obtain all matching verification material. Complete the [supply-chain verification](./supply-chain.md), then extract and install the verified binary. Replace `{target}` with the exact release target: +Download [Stack CLI 0.4.0](https://github.com/stack-sh/cli/releases/tag/v0.4.0), select the archive whose target matches the supported platform table, and obtain all matching verification material. Complete the [supply-chain verification](./supply-chain.md), then extract and install the verified binary. Replace `{target}` with the exact release target: ```sh -tar -xzf "stack-v0.3.0-{target}.tar.gz" +tar -xzf "stack-v0.4.0-{target}.tar.gz" mkdir -p "$HOME/.local/bin" -install -m 0755 "stack-v0.3.0-{target}/stack" "$HOME/.local/bin/stack" +install -m 0755 "stack-v0.4.0-{target}/stack" "$HOME/.local/bin/stack" "$HOME/.local/bin/stack" --version ``` -Add `$HOME/.local/bin` to `PATH` if it is not already present. This manual installation has no self-update receipt. The source tree after 0.3.0 contains `stack update`, but the published 0.3.0 binary does not, and this installation cannot be claimed retroactively without risking a package-manager-owned binary. Self-update remains unavailable until a later release and verified direct installer separately activate the channel. The command and receipt contract are documented in the [self-update guide](./self-update.md). +Add `$HOME/.local/bin` to `PATH` if it is not already present. This manual installation has no self-update receipt. Although 0.4.0 contains `stack update`, its release manifest does not activate `self-update`, and an unreceipted binary cannot be claimed retroactively without risking a package-manager-owned installation. Self-update remains unavailable until a later release and verified direct installer separately activate the channel. The command and receipt contract are documented in the [self-update guide](./self-update.md). -On a future archive that carries completion and manual assets, either copy the verified `share/` files into the matching system prefix or use the installed binary to generate user-owned files following the [completion guide](./completions.md). Do not copy these files from a different Stack version; CI and release verification require them to match the binary's command definition. +The 0.4.0 archive carries completion and manual assets. Either copy its verified `share/` files into the matching system prefix or use the installed binary to generate user-owned files following the [completion guide](./completions.md). Do not copy these files from a different Stack version; CI and release verification require them to match the binary's command definition. ## Channel ownership diff --git a/docs/self-update.md b/docs/self-update.md index 30a89e9..a295d75 100644 --- a/docs/self-update.md +++ b/docs/self-update.md @@ -2,7 +2,7 @@ `stack update` updates only a direct GitHub Release installation that has a matching Stack installation receipt. It never claims an unreceipted binary and never replaces an installation owned by Homebrew, Aqua, Cargo, or an unknown installer. -The command is implemented in the source tree after Stack CLI 0.3.0. The published 0.3.0 binary does not contain it, and the documented 0.3.0 manual installation does not create a receipt. The self-update channel therefore remains **planned** until a later release both activates `self-update` in its authenticated release manifest and has a verified direct installer that creates the receipt. Do not describe 0.3.0 as self-updatable. +The command is included in Stack CLI 0.4.0, but that release's authenticated manifest lists only `github-release`, and the documented manual installation does not create a receipt. The self-update channel therefore remains **planned** until a later release both activates `self-update` in its authenticated release manifest and has a verified direct installer that creates the receipt. Do not describe 0.4.0 as self-updatable. ## Commands diff --git a/scripts/aqua-registry.test.mjs b/scripts/aqua-registry.test.mjs index 88169f5..1bcccc6 100644 --- a/scripts/aqua-registry.test.mjs +++ b/scripts/aqua-registry.test.mjs @@ -9,9 +9,13 @@ const configuration = fs.readFileSync(path.join(root, "tests/aqua/aqua.yaml"), " const policy = fs.readFileSync(path.join(root, "tests/aqua/aqua-policy.yaml"), "utf8"); const registry = fs.readFileSync(path.join(root, "aqua/registry.yaml"), "utf8"); const distribution = fs.readFileSync(path.join(root, "docs/distribution.md"), "utf8"); +const distributionContract = JSON.parse( + fs.readFileSync(path.join(root, "distribution/distribution-contract.json"), "utf8"), +); const checksums = JSON.parse( fs.readFileSync(path.join(root, "tests/aqua/aqua-checksums.json"), "utf8"), ); +const releaseVersion = `v${distributionContract.product.currentSourceVersion}`; const targets = [ "aarch64-apple-darwin", @@ -44,9 +48,10 @@ test("the registry maps exactly the four supported release targets", () => { test("the checksum lock covers every archive and the registry revision", () => { const revision = configuration.match(/^\s+ref: ([0-9a-f]{40})$/m)?.[1]; + assert.ok(configuration.includes(`name: stack-sh/cli@${releaseVersion}`)); const expectedIds = targets.map( (target) => - `github_release/github.com/stack-sh/cli/v0.3.0/stack-v0.3.0-${target}.tar.gz`, + `github_release/github.com/stack-sh/cli/${releaseVersion}/stack-${releaseVersion}-${target}.tar.gz`, ); expectedIds.push( `registries/github_content/github.com/stack-sh/cli/${revision}/aqua/registry.yaml`, diff --git a/scripts/distribution-contract.test.mjs b/scripts/distribution-contract.test.mjs index f267248..028c2e8 100644 --- a/scripts/distribution-contract.test.mjs +++ b/scripts/distribution-contract.test.mjs @@ -40,6 +40,19 @@ test("source version drift is rejected", () => { assert.throws(() => validateDistributionContract(candidate, cargoToml), /must match Cargo.toml/); }); +test("a stale stable release in the availability message is rejected", () => { + const candidate = changed((value) => { + value.availability.message = value.availability.message.replace( + `Stack CLI ${value.product.currentSourceVersion}`, + "Stack CLI 0.0.0", + ); + }); + assert.throws( + () => validateDistributionContract(candidate, cargoToml), + /must identify the verified stable GitHub release/, + ); +}); + test("an unverified crates.io package name is rejected", () => { const candidate = changed((value) => { value.product.publishedCargoPackage = "stack-cli"; diff --git a/scripts/validate-distribution-contract.mjs b/scripts/validate-distribution-contract.mjs index 95e1ab7..47817bc 100644 --- a/scripts/validate-distribution-contract.mjs +++ b/scripts/validate-distribution-contract.mjs @@ -59,6 +59,7 @@ function cargoValue(cargoToml, field) { } export function validateDistributionContract(contract, cargoToml) { + const cargoVersion = cargoValue(cargoToml, "version"); invariant(contract.schemaVersion === 1, "schemaVersion must be 1"); invariant(contract.product?.binary === "stack", "binary must be stack"); invariant(contract.product?.sourceCargoPackage === "stack-cli", "source Cargo package must be stack-cli"); @@ -69,14 +70,14 @@ export function validateDistributionContract(contract, cargoToml) { invariant(contract.product?.publishedCargoPackage === null, "published Cargo package must remain unset before registry ownership is verified"); invariant(contract.availability?.state === "available", "distribution must be available after the verified stable release"); invariant( - contract.availability?.message?.includes("Stack CLI 0.3.0") && + contract.availability?.message?.includes(`Stack CLI ${cargoVersion}`) && contract.availability.message.includes("GitHub Releases") && contract.availability.message.includes("Homebrew") && contract.availability.message.includes("Aqua"), "availability message must identify the verified stable GitHub release, Homebrew, and Aqua channels", ); invariant( - contract.product.currentSourceVersion === cargoValue(cargoToml, "version"), + contract.product.currentSourceVersion === cargoVersion, "currentSourceVersion must match Cargo.toml", ); invariant( diff --git a/tests/aqua/aqua-checksums.json b/tests/aqua/aqua-checksums.json index 93385f6..8534447 100644 --- a/tests/aqua/aqua-checksums.json +++ b/tests/aqua/aqua-checksums.json @@ -1,23 +1,23 @@ { "checksums": [ { - "id": "github_release/github.com/stack-sh/cli/v0.3.0/stack-v0.3.0-aarch64-apple-darwin.tar.gz", - "checksum": "10DF35058C9E8438B331B69392F6B9840CBAE3A5278105B0118C3942F62FC356", + "id": "github_release/github.com/stack-sh/cli/v0.4.0/stack-v0.4.0-aarch64-apple-darwin.tar.gz", + "checksum": "DD43CF3D966A3DC28DE3AC8752B6A98F19E4CB7CF6B04652AB73A013800CB015", "algorithm": "sha256" }, { - "id": "github_release/github.com/stack-sh/cli/v0.3.0/stack-v0.3.0-aarch64-unknown-linux-gnu.tar.gz", - "checksum": "2BED2BA5FF4A727646CEDB4EC77AC875E09FC3EDE996A963022D9A97CCDBF7AC", + "id": "github_release/github.com/stack-sh/cli/v0.4.0/stack-v0.4.0-aarch64-unknown-linux-gnu.tar.gz", + "checksum": "A0D76BFA9ED9E767FCD06DBEB7140234DB865440210C7C3ABF6C3DB4F6983A6E", "algorithm": "sha256" }, { - "id": "github_release/github.com/stack-sh/cli/v0.3.0/stack-v0.3.0-x86_64-apple-darwin.tar.gz", - "checksum": "23D8EEA13FF2663E059B7EC91CBC8D6BCA8825380766E87F1718C2DEA217A49F", + "id": "github_release/github.com/stack-sh/cli/v0.4.0/stack-v0.4.0-x86_64-apple-darwin.tar.gz", + "checksum": "48A72328FCF6D160A123A766D9701108F8EE9F633001581DAB533B93DDDF0827", "algorithm": "sha256" }, { - "id": "github_release/github.com/stack-sh/cli/v0.3.0/stack-v0.3.0-x86_64-unknown-linux-gnu.tar.gz", - "checksum": "6C9AB21D96FC6FB0A12A6FF4F7F56103D8DD8513AC85C8D30AB6E072C5C6A7D9", + "id": "github_release/github.com/stack-sh/cli/v0.4.0/stack-v0.4.0-x86_64-unknown-linux-gnu.tar.gz", + "checksum": "89D8A34C0DA5F67932EDFF2641FE0A0527AFBD120CFD5133CB38CDEFFCA55319", "algorithm": "sha256" }, { diff --git a/tests/aqua/aqua.yaml b/tests/aqua/aqua.yaml index 7ae3393..1445d95 100644 --- a/tests/aqua/aqua.yaml +++ b/tests/aqua/aqua.yaml @@ -13,5 +13,5 @@ registries: ref: 42702cda91a4156901b9a601bd143c43dcf05766 path: aqua/registry.yaml packages: - - name: stack-sh/cli@v0.3.0 + - name: stack-sh/cli@v0.4.0 registry: stack-sh