From e8fc02d1c8b3b0fc406e729e068c01b424cc60c1 Mon Sep 17 00:00:00 2001 From: fknmiz <150495873+fknmiz@users.noreply.github.com> Date: Sun, 13 Sep 2026 17:47:08 -0400 Subject: [PATCH 1/2] ci: use npm ci over npm install, pin npm CLI, move audit earlier publish.yml previously ran npm install -g npm@latest (unpinned mutable tag) then npm install (ignoring the committed lockfile) in a job that holds id-token: write immediately before npm publish --provenance. A compromised transitive dependency resolved fresh at publish time would get a valid provenance attestation. Pins the npm CLI to the version the file's own comment already names (11.5.1), switches both publish.yml and ci.yml to npm ci --ignore-scripts against the audited lockfile, and adds/moves npm audit --audit-level=high to run immediately after install rather than last (or not at all, in publish.yml's case). Deliberately not doing in this branch: SHA-pinning actions/checkout, actions/setup-node, and codeql-action, or adding an environment approval gate. Both are sound hygiene but defend against GitHub/npm Inc. itself being compromised, lower urgency than the lockfile-bypass issue above for a single-maintainer repo, and the environment gate needs an actual GitHub Environment created first. Verified locally end to end: npm ci --ignore-scripts (194 packages, 0 vulnerabilities), lint, typecheck, coverage (24 tests), build, demo all pass. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 4 ++-- .github/workflows/publish.yml | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c29c649..8d768d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,13 +18,13 @@ jobs: - uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - - run: npm install + - run: npm ci --ignore-scripts + - run: npm audit --audit-level=high - run: npm run lint - run: npm run typecheck - run: npm run coverage - run: npm run build - run: npm run demo - - run: npm audit --audit-level=high # Least-privilege: read-only test/CI runs. GITHUB_TOKEN gets no write to # anything. The publish/release flows (where they exist) carry their own diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c06ccde..e683cd5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -27,8 +27,9 @@ jobs: # Node 22's bundled npm predates full OIDC trusted-publishing support # (needs npm >= 11.5.1); the initial rollout of this workflow 404'd on # the actual publish PUT even though provenance signing succeeded. - - run: npm install -g npm@latest - - run: npm install + - run: npm install -g npm@11.5.1 --ignore-scripts + - run: npm ci --ignore-scripts + - run: npm audit --audit-level=high - run: npm run lint - run: npm run typecheck - run: npm run coverage From 227c6f04f2062dcc950fb62696bd3d847115fe76 Mon Sep 17 00:00:00 2001 From: fknmiz <150495873+fknmiz@users.noreply.github.com> Date: Sun, 13 Sep 2026 17:50:12 -0400 Subject: [PATCH 2/2] fix(ci): drop --ignore-scripts from npm ci, it breaks esbuild on Linux The first version of this branch failed real CI: npm ci --ignore-scripts on ubuntu-latest left @esbuild/linux-x64 unresolved (vite/vitest/tsx all depend on esbuild transitively), because --ignore-scripts also disables esbuild's postinstall fallback that resolves the platform binary when npm's own optionalDependencies resolution doesn't land it. Local verification on Windows didn't catch this, esbuild resolved fine there, which is exactly why the real Linux CI run is the actual check, not a local pass. Keeping npm ci (the real fix: pins to the audited lockfile instead of re-resolving ^ ranges) and npm install -g npm@11.5.1 --ignore-scripts (installing the npm CLI binary itself has no legitimate need for scripts and isn't affected by this). Dropping --ignore-scripts only from the npm ci steps. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 2 +- .github/workflows/publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d768d7..a645b66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - - run: npm ci --ignore-scripts + - run: npm ci - run: npm audit --audit-level=high - run: npm run lint - run: npm run typecheck diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e683cd5..ff4e24a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -28,7 +28,7 @@ jobs: # (needs npm >= 11.5.1); the initial rollout of this workflow 404'd on # the actual publish PUT even though provenance signing succeeded. - run: npm install -g npm@11.5.1 --ignore-scripts - - run: npm ci --ignore-scripts + - run: npm ci - run: npm audit --audit-level=high - run: npm run lint - run: npm run typecheck