mirror of
https://github.com/openclaw/clawhub.git
synced 2026-08-14 00:47:57 +00:00
fix(security): handle artifact directory markers (#3206)
This commit is contained in:
@@ -412,6 +412,51 @@ describe("run-codex-scan-worker diagnostics", () => {
|
||||
expect(metadata.target.files).toEqual([{ path: "SKILL.md", sha256: "abc123", size: 42 }]);
|
||||
});
|
||||
|
||||
it("materializes zero-byte directory markers with descendant files", async () => {
|
||||
const workspace = await tempDir();
|
||||
|
||||
await writeArtifactWorkspace(
|
||||
{
|
||||
job: {
|
||||
_id: "job-directory-marker",
|
||||
hasMaliciousSignal: false,
|
||||
leaseToken: "lease-secret",
|
||||
source: "pre-publication",
|
||||
targetKind: "skillVersion",
|
||||
waitForVtUntil: 0,
|
||||
},
|
||||
target: {
|
||||
files: [
|
||||
{
|
||||
path: "scripts",
|
||||
sha256: "empty",
|
||||
size: 0,
|
||||
url: "data:application/octet-stream,",
|
||||
},
|
||||
{
|
||||
path: "scripts/run.sh",
|
||||
sha256: "script",
|
||||
size: 18,
|
||||
url: "data:text/plain,echo%20ready%0A",
|
||||
},
|
||||
{
|
||||
path: "EMPTY",
|
||||
sha256: "empty",
|
||||
size: 0,
|
||||
url: "data:application/octet-stream,",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
workspace,
|
||||
);
|
||||
|
||||
expect(await readFile(join(workspace, "artifact", "scripts", "run.sh"), "utf8")).toBe(
|
||||
"echo ready\n",
|
||||
);
|
||||
expect(await readFile(join(workspace, "artifact", "EMPTY"))).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("omits signed artifact URLs from download failure errors", async () => {
|
||||
const unsafeLabels = unsafeFixtureLabels();
|
||||
const fetchMock = vi
|
||||
|
||||
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
|
||||
import { mkdirSync, readFileSync } from "node:fs";
|
||||
import { appendFile, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, dirname, join, resolve } from "node:path";
|
||||
import { basename, dirname, join, resolve, sep } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { ConvexHttpClient } from "convex/browser";
|
||||
import { api } from "../../convex/_generated/api";
|
||||
@@ -743,8 +743,19 @@ export async function writeArtifactWorkspace(job: ClaimedJob, workspace: string)
|
||||
};
|
||||
await writeFile(join(workspace, "metadata.json"), `${JSON.stringify(metadata, null, 2)}\n`);
|
||||
|
||||
for (const file of job.target.files ?? []) {
|
||||
const out = safeOutputPath(workspace, file.path);
|
||||
const files = (job.target.files ?? []).map((file) => ({
|
||||
file,
|
||||
out: safeOutputPath(workspace, file.path),
|
||||
}));
|
||||
for (const candidate of files) {
|
||||
const isDirectoryMarker =
|
||||
candidate.file.size === 0 &&
|
||||
files.some(
|
||||
(other) => other.out !== candidate.out && other.out.startsWith(`${candidate.out}${sep}`),
|
||||
);
|
||||
if (isDirectoryMarker) continue;
|
||||
|
||||
const { file, out } = candidate;
|
||||
await mkdir(dirname(out), { recursive: true });
|
||||
await writeFile(out, await download(file.url, { kind: "file", path: file.path }));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user