Skip to content

ci: add 7-day lockfile age audit for package-lock.json - #882

Merged
peter-leonov-ch merged 3 commits into
mainfrom
chore/lockfile-age-audit
Jun 23, 2026
Merged

ci: add 7-day lockfile age audit for package-lock.json#882
peter-leonov-ch merged 3 commits into
mainfrom
chore/lockfile-age-audit

Conversation

@motsc

@motsc motsc commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

fails PRs that add package-lock.json entries published less than 7 days ago. complements the Dependabot cooldown by catching anything that bypasses it (manual edits, --package-lock-only, escape flags), audits the lockfile diff so it isn't tool-specific.

set-diff against git merge-base origin/main HEAD, not + lines, so lockfile reorders don't false-positive. existing lockfile grandfathered. ~1 registry request per added package, concurrency 8. @clickhouse/* excluded.

escape hatch is the lockfile-age-skip label, for legit CVE bumps inside the window.

failure looks like:

✗ 1 entries younger than 7 days:
  foo@1.2.3
    published: 2026-XX-XXT14:00:00Z (2 days ago)
    mergeable after: 2026-XX-XXT14:00:00Z

advisory only until repo admin adds Lockfile age audit / audit as a required check on main. will follow up once this lands.

companion: #881.

Comment thread scripts/ci/lockfile-age-audit.mjs Fixed
Fails PRs that add package-lock.json entries published less than 7 days
ago. Catches lockfile-bypass paths the Dependabot cooldown doesn't
cover (manual edits, --package-lock-only, escape flags).

Set-diffs head vs merge-base resolutions (not just '+' lines) so
lockfile reorders don't trigger false positives. @clickhouse/*
preapproved — first-party.

Skip via 'lockfile-age-skip' label.
@motsc
motsc force-pushed the chore/lockfile-age-audit branch from 2646b5f to c8d9507 Compare June 23, 2026 10:23
…okup

CodeQL flagged name.replace('/', '%2F') as only replacing the first '/'.
For valid npm names that's always one '/' max (scoped: @scope/pkg), so
no functional bug today — just hardens against future regressions.
@motsc
motsc marked this pull request as ready for review June 23, 2026 10:27
Copilot AI review requested due to automatic review settings June 23, 2026 10:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new GitHub Actions workflow and Node.js script to enforce a “minimum lockfile entry age” policy for package-lock.json changes in PRs. The workflow diffs lockfile resolutions between the PR’s merge-base and HEAD, then queries the npm registry to fail PRs that introduce packages published within the last 7 days (with an opt-out label).

Changes:

  • Introduces scripts/ci/lockfile-age-audit.mjs to compute newly-added lockfile resolutions and validate their publish timestamps via the npm registry.
  • Adds .github/workflows/lockfile-age-audit.yml to run the audit on PR events, with a lockfile-age-skip label escape hatch.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
scripts/ci/lockfile-age-audit.mjs Implements the lockfile resolution diffing and npm publish-time checks.
.github/workflows/lockfile-age-audit.yml Runs the audit in CI on PR updates and supports a label-based bypass.

Comment thread scripts/ci/lockfile-age-audit.mjs Outdated
Comment thread scripts/ci/lockfile-age-audit.mjs
Comment thread scripts/ci/lockfile-age-audit.mjs
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
if (next) await checkOne(next)
}
}
await Promise.all(Array.from({ length: CONCURRENCY }, worker))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is likely gonna get us rate limited

@peter-leonov-ch
peter-leonov-ch merged commit 66acb4d into main Jun 23, 2026
10 checks passed
@peter-leonov-ch
peter-leonov-ch deleted the chore/lockfile-age-audit branch June 23, 2026 10:49
peter-leonov-ch added a commit that referenced this pull request Jun 24, 2026
…rettify (#886)

## Summary

Addresses CI failure and review feedback on the lockfile age gate
(`scripts/ci/lockfile-age-audit.mjs`, introduced in #882). These changes
are made in a fresh PR to `main` because #883 targets the `release`
branch and cannot be modified.

Two fixes, both in `scripts/ci/lockfile-age-audit.mjs`:

1. **Fail closed on non-registry sources** (Copilot review comment).
Previously `extractNpmResolutions` silently `continue`d on any entry
whose `resolved` host was not an allowed registry, so a PR could bypass
the age gate entirely by pinning a new dependency from an alternative
registry, a plain-`http` URL, or a `git+https` source. Now
`isRegistryEntry` is replaced by `classifyResolved`:
- `registry` — allowed HTTPS registry tarball → audited against the age
gate (unchanged behavior).
- `foreign` — a URL but not an allowed HTTPS registry host → **fails
closed** (new).
- `local` — no resolved URL (workspace source dirs, `file:` links) →
skipped, nothing to age-check.

The `lockfile-age-skip` PR label (handled in
`.github/workflows/lockfile-age-audit.yml`) remains the intentional
escape hatch.

2. **Prettier formatting** (Copilot review comment + the failing
`code-quality` check). The file was written in single-quote /
no-semicolon style; the repo's Prettier defaults (`.prettierrc` = `{}`)
use double quotes + semicolons. Reformatted with `prettier --write`.

## Verification

- `prettier --check` passes on the file (full-repo check is clean apart
from an untracked local scratch dir).
- `node --check` passes.
- Manually exercised the fail-closed path against synthetic lockfiles:
new deps resolved from an alternative host, `git+https`, and plain
`http` all fail closed; unchanged legit registry entries are not
flagged.

## Test plan

- [x] `npm run prettier:check` clean for tracked files
- [x] Fail-closed logic verified against synthetic base/head lockfiles

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (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.

4 participants