Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/pinact.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# pinact config: https://github.com/suzuki-shunsuke/pinact
#
# The SLSA generic generator reusable workflow must stay pinned by a vX.Y.Z tag —
# SHA-pinning it breaks slsa-verifier's builder-identity resolution. Exclude it from
# `pinact run` so the tag pin survives automated re-pinning passes.
ignore_actions:
- name: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml
ref: "v\\d+\\.\\d+\\.\\d+"
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
permissions:
contents: write
packages: write
id-token: write # required for cosign keyless signing
outputs:
hashes: ${{ steps.hash.outputs.hashes }}
steps:
- name: Check out repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Expand Down Expand Up @@ -86,6 +89,9 @@
repositories: bomly-cli
permission-contents: write

- name: Install cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
Expand All @@ -97,3 +103,22 @@
TAP_GITHUB_TOKEN: ${{ steps.package-token.outputs.token }}
SCOOP_GITHUB_TOKEN: ${{ steps.package-token.outputs.token }}
WINGET_GITHUB_TOKEN: ${{ secrets.WINGET_GITHUB_TOKEN }}

- name: Generate artifact hashes for SLSA provenance
id: hash
run: echo "hashes=$(base64 -w0 < dist/SHA256SUMS)" >> "$GITHUB_OUTPUT"

provenance:
needs: release
permissions:
actions: read # detect the workflow that triggered this run
id-token: write # sign the provenance
contents: write # upload the provenance to the release
# The SLSA generator MUST be pinned by a full vX.Y.Z tag, not a commit SHA or
# shorter tag — slsa-verifier resolves the builder identity from this exact ref,
# and SHA-pinning breaks that resolution. See .github/pinact.yaml, which excludes
# this line from automated re-pinning.
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0

Check warning

Code scanning / bomly

Package license is unknown Warning

Package license is unknown in pkg:githubactions/slsa-framework/slsa-github-generator%2F.github%2Fworkflows%2Fgenerator_generic_slsa3.yml@v2.1.0
with:
base64-subjects: ${{ needs.release.outputs.hashes }}
upload-assets: ${{ startsWith(github.ref, 'refs/tags/') }}
16 changes: 14 additions & 2 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ archives:
checksum:
name_template: "SHA256SUMS"

signs:
- cmd: cosign
signature: "${artifact}.sigstore.json"
args:
- sign-blob
- "--bundle=${signature}"
- "${artifact}"
- "--yes"
artifacts: checksum
output: true

snapshot:
version_template: "{{ incpatch .Version }}-next"

Expand All @@ -106,9 +117,10 @@ release:
- Alternate `bomly-lite` archives for users who prefer external Syft and Grype binaries.
- Linux packages for Debian, RPM, Alpine, and Arch-compatible package managers.
- Homebrew, Scoop, and WinGet package-manager manifests or publishing pull requests.
- `SHA256SUMS` for release artifact verification.
- `SHA256SUMS` for release artifact verification, signed keylessly with [cosign](https://docs.sigstore.dev/cosign/signing/overview/) (`SHA256SUMS.sigstore.json`).
- SLSA Build Level 3 provenance (`multiple.intoto.jsonl`) generated by [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator).

Each archive includes `LICENSE`, `NOTICE`, and a `licenses/` directory with third-party license texts. GitHub-native artifact attestations are planned for a future release.
Each archive includes `LICENSE`, `NOTICE`, and a `licenses/` directory with third-party license texts. See [Verify release checksums](https://github.com/bomly-dev/bomly-cli/blob/main/docs/INSTALLATION.md#verify-release-checksums) for signature and provenance verification commands.

nfpms:
- id: bomly-linux-packages
Expand Down
3 changes: 2 additions & 1 deletion dev-docs/CI.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Bomly uses GitHub Actions for validation, security analysis, smoke coverage, and
| `Smoke` | Merge queue, nightly schedule, manual dispatch | Slow end-to-end coverage against real repositories, SBOMs, and containers before merge, plus scheduled drift detection |
| `Update Smoke Goldens` | Manual dispatch | Regenerate golden files on a chosen ref and open a PR when the changes are intentional |
| `Auto Version` | Manual dispatch | Bump `cmd/bomly/main.go`, create a semver tag, and start the release workflow |
| `Release` | Semver tags like `v1.2.3`, manual dispatch | GoReleaser packaging, checksums, Linux packages, package-manager manifests, and GitHub release publication |
| `Release` | Semver tags like `v1.2.3`, manual dispatch | GoReleaser packaging, checksums, Linux packages, package-manager manifests, GitHub release publication, cosign keyless signing, and SLSA provenance |

## Required Checks

Expand All @@ -35,6 +35,7 @@ Bomly dogfoods its own domain by tracking the project's [OpenSSF Scorecard](http
- **Token-Permissions** — every workflow declares a top-level `permissions:` block scoped to `contents: read`. Any write scope (release publishing, the Guard PR comment, the smoke-goldens PR) is granted at the **job** level only, never at the top level.
- **Pinned-Dependencies** — all GitHub Actions are pinned by full commit SHA with a trailing `# vX.Y.Z` comment (for example `actions/checkout@<sha> # v7.0.0`). Dependabot's `github-actions` updater understands this form and bumps both the SHA and the comment, so pinning does not freeze us on stale actions. When adding a new `uses:`, pin it the same way — `pinact run` (suzuki-shunsuke/pinact) rewrites the whole tree, or resolve a single tag with `gh api repos/<owner>/<repo>/commits/<tag> --jq .sha`. The `Smoke` and `Update Smoke Goldens` workflows install `pip`/`pipenv`/`poetry` from `.github/requirements-ci-tools.txt`, a hash-locked, fully-resolved requirements file (`pip install --require-hashes`) instead of an unpinned inline `pip install`. Regenerate it after bumping `.github/requirements-ci-tools.in` with `pip-compile --allow-unsafe --generate-hashes --output-file=requirements-ci-tools.txt requirements-ci-tools.in` run from `.github/` under the same Python version the workflows use (3.12), so the resolved hash set covers the right wheel tags.
- **SAST** — CodeQL runs on every push, PR, and weekly.
- **Signed-Releases** — the `release` job signs `SHA256SUMS` keylessly with [cosign](https://docs.sigstore.dev/cosign/signing/overview/) (`SHA256SUMS.sigstore.json`, GitHub OIDC identity, no managed keys), and a separate `provenance` job calls the [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) generic builder to produce a single `multiple.intoto.jsonl` SLSA Build Level 3 provenance file over every release artifact's hash, uploaded to the same GitHub release. Verification commands for end users are in [docs/INSTALLATION.md](../docs/INSTALLATION.md#verify-release-checksums). The generator's `uses:` line is pinned to the `v2.1.0` tag, not a commit SHA — SHA-pinning it breaks `slsa-verifier`'s builder-identity check — and `.github/pinact.yaml` excludes that line from automated re-pinning so it doesn't regress.

A few Scorecard checks require maintainer action **outside** the repository and are not code changes:

Expand Down
28 changes: 28 additions & 0 deletions docs/INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,34 @@ Get-FileHash .\bomly_v0.14.2_windows_amd64.zip -Algorithm SHA256
# Compare the printed hash against the matching line in SHA256SUMS.
```

### Verify the signature

`SHA256SUMS` is itself signed keylessly with [cosign](https://docs.sigstore.dev/cosign/signing/overview/), tying the release to the exact GitHub Actions workflow run that built it:

```bash
curl -L -O https://github.com/bomly-dev/bomly-cli/releases/download/v0.14.2/SHA256SUMS.sigstore.json
cosign verify-blob \
--bundle SHA256SUMS.sigstore.json \
--certificate-identity-regexp "^https://github.com/bomly-dev/bomly-cli/.github/workflows/release.yml@.*$" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
SHA256SUMS
```

### Verify SLSA provenance

Each release also publishes a single `multiple.intoto.jsonl` SLSA Build Level 3 provenance file covering every release artifact, attesting which source commit and workflow produced them:

```bash
curl -L -O https://github.com/bomly-dev/bomly-cli/releases/download/v0.14.2/bomly_v0.14.2_linux_amd64.tar.gz
curl -L -O https://github.com/bomly-dev/bomly-cli/releases/download/v0.14.2/multiple.intoto.jsonl
slsa-verifier verify-artifact bomly_v0.14.2_linux_amd64.tar.gz \
--provenance-path multiple.intoto.jsonl \
--source-uri github.com/bomly-dev/bomly-cli \
--source-tag v0.14.2
```

`slsa-verifier` is available from the [slsa-framework/slsa-verifier releases](https://github.com/slsa-framework/slsa-verifier/releases).

## CI installation

For pinned CI recipes, see [CI integration](CI_INTEGRATION.md). Prefer a package-manager install when your CI environment supports it. If you download archives directly, pin a specific tag rather than `latest`.
Expand Down