UNPKG

claude-flow

Version:

Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration

169 lines (153 loc) 6.95 kB
#!/usr/bin/env node /** * Regression guard for ruvnet/ruflo#1880. * * The 12-hour scheduled witness verification runs `verify.mjs` in a * source-only checkout (no `npm ci`, no `npm run build`) and conflates * two completely different failure modes: * * 1. `@noble/ed25519` not installed → precondition (install needed) * 2. dist files referenced by manifest → precondition (build needed) * not present on disk * 3. signature actually doesn't verify → real failure * 4. specific dist file regressed → real failure * * Before this guard, all four exited with code 1, so the scheduled * runner filed a duplicate "verification failed" issue every 12 hours * even though nothing was actually wrong with the manifest. * * verify.mjs now reserves exit 2 for preconditions (cases 1 and 2) and * keeps exit 1 strictly for real failures (cases 3 and 4). This smoke * drives both shapes through the script and asserts the contract holds. * * Fails CI if any of: * - missing @noble/ed25519 exit code is anything other than 2 * - all-files-missing manifest exit code is anything other than 2 * - precondition output missing the operator-facing fix hint * - precondition output missing the machine-parseable `reason` / `precondition` field */ import { spawnSync } from 'node:child_process'; import { existsSync, mkdirSync, mkdtempSync, writeFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join, resolve } from 'node:path'; const REPO_ROOT = process.cwd(); const VERIFY = resolve(REPO_ROOT, 'plugins/ruflo-core/scripts/witness/verify.mjs'); const REAL_MANIFEST = resolve(REPO_ROOT, 'verification/macos/manifest.md.json'); if (!existsSync(VERIFY)) { console.error(`smoke: not found: ${VERIFY}`); process.exit(1); } if (!existsSync(REAL_MANIFEST)) { console.error(`smoke: not found: ${REAL_MANIFEST}`); process.exit(1); } const failures = []; function record(name, condition, detail) { if (condition) { console.log(` PASS ${name}`); } else { console.log(` FAIL ${name}`); if (detail) console.log(` ${detail}`); failures.push(name); } } // ── Case 1: @noble/ed25519 missing → exit 2 (precondition) ────────── // Drop verify.mjs into an empty root with no node_modules anywhere up // the tree, so the ed25519 probe fails on every candidate. console.log('\nCase 1: @noble/ed25519 not installed (source-only)'); { const tmp = mkdtempSync(join(tmpdir(), 'witness-smoke-nodep-')); // verify.mjs's probes use createRequire(join(root, 'noop.js')) which // walks up from `root`. Putting `root` deep under tmp ensures Node // walks /tmp/.../node_modules (absent) then /tmp/node_modules (absent) // then /node_modules (absent on CI) — no resolution. const isolatedRoot = join(tmp, 'isolated', 'repo'); mkdirSync(isolatedRoot, { recursive: true }); // Stub node_modules to mask any system-level @noble/ed25519 install. mkdirSync(join(isolatedRoot, 'node_modules'), { recursive: true }); const out = spawnSync('node', [VERIFY, '--manifest', REAL_MANIFEST, '--root', isolatedRoot, '--json'], { encoding: 'utf8', env: { ...process.env, NODE_PATH: '' }, }); record( 'exit code is 2 (precondition), not 1', out.status === 2, `got exit=${out.status}, stdout=${out.stdout?.slice(0, 200)}, stderr=${out.stderr?.slice(0, 200)}`, ); record( 'stderr names @noble/ed25519 and the fix command', /@noble\/ed25519/.test(out.stderr) && /npm (ci|install)/.test(out.stderr), `stderr=${out.stderr?.slice(0, 400)}`, ); record( 'JSON output carries machine-parseable precondition tag', /noble-ed25519-not-installed/.test(out.stdout), `stdout=${out.stdout?.slice(0, 200)}`, ); rmSync(tmp, { recursive: true, force: true }); } // ── Case 2: all manifest files missing → exit 2 (precondition) ────── // Point verify.mjs at an isolated root that DOES have @noble/ed25519 // reachable (symlinked from the real install) but has none of the // manifest's dist/ files — mimicking a clean clone with no build run. console.log('\nCase 2: all manifest files missing (source-only, deps installed)'); { const tmp = mkdtempSync(join(tmpdir(), 'witness-smoke-nobuild-')); // Make @noble/ed25519 reachable by symlinking node_modules. const realNodeModules = resolve(REPO_ROOT, 'node_modules'); if (existsSync(join(realNodeModules, '@noble', 'ed25519'))) { mkdirSync(join(tmp, 'node_modules', '@noble'), { recursive: true }); // Use a relative symlink that survives the spawn. const src = join(realNodeModules, '@noble', 'ed25519'); const dst = join(tmp, 'node_modules', '@noble', 'ed25519'); try { // fs.symlinkSync via spawnSync to avoid extra import for the rare-path branch. spawnSync('ln', ['-s', src, dst]); } catch { /* best-effort */ } } const out = spawnSync('node', [VERIFY, '--manifest', REAL_MANIFEST, '--root', tmp, '--json'], { encoding: 'utf8', }); // We accept either: // - exit 2 with precondition=dist-not-built (the new behavior) // - exit 2 with precondition=noble-ed25519-not-installed (if the // symlink trick didn't satisfy the probe on this runner — also a // precondition, still not a real failure) // We do NOT accept exit 1 — that's the bug this guard exists to catch. record( 'exit code is 2 (precondition), not 1', out.status === 2, `got exit=${out.status}, stdout head=${out.stdout?.slice(0, 200)}, stderr head=${out.stderr?.slice(0, 200)}`, ); record( 'output carries a precondition tag', /noble-ed25519-not-installed|dist-not-built/.test(out.stdout + out.stderr), `combined output=${(out.stdout + out.stderr).slice(0, 400)}`, ); rmSync(tmp, { recursive: true, force: true }); } // ── Case 3: built tree → never exit 2 (precondition is one-way) ───── // On a built tree the verifier may produce 0 (clean) or 1 (some real // regression caught) — both mean verification actually ran. What it // must NEVER produce here is exit 2, because that would mean a built // tree was mis-classified as "needs install/build" and the scheduled // runner would silently skip filing real regressions. console.log('\nCase 3: built tree never reports precondition'); { const out = spawnSync('node', [VERIFY, '--manifest', REAL_MANIFEST], { encoding: 'utf8', cwd: REPO_ROOT, }); record( 'exit code is NOT 2 (built tree should never be flagged as a precondition miss)', out.status !== 2, `got exit=${out.status}, tail=${(out.stdout + out.stderr).slice(-300)}`, ); } console.log(''); if (failures.length > 0) { console.error(`smoke-witness-verify-precondition: ${failures.length} check(s) failed:`); for (const f of failures) console.error(` - ${f}`); process.exit(1); } console.log('smoke-witness-verify-precondition: all checks passed');