Skip to content

Verify a release ​

The agent is root on your server, so it should be possible to say where it came from. From 0.8.0 on, every release is signed by the workflow that built it. This page says what that signature proves, how to check it yourself for the files and the images, what the installer and shipwick upgrade check for you, and where the bill of materials of a release is.

Before you begin ​

  • Releases before 0.8.0 have no signature. Their files are verified against the release's checksums, as before.
  • Verifying a file takes cosign 2.4 or later. An older cosign fails on this signature whatever the file.
  • Verifying an image takes cosign 3; cosign 2.6 reads these signatures with --new-bundle-format.
  • A provenance attestation is read with the GitHub CLI, signed in.

What the signature proves ​

A release is signed by the workflow that built it, and by nothing else: there is no signing key, in the repository or anywhere. GitHub tells Sigstore which workflow is running and for which tag, Sigstore issues a certificate for that identity that is valid for ten minutes, and the signature goes into a public log. A signature verifies only for the identity you name, which for release v0.8.0 is

text
https://github.com/shipwick/shipwick/.github/workflows/release.yml@refs/tags/v0.8.0
issued by https://token.actions.githubusercontent.com

So what it proves is that the file or image was produced by that workflow file, at that tag, in that repository: a commit you can read. It does not prove that the commit is good.

Verify the files ​

The release's files — the CLI for every platform, the packages, the compose file, the installer, the digests of the images — are listed in checksums.txt, and checksums.txt is what is signed. The signature is a file of the release, checksums.txt.sigstore.json.

bash
curl -fsSLO https://github.com/shipwick/shipwick/releases/download/v0.8.0/checksums.txt
curl -fsSLO https://github.com/shipwick/shipwick/releases/download/v0.8.0/checksums.txt.sigstore.json
cosign verify-blob checksums.txt --bundle checksums.txt.sigstore.json \
  --certificate-identity https://github.com/shipwick/shipwick/.github/workflows/release.yml@refs/tags/v0.8.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum -c --ignore-missing checksums.txt     # the files you downloaded, against the list

The first three lines prove who wrote the list; the last holds the files you downloaded against it.

Verify the images ​

The images are signed by digest. A tag is resolved to its digest when you verify, so this proves what the registry serves under the tag now.

bash
cosign verify ghcr.io/shipwick/agent:0.8.0 \
  --certificate-identity https://github.com/shipwick/shipwick/.github/workflows/release.yml@refs/tags/v0.8.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

The same goes for ghcr.io/shipwick/dashboard and ghcr.io/shipwick/caddy. The digest it prints is the index line of that image in the release's image-digests.txt, and what this shows on a server that pulled the tag:

bash
docker image inspect --format '{{.RepoDigests}}' ghcr.io/shipwick/agent:0.8.0

Verify the provenance ​

Each file and each image also has a provenance attestation, kept by GitHub: the repository, the commit, the workflow and the run.

bash
gh attestation verify shipwick_linux_amd64 --repo shipwick/shipwick \
  --cert-identity https://github.com/shipwick/shipwick/.github/workflows/release.yml@refs/tags/v0.8.0
gh attestation verify oci://ghcr.io/shipwick/agent:0.8.0 --repo shipwick/shipwick \
  --cert-identity https://github.com/shipwick/shipwick/.github/workflows/release.yml@refs/tags/v0.8.0

What the installer and the CLI check for you ​

The installer, shipwick upgrade and shipwick server bundle verify the signature of checksums.txt before they use the checksums, when cosign is installed where they run. Nothing installs cosign for you, and nothing needs it.

With cosign installedWithout cosign
The installerVerifies the signature and stops if it is not the release workflow's: ✓ The release is signed by the release workflow of github.com/shipwick/shipwick. A release without a signature is installed with a warningSays so in one line and goes by the checksums alone: The release's signature was not checked: cosign is not installed. Every file is checked against the release's checksums.
The installer with SHIPWICK_REQUIRE_SIGNATURE=1The same, and a release without a signature is refusedInstalls nothing
shipwick upgradeVerifies the signature; a signature that does not verify changes nothing. A release from 0.8.0 on that has no signature is refusedSays that the signature was not checked
shipwick server bundleVerifies the signature before it downloads anything else, and says which it was. The signature travels in the bundleSays that the signature was not checked. The signature travels in the bundle all the same

A new server has no cosign, so the installer's line about it is the second line of an ordinary installation.

Make the check a condition ​

bash
curl -fsSL https://get.shipwick.com | SHIPWICK_REQUIRE_SIGNATURE=1 sh

With SHIPWICK_REQUIRE_SIGNATURE=1 the installer installs nothing without cosign, from a release without a signature, or from one whose signature does not verify.

Without that setting a release that has no signature is installed with a warning. Releases before 0.8.0 have none, and the installer cannot tell one of those from a release whose signature somebody removed. shipwick upgrade can, because it knows which release it asked for: with cosign installed it refuses a release from 0.8.0 on that has no signature.

A bundle for a server with no connection ​

Where the bundle is made is also where its signature is checked. With cosign installed there, shipwick server bundle verifies the release's signature of checksums.txt before it downloads anything else, and says which it was: verified, not checked for want of cosign, or a release from before releases were signed. The signature travels in the bundle as checksums.txt.sigstore.json.

The installer on the server does not verify it by itself: cosign asks Sigstore for the keys it trusts, and that server reaches nothing. With SHIPWICK_REQUIRE_SIGNATURE=1 it does, for a server whose cosign was given those keys beforehand. See Install on a server with no way out.

The packages ​

The Debian and RPM packages of the agent are files of the release, listed in the signed checksums.txt. Verify that file as above, and the package against it, before you install one. See Install from a package.

What a release is made of ​

Each binary of a release has a bill of materials next to it, shipwick_linux_amd64.spdx.json and so on, and shipwick-agent_amd64.spdx.json for the agent inside the packages: the Go modules it was linked from, with their versions, and the Go it was compiled with, read from the binary itself. They are listed in checksums.txt like every other file.

Each image carries one for each platform, written when it was built from the files in it, as part of the signed manifest list:

bash
docker buildx imagetools inspect ghcr.io/shipwick/agent:0.8.0 \
  --format '{{ json (index .SBOM "linux/amd64").SPDX }}'

All of them are SPDX 2.3 JSON, which scanners such as Grype and Trivy read.

What's next ​