mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
f03c3150ac
npm-publish.yml runs a consumer-POV tarball audit as a publish blocker, but only at release time — so an override-masked vuln (root-only `overrides` don't propagate to consumers) merges to main undetected and only surfaces as a late, blocked release. This adds consumer-audit.yml running the SAME clean-consumer tarball audit on every dependency-affecting PR and push to main, catching the regression before merge so main stays releasable. Mirrors the proven publish-time job: npm ci -> build -> npm pack -> install the tarball into a fresh consumer project -> `npm audit --audit-level=high` from the consumer's perspective (where our overrides do NOT apply). Path-filtered to dependency-affecting files (package.json, package-lock.json, build/pack scripts, .npmignore, this workflow), least-privilege (contents: read), concurrency-guarded. Precedent: v3.9.13 shipped 15 CRITICAL protobufjs ACE vulns to every installer while in-repo `npm audit` read 0 (GHSA-xq3m-2v4x-88gg). Verified: actionlint clean; logic confirmed passing on the current v3.10.6 tree (consumer install resolves protobufjs@7.6.3, 0 high/critical). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
106 lines
4.0 KiB
YAML
106 lines
4.0 KiB
YAML
# =============================================================================
|
|
# Consumer-side Audit — shift-left supply-chain gate
|
|
# =============================================================================
|
|
#
|
|
# `npm audit` run inside THIS repo audits from our perspective, where the
|
|
# top-level `overrides` block in package.json forces patched versions of
|
|
# otherwise-vulnerable transitives (e.g. protobufjs >=7.5.6). But npm
|
|
# `overrides` are root-only — they do NOT propagate to downstream consumers.
|
|
# So an in-repo audit can read clean while `npm install agentic-qe`
|
|
# simultaneously exposes real high/critical CVEs to every user.
|
|
#
|
|
# npm-publish.yml already runs this exact check as a publish blocker, but only
|
|
# at release time. By then a masked vuln has already merged to `main` and the
|
|
# discovery is a late, disruptive blocked release. This workflow shifts the
|
|
# SAME consumer-POV audit LEFT — onto every dependency-affecting PR and every
|
|
# push to main — so the regression is caught before merge and main stays
|
|
# releasable.
|
|
#
|
|
# Precedent: at v3.9.13, 15 CRITICAL protobufjs ACE vulns
|
|
# (@xenova/transformers -> onnxruntime-web -> onnx-proto -> protobufjs,
|
|
# GHSA-xq3m-2v4x-88gg) shipped to every installer while in-repo `npm audit`
|
|
# reported 0 — invisible until a manual consumer-tarball install surfaced them.
|
|
# =============================================================================
|
|
|
|
name: Consumer Audit
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- 'package.json'
|
|
- 'package-lock.json'
|
|
- 'scripts/build-cli.mjs'
|
|
- 'scripts/build-mcp.mjs'
|
|
- '.npmignore'
|
|
- '.github/workflows/consumer-audit.yml'
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'package.json'
|
|
- 'package-lock.json'
|
|
- 'scripts/build-cli.mjs'
|
|
- 'scripts/build-mcp.mjs'
|
|
- '.npmignore'
|
|
- '.github/workflows/consumer-audit.yml'
|
|
workflow_dispatch:
|
|
|
|
# Least-privilege: only reads the repo, packs a tarball, and audits.
|
|
permissions:
|
|
contents: read
|
|
|
|
# A newer commit on the same ref supersedes an in-flight audit.
|
|
concurrency:
|
|
group: consumer-audit-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
NODE_VERSION: '24.13.0'
|
|
|
|
jobs:
|
|
consumer-audit:
|
|
name: Consumer-side audit (tarball install)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build (so the packed tarball matches what publish ships)
|
|
run: npm run build
|
|
|
|
- name: Pack tarball
|
|
id: pack
|
|
run: |
|
|
TARBALL=$(npm pack --json | jq -r '.[0].filename')
|
|
echo "tarball=${TARBALL}" >> "$GITHUB_OUTPUT"
|
|
echo "Packed: ${TARBALL}"
|
|
|
|
- name: Audit against a clean consumer install
|
|
run: |
|
|
set -euo pipefail
|
|
CONSUMER_DIR=$(mktemp -d)
|
|
pushd "${CONSUMER_DIR}" >/dev/null
|
|
echo '{"name":"audit-consumer","version":"0.0.0","private":true}' > package.json
|
|
# Install our tarball exactly as a downstream consumer would. Our
|
|
# root-only `overrides` do NOT apply here — this is the user's view.
|
|
npm install --no-audit --no-fund "${GITHUB_WORKSPACE}/${{ steps.pack.outputs.tarball }}"
|
|
# The moment of truth: fail on any high/critical CVE a consumer sees.
|
|
if ! npm audit --audit-level=high; then
|
|
echo "::error::Consumer-side npm audit found high/critical vulnerabilities reachable by end users. \
|
|
In-repo overrides do NOT protect consumers — fix the dependency (upgrade, replace, or drop the vulnerable path) \
|
|
before merging. See .github/workflows/consumer-audit.yml header for context."
|
|
popd >/dev/null
|
|
exit 1
|
|
fi
|
|
popd >/dev/null
|
|
echo "Consumer-side audit clean — no high/critical CVEs reachable by end users."
|