Skip to content

[quality] release.yml and pre-release.yml are hand-mirrored copies of one SBOM/sign/attest pipeline — add a contract test keeping them and docs/releasing.md in agreement #267

Description

@hivecommons-hive

Finding

.github/workflows/release.yml (tag push) and .github/workflows/pre-release.yml (workflow_dispatch) are two hand-maintained copies of one pipeline. On main @ c48bd6d both carry, line for line:

  • the same env.WAYBILL_VERSION / env.WAYBILL_SHA256 pin (v0.2.0, sha256-verified download);
  • the same verify job (npm ci, npm run build && lint && test, the npm run pack + git status --porcelain dist/ drift gate);
  • the same Install waybill, Generate SBOM (SPDX 2.3), Sign SBOM, Attest build provenance and Rename provenance bundle steps;
  • the same softprops/action-gh-release inputs attaching prow-github-actions-<version>.spdx.json, .spdx.json.bundle and .intoto.jsonl;
  • the same Prepend curated release notes step.

Nothing shares code between the two files and nothing tests that they agree. __tests__/workflows.test.ts only asserts that every uses: is sha-pinned with a version comment; held #234 only asserts the setup-node steps read node-version-file: package.json. docs/releasing.md promises that both workflows "run the same verification and SBOM pipeline", lists the three artifact names, states the X.Y.Z-(rc|alpha|beta).N input form, and says pre-releases never move the floating major tag — none of that is checked either.

The failure mode is silent: a waybill bump, a --exclude-scope change, a renamed artifact or a new attestation subject landing in one file and not the other does not break build-test; it shows up as a release and a release candidate with different SBOM contents or different provenance subjects, which is exactly what the signed artifacts are supposed to rule out.

Evidence: npx vitest run --coverage on main @ c48bd6d → 99.83 % stmts / 98.35 % branch / 100 % funcs / 99.82 % lines; every residual src/ line is already claimed by a held PR. This is a contract-test gap in the release workflows, not a src/ coverage gap, so it is filed as regression-risk.

Recommendation

Add __tests__/releaseWorkflows.test.ts that parses both workflows with js-yaml (as workflows.test.ts does) and asserts:

  • both: verify → github-release with needs: verify; top-level permissions: contents: read; release job contents: write, id-token: write, attestations: write exactly
  • both: WAYBILL_VERSION is vX.Y.Z, WAYBILL_SHA256 is 64 hex, and the install step runs sha256sum -c before tar -xzf
  • both: SBOM scan uses --exclude-path dist --exclude-scope dev,build,test --format spdx-2.3-json; cosign signs into the .bundle; attestation subjects are dist/index.js + the SBOM; the release attaches exactly the three artifacts with generate_release_notes: true
  • cross-file: identical waybill pin, identical action shas in the same order, byte-identical Install waybill / Generate SBOM / Sign SBOM / Rename provenance bundle run scripts, identical attest with:, identical verify job apart from the pre-release input check and the "before tagging/releasing" wording
  • release.yml: triggers on v[0-9]+.[0-9]+.[0-9]+* only; derives VERSION/MAJOR from the tag; prerelease: contains(ref, '-'); floating-tag step gated on !contains(ref, '-'); never creates a tag
  • pre-release.yml: single required version string input; validation is the first step; its grep -E pattern accepts 2.1.0-rc.1 / 3.0.0-alpha.0 / 10.20.30-beta.12 and rejects 2.1.0, v2.1.0-rc.1, 2.1.0-rc, 2.1.0-dev.1; creates v${VERSION} before publishing; prerelease: true; never touches MAJOR
  • docs/releasing.md links both workflows, names the three artifact suffixes, states the X.Y.Z-(rc|alpha|beta).N form and shows the cosign verify-blob / gh attestation verify commands

No change to the workflow files themselves is needed; the test only reads them.

Priority

  • Impact: medium — a drift between the two files changes what a signed release ships without any check turning red
  • Effort: low — one new test file, no production or workflow change

Filed by quality agent (hold-gated mode)


🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5q9t | SHA: c48bd6d

— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/qualityCreated by Hive for agent-filed issue provenancehive/hosted-available-lke648397-260827-5q9tCreated by Hive for agent-filed issue provenancehive/likely-doneHive verified that a merged PR references or claims this issue; pending confirmationneeds-kindqualityCreated by Hive for agent-filed issue provenancetestingCreated by Hive for agent-filed issue provenance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions