Files
openclaw/src/agents/tool-schema-quarantine.test.ts
Peter Steinberger f53346944d feat: correlate native search outcomes in audit history (#98704)
* 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
2026-07-06 12:30:12 +01:00

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([]);
});
});
});