Skip to content
Draft
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
6 changes: 6 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ on:

permissions:
contents: write
# id-token lets cosign obtain a GitHub OIDC token for keyless (Sigstore)
# signing of checksums.txt during the goreleaser step.
id-token: write

jobs:
# GoReleaser runs on macOS so the darwin binary builds natively (CoreAudio
Expand Down Expand Up @@ -92,6 +95,9 @@ jobs:
path: .cross
key: cross-${{ runner.os }}-zig0.14.1-alsa1.2.12-${{ hashFiles('scripts/setup-cross.sh') }}

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

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
with:
Expand Down
22 changes: 22 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,27 @@ gomod:
checksum:
name_template: 'checksums.txt'

# Keyless (Sigstore) signing: cosign signs checksums.txt with the release
# workflow's GitHub OIDC identity — no long-lived key to manage. Every archive
# is listed in checksums.txt, so one signature covers all release artifacts.
# Verify with:
# cosign verify-blob \
# --certificate checksums.txt.pem --signature checksums.txt.sig \
# --certificate-identity-regexp '^https://github.com/livekit/livekit-cli/\.github/workflows/release\.yaml@.*$' \
# --certificate-oidc-issuer https://token.actions.githubusercontent.com \
# checksums.txt
signs:
- cmd: cosign
signature: "${artifact}.sig"
certificate: "${artifact}.pem"
args:
- sign-blob
- --output-signature=${signature}
- --output-certificate=${certificate}
- --yes
- ${artifact}
artifacts: checksum
output: true

snapshot:
version_template: "{{ incpatch .Version }}-next"
30 changes: 28 additions & 2 deletions install-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,36 @@ trap 'rm -rf "$TEMP_DIR"' EXIT
curl -fsSL "$ARCHIVE_URL" -o "$TEMP_DIR/$ARCHIVE_NAME"
curl -fsSL "$CHECKSUMS_URL" -o "$TEMP_DIR/checksums.txt"

# When cosign is available, verify the Sigstore signature on checksums.txt. The
# certificate identity is pinned to this repo's release workflow running for this
# exact version tag, so a valid signature proves the checksums were produced by
# livekit-cli's release CI and not substituted alongside a tampered archive.
# Releases published before signing was introduced have no .sig/.pem assets, so a
# missing signature is skipped rather than fatal; a present-but-invalid one aborts.
if command -v cosign >/dev/null; then
# No -S here: a 404 is the expected outcome for releases that predate signing,
# so curl's error output would just be noise.
if curl -fsL "$CHECKSUMS_URL.sig" -o "$TEMP_DIR/checksums.txt.sig" &&
curl -fsL "$CHECKSUMS_URL.pem" -o "$TEMP_DIR/checksums.txt.pem"; then
log "Verifying signature..."
cosign verify-blob \
--certificate "$TEMP_DIR/checksums.txt.pem" \
--signature "$TEMP_DIR/checksums.txt.sig" \
--certificate-identity-regexp "^https://github.com/livekit/$REPO/\.github/workflows/release\.yaml@refs/tags/v${VERSION}$" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
"$TEMP_DIR/checksums.txt" \
|| abort "Signature verification failed for checksums.txt"
else
log "No signature published for this release; skipping signature verification."
fi
else
log "cosign not found; skipping signature verification."
fi

# Verify the archive against the release's checksums.txt before extracting. The checksums
# file is fetched from the same release over HTTPS, so this guards against corrupted/partial
# downloads and accidental mismatches; it is not a substitute for signature verification
# against an out-of-band key.
# downloads and accidental mismatches; when cosign is absent it is not a substitute for
# signature verification against an out-of-band key.
log "Verifying checksum..."
expected_sum=$(awk -v f="$ARCHIVE_NAME" '$2 == f {print $1}' "$TEMP_DIR/checksums.txt")
[ -n "$expected_sum" ] || abort "Could not find a checksum for $ARCHIVE_NAME in checksums.txt"
Expand Down
Loading