From da0ecf6a250ba7d08687be1fad46d237ea08eeaf Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 28 Nov 2025 10:27:49 -0800 Subject: [PATCH 1/4] Add security scanning and modernize GitHub Actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add CodeQL workflow for Rust security vulnerability scanning - Add cargo-audit workflow for dependency CVE checking - Replace deprecated actions-rs/toolchain with dtolnay/rust-toolchain - Replace actions-rs/cargo with direct cargo commands 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/audit.yml | 21 +++++++++++++++++++++ .github/workflows/codeql.yml | 30 ++++++++++++++++++++++++++++++ .github/workflows/doc.yml | 11 ++--------- .github/workflows/rust.yml | 32 ++++++++------------------------ 4 files changed, 61 insertions(+), 33 deletions(-) create mode 100644 .github/workflows/audit.yml create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 00000000..1548a077 --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,21 @@ +name: Security Audit + +on: + push: + branches: [main, master] + pull_request: + schedule: + - cron: "0 0 * * *" # Daily at midnight + +jobs: + audit: + name: Cargo Audit + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Run cargo-audit + uses: rustsec/audit-check@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..36847092 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,30 @@ +name: CodeQL + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + schedule: + - cron: "0 6 * * 1" # Weekly on Monday + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + security-events: write + actions: read + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: rust + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 506c5216..b221aed4 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -15,17 +15,10 @@ jobs: uses: actions/checkout@v6 - name: Install Rust toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - profile: minimal - override: true + uses: dtolnay/rust-toolchain@stable - name: Build Documentation - uses: actions-rs/cargo@v1 - with: - command: doc - args: --all --no-deps + run: cargo doc --all --no-deps - name: Create index run: echo '' > target/doc/index.html diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d22f94e8..9fcce7b3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -20,17 +20,14 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Install ${{ matrix.toolchain }} toolchain - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: - profile: minimal toolchain: ${{ matrix.toolchain }} - override: true - name: Run cargo check - uses: actions-rs/cargo@v1 - with: - command: check + run: cargo check test: name: Test Suite @@ -46,16 +43,12 @@ jobs: submodules: true - name: Install ${{ matrix.toolchain }} toolchain - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: - profile: minimal toolchain: ${{ matrix.toolchain }} - override: true - name: Run cargo test - uses: actions-rs/cargo@v1 - with: - command: test + run: cargo test lints: name: Lints @@ -65,21 +58,12 @@ jobs: uses: actions/checkout@v6 - name: Install stable toolchain - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@stable with: - profile: minimal - toolchain: stable - override: true components: rustfmt, clippy - name: Run cargo fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check + run: cargo fmt --all -- --check - name: Run cargo clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: -- -D warnings + run: cargo clippy -- -D warnings From 5867bc7e04a599bf3335e8c41ddd2d7e298089ba Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 28 Nov 2025 10:31:42 -0800 Subject: [PATCH 2/4] Add Trusted Publishing workflow for crates.io MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses OIDC token exchange via rust-lang/crates-io-auth-action to publish to crates.io without long-lived API tokens. Triggers on version tags (v*) and requires the "release" environment. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/release.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..8e0157cf --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,30 @@ +name: Publish to crates.io + +on: + push: + tags: + - "v*" + +jobs: + publish: + name: Publish + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Authenticate with crates.io + uses: rust-lang/crates-io-auth-action@v1 + id: auth + + - name: Publish to crates.io + run: cargo publish + env: + CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} From 8e9cbaee4f84e73cd8beca1b7067fa53fc382690 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 28 Nov 2025 10:38:18 -0800 Subject: [PATCH 3/4] Add release script and trigger publish on GitHub releases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add dev-bin/release.sh to automate the release process: - Validates branch and sync with origin/main - Parses version/date from CHANGELOG.md - Updates Cargo.toml version - Runs tests, commits, and creates GitHub release via gh CLI - Change publish workflow trigger from tag push to release published event to work with Trusted Publishing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/release.yml | 6 +-- dev-bin/release.sh | 84 +++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) create mode 100755 dev-bin/release.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e0157cf..47ada723 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,9 @@ name: Publish to crates.io on: - push: - tags: - - "v*" + release: + types: + - published jobs: publish: diff --git a/dev-bin/release.sh b/dev-bin/release.sh new file mode 100755 index 00000000..518f83f1 --- /dev/null +++ b/dev-bin/release.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +set -eu -o pipefail + +# Check that we're not on the main branch +current_branch=$(git branch --show-current) +if [ "$current_branch" = "main" ]; then + echo "Error: Releases should not be done directly on the main branch." + echo "Please create a release branch and run this script from there." + exit 1 +fi + +# Fetch latest changes and check that we're not behind origin/main +echo "Fetching from origin..." +git fetch origin + +if ! git merge-base --is-ancestor origin/main HEAD; then + echo "Error: Current branch is behind origin/main." + echo "Please merge or rebase with origin/main before releasing." + exit 1 +fi + +changelog=$(cat CHANGELOG.md) + +# Match: ## X.Y.Z - YYYY-MM-DD +regex='## ([0-9]+\.[0-9]+\.[0-9]+) - ([0-9]{4}-[0-9]{2}-[0-9]{2})' + +if [[ ! $changelog =~ $regex ]]; then + echo "Could not find version/date line in CHANGELOG.md!" + echo "Expected format: ## X.Y.Z - YYYY-MM-DD" + exit 1 +fi + +version="${BASH_REMATCH[1]}" +date="${BASH_REMATCH[2]}" + +# Extract release notes (everything between first ## version and next ## version) +notes=$(sed -n '/^## '"$version"'/,/^## [0-9]/p' CHANGELOG.md | sed '1d;$d') + +if [[ "$date" != $(date +"%Y-%m-%d") ]]; then + echo "Release date $date is not today ($(date +"%Y-%m-%d"))!" + exit 1 +fi + +tag="v$version" + +if [ -n "$(git status --porcelain)" ]; then + echo "Working directory is not clean." >&2 + exit 1 +fi + +# Update version in Cargo.toml +current_cargo_version=$(grep -E '^version = "[0-9]+\.[0-9]+\.[0-9]+"' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') +if [ "$current_cargo_version" != "$version" ]; then + echo "Updating Cargo.toml version from $current_cargo_version to $version" + sed -i "s/^version = \"$current_cargo_version\"/version = \"$version\"/" Cargo.toml +fi + +echo "Running tests..." +cargo test + +echo $'\nDiff:' +git diff + +echo $'\nRelease notes:' +echo "$notes" + +read -r -p "Commit changes and push to origin? [y/N] " should_push + +if [ "$should_push" != "y" ]; then + echo "Aborting" + git checkout -- Cargo.toml + exit 1 +fi + +if [ -n "$(git status --porcelain)" ]; then + git commit -m "Prepare $tag release" -a +fi + +git push + +gh release create --target "$(git branch --show-current)" -t "$version" -n "$notes" "$tag" + +git push --tags From c7052eaa4c2fa3afaf0dac5b6f31716371598c98 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 28 Nov 2025 10:45:34 -0800 Subject: [PATCH 4/4] Fix cargo audit workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Switch from rustsec/audit-check@v2 to actions-rust-lang/audit@v1 to fix "Unexpected end of JSON input" error - Add explicit permissions block 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/audit.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 1548a077..9dfee96a 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -7,6 +7,9 @@ on: schedule: - cron: "0 0 * * *" # Daily at midnight +permissions: + contents: read + jobs: audit: name: Cargo Audit @@ -16,6 +19,4 @@ jobs: uses: actions/checkout@v6 - name: Run cargo-audit - uses: rustsec/audit-check@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} + uses: actions-rust-lang/audit@v1