fix(release): keep package output names local

This commit is contained in:
Vincent Koc
2026-06-17 02:18:38 +02:00
parent 5b9a3d05b6
commit b67775f7fe
4 changed files with 50 additions and 0 deletions

View File

@@ -78,6 +78,12 @@ function readEqualsOptionValue(value, optionName) {
return value;
}
function validateOutputName(value) {
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*\.t(?:ar\.)?gz$/u.test(value)) {
throw new Error(`--output-name must be a tarball filename, not a path: ${value}`);
}
}
export function parseArgs(argv) {
const options = {
outputDir: "",
@@ -111,6 +117,9 @@ export function parseArgs(argv) {
throw new Error(`unknown argument: ${arg}`);
}
}
if (options.outputName) {
validateOutputName(options.outputName);
}
return options;
}

View File

@@ -131,9 +131,16 @@ export function parseArgs(argv) {
throw new Error(`unknown argument: ${arg}`);
}
}
validateOutputName(options.outputName);
return options;
}
function validateOutputName(value) {
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*\.t(?:ar\.)?gz$/u.test(value)) {
throw new Error(`--output-name must be a tarball filename, not a path: ${value}`);
}
}
export function validateOpenClawPackageSpec(spec) {
if (!OPENCLAW_PACKAGE_SPEC_RE.test(spec)) {
throw new Error(

View File

@@ -96,6 +96,23 @@ describe("package-openclaw-for-docker", () => {
}
});
it("rejects package artifact output names that escape the output directory", () => {
for (const outputName of [
"../openclaw-current.tgz",
"nested/openclaw-current.tgz",
"openclaw-current.zip",
".openclaw-current.tgz",
]) {
expect(() => parseArgs(["--output-name", outputName])).toThrow(
`--output-name must be a tarball filename, not a path: ${outputName}`,
);
}
expect(parseArgs(["--output-name", "openclaw-current.tar.gz"]).outputName).toBe(
"openclaw-current.tar.gz",
);
});
it("uses build-all as the single bounded package artifact build step", async () => {
const calls: Array<{
command: string;

View File

@@ -165,6 +165,23 @@ describe("resolve-openclaw-package-candidate", () => {
});
});
it("rejects package candidate output names that escape the output directory", () => {
for (const outputName of [
"../openclaw-current.tgz",
"nested/openclaw-current.tgz",
"openclaw-current.zip",
".openclaw-current.tgz",
]) {
expect(() => parseArgs(["--output-name", outputName])).toThrow(
`--output-name must be a tarball filename, not a path: ${outputName}`,
);
}
expect(parseArgs(["--output-name", "openclaw-current.tar.gz"]).outputName).toBe(
"openclaw-current.tar.gz",
);
});
it("resolves npm package candidates through the Windows npm.cmd toolchain shim", () => {
const execPath = "C:\\nodejs\\node.exe";
const npmCmdPath = path.win32.resolve(path.win32.dirname(execPath), "npm.cmd");