Files
aios/plugins/aios-tenant-boundary/dispatch-audit.js
T

46 lines
1.4 KiB
JavaScript

import fs from "node:fs";
import path from "node:path";
function redacted(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
const scrubbed = {};
for (const [key, item] of Object.entries(value)) {
if (key === "token" || key === "authorization" || key === "secret" || key === "credential") {
continue;
}
if (item && typeof item === "object") {
scrubbed[key] = redacted(item);
} else if (typeof item === "string" && ["x-aios-token", "x-api-token", "authorization"].includes(key.toLowerCase())) {
scrubbed[key] = "[redacted]";
} else {
scrubbed[key] = item;
}
}
return scrubbed;
}
function appendRecord(auditPath, record) {
const parent = path.dirname(auditPath);
fs.mkdirSync(parent, { recursive: true, mode: 0o750 });
const fd = fs.openSync(auditPath, "a", 0o640);
try {
fs.writeSync(fd, `${JSON.stringify(record)}\n`, null, "utf8");
fs.fsyncSync(fd);
} finally {
fs.closeSync(fd);
}
fs.chmodSync(auditPath, 0o640);
}
export function appendDispatchAudit(auditPath, record) {
if (!auditPath) return;
const absolute = path.isAbsolute(auditPath);
if (!absolute) throw new Error("invalid_audit_path");
const payload = {
schema_version: "aios.protected-dispatch-audit/v1",
recorded_at: Date.now(),
...(redacted(record) || {}),
};
appendRecord(auditPath, payload);
}