mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-28 11:41:16 +00:00
* feat: correlate native search outcomes in audit history Metadata-only audit ledger for agent runs and tool actions in the shared state DB: stable event identity, closed action/status/error vocabularies, one-way-hashed tool-call ids, never-inferred terminal outcomes for native web-search (explicit completed/failed only; otherwise unknown), bounded retention, audit.list gateway RPC and openclaw audit CLI. Squashed from the 82-commit audit stack for replay onto current main. * feat(audit): add audit.enabled config gate (default on) The metadata-only audit ledger records by default: an audit trail enabled only after an incident cannot explain the incident, and the rows are strictly less sensitive than the transcripts every install already stores. audit.enabled=false stops new writes at the gateway subscription seam; audit.list and openclaw audit keep serving existing records until they expire. Documented in the configuration reference, protocol page, and CLI reference. * fix: repair full-matrix CI findings after rebase - break the dynamic-tools/dynamic-tool-execution import cycle by extracting resolveCodexToolAbortTerminalReason into a leaf module - restore main's session-worktree protocol exports lost in the index.ts auto-merge - register the audit event writer worker as a knip entry point - docs table formatting; subagent wait-cancellation test scoped to its audit intent (outcome + timing) and advanced past main's new lifecycle-timeout retry grace
89 lines
2.8 KiB
TypeScript
89 lines
2.8 KiB
TypeScript
// Tool schema quarantine tests cover diagnostic logging for unreadable runtime
|
|
// tool entries without touching the broken tool object again.
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
onTrustedToolExecutionEvent,
|
|
type TrustedToolExecutionEvent,
|
|
} from "../infra/diagnostic-events.js";
|
|
import { resetPluginStateStoreForTests } from "../plugin-state/plugin-state-store.js";
|
|
import { withStateDirEnv } from "../test-helpers/state-dir-env.js";
|
|
import {
|
|
listPersistedRuntimeToolSchemaQuarantines,
|
|
recordPersistedRuntimeToolSchemaQuarantine,
|
|
} from "./tool-schema-quarantine-health.js";
|
|
import { logRuntimeToolSchemaQuarantine } from "./tool-schema-quarantine.js";
|
|
import type { AnyAgentTool } from "./tools/common.js";
|
|
|
|
afterEach(() => {
|
|
resetPluginStateStoreForTests();
|
|
});
|
|
|
|
describe("runtime tool schema quarantine logging", () => {
|
|
it("does not re-read unreadable tool entries while logging diagnostics", () => {
|
|
const events: TrustedToolExecutionEvent[] = [];
|
|
const stop = onTrustedToolExecutionEvent((event) => events.push(event));
|
|
const tools = new Proxy([] as AnyAgentTool[], {
|
|
get(target, property, receiver) {
|
|
if (property === "0") {
|
|
throw new Error("fuzzplugin tool entry getter exploded");
|
|
}
|
|
return Reflect.get(target, property, receiver);
|
|
},
|
|
});
|
|
|
|
try {
|
|
expect(() =>
|
|
logRuntimeToolSchemaQuarantine({
|
|
diagnostics: [
|
|
{
|
|
toolName: "tool[0]",
|
|
toolIndex: 0,
|
|
violations: ["tool[0] is unreadable"],
|
|
},
|
|
],
|
|
tools,
|
|
runId: "run-fuzzplugin-unreadable-tool",
|
|
agentId: "main",
|
|
}),
|
|
).not.toThrow();
|
|
} finally {
|
|
stop();
|
|
}
|
|
expect(events).toMatchObject([
|
|
{
|
|
type: "tool.execution.blocked",
|
|
runId: "run-fuzzplugin-unreadable-tool",
|
|
agentId: "main",
|
|
toolName: "tool[0]",
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("clears this process's persisted quarantine after the tool schema recovers", async () => {
|
|
await withStateDirEnv("openclaw-tool-schema-quarantine-recovery-", async () => {
|
|
recordPersistedRuntimeToolSchemaQuarantine({
|
|
toolName: "recovered_tool",
|
|
reason: 'recovered_tool.parameters.type must be "object"',
|
|
failedAt: new Date(123),
|
|
});
|
|
|
|
logRuntimeToolSchemaQuarantine({
|
|
diagnostics: [],
|
|
tools: [
|
|
{
|
|
name: "recovered_tool",
|
|
label: "Recovered tool",
|
|
description: "Recovered tool",
|
|
parameters: { type: "object", properties: {} },
|
|
execute: async () => ({ content: [{ type: "text", text: "ok" }], details: {} }),
|
|
},
|
|
],
|
|
runId: "run-recovered-tool",
|
|
agentId: "main",
|
|
});
|
|
|
|
expect(listPersistedRuntimeToolSchemaQuarantines()).toEqual([]);
|
|
});
|
|
});
|
|
});
|