CI: the Security job installs the whole project and every npm package only to audit two lock files #1166

Closed
opened 2026-10-31 03:04:28 +00:00 by tiagoagueda · 0 comments
Owner

This issue holds 2 findings of the audit that share one fix or the same files.

C3: CI: the Security job installs the whole project to run pip-audit over an exported lock

What exists today

.forgejo/workflows/ci.yml:688-691:

uv export --no-emit-project --all-groups --all-extras --format requirements-txt --no-hashes > /tmp/locked-requirements.txt
uv run --with pip-audit==2.10.1 pip-audit --strict --progress-spinner off -r /tmp/locked-requirements.txt

uv export reads uv.lock and needs no environment. uv run inside the project does: it first syncs the project environment with the default groups (dev, e2e), which on node:22-bookworm means downloading a managed Python 3.14 (the image's Python 3.11 is below requires-python) and every locked package, building Postulo as an editable package, and only then layering pip-audit on top. pip-audit never looks at that environment: it audits the file given with -r.

#1033's table gives the audit step 33 s. With -r and no hashes, pip-audit also resolves the requirements through pip in a temporary virtual environment of its own, which downloads the packages a second time.

What would change

  • uvx pip-audit==2.10.1 ... (uv tool run), which runs the pinned tool in its own environment and does not touch the project. It can run on the image's own Python.
  • Measure, then consider, --disable-pip --no-deps: the export already lists every transitive pin, so pip-audit has nothing to resolve. Keep --strict; the set audited must stay exactly the exported lock, and tests/test_security_audit.py should still pass. If markers in the export (; python_version < '3.14') trouble --disable-pip, keep the pip resolve.
  • C4 is the same job and the same kind of change; one pull request for both.

What it saves or protects

small: a managed Python download (34 MB), about 100 packages and an editable build skipped per run; the pip resolve inside pip-audit may be most of the step's 33 s (unmeasured)

Accessibility

none

Decisions

  • One issue for C3 and C4? Recommended: yes, "CI: the Security job installs only what the audits read".
  • --disable-pip --no-deps? Recommended: only if one run shows the same findings list and a shorter step.

C4: CI: the Security job runs npm ci only so that npm audit can read the lock

What exists today

.forgejo/workflows/ci.yml:693-696:

- name: Audit the asset build's Node dependencies
  run: |
    npm ci
    npm audit --audit-level=high

package-lock.json (39 KB, 73 entries under packages) is everything npm audit reports on. npm audit builds its tree from the lock when told to with --package-lock-only, which npm documents for exactly this ("only use the package-lock.json, ignore node_modules"). npm ci installs every devDependency, Tailwind's native binaries included; node_modules is 130 MB on the developer's machine. The job has no npm cache, so the install downloads every run. #1033 timed npm ci at 4 s in the browser job, so the saving is seconds, not minutes.

What would change

npm audit --package-lock-only --audit-level=high, without npm ci. Same advisories, same lock, same threshold. Belongs in the same pull request as C3.

What it saves or protects

small: one npm ci of 73 locked packages (about 130 MB unpacked locally) skipped per run, a few seconds

Accessibility

none

Decisions

  • Fold into C3's issue? Recommended: yes.

Found by the efficiency and reliability audit of 2026-10-30 (finding C3, C4; index postulo/postulo#1108). Checked against main at daee30b15 (2026-10-30).

This issue holds 2 findings of the audit that share one fix or the same files. ## C3: CI: the Security job installs the whole project to run pip-audit over an exported lock ### What exists today `.forgejo/workflows/ci.yml:688-691`: ``` uv export --no-emit-project --all-groups --all-extras --format requirements-txt --no-hashes > /tmp/locked-requirements.txt uv run --with pip-audit==2.10.1 pip-audit --strict --progress-spinner off -r /tmp/locked-requirements.txt ``` `uv export` reads `uv.lock` and needs no environment. `uv run` inside the project does: it first syncs the project environment with the default groups (`dev`, `e2e`), which on `node:22-bookworm` means downloading a managed Python 3.14 (the image's Python 3.11 is below `requires-python`) and every locked package, building Postulo as an editable package, and only then layering pip-audit on top. pip-audit never looks at that environment: it audits the file given with `-r`. #1033's table gives the audit step 33 s. With `-r` and no hashes, pip-audit also resolves the requirements through pip in a temporary virtual environment of its own, which downloads the packages a second time. ### What would change - `uvx pip-audit==2.10.1 ...` (`uv tool run`), which runs the pinned tool in its own environment and does not touch the project. It can run on the image's own Python. - Measure, then consider, `--disable-pip --no-deps`: the export already lists every transitive pin, so pip-audit has nothing to resolve. Keep `--strict`; the set audited must stay exactly the exported lock, and `tests/test_security_audit.py` should still pass. If markers in the export (`; python_version < '3.14'`) trouble `--disable-pip`, keep the pip resolve. - C4 is the same job and the same kind of change; one pull request for both. ### What it saves or protects small: a managed Python download (34 MB), about 100 packages and an editable build skipped per run; the pip resolve inside pip-audit may be most of the step's 33 s (unmeasured) ### Accessibility none ### Decisions - **One issue for C3 and C4?** Recommended: yes, "CI: the Security job installs only what the audits read". - **`--disable-pip --no-deps`?** Recommended: only if one run shows the same findings list and a shorter step. ## C4: CI: the Security job runs `npm ci` only so that `npm audit` can read the lock ### What exists today `.forgejo/workflows/ci.yml:693-696`: ``` - name: Audit the asset build's Node dependencies run: | npm ci npm audit --audit-level=high ``` `package-lock.json` (39 KB, 73 entries under `packages`) is everything `npm audit` reports on. `npm audit` builds its tree from the lock when told to with `--package-lock-only`, which npm documents for exactly this ("only use the package-lock.json, ignore node_modules"). `npm ci` installs every devDependency, Tailwind's native binaries included; `node_modules` is 130 MB on the developer's machine. The job has no npm cache, so the install downloads every run. #1033 timed `npm ci` at 4 s in the browser job, so the saving is seconds, not minutes. ### What would change `npm audit --package-lock-only --audit-level=high`, without `npm ci`. Same advisories, same lock, same threshold. Belongs in the same pull request as C3. ### What it saves or protects small: one `npm ci` of 73 locked packages (about 130 MB unpacked locally) skipped per run, a few seconds ### Accessibility none ### Decisions - **Fold into C3's issue?** Recommended: yes. --- Found by the efficiency and reliability audit of 2026-10-30 (finding C3, C4; index postulo/postulo#1108). Checked against `main` at `daee30b15` (2026-10-30).
tiagoagueda added this to the 0.6.0 milestone 2026-10-31 03:04:28 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#1166
No description provided.