fix(plugins): preserve archive publication authority

This commit is contained in:
jesse-merhi
2026-08-13 03:59:23 +10:00
parent b6def3c6c0
commit 5ca8f5ccd7
4 changed files with 102 additions and 8 deletions
+15
View File
@@ -279,6 +279,7 @@ type ArchiveInstallCall = {
dangerouslyForceUnsafeInstall?: boolean;
expectedPluginId?: string;
onInstallPolicyWarning?: unknown;
publicationAuthority?: unknown;
installPolicyRequest?: {
kind?: string;
requestedSpecifier?: string;
@@ -1784,6 +1785,20 @@ describe("installPluginFromClawHub", () => {
expect(archiveInstallCall().onInstallPolicyWarning).toBe(onInstallPolicyWarning);
});
it("passes install publication authority through to archive installs", async () => {
const publicationAuthority = {
assertCurrent: vi.fn(),
commit: vi.fn(),
};
await installPluginFromClawHub({
spec: "clawhub:demo",
publicationAuthority,
});
expect(archiveInstallCall().publicationAuthority).toBe(publicationAuthority);
});
it("preserves the reviewed policy spec when retrying a pinned ClawHub version", async () => {
await installPluginFromClawHub({
spec: "clawhub:demo@2026.3.22",
-1
View File
@@ -586,7 +586,6 @@ export async function installPluginFromManagedNpmRoot(
}
}
const result = await installPluginFromInstalledPackageDir({
publicationAuthority: params.publicationAuthority,
dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
onInstallPolicyWarning: params.onInstallPolicyWarning,
config: params.config,
+1 -7
View File
@@ -386,16 +386,10 @@ export async function installPluginFromArchive(
await installPluginFromSourceDir({
sourceDir,
...pickPackageInstallCommonParams({
dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
onInstallPolicyWarning: params.onInstallPolicyWarning,
extensionsDir: params.extensionsDir,
...params,
timeoutMs,
logger,
mode,
dryRun: params.dryRun,
config: params.config,
expectedPluginId: params.expectedPluginId,
trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
requirePluginManifest: true,
installPolicyRequest,
onEffectiveMode: (resolvedMode) => {
+86
View File
@@ -1040,6 +1040,92 @@ describe("installPluginFromArchive", () => {
expect(updatedVersion).toBe("0.0.2");
});
it("does not publish a new archive install after its approval expires", async () => {
const stateDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(stateDir, "extensions");
const archivePath = await ensureDynamicArchiveTemplate({
outName: "archive-publication-authority.tgz",
packageJson: {
name: "archive-publication-authority",
version: "1.0.0",
openclaw: { extensions: ["./dist/index.js"] },
},
withDistIndex: true,
});
const commit = vi.fn(() => {
throw new Error("approval expired");
});
const result = await installPluginFromArchive({
archivePath,
extensionsDir,
publicationAuthority: { assertCurrent: vi.fn(), commit },
});
expect(result).toEqual({
ok: false,
error: "failed to copy plugin: Error: approval expired",
});
expect(commit).toHaveBeenCalledOnce();
expect(
fs.existsSync(resolvePluginInstallDir("archive-publication-authority", extensionsDir)),
).toBe(false);
});
it("restores an archive update when its approval expires during publication", async () => {
const stateDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(stateDir, "extensions");
const archiveV1 = await ensureDynamicArchiveTemplate({
outName: "archive-publication-update-1.tgz",
packageJson: {
name: "archive-publication-update",
version: "1.0.0",
openclaw: { extensions: ["./dist/index.js"] },
},
withDistIndex: true,
});
const archiveV2 = await ensureDynamicArchiveTemplate({
outName: "archive-publication-update-2.tgz",
packageJson: {
name: "archive-publication-update",
version: "2.0.0",
openclaw: { extensions: ["./dist/index.js"] },
},
withDistIndex: true,
});
const first = await installPluginFromArchive({ archivePath: archiveV1, extensionsDir });
expect(first.ok).toBe(true);
if (!first.ok) {
return;
}
let approvalCurrent = true;
const assertCurrent = vi.fn(() => {
approvalCurrent = false;
});
const commit = vi.fn(() => {
if (!approvalCurrent) {
throw new Error("approval expired");
}
});
const update = await installPluginFromArchive({
archivePath: archiveV2,
extensionsDir,
mode: "update",
publicationAuthority: { assertCurrent, commit },
});
expect(update).toEqual({
ok: false,
error: "failed to copy plugin: Error: approval expired",
});
expect(assertCurrent).toHaveBeenCalledOnce();
expect(commit).toHaveBeenCalledOnce();
expect(
JSON.parse(fs.readFileSync(path.join(first.targetDir, "package.json"), "utf8")),
).toMatchObject({ version: "1.0.0" });
});
it("emits effective install mode when requested archive update creates a new target", async () => {
const stateDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(stateDir, "extensions");