From 625695a3f6d7686c80c78066f11964e727f055ef Mon Sep 17 00:00:00 2001 From: Kamil Sopko Date: Thu, 25 Jun 2026 18:17:18 +0200 Subject: [PATCH 1/3] ci: add unified release workflow for all crates --- .github/workflows/release.yml | 126 ++++++++++++++++++++++++++++++++++ 1 file changed, 126 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 0000000..ac4e34f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,126 @@ +name: Release + +on: + push: + tags: ["v*"] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: "-D warnings" + +jobs: + publish: + name: Publish all crates + runs-on: ubuntu-latest + environment: release + permissions: + contents: write + steps: + - uses: actions/checkout@v7 + + - name: Install Rust stable + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo registry + uses: actions/cache@v6 + with: + path: | + ~/.cargo/registry/ + ~/.cargo/git/ + target/ + key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-release- + + # ── xtax-encryption ── + - name: Publish xtax-encryption (if changed) + id: publish-enc + run: | + VERSION="$(cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "xtax-encryption") | .version')" + RESPONSE="$(curl -sf "https://crates.io/api/v1/crates/xtax-encryption" || echo "")" + if [ -z "$RESPONSE" ]; then + PUBLISHED="0" + else + PUBLISHED="$(echo "$RESPONSE" | jq -r '.versions[].num' | grep -c "^${VERSION}$" || true)" + fi + + if [ "$PUBLISHED" = "0" ]; then + echo "Publishing xtax-encryption $VERSION..." + cargo publish -p xtax-encryption --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + echo "published=true" >> "$GITHUB_OUTPUT" + else + echo "xtax-encryption $VERSION already published — skipping" + echo "published=false" >> "$GITHUB_OUTPUT" + fi + + - name: Wait for crates.io index (xtax-encryption) + if: steps.publish-enc.outputs.published == 'true' + run: sleep 30 + + # ── xtax-blob-storage ── + - name: Publish xtax-blob-storage (if changed) + id: publish-blob + run: | + VERSION="$(cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "xtax-blob-storage") | .version')" + RESPONSE="$(curl -sf "https://crates.io/api/v1/crates/xtax-blob-storage" || echo "")" + if [ -z "$RESPONSE" ]; then + PUBLISHED="0" + else + PUBLISHED="$(echo "$RESPONSE" | jq -r '.versions[].num' | grep -c "^${VERSION}$" || true)" + fi + + if [ "$PUBLISHED" = "0" ]; then + echo "Publishing xtax-blob-storage $VERSION..." + cargo publish -p xtax-blob-storage --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + echo "published=true" >> "$GITHUB_OUTPUT" + else + echo "xtax-blob-storage $VERSION already published — skipping" + echo "published=false" >> "$GITHUB_OUTPUT" + fi + + - name: Wait for xtax-blob-storage on crates.io + if: steps.publish-blob.outputs.published == 'true' + run: | + VERSION="$(cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "xtax-blob-storage") | .version')" + echo "Waiting for xtax-blob-storage $VERSION on crates.io index..." + for i in $(seq 1 60); do + echo "Attempt $i/60..." + RESPONSE="$(curl -sf "https://crates.io/api/v1/crates/xtax-blob-storage" || echo "")" + if [ -n "$RESPONSE" ]; then + MATCH="$(echo "$RESPONSE" | jq -r '.versions[].num' | grep -c "^${VERSION}$" || true)" + if [ "$MATCH" -gt 0 ]; then + echo "xtax-blob-storage $VERSION is now visible in API index" + exit 0 + fi + fi + sleep 10 + done + echo "Timed out waiting for xtax-blob-storage $VERSION" + exit 1 + + # ── xtax (facade) ── + - name: Publish xtax (if changed) + run: | + VERSION="$(cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "xtax") | .version')" + RESPONSE="$(curl -sf "https://crates.io/api/v1/crates/xtax" || echo "")" + if [ -z "$RESPONSE" ]; then + PUBLISHED="0" + else + PUBLISHED="$(echo "$RESPONSE" | jq -r '.versions[].num' | grep -c "^${VERSION}$" || true)" + fi + + if [ "$PUBLISHED" = "0" ]; then + echo "Publishing xtax $VERSION..." + cargo publish -p xtax --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + else + echo "xtax $VERSION already published — skipping" + fi + + # ── GitHub Release ── + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create ${{ github.ref_name }} \ + --repo ${{ github.repository }} \ + --title "Release ${{ github.ref_name }}" \ + --generate-notes \ No newline at end of file From b87420220f8b538783bc0bb0500045baaa30ba73 Mon Sep 17 00:00:00 2001 From: Kamil Sopko Date: Thu, 25 Jun 2026 18:22:00 +0200 Subject: [PATCH 2/3] ci: only create GitHub Release when something was published --- .github/workflows/release.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ac4e34f..e0ce686 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -99,6 +99,7 @@ jobs: # ── xtax (facade) ── - name: Publish xtax (if changed) + id: publish-xtax run: | VERSION="$(cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "xtax") | .version')" RESPONSE="$(curl -sf "https://crates.io/api/v1/crates/xtax" || echo "")" @@ -111,16 +112,24 @@ jobs: if [ "$PUBLISHED" = "0" ]; then echo "Publishing xtax $VERSION..." cargo publish -p xtax --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + echo "published=true" >> "$GITHUB_OUTPUT" else echo "xtax $VERSION already published — skipping" + echo "published=false" >> "$GITHUB_OUTPUT" fi # ── GitHub Release ── - - name: Create GitHub Release + - name: Create GitHub Release (only if something was published) + if: | + steps.publish-enc.outputs.published == 'true' || + steps.publish-blob.outputs.published == 'true' || + steps.publish-xtax.outputs.published == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh release create ${{ github.ref_name }} \ - --repo ${{ github.repository }} \ - --title "Release ${{ github.ref_name }}" \ - --generate-notes \ No newline at end of file + TAG="${{ github.ref_name }}" + echo "Some crates were published — creating GitHub Release $TAG..." + gh release create "$TAG" \ + --repo "${{ github.repository }}" \ + --title "Release $TAG" \ + --generate-notes From 5b08ee29c9d3783b3541d0835af05755cd8d05e0 Mon Sep 17 00:00:00 2001 From: Kamil Sopko Date: Thu, 25 Jun 2026 18:31:31 +0200 Subject: [PATCH 3/3] ci: pin all GitHub Actions to full commit SHAs for security --- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/codeql.yml | 8 ++++---- .../workflows/publish-xtax-blob-storage.yml | 12 ++++++------ .github/workflows/publish-xtax-encryption.yml | 12 ++++++------ .github/workflows/publish-xtax.yml | 12 ++++++------ .github/workflows/release.yml | 6 +++--- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1284777..f8081d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,15 +15,15 @@ jobs: name: Checks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: components: rustfmt, clippy - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ @@ -49,13 +49,13 @@ jobs: name: xtax-encryption runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ @@ -85,13 +85,13 @@ jobs: - "--features s3" - "--no-default-features --features s3" steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bc786f8..f59718b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,13 +21,13 @@ jobs: language: [rust] steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@411bbbe57033eedfc1a82d68c01345aa96c737d7 # v4 with: languages: ${{ matrix.language }} @@ -35,4 +35,4 @@ jobs: run: cargo build --workspace --all-features - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@411bbbe57033eedfc1a82d68c01345aa96c737d7 # v4 diff --git a/.github/workflows/publish-xtax-blob-storage.yml b/.github/workflows/publish-xtax-blob-storage.yml index 24920d5..9710efb 100644 --- a/.github/workflows/publish-xtax-blob-storage.yml +++ b/.github/workflows/publish-xtax-blob-storage.yml @@ -13,13 +13,13 @@ jobs: name: Dry-run publish check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ @@ -37,13 +37,13 @@ jobs: needs: dry-run environment: release steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ diff --git a/.github/workflows/publish-xtax-encryption.yml b/.github/workflows/publish-xtax-encryption.yml index 7f1bd2c..c6ad21e 100644 --- a/.github/workflows/publish-xtax-encryption.yml +++ b/.github/workflows/publish-xtax-encryption.yml @@ -13,13 +13,13 @@ jobs: name: Dry-run publish check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ @@ -37,13 +37,13 @@ jobs: needs: dry-run environment: release steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ diff --git a/.github/workflows/publish-xtax.yml b/.github/workflows/publish-xtax.yml index b945d9b..ba838fe 100644 --- a/.github/workflows/publish-xtax.yml +++ b/.github/workflows/publish-xtax.yml @@ -13,13 +13,13 @@ jobs: name: Dry-run publish check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ @@ -37,13 +37,13 @@ jobs: needs: dry-run environment: release steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e0ce686..7538be6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,13 +16,13 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Rust stable - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Cache cargo registry - uses: actions/cache@v6 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6 with: path: | ~/.cargo/registry/