Files
ruv d09a0e4cbd fix(ci): 5 CI failures — Build V3, Static guards, ADR-112, witness verify, supply-chain audit
Stacked fixes to clear the remaining red CI checks on \`main\` that pre-dated
the #2412 lockfile-cascade fix. Each one verified locally before commit.

1. **Build V3 (ubuntu/macos/windows)** — \`graph-edge-writer.ts\` did a static
   \`await import('better-sqlite3')\` which forces tsc to resolve the package's
   types at build time. \`better-sqlite3\` is in \`optionalDependencies\` (so
   CI doesn't install it) — type resolution failed with TS2307 on every
   platform. Routed the module name through a variable so the static analyzer
   stops trying to resolve it; runtime presence is still gated by the
   existing try/catch.

2. **Static regression guards (#2267)** — \`scripts/smoke-workflows-yaml.mjs\`
   crashed with \`SyntaxError: The requested module 'js-yaml' does not provide
   an export named 'default'\` after js-yaml dropped the synthetic default
   from its package exports. Switched to \`import * as yaml from 'js-yaml'\`.

3. **Tool description discoverability (ADR-112)** — two MCP tools regressed
   the no-guidance baseline (count went from 0 → 2):
     - \`metaharness_bench\` had no Use-when / Prefer / Pair-with hint
     - \`testgen_tdd_repair\` had \"Use when …\" in a *later* string
       fragment of a concatenated description, which the audit regex
       (single-quoted-literal-only) misses
   Added explicit \"Use when …\" guidance to the first fragment of each.
   Audit now reports 340/340 tools with guidance.

4. **witness verify precondition smoke (#1880)** — Root \`package-lock.json\`
   drifted: \`agentdb@3.0.0-alpha.16\` in lock vs \`^3.0.0-alpha.17\` in
   package.json (same root cause as #2412 but for the npm lockfile, not the
   pnpm one fixed last release). Every job that runs \`npm ci\` was failing
   at install. Regenerated via \`npm install --package-lock-only\`. Verified:
   \`npm ci --dry-run --legacy-peer-deps\` now exits 0.

5. **Supply-chain audit (#2046)** — \`plugins/ruflo-graph-intelligence\` had
   1 HIGH/CRITICAL unaccepted direct-dep finding:
     - \`ws@8.20.1\` pulled by \`sublinear-time-solver\` (GHSA-96hv-2xvq-fx4p,
       memory exhaustion DoS) — bumped root override \`ws >=8.18.4\` →
       \`>=8.21.0\` and added the same override to the plugin's own
       package.json so it propagates through the plugin's own npm install
     - \`@claude-flow/cli\` peerDep surfaces every HIGH transitive in cli's
       own tree inside the plugin's audit report — added a tracked,
       expiring accepted-finding (cli ships its own audit pipeline on
       every publish; the plugin doesn't redistribute cli's tree).
   Audit now reports \`OK: no hard-fail findings\`.

Verified locally:
  - \`npm run build\` in v3/@claude-flow/cli: clean
  - \`node scripts/smoke-workflows-yaml.mjs\`: exit 0, 53 workflows parsed
  - \`node scripts/audit-tool-descriptions.mjs\`: 340/340 with guidance, OK
  - \`npm ci --dry-run --legacy-peer-deps\` at repo root: exit 0
  - \`node scripts/audit-supply-chain.mjs\`: OK, no hard-fail findings

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-06-25 18:18:19 -04:00
..

Supply-chain hardening — .github/supply-chain/

This directory is the maintained surface for ruflo's supply-chain defence.

CI runs scripts/audit-supply-chain.mjs on every PR and push that touches a package.json, a lockfile, this directory, or the audit script itself. Five layers of defence:

# Layer Source of truth Hard-fail?
1 CVE audit (HIGH/CRITICAL in DIRECT deps) npm audit ✅ unless accepted
2 Lockfile integrity (SHA-512 on every downloaded entry) package-lock.json ✅ unless accepted
3 Top-level allowlist allowed-deps.json ✅
4 Typosquat reject allowed-deps.json → policies.rejectInRegistry ✅
5 Publisher trust snapshot live npm view logged-only

Plus, on PRs only, GitHub's actions/dependency-review-action@v4 flags newly-added vulnerable deps + denies the deny-list of compromised package versions.

Files

allowed-deps.json

Whitelist of direct deps per package. Adding a new direct dep to a covered package requires an explicit allowlist edit. Also lists policies.rejectInRegistry — names we always block regardless of whether they're real (typosquat defence) — and publisherTrust.criticalUpstreamPackages — upstream deps whose maintainer identity we snapshot in CI logs so unexpected handover is visible.

accepted-findings.json

Triaged findings that the audit currently tolerates. Every entry must cite a tracking issue or ADR, and should have an expiresAt date so the audit re-fails after the triage window expires.

Editing this file requires CODEOWNER review per .github/CODEOWNERS.

Running locally

# Full audit
node scripts/audit-supply-chain.mjs

# JSON output (for tooling)
node scripts/audit-supply-chain.mjs --json

# Just one layer
node scripts/audit-supply-chain.mjs --scope cve
node scripts/audit-supply-chain.mjs --scope lockfile
node scripts/audit-supply-chain.mjs --scope allowlist
node scripts/audit-supply-chain.mjs --scope typosquat
node scripts/audit-supply-chain.mjs --scope publisher-trust

Adding a new package to the audit

  1. Add the package path to PACKAGES_TO_AUDIT in scripts/audit-supply-chain.mjs.
  2. Add a packages.<pkgName> block to allowed-deps.json listing the expected dependencies / devDependencies / peerDependencies.
  3. Add a dependabot stanza to .github/dependabot.yml.
  4. Run node scripts/audit-supply-chain.mjs locally — fix any new findings before opening the PR.

Triaging a new finding

If audit-supply-chain.mjs fails on your PR:

  • CVE in direct dep — first try to upgrade the offending dep. If the upstream maintainer hasn't released a fix yet, add an entry to accepted-findings.json.cve[] with:
    • package, depName, severity, via — copy from the audit's failure output
    • tracking — short label (e.g. "ADR-121 Phase 4")
    • trackingIssue — link to the GitHub issue / ADR file
    • expiresAt — 90 days from today (audit will re-fail then so re-triage is forced)
    • rationale — why we can ship with this finding (e.g. "vulnerable code path not invoked from our usage")
  • Lockfile missing integrity — check if it's a pnpm-store-shadow or workspace-link entry (those legitimately have no integrity). If so, add a lockfile[] entry with the path pattern.
  • Allowlist violation — either the new dep is legitimate (add it to allowed-deps.json) or unintended (remove from package.json).
  • Typosquat hit — never accept. Either fix the typo or remove the dep entirely.

Why this matters

Three real supply-chain incidents on npm in the last 18 months involved:

  • a maintainer takeover of a popular package (colors@1.4.1, ua-parser-js)
  • a typosquat that pulled in event-stream → flatmap-stream and exfiltrated wallets
  • a postinstall script in a transitively-pulled dep that ran during npm install

This audit doesn't make ruflo immune. It does make these patterns visible in CI before they reach production, with structured failures the maintainer can triage rather than silent installs.

Related: ADR-123 (introduced the new plugin under audit), ADR-122 (introduced the browser substrate under audit).