mirror of
https://github.com/openclaw/clawhub.git
synced 2026-08-14 00:47:57 +00:00
fix: keep inspector target cache in workspace (#3347)
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
### Fixes
|
||||
|
||||
- API: keep publish-time Plugin Inspector target preparation inside its disposable workspace when hosted runtimes expose an unusable home directory.
|
||||
- API: keep older code-plugin and Claw backports from replacing the highest-semver `latest` release while preserving custom distribution tags.
|
||||
- Integrations: truncate publisher-controlled Discord webhook titles to the platform's 256-character embed limit.
|
||||
- Security: recover scheduled temporal publisher-abuse scans from strict Convex payload validation failures without leaving zombie running runs (thanks @jesse-merhi).
|
||||
|
||||
+6
@@ -26,9 +26,15 @@ declare module "@openclaw/plugin-inspector" {
|
||||
allowExecution?: boolean;
|
||||
configPath?: string;
|
||||
generatedAt?: string;
|
||||
targetOpenClaw?: unknown;
|
||||
}): Promise<{ report: PluginInspectorReport; paths: PluginInspectorPaths }>;
|
||||
};
|
||||
|
||||
export const openClawTargets: {
|
||||
resolveVersion(requestedVersion: string): Promise<unknown>;
|
||||
prepare(resolvedTarget: unknown, options?: { cacheDir?: string }): Promise<unknown>;
|
||||
};
|
||||
|
||||
export const reports: {
|
||||
renderTextSummary(report: PluginInspectorReport, options?: Record<string, unknown>): string;
|
||||
sanitizeArtifact(report: PluginInspectorReport): unknown;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/* @vitest-environment node */
|
||||
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
buildPublishInspectorRunCheckOptions,
|
||||
createPackageInspectorWorkspace,
|
||||
normalizeInspectorReportForPublish,
|
||||
preparePublishInspectorOpenClawTarget,
|
||||
} from "./packageInspectorNode";
|
||||
|
||||
const originalPlatform = process.platform;
|
||||
@@ -60,12 +61,37 @@ describe("package inspector publish normalization", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("targets latest stable OpenClaw for publish-time inspection", () => {
|
||||
expect(buildPublishInspectorRunCheckOptions("/tmp/plugin", "2026-07-30T00:00:00.000Z")).toEqual(
|
||||
it("prepares latest stable OpenClaw with a cache outside the inspected package", async () => {
|
||||
const resolvedTarget = { version: "2026.7.0" };
|
||||
const preparedTarget = { status: "ok", version: "2026.7.0" };
|
||||
const resolveVersion = vi.fn(async () => resolvedTarget);
|
||||
const prepare = vi.fn(async () => preparedTarget);
|
||||
|
||||
await expect(
|
||||
preparePublishInspectorOpenClawTarget("/tmp/plugin", { resolveVersion, prepare }),
|
||||
).resolves.toBe(preparedTarget);
|
||||
expect(resolveVersion).toHaveBeenCalledWith("latest");
|
||||
expect(prepare).toHaveBeenCalledWith(resolvedTarget, {
|
||||
cacheDir: path.join("/tmp/plugin", ".plugin-inspector-cache"),
|
||||
});
|
||||
expect(path.join("/tmp/plugin", ".plugin-inspector-cache")).not.toContain(
|
||||
path.join("/tmp/plugin", "package") + path.sep,
|
||||
);
|
||||
});
|
||||
|
||||
it("uses the prepared OpenClaw target for publish-time inspection", () => {
|
||||
const targetOpenClaw = { status: "ok", version: "2026.7.0" };
|
||||
expect(
|
||||
buildPublishInspectorRunCheckOptions(
|
||||
"/tmp/plugin",
|
||||
"2026-07-30T00:00:00.000Z",
|
||||
targetOpenClaw,
|
||||
),
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
pluginRoot: "/tmp/plugin",
|
||||
openclawPath: false,
|
||||
openclawVersion: "latest",
|
||||
targetOpenClaw,
|
||||
authorFacing: true,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -130,11 +130,32 @@ const inspectorMetadataValidator = v.object({
|
||||
targetOpenClawVersion: v.optional(v.string()),
|
||||
});
|
||||
|
||||
export function buildPublishInspectorRunCheckOptions(root: string, generatedAt: string) {
|
||||
export async function preparePublishInspectorOpenClawTarget<ResolvedTarget, PreparedTarget>(
|
||||
root: string,
|
||||
targets: {
|
||||
resolveVersion: (requestedVersion: string) => Promise<ResolvedTarget>;
|
||||
prepare: (
|
||||
resolvedTarget: ResolvedTarget,
|
||||
options: { cacheDir: string },
|
||||
) => Promise<PreparedTarget>;
|
||||
},
|
||||
) {
|
||||
const resolvedTarget = await targets.resolveVersion("latest");
|
||||
return await targets.prepare(resolvedTarget, {
|
||||
// The dependency defaults to os.homedir(), which can be unusable in serverless runtimes.
|
||||
cacheDir: path.join(root, ".plugin-inspector-cache"),
|
||||
});
|
||||
}
|
||||
|
||||
export function buildPublishInspectorRunCheckOptions(
|
||||
root: string,
|
||||
generatedAt: string,
|
||||
targetOpenClaw: unknown,
|
||||
) {
|
||||
return {
|
||||
pluginRoot: root,
|
||||
openclawPath: false,
|
||||
openclawVersion: "latest",
|
||||
targetOpenClaw,
|
||||
outDir: "reports",
|
||||
capture: false,
|
||||
mockSdk: true,
|
||||
@@ -187,9 +208,11 @@ export const runPackageInspectorForPublishInternal = internalAction({
|
||||
metadata: inspectorMetadataValidator,
|
||||
}),
|
||||
handler: async (ctx, args) => {
|
||||
let root: string | undefined;
|
||||
let workspaceRoot: string | undefined;
|
||||
try {
|
||||
root = await createPackageInspectorWorkspace();
|
||||
workspaceRoot = await createPackageInspectorWorkspace();
|
||||
const root = path.join(workspaceRoot, "package");
|
||||
await mkdir(root, { recursive: true });
|
||||
for (const file of args.files) {
|
||||
const blob = await ctx.storage.get(file.storageId);
|
||||
if (!blob) {
|
||||
@@ -201,8 +224,16 @@ export const runPackageInspectorForPublishInternal = internalAction({
|
||||
}
|
||||
await writeSyntheticInspectorConfigIfNeeded(root, args.files, args.packageName);
|
||||
|
||||
const { pluginRoot } = await import("@openclaw/plugin-inspector");
|
||||
const runCheckOptions = buildPublishInspectorRunCheckOptions(root, new Date().toISOString());
|
||||
const { openClawTargets, pluginRoot } = await import("@openclaw/plugin-inspector");
|
||||
const targetOpenClaw = await preparePublishInspectorOpenClawTarget(
|
||||
workspaceRoot,
|
||||
openClawTargets,
|
||||
);
|
||||
const runCheckOptions = buildPublishInspectorRunCheckOptions(
|
||||
root,
|
||||
new Date().toISOString(),
|
||||
targetOpenClaw,
|
||||
);
|
||||
const { report } = await pluginRoot.runCheck(runCheckOptions);
|
||||
|
||||
return normalizeInspectorReportForPublish(report);
|
||||
@@ -230,8 +261,8 @@ export const runPackageInspectorForPublishInternal = internalAction({
|
||||
},
|
||||
};
|
||||
} finally {
|
||||
if (root) {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
if (workspaceRoot) {
|
||||
await rm(workspaceRoot, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user