diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 14ca2f67a..d4f7c4145 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -34,10 +34,7 @@ jobs: with: path: | ~/.bun/install/cache - frontend/node_modules key: ${{ runner.os }}-bun-${{ hashFiles('frontend/bun.lock') }} - restore-keys: | - ${{ runner.os }}-bun- - name: Install Rust uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # was stable @@ -90,14 +87,11 @@ jobs: with: path: ~/.cargo/bin/ key: ${{ runner.os }}-cargo-bin-tauri-cli-2.11.1 - restore-keys: | - ${{ runner.os }}-cargo-bin-tauri-cli- - ${{ runner.os }}-cargo-bin- - name: Install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y libssl-dev + sudo apt-get install -y --no-install-recommends libssl-dev - name: Install frontend dependencies working-directory: ./frontend diff --git a/.github/workflows/android-pr-build.yml b/.github/workflows/android-pr-build.yml index 1dac933e7..a0ff6f197 100644 --- a/.github/workflows/android-pr-build.yml +++ b/.github/workflows/android-pr-build.yml @@ -34,10 +34,7 @@ jobs: with: path: | ~/.bun/install/cache - frontend/node_modules key: ${{ runner.os }}-bun-${{ hashFiles('frontend/bun.lock') }} - restore-keys: | - ${{ runner.os }}-bun- - name: Install Rust uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # was stable @@ -90,14 +87,11 @@ jobs: with: path: ~/.cargo/bin/ key: ${{ runner.os }}-cargo-bin-tauri-cli-2.11.1 - restore-keys: | - ${{ runner.os }}-cargo-bin-tauri-cli- - ${{ runner.os }}-cargo-bin- - name: Install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y libssl-dev + sudo apt-get install -y --no-install-recommends libssl-dev - name: Install frontend dependencies working-directory: ./frontend diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index b6dea68b7..916257f80 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -34,16 +34,33 @@ jobs: with: path: | ~/Library/Caches/Homebrew - /opt/homebrew/Cellar/sccache /opt/homebrew/Cellar/openssl@3 key: ${{ runner.os }}-brew-${{ hashFiles('.github/workflows/desktop-build.yml') }} - restore-keys: | - ${{ runner.os }}-brew- - name: Install sccache run: | - brew install sccache - brew link --overwrite --force sccache + SCCACHE_VERSION=0.8.2 + case "$(uname -m)" in + arm64) + SCCACHE_TARGET="aarch64-apple-darwin" + SCCACHE_SHA256="32604da614ce679623a8de0d38eab91b87431d59f3344c5523c82e1b6e85ffc4" + ;; + x86_64) + SCCACHE_TARGET="x86_64-apple-darwin" + SCCACHE_SHA256="fcbe1b76356f7183cee0b5bc150c0583abc01a5c42e9b2be94e9d17ed7dca3a4" + ;; + *) + echo "Unsupported macOS architecture: $(uname -m)" >&2 + exit 1 + ;; + esac + SCCACHE_ARCHIVE="sccache-v${SCCACHE_VERSION}-${SCCACHE_TARGET}.tar.gz" + SCCACHE_URL="https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/${SCCACHE_ARCHIVE}" + curl --fail --location --show-error --silent "$SCCACHE_URL" --output "$SCCACHE_ARCHIVE" + echo "${SCCACHE_SHA256} ${SCCACHE_ARCHIVE}" | shasum -a 256 -c - + tar xzf "$SCCACHE_ARCHIVE" + sudo mv "sccache-v${SCCACHE_VERSION}-${SCCACHE_TARGET}/sccache" /usr/local/bin/ + chmod +x /usr/local/bin/sccache sccache --version - name: Cache sccache @@ -163,14 +180,11 @@ jobs: with: path: ~/.cargo/bin/ key: ${{ runner.os }}-cargo-bin-tauri-cli-2.11.1 - restore-keys: | - ${{ runner.os }}-cargo-bin-tauri-cli- - ${{ runner.os }}-cargo-bin- - name: Install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.1-dev \ + sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev \ libssl-dev \ libgtk-3-dev \ libayatana-appindicator3-dev \ diff --git a/.github/workflows/desktop-pr-build.yml b/.github/workflows/desktop-pr-build.yml index 90af9b7fa..e63185312 100644 --- a/.github/workflows/desktop-pr-build.yml +++ b/.github/workflows/desktop-pr-build.yml @@ -34,16 +34,33 @@ jobs: with: path: | ~/Library/Caches/Homebrew - /opt/homebrew/Cellar/sccache /opt/homebrew/Cellar/openssl@3 key: ${{ runner.os }}-brew-${{ hashFiles('.github/workflows/desktop-build.yml') }} - restore-keys: | - ${{ runner.os }}-brew- - name: Install sccache run: | - brew install sccache - brew link --overwrite --force sccache + SCCACHE_VERSION=0.8.2 + case "$(uname -m)" in + arm64) + SCCACHE_TARGET="aarch64-apple-darwin" + SCCACHE_SHA256="32604da614ce679623a8de0d38eab91b87431d59f3344c5523c82e1b6e85ffc4" + ;; + x86_64) + SCCACHE_TARGET="x86_64-apple-darwin" + SCCACHE_SHA256="fcbe1b76356f7183cee0b5bc150c0583abc01a5c42e9b2be94e9d17ed7dca3a4" + ;; + *) + echo "Unsupported macOS architecture: $(uname -m)" >&2 + exit 1 + ;; + esac + SCCACHE_ARCHIVE="sccache-v${SCCACHE_VERSION}-${SCCACHE_TARGET}.tar.gz" + SCCACHE_URL="https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/${SCCACHE_ARCHIVE}" + curl --fail --location --show-error --silent "$SCCACHE_URL" --output "$SCCACHE_ARCHIVE" + echo "${SCCACHE_SHA256} ${SCCACHE_ARCHIVE}" | shasum -a 256 -c - + tar xzf "$SCCACHE_ARCHIVE" + sudo mv "sccache-v${SCCACHE_VERSION}-${SCCACHE_TARGET}/sccache" /usr/local/bin/ + chmod +x /usr/local/bin/sccache sccache --version - name: Cache sccache @@ -131,14 +148,11 @@ jobs: with: path: ~/.cargo/bin/ key: ${{ runner.os }}-cargo-bin-tauri-cli-2.11.1 - restore-keys: | - ${{ runner.os }}-cargo-bin-tauri-cli- - ${{ runner.os }}-cargo-bin- - name: Install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.1-dev \ + sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev \ libssl-dev \ libgtk-3-dev \ libayatana-appindicator3-dev \ diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml index 6fb54d5d7..b63ae8b35 100644 --- a/.github/workflows/frontend-tests.yml +++ b/.github/workflows/frontend-tests.yml @@ -27,10 +27,7 @@ jobs: with: path: | ~/.bun/install/cache - frontend/node_modules key: ${{ runner.os }}-bun-${{ hashFiles('frontend/bun.lock') }} - restore-keys: | - ${{ runner.os }}-bun- - name: Install dependencies working-directory: ./frontend diff --git a/.github/workflows/mobile-build.yml b/.github/workflows/mobile-build.yml index d3c97677a..25eef63d1 100644 --- a/.github/workflows/mobile-build.yml +++ b/.github/workflows/mobile-build.yml @@ -38,8 +38,6 @@ jobs: ~/Library/Caches/Homebrew /opt/homebrew/Cellar/openssl@3 key: ${{ runner.os }}-brew-${{ hashFiles('.github/workflows/mobile-build.yml') }} - restore-keys: | - ${{ runner.os }}-brew- - name: Cache Xcode DerivedData and SourcePackages uses: irgaly/xcode-cache@4141f139f00e335c6e1031fb93e667181f86146f # was v1 @@ -54,9 +52,6 @@ jobs: with: path: ~/.cargo/bin/ key: ${{ runner.os }}-cargo-bin-tauri-cli-2.11.1 - restore-keys: | - ${{ runner.os }}-cargo-bin-tauri-cli- - ${{ runner.os }}-cargo-bin- - name: Install frontend dependencies working-directory: ./frontend diff --git a/.github/workflows/mobile-pr-build.yml b/.github/workflows/mobile-pr-build.yml index 2571ac903..b2888353a 100644 --- a/.github/workflows/mobile-pr-build.yml +++ b/.github/workflows/mobile-pr-build.yml @@ -38,8 +38,6 @@ jobs: ~/Library/Caches/Homebrew /opt/homebrew/Cellar/openssl@3 key: ${{ runner.os }}-brew-${{ hashFiles('.github/workflows/mobile-build.yml') }} - restore-keys: | - ${{ runner.os }}-brew- - name: Cache Xcode DerivedData and SourcePackages uses: irgaly/xcode-cache@4141f139f00e335c6e1031fb93e667181f86146f # was v1 @@ -54,9 +52,6 @@ jobs: with: path: ~/.cargo/bin/ key: ${{ runner.os }}-cargo-bin-tauri-cli-2.11.1 - restore-keys: | - ${{ runner.os }}-cargo-bin-tauri-cli- - ${{ runner.os }}-cargo-bin- - name: Install frontend dependencies working-directory: ./frontend diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4902ed392..be5da4284 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,11 +4,13 @@ on: types: [created] permissions: - contents: write + contents: read jobs: create-release: runs-on: ubuntu-latest + permissions: + contents: read outputs: release_id: ${{ steps.get_version.outputs.version }} @@ -22,12 +24,30 @@ jobs: with: bun-version: 1.3.5 - - name: Get version + - name: Validate release tag id: get_version - run: echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} + run: | + if [ -z "$RELEASE_TAG" ] || [ "$RELEASE_TAG" != "${GITHUB_REF#refs/tags/}" ]; then + echo "Release tag does not match GITHUB_REF" >&2 + exit 1 + fi + + if [[ ! "$RELEASE_TAG" =~ ^v?[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?([+][0-9A-Za-z.-]+)?$ ]]; then + echo "Refusing to build unexpected release tag: $RELEASE_TAG" >&2 + exit 1 + fi + + echo "version=$RELEASE_TAG" >> "$GITHUB_OUTPUT" build-tauri: needs: create-release + permissions: + contents: write + id-token: write + attestations: write + artifact-metadata: write strategy: fail-fast: false matrix: @@ -60,17 +80,34 @@ jobs: with: path: | ~/Library/Caches/Homebrew - /opt/homebrew/Cellar/sccache /opt/homebrew/Cellar/openssl@3 key: ${{ runner.os }}-brew-${{ hashFiles('.github/workflows/release.yml') }} - restore-keys: | - ${{ runner.os }}-brew- - name: Install sccache (macOS) if: matrix.platform == 'macos-latest-xlarge' run: | - brew install sccache - brew link --overwrite --force sccache + SCCACHE_VERSION=0.8.2 + case "$(uname -m)" in + arm64) + SCCACHE_TARGET="aarch64-apple-darwin" + SCCACHE_SHA256="32604da614ce679623a8de0d38eab91b87431d59f3344c5523c82e1b6e85ffc4" + ;; + x86_64) + SCCACHE_TARGET="x86_64-apple-darwin" + SCCACHE_SHA256="fcbe1b76356f7183cee0b5bc150c0583abc01a5c42e9b2be94e9d17ed7dca3a4" + ;; + *) + echo "Unsupported macOS architecture: $(uname -m)" >&2 + exit 1 + ;; + esac + SCCACHE_ARCHIVE="sccache-v${SCCACHE_VERSION}-${SCCACHE_TARGET}.tar.gz" + SCCACHE_URL="https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/${SCCACHE_ARCHIVE}" + curl --fail --location --show-error --silent "$SCCACHE_URL" --output "$SCCACHE_ARCHIVE" + echo "${SCCACHE_SHA256} ${SCCACHE_ARCHIVE}" | shasum -a 256 -c - + tar xzf "$SCCACHE_ARCHIVE" + sudo mv "sccache-v${SCCACHE_VERSION}-${SCCACHE_TARGET}/sccache" /usr/local/bin/ + chmod +x /usr/local/bin/sccache sccache --version - name: Install sccache (Linux) @@ -100,7 +137,7 @@ jobs: if: matrix.platform == 'ubuntu-latest-8-cores' run: | sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.1-dev \ + sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev \ libssl-dev \ libgtk-3-dev \ libayatana-appindicator3-dev \ @@ -140,17 +177,50 @@ jobs: VITE_CLIENT_ID: ba5a14b5-d915-47b1-b7b1-afda52bc5fc6 with: projectPath: './frontend' - tagName: ${{ github.ref_name }} - releaseName: 'Maple v${{ github.ref_name }}' + tagName: ${{ github.event.release.tag_name }} + releaseName: 'Maple v${{ github.event.release.tag_name }}' releaseBody: 'See the assets to download this version and install.' releaseDraft: true prerelease: false args: ${{ matrix.args }} assetNamePattern: '[name]_[version]_[arch].[ext]' + - name: Record desktop release artifact checksums + run: | + hash_artifact() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" + else + shasum -a 256 "$1" + fi + } + + find frontend/src-tauri/target -type f \( \ + -name "*.dmg" -o \ + -name "*.app.tar.gz" -o \ + -name "*.app.tar.gz.sig" -o \ + -name "*.AppImage" -o \ + -name "*.AppImage.sig" -o \ + -name "*.deb" \ + \) -print | sort | while IFS= read -r artifact; do + hash_artifact "$artifact" + done > desktop-release-artifacts.sha256 + test -s desktop-release-artifacts.sha256 + cat desktop-release-artifacts.sha256 + + - name: Attest desktop release artifacts + uses: actions/attest@281a49d4cbb0a72c9575a50d18f6deb515a11deb # was v4 + with: + subject-checksums: desktop-release-artifacts.sha256 + build-android: needs: create-release runs-on: ubuntu-latest-8-cores + permissions: + contents: write + id-token: write + attestations: write + artifact-metadata: write steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # was v4 with: @@ -175,10 +245,7 @@ jobs: with: path: | ~/.bun/install/cache - frontend/node_modules key: ${{ runner.os }}-bun-${{ hashFiles('frontend/bun.lock') }} - restore-keys: | - ${{ runner.os }}-bun- - name: Install Rust uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # was stable @@ -231,14 +298,11 @@ jobs: with: path: ~/.cargo/bin/ key: ${{ runner.os }}-cargo-bin-tauri-cli-2.11.1 - restore-keys: | - ${{ runner.os }}-cargo-bin-tauri-cli- - ${{ runner.os }}-cargo-bin- - name: Install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y libssl-dev + sudo apt-get install -y --no-install-recommends libssl-dev - name: Install frontend dependencies working-directory: ./frontend @@ -357,25 +421,45 @@ jobs: VITE_MAPLE_BILLING_API_URL: https://billing.opensecret.cloud VITE_CLIENT_ID: ba5a14b5-d915-47b1-b7b1-afda52bc5fc6 + - name: Record Android release artifact checksums + run: | + sha256sum \ + frontend/src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk \ + frontend/src-tauri/gen/android/app/build/outputs/bundle/universalRelease/app-universal-release.aab \ + > android-release-artifacts.sha256 + cat android-release-artifacts.sha256 + + - name: Attest Android release artifacts + uses: actions/attest@281a49d4cbb0a72c9575a50d18f6deb515a11deb # was v4 + with: + subject-checksums: android-release-artifacts.sha256 + - name: Upload Android APK to Release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | - gh release upload ${{ github.ref_name }} \ + gh release upload "$RELEASE_TAG" \ frontend/src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk \ --clobber - name: Upload Android AAB to Release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | - gh release upload ${{ github.ref_name }} \ + gh release upload "$RELEASE_TAG" \ frontend/src-tauri/gen/android/app/build/outputs/bundle/universalRelease/app-universal-release.aab \ --clobber update-latest-json: needs: build-tauri runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + attestations: write + artifact-metadata: write steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # was v4 with: @@ -384,14 +468,17 @@ jobs: - name: Download release artifacts env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | mkdir -p artifacts - gh release download ${{ github.ref_name }} -D artifacts + gh release download "$RELEASE_TAG" -D artifacts - name: Generate latest.json id: generate-latest + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | - VERSION="${{ github.ref_name }}" + VERSION="$RELEASE_TAG" RELEASE_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # Get signatures from the artifacts @@ -426,8 +513,14 @@ jobs: } EOF + - name: Attest latest.json + uses: actions/attest@281a49d4cbb0a72c9575a50d18f6deb515a11deb # was v4 + with: + subject-path: latest.json + - name: Upload latest.json env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | - gh release upload ${{ github.ref_name }} latest.json --clobber + gh release upload "$RELEASE_TAG" latest.json --clobber diff --git a/.github/workflows/zapstore-publish.yml b/.github/workflows/zapstore-publish.yml index 70f06d197..41580e34c 100644 --- a/.github/workflows/zapstore-publish.yml +++ b/.github/workflows/zapstore-publish.yml @@ -10,7 +10,10 @@ permissions: jobs: publish: - if: github.event.workflow_run.conclusion == 'success' + if: >- + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'release' && + github.event.workflow_run.head_repository.full_name == github.repository runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # was v4 @@ -25,6 +28,10 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ github.event.workflow_run.head_branch }} run: | + if [[ ! "$RELEASE_TAG" =~ ^v?[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?([+][0-9A-Za-z.-]+)?$ ]]; then + echo "Refusing to publish from unexpected release tag: $RELEASE_TAG" >&2 + exit 1 + fi echo "Downloading APK from release $RELEASE_TAG" gh release download "$RELEASE_TAG" \ --pattern "app-universal-release.apk" \ @@ -36,6 +43,8 @@ jobs: go-version: "1.22.12" - name: Install zsp + env: + GOTOOLCHAIN: local run: | go install "github.com/zapstore/zsp@v0.4.5" echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" @@ -44,12 +53,18 @@ jobs: env: SIGN_WITH: ${{ secrets.ZAPSTORE_SIGN_WITH }} COMMIT_SHA: ${{ github.event.workflow_run.head_sha }} + GOTOOLCHAIN: local run: | if [ -z "${SIGN_WITH}" ]; then echo "Missing required secret: ZAPSTORE_SIGN_WITH" >&2 exit 1 fi + if [[ ! "$COMMIT_SHA" =~ ^[0-9a-f]{40}$ ]]; then + echo "Refusing to publish with unexpected commit SHA: $COMMIT_SHA" >&2 + exit 1 + fi + set +e output="$( zsp publish \ diff --git a/frontend/bun.lockb b/frontend/bun.lockb deleted file mode 100755 index d43d39d7b..000000000 Binary files a/frontend/bun.lockb and /dev/null differ