Files
ruvnet__ruflo/scripts/smoke-workflows-yaml.mjs
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

69 lines
2.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Smoke test for #2267: every .github/workflows/*.yml must parse as YAML.
*
* Root cause that motivated this guard: an unquoted `:` inside a step `name`
* (`Guard 2 — smoke: generate ...`) made the YAML parser treat `smoke:` as a
* second mapping key, rejecting the whole workflow. GitHub Actions accepted
* the push and scheduled the run, but produced zero jobs and a "workflow
* file issue" failure — invisible to the kind of green-build dashboard that
* usually catches regressions. Five consecutive scheduled runs failed
* silently before #2267 surfaced it.
*
* This guard runs as an early CI step so any future YAML break is caught
* at PR-time, not at scheduled-cron-time when nobody is looking.
*
* Exit codes:
* 0 — every workflow parsed
* 1 — at least one workflow failed to parse
*/
import { readFileSync, readdirSync } from 'node:fs';
import { join } from 'node:path';
// js-yaml's package exports map removed the synthetic default in newer
// versions when loaded as ESM, so `import yaml from 'js-yaml'` throws
// `SyntaxError: does not provide an export named 'default'`. Use the
// namespace import — works in every js-yaml release since 4.x.
import * as yaml from 'js-yaml';
const WORKFLOWS_DIR = '.github/workflows';
let files;
try {
files = readdirSync(WORKFLOWS_DIR).filter(f => f.endsWith('.yml') || f.endsWith('.yaml'));
} catch (e) {
console.error(`No ${WORKFLOWS_DIR} directory (or unreadable): ${e.message}`);
process.exit(1);
}
let failed = 0;
const results = [];
for (const file of files.sort()) {
const full = join(WORKFLOWS_DIR, file);
try {
const parsed = yaml.load(readFileSync(full, 'utf8'));
const jobCount = parsed && parsed.jobs ? Object.keys(parsed.jobs).length : 0;
results.push({ file, ok: true, jobs: jobCount });
} catch (e) {
failed++;
results.push({
file,
ok: false,
error: e.message,
line: e.mark ? e.mark.line + 1 : null,
column: e.mark ? e.mark.column + 1 : null,
});
}
}
const okCount = results.filter(r => r.ok).length;
console.log(`Workflows: ${okCount}/${results.length} parsed`);
for (const r of results) {
if (r.ok) {
console.log(` ok ${r.file} (${r.jobs} jobs)`);
} else {
console.log(` FAIL ${r.file} ${r.line}:${r.column} ${r.error}`);
}
}
process.exit(failed > 0 ? 1 : 0);