



























@@ -1,4 +1,4 @@
1-import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
1+import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
22import { tmpdir } from "node:os";
33import { dirname, join } from "node:path";
44import { bundledDistPluginFile, bundledPluginFile } from "openclaw/plugin-sdk/test-fixtures";
@@ -17,6 +17,7 @@ import {
1717collectForbiddenPackContentPaths,
1818collectForbiddenPackPaths,
1919collectMissingPackPaths,
20+collectSkillShellScriptExecutableErrors,
2021collectPackUnpackedSizeErrors,
2122collectPackedInstalledPackageVerificationErrors,
2223createPackedCompletionSmokeEnv,
@@ -338,6 +339,41 @@ describe("bundled plugin package dependency checks", () => {
338339});
339340});
340341342+// This suite exists both as regression coverage and as an intentional CI touchpoint for executable-bit fixes.
343+// Windows doesn't support Unix permission bits; chmod 0o755 is a no-op and
344+// statSync().mode never reports execute bits, so these tests are meaningless there.
345+describe.skipIf(process.platform === "win32")("collectSkillShellScriptExecutableErrors", () => {
346+it("flags non-executable shell scripts under skills/*/scripts", () => {
347+const root = mkdtempSync(join(tmpdir(), "openclaw-release-check-"));
348+const scriptPath = join(root, "skills", "openai-whisper-api", "scripts", "transcribe.sh");
349+mkdirSync(join(root, "skills", "openai-whisper-api", "scripts"), { recursive: true });
350+writeFileSync(scriptPath, "#!/usr/bin/env bash\necho test\n", "utf8");
351+chmodSync(scriptPath, 0o644);
352+353+try {
354+expect(collectSkillShellScriptExecutableErrors(root)).toEqual([
355+"skill shell script is not executable: skills/openai-whisper-api/scripts/transcribe.sh",
356+]);
357+} finally {
358+rmSync(root, { recursive: true, force: true });
359+}
360+});
361+362+it("accepts executable shell scripts", () => {
363+const root = mkdtempSync(join(tmpdir(), "openclaw-release-check-"));
364+const scriptPath = join(root, "skills", "openai-whisper-api", "scripts", "transcribe.sh");
365+mkdirSync(join(root, "skills", "openai-whisper-api", "scripts"), { recursive: true });
366+writeFileSync(scriptPath, "#!/usr/bin/env bash\necho test\n", "utf8");
367+chmodSync(scriptPath, 0o755);
368+369+try {
370+expect(collectSkillShellScriptExecutableErrors(root)).toEqual([]);
371+} finally {
372+rmSync(root, { recursive: true, force: true });
373+}
374+});
375+});
376+341377describe("collectForbiddenPackPaths", () => {
342378it("blocks all packaged node_modules payloads", () => {
343379expect(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。