Brings the parallel CI paths into line with the lockfile-pinned
release path and tightens the supply-chain audit surface:
studio-tauri-smoke.yml: run lockfile_supply_chain_audit.py before
the Tauri CLI install, and install via `npm ci --prefix studio`
against the committed studio/package-lock.json (was a mutable
`npm install --save-dev` post-audit). This relocates the existing
pre-install lockfile supply-chain audit step; the step's name and
command are preserved verbatim so its purpose is unchanged, only
its position relative to the install. The earlier security
rationale about lifecycle scripts and the postinstall-dropper
class is preserved on the Frontend build step where it actually
applies (vite/esbuild lifecycle scripts run on the frontend
install); the Tauri CLI install step gets a new rationale tied to
`npm ci` semantics.
security-audit.yml:
* add studio/package.json and studio/package-lock.json to the PR
path filter so a Tauri CLI lockfile change cannot bypass the
workflow,
* extend OSV-Scanner, scan_npm_packages.py (with LOG3 and exit-
code propagation), and the install-script diff to cover
studio/package-lock.json,
* add an npm audit step for the Tauri CLI holder project,
* extend the npm-provenance-and-install-scripts job with
--ignore-scripts installs + npm audit signatures for the
oxc-validator and Tauri CLI holder projects; the existing
frontend audit-signatures step is renamed to "(Studio
frontend, informational)" purely for disambiguation against
the two new sibling steps, with its log path rerouted through
$GITHUB_WORKSPACE so a single artifact upload can collect all
three logs,
* update the lockfile-audit step summary to list the Tauri CLI
holder lockfile,
* fix the stale "Initially non-blocking" comment on the now-
blocking npm scan-packages step.
build.sh and studio/setup.ps1 (oxc): pass --no-fund --no-audit to
npm ci for parity with the other call sites.
studio/setup.sh and studio/setup.ps1: restore the bun.lock
exclusion in the frontend staleness check so a leftover local
bun.lock from the migration does not trigger a spurious rebuild.
scripts/lockfile_supply_chain_audit.py: emit a HIGH-severity
missing-lockfile Finding when a requested lockfile does not
exist, so a deleted default cannot silently pass the audit. Uses
the script's own Finding accumulator pattern (sibling
scripts/scan_npm_packages.py implements the same intent via an
rc=2 hard-fail, its single-lockfile-per-invocation idiom; this
script aggregates multiple lockfiles so Finding is the natural
channel).
scripts/check_frontend_dep_removal.py: add studio/package.json
and studio/package-lock.json to EXPECTED_NOISE_FILES; the new
Tauri CLI holder manifests must not count as frontend dep usage.
129 lines
5 KiB
YAML
129 lines
5 KiB
YAML
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved.
|
|
|
|
# PR-time smoke for the Tauri desktop wrapper. Builds the frontend and the
|
|
# Tauri Linux debug binary, with no codesigning. Catches:
|
|
# - tauri.conf.json drift
|
|
# - src-tauri Cargo.toml or rust source breakage
|
|
# - Tauri CLI version drift (we pin 2.10.1, matching release-desktop.yml)
|
|
# - frontend output not picked up by Tauri's distDir
|
|
#
|
|
# Linux-only on a free `ubuntu-latest` runner. Mac and Windows desktop builds
|
|
# stay in release-desktop.yml (manual `workflow_dispatch`) because they need
|
|
# code-signing secrets and ~30 min of runner time each.
|
|
|
|
name: Studio Tauri CI
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- 'studio/frontend/**'
|
|
- 'studio/src-tauri/**'
|
|
# CLI rename / signature change can break Tauri's spawned
|
|
# `unsloth studio` -- include unsloth_cli in the trigger set.
|
|
- 'unsloth_cli/**'
|
|
- '.github/workflows/studio-tauri-smoke.yml'
|
|
push:
|
|
branches: [main, pip]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
linux-debug-build:
|
|
name: Tauri Linux debug build (no codesign)
|
|
runs-on: ubuntu-22.04
|
|
timeout-minutes: 25
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Linux native deps for Tauri / WebKit2GTK
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y \
|
|
libwebkit2gtk-4.1-dev libayatana-appindicator3-dev \
|
|
librsvg2-dev libxdo-dev libssl-dev patchelf
|
|
|
|
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version: '24'
|
|
|
|
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable @ 2026-03-27
|
|
|
|
- uses: swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2.9.1
|
|
with:
|
|
workspaces: studio/src-tauri -> target
|
|
|
|
# Pre-install lockfile structural audit. Has to fire BEFORE
|
|
# any `npm ci` so a tarball's `prepare` / `postinstall` cannot
|
|
# run ahead of the scan. Pure-Python read-only; safe everywhere.
|
|
- name: Lockfile supply-chain audit (pre-install scan)
|
|
run: python3 scripts/lockfile_supply_chain_audit.py
|
|
|
|
- name: Install pinned Tauri CLI (matches release-desktop.yml)
|
|
# `npm ci` resolves @tauri-apps/cli and its platform-specific
|
|
# optional native binaries from studio/package-lock.json --
|
|
# transitive versions are fully pinned, integrity hashes are
|
|
# verified, and the install is reproducible across re-runs.
|
|
run: npm ci --prefix studio --no-fund --no-audit
|
|
|
|
- name: Verify pinned Tauri CLI version
|
|
run: |
|
|
out="$(npx --prefix studio tauri --version)"
|
|
echo "$out"
|
|
[ "$out" = "tauri-cli 2.10.1" ] || { echo "::error::expected tauri-cli 2.10.1, got $out"; exit 1; }
|
|
|
|
- name: Frontend build (npm ci, vite)
|
|
working-directory: studio/frontend
|
|
# Lifecycle scripts (esbuild native-binary postinstall, etc.) are
|
|
# required for `vite build`. The pre-install lockfile structural
|
|
# audit (lockfile_supply_chain_audit.py) above is the practical
|
|
# defence against the npm postinstall-dropper class -- it fires
|
|
# BEFORE any tarball runs, on the injection pattern itself rather
|
|
# than an advisory-DB lookup.
|
|
run: |
|
|
npm ci --no-fund --no-audit
|
|
npm run build
|
|
test -f dist/index.html
|
|
|
|
- name: Tauri debug build (Linux, no bundle, no codesign)
|
|
# `--debug` + `--no-bundle` keeps this lean: compiles the Rust crate,
|
|
# confirms the frontend dist is wired into Tauri, but skips the AppImage
|
|
# / .deb production. Code signing is irrelevant because we never produce
|
|
# a distributable artifact.
|
|
env:
|
|
TAURI_SIGNING_PRIVATE_KEY: ''
|
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ''
|
|
run: npx --prefix studio tauri build --debug --no-bundle
|
|
|
|
- name: Inspect produced binary
|
|
run: |
|
|
BIN=$(find studio/src-tauri/target/debug -maxdepth 1 -type f -executable 2>/dev/null \
|
|
| grep -Ev '\.(d|so|dylib|dll)$' \
|
|
| grep -Ev '/(deps|build|examples)$' \
|
|
| head -1)
|
|
echo "binary: $BIN"
|
|
if [ -z "$BIN" ]; then
|
|
echo "::error::Tauri debug binary not produced"
|
|
ls -la studio/src-tauri/target/debug/ || true
|
|
exit 1
|
|
fi
|
|
file "$BIN"
|
|
du -h "$BIN"
|
|
|
|
- name: Upload Tauri debug build
|
|
# Always upload so a green run leaves the binary inspectable too.
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: tauri-debug-build
|
|
path: |
|
|
studio/src-tauri/target/debug
|
|
studio/frontend/dist
|
|
retention-days: 3
|