← Files Aivana Database EngineerARCHIVED FILE

runtime/auditLogger.js

8.25 KB · Oct 2, 2026 · 00:34 UTC

↓ Download file

const path = require("node:path");
const crypto = require("node:crypto");
const fs = require("node:fs");
const { getPolicy } = require("./config");
const { withState, importOnce, readLegacyLines } = require("./stateStore");

function sanitizeObject(value) {
  if (Array.isArray(value)) return value.map(sanitizeObject);
  if (value && typeof value === "object") {
    return Object.fromEntries(Object.entries(value).map(([key, child]) => [key,
      /^(data|raw|rawPayload|body|soql|parameters)$/i.test(key) ? "[raw_input_omitted]" :
      /password|secret|token|key|credential|dsn|authorization|connectionstring/i.test(key)
        ? "***redacted***" : sanitizeObject(child)]));
  }
  if (typeof value === "string") {
    return value.replace(/(Bearer\s+)[^\s",]+/gi, "$1***redacted***")
      .replace(/(https?:\/\/|postgres(?:ql)?:\/\/|mysql:\/\/|mariadb:\/\/)[^\s/@]+:[^\s/@]+@/gi, "$1***redacted***@")
      .replace(/((?:password|pwd|access_token)\s*[=:]\s*)[^;\s&]+/gi, "$1***redacted***");
  }
  return value;
}

function importAudit(db, file) {
  importOnce(db, "legacy_audit", () => {
    const records = readLegacyLines(file);
    const replay = readLegacyLines(path.join(path.dirname(file), "replay.jsonl"));
    if (!records.length && !replay.length) return;
    const replayById = new Map(replay.map((row) => [row.id, row]));
    if (records.length !== replay.length || replayById.size !== replay.length ||
        records.some((row) => !replayById.has(row.id))) {
      throw new Error("Legacy audit/replay mismatch; preserve files and reconcile before migration");
    }
    const insert = db.prepare("INSERT INTO audit(record,replay) VALUES(?,?)");
    for (const record of records) insert.run(JSON.stringify(sanitizeObject(record)), JSON.stringify(sanitizeObject(replayById.get(record.id))));
  });
}

function appendAuditEvent(logFile, event) {
  return withState(logFile, (db) => {
    importAudit(db, logFile);
    const previous = db.prepare("SELECT replay FROM audit ORDER BY sequence DESC LIMIT 1").get();
    const previousReplayId = previous ? JSON.parse(previous.replay).replayId : null;
    const record = sanitizeObject({ ...event, ts: new Date().toISOString() });
    const replay = {
      ...record,
      payload: getPolicy().replay?.includePayload ? record.payload : "[redacted]",
      replayId: "replay-" + crypto.randomUUID(),
      previousReplayId,
    };
    db.prepare("INSERT INTO audit(record,replay) VALUES(?,?)").run(JSON.stringify(record), JSON.stringify(replay));
    return { record, replay };
  });
}

function buildEvent({ tool, actor = "codex-agent", environment = "lab", riskLevel = "LOW",
  decision = "ALLOW", payload = {}, requiresApproval = false, status, blockedReason }) {
  return { actor, environment, tool, riskLevel, decision, status, requiresApproval,
    blockedReason, payload, id: "audit-" + crypto.randomUUID() };
}

function readReplayLog(logFile, replayId) {
  return withState(logFile, (db) => {
    importAudit(db, logFile);
    return db.prepare("SELECT replay FROM audit ORDER BY sequence").all()
      .map((row) => JSON.parse(row.replay)).filter((row) => !replayId || row.replayId === replayId);
  });
}

function verifyAudit(logFile) {
  return withState(logFile, (db) => {
    importAudit(db, logFile);
    const rows = db.prepare("SELECT record,replay FROM audit ORDER BY sequence").all();
    let previous = null;
    const seen = new Set();
    const issues = [];
    for (const [index, row] of rows.entries()) {
      const record = JSON.parse(row.record);
      const replay = JSON.parse(row.replay);
      if (replay.previousReplayId !== previous || seen.has(replay.replayId) || record.id !== replay.id) issues.push(index);
      seen.add(replay.replayId);
      previous = replay.replayId;
    }
    const integrity = db.prepare("PRAGMA integrity_check").get().integrity_check;
    const recovery = db.prepare("SELECT value FROM metadata WHERE key='legacy_recovery_epoch'").get();
    return { status: issues.length || integrity !== "ok" ? "failed" : recovery ? "current_epoch_verified_legacy_unverified" : "verified",
      records: rows.length, issues, storageIntegrity: integrity, source: "local_audit",
      historicalIntegrity: recovery ? "unverified_preserved_separately" : "not_separately_recovered",
      recovery: recovery ? JSON.parse(recovery.value) : null,
      tamperProof: false, storage: "sqlite_transactional" };
  });
}

function auditStateRecovery(logFile, args = {}) {
  if (!["inspect", "start_new_epoch"].includes(args.action)) throw new Error("Recovery action must be inspect or start_new_epoch");
  const files = [logFile, path.join(path.dirname(logFile), "replay.jsonl")];
  const capture = () => files.map((file) => {
    if (fs.existsSync(file) && fs.statSync(file).size > 64 * 1024 * 1024) throw new Error("Legacy file exceeds recovery size bound");
    const raw = fs.existsSync(file) ? fs.readFileSync(file) : Buffer.alloc(0);
    return { file, raw, hash: crypto.createHash("sha256").update(raw).digest("hex") };
  });
  const captured = capture();
  const parsed = captured.map(({ raw }) => raw.toString("utf8").split(/\r?\n/).filter((line) => line.trim()).map((line) => {
    try { const value = JSON.parse(line); return value && typeof value === "object" && !Array.isArray(value) ? value : null; } catch { return null; }
  }));
  const [audit, replay] = parsed;
  const replayIds = new Set(replay.filter(Boolean).map((row) => row.id));
  let previous = null, chainBreaks = 0;
  const seen = new Set();
  for (const row of replay) {
    if (!row || !row.replayId || row.previousReplayId !== previous || seen.has(row.replayId)) chainBreaks++;
    if (row) { previous = row.replayId; seen.add(row.replayId); }
  }
  const fingerprint = crypto.createHash("sha256").update(JSON.stringify(captured.map(({ file, hash }) => ({ file, hash })))).digest("hex");
  const report = { fingerprint, auditRecords: audit.length, replayRecords: replay.length,
    malformedRecords: parsed.flat().filter((row) => !row).length,
    unmatchedAuditRecords: audit.filter((row) => row && !replayIds.has(row.id)).length,
    chainBreaks, files: captured.map(({ file, hash }) => ({ file, sha256: hash })),
    historicalIntegrity: "not_verified", executionAuthorized: false };
  if (args.action === "inspect") return { ...report, action: "inspect", changed: false };
  if (args.expectedFingerprint !== fingerprint || args.acknowledgeHistoricalGaps !== true || typeof args.reason !== "string" || !args.reason.trim() || args.reason.length > 1000) {
    throw new Error("Exact fingerprint, explicit historical-gap acknowledgment and bounded reason required");
  }
  return withState(logFile, (db) => {
    if (db.prepare("SELECT COUNT(*) AS count FROM audit").get().count || db.prepare("SELECT value FROM metadata WHERE key='legacy_audit'").get()) throw new Error("Existing audit epoch cannot be replaced");
    if (capture().some((item, index) => item.hash !== captured[index].hash)) throw new Error("Legacy evidence changed during recovery");
    const epoch = { ...report, epochId: crypto.randomUUID(), startedAt: new Date().toISOString(), reason: sanitizeObject(args.reason) };
    // Preserve exact original bytes separately; they are never rewritten into a fabricated replay chain.
    db.exec("CREATE TABLE IF NOT EXISTS legacy_recovery_sources (path TEXT PRIMARY KEY, sha256 TEXT NOT NULL, content BLOB NOT NULL)");
    const insert = db.prepare("INSERT INTO legacy_recovery_sources(path,sha256,content) VALUES(?,?,?)");
    for (const item of captured) insert.run(item.file, item.hash, item.raw);
    db.prepare("INSERT INTO metadata(key,value) VALUES('legacy_recovery_epoch',?)").run(JSON.stringify(epoch));
    db.prepare("INSERT INTO metadata(key,value) VALUES('legacy_audit',?)").run(epoch.startedAt);
    const record = { ...buildEvent({ tool: "audit_state_recovery", actor: "local-operator", payload: epoch }), ts: epoch.startedAt };
    const replayRecord = { ...record, replayId: "replay-" + crypto.randomUUID(), previousReplayId: null };
    db.prepare("INSERT INTO audit(record,replay) VALUES(?,?)").run(JSON.stringify(record), JSON.stringify(replayRecord));
    return { ...epoch, action: "start_new_epoch", changed: true, originalFilesModified: false, historicalIntegrity: "unverified_preserved_separately" };
  });
}

module.exports = { appendAuditEvent, buildEvent, readReplayLog, verifyAudit, sanitizeObject, auditStateRecovery };

SHA-256: 5957312a7555e6778502d0da1f17236cf315678a976b303dca47c5d5c6a0b125