mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-01 02:01:45 +00:00
fix(config): add forensic config write audit and watch attribution
This commit is contained in:
@@ -311,4 +311,91 @@ describe("config io write", () => {
|
||||
expect(overwriteLogs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
it("appends config write audit JSONL entries with forensic metadata", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const configPath = path.join(home, ".openclaw", "openclaw.json");
|
||||
const auditPath = path.join(home, ".openclaw", "logs", "config-audit.jsonl");
|
||||
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
||||
await fs.writeFile(
|
||||
configPath,
|
||||
JSON.stringify({ gateway: { port: 18789 } }, null, 2),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const io = createConfigIO({
|
||||
env: {} as NodeJS.ProcessEnv,
|
||||
homedir: () => home,
|
||||
logger: {
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
const snapshot = await io.readConfigFileSnapshot();
|
||||
expect(snapshot.valid).toBe(true);
|
||||
|
||||
const next = structuredClone(snapshot.config);
|
||||
next.gateway = {
|
||||
...next.gateway,
|
||||
mode: "local",
|
||||
};
|
||||
|
||||
await io.writeConfigFile(next);
|
||||
|
||||
const lines = (await fs.readFile(auditPath, "utf-8")).trim().split("\n").filter(Boolean);
|
||||
expect(lines.length).toBeGreaterThan(0);
|
||||
const last = JSON.parse(lines.at(-1) ?? "{}") as Record<string, unknown>;
|
||||
expect(last.source).toBe("config-io");
|
||||
expect(last.event).toBe("config.write");
|
||||
expect(last.configPath).toBe(configPath);
|
||||
expect(last.existsBefore).toBe(true);
|
||||
expect(last.hasMetaAfter).toBe(true);
|
||||
expect(last.previousHash).toBeTypeOf("string");
|
||||
expect(last.nextHash).toBeTypeOf("string");
|
||||
expect(last.result === "rename" || last.result === "copy-fallback").toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("records gateway watch session markers in config audit entries", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const configPath = path.join(home, ".openclaw", "openclaw.json");
|
||||
const auditPath = path.join(home, ".openclaw", "logs", "config-audit.jsonl");
|
||||
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
||||
await fs.writeFile(
|
||||
configPath,
|
||||
JSON.stringify({ gateway: { mode: "local" } }, null, 2),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const io = createConfigIO({
|
||||
env: {
|
||||
OPENCLAW_WATCH_MODE: "1",
|
||||
OPENCLAW_WATCH_SESSION: "watch-session-1",
|
||||
OPENCLAW_WATCH_COMMAND: "gateway --force",
|
||||
} as NodeJS.ProcessEnv,
|
||||
homedir: () => home,
|
||||
logger: {
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
const snapshot = await io.readConfigFileSnapshot();
|
||||
expect(snapshot.valid).toBe(true);
|
||||
const next = structuredClone(snapshot.config);
|
||||
next.gateway = {
|
||||
...next.gateway,
|
||||
bind: "loopback",
|
||||
};
|
||||
|
||||
await io.writeConfigFile(next);
|
||||
|
||||
const lines = (await fs.readFile(auditPath, "utf-8")).trim().split("\n").filter(Boolean);
|
||||
const last = JSON.parse(lines.at(-1) ?? "{}") as Record<string, unknown>;
|
||||
expect(last.watchMode).toBe(true);
|
||||
expect(last.watchSession).toBe("watch-session-1");
|
||||
expect(last.watchCommand).toBe("gateway --force");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user