diff --git a/.github/workflows/flathub.yml b/.github/workflows/flathub.yml index 98d95e02..5ecad626 100644 --- a/.github/workflows/flathub.yml +++ b/.github/workflows/flathub.yml @@ -16,6 +16,21 @@ jobs: - name: Checkout app repo uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install source generators + run: | + pip install flatpak-node-generator tomlkit aiohttp + git clone --depth 1 https://github.com/flatpak/flatpak-builder-tools flatpak/flatpak-builder-tools + - name: Run update-manifest.sh run: bash flatpak/update-manifest.sh "${{ github.event.release.tag_name }}" @@ -29,6 +44,9 @@ jobs: - name: Copy updated files to Flathub repo run: | cp flatpak/app.yaak.Yaak.yml flathub-repo/ + cp flatpak/app.yaak.Yaak.metainfo.xml flathub-repo/ + cp flatpak/cargo-sources.json flathub-repo/ + cp flatpak/node-sources.json flathub-repo/ cp LICENSE flathub-repo/ sed -i 's|path: \.\./LICENSE|path: LICENSE|' flathub-repo/app.yaak.Yaak.yml diff --git a/.gitignore b/.gitignore index a8773a8a..40c48bd8 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,6 @@ crates-tauri/yaak-app/tauri.worktree.conf.json # Flatpak build artifacts flatpak-repo/ .flatpak-builder/ +flatpak/flatpak-builder-tools/ +flatpak/cargo-sources.json +flatpak/node-sources.json diff --git a/crates/yaak-templates/build-wasm.cjs b/crates/yaak-templates/build-wasm.cjs new file mode 100644 index 00000000..4f86941b --- /dev/null +++ b/crates/yaak-templates/build-wasm.cjs @@ -0,0 +1,8 @@ +const { execSync } = require('node:child_process'); + +if (process.env.SKIP_WASM_BUILD === '1') { + console.log('Skipping wasm-pack build (SKIP_WASM_BUILD=1)'); + return; +} + +execSync('wasm-pack build --target bundler', { stdio: 'inherit' }); diff --git a/crates/yaak-templates/package.json b/crates/yaak-templates/package.json index f4c75149..9826bfb6 100644 --- a/crates/yaak-templates/package.json +++ b/crates/yaak-templates/package.json @@ -6,7 +6,7 @@ "scripts": { "bootstrap": "npm run build", "build": "run-s build:*", - "build:pack": "wasm-pack build --target bundler", + "build:pack": "node build-wasm.cjs", "build:clean": "rimraf ./pkg/.gitignore" }, "devDependencies": { diff --git a/flatpak/app.yaak.Yaak.metainfo.xml b/flatpak/app.yaak.Yaak.metainfo.xml index 6fd4120d..83f52d38 100644 --- a/flatpak/app.yaak.Yaak.metainfo.xml +++ b/flatpak/app.yaak.Yaak.metainfo.xml @@ -52,6 +52,5 @@ - diff --git a/flatpak/app.yaak.Yaak.yml b/flatpak/app.yaak.Yaak.yml index ad4e5817..d5f6119c 100644 --- a/flatpak/app.yaak.Yaak.yml +++ b/flatpak/app.yaak.Yaak.yml @@ -3,6 +3,11 @@ runtime: org.gnome.Platform runtime-version: "49" sdk: org.gnome.Sdk command: yaak-app + +sdk-extensions: + - org.freedesktop.Sdk.Extension.node22 + - org.freedesktop.Sdk.Extension.rust-stable + rename-desktop-file: yaak.desktop rename-icon: yaak-app @@ -36,26 +41,135 @@ modules: - name: yaak buildsystem: simple + build-options: + append-path: /app/bin:/usr/lib/sdk/node22/bin:/usr/lib/sdk/rust-stable/bin + env: + CARGO_HOME: /run/build/yaak/cargo + XDG_CACHE_HOME: /run/build/yaak/flatpak-node/cache + npm_config_cache: /run/build/yaak/flatpak-node/npm-cache + npm_config_offline: "true" + npm_config_nodedir: /usr/lib/sdk/node22 + NODE_OPTIONS: --max_old_space_size=4096 + build-commands: - - ar -x yaak.deb - - tar -xf data.tar.gz - - mv usr/bin/* /app/bin - - mv usr/lib/* /app/lib - - mv usr/share/* /app/share + # Vendor Node.js binary (sidecar for plugin runtime) + - mkdir -p crates-tauri/yaak-app/vendored/node + - install -Dm755 vendored-node/bin/node crates-tauri/yaak-app/vendored/node/yaaknode + + # Vendor protoc binary and includes + - mkdir -p crates-tauri/yaak-app/vendored/protoc + - install -Dm755 protoc-bin/protoc crates-tauri/yaak-app/vendored/protoc/yaakprotoc + - mkdir -p crates-tauri/yaak-app/vendored/protoc/include && cp -r protoc-bin/google crates-tauri/yaak-app/vendored/protoc/include/google + + # Patch lockfile: add resolved URLs for nested workspace deps that npm + # omits (see https://github.com/npm/cli/issues/4460) + - >- + node -e "const fs=require('fs'); + const p='package-lock.json'; + const d=JSON.parse(fs.readFileSync(p,'utf-8')); + for(const[n,info]of Object.entries(d.packages||{})){ + if(!n||info.link||info.resolved||!n.includes('node_modules/')||!info.version)continue; + const pkg=n.split('node_modules/').pop(); + const base=pkg.split('/').pop(); + info.resolved='https://registry.npmjs.org/'+pkg+'/-/'+base+'-'+info.version+'.tgz'; + }fs.writeFileSync(p,JSON.stringify(d,null,2));" + + # Install npm dependencies offline + - npm ci --offline + + # Pre-fetch Cargo dependencies offline + - cargo --offline fetch --manifest-path Cargo.toml + + # Skip wasm-pack build (pre-built wasm is checked into the repo) + - >- + node -e "const fs=require('fs'); + const p='crates/yaak-templates/package.json'; + const d=JSON.parse(fs.readFileSync(p)); + d.scripts['build:pack']='echo Skipping wasm-pack build'; + fs.writeFileSync(p,JSON.stringify(d,null,2));" + + # Build all workspace packages (frontend, plugins, wasm, plugin-runtime) + - npm run build + + # Copy built plugins to vendored directory + - npm run vendor:vendor-plugins + + # Build the Tauri app (cargo build directly to avoid inotify limits from tauri CLI) + - cargo build --offline --release -p yaak-app + + # Install binary + - install -Dm755 target/release/yaak-app /app/bin/yaak-app + + # Install icons from source + - install -Dm644 crates-tauri/yaak-app/icons/release/32x32.png /app/share/icons/hicolor/32x32/apps/yaak-app.png + - install -Dm644 crates-tauri/yaak-app/icons/release/64x64.png /app/share/icons/hicolor/64x64/apps/yaak-app.png + - install -Dm644 crates-tauri/yaak-app/icons/release/128x128.png /app/share/icons/hicolor/128x128/apps/yaak-app.png + - install -Dm644 crates-tauri/yaak-app/icons/release/icon.png /app/share/icons/hicolor/512x512/apps/yaak-app.png + + # Install desktop file + - >- + printf '[Desktop Entry]\nCategories=Development;\nComment=The API client for modern developers\nExec=yaak-app\nIcon=yaak-app\nName=Yaak\nStartupWMClass=yaak\nTerminal=false\nType=Application\n' + > yaak.desktop + - install -Dm644 yaak.desktop /app/share/applications/yaak.desktop + + # Install metainfo and license + - install -Dm644 app.yaak.Yaak.metainfo.xml /app/share/metainfo/app.yaak.Yaak.metainfo.xml - install -Dm644 LICENSE /app/share/licenses/app.yaak.Yaak/LICENSE sources: - - type: file - dest-filename: yaak.deb - url: https://github.com/mountain-loop/yaak/releases/download/v2026.1.2/yaak_2026.1.2_amd64.deb - sha256: "c4236b5bcf391e579dc79b71c3b5c58f6f9bfc6c175fc70426d0ca85799beba5" + # Application source + - type: git + url: https://github.com/mountain-loop/yaak.git + tag: v2026.1.2 + commit: bd7e840a5700ddefb5ef1f22771cc5555000f777 + x-checker-data: + type: git + tag-pattern: ^v(\d+\.\d+\.\d+)$ + + # Offline npm dependencies + - node-sources.json + + # Offline Cargo dependencies + - cargo-sources.json + + # Vendored Node.js binary (x86_64) + - type: archive + url: https://nodejs.org/download/release/v24.11.1/node-v24.11.1-linux-x64.tar.gz + sha256: 58a5ff5cc8f2200e458bea22e329d5c1994aa1b111d499ca46ec2411d58239ca + strip-components: 1 + dest: vendored-node only-arches: - x86_64 - - type: file - dest-filename: yaak.deb - url: https://github.com/mountain-loop/yaak/releases/download/v2026.1.2/yaak_2026.1.2_arm64.deb - sha256: "9ba9b7c9df56ffb9b801e40cb38685f1650cf7e2f9e85dad0ae3329f8e01ff6d" + + # Vendored Node.js binary (aarch64) + - type: archive + url: https://nodejs.org/download/release/v24.11.1/node-v24.11.1-linux-arm64.tar.gz + sha256: 0dc93ec5c798b0d347f068db6d205d03dea9a71765e6a53922b682b91265d71f + strip-components: 1 + dest: vendored-node only-arches: - aarch64 + + # Vendored protoc binary and includes (x86_64) + - type: archive + url: https://github.com/protocolbuffers/protobuf/releases/download/v33.1/protoc-33.1-linux-x86_64.zip + sha256: f3340e28a83d1c637d8bafdeed92b9f7db6a384c26bca880a6e5217b40a4328b + dest: protoc-bin + only-arches: + - x86_64 + + # Vendored protoc binary and includes (aarch64) + - type: archive + url: https://github.com/protocolbuffers/protobuf/releases/download/v33.1/protoc-33.1-linux-aarch_64.zip + sha256: 6018147740548e0e0f764408c87f4cd040e6e1c1203e13aeacaf811892b604f3 + dest: protoc-bin + only-arches: + - aarch64 + + # License file - type: file path: ../LICENSE + + # Metainfo file (not in tagged source yet) + - type: file + path: app.yaak.Yaak.metainfo.xml diff --git a/flatpak/fix-lockfile.mjs b/flatpak/fix-lockfile.mjs new file mode 100644 index 00000000..aa3826de --- /dev/null +++ b/flatpak/fix-lockfile.mjs @@ -0,0 +1,73 @@ +#!/usr/bin/env node + +// Adds missing `resolved` and `integrity` fields to npm package-lock.json. +// +// npm sometimes omits these fields for nested dependencies inside workspace +// packages. This breaks offline installs and tools like flatpak-node-generator +// that need explicit tarball URLs for every package. +// +// Based on https://github.com/grant-dennison/npm-package-lock-add-resolved +// (MIT License, Copyright (c) 2024 Grant Dennison) + +import { readFile, writeFile } from "node:fs/promises"; +import { get } from "node:https"; + +const lockfilePath = process.argv[2] || "package-lock.json"; + +function fetchJson(url) { + return new Promise((resolve, reject) => { + get(url, (res) => { + let data = ""; + res.on("data", (chunk) => { + data += chunk; + }); + res.on("end", () => { + if (res.statusCode === 200) { + resolve(JSON.parse(data)); + } else { + reject(`${url} returned ${res.statusCode} ${res.statusMessage}`); + } + }); + res.on("error", reject); + }).on("error", reject); + }); +} + +async function fillResolved(name, p) { + const version = p.version.replace(/^.*@/, ""); + console.log(`Retrieving metadata for ${name}@${version}`); + const metadataUrl = `https://registry.npmjs.com/${name}/${version}`; + const metadata = await fetchJson(metadataUrl); + p.resolved = metadata.dist.tarball; + p.integrity = metadata.dist.integrity; +} + +let changesMade = false; + +async function fillAllResolved(packages) { + for (const packagePath in packages) { + if (packagePath === "") continue; + const p = packages[packagePath]; + if (!p.inBundle && !p.bundled && (!p.resolved || !p.integrity)) { + const packageName = + p.name || + /^npm:(.+?)@.+$/.exec(p.version)?.[1] || + packagePath.replace(/^.*node_modules\/(?=.+?$)/, ""); + await fillResolved(packageName, p); + changesMade = true; + } + } +} + +const oldContents = await readFile(lockfilePath, "utf-8"); +const packageLock = JSON.parse(oldContents); + +await fillAllResolved(packageLock.packages ?? []); + +if (changesMade) { + const newContents = JSON.stringify(packageLock, null, 2) + "\n"; + await writeFile(lockfilePath, newContents); + console.log(`Updated ${lockfilePath}`); +} else { + console.log("No changes needed."); +} diff --git a/flatpak/generate-sources.sh b/flatpak/generate-sources.sh new file mode 100755 index 00000000..f656d0aa --- /dev/null +++ b/flatpak/generate-sources.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# +# Generate offline dependency source files for Flatpak builds. +# +# Prerequisites: +# pip install flatpak-node-generator tomlkit aiohttp +# Clone https://github.com/flatpak/flatpak-builder-tools (for cargo generator) +# +# Usage: +# ./flatpak/generate-sources.sh + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Generate cargo-sources.json +python3 "$SCRIPT_DIR/flatpak-builder-tools/cargo/flatpak-cargo-generator.py" \ + -o "$SCRIPT_DIR/cargo-sources.json" "$REPO_ROOT/Cargo.lock" + +# Generate node-sources.json from a patched copy of the lockfile. +# npm omits resolved/integrity for some workspace deps, and +# flatpak-node-generator can't handle workspace link entries. +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +cp "$REPO_ROOT/package-lock.json" "$TMPDIR/package-lock.json" +cp "$REPO_ROOT/package.json" "$TMPDIR/package.json" + +node "$SCRIPT_DIR/fix-lockfile.mjs" "$TMPDIR/package-lock.json" + +node -e " + const fs = require('fs'); + const p = process.argv[1]; + const d = JSON.parse(fs.readFileSync(p, 'utf-8')); + for (const [name, info] of Object.entries(d.packages || {})) { + if (name && (info.link || !info.resolved)) delete d.packages[name]; + } + fs.writeFileSync(p, JSON.stringify(d, null, 2)); +" "$TMPDIR/package-lock.json" + +flatpak-node-generator --no-requests-cache \ + -o "$SCRIPT_DIR/node-sources.json" npm "$TMPDIR/package-lock.json" diff --git a/flatpak/update-manifest.sh b/flatpak/update-manifest.sh index e75c6186..1676365c 100755 --- a/flatpak/update-manifest.sh +++ b/flatpak/update-manifest.sh @@ -1,19 +1,19 @@ #!/usr/bin/env bash # -# Update the Flatpak manifest with URLs and SHA256 hashes for a given release. +# Update the Flatpak manifest for a new release. # # Usage: # ./flatpak/update-manifest.sh v2026.2.0 # # This script: -# 1. Downloads the x86_64 and aarch64 .deb files from the GitHub release -# 2. Computes their SHA256 checksums -# 3. Updates the manifest YAML with the correct URLs and hashes -# 4. Updates the metainfo.xml with a new entry +# 1. Updates the git tag and commit in the manifest +# 2. Regenerates cargo-sources.json and node-sources.json from the tagged lockfiles +# 3. Adds a new entry to the metainfo set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" MANIFEST="$SCRIPT_DIR/app.yaak.Yaak.yml" METAINFO="$SCRIPT_DIR/app.yaak.Yaak.metainfo.xml" @@ -26,57 +26,64 @@ fi VERSION_TAG="$1" VERSION="${VERSION_TAG#v}" -# Only allow stable releases (skip beta, alpha, rc, etc.) if [[ "$VERSION" == *-* ]]; then echo "Skipping pre-release version '$VERSION_TAG' (only stable releases are published to Flathub)" exit 0 fi REPO="mountain-loop/yaak" -BASE_URL="https://github.com/$REPO/releases/download/$VERSION_TAG" +COMMIT=$(git ls-remote "https://github.com/$REPO.git" "refs/tags/$VERSION_TAG" | cut -f1) -DEB_AMD64="yaak_${VERSION}_amd64.deb" -DEB_ARM64="yaak_${VERSION}_arm64.deb" +if [ -z "$COMMIT" ]; then + echo "Error: Could not resolve commit for tag $VERSION_TAG" + exit 1 +fi +echo "Tag: $VERSION_TAG" +echo "Commit: $COMMIT" + +# Update git tag and commit in the manifest +sed -i "s|tag: v.*|tag: $VERSION_TAG|" "$MANIFEST" +sed -i "s|commit: .*|commit: $COMMIT|" "$MANIFEST" +echo "Updated manifest tag and commit." + +# Regenerate offline dependency sources from the tagged lockfiles TMPDIR=$(mktemp -d) trap 'rm -rf "$TMPDIR"' EXIT -echo "Downloading $DEB_AMD64..." -curl -fSL "$BASE_URL/$DEB_AMD64" -o "$TMPDIR/$DEB_AMD64" -SHA_AMD64=$(sha256sum "$TMPDIR/$DEB_AMD64" | cut -d' ' -f1) -echo " SHA256: $SHA_AMD64" +echo "Fetching lockfiles from $VERSION_TAG..." +curl -fsSL "https://raw.githubusercontent.com/$REPO/$VERSION_TAG/Cargo.lock" -o "$TMPDIR/Cargo.lock" +curl -fsSL "https://raw.githubusercontent.com/$REPO/$VERSION_TAG/package-lock.json" -o "$TMPDIR/package-lock.json" +curl -fsSL "https://raw.githubusercontent.com/$REPO/$VERSION_TAG/package.json" -o "$TMPDIR/package.json" -echo "Downloading $DEB_ARM64..." -curl -fSL "$BASE_URL/$DEB_ARM64" -o "$TMPDIR/$DEB_ARM64" -SHA_ARM64=$(sha256sum "$TMPDIR/$DEB_ARM64" | cut -d' ' -f1) -echo " SHA256: $SHA_ARM64" +echo "Generating cargo-sources.json..." +python3 "$SCRIPT_DIR/flatpak-builder-tools/cargo/flatpak-cargo-generator.py" \ + -o "$SCRIPT_DIR/cargo-sources.json" "$TMPDIR/Cargo.lock" -echo "" -echo "Updating manifest: $MANIFEST" +echo "Generating node-sources.json..." +node "$SCRIPT_DIR/fix-lockfile.mjs" "$TMPDIR/package-lock.json" -# Update URLs by matching the arch-specific deb filename -sed -i "s|url: .*amd64\.deb|url: $BASE_URL/$DEB_AMD64|" "$MANIFEST" -sed -i "s|url: .*arm64\.deb|url: $BASE_URL/$DEB_ARM64|" "$MANIFEST" +node -e " + const fs = require('fs'); + const p = process.argv[1]; + const d = JSON.parse(fs.readFileSync(p, 'utf-8')); + for (const [name, info] of Object.entries(d.packages || {})) { + if (name && (info.link || !info.resolved)) delete d.packages[name]; + } + fs.writeFileSync(p, JSON.stringify(d, null, 2)); +" "$TMPDIR/package-lock.json" -# Update SHA256 hashes by finding the current ones and replacing -OLD_SHA_AMD64=$(grep -A2 "amd64\.deb" "$MANIFEST" | grep sha256 | sed 's/.*"\(.*\)"/\1/') -OLD_SHA_ARM64=$(grep -A2 "arm64\.deb" "$MANIFEST" | grep sha256 | sed 's/.*"\(.*\)"/\1/') - -sed -i "s|$OLD_SHA_AMD64|$SHA_AMD64|" "$MANIFEST" -sed -i "s|$OLD_SHA_ARM64|$SHA_ARM64|" "$MANIFEST" - -echo " Manifest updated." - -echo "Updating metainfo: $METAINFO" +flatpak-node-generator --no-requests-cache \ + -o "$SCRIPT_DIR/node-sources.json" npm "$TMPDIR/package-lock.json" +# Update metainfo with new release TODAY=$(date +%Y-%m-%d) - -# Insert new release entry after sed -i "s| | \n |" "$METAINFO" - -echo " Metainfo updated." +echo "Updated metainfo with release $VERSION." echo "" echo "Done! Review the changes:" echo " $MANIFEST" echo " $METAINFO" +echo " $SCRIPT_DIR/cargo-sources.json" +echo " $SCRIPT_DIR/node-sources.json" diff --git a/package-lock.json b/package-lock.json index 167cad0f..1946700b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16062,18 +16062,6 @@ "name": "@yaak/auth-oauth2", "version": "0.1.0" }, - "plugins/faker": { - "name": "@yaak/faker", - "version": "1.1.1", - "extraneous": true, - "dependencies": { - "@faker-js/faker": "^10.1.0" - }, - "devDependencies": { - "@types/node": "^25.0.3", - "typescript": "^5.9.3" - } - }, "plugins/filter-jsonpath": { "name": "@yaak/filter-jsonpath", "version": "0.1.0", diff --git a/scripts/vendor-node.cjs b/scripts/vendor-node.cjs index 1dd29cf0..92160b3a 100644 --- a/scripts/vendor-node.cjs +++ b/scripts/vendor-node.cjs @@ -1,4 +1,6 @@ const path = require('node:path'); +const crypto = require('node:crypto'); +const fs = require('node:fs'); const decompress = require('decompress'); const Downloader = require('nodejs-file-downloader'); const { rmSync, cpSync, mkdirSync, existsSync } = require('node:fs'); @@ -41,6 +43,15 @@ const DST_BIN_MAP = { [WIN_ARM]: 'yaaknode.exe', }; +const SHA256_MAP = { + [MAC_ARM]: 'b05aa3a66efe680023f930bd5af3fdbbd542794da5644ca2ad711d68cbd4dc35', + [MAC_X64]: '096081b6d6fcdd3f5ba0f5f1d44a47e83037ad2e78eada26671c252fe64dd111', + [LNX_ARM]: '0dc93ec5c798b0d347f068db6d205d03dea9a71765e6a53922b682b91265d71f', + [LNX_X64]: '58a5ff5cc8f2200e458bea22e329d5c1994aa1b111d499ca46ec2411d58239ca', + [WIN_X64]: '5355ae6d7c49eddcfde7d34ac3486820600a831bf81dc3bdca5c8db6a9bb0e76', + [WIN_ARM]: 'ce9ee4e547ebdff355beb48e309b166c24df6be0291c9eaf103ce15f3de9e5b4', +}; + const key = `${process.platform}_${process.env.YAAK_TARGET_ARCH ?? process.arch}`; const destDir = path.join(__dirname, `..`, 'crates-tauri', 'yaak-app', 'vendored', 'node'); @@ -68,6 +79,15 @@ rmSync(tmpDir, { recursive: true, force: true }); timeout: 1000 * 60 * 2, }).download(); + // Verify SHA256 + const expectedHash = SHA256_MAP[key]; + const fileBuffer = fs.readFileSync(filePath); + const actualHash = crypto.createHash('sha256').update(fileBuffer).digest('hex'); + if (actualHash !== expectedHash) { + throw new Error(`SHA256 mismatch for ${path.basename(filePath)}\n expected: ${expectedHash}\n actual: ${actualHash}`); + } + console.log('SHA256 verified:', actualHash); + // Decompress to the same directory await decompress(filePath, tmpDir, {}); diff --git a/scripts/vendor-protoc.cjs b/scripts/vendor-protoc.cjs index 48a867ee..439bb10c 100644 --- a/scripts/vendor-protoc.cjs +++ b/scripts/vendor-protoc.cjs @@ -1,3 +1,5 @@ +const crypto = require('node:crypto'); +const fs = require('node:fs'); const decompress = require('decompress'); const Downloader = require('nodejs-file-downloader'); const path = require('node:path'); @@ -41,6 +43,15 @@ const DST_BIN_MAP = { [WIN_ARM]: 'yaakprotoc.exe', }; +const SHA256_MAP = { + [MAC_ARM]: 'db7e66ff7f9080614d0f5505a6b0ac488cf89a15621b6a361672d1332ec2e14e', + [MAC_X64]: 'e20b5f930e886da85e7402776a4959efb1ed60c57e72794bcade765e67abaa82', + [LNX_ARM]: '6018147740548e0e0f764408c87f4cd040e6e1c1203e13aeacaf811892b604f3', + [LNX_X64]: 'f3340e28a83d1c637d8bafdeed92b9f7db6a384c26bca880a6e5217b40a4328b', + [WIN_X64]: 'd7a207fb6eec0e4b1b6613be3b7d11905375b6fd1147a071116eb8e9f24ac53b', + [WIN_ARM]: 'd7a207fb6eec0e4b1b6613be3b7d11905375b6fd1147a071116eb8e9f24ac53b', +}; + const dstDir = path.join(__dirname, `..`, 'crates-tauri', 'yaak-app', 'vendored', 'protoc'); const key = `${process.platform}_${process.env.YAAK_TARGET_ARCH ?? process.arch}`; console.log(`Vendoring protoc ${VERSION} for ${key}`); @@ -63,6 +74,15 @@ mkdirSync(dstDir, { recursive: true }); // Download GitHub release artifact const { filePath } = await new Downloader({ url, directory: tmpDir }).download(); + // Verify SHA256 + const expectedHash = SHA256_MAP[key]; + const fileBuffer = fs.readFileSync(filePath); + const actualHash = crypto.createHash('sha256').update(fileBuffer).digest('hex'); + if (actualHash !== expectedHash) { + throw new Error(`SHA256 mismatch for ${path.basename(filePath)}\n expected: ${expectedHash}\n actual: ${actualHash}`); + } + console.log('SHA256 verified:', actualHash); + // Decompress to the same directory await decompress(filePath, tmpDir, {});