mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 11:44:46 +00:00
test: make root permission assertions deterministic
This commit is contained in:
@@ -477,36 +477,53 @@ describe("runGlobalPackageUpdateSteps", () => {
|
||||
await fs.mkdir(path.dirname(targetShim), { recursive: true });
|
||||
await fs.writeFile(targetShim, "old shim\n", "utf8");
|
||||
|
||||
const result = await runGlobalPackageUpdateSteps({
|
||||
installTarget: createNpmTarget(globalRoot),
|
||||
installSpec: "openclaw@2.0.0",
|
||||
packageName: "openclaw",
|
||||
packageRoot,
|
||||
runCommand: createRootRunner(globalRoot),
|
||||
runStep: async ({ name, argv, cwd }) => {
|
||||
const prefixIndex = argv.indexOf("--prefix");
|
||||
const stagePrefix = argv[prefixIndex + 1];
|
||||
if (!stagePrefix) {
|
||||
throw new Error("missing staged prefix");
|
||||
let stagedShimForFailure: string | undefined;
|
||||
const realCopyFile = fs.copyFile.bind(fs);
|
||||
const copyFileSpy = vi
|
||||
.spyOn(fs, "copyFile")
|
||||
.mockImplementation(async (...args: Parameters<typeof fs.copyFile>) => {
|
||||
const [source] = args;
|
||||
if (stagedShimForFailure && String(source) === stagedShimForFailure) {
|
||||
throw createFsError("EACCES", "staged shim copy failed");
|
||||
}
|
||||
await writePackageRoot(
|
||||
path.join(stagePrefix, "lib", "node_modules", "openclaw"),
|
||||
"2.0.0",
|
||||
);
|
||||
const stagedShim = path.join(stagePrefix, "bin", "openclaw");
|
||||
await fs.mkdir(path.dirname(stagedShim), { recursive: true });
|
||||
await fs.writeFile(stagedShim, "new shim\n", "utf8");
|
||||
await fs.chmod(stagedShim, 0);
|
||||
return {
|
||||
name,
|
||||
command: argv.join(" "),
|
||||
cwd: cwd ?? process.cwd(),
|
||||
durationMs: 1,
|
||||
exitCode: 0,
|
||||
};
|
||||
},
|
||||
timeoutMs: 1000,
|
||||
});
|
||||
return await realCopyFile(...args);
|
||||
});
|
||||
|
||||
let result: Awaited<ReturnType<typeof runGlobalPackageUpdateSteps>>;
|
||||
try {
|
||||
result = await runGlobalPackageUpdateSteps({
|
||||
installTarget: createNpmTarget(globalRoot),
|
||||
installSpec: "openclaw@2.0.0",
|
||||
packageName: "openclaw",
|
||||
packageRoot,
|
||||
runCommand: createRootRunner(globalRoot),
|
||||
runStep: async ({ name, argv, cwd }) => {
|
||||
const prefixIndex = argv.indexOf("--prefix");
|
||||
const stagePrefix = argv[prefixIndex + 1];
|
||||
if (!stagePrefix) {
|
||||
throw new Error("missing staged prefix");
|
||||
}
|
||||
await writePackageRoot(
|
||||
path.join(stagePrefix, "lib", "node_modules", "openclaw"),
|
||||
"2.0.0",
|
||||
);
|
||||
const stagedShim = path.join(stagePrefix, "bin", "openclaw");
|
||||
stagedShimForFailure = stagedShim;
|
||||
await fs.mkdir(path.dirname(stagedShim), { recursive: true });
|
||||
await fs.writeFile(stagedShim, "new shim\n", "utf8");
|
||||
return {
|
||||
name,
|
||||
command: argv.join(" "),
|
||||
cwd: cwd ?? process.cwd(),
|
||||
durationMs: 1,
|
||||
exitCode: 0,
|
||||
};
|
||||
},
|
||||
timeoutMs: 1000,
|
||||
});
|
||||
} finally {
|
||||
copyFileSpy.mockRestore();
|
||||
}
|
||||
|
||||
expect(result.failedStep?.name).toBe("global install swap");
|
||||
expect(result.verifiedPackageRoot).toBe(packageRoot);
|
||||
|
||||
@@ -65,6 +65,22 @@ function sha256FileSync(filePath: string): string {
|
||||
return createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
|
||||
}
|
||||
|
||||
function canWritePathSync(targetPath: string): boolean {
|
||||
try {
|
||||
fs.accessSync(targetPath, fs.constants.W_OK);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function canMutateNativeBinaryFixturePath(binaryPath: string): boolean {
|
||||
const realPath = fs.realpathSync(binaryPath);
|
||||
return [binaryPath, path.dirname(binaryPath), realPath, path.dirname(realPath)].some((entry) =>
|
||||
canWritePathSync(entry),
|
||||
);
|
||||
}
|
||||
|
||||
function createScriptOperandFixture(tmp: string, fixture?: RuntimeFixture): ScriptOperandFixture {
|
||||
if (fixture) {
|
||||
return {
|
||||
@@ -646,7 +662,7 @@ describe("hardenApprovedExecutionPaths", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("allows shell payloads that invoke absolute-path native binaries", () => {
|
||||
it("handles shell payloads that invoke absolute-path native binaries", () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
}
|
||||
@@ -656,6 +672,10 @@ describe("hardenApprovedExecutionPaths", () => {
|
||||
rawCommand: binaryPath,
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
if (canMutateNativeBinaryFixturePath(binaryPath)) {
|
||||
expect(prepared).toEqual(DENIED_RUNTIME_APPROVAL);
|
||||
return;
|
||||
}
|
||||
expect(prepared.ok).toBe(true);
|
||||
if (!prepared.ok) {
|
||||
throw new Error("unreachable");
|
||||
|
||||
Reference in New Issue
Block a user