Skip to content

perf(vuln-scan): audit the lock file instead of installing - #54

Merged
oxyc merged 1 commit into
masterfrom
perf/scan-locked-audit
Jul 30, 2026
Merged

perf(vuln-scan): audit the lock file instead of installing#54
oxyc merged 1 commit into
masterfrom
perf/scan-locked-audit

Conversation

@oxyc

@oxyc oxyc commented Jul 30, 2026

Copy link
Copy Markdown
Member

The nightly scan installed the entire project in order to audit it, then threw the installation away. It is the largest single line in the org's CI bill — 19 repos, every night — and almost all of it is scaffolding.

Where the time went

suomentyokalu run 30515814093, 90s total:

36s  Random delay           (removed separately)
23s  Post Setup project     saving caches
14s  Install dependencies   composer install
 9s  Setup project          Node + PHP + cache restores
 2s  Run vulnerability scan

The audit is 2 seconds. The other ~50s exists to populate vendor/ — and the workflow contains not one reference to vendor/.

The change

composer audit --locked reads composer.lock directly. Verified locally: 2s, and the same .advisories JSON shape the existing jq -e '.advisories' guard requires. Same advisory sources, since the wpsecadv repository is still configured.

That makes the install redundant, and with it all three caches and Node. The job becomes: checkout → PHP → auth → audit. The shared setup action is deliberately not used here — it installs Node and manages three caches this job has no use for.

Expected ~90s → ~15s per scan, ~19 × 30 runs a month.

The auto-update path still works on the lock alone

composer update -W / composer require calls gain --no-install, so they rewrite composer.json and composer.lock without materialising vendor/. This is what the flow already wanted: the PR it opens has always been a lock diff, and its post-update gate is composer validate --no-check-all --no-check-publish, which inspects composer.json against the lock rather than an installed tree.

The composer-update test suite runs on this PR and exercises those call sites.

Details worth reviewing

  • PHP version is read from config.platform.php as the shared action does, rather than hardcoded, so repos on older PHP are unaffected.
  • Yoast auth is guarded in the shell, not with if:secrets.* is unavailable in step-level if: inside a reusable workflow, which this repo already fixed once in 2702182.
  • Repository auth is retained. --locked resolves nothing, but composer still loads metadata from configured repositories and the private ones 401 without credentials.

Verification plan

Timing on a real repo via a temporary pin, with auto_update: false so no spurious PRs are opened. The vulns-found path needs a genuine finding to exercise end to end; the composer-update tests cover the script changes in the meantime.

🤖 Generated with Claude Code

The scan installed the whole project to audit it, then threw the result away.
Measured on suomentyokalu run 30515814093 (90s total):

  36s  Random delay          (removed separately)
  23s  Post Setup project    saving caches
  14s  Install dependencies  composer install
   9s  Setup project         Node + PHP + cache restores
   2s  Run vulnerability scan

The audit is 2s. Everything else exists to populate vendor/, which this job
never reads — there is not one reference to vendor/ in the workflow.

composer audit --locked reads composer.lock directly: same advisory data, same
JSON shape the jq guard already requires, no install. That removes the install,
all three caches and Node entirely, leaving checkout, PHP, auth and the audit.

composer-update keeps working on the lock alone — its calls gain --no-install,
and its post-update check is composer validate, which inspects composer.json and
composer.lock rather than vendor/. The PR it opens has always been a lock diff.

Expected ~90s -> ~15s per scan. Across 19 repos every night that is the largest
remaining item in the org's CI bill.

Not using the shared setup action here on purpose: it installs Node and manages
three caches this job has no use for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@oxyc
oxyc merged commit 2726f90 into master Jul 30, 2026
1 check passed
@oxyc
oxyc deleted the perf/scan-locked-audit branch July 30, 2026 17:45
oxyc added a commit that referenced this pull request Jul 31, 2026
#54 removed composer install from this job because the audit runs off
composer.lock. It does — but composer-update does not: its
compute-min-safe-constraints.php loads composer/semver from the consuming
project's vendor/autoload.php and bails with 'needs composer install first'
when it is missing.

That broke the vulns-found path on the first night. generoi/solving run
30598123430: audit correct, PR body assembled, then 'Update packages' died in
70ms. The same path succeeded on the four previous nights.

I checked the workflow for vendor/ references before #54 and found none; I did
not check the action it calls.

Install only on that path, gated on the same condition the update steps already
use, with the download cache restored alongside so it does not fetch every
package over the network. A clean scan — about half of nightly runs — still
finishes in ~12s having installed nothing.

Co-authored-by: test <test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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