fix(gateway): revoke install approvals on restart

This commit is contained in:
jesse-merhi
2026-08-12 22:16:41 +10:00
parent 627da2cc15
commit 29d9c64583
2 changed files with 47 additions and 1 deletions
@@ -7,6 +7,7 @@ import type {
InstallPolicyWarningOccurrence,
} from "../../plugins/install-security-scan.types.js";
import { parseInstallPolicyResponse } from "../../security/install-policy-response.js";
import { drainGlobalSingletonLifecycleState } from "../../shared/global-singleton.js";
type InstallPolicyWarningScanIdentity = InstallPolicyWarningOccurrence["scan"];
type ManagementServiceModule = typeof import("../../plugins/management-service.js");
@@ -559,6 +560,47 @@ describe("plugin management Gateway handlers", () => {
expect(managementMocks.install).toHaveBeenCalledOnce();
});
it("revokes install-policy acknowledgements when the Gateway restarts", async () => {
managementMocks.install.mockRejectedValueOnce(
new ManagedPluginLifecycleError("Install requires approval", {
installPolicyResolvedRequest: {
source: "official",
spec: "@openclaw/diffs@1.0.0",
pluginId: "diffs",
mode: "install",
},
installPolicyWarning: warningOccurrence({
targetName: "diffs",
targetType: "plugin",
requestMode: "install",
reason: "Review required",
}),
}),
);
const warning = await callHandler("plugins.install", {
source: "official",
pluginId: "diffs",
});
const acknowledgementToken = expectDefined(
(warning.error as { details?: { acknowledgementToken?: unknown } }).details
?.acknowledgementToken,
"expected install-policy acknowledgement token",
);
await drainGlobalSingletonLifecycleState("restart");
const retry = await callHandler("plugins.install", {
source: "official",
pluginId: "diffs",
installPolicyWarningAcknowledgement: acknowledgementToken,
});
expect(retry.error).toMatchObject({
code: "INVALID_REQUEST",
message: expect.stringContaining("expired or does not match this plugin"),
});
expect(managementMocks.install).toHaveBeenCalledOnce();
});
it("carries earlier approvals into a token for a later scan-stage warning", async () => {
const warning: InstallPolicyWarningDetails = {
targetName: "demo-plugin",
+5 -1
View File
@@ -27,6 +27,7 @@ import {
type ManagedPluginInstallRequest,
type ManagedPluginSourceInstallRequest,
} from "../../plugins/management-service.js";
import { resolveGlobalMap } from "../../shared/global-singleton.js";
import { buildGatewayReloadPlan } from "../config-reload-plan.js";
import { resolveGatewayReloadSettings } from "../config-reload-settings.js";
import { readInstallPolicyWarningErrorDetails } from "../install-policy-warning-error-details.js";
@@ -43,7 +44,10 @@ type InstallPolicyAcknowledgement = {
warnings: InstallPolicyWarningOccurrence[];
};
const installPolicyAcknowledgements = new Map<string, InstallPolicyAcknowledgement>();
const installPolicyAcknowledgements = resolveGlobalMap<string, InstallPolicyAcknowledgement>(
Symbol.for("openclaw.installPolicyAcknowledgements"),
"close-and-restart",
);
function installPolicyRequestKey(request: PluginsInstallParams): string {
return request.source === "clawhub"