23f7624596
🔄 Automated Rollback Manager / 🔄 Execute Rollback (push) Blocked by required conditions
🔄 Automated Rollback Manager / ✅ Post-Rollback Verification (push) Blocked by required conditions
🔄 Automated Rollback Manager / 📊 Rollback Monitoring (push) Blocked by required conditions
🔄 Automated Rollback Manager / ⏳ Manual Rollback Approval (push) Blocked by required conditions
V3 CI/CD Pipeline / MCP protocol smoke / macos-latest (push) Waiting to run
V3 CI/CD Pipeline / Memory import smoke / macos-latest (push) Waiting to run
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / macos-latest (push) Waiting to run
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / windows-latest (push) Waiting to run
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / macos-latest (push) Waiting to run
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / windows-latest (push) Waiting to run
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / macos-latest (push) Waiting to run
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / windows-latest (push) Waiting to run
V3 CI/CD Pipeline / Witness verify (signed manifest) / macos-latest (push) Blocked by required conditions
V3 CI/CD Pipeline / Witness verify (signed manifest) / ubuntu-latest (push) Blocked by required conditions
V3 CI/CD Pipeline / Witness verify (signed manifest) / windows-latest (push) Blocked by required conditions
V3 CI/CD Pipeline / Publish to npm (alpha) (push) Blocked by required conditions
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / macos-latest / Node 22 (push) Waiting to run
V3 CI/CD Pipeline / Plugin hooks smoke / macos-latest / Node 22 (push) Waiting to run
ADR-166 MCP Bridge Security Lock / Static-source security lock (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / Compose default binds loopback + Mongo has auth (push) Failing after 2s
CodeQL Advanced / Analyze (rust) (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / plugin-agent-federation bindHost default (push) Failing after 1s
ADR-166 MCP Bridge Security Lock / Runtime behavior — 401 + terminal gate + fail-closed (push) Failing after 4s
business-pods-smoke / smoke (push) Failing after 1s
all-plugins-smoke / smoke-all (push) Failing after 2s
CI/CD Pipeline / Security & Code Quality (push) Failing after 1s
CI/CD Pipeline / Test Suite (ubuntu-latest) (push) Failing after 1s
CI/CD Pipeline / Build & Package (macos-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (ubuntu-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (windows-latest) (push) Has been skipped
CI/CD Pipeline / Deploy & Release (push) Waiting to run
CI/CD Pipeline / CI Status (push) Waiting to run
CI/CD Pipeline / Documentation & Examples (push) Failing after 1s
Clone Tracker (14-day rolling) / Snapshot clones for ruflo ecosystem (push) Failing after 1s
CodeQL Advanced / Analyze (actions) (push) Failing after 1s
CodeQL Advanced / Analyze (javascript-typescript) (push) Failing after 1s
federation-peer-rust / stable-noop (push) Failing after 1s
metaharness-ci / score (push) Failing after 1s
metaharness-ci / router-compat (push) Failing after 0s
metaharness-ci / similarity-tests (push) Failing after 0s
no-agentbbs-smoke / smoke-without-agentbbs (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (windows-latest) (push) Has been skipped
codex-integration-audit / Codex integration audit (push) Failing after 1s
helpers-manifest-guard / guard (push) Failing after 1s
🔗 Cross-Agent Integration Tests / 🤝 Agent Coordination Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🧠 Memory Sharing Integration (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🛡️ Fault Tolerance Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / ⚡ Performance Integration Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / 📊 Integration Test Report (push) Waiting to run
metaharness-ci / mcp-scan (push) Failing after 1s
metaharness-ci / eject-dryrun (push) Failing after 1s
metaharness-ci / metaharness-real-data (push) Failing after 0s
no-cli-optdep-bloat-2561 / guard (push) Failing after 1s
no-metaharness-smoke / smoke-without-metaharness (push) Failing after 1s
no-phantom-agentic-flow-subpath / guard (push) Failing after 1s
🔄 Automated Rollback Manager / 🚨 Failure Detection (push) Failing after 1s
V3 CI/CD Pipeline / Plugin hooks smoke / ubuntu-latest / Node 22 (push) Failing after 1s
V3 CI/CD Pipeline / ruflo-graph-intelligence build + test smoke (#2044, ADR-123) (push) Failing after 1s
CVE Audit Gate / Audit root (critical-blocking) (push) Failing after 2s
cost-tracker-smoke / smoke (push) Failing after 3s
oia-audit-weekly / audit (push) Failing after 2s
ruflo-agent-smoke / ruflo-agent structural smoke (push) Failing after 1s
📊 Status Badges Update / 📊 Update Status Badges (push) Failing after 1s
V3 CI/CD Pipeline / Static regression guards (#2267 YAML + (push) Failing after 1s
V3 CI/CD Pipeline / Test V3 Packages (push) Failing after 0s
V3 CI/CD Pipeline / agent_execute provider routing smoke (#2042) (push) Failing after 0s
CVE Audit Gate / Audit v3 (critical-blocking) (push) Failing after 1s
federation-peer-rust / stable-native (push) Failing after 2s
🔗 Cross-Agent Integration Tests / 🚀 Integration Test Setup (push) Failing after 2s
neural-trader-smoke / runtime-smoke (push) Failing after 1s
🔄 Automated Rollback Manager / 🔍 Pre-Rollback Validation (push) Waiting to run
V3 CI/CD Pipeline / Build V3 (macos-latest) (push) Has been skipped
V3 CI/CD Pipeline / Build V3 (ubuntu-latest) (push) Has been skipped
V3 CI/CD Pipeline / Type Check V3 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 24 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 22 (push) Failing after 2s
V3 CI/CD Pipeline / browser rvf create flag smoke (#2015) (push) Failing after 0s
V3 CI/CD Pipeline / Dependency review (#2046) (push) Has been skipped
V3 CI/CD Pipeline / Supply-chain audit (#2046) (push) Failing after 0s
V3 CI/CD Pipeline / witness marker drift smoke (#2021) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader portfolio CG smoke (#2068, ADR-126 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader backtest signing smoke (#2068, ADR-126 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / kg-extract type-import classification smoke (#2049) (push) Failing after 0s
V3 CI/CD Pipeline / witness verify precondition smoke (#1880) (push) Failing after 2s
V3 CI/CD Pipeline / neural-trader pipeline risk-gate smoke (#2068, ADR-126 Phase 5) (push) Failing after 0s
V3 CI/CD Pipeline / neural-trader feature attribution smoke (#2068, ADR-126 Phase 6) (push) Failing after 0s
V3 CI/CD Pipeline / plugin-registry signature verification smoke (#1922, CWE-347) (push) Failing after 4s
V3 CI/CD Pipeline / memory stats legacy-DB smoke (#2120) (push) Failing after 4s
V3 CI/CD Pipeline / github deprecated actions smoke (#2089, ADR-127 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / graph query + pathfinder smoke (ADR-130 P2+P5) (push) Has been skipped
V3 CI/CD Pipeline / graph trajectory hooks smoke (ADR-130 P3) (push) Has been skipped
V3 CI/CD Pipeline / graph plugin adapter smoke (ADR-130 P4) (push) Has been skipped
V3 CI/CD Pipeline / graph benchmark (ADR-130 P6) (push) Has been skipped
V3 CI/CD Pipeline / statusline generator delegation smoke (#2195) (push) Failing after 1s
V3 CI/CD Pipeline / wizard init regression guard (#2206 (push) Failing after 1s
V3 CI/CD Pipeline / memory no-stray-db smoke (ADR-125 P7) (push) Failing after 1s
V3 CI/CD Pipeline / github-safe injection smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github actions pin smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github attribution opt-in smoke (#2089, ADR-127 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / pre-bash hook safety smoke (#2017) (push) Failing after 1s
V3 CI/CD Pipeline / Memory import smoke / ubuntu-latest (push) Failing after 0s
V3 CI/CD Pipeline / MCP protocol smoke / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / ruvllm WASM auto-init smoke (#2086) (push) Failing after 4s
V3 CI/CD Pipeline / MCP paired-tool round-trip smoke (#1889) (push) Failing after 1s
V3 CI/CD Pipeline / Plugin package install-safety (#1902/#1903/#1904) (push) Failing after 1s
V3 CI/CD Pipeline / Tool description discoverability (ADR-112) (push) Failing after 3s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (22) (push) Failing after 1s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (24) (push) Failing after 1s
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Vector-index dimension audit (#1947) (push) Failing after 0s
V3 CI/CD Pipeline / Hook-command install safety (#1921) (push) Failing after 1s
V3 CI/CD Pipeline / ToolOutputGuardrail smoke (ADR-131, (push) Failing after 1s
V3 CI/CD Pipeline / init-bundle invariants smoke (#2095, ADR-128 Phase 5) (push) Failing after 1s
V3 CI/CD Pipeline / wasm provider bridge smoke (ADR-129 P1) (push) Failing after 2s
V3 CI/CD Pipeline / wasm gallery CRUD smoke (ADR-129 P3) (push) Failing after 1s
V3 CI/CD Pipeline / wasm plugin bridge smoke (ADR-129 P4) (push) Failing after 0s
V3 CI/CD Pipeline / wasm compose smoke (ADR-129 P2) (push) Failing after 4s
V3 CI/CD Pipeline / graph schema smoke (ADR-130 P1) (push) Failing after 0s
Validate Marketplace / validate (push) Failing after 1s
🔍 Verification Pipeline / 🚀 Setup Verification (push) Failing after 1s
🔍 Verification Pipeline / 🛡️ Security Verification (push) Has been skipped
🔍 Verification Pipeline / 📝 Code Quality (push) Has been skipped
🔍 Verification Pipeline / 🧪 Test Verification (${{ matrix.os }}, Node ${{ matrix.node }}) (push) Has been skipped
🔍 Verification Pipeline / 🏗️ Build Verification (push) Has been skipped
🔍 Verification Pipeline / 📚 Documentation Verification (push) Has been skipped
🔍 Verification Pipeline / ⚡ Performance Verification (push) Waiting to run
🔍 Verification Pipeline / 📊 Verification Report (push) Waiting to run
CVE Audit Gate / High-severity report (warn only) (push) Has been cancelled
343 lines
16 KiB
JavaScript
343 lines
16 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Static guard for ruvnet/ruflo ADR-125 / ADR-130 env-var precedence pattern.
|
|
*
|
|
* Context
|
|
* -------
|
|
* ADR-125 (rvagent integration) and ADR-130 (graph intelligence backend)
|
|
* introduced several new env vars that configure runtime behaviour:
|
|
*
|
|
* CLAUDE_FLOW_MEMORY_PATH — override memory root directory
|
|
* CLAUDE_FLOW_DISABLE_BRIDGE — bypass AgentDB v3 bridge
|
|
* CLAUDE_FLOW_GRAPH_BACKEND — select graph backend (sqlite | agentdb)
|
|
* CLAUDE_FLOW_GRAPH_DECAY_RATE — default temporal decay rate
|
|
* CLAUDE_FLOW_EMBED_DIMS — embedding dimension override
|
|
*
|
|
* The project's documented resolution order for every config value is:
|
|
*
|
|
* CLI flag > ENV var > config-file > hardcoded default
|
|
*
|
|
* This audit scans the source tree for any env var read pattern that does NOT
|
|
* have a corresponding CLI-flag precedence guard (i.e., where `process.env`
|
|
* is the ONLY source of the value and no CLI argument can override it).
|
|
*
|
|
* Concretely it checks that every `process.env.CLAUDE_FLOW_*` read site
|
|
* either:
|
|
* (a) is inside a function that accepts an explicit argument (meaning the
|
|
* caller CAN pass a CLI-derived value and the env var is only a
|
|
* fallback), OR
|
|
* (b) has a comment containing "cli.*flag" / "argv" / "precedence" / "flag"
|
|
* documenting that a CLI flag takes precedence, OR
|
|
* (c) is a known opt-out env var (DISABLE_BRIDGE, SKIP_NPX — intentionally
|
|
* env-only because they are CI/test escape hatches, not user config).
|
|
*
|
|
* A violation means: a future contributor adds an env var and forgets to wire
|
|
* a CLI flag, silently making the CLI flag have no effect when the env var is
|
|
* set. That's the class of bug ADR-125 §"CLI flag wins" was written to prevent.
|
|
*
|
|
* Failure exits 1 with remediation instructions.
|
|
* CI wiring: .github/workflows/v3-ci.yml `env-var-precedence-audit` step in
|
|
* the `plugin-package-audit` job.
|
|
*/
|
|
|
|
import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { dirname, join, resolve, relative } from 'node:path';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const REPO_ROOT = resolve(__dirname, '..');
|
|
|
|
// ── Knob-controlled env vars that are intentionally env-only ─────────────────
|
|
// These are CI/test escape hatches or cross-process signals, not user config.
|
|
// They are explicitly exempt from the "CLI flag must win" requirement.
|
|
const KNOWN_ESCAPE_HATCHES = new Set([
|
|
// ── CI / test escape hatches ────────────────────────────────────────────────
|
|
'CLAUDE_FLOW_DISABLE_BRIDGE', // CI/test: force raw sql.js path — intentionally no CLI flag
|
|
'RUFLO_HOOK_SKIP_NPX', // CI: suppress cold-install latency in smoke tests
|
|
'RUFLO_SUBLINEAR_NATIVE', // Manual override for native vs WASM sublinear — CI/perf knob
|
|
'RUFLO_METAHARNESS_CACHE_BASE', // CI/test seam: relocates the ~/.ruflo pinned-cache root in metaharness smoke tests — intentionally env-only, plugin scripts have no CLI-flag surface
|
|
|
|
// ── Embedding substrate toggles (3.25.x — opt-in tier + fail-closed ops flag) ─
|
|
'RUFLO_REQUIRE_REAL_EMBEDDINGS', // Fail-closed "no stubs" strict mode — deploy/CI ops toggle, not a per-invocation CLI flag (ADR-176)
|
|
'RUFLO_EMBED_WASM_PKG', // Opt-in specifier for the optional WASM embedder tier — env-only deployment config, inert by default
|
|
'RUFLO_LATTICE_WASM_PKG', // Back-compat alias of RUFLO_EMBED_WASM_PKG
|
|
'RUFLO_EMBED_MODEL', // Model name for the optional WASM embedder — substrate config, env-only
|
|
|
|
// ── Feature flags (set by init into settings.json, not user-typed CLI) ──────
|
|
'CLAUDE_FLOW_V3_ENABLED',
|
|
'CLAUDE_FLOW_HOOKS_ENABLED',
|
|
'CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS',
|
|
|
|
// ── Process-internal / inter-process signalling ─────────────────────────────
|
|
'CLAUDE_FLOW_HEADLESS', // Set/read within same process invocation lifecycle
|
|
'CLAUDE_FLOW_FORCE_UPDATE', // Set by --force flag internally, then cleared — not external
|
|
'CLAUDE_FLOW_AUTO_UPDATE', // Auto-update cadence — env-only documented design
|
|
|
|
// ── Logging / diagnostics ───────────────────────────────────────────────────
|
|
'CLAUDE_FLOW_LOG_LEVEL',
|
|
'DEBUG',
|
|
'CLAUDE_FLOW_DEBUG',
|
|
|
|
// ── Provider credentials ─────────────────────────────────────────────────────
|
|
'ANTHROPIC_API_KEY',
|
|
'OPENAI_API_KEY',
|
|
'GOOGLE_API_KEY',
|
|
'CLAUDE_FLOW_ENCRYPTION_KEY', // Encryption key — credential, never a CLI flag
|
|
'RUFLO_GRAPH_INTELLIGENCE_WITNESS_KEY', // Ed25519 witness signing key — credential
|
|
'RUFLO_PROVIDER', // Provider selection in headless agent context
|
|
'PINATA_API_KEY',
|
|
'PINATA_API_SECRET',
|
|
'PINATA_API_JWT',
|
|
|
|
// ── Bootstrap / process-level bindings (can't chicken-egg with CLI parsing) ──
|
|
'CLAUDE_FLOW_CONFIG',
|
|
'CLAUDE_FLOW_MEMORY_BACKEND',
|
|
'CLAUDE_FLOW_MCP_PORT',
|
|
'CLAUDE_FLOW_MCP_HOST',
|
|
'CLAUDE_FLOW_MCP_TRANSPORT',
|
|
|
|
// ── CLI-flag-dominated env vars: documented precedence, large context window ─
|
|
// These have explicit precedence docs that appear >10 lines before the read.
|
|
// The audit's 10-line context window misses them; they are tracked here to
|
|
// prevent noisy false positives. Each must have the precedence documented
|
|
// in the source file (checked manually and confirmed below).
|
|
// CLAUDE_FLOW_MEMORY_PATH — memory-initializer.ts lines 19-28 doc
|
|
// "Precedence (highest → lowest): 1. CLAUDE_FLOW_MEMORY_PATH env var"
|
|
// See also memory.ts line 12: "#2105: --path > CLAUDE_FLOW_DB_PATH > CLAUDE_FLOW_MEMORY_PATH"
|
|
'CLAUDE_FLOW_MEMORY_PATH',
|
|
|
|
// ── Statusline cosmetics (no CLI on the statusline; init-time settings.json) ─
|
|
// Added 2026-06-02: statusline is invoked by Claude Code via hook config,
|
|
// not by an interactive `ruflo statusline …` command line. There is no CLI
|
|
// surface to attach a flag to; the env reads in statusline-generator.ts
|
|
// are the documented configuration channel.
|
|
'RUFLO_STATUSLINE_COST_SYMBOL',
|
|
'RUFLO_STATUSLINE_HIDE_COST',
|
|
|
|
// ── Tunables for routing/learning thresholds (operator knob, not user CLI) ───
|
|
// Added 2026-06-02: model-router uses this as a runtime escalation threshold
|
|
// tuned by ops, not selected per-command. No CLI flag is wired because no
|
|
// single CLI invocation owns the router's lifetime.
|
|
'CLAUDE_FLOW_MAX_UNCERTAINTY',
|
|
|
|
// ── MCP-tool-shaped tunables (param wins over env; env is documented fallback) ─
|
|
// Added 2026-06-02 (ADR-089 #2246): memory_search_unified resolves namespaces
|
|
// in this priority: `namespace` param → `namespaces[]` param → env var →
|
|
// dynamic enumeration. The `namespaces[]` MCP-tool parameter IS the
|
|
// CLI-flag-equivalent and takes precedence (memory-tools.ts:1079-1109). The
|
|
// env is the documented operator fallback.
|
|
'CLAUDE_FLOW_MEMORY_SEARCH_NAMESPACES',
|
|
|
|
// ── OS / runtime standard env ────────────────────────────────────────────────
|
|
'HOME',
|
|
'USERPROFILE',
|
|
'CLAUDE_PROJECT_DIR',
|
|
'PATH',
|
|
'npm_config_prefix',
|
|
'npm_execpath',
|
|
'NODE_ENV',
|
|
'PROMPT',
|
|
'TOOL_INPUT_command',
|
|
|
|
// ── Router (ADR-130/148/149) operator knobs ─────────────────────────────────
|
|
// These configure ruflo's neural-router/bandit/trajectory subsystems and
|
|
// are intentionally env-only:
|
|
// - Most are CI/benchmark knobs (KNN_K, LATENCY_BUDGET_MS, COST_CEILING),
|
|
// not user-typed inputs.
|
|
// - Several are feature flags (NEURAL=1, BANDIT_PER_MODEL=1, TRAJECTORY=1)
|
|
// that, like CLAUDE_FLOW_V3_ENABLED above, get baked into settings
|
|
// by `ruflo init` rather than passed on the command line.
|
|
// - SEED_CORPUS / CALIBRATOR_PATH / MODEL_PATH are file-path inputs to
|
|
// long-running daemons, not transient CLI flags.
|
|
// If a router knob graduates to user-facing surface, add a CLI flag override
|
|
// per ADR-125 and remove its entry here.
|
|
'CLAUDE_FLOW_ROUTER_AB',
|
|
'CLAUDE_FLOW_ROUTER_AB_SAMPLE_RATE',
|
|
'CLAUDE_FLOW_ROUTER_BANDIT_FULL_INFLUENCE',
|
|
'CLAUDE_FLOW_ROUTER_BANDIT_PER_MODEL',
|
|
'CLAUDE_FLOW_ROUTER_BANDIT_SHRINKAGE_LAMBDA',
|
|
'CLAUDE_FLOW_ROUTER_BANDIT_WARMUP_RANGE',
|
|
'CLAUDE_FLOW_ROUTER_CALIBRATE',
|
|
'CLAUDE_FLOW_ROUTER_CALIBRATOR_PATH',
|
|
'CLAUDE_FLOW_ROUTER_COST_CEILING_USD_PER_MTOK',
|
|
'CLAUDE_FLOW_ROUTER_EMBED_CACHE_SIZE',
|
|
'CLAUDE_FLOW_ROUTER_ENSEMBLE_UNCERTAINTY_THRESHOLD',
|
|
'CLAUDE_FLOW_ROUTER_FALLBACK_MAX_RETRIES',
|
|
'CLAUDE_FLOW_ROUTER_KNN_K',
|
|
'CLAUDE_FLOW_ROUTER_LATENCY_BUDGET_MS',
|
|
'CLAUDE_FLOW_ROUTER_MODEL_PATH',
|
|
'CLAUDE_FLOW_ROUTER_NEURAL',
|
|
'CLAUDE_FLOW_ROUTER_NEURAL_WEIGHT',
|
|
'CLAUDE_FLOW_ROUTER_OPENROUTER_ALTS',
|
|
'CLAUDE_FLOW_ROUTER_PARALLEL_LOG',
|
|
'CLAUDE_FLOW_ROUTER_PARALLEL_LOG_PATH',
|
|
'CLAUDE_FLOW_ROUTER_PROVIDER',
|
|
'CLAUDE_FLOW_ROUTER_QUALITY_BAR',
|
|
'CLAUDE_FLOW_ROUTER_SEED_CORPUS',
|
|
'CLAUDE_FLOW_ROUTER_TRAJECTORY',
|
|
'CLAUDE_FLOW_ROUTER_TRAJECTORY_MAXROTATIONS',
|
|
'CLAUDE_FLOW_ROUTER_TRAJECTORY_MAXSIZE',
|
|
'CLAUDE_FLOW_ROUTER_TRAJECTORY_PATH',
|
|
'CLAUDE_FLOW_ROUTER_TRAJECTORY_TASKLEN',
|
|
// Run-transcript capture (ADR-173 distill capture path) — opt-in, off by
|
|
// default background recorder (PII/retention surface, mirrors ROUTER_TRAJECTORY
|
|
// above). No user-facing command, so env-only by design; no CLI-flag precedence.
|
|
'CLAUDE_FLOW_RUN_TRANSCRIPTS',
|
|
'CLAUDE_FLOW_RUN_TRANSCRIPTS_PATH',
|
|
'CLAUDE_FLOW_RUN_TRANSCRIPTS_MAXROTATIONS',
|
|
'CLAUDE_FLOW_RUN_TRANSCRIPTS_MAXSIZE',
|
|
'CLAUDE_FLOW_SWARM_DIR', // Set by ruflo init / inter-process — not user-typed
|
|
// Nightly backup daemon-worker config (ADR-174 follow-up). The interactive
|
|
// `memory backup` command exposes --keep / --gcs / --dir flags with proper
|
|
// precedence; these env vars only configure the headless daemon worker path.
|
|
'RUFLO_BACKUP_KEEP',
|
|
'RUFLO_BACKUP_GCS',
|
|
// Self-running daemon opt-out (auto-start on CLI use). A pure on/off toggle
|
|
// for a background behavior — no CLI flag equivalent; escape-hatch by design.
|
|
'RUFLO_DAEMON_AUTOSTART',
|
|
// Self-optimizing harness loop opt-IN (ADR-176). Background daemon-worker
|
|
// toggle; $0-default even when on. Escape-hatch by design.
|
|
'RUFLO_HARNESS_LOOP',
|
|
]);
|
|
|
|
// ── Source directories to scan ────────────────────────────────────────────────
|
|
const SCAN_ROOTS = [
|
|
join(REPO_ROOT, 'v3/@claude-flow/cli/src'),
|
|
join(REPO_ROOT, 'plugins'),
|
|
];
|
|
|
|
// ── Skip patterns ─────────────────────────────────────────────────────────────
|
|
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '__tests__', 'tests']);
|
|
const SCAN_EXTS = new Set(['.ts', '.mjs', '.cjs', '.js']);
|
|
|
|
// ── Regex to find process.env.CLAUDE_FLOW_* reads ────────────────────────────
|
|
// Matches: process.env.CLAUDE_FLOW_FOO or process.env['CLAUDE_FLOW_FOO']
|
|
const ENV_READ_RE = /process\.env(?:\.([A-Z_]+)|\[['"]([A-Z_]+)['"]\])/g;
|
|
|
|
// ── Indicator that a CLI arg takes precedence ─────────────────────────────────
|
|
// Presence of any of these in the surrounding 10 lines counts as documented precedence.
|
|
const PRECEDENCE_INDICATORS = [
|
|
/cli.*flag/i,
|
|
/argv/i,
|
|
/precedence/i,
|
|
/--[a-z]/, // looks like a --flag reference in a comment
|
|
/options\.\w+/, // options.someFlag pattern (function param wins)
|
|
/args\.\w+/, // args.someFlag pattern
|
|
/param.*overrid/i,
|
|
/flag.*win/i,
|
|
/caller.*can.*pass/i,
|
|
];
|
|
|
|
// ── Walk source tree ─────────────────────────────────────────────────────────
|
|
|
|
function* walkSourceFiles(dir) {
|
|
let entries;
|
|
try { entries = readdirSync(dir); } catch { return; }
|
|
for (const entry of entries) {
|
|
if (SKIP_DIRS.has(entry)) continue;
|
|
const full = join(dir, entry);
|
|
let st;
|
|
try { st = statSync(full); } catch { continue; }
|
|
if (st.isDirectory()) {
|
|
yield* walkSourceFiles(full);
|
|
} else if (st.isFile()) {
|
|
const dot = entry.lastIndexOf('.');
|
|
if (dot >= 0 && SCAN_EXTS.has(entry.slice(dot))) yield full;
|
|
}
|
|
}
|
|
}
|
|
|
|
const violations = [];
|
|
const warnings = [];
|
|
const scanned = [];
|
|
|
|
for (const root of SCAN_ROOTS) {
|
|
if (!existsSync(root)) continue;
|
|
for (const file of walkSourceFiles(root)) {
|
|
let text;
|
|
try { text = readFileSync(file, 'utf8'); } catch { continue; }
|
|
|
|
const lines = text.split('\n');
|
|
scanned.push(relative(REPO_ROOT, file));
|
|
|
|
let match;
|
|
ENV_READ_RE.lastIndex = 0;
|
|
while ((match = ENV_READ_RE.exec(text)) !== null) {
|
|
const varName = match[1] || match[2];
|
|
if (!varName) continue;
|
|
if (!varName.startsWith('CLAUDE_FLOW_') && !varName.startsWith('RUFLO_')) continue;
|
|
if (KNOWN_ESCAPE_HATCHES.has(varName)) continue;
|
|
|
|
// Find the line number
|
|
const lineIdx = text.slice(0, match.index).split('\n').length - 1;
|
|
const contextStart = Math.max(0, lineIdx - 5);
|
|
const contextEnd = Math.min(lines.length - 1, lineIdx + 5);
|
|
const contextLines = lines.slice(contextStart, contextEnd + 1).join('\n');
|
|
|
|
// Check for precedence indicators in surrounding context
|
|
const hasPrecedenceDoc = PRECEDENCE_INDICATORS.some(re => re.test(contextLines));
|
|
|
|
const relFile = relative(REPO_ROOT, file);
|
|
const lineNo = lineIdx + 1;
|
|
|
|
if (!hasPrecedenceDoc) {
|
|
// Check if it's inside a function with an explicit parameter that could override.
|
|
// Heuristic: look for a function declaration within 20 lines above that has params.
|
|
const fnContextStart = Math.max(0, lineIdx - 20);
|
|
const fnContext = lines.slice(fnContextStart, lineIdx + 1).join('\n');
|
|
const hasExplicitParam = /function\s+\w+\s*\([^)]+\)|=>\s*\{|\([^)]+\)\s*:\s*\w+/.test(fnContext)
|
|
&& !/function\s+\w+\s*\(\s*\)/.test(fnContext.split('\n').slice(-5).join('\n'));
|
|
|
|
if (hasExplicitParam) {
|
|
// Warn rather than fail — function params could be the override path
|
|
warnings.push({ file: relFile, line: lineNo, varName });
|
|
} else {
|
|
violations.push({
|
|
file: relFile,
|
|
line: lineNo,
|
|
varName,
|
|
context: lines[lineIdx]?.trim() ?? '',
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ── Report ────────────────────────────────────────────────────────────────────
|
|
|
|
console.log(`env-var-precedence audit — scanned ${scanned.length} source file(s)`);
|
|
|
|
if (warnings.length > 0) {
|
|
console.log(`\nwarnings (function-param override path detected — verify manually):`);
|
|
for (const w of warnings) {
|
|
console.log(` ? ${w.file}:${w.line} ${w.varName}`);
|
|
}
|
|
}
|
|
|
|
if (violations.length === 0) {
|
|
console.log('\n ok: all CLAUDE_FLOW_* / RUFLO_* env var reads have documented CLI-flag precedence');
|
|
console.log(' ok: or are registered as known escape-hatch env vars (CI/test/credential use)');
|
|
process.exit(0);
|
|
}
|
|
|
|
console.error(`\n${violations.length} violation(s) — env var read without CLI-flag precedence documentation:`);
|
|
for (const v of violations) {
|
|
console.error(` x ${v.file}:${v.line} ${v.varName}`);
|
|
console.error(` context: ${v.context}`);
|
|
}
|
|
console.error(`
|
|
Remediation:
|
|
Option A — Wire a CLI flag that takes precedence:
|
|
Before: const val = process.env.CLAUDE_FLOW_FOO;
|
|
After: const val = options.foo ?? process.env.CLAUDE_FLOW_FOO ?? DEFAULT;
|
|
Then add "// CLI flag options.foo takes precedence over CLAUDE_FLOW_FOO env var"
|
|
|
|
Option B — Register as an escape hatch (CI/test/credential only):
|
|
Add the env var name to KNOWN_ESCAPE_HATCHES in scripts/audit-env-var-precedence.mjs
|
|
with a comment explaining why it is intentionally env-only.
|
|
|
|
Reference: ADR-125 §"CLI flag wins", ADR-130 §env-var-config-precedence.
|
|
`);
|
|
process.exit(1);
|