Files
fusion/scripts/check-no-nohup.mjs
gsxdsm c25f8b796d Harden PostgreSQL migration foundation (#2088)
## Summary

- make SQLite-to-PostgreSQL cutover retryable, fail-closed, versioned,
and transactionally serialized
- isolate migration sessions from runtime traffic and apply schema
upgrades through `0002`
- enforce tenant ownership across automations, analytics, activity,
usage, agent runs, evals, and todos
- replace expired SQLite-only coverage with PostgreSQL parity and
concurrency coverage

This is PR 1 of 2. The stacked follow-up restores PostgreSQL parity for
CLI, engine, dashboard, and bundled integrations.

## Verification

- `pnpm check:changesets --strict`
- `pnpm --filter @fusion/core typecheck`
- migration schema, connection, and SQLite cutover suite: 57 tests
passed
- `pnpm test:gate`: 463 tests passed

## Post-Deploy Monitoring & Validation

- take a restorable PostgreSQL backup before deploy
- confirm `fusion_schema_migrations` contains `0002`
- confirm each expected project has a complete
`fusion_sqlite_migrations` row
- verify no null or empty tenant ownership in automations, activity
logs, agent runs, and usage events
- monitor for ownership inference failures, cutover verification
failures, and migration session errors
- restore the backup for data rollback; do not downgrade the
tenant-isolation schema in place

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* PostgreSQL-backed analytics and live dashboard metrics are now
project-scoped (activity, tools, monitor, signals, and live snapshots).
* Evaluation runs and scheduled eval batches received lifecycle
improvements (ordering, updates, and execution flow).
* Todo list changes now emit events; WhatsApp persistence and
project-scoped roadmap data are supported.

* **Bug Fixes**
* SQLite-to-PostgreSQL cutovers now fail safely with stronger
verification, serialized cutover handling, and safer project ownership.
* PostgreSQL backend writes and reads are now strictly project-isolated
and fail closed when project context is missing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 08:16:42 -07:00

81 lines
2.4 KiB
JavaScript

#!/usr/bin/env node
import { readFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
const token = ["no", "hup"].join("");
const tokenPattern = new RegExp(`\\b${token}\\b`);
const allowlistMarker = "process-supervisor-allowlist";
function listTrackedTargets() {
const result = spawnSync("git", ["ls-files", "--", "packages", "scripts"], {
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
});
if (result.status !== 0) {
throw new Error(result.stderr?.trim() || "git ls-files failed");
}
return result.stdout
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
}
export function scanFileContent(content, filePath) {
const matches = [];
const lines = content.split(/\r?\n/);
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index];
if (!tokenPattern.test(line) || line.includes(allowlistMarker)) {
continue;
}
matches.push({ filePath, lineNumber: index + 1, line });
}
return matches;
}
export function scanTrackedFiles(files = listTrackedTargets(), readFile = readFileSync) {
const matches = [];
for (const filePath of files) {
let content;
try {
content = readFile(filePath, "utf8");
} catch (error) {
/*
FNXC:MergeGateSourceScan 2026-07-14-01:41:
Git continues listing an unstaged deletion as tracked, so source guards may skip ENOENT while the deletion awaits commit. Permission, I/O, and other read failures must still fail the gate rather than silently omitting tracked source from enforcement.
*/
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
continue;
}
throw error;
}
matches.push(...scanFileContent(content, filePath));
}
return matches;
}
export function formatFailureMessage(matches) {
const lines = matches.map(({ filePath, lineNumber, line }) => `${filePath}:${lineNumber}: ${line.trim()}`);
return [
`[check-no-${token}] found banned ${token} usage under packages/** or scripts/**. Use superviseSpawn(...) instead.`,
...lines,
].join("\n");
}
export function main() {
const matches = scanTrackedFiles();
if (matches.length === 0) {
return 0;
}
console.error(formatFailureMessage(matches));
return 1;
}
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
process.exitCode = main();
}