ci: address bot review on
Two issues codex flagged: 1. bun.lock gate (studio/frontend/.gitignore line 14 ignores bun.lock, so it is never committed). bun install --frozen-lockfile cannot migrate from package-lock.json, so without a bun.lock the bun path always fails. setup.sh then misclassifies that as a corrupt cache, clears the user's bun cache, and re-runs the same guaranteed-failing command before falling back to npm. build.sh, studio/setup.sh, and studio/setup.ps1 now only enter the bun path when bun.lock is present; otherwise we go straight to npm ci. 2. OXC validator lockfile was outside the npm supply-chain scan surface. lockfile_supply_chain_audit.py default, npm audit, OSV, scan_npm_packages.py invocation, and the diff-for-new-install-scripts step all now cover both lockfiles. security-audit.yml pull_request paths filter triggers on changes to either. wheel-smoke checks the built wheel ships the OXC lockfile too. Verified: python3 scripts/lockfile_supply_chain_audit.py > OK: 0 findings across 2 npm + 1 cargo lockfile(s) python3 scripts/scan_npm_packages.py --lockfile oxc-validator/... > OK
This commit is contained in:
parent
75a8129e3b
commit
d1124c52a9
6 changed files with 63 additions and 12 deletions
46
.github/workflows/security-audit.yml
vendored
46
.github/workflows/security-audit.yml
vendored
|
|
@ -53,6 +53,8 @@ on:
|
|||
- 'studio/backend/requirements/**'
|
||||
- 'studio/frontend/package.json'
|
||||
- 'studio/frontend/package-lock.json'
|
||||
- 'studio/backend/core/data_recipe/oxc-validator/package.json'
|
||||
- 'studio/backend/core/data_recipe/oxc-validator/package-lock.json'
|
||||
- 'studio/src-tauri/Cargo.toml'
|
||||
- 'studio/src-tauri/Cargo.lock'
|
||||
- 'pyproject.toml'
|
||||
|
|
@ -278,7 +280,7 @@ jobs:
|
|||
{
|
||||
echo "## Lockfile supply-chain audit"
|
||||
echo
|
||||
echo "Scanned: studio/frontend/package-lock.json + studio/src-tauri/Cargo.lock"
|
||||
echo "Scanned: studio/frontend/package-lock.json + studio/backend/core/data_recipe/oxc-validator/package-lock.json + studio/src-tauri/Cargo.lock"
|
||||
echo
|
||||
echo "No structural anomalies or known IOC strings."
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
|
@ -307,6 +309,22 @@ jobs:
|
|||
echo '```'
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: npm audit (oxc-validator runtime)
|
||||
# Same audit surface, separate npm project (oxc-parser, oxlint).
|
||||
continue-on-error: true
|
||||
working-directory: studio/backend/core/data_recipe/oxc-validator
|
||||
run: |
|
||||
set +e
|
||||
npm audit --audit-level=high | tee "$GITHUB_WORKSPACE/logs-npm-audit-oxc.txt"
|
||||
npm audit --json > "$GITHUB_WORKSPACE/logs-npm-audit-oxc.json" || true
|
||||
{
|
||||
echo "## npm audit (oxc-validator)"
|
||||
echo
|
||||
echo '```'
|
||||
tail -200 "$GITHUB_WORKSPACE/logs-npm-audit-oxc.txt"
|
||||
echo '```'
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# cargo: Studio Tauri shell
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
|
@ -348,6 +366,7 @@ jobs:
|
|||
/tmp/osv-scanner --version
|
||||
/tmp/osv-scanner scan source \
|
||||
--lockfile=studio/frontend/package-lock.json \
|
||||
--lockfile=studio/backend/core/data_recipe/oxc-validator/package-lock.json \
|
||||
--lockfile=studio/src-tauri/Cargo.lock \
|
||||
--lockfile=requirements.txt:audit-reqs/unsloth-deps.txt \
|
||||
--lockfile=requirements.txt:audit-reqs/studio.txt \
|
||||
|
|
@ -913,24 +932,39 @@ jobs:
|
|||
# downloaded tarball, and only fetches from registry.npmjs.org.
|
||||
# Initially non-blocking so the baseline can settle; drop
|
||||
# continue-on-error once the baseline is clean for a week.
|
||||
#
|
||||
# Two separate npm projects share this scan surface; scan each.
|
||||
run: |
|
||||
set -o pipefail
|
||||
LOG=logs-scan-npm.txt
|
||||
python3 scripts/scan_npm_packages.py 2>&1 | tee "$LOG"
|
||||
LOG2=logs-scan-npm-oxc.txt
|
||||
python3 scripts/scan_npm_packages.py \
|
||||
--lockfile studio/backend/core/data_recipe/oxc-validator/package-lock.json \
|
||||
2>&1 | tee "$LOG2"
|
||||
{
|
||||
echo "## scan_npm_packages"
|
||||
echo "## scan_npm_packages (Studio frontend)"
|
||||
echo
|
||||
echo '### Findings (tail)'
|
||||
echo '```'
|
||||
tail -300 "$LOG"
|
||||
echo '```'
|
||||
echo
|
||||
echo "## scan_npm_packages (oxc-validator)"
|
||||
echo
|
||||
echo '### Findings (tail)'
|
||||
echo '```'
|
||||
tail -300 "$LOG2"
|
||||
echo '```'
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: always()
|
||||
with:
|
||||
name: scan-npm-packages-log
|
||||
path: logs-scan-npm.txt
|
||||
path: |
|
||||
logs-scan-npm.txt
|
||||
logs-scan-npm-oxc.txt
|
||||
retention-days: 30
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
|
|
@ -1103,6 +1137,9 @@ jobs:
|
|||
BASE_SHA="${{ github.event.pull_request.base.sha }}"
|
||||
git show "$BASE_SHA:studio/frontend/package-lock.json" \
|
||||
> /tmp/base-package-lock.json
|
||||
# OXC lockfile may not exist on the base ref (newly added).
|
||||
git show "$BASE_SHA:studio/backend/core/data_recipe/oxc-validator/package-lock.json" \
|
||||
> /tmp/base-oxc-package-lock.json 2>/dev/null || echo '{}' > /tmp/base-oxc-package-lock.json
|
||||
|
||||
- name: Diff for newly-added install-script deps
|
||||
if: github.event_name == 'pull_request'
|
||||
|
|
@ -1110,6 +1147,9 @@ jobs:
|
|||
python3 scripts/check_new_install_scripts.py \
|
||||
--base /tmp/base-package-lock.json \
|
||||
--head studio/frontend/package-lock.json
|
||||
python3 scripts/check_new_install_scripts.py \
|
||||
--base /tmp/base-oxc-package-lock.json \
|
||||
--head studio/backend/core/data_recipe/oxc-validator/package-lock.json
|
||||
|
||||
- name: Skip install-script diff (non-PR trigger)
|
||||
if: github.event_name != 'pull_request'
|
||||
|
|
|
|||
1
.github/workflows/wheel-smoke.yml
vendored
1
.github/workflows/wheel-smoke.yml
vendored
|
|
@ -87,6 +87,7 @@ jobs:
|
|||
n = z.namelist()
|
||||
checks = {
|
||||
"lockfile shipped": any(s.endswith("studio/frontend/package-lock.json") for s in n),
|
||||
"oxc lockfile shipped": any(s.endswith("oxc-validator/package-lock.json") for s in n),
|
||||
"frontend dist shipped": any(s.endswith("studio/frontend/dist/index.html") for s in n),
|
||||
"no node_modules": not any("studio/frontend/node_modules/" in s for s in n),
|
||||
"no bun.lock": not any(s.endswith("studio/frontend/bun.lock") for s in n),
|
||||
|
|
|
|||
8
build.sh
8
build.sh
|
|
@ -33,11 +33,11 @@ _restore_gitignores() {
|
|||
}
|
||||
trap _restore_gitignores EXIT
|
||||
|
||||
# Use bun if available (faster), fall back to npm. Lockfile-strict on
|
||||
# both paths so a release build can't pull a fresh caret-range patch
|
||||
# of any transitive from the registry.
|
||||
# Use bun if a bun.lock is committed (lockfile-strict, fast), else npm ci.
|
||||
# bun install --frozen-lockfile cannot migrate from package-lock.json, so if
|
||||
# only the npm lockfile is present we skip bun and go straight to npm ci.
|
||||
_install_ok=false
|
||||
if command -v bun &>/dev/null; then
|
||||
if [ -f bun.lock ] && command -v bun &>/dev/null; then
|
||||
if bun install --frozen-lockfile; then
|
||||
_install_ok=true
|
||||
else
|
||||
|
|
|
|||
|
|
@ -652,7 +652,10 @@ def audit_cargo_lockfile(path: Path) -> list[Finding]:
|
|||
# ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
DEFAULT_NPM_LOCKFILES = ("studio/frontend/package-lock.json",)
|
||||
DEFAULT_NPM_LOCKFILES = (
|
||||
"studio/frontend/package-lock.json",
|
||||
"studio/backend/core/data_recipe/oxc-validator/package-lock.json",
|
||||
)
|
||||
DEFAULT_CARGO_LOCKFILES = ("studio/src-tauri/Cargo.lock",)
|
||||
|
||||
|
||||
|
|
@ -671,7 +674,8 @@ def main(argv: list[str] | None = None) -> int:
|
|||
default = None,
|
||||
help = (
|
||||
"Path to a package-lock.json (repeatable). "
|
||||
"Default: studio/frontend/package-lock.json."
|
||||
"Default: studio/frontend/package-lock.json plus "
|
||||
"studio/backend/core/data_recipe/oxc-validator/package-lock.json."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
|
|
|
|||
|
|
@ -1327,13 +1327,15 @@ if ($NeedFrontendBuild -and -not $IsPipInstall) {
|
|||
$ErrorActionPreference = "Continue"
|
||||
Push-Location $FrontendDir
|
||||
|
||||
$UseBun = $null -ne (Get-Command bun -ErrorAction SilentlyContinue)
|
||||
# Only use bun when a committed bun.lock is present. bun install
|
||||
# --frozen-lockfile cannot migrate from package-lock.json, so without
|
||||
# bun.lock the bun path would always fail.
|
||||
$UseBun = ($null -ne (Get-Command bun -ErrorAction SilentlyContinue)) -and (Test-Path "bun.lock")
|
||||
|
||||
# bun's package cache can become corrupt -- packages get stored with only
|
||||
# metadata but no actual content (bin/, lib/). When this happens bun install
|
||||
# exits 0 but leaves binaries missing. We validate after install and clear
|
||||
# the cache + retry once before falling back to npm.
|
||||
# --frozen-lockfile so a fresh caret-range patch can't land via npm registry.
|
||||
if ($UseBun) {
|
||||
Write-Host " Using bun for package install (faster)" -ForegroundColor DarkGray
|
||||
$bunExit = Invoke-SetupCommand { bun install --frozen-lockfile }
|
||||
|
|
|
|||
|
|
@ -367,7 +367,11 @@ _try_bun_install() {
|
|||
}
|
||||
|
||||
_bun_install_ok=false
|
||||
if command -v bun &>/dev/null; then
|
||||
# bun install --frozen-lockfile cannot migrate from package-lock.json, so we
|
||||
# only enter the bun path when a committed bun.lock exists. Without it,
|
||||
# bun would fail every time and the corrupt-cache retry would clear the
|
||||
# user's bun cache for nothing.
|
||||
if [ -f bun.lock ] && command -v bun &>/dev/null; then
|
||||
substep "using bun for package install (faster)"
|
||||
if _try_bun_install; then
|
||||
_bun_install_ok=true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue