Skip to content

ci: enforce npm ci on Studio install paths (follow-up to #5604)#5616

Draft
danielhanchen wants to merge 2 commits into
mainfrom
ci/npm-ci-followup-5604
Draft

ci: enforce npm ci on Studio install paths (follow-up to #5604)#5616
danielhanchen wants to merge 2 commits into
mainfrom
ci/npm-ci-followup-5604

Conversation

@danielhanchen

Copy link
Copy Markdown
Member

Summary

Follow-up to #5604. Now that the three Studio npm lockfiles are committed and audited, flip every install path that depends on them from npm install (mutates the lockfile, ignores integrity hashes) to npm ci (refuses to run unless the lockfile is exact). This closes the supply-chain gap between "the lockfile passes the audit" and "the install respected that lockfile".

What changes

Install scripts (build.sh, studio/setup.sh, studio/setup.ps1)

  • Frontend + OXC validator npm paths: npm install -> npm ci --no-fund --no-audit.
  • Bun calls gated on [ -f bun.lock ] && command -v bun (Test-Path / Get-Command on Windows) plus --frozen-lockfile --no-progress. Forward-compatible for the eventual bun.lock PR; inert today (no bun.lock checked in -> the gate fails closed -> execution falls through to npm ci).
  • Existing bun infrastructure (cache-corruption retry + critical-binary verification + npm fallback) kept intact so the auto-upgrade is clean when bun.lock eventually lands.

Workflows

  • release-desktop.yml: 2 npm install -> npm ci swaps (Tauri CLI + frontend); new pre-install lockfile audit step.
  • studio-tauri-smoke.yml: 1 npm install -> npm ci swap; audit step relocated to run before install.
  • wheel-smoke.yml: single-line content-sanity assertion that oxc-validator/package-lock.json is shipped in the wheel.
  • security-audit.yml: paths trigger gains 4 entries; OSV-scanner --lockfile= gains 2; two new npm audit steps (oxc + Tauri CLI holder); npm audit signatures block split into three (frontend / oxc / Tauri CLI), each preceded by npm ci --ignore-scripts; check_new_install_scripts.py extended to diff both new lockfiles with git show … || echo '{}' fallback for PRs whose base predates ci: advisory lockfile supply-chain audit (no install-script changes) #5604; upload-artifact paths extended.

Explicitly NOT in this PR

  • No bun.lock files (deferred per the "we don't want the bun lockfile yet" decision).
  • No BUN_PIN_VERSION / 3-attempt cache-corruption recovery ladders (would need committed bun.lock to be useful).
  • No unsloth.exe rename-and-restore block changes in setup.ps1 (unrelated Windows pip-replace workaround).
  • No continue-on-error policy flips on advisory audit jobs.
  • No pyproject.toml, test file, or Studio source edits.

Supersedes #5479

#5479 was a 41-file draft whose sequential git merge main operations had collateral reverts of files that exist on main (studio/backend/core/tool_healing.py, tests/test_finetune_last_n_layers.py, tests/test_import_fixes_drift.py, etc.). This PR is a clean re-derivation off latest origin/main containing only the install-path hardening.

Test plan

  • bash -n build.sh && bash -n studio/setup.sh — clean
  • PowerShell parse: [System.Management.Automation.Language.Parser]::ParseFile('studio/setup.ps1', ...) — clean
  • YAML parse for all 4 edited workflow files — clean
  • Local npm ci in studio/, studio/frontend/, studio/backend/core/data_recipe/oxc-validator/ — all 3 succeed, expected binaries present, no lockfile mutation
  • npm run build in studio/frontend/ — produces dist/index.html + dist/assets/*.css + dist/assets/index-*.js
  • unsloth.exe rename-and-restore block in setup.ps1 still present (grep -c 'unsloth.exe.deleteme' studio/setup.ps1 = 1)
  • python3 scripts/lockfile_supply_chain_audit.py — 0 findings on edited tree
  • CI green on Linux / macOS / Windows runners

PR #5604 committed three npm lockfiles (studio/, studio/frontend/,
studio/backend/core/data_recipe/oxc-validator/) but the install
paths still ran `npm install` -- mutates the lockfile, ignores
integrity hashes. Flip them to `npm ci`, which is non-mutating
and refuses to run unless the committed package-lock.json matches
the dependency tree byte-for-byte. This closes the gap between
"the lockfile passes the audit" and "the install respected that
lockfile".

For bun: gate every `bun install` on `[ -f bun.lock ]` (Test-Path
on Windows) plus `command -v bun` (Get-Command), and add
`--frozen-lockfile --no-progress` to the bun invocation. No
bun.lock is committed in this PR, so the gate fails closed today
and execution falls through to `npm ci`. When the eventual
bun.lock PR lands, the gate auto-activates with no further
script edits.

Existing bun infrastructure (cache-corruption retry +
critical-binary verification + npm fallback) is kept intact so
the auto-upgrade is clean. Deliberately NOT introducing
_BUN_PIN_VERSION or the 3-attempt cache-corruption recovery
ladder; both require committed bun.lock to be useful.

Touches three files only:
- build.sh
- studio/setup.sh
- studio/setup.ps1
Point the existing audit + install + content-sanity workflows at
the two lockfiles PR #5604 introduced (studio/package-lock.json
and studio/backend/core/data_recipe/oxc-validator/package-lock.json)
so the Studio Tauri CLI holder and the oxc-validator runtime
benefit from the same per-PR coverage the frontend already has.

release-desktop.yml:
  - Tauri CLI install: `npm install --save-dev --prefix studio` ->
    `npm ci --prefix studio --no-fund --no-audit`.
  - Frontend install: `npm install --no-fund --no-audit` ->
    `npm ci --no-fund --no-audit`.
  - New "Lockfile supply-chain audit" step inserted BEFORE the
    Tauri CLI install so the structural audit fires before any
    tarball-side lifecycle script.

studio-tauri-smoke.yml:
  - Tauri CLI install: `npm install --save-dev --prefix studio` ->
    `npm ci --prefix studio --no-fund --no-audit`.
  - Existing audit step relocated to run BEFORE the Tauri CLI
    install (same ordering rationale).

wheel-smoke.yml:
  - One-line content-sanity assertion ensuring the oxc-validator
    package-lock.json is shipped in the wheel.

security-audit.yml:
  - `paths` trigger gains the 4 new entries (oxc + Tauri CLI
    holder package.json + package-lock.json).
  - `Scanned:` summary string updated to list the two new
    lockfiles.
  - OSV-scanner picks up `--lockfile=` for both.
  - Two new `npm audit` steps: oxc-validator runtime + Studio
    Tauri CLI holder.
  - `npm audit signatures` block split into three (frontend / oxc
    / Tauri CLI), each preceded by `npm ci --ignore-scripts` in
    its own directory.
  - `check_new_install_scripts.py` invocation extended to diff
    both new lockfiles base->head, with `git show ... 2>/dev/null
    || echo '{}'` fallback for PRs whose base predates #5604.
  - `upload-artifact` paths extended for the new log files.

Deliberately NOT included: removing `continue-on-error` from the
existing `scan_npm_packages` job. That is a policy flip from
advisory to blocking and is orthogonal to install-path hardening.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the build and setup scripts (build.sh, setup.ps1, and setup.sh) to enforce lockfile-pinned dependency installations. The scripts now only attempt to use bun if a bun.lock file is present, utilizing the --frozen-lockfile flag, and have transitioned from npm install to npm ci for fallbacks to ensure environment consistency. Reviewer feedback recommends redirecting warning messages to stderr in the shell scripts to align with standard error reporting practices.

Comment thread build.sh
_install_ok=true
else
echo "⚠ bun install failed, falling back to npm"
echo "⚠ bun install --frozen-lockfile failed, falling back to npm ci"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's good practice to direct warning messages to stderr (standard error) rather than stdout (standard output). This helps in distinguishing informational output from potential issues, especially when scripts are used in automated environments or piped to other commands. The error message on line 54 already correctly uses >&2.

Suggested change
echo "⚠ bun install --frozen-lockfile failed, falling back to npm ci"
echo "⚠ bun install --frozen-lockfile failed, falling back to npm ci" >&2

Comment thread studio/setup.sh
# Either bun install failed or it exited 0 but left packages missing
if [ "$_exit_code" -ne 0 ]; then
echo " bun install failed (exit code $_exit_code):"
echo " bun install --frozen-lockfile failed (exit code $_exit_code):"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to build.sh, this warning message should be directed to stderr for consistent error reporting in shell scripts.

Suggested change
echo " bun install --frozen-lockfile failed (exit code $_exit_code):"
echo " bun install --frozen-lockfile failed (exit code $_exit_code):" >&2

Comment thread studio/setup.sh
echo " bun install failed (exit code $_exit_code):"
echo " bun install --frozen-lockfile failed (exit code $_exit_code):"
else
echo " bun install exited 0 but critical binaries are missing:"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This warning message should also be directed to stderr for consistent error reporting.

Suggested change
echo " bun install exited 0 but critical binaries are missing:"
echo " bun install exited 0 but critical binaries are missing:" >&2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant