Files
openclaw/src/plugins/runtime/runtime-embedded-agent.runtime.test.ts
T
Josh Avant 73a9eed95b refactor(audit): add canonical admitted-run context (#120534)
* feat(audit): carry canonical admitted execution context

* fix(agents): preserve admitted context across retries

* fix(worker): fence legacy launch dialect

* test(gateway): track approval temp dirs

* fix(plugin-sdk): preserve harness attempt compatibility

* fix: close delegated run authority at owner boundaries

* fix: internalize delegated authority validators

* refactor: split delegated authority proof surfaces

* refactor: centralize command admission identity

* test: claim runtime tool authority

* fix(gateway): keep lifecycle cleanup within static budgets

* fix(agents): revalidate harness policy authority

* fix(agents): fence awaited approval capability results

* test(copilot): supply required harness capability fixtures

* fix(agent): preserve scoped embedded run admission

* fix(agent): preserve keyless and worker authority

* test(agent): bind incomplete-turn authority

* docs: preserve execution authority invariants

* chore(plugin-sdk): regenerate API baseline

* fix(gateway): notify pending claim closure

* fix(gateway): revalidate delegated tool authority

* fix(plugin-sdk): keep source guard internal

* fix: close delegated authority races

* fix: revalidate delegated side effects

* fix: close harness authority projection gaps

* fix: align authority integration types

* fix: isolate settled harness finalization

* fix: fence recovery identity finalization

* fix: preserve committed session worktrees

* fix: preserve worker placement agent identity

* fix: fence active harness tool work

* fix(plugins): restore embedded run admission owner

* chore(plugin-sdk): compose integrated surface budgets

* fix(copilot): keep finalization attempt type internal

* fix(plugins): complete admission owner type imports

* test(harness): use settled finalization attempt shape

* fix(security): retain exact side-run and approval authority

* fix(security): preserve protected authority through terminal sweep

* fix(agents): follow moved recovery store owner

* fix(ci): align integrated authority owners with gates

* fix(plugins): distinguish embedded agent adapter export

* chore(plugin-sdk): regenerate API baseline after rolling integration

* refactor(gateway): keep session authority within owner budgets

* fix(gateway): keep session helpers private

* docs(plugin-sdk): name the V2 parameter subpath

* chore(integration): reconcile worker and SDK surfaces

* docs(plugin-sdk): require the V2 host API floor

* chore(plugin-sdk): regenerate after proxy-auth integration
2026-08-10 23:15:20 -05:00

168 lines
6.0 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { withPluginRuntimePluginIdScope } from "./gateway-request-scope.js";
import type { PluginRuntime } from "./types.js";
const mocks = vi.hoisted(() => ({
close: vi.fn(),
createOperationalRunInstanceRef: vi.fn((runId: string) => ({
instanceId: `instance:${runId}`,
runId,
})),
getRuntimeConfig: vi.fn(() => ({}) as OpenClawConfig),
prepareAgentRunAdmission: vi.fn(),
runEmbeddedAgentCore: vi.fn(),
}));
vi.mock("../../agents/admitted-run-context.js", () => ({
createOperationalRunInstanceRef: mocks.createOperationalRunInstanceRef,
prepareAgentRunAdmission: mocks.prepareAgentRunAdmission,
}));
vi.mock("../../agents/embedded-agent.js", () => ({
runEmbeddedAgent: mocks.runEmbeddedAgentCore,
}));
vi.mock("../../config/config.js", () => ({ getRuntimeConfig: mocks.getRuntimeConfig }));
import { runPluginEmbeddedAgent } from "./runtime-embedded-agent.runtime.js";
function deferred<T>() {
let resolve!: (value: T) => void;
const promise = new Promise<T>((done) => {
resolve = done;
});
return { promise, resolve };
}
const config = {} as OpenClawConfig;
const params = {
config,
prompt: "check",
runId: "run-plugin",
sessionId: "session-plugin",
sessionTarget: {
agentId: "researcher",
sessionId: "session-plugin",
sessionKey: "agent:researcher:plugin",
storePath: "/tmp/sessions",
},
timeoutMs: 1,
workspaceDir: "/tmp/workspace",
} as Parameters<PluginRuntime["agent"]["runEmbeddedAgent"]>[0];
describe("plugin embedded-agent runtime admission", () => {
beforeEach(() => {
vi.clearAllMocks();
mocks.prepareAgentRunAdmission.mockReturnValue({
operationalRunInstance: { instanceId: "instance:run-plugin", runId: "run-plugin" },
admit: vi.fn(),
close: mocks.close,
});
mocks.runEmbeddedAgentCore.mockResolvedValue({ payloads: [] });
});
it("binds plugin facts and closes the exact prepared admission after success", async () => {
await expect(
withPluginRuntimePluginIdScope("memory-plugin", () => runPluginEmbeddedAgent(params)),
).resolves.toEqual({ payloads: [] });
expect(mocks.prepareAgentRunAdmission).toHaveBeenCalledWith({
cfg: config,
operationalRunInstance: { instanceId: "instance:run-plugin", runId: "run-plugin" },
facts: {
runId: "run-plugin",
agentId: "researcher",
ingress: {
kind: "plugin",
boundary: "plugin-runtime",
rawSourceRef: "memory-plugin",
state: "present",
},
},
});
expect(mocks.runEmbeddedAgentCore).toHaveBeenCalledWith(
expect.objectContaining({
...params,
preparedRunAdmission: expect.objectContaining({ close: mocks.close }),
}),
);
expect(mocks.close).toHaveBeenCalledOnce();
});
it("closes the prepared admission when core execution throws", async () => {
mocks.runEmbeddedAgentCore.mockRejectedValueOnce(new Error("core failed"));
await expect(
withPluginRuntimePluginIdScope("memory-plugin", () => runPluginEmbeddedAgent(params)),
).rejects.toThrow("core failed");
expect(mocks.close).toHaveBeenCalledOnce();
});
it("revokes admission immediately when a pending plugin run aborts", async () => {
const core = deferred<{ payloads: never[] }>();
mocks.runEmbeddedAgentCore.mockReturnValueOnce(core.promise);
const controller = new AbortController();
const run = withPluginRuntimePluginIdScope("memory-plugin", () =>
runPluginEmbeddedAgent({ ...params, abortSignal: controller.signal }),
);
await vi.waitFor(() => expect(mocks.runEmbeddedAgentCore).toHaveBeenCalledOnce());
controller.abort(new Error("cancelled"));
expect(mocks.close).toHaveBeenCalledOnce();
core.resolve({ payloads: [] });
await expect(run).resolves.toEqual({ payloads: [] });
expect(mocks.close).toHaveBeenCalledOnce();
});
it("closes admission when abort races with listener registration", async () => {
const controller = new AbortController();
mocks.prepareAgentRunAdmission.mockImplementationOnce(() => {
controller.abort(new Error("raced cancellation"));
return {
operationalRunInstance: { instanceId: "instance:run-plugin", runId: "run-plugin" },
admit: vi.fn(),
close: mocks.close,
};
});
await expect(
withPluginRuntimePluginIdScope("memory-plugin", () =>
runPluginEmbeddedAgent({ ...params, abortSignal: controller.signal }),
),
).rejects.toThrow("raced cancellation");
expect(mocks.close).toHaveBeenCalledOnce();
expect(mocks.runEmbeddedAgentCore).not.toHaveBeenCalled();
});
it("does not create admission for an already-aborted plugin run", async () => {
const controller = new AbortController();
controller.abort(new Error("already cancelled"));
await expect(
withPluginRuntimePluginIdScope("memory-plugin", () =>
runPluginEmbeddedAgent({ ...params, abortSignal: controller.signal }),
),
).rejects.toThrow("already cancelled");
expect(mocks.prepareAgentRunAdmission).not.toHaveBeenCalled();
expect(mocks.runEmbeddedAgentCore).not.toHaveBeenCalled();
});
it("fails closed outside a plugin scope", async () => {
await expect(runPluginEmbeddedAgent(params)).rejects.toThrow("active plugin runtime scope");
expect(mocks.prepareAgentRunAdmission).not.toHaveBeenCalled();
expect(mocks.runEmbeddedAgentCore).not.toHaveBeenCalled();
});
it.each(["admittedRunContext", "preparedRunAdmission"] as const)(
"rejects a plugin-supplied %s",
async (field) => {
await expect(
withPluginRuntimePluginIdScope("memory-plugin", () =>
runPluginEmbeddedAgent({ ...params, [field]: {} } as never),
),
).rejects.toThrow("cannot supply host run authority");
expect(mocks.prepareAgentRunAdmission).not.toHaveBeenCalled();
expect(mocks.runEmbeddedAgentCore).not.toHaveBeenCalled();
},
);
});