diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70799c4..576114b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ env: HELM_LINUX_AMD64_SHA256: "e9b88b4ee95b18c706839c28d3a0220e5bc470e9cd9262410c90793c45ff8b7c" PROMETHEUS_VERSION: "v3.13.1" PROMETHEUS_LINUX_AMD64_SHA256: "962b812371aff838d152b6ff2d56fdb7a6396f5542f48ebf73421b9721f0d103" - SYFT_VERSION: "v1.46.0" + SYFT_VERSION: "v1.49.0" jobs: build-test-lint: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f3e4240..e6d492d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,8 +15,8 @@ concurrency: env: GO_VERSION: "1.26.5" GORELEASER_VERSION: "v2.17.0" - SYFT_VERSION: "v1.46.0" - COSIGN_VERSION: "v3.0.6" + SYFT_VERSION: "v1.49.0" + COSIGN_VERSION: "v3.1.2" HUB_IMAGE: ghcr.io/ardurai/sith-hub jobs: diff --git a/Makefile b/Makefile index a3e3ae5..53cf7a0 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,7 @@ test: ## Run unit tests with the race detector and report coverage test-scripts: ## Run focused safety tests for operator-facing shell harnesses bash tests/scripts/wails_tooling_policy_test.sh + bash tests/scripts/release_tooling_policy_test.sh bash tests/scripts/helm_tooling_policy_test.sh bash tests/scripts/m0_ocm_falsification_safety_test.sh bash tests/scripts/release_tag_identity_guide_test.sh diff --git a/README.md b/README.md index e485f2d..03d10dc 100644 --- a/README.md +++ b/README.md @@ -768,7 +768,7 @@ Run the full local quality gate with golangci-lint v2.12.2 and govulncheck v1.6. make ci ``` -Release changes additionally require GoReleaser v2.17.0 and Syft v1.46.0. This gate builds all +Release changes additionally require GoReleaser v2.17.0 and Syft v1.49.0. This gate builds all four archives twice and refuses the change if their SHA-256 digests differ: ```bash diff --git a/docs/adr/0009-release-supply-chain.md b/docs/adr/0009-release-supply-chain.md index e27f2e2..822c61b 100644 --- a/docs/adr/0009-release-supply-chain.md +++ b/docs/adr/0009-release-supply-chain.md @@ -26,8 +26,8 @@ long-lived cross-repository credential. 2. CI performs two complete snapshot builds and compares archive SHA-256 digests. It separately verifies checksum coverage, exact archive shape, native `sith version` metadata, and SPDX 2.3 documents. SBOM timestamps and transparency-log signatures are not called reproducible. -3. Syft v1.46.0 creates one SPDX SBOM per archive. The checksum manifest covers both archives and - SBOMs. Cosign v3.0.6 signs every archive, SBOM, and the checksum manifest with GitHub's short-lived +3. Syft v1.49.0 creates one SPDX SBOM per archive. The checksum manifest covers both archives and + SBOMs. Cosign v3.1.2 signs every archive, SBOM, and the checksum manifest with GitHub's short-lived OIDC identity and emits self-contained Sigstore bundles. 4. `actions/attest` v4 creates one SLSA provenance statement over the checksum manifest's subjects and one SPDX predicate binding for each archive/SBOM pair. Action dependencies are pinned to diff --git a/sessions/2026-07-21-release-tooling.md b/sessions/2026-07-21-release-tooling.md new file mode 100644 index 0000000..87fc945 --- /dev/null +++ b/sessions/2026-07-21-release-tooling.md @@ -0,0 +1,45 @@ +# Release supply-chain tooling refresh — 2026-07-21 + +## [S] Scope + +Refresh the explicitly pinned SBOM and signing executables used by pull-request reproducibility and +tag release. The release identity, permissions, action commit pins, artifact graph, publish order, +and consumer verification contract remain unchanged. + +## [D] Decision + +- Syft advances from v1.46.0 to v1.49.0. The upstream release fixes Go `replace`-directive + interpretation and adds root OCI-layout index support, both relevant to Sith's Go SBOM and + multi-architecture image boundary. +- Cosign advances from v3.0.6 to v3.1.2. The upstream release fixes malformed-input panics and + bundle signing/verification defects. Sith already emits bundles and uses none of the newly + deprecated `--payload` or `--output-attestation` flags. +- A repository policy test now keeps CI, tag release, README prerequisites, and the supply-chain ADR + synchronized instead of relying on manual version searches. + +## [V] Verification + +- Rebased onto exact `dev` merge `ae2d28de2d7fc6e6661098d9b1bb07e1b9381cad`, after its CI and + CodeQL workflows completed successfully. The one shared Makefile insertion retained both the + Wails and release-tooling policy gates. +- Official release assets are checksum-verified before local use. Both selected versions are stable + upstream releases: [Syft v1.49.0](https://github.com/anchore/syft/releases/tag/v1.49.0), published + 2026-07-21, and [Cosign v3.1.2](https://github.com/sigstore/cosign/releases/tag/v3.1.2), published + 2026-07-17. +- Actionlint, ShellCheck, and the focused policy test pass. Its 9 assertions validate every + synchronized pin, installer binding, documentation reference, and deprecated-flag exclusion. +- The real installed tools report Syft 1.49.0, Cosign 3.1.2, and GoReleaser 2.17.0. +- `go mod verify`, `govulncheck ./...`, and `make ci` pass, including race and all operator-facing + policy tests. +- `make e2e-isolation` passes against PostgreSQL plus 100,000 tenant-boundary fuzz executions. +- `make release-check` passes two independently rebuilt archive/SBOM distributions, Homebrew + formula validation, and the dual-architecture OCI layout contract using Syft 1.49.0. +- `make e2e-kind KIND=/Volumes/EXTENDED/MacData/tools/bin/kind` passes the fleet fan-out, immutable + OCI image, and Argo application projection contracts in 241.080 seconds. + +## [C] Security, operations, and cost + +The update repairs producer-side parsing and verification behavior without adding credentials, +permissions, services, storage, egress, or recurring cloud cost. Pull-request and tag CPU duration +may vary slightly with the newer scanners, but the number of builds, SBOMs, signatures, and +attestations is unchanged. diff --git a/tests/scripts/release_tooling_policy_test.sh b/tests/scripts/release_tooling_policy_test.sh new file mode 100755 index 0000000..642544a --- /dev/null +++ b/tests/scripts/release_tooling_policy_test.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2016 + +set -Eeuo pipefail + +REPO_ROOT="$(git rev-parse --show-toplevel)" +readonly REPO_ROOT +readonly EXPECTED_GORELEASER_VERSION="v2.17.0" +readonly EXPECTED_SYFT_VERSION="v1.49.0" +readonly EXPECTED_COSIGN_VERSION="v3.1.2" + +PASS_COUNT=0 + +pass() { + PASS_COUNT=$((PASS_COUNT + 1)) + printf '[release-tooling] PASS: %s\n' "$1" +} + +assert_equal() { + local actual=$1 + local expected=$2 + local description=$3 + + if [[ "${actual}" != "${expected}" ]]; then + printf '[release-tooling] FAIL: %s = %q, want %q\n' \ + "${description}" "${actual}" "${expected}" >&2 + return 1 + fi + pass "${description}" +} + +workflow_value() { + local workflow=$1 + local name=$2 + awk -F '"' -v key="${name}:" '$1 ~ "^[[:space:]]*" key "[[:space:]]*$" { print $2 }' "${workflow}" +} + +ci_workflow="${REPO_ROOT}/.github/workflows/ci.yml" +release_workflow="${REPO_ROOT}/.github/workflows/release.yml" + +ci_goreleaser="$(workflow_value "${ci_workflow}" GORELEASER_VERSION)" +ci_syft="$(workflow_value "${ci_workflow}" SYFT_VERSION)" +release_goreleaser="$(workflow_value "${release_workflow}" GORELEASER_VERSION)" +release_syft="$(workflow_value "${release_workflow}" SYFT_VERSION)" +release_cosign="$(workflow_value "${release_workflow}" COSIGN_VERSION)" + +assert_equal "${ci_goreleaser}" "${EXPECTED_GORELEASER_VERSION}" "CI GoReleaser pin is current" +assert_equal "${release_goreleaser}" "${ci_goreleaser}" "release GoReleaser pin matches CI" +assert_equal "${ci_syft}" "${EXPECTED_SYFT_VERSION}" "CI Syft pin is current" +assert_equal "${release_syft}" "${ci_syft}" "release Syft pin matches CI" +assert_equal "${release_cosign}" "${EXPECTED_COSIGN_VERSION}" "release Cosign pin is current" + +grep -Fq "GoReleaser ${EXPECTED_GORELEASER_VERSION} and Syft ${EXPECTED_SYFT_VERSION}" \ + "${REPO_ROOT}/README.md" +pass "README release prerequisites match executable pins" + +grep -Fq "Syft ${EXPECTED_SYFT_VERSION}" "${REPO_ROOT}/docs/adr/0009-release-supply-chain.md" +grep -Fq "Cosign ${EXPECTED_COSIGN_VERSION}" "${REPO_ROOT}/docs/adr/0009-release-supply-chain.md" +pass "release-supply-chain decision records current pins" + +grep -Fq 'syft-version: ${{ env.SYFT_VERSION }}' "${ci_workflow}" +grep -Fq 'syft-version: ${{ env.SYFT_VERSION }}' "${release_workflow}" +grep -Fq 'cosign-release: ${{ env.COSIGN_VERSION }}' "${release_workflow}" +pass "installer actions consume the synchronized pins" + +if grep -Eq -- '--(payload|output-attestation)([=[:space:]]|$)' "${release_workflow}"; then + printf '[release-tooling] FAIL: release workflow uses a Cosign v3.1-deprecated flag\n' >&2 + exit 1 +fi +pass "release workflow avoids newly deprecated Cosign flags" + +printf '[release-tooling] %d assertions passed\n' "${PASS_COUNT}"