diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index c1ab14c8..cc0baab6 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -187,5 +187,31 @@ jobs: with: prerelease: ${{ !startsWith(github.ref, 'refs/tags/') }} generate_release_notes: true + # Prepended to the generated changelog. Keep in sync with + # docs/quickstart.mdx "Verify a downloaded release". + body: | + ## Verify this release + + After downloading your platform archive from this release: + + ```bash + # Example for linux-x86_64 — set ARCHIVE to the asset you downloaded. + TARGET=linux-x86_64 + ARCHIVE=strix-VERSION-${TARGET}.tar.gz # VERSION without the leading v + + curl -fsSLO "https://github.com/usestrix/strix/releases/download/${{ github.ref_name }}/SHA256SUMS" + curl -fsSLO "https://github.com/usestrix/strix/releases/download/${{ github.ref_name }}/strix-${TARGET}.intoto.jsonl" + + sha256sum -c --ignore-missing SHA256SUMS + + gh attestation verify "${ARCHIVE}" \ + --repo usestrix/strix \ + --bundle "strix-${TARGET}.intoto.jsonl" \ + --signer-workflow usestrix/strix/.github/workflows/build-release.yml \ + --predicate-type https://slsa.dev/provenance/v1 \ + --deny-self-hosted-runners + ``` + + Full instructions (including `cosign`): https://docs.strix.ai/quickstart#verify-a-downloaded-release # Includes SHA256SUMS and *.intoto.jsonl provenance bundles. files: release/** diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx index dcd2e7c5..b0349dd3 100644 --- a/docs/quickstart.mdx +++ b/docs/quickstart.mdx @@ -15,6 +15,13 @@ description: "Install Strix and run your first security scan" ```bash curl -sSL https://strix.ai/install | bash ``` + + The installer downloads the release archive, checks `SHA256SUMS`, then verifies + Sigstore provenance before extracting. To skip those checks (not recommended): + + ```bash + STRIX_INSTALL_SKIP_VERIFY=1 curl -sSL https://strix.ai/install | bash + ``` ```bash @@ -23,6 +30,44 @@ description: "Install Strix and run your first security scan" +## Verify a downloaded release + +If you download assets from GitHub Releases yourself: + +```bash +# Replace VERSION and TARGET (e.g. 1.6.2 and linux-x86_64). +VERSION=1.6.2 +TARGET=linux-x86_64 +ARCHIVE="strix-${VERSION}-${TARGET}.tar.gz" + +curl -fsSLO "https://github.com/usestrix/strix/releases/download/v${VERSION}/${ARCHIVE}" +curl -fsSLO "https://github.com/usestrix/strix/releases/download/v${VERSION}/SHA256SUMS" +curl -fsSLO "https://github.com/usestrix/strix/releases/download/v${VERSION}/strix-${TARGET}.intoto.jsonl" + +# 1) Integrity +sha256sum -c --ignore-missing SHA256SUMS + +# 2) Provenance (GitHub CLI) +gh attestation verify "${ARCHIVE}" \ + --repo usestrix/strix \ + --bundle "strix-${TARGET}.intoto.jsonl" \ + --signer-workflow usestrix/strix/.github/workflows/build-release.yml \ + --predicate-type https://slsa.dev/provenance/v1 \ + --deny-self-hosted-runners +``` + +With `cosign` instead of `gh`: + +```bash +cosign verify-blob-attestation \ + --bundle "strix-${TARGET}.intoto.jsonl" \ + --new-bundle-format \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-identity-regexp '^https://github.com/usestrix/strix/.github/workflows/build-release.yml' \ + --type slsaprovenance1 \ + "${ARCHIVE}" +``` + ## Configuration Set your LLM provider: diff --git a/tests/test_build_release_workflow.py b/tests/test_build_release_workflow.py index 4ef3ed0d..ec02d625 100644 --- a/tests/test_build_release_workflow.py +++ b/tests/test_build_release_workflow.py @@ -165,6 +165,17 @@ def test_sha256sums_script_hashes_product_files_only(tmp_path: Path) -> None: assert digest == expected +def test_release_notes_include_manual_verification() -> None: + create = _step_named("release", "Create Release") + body = str(create["with"]["body"]) + assert "## Verify this release" in body + assert "sha256sum -c --ignore-missing SHA256SUMS" in body + assert "gh attestation verify" in body + assert "usestrix/strix/.github/workflows/build-release.yml" in body + assert "docs.strix.ai/quickstart#verify-a-downloaded-release" in body + assert create["with"]["generate_release_notes"] is True + + @pytest.mark.parametrize( ("job_name", "step_name"), [