chore(deps): bump tokio from 1.50.0 to 1.51.1 #93
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
| # CI — Checks, Build, Sign, Release | |
| # | |
| # Branch-aware: same workflow on develop and main. | |
| # develop → alpha channel (forestage-a), alpha pre-release | |
| # main → stable channel (forestage), stable pre-release | |
| # Tagged releases (v*) are handled by release.yml. | |
| name: CI | |
| on: | |
| push: | |
| branches: [develop, main] | |
| paths-ignore: | |
| - '*.md' | |
| - 'docs/**' | |
| - 'LICENSE' | |
| - 'CREDITS.md' | |
| - '.gitignore' | |
| - 'sources.toml' | |
| - '_kos/**' | |
| - '.github/workflows/release.yml' | |
| - '.github/workflows/release-verify.yml' | |
| pull_request: | |
| branches: [develop, main] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| CARGO_INCREMENTAL: 0 | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| # ── Branch config ───────────────────────────────────────────────────── | |
| # Derive channel-specific values from the branch name. | |
| # All downstream jobs reference these outputs. | |
| config: | |
| name: Config | |
| runs-on: ubuntu-latest | |
| outputs: | |
| is_alpha: ${{ steps.cfg.outputs.is_alpha }} | |
| channel: ${{ steps.cfg.outputs.channel }} | |
| binary_prefix: ${{ steps.cfg.outputs.binary_prefix }} | |
| tag_prefix: ${{ steps.cfg.outputs.tag_prefix }} | |
| release_title: ${{ steps.cfg.outputs.release_title }} | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - name: Set config from branch | |
| id: cfg | |
| run: | | |
| if [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then | |
| echo "is_alpha=true" >> "$GITHUB_OUTPUT" | |
| echo "channel=alpha" >> "$GITHUB_OUTPUT" | |
| echo "binary_prefix=forestage-a" >> "$GITHUB_OUTPUT" | |
| echo "tag_prefix=alpha" >> "$GITHUB_OUTPUT" | |
| echo "release_title=Alpha" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is_alpha=false" >> "$GITHUB_OUTPUT" | |
| echo "channel=stable" >> "$GITHUB_OUTPUT" | |
| echo "binary_prefix=forestage" >> "$GITHUB_OUTPUT" | |
| echo "tag_prefix=stable" >> "$GITHUB_OUTPUT" | |
| echo "release_title=Stable" >> "$GITHUB_OUTPUT" | |
| fi | |
| # ── Checks ──────────────────────────────────────────────────────────── | |
| check-fmt: | |
| name: Rustfmt | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 1 | |
| - uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly | |
| with: | |
| toolchain: nightly | |
| components: rustfmt | |
| - uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2 | |
| with: | |
| cache-on-failure: true | |
| - run: cargo +nightly fmt --all -- --check | |
| check-clippy: | |
| name: Clippy | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 1 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: stable | |
| components: clippy | |
| - uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2 | |
| with: | |
| cache-on-failure: true | |
| - run: cargo clippy --all-targets --all-features -- -D warnings | |
| test: | |
| name: Test | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 1 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: stable | |
| - uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2 | |
| with: | |
| cache-on-failure: true | |
| - run: cargo test --all-targets | |
| deny: | |
| name: Cargo Deny | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 1 | |
| - uses: EmbarkStudios/cargo-deny-action@82eb9f621fbc699dd0918f3ea06864c14cc84246 # v2 | |
| with: | |
| command: check advisories licenses bans | |
| # ── Build ───────────────────────────────────────────────────────────── | |
| build: | |
| name: Build (${{ matrix.target }}) | |
| needs: [config, check-fmt, check-clippy, test, deny] | |
| if: github.event_name == 'push' | |
| strategy: | |
| matrix: | |
| include: | |
| - target: aarch64-apple-darwin | |
| os: macos-latest | |
| artifact_name: forestage-darwin-arm64 | |
| - target: x86_64-unknown-linux-gnu | |
| os: ubuntu-latest | |
| artifact_name: forestage-linux-amd64 | |
| - target: aarch64-unknown-linux-gnu | |
| os: ubuntu-24.04-arm | |
| artifact_name: forestage-linux-arm64 | |
| runs-on: ${{ matrix.os }} | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| tag: ${{ steps.version.outputs.tag }} | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 1 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: stable | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2 | |
| with: | |
| cache-on-failure: true | |
| - name: Extract version | |
| id: version | |
| run: | | |
| VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') | |
| TAG="${{ needs.config.outputs.tag_prefix }}-$(date -u +%Y%m%d-%H%M%S)-$(echo ${{ github.sha }} | head -c 7)" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| - name: Build binary | |
| env: | |
| FORESTAGE_CHANNEL: ${{ needs.config.outputs.channel }} | |
| FORESTAGE_TAG: ${{ steps.version.outputs.tag }} | |
| run: | | |
| cargo build --release --target ${{ matrix.target }} | |
| # Derive the output binary name from the artifact name and binary prefix | |
| OUTPUT=$(echo "${{ matrix.artifact_name }}" | sed "s/forestage/${{ needs.config.outputs.binary_prefix }}/") | |
| cp target/${{ matrix.target }}/release/forestage "$OUTPUT" | |
| - name: Verify binary | |
| run: | | |
| OUTPUT=$(echo "${{ matrix.artifact_name }}" | sed "s/forestage/${{ needs.config.outputs.binary_prefix }}/") | |
| ./"$OUTPUT" --version | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 | |
| with: | |
| name: binaries-${{ matrix.artifact_name }} | |
| path: ${{ needs.config.outputs.binary_prefix }}-* | |
| # ── Sign & Notarize ─────────────────────────────────────────────────── | |
| sign-and-notarize: | |
| name: Sign & Notarize | |
| needs: [config, build] | |
| if: vars.SIGNING_ENABLED == 'true' | |
| permissions: | |
| contents: write | |
| environment: release | |
| strategy: | |
| matrix: | |
| arch: [arm64] | |
| runs-on: macos-latest | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - name: Download binaries | |
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 | |
| with: | |
| name: binaries-forestage-darwin-${{ matrix.arch }} | |
| - name: Import certificates | |
| env: | |
| APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_INSTALLER_CERTIFICATE_P12: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_P12 }} | |
| APPLE_INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_PASSWORD }} | |
| run: | | |
| security create-keychain -p "" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "" build.keychain | |
| echo "$APPLE_CERTIFICATE_P12" | base64 --decode > cert.p12 | |
| security import cert.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| rm cert.p12 | |
| echo "$APPLE_INSTALLER_CERTIFICATE_P12" | base64 --decode > installer-cert.p12 | |
| security import installer-cert.p12 -k build.keychain -P "$APPLE_INSTALLER_CERTIFICATE_PASSWORD" -T /usr/bin/pkgbuild -T /usr/bin/productbuild -T /usr/bin/productsign | |
| rm installer-cert.p12 | |
| curl -sfo /tmp/DeveloperIDG2CA.cer https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer | |
| security add-certificates -k build.keychain /tmp/DeveloperIDG2CA.cer | |
| rm /tmp/DeveloperIDG2CA.cer | |
| security set-key-partition-list -S apple-tool:,apple: -s -k "" build.keychain | |
| - name: Sign binary | |
| env: | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| BINARY: ${{ needs.config.outputs.binary_prefix }}-darwin-${{ matrix.arch }} | |
| run: | | |
| codesign --force --options runtime \ | |
| --sign "$APPLE_SIGNING_IDENTITY" \ | |
| --timestamp \ | |
| "$BINARY" | |
| - name: Verify signature | |
| run: codesign --verify --deep --strict ${{ needs.config.outputs.binary_prefix }}-darwin-${{ matrix.arch }} | |
| - name: Build app bundle | |
| run: | | |
| VERSION="${{ needs.build.outputs.version }}" | |
| chmod +x scripts/create-app.sh | |
| ./scripts/create-app.sh ${{ needs.config.outputs.binary_prefix }}-darwin-${{ matrix.arch }} "$VERSION" . | |
| mv Forestage.app Forestage-${{ matrix.arch }}.app | |
| - name: Sign app bundle | |
| env: | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| run: | | |
| codesign --force --deep --options runtime \ | |
| --sign "$APPLE_SIGNING_IDENTITY" \ | |
| --timestamp \ | |
| Forestage-${{ matrix.arch }}.app | |
| - name: Build dmg | |
| run: | | |
| VERSION="${{ needs.build.outputs.version }}" | |
| chmod +x scripts/create-dmg.sh | |
| ./scripts/create-dmg.sh Forestage-${{ matrix.arch }}.app "$VERSION" forestage-${{ matrix.arch }}.dmg | |
| - name: Build pkg | |
| env: | |
| APPLE_INSTALLER_IDENTITY: ${{ secrets.APPLE_INSTALLER_IDENTITY }} | |
| run: | | |
| if ! security find-identity -v build.keychain | grep -q "$APPLE_INSTALLER_IDENTITY"; then | |
| echo "::error::APPLE_INSTALLER_IDENTITY not found in keychain" | |
| security find-identity -v build.keychain | |
| exit 1 | |
| fi | |
| VERSION="${{ needs.build.outputs.version }}" | |
| chmod +x scripts/create-pkg.sh | |
| ./scripts/create-pkg.sh ${{ needs.config.outputs.binary_prefix }}-darwin-${{ matrix.arch }} "$VERSION" "$APPLE_INSTALLER_IDENTITY" forestage-${{ matrix.arch }}.pkg | |
| - name: Notarize and staple | |
| env: | |
| APPLE_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_NOTARIZATION_APPLE_ID }} | |
| APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }} | |
| APPLE_NOTARIZATION_TEAM_ID: ${{ secrets.APPLE_NOTARIZATION_TEAM_ID }} | |
| run: | | |
| for ARTIFACT in forestage-${{ matrix.arch }}.pkg forestage-${{ matrix.arch }}.dmg; do | |
| echo "Notarizing $ARTIFACT..." | |
| xcrun notarytool submit "$ARTIFACT" \ | |
| --apple-id "$APPLE_NOTARIZATION_APPLE_ID" \ | |
| --password "$APPLE_NOTARIZATION_PASSWORD" \ | |
| --team-id "$APPLE_NOTARIZATION_TEAM_ID" \ | |
| --wait --timeout 14400 | |
| xcrun stapler staple "$ARTIFACT" | |
| done | |
| - name: Upload signed artifacts | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 | |
| with: | |
| name: signed-binaries-darwin-${{ matrix.arch }} | |
| path: | | |
| ${{ needs.config.outputs.binary_prefix }}-darwin-${{ matrix.arch }} | |
| forestage-${{ matrix.arch }}.pkg | |
| forestage-${{ matrix.arch }}.dmg | |
| retention-days: 14 | |
| - name: Cleanup keychain | |
| if: always() | |
| run: security delete-keychain build.keychain || true | |
| # ── Release ─────────────────────────────────────────────────────────── | |
| create-release: | |
| name: Create ${{ needs.config.outputs.release_title }} Release | |
| needs: [config, build, sign-and-notarize] | |
| if: | | |
| always() && | |
| needs.build.result == 'success' && | |
| (needs.sign-and-notarize.result == 'success' || needs.sign-and-notarize.result == 'skipped') | |
| permissions: | |
| contents: write | |
| environment: release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - name: Download macOS arm64 | |
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 | |
| with: | |
| name: ${{ needs.sign-and-notarize.result == 'success' && 'signed-binaries-darwin-arm64' || 'binaries-forestage-darwin-arm64' }} | |
| path: dist/ | |
| - name: Download Linux amd64 | |
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 | |
| with: | |
| name: binaries-forestage-linux-amd64 | |
| path: dist/ | |
| - name: Download Linux arm64 | |
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 | |
| with: | |
| name: binaries-forestage-linux-arm64 | |
| path: dist/ | |
| - name: List release files | |
| run: ls -la dist/ | |
| - name: Create pre-release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="${{ needs.build.outputs.tag }}" | |
| TITLE="${{ needs.config.outputs.release_title }}" | |
| PREFIX="${{ needs.config.outputs.binary_prefix }}" | |
| gh release create "$TAG" \ | |
| --repo "${{ github.repository }}" \ | |
| --prerelease \ | |
| --title "$TITLE: $TAG" \ | |
| --notes "$(cat <<NOTES | |
| Automated $TITLE release. | |
| **Version:** ${{ needs.build.outputs.version }} | |
| **Commit:** ${{ github.sha }} | |
| **Branch:** ${{ github.ref_name }} | |
| **Built with:** Rust (cargo) | |
| **Signed:** ${{ needs.sign-and-notarize.result == 'success' && 'Yes (Apple Developer ID)' || 'No (unsigned)' }} | |
| **Binaries:** | |
| - \`${PREFIX}-darwin-arm64\` — macOS Apple Silicon | |
| - \`${PREFIX}-linux-amd64\` — Linux x86_64 | |
| - \`${PREFIX}-linux-arm64\` — Linux ARM64 | |
| NOTES | |
| )" \ | |
| dist/* | |
| - name: Clean old pre-releases (keep 30) | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh release list --repo "${{ github.repository }}" \ | |
| --json tagName,isPrerelease \ | |
| --jq '[.[] | select(.isPrerelease)] | sort_by(.tagName) | reverse | .[30:] | .[].tagName' \ | |
| | while read -r tag; do | |
| echo "Deleting old pre-release: $tag" | |
| gh release delete "$tag" --repo "${{ github.repository }}" --yes --cleanup-tag | |
| done | |
| # ── Homebrew (alpha only) ───────────────────────────────────────────── | |
| update-homebrew: | |
| name: Update Homebrew Tap | |
| needs: [config, build, sign-and-notarize, create-release] | |
| if: needs.create-release.result == 'success' && needs.sign-and-notarize.result == 'success' && needs.config.outputs.is_alpha == 'true' | |
| permissions: | |
| contents: write | |
| environment: release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| - name: Download signed darwin binaries | |
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 | |
| with: | |
| name: signed-binaries-darwin-arm64 | |
| path: dist/ | |
| - name: Update Homebrew formula | |
| env: | |
| HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| run: | | |
| TAG="${{ needs.build.outputs.tag }}" | |
| VERSION="${{ needs.build.outputs.version }}" | |
| SHA256_ARM64=$(shasum -a 256 dist/forestage-a-darwin-arm64 | cut -d' ' -f1) | |
| git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/arcavenae/homebrew-tap.git" homebrew-tap-repo | |
| cd homebrew-tap-repo | |
| mkdir -p Formula | |
| cp ../Formula/forestage-a.rb Formula/forestage-a.rb | |
| sed -i "s/VERSION_PLACEHOLDER/$TAG/g" Formula/forestage-a.rb | |
| sed -i "s/TAG_PLACEHOLDER/$TAG/g" Formula/forestage-a.rb | |
| sed -i "s/SHA256_ARM64_PLACEHOLDER/$SHA256_ARM64/g" Formula/forestage-a.rb | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Formula/forestage-a.rb | |
| git diff --cached --quiet || git commit -m "Update forestage-a to $TAG" | |
| git push |