From 2ced53bab8087e77bbd25814d8dff30d7cb937da Mon Sep 17 00:00:00 2001 From: konojunya Date: Sat, 5 Sep 2026 12:35:26 +0900 Subject: [PATCH] Mark GitHub release channel available --- README.md | 8 ++++++-- SECURITY.md | 2 +- distribution/distribution-contract.json | 14 +++++++------- docs/distribution.md | 16 ++++++++-------- scripts/distribution-contract.test.mjs | 13 ++++++++++--- scripts/validate-distribution-contract.mjs | 12 +++++++++--- 6 files changed, 41 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index f1d32da..c14e5d7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,11 @@ `stack-sh/cli` is the open-source native Rust `stack` command for Stack architecture diagrams. -The repository contains native validation, formatting, and rendering commands. The interface remains pre-release and no supported binary distribution is published yet. The planned 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.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. Homebrew, Cargo, Aqua, and self-update are not available yet. 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 + +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. ## Commands @@ -79,4 +83,4 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a change. Please report ## Licensing -Repository-authored work is licensed under the [Apache License 2.0](./LICENSE) for personal and commercial use. Runtime and build dependency licenses are recorded in [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md). A future binary release must ship the applicable license and notice files described there. +Repository-authored work is licensed under the [Apache License 2.0](./LICENSE) for personal and commercial use. Runtime and build dependency licenses are recorded in [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md). Every published binary archive ships the applicable license and notice files described there. diff --git a/SECURITY.md b/SECURITY.md index a411107..316cb09 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Supported versions -Stack CLI is pre-release. Security fixes are applied to the latest revision on `main`; no released binary version is currently supported. +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). ## Reporting a vulnerability diff --git a/distribution/distribution-contract.json b/distribution/distribution-contract.json index e3ae738..74205da 100644 --- a/distribution/distribution-contract.json +++ b/distribution/distribution-contract.json @@ -10,8 +10,8 @@ "minimumRustVersion": "1.85" }, "availability": { - "state": "planned", - "message": "No supported binary or package-manager release is currently published. A channel becomes available only after its required verification passes for a stable release." + "state": "available", + "message": "Stack CLI 0.3.0 is available from GitHub Releases. Homebrew, Cargo, Aqua, and self-update remain planned." }, "versioning": { "scheme": "Semantic Versioning", @@ -55,7 +55,7 @@ "libc": "system", "minimumRuntime": "macOS 13", "supportTier": "tier-1", - "state": "planned" + "state": "available" }, { "target": "x86_64-apple-darwin", @@ -64,7 +64,7 @@ "libc": "system", "minimumRuntime": "macOS 13", "supportTier": "tier-1", - "state": "planned" + "state": "available" }, { "target": "aarch64-unknown-linux-gnu", @@ -73,7 +73,7 @@ "libc": "glibc", "minimumRuntime": "glibc 2.31", "supportTier": "tier-1", - "state": "planned" + "state": "available" }, { "target": "x86_64-unknown-linux-gnu", @@ -82,7 +82,7 @@ "libc": "glibc", "minimumRuntime": "glibc 2.31", "supportTier": "tier-1", - "state": "planned" + "state": "available" } ], "unsupported": [ @@ -106,7 +106,7 @@ "channels": [ { "id": "github-release", - "state": "planned", + "state": "available", "targets": [ "aarch64-apple-darwin", "x86_64-apple-darwin", diff --git a/docs/distribution.md b/docs/distribution.md index cc83f6e..d20bdda 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). -No supported binary or package-manager release is published yet. Every target and channel below is **planned**, not currently available. A stable release changes availability only after its complete matrix passes the activation checks in this document. +[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. Homebrew, Cargo, Aqua, and self-update remain **planned** and have no supported install command yet. ## Supported platform matrix @@ -10,10 +10,10 @@ The first supported binary matrix is intentionally narrow: | Rust target | OS | Architecture | Runtime floor | Direct | Homebrew | Cargo | Aqua | Self-update | | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| `aarch64-apple-darwin` | macOS | arm64 | macOS 13 | planned | planned | planned | planned | planned | -| `x86_64-apple-darwin` | macOS | x86_64 | macOS 13 | planned | — | planned | planned | planned | -| `aarch64-unknown-linux-gnu` | Linux | arm64 | glibc 2.31 | planned | planned | planned | planned | planned | -| `x86_64-unknown-linux-gnu` | Linux | x86_64 | glibc 2.31 | planned | planned | planned | planned | planned | +| `aarch64-apple-darwin` | macOS | arm64 | macOS 13 | available | planned | planned | planned | planned | +| `x86_64-apple-darwin` | macOS | x86_64 | macOS 13 | available | — | planned | planned | planned | +| `aarch64-unknown-linux-gnu` | Linux | arm64 | glibc 2.31 | available | planned | planned | planned | planned | +| `x86_64-unknown-linux-gnu` | Linux | x86_64 | glibc 2.31 | available | planned | planned | planned | planned | Windows, musl-based Linux distributions such as Alpine, BSD, and 32-bit architectures are not supported release targets. A source build may happen to work elsewhere, but it is best-effort and does not block a release. Cargo installs on supported targets require Rust 1.85 or newer. Homebrew availability additionally follows [Homebrew's current tier-1 host requirements](https://docs.brew.sh/Support-Tiers); Stack does not label a host as supported when the package manager itself classifies it below tier 1. @@ -60,12 +60,12 @@ The release manifest records the tag, commit, source version, `minimumSupportedC ## Direct installation -After a GitHub Release is marked available, select the archive whose target matches the supported platform table and download it together with all matching verification material. Complete the [supply-chain verification](./supply-chain.md), then extract and install the verified binary. For example, replace `{version}` and `{target}` with the exact release values: +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: ```sh -tar -xzf "stack-v{version}-{target}.tar.gz" +tar -xzf "stack-v0.3.0-{target}.tar.gz" mkdir -p "$HOME/.local/bin" -install -m 0755 "stack-v{version}-{target}/stack" "$HOME/.local/bin/stack" +install -m 0755 "stack-v0.3.0-{target}/stack" "$HOME/.local/bin/stack" "$HOME/.local/bin/stack" --version ``` diff --git a/scripts/distribution-contract.test.mjs b/scripts/distribution-contract.test.mjs index bf16959..99cf2ea 100644 --- a/scripts/distribution-contract.test.mjs +++ b/scripts/distribution-contract.test.mjs @@ -59,9 +59,16 @@ test("package-manager ownership cannot be delegated to self-update", () => { assert.throws(() => validateDistributionContract(candidate, cargoToml), /must own upgrades/); }); -test("a distribution cannot be marked available before release verification", () => { +test("the GitHub release cannot be activated with a planned target", () => { const candidate = changed((value) => { - value.availability.state = "available"; + value.targets[0].state = "planned"; }); - assert.throws(() => validateDistributionContract(candidate, cargoToml), /must remain planned/); + assert.throws(() => validateDistributionContract(candidate, cargoToml), /must be available after release verification/); +}); + +test("package-manager channels remain planned after direct release activation", () => { + const candidate = changed((value) => { + value.channels.find(({ id }) => id === "homebrew").state = "available"; + }); + assert.throws(() => validateDistributionContract(candidate, cargoToml), /homebrew state must be planned/); }); diff --git a/scripts/validate-distribution-contract.mjs b/scripts/validate-distribution-contract.mjs index 0abba73..51dbbdb 100644 --- a/scripts/validate-distribution-contract.mjs +++ b/scripts/validate-distribution-contract.mjs @@ -52,7 +52,12 @@ export function validateDistributionContract(contract, cargoToml) { "sourceCargoPackage must match Cargo.toml", ); invariant(contract.product?.publishedCargoPackage === null, "published Cargo package must remain unset before registry ownership is verified"); - invariant(contract.availability?.state === "planned", "distribution must remain planned until a verified stable release exists"); + 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("GitHub Releases"), + "availability message must identify the verified stable GitHub release", + ); invariant( contract.product.currentSourceVersion === cargoValue(cargoToml, "version"), "currentSourceVersion must match Cargo.toml", @@ -75,7 +80,7 @@ export function validateDistributionContract(contract, cargoToml) { `${target.target} has inconsistent OS, architecture, or libc metadata`, ); invariant(target.supportTier === "tier-1", `${target.target} must be tier-1`); - invariant(target.state === "planned", `${target.target} must remain planned before release`); + invariant(target.state === "available", `${target.target} must be available after release verification`); invariant(target.minimumRuntime, `${target.target} must declare a runtime floor`); if (target.os === "linux") invariant(target.libc === "glibc", `${target.target} must use glibc`); if (target.os === "macos") invariant(target.libc === "system", `${target.target} must use the system libc`); @@ -89,7 +94,8 @@ export function validateDistributionContract(contract, cargoToml) { ); const targetIds = new Set(expectedTargets); for (const channel of contract.channels) { - invariant(channel.state === "planned", `${channel.id} must remain planned before release`); + const expectedState = channel.id === "github-release" ? "available" : "planned"; + invariant(channel.state === expectedState, `${channel.id} state must be ${expectedState}`); uniqueSorted(channel.targets, `${channel.id} targets`); for (const target of channel.targets) { invariant(targetIds.has(target), `${channel.id} references unknown target ${target}`);