From 3c35837ed11ec6175a1ee4bd79979c1fc9452d35 Mon Sep 17 00:00:00 2001 From: LucaCappelletti94 Date: Wed, 30 Sep 2026 17:05:14 +0200 Subject: [PATCH] Verify the upstream signature on every run and add zizmor and cargo-deny --- .github/dependabot.yml | 6 ++++++ .github/workflows/ci.yml | 38 +++++++++++++++++++++++++++++++++- .github/workflows/codeql.yml | 2 ++ .github/workflows/coverage.yml | 2 ++ .github/workflows/release.yml | 3 ++- .github/workflows/sonar.yml | 1 + README.md | 2 +- bump.sh | 17 +++------------ deny.toml | 22 ++++++++++++++++++++ sigstore.sh | 16 ++++++++++++++ upgrade.sh | 17 +++++++++------ 11 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 deny.toml create mode 100644 sigstore.sh diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e3baf02..defb264 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,11 +5,17 @@ updates: directory: / schedule: interval: weekly + cooldown: + default-days: 7 - package-ecosystem: cargo directory: /smoke schedule: interval: weekly + cooldown: + default-days: 7 - package-ecosystem: cargo directory: /wasm schedule: interval: weekly + cooldown: + default-days: 7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3c24fa..5ba9880 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,8 @@ jobs: toolchain: [stable, "1.81"] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master with: toolchain: ${{ matrix.toolchain }} @@ -41,6 +43,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master with: toolchain: stable @@ -59,11 +63,36 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - run: shellcheck upgrade.sh bump.sh + with: + persist-credentials: false + - run: shellcheck -x upgrade.sh bump.sh sigstore.sh - name: actionlint run: | bash <(curl -sSfL https://raw.githubusercontent.com/rhysd/actionlint/914e7df21a07ef503a81201c76d2b11c789d3fca/scripts/download-actionlint.bash) 1.7.12 ./actionlint -color + - uses: taiki-e/install-action@7623a79cdfecb99d681017af368ca353d9f49bb5 # v2.87.19 + with: + tool: zizmor@1.30.1 + # The token enables the online audits, which catch impostor commits and known-vulnerable actions. + - run: zizmor . + env: + GH_TOKEN: ${{ github.token }} + + deny: + name: Dependencies of the test crates pass cargo-deny + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master + with: + toolchain: stable + - uses: taiki-e/install-action@7623a79cdfecb99d681017af368ca353d9f49bb5 # v2.87.19 + with: + tool: cargo-deny@0.20.2 + - run: cargo deny --manifest-path smoke/Cargo.toml check + - run: cargo deny --manifest-path wasm/Cargo.toml check compile: name: Compile the packaged amalgamation on ${{ matrix.os }} @@ -74,6 +103,8 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master with: toolchain: stable @@ -95,6 +126,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master with: toolchain: stable @@ -122,5 +155,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - run: ./upgrade.sh - run: git diff --exit-code diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 17706bc..fec5ad2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,6 +33,8 @@ jobs: build-mode: none steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Initialize CodeQL uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d4bf00f..a2b9136 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,6 +29,8 @@ jobs: github.event.pull_request.user.login != 'dependabot[bot]') steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install stable toolchain with llvm-tools run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e6e6735..a7a2c06 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,7 +52,8 @@ jobs: ci: name: CI needs: verify - uses: ./.github/workflows/ci.yml + # actionlint 1.7.12 rejects $/ (rhysd/actionlint#711), and a local reusable workflow already loads from this commit. + uses: ./.github/workflows/ci.yml # zizmor: ignore[self-repository] publish: name: Publish ${{ github.ref_name }} diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 01e3ace..2261082 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -32,6 +32,7 @@ jobs: with: # Full history improves blame-based new-code attribution. fetch-depth: 0 + persist-credentials: false - name: Install stable toolchain with clippy and llvm-tools run: | diff --git a/README.md b/README.md index b6a8ae2..17b4d1d 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,4 @@ The version encodes the release, so `205.1.x` is SQLite3MC 2.5.1. A `205.1` requ SQLite3MC is MIT licensed. The amalgamation also carries public-domain code (SQLite among it), a password-hashing file under CC0-1.0, a block under the Unlicense, and Argon2 under CC0-1.0 or Apache-2.0. -A daily workflow in the [repository](https://github.com/LucaCappelletti94/sqlite3mc-src) opens a pull request for each new SQLite3MC release, taking the archive's checksum only from the release's Sigstore-signed `SHA256SUMS`. CI re-runs `upgrade.sh` to prove the vendored bytes match the pinned release. +A daily workflow in the [repository](https://github.com/LucaCappelletti94/sqlite3mc-src) opens a pull request for each new SQLite3MC release, taking the archive's checksum only from the release's Sigstore-signed `SHA256SUMS`. CI re-runs `upgrade.sh`, which checks that signature again before trusting the pinned checksum, to prove the vendored bytes match the pinned release. diff --git a/bump.sh b/bump.sh index 094d77b..8db5d11 100755 --- a/bump.sh +++ b/bump.sh @@ -1,25 +1,14 @@ #!/bin/sh -e -# Moves the vendored SQLite3MC to release VERSION. The archive checksum and the SQLite version -# come from the release's SHA256SUMS, accepted only with a valid Sigstore signature from -# SQLite3MC's own release workflow. +# Moves the vendored SQLite3MC to release VERSION, taking the archive checksum and SQLite version from its signed SHA256SUMS. VERSION=${1:?usage: bump.sh VERSION} echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' || { echo "not a release version: $VERSION" >&2; exit 1; } cd "$(dirname "$0")" -RELEASE="https://github.com/utelle/SQLite3MultipleCiphers/releases/download/v${VERSION}" +. ./sigstore.sh WORK=$(mktemp -d) trap 'rm -rf "$WORK"' EXIT - -for file in SHA256SUMS SHA256SUMS.pem SHA256SUMS.sig; do - curl -sfL -o "$WORK/$file" "$RELEASE/sqlite3mc-${VERSION}-$file" -done -cosign verify-blob \ - --certificate "$WORK/SHA256SUMS.pem" \ - --signature "$WORK/SHA256SUMS.sig" \ - --certificate-identity-regexp '^https://github\.com/utelle/SQLite3MultipleCiphers/\.github/workflows/[^@]+@refs/heads/main$' \ - --certificate-oidc-issuer https://token.actions.githubusercontent.com \ - "$WORK/SHA256SUMS" +fetch_signed_sums "$VERSION" "$WORK" ESCAPED=$(echo "$VERSION" | sed 's/\./\\./g') LINE=$(grep -E "^[0-9a-f]{64} sqlite3mc-${ESCAPED}-sqlite-[0-9]+\.[0-9]+\.[0-9]+-amalgamation\.zip$" "$WORK/SHA256SUMS") diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..074c667 --- /dev/null +++ b/deny.toml @@ -0,0 +1,22 @@ +# Dependency policy for the unpublished test crates in smoke/ and wasm/, whose dependencies are mostly dev-dependencies. + +[advisories] +yanked = "deny" + +[licenses] +# sqlite3mc-src's own expression needs MIT, CC0-1.0 and the Unlicense, and unicode-ident needs Unicode-3.0. +allow = ["Apache-2.0", "CC0-1.0", "MIT", "Unicode-3.0", "Unlicense"] +include-dev = true +private = { ignore = true } +# One policy serves both graphs, and smoke/ alone never meets every licence. +unused-allowed-license = "allow" + +[bans] +multiple-versions = "deny" +multiple-versions-include-dev = true +wildcards = "deny" +allow-wildcard-paths = true + +[sources] +unknown-registry = "deny" +unknown-git = "deny" diff --git a/sigstore.sh b/sigstore.sh new file mode 100644 index 0000000..080e09f --- /dev/null +++ b/sigstore.sh @@ -0,0 +1,16 @@ +# shellcheck shell=sh +# SQLite3MC's release signing identity, sourced by bump.sh and upgrade.sh. + +# Writes release $1's SHA256SUMS to $2/SHA256SUMS once it verifies as signed by SQLite3MC's own release workflow. +fetch_signed_sums() { + release="https://github.com/utelle/SQLite3MultipleCiphers/releases/download/v$1" + for file in SHA256SUMS SHA256SUMS.pem SHA256SUMS.sig; do + curl -sfL -o "$2/$file" "$release/sqlite3mc-$1-$file" + done + cosign verify-blob \ + --certificate "$2/SHA256SUMS.pem" \ + --signature "$2/SHA256SUMS.sig" \ + --certificate-identity-regexp '^https://github\.com/utelle/SQLite3MultipleCiphers/\.github/workflows/[^@]+@refs/heads/main$' \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + "$2/SHA256SUMS" +} diff --git a/upgrade.sh b/upgrade.sh index 1b2c967..55229c3 100755 --- a/upgrade.sh +++ b/upgrade.sh @@ -1,21 +1,26 @@ #!/bin/sh -e -# Re-vendors the pinned release byte for byte. bump.sh moves the pins. +# Re-vendors the pinned release byte for byte, trusting the pinned checksum only while the release's signed SHA256SUMS lists it. bump.sh moves the pins. SQLITE3MC_VERSION="2.5.1" SQLITE_VERSION="3.53.4" ARCHIVE_SHA256="4125f8ff275ea953dabb3289331b20a0e76d4fc060f57148f4a5df3bf3b0d5e0" cd "$(dirname "$0")" +. ./sigstore.sh +WORK=$(mktemp -d) +trap 'rm -rf "$WORK"' EXIT +fetch_signed_sums "$SQLITE3MC_VERSION" "$WORK" + ARCHIVE="sqlite3mc-${SQLITE3MC_VERSION}-sqlite-${SQLITE_VERSION}-amalgamation.zip" -RELEASE="https://github.com/utelle/SQLite3MultipleCiphers/releases/download/v${SQLITE3MC_VERSION}" -curl -sfL -o "$ARCHIVE" "$RELEASE/$ARCHIVE" -echo "$ARCHIVE_SHA256 $ARCHIVE" | shasum -a 256 -c - +grep -qxF "$ARCHIVE_SHA256 $ARCHIVE" "$WORK/SHA256SUMS" || + { echo "the signed SHA256SUMS does not list $ARCHIVE with $ARCHIVE_SHA256" >&2; exit 1; } +curl -sfL -o "$WORK/$ARCHIVE" "https://github.com/utelle/SQLite3MultipleCiphers/releases/download/v${SQLITE3MC_VERSION}/$ARCHIVE" +(cd "$WORK" && echo "$ARCHIVE_SHA256 $ARCHIVE" | shasum -a 256 -c -) mkdir -p sqlite3mc for file in sqlite3mc_amalgamation.c sqlite3mc_amalgamation.h sqlite3ext.h; do - unzip -p "$ARCHIVE" "$file" > "sqlite3mc/$file" + unzip -p "$WORK/$ARCHIVE" "$file" > "sqlite3mc/$file" done -rm -f "$ARCHIVE" curl -sfL -o sqlite3mc/LICENSE "https://raw.githubusercontent.com/utelle/SQLite3MultipleCiphers/v${SQLITE3MC_VERSION}/LICENSE" (cd sqlite3mc && shasum -a 256 sqlite3mc_amalgamation.c sqlite3mc_amalgamation.h sqlite3ext.h LICENSE > SHA256SUMS)