S2 - Release GitHub #1
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: S2 - Release GitHub | |
| on: | |
| workflow_dispatch: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| permissions: | |
| contents: read | |
| jobs: | |
| test: | |
| name: Test (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [macos-latest] | |
| rust: [stable] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: ${{ matrix.rust }} | |
| components: rustfmt, clippy | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Check formatting | |
| run: cargo +${{ matrix.rust }} fmt --all -- --check | |
| - name: Clippy | |
| run: cargo +${{ matrix.rust }} clippy --all-targets --all-features -- -D warnings | |
| - name: Run tests | |
| run: cargo +${{ matrix.rust }} test --all-features -- --test-threads=1 | |
| coverage: | |
| name: Code Coverage | |
| runs-on: macos-latest | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Install cargo-tarpaulin | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-tarpaulin | |
| - name: Clean before coverage | |
| run: cargo clean | |
| - name: Generate coverage | |
| run: cargo +stable tarpaulin --all-features --workspace --timeout 120 --out xml --engine llvm | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| use_oidc: true | |
| fail_ci_if_error: false | |
| alias-drift-check: | |
| name: Alias Drift Check | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Verify alias manifest and consumers | |
| run: | | |
| set -e | |
| # Manifest exists | |
| if [ ! -f toolkit/packaging/binary-aliases.txt ]; then | |
| echo "ERROR: toolkit/packaging/binary-aliases.txt not found"; exit 1 | |
| fi | |
| # Only 1 [[bin]] in Cargo.toml | |
| BIN_COUNT=$(grep -c '^[[:space:]]*\[\[bin\]\]' Cargo.toml || true) | |
| if [ "$BIN_COUNT" -ne 1 ]; then | |
| echo "ERROR: Cargo.toml has $BIN_COUNT [[bin]] entries, expected 1"; exit 1 | |
| fi | |
| # Primary matches Cargo.toml bin name | |
| MANIFEST_PRIMARY=$(head -n1 toolkit/packaging/binary-aliases.txt) | |
| CARGO_BIN=$(awk ' | |
| /^\[\[bin\]\]/ { in_bin=1; next } | |
| in_bin && /^\[/ { exit } | |
| in_bin && $1 == "name" { | |
| line = $0 | |
| sub(/^[^"]*"/, "", line) | |
| sub(/".*$/, "", line) | |
| if (line != "") { print line; exit } | |
| } | |
| ' Cargo.toml) | |
| if [ -z "$CARGO_BIN" ]; then | |
| echo "ERROR: Could not resolve bin name from Cargo.toml"; exit 1 | |
| fi | |
| if [ "$MANIFEST_PRIMARY" != "$CARGO_BIN" ]; then | |
| echo "ERROR: Primary mismatch: manifest=$MANIFEST_PRIMARY cargo=$CARGO_BIN"; exit 1 | |
| fi | |
| # Homebrew workflow references all aliases | |
| while IFS= read -r alias; do | |
| [ -z "$alias" ] && continue | |
| if ! grep -Fq -- "$alias" .github/workflows/S3-Publish-Homebrew.yml; then | |
| echo "ERROR: '$alias' missing from S3-Publish-Homebrew.yml"; exit 1 | |
| fi | |
| done < toolkit/packaging/binary-aliases.txt | |
| # Conductor script paths exist with exact casing (important on Linux) | |
| [ -f toolkit/conductor/run.sh ] || { echo "ERROR: toolkit/conductor/run.sh not found"; exit 1; } | |
| [ -f toolkit/conductor/archive.sh ] || { echo "ERROR: toolkit/conductor/archive.sh not found"; exit 1; } | |
| # Scripts reference the manifest | |
| grep -q 'binary-aliases.txt' toolkit/conductor/run.sh || { echo "ERROR: run.sh missing manifest ref"; exit 1; } | |
| grep -q 'binary-aliases.txt' toolkit/conductor/archive.sh || { echo "ERROR: archive.sh missing manifest ref"; exit 1; } | |
| echo "All alias drift checks passed." | |
| audit: | |
| name: Security Audit | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - uses: rustsec/audit-check@v2 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| workflow-secret-safety: | |
| name: Workflow Secret Safety | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Block known secret-leak patterns in workflows | |
| run: | | |
| set -euo pipefail | |
| # Prevent credentials embedded in URLs (high leak risk in logs/config). | |
| if grep -RInE 'https://[^/@[:space:]]+@github[.]com' .github/workflows; then | |
| echo "ERROR: Credential-in-URL pattern found in workflow files." | |
| exit 1 | |
| fi | |
| # Prevent direct printing of expressions that evaluate from secrets. | |
| if grep -RInE 'echo[[:space:]].*\$\{\{[[:space:]]*secrets\.' .github/workflows; then | |
| echo "ERROR: Direct echo of secrets expression found in workflow files." | |
| exit 1 | |
| fi | |
| # Prevent shell xtrace in workflow scripts. | |
| if grep -RInE '(^|[[:space:];])set[[:space:]]+-[a-wyzA-WYZ]*x|bash[[:space:]]+-[a-wyzA-WYZ]*x' .github/workflows; then | |
| echo "ERROR: Shell xtrace detected in workflow files." | |
| exit 1 | |
| fi | |
| build-release-assets: | |
| name: Build Release Asset (${{ matrix.target }}) | |
| needs: [test, coverage, alias-drift-check, audit, workflow-secret-safety] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - target: x86_64-unknown-linux-gnu | |
| os: ubuntu-latest | |
| artifact_name: git-same | |
| asset_name: git-same-linux-x86_64 | |
| - target: aarch64-unknown-linux-gnu | |
| os: ubuntu-24.04-arm | |
| artifact_name: git-same | |
| asset_name: git-same-linux-aarch64 | |
| - target: x86_64-apple-darwin | |
| os: macos-latest | |
| artifact_name: git-same | |
| asset_name: git-same-macos-x86_64 | |
| - target: aarch64-apple-darwin | |
| os: macos-latest | |
| artifact_name: git-same | |
| asset_name: git-same-macos-aarch64 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build | |
| run: cargo +stable build --release --target ${{ matrix.target }} | |
| - name: Rename binary | |
| shell: bash | |
| run: | | |
| mv target/${{ matrix.target }}/release/${{ matrix.artifact_name }} ${{ matrix.asset_name }} | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.asset_name }} | |
| path: ${{ matrix.asset_name }} | |
| publish-release: | |
| name: Publish GitHub Release | |
| needs: [build-release-assets] | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/') | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Require tag in semantic version format | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| if ! [[ "$TAG" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then | |
| echo "Tag must be strict semver only, no leading zeros (e.g., 1.0.0). Got: $TAG" | |
| exit 1 | |
| fi | |
| - name: Download built artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Collect release assets | |
| shell: bash | |
| run: | | |
| mkdir -p release-assets | |
| find artifacts -type f -exec cp {} release-assets/ \; | |
| - name: Create/update release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: release-assets/* | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |