lacs-project / lacs-project/sysknife

npm audit makes `frontend` fail whenever registry.npmjs.org does

Open
#367 6 comments 0 reactions 0 assignees View on GitHub
bug easy help wanted
Dominant language
Rust
Stars
12
Forks
19
Avg merge
18h 57m
Merged PRs (30d)
116

Description

> **Line references corrected 2026-09-07 at `adab560`.** The three line numbers
> in this issue were wrong when it was filed, and the `grep -n` output pasted
> under "Getting started" reproduces on no commit this repository has. My error,
> not a change under you. The step is at **197-198**, the surrounding numbers are
> in the corrected block below, and the substance of the issue is unchanged:
> `frontend` is still required, the step is still enforced, and it still gates
> every pull request on `registry.npmjs.org`.

`frontend` is a required status check on `main`, and its fourth step is:

```yaml
- name: Audit production dependencies
run: npm audit --omit=dev --audit-level=high
```

That command POSTs to `https://registry.npmjs.org/-/npm/v1/security/advisories/bulk`.
When the endpoint is unavailable, npm exits 1, and the check fails exactly the way
it fails for a genuine high-severity advisory.

This morning that took every open pull request down for 45 minutes:

| run | PR | started (UTC) | error |
|---|---|---|---|
| [33859810636](https://github.com/lacs-project/sysknife/actions/runs/33859810636) | #365 | 09:44 | `npm warn audit 503 Service Unavailable - POST .../advisories/bulk` |
| [33862001249](https://github.com/lacs-project/sysknife/actions/runs/33862001249) | #366 | 10:11 | `npm warn audit network timeout at: .../advisories/bulk` |
| [33863121379](https://github.com/lacs-project/sysknife/actions/runs/33863121379) | #366 | 10:25 | `503 Service Unavailable` |

Each attempt ran for five minutes before npm gave up (10:25:37 → 10:30:37 on the
last one), so a bad morning at the registry costs runner minutes on top of the
blocked merges. Re-running the failed job cleared all three.

Two things make this worse than an ordinary flake.

The audit covers `apps/sysknife-shell`, the paused Tauri GUI. `CONTRIBUTING.md`
puts GUI work out of scope, so #366, which changes one line of `CONTRIBUTING.md`,
waited twice on that directory's dependency advisories.

And `gh pr checks` prints `frontend fail` either way. A contributor reading that
cannot separate an outage from a vulnerability without opening the log.

Three shapes, and I hold none of them strongly:

- Move the audit into its own scheduled workflow against `main`, daily, and drop
it from the pull-request path. Advisories appear on the registry's clock. A
PR-time audit answers a question the pull request did not ask.
- Keep it on pull requests and stop it blocking: `continue-on-error: true`, so
the result is reported and not enforced.
- Leave the PR-shaped half to `dependency-review`, which already runs here and
already catches a dependency a pull request introduces.

Whoever picks this up: the step is `.github/workflows/ci.yml:197-198`. Branch
protection on `main` lists `frontend` among its required contexts, so deleting
the step is enough; deleting the job would need the protection setting changed
in the same breath or every pull request sits on a check that never reports.

## Getting started

One workflow file. No VM, no daemon, no LLM provider, no credentials.

```
$ grep -n 'npm audit' .github/workflows/ci.yml
198: run: npm audit --omit=dev --audit-level=high
$ awk 'NR>=170 && NR<=230 && /- name:/ {print NR": "$0}' .github/workflows/ci.yml
177: - name: Lint GitHub issue templates
186: - name: Checkout
189: - name: Set up Node
194: - name: Install dependencies
197: - name: Audit production dependencies
200: - name: Type check
203: - name: Test
216: - name: Checkout
219: - name: Install Tauri system dependencies
229: - name: Set up Rust
```

That window is wider than the `frontend` job, so it picks up the tail of
`docs-and-hygiene` at 177 and the head of the next job at 216. Steps 186 through
203 are the ones this issue is about.

The job runs with `working-directory: apps/sysknife-shell`, which is the paused
desktop app, so this step gates every pull request in the repository on the
availability of `registry.npmjs.org` for a component nobody is developing.

Confirm the branch-protection half before you touch anything, because it decides
which of the three options in the body is safe:

```
$ gh api repos/lacs-project/sysknife/branches/main/protection --jq '.required_status_checks.contexts'
```

`frontend` is in that list. Deleting the step leaves the job reporting. Deleting
the job leaves every pull request waiting on a context that never arrives.

## Tests first

The awkward part is that the thing you are fixing is a network outage, and you
cannot make `registry.npmjs.org` fail on demand.

**Break what the guard protects.** Whichever option you take, assert on the
workflow text rather than on a run. A guard under `tests/release/` that parses
the `frontend` job and asserts the audit step carries `continue-on-error: true`,
or that no `npm audit` invocation is enforced on the pull-request path, is
checkable offline and cannot pass by accident.

**Break the guard's own input.** This is the failure mode #346, #362 and #368 all
share, so it is worth care here. Assert on a count, not only on a match. If your
guard greps the job for a token, it passes just as happily when the job is renamed
out from under it and it reads zero steps. Give it a fixture whose `frontend` job
has the step enforced, and assert it goes red on that fixture. A guard that has
never been seen to fail is not a guard.

`tests/release/postgres-contract-guard.test.sh` is the closest existing model for
parsing a job out of `ci.yml`, and #362 is the open issue about the ways that
particular pattern can fool you.

## Difficulty

`easy`. The change is a few lines of YAML. Choosing among the three options is the
judgement, and the body already lays them out.

Contributor guide

Open the contributing guide

Research direction

Read the frontend job in .github/workflows/ci.yml around steps 186-203, then confirm required contexts with the branch-protection API command in the issue. Review tests/release/postgres-contract-guard.test.sh and issue #362 before choosing among the listed workflow approaches. Done means the pull-request path no longer blocks on an npm registry outage, with an offline guard that verifies the intended workflow text and fails on an enforced-audit fixture.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, javascript
Domain
ci-cd, devops, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.