mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-16 12:30:45 +00:00
test: sandbox audit-exec-surface under OpenClaw home tempdir
audit-exec-surface.test.ts called saveExecApprovals({ version: 1, agents: {} })
in a top-level afterEach and inside several it() blocks without redirecting
the OpenClaw home env vars. Sibling exec-approvals tests (the store and
agent ones) already wrap their cases in beforeAll(mkdtemp) +
beforeEach(set OPENCLAW_HOME/HOME/USERPROFILE = tempDir) for exactly this
reason.
Without that wrapping, every saveExecApprovals call resolved through
expandHomePrefix → resolveRawHomeDir, which prefers OPENCLAW_HOME and falls
back through HOME and USERPROFILE — so on a developer machine running an
OpenClaw gateway, pnpm test silently truncated the live
~/.openclaw/exec-approvals.json to { "version": 1, "agents": {} }.
Move the cleanup hook inside the describe block, add the standard
beforeAll / beforeEach / afterAll setup, and save/restore all three env
vars (OPENCLAW_HOME, HOME, USERPROFILE) so every case runs against a
per-case tempdir regardless of what the host has set.
Verified on macOS Darwin 25.4.0 (M1) running an active OpenClaw gateway
with the live ~/.openclaw/exec-approvals.json (11722 bytes, 7 configured
agents): SHA-256 unchanged before vs after running
pnpm exec vitest run src/security/audit-exec-surface.test.ts
all 7 cases pass.
This commit is contained in:
@@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Cron/failover: classify structured OpenAI-compatible `server_error` payloads as `server_error`, expose that reason in cron state, and let one-shot cron retry policy honor `retryOn: ["server_error"]` without requiring raw `5xx` text. (#45594) Thanks @clovericbot.
|
||||
- Slack: wake the resolved thread session after interactive reply button/select clicks and carry Slack delivery context through the queued interaction event, so clicks continue the visible conversation. Fixes #79676 and #61502. (#79836) Thanks @velvet-shark, @tianxiaochannel-oss88, and @Saicheg.
|
||||
- WhatsApp/streaming: send only the new suffix when text-end block replies repeat prior preambles across tool-call cycles, preventing cumulative WhatsApp preamble messages. Fixes #78946. (#79120) Thanks @brokemac79 and @papawattu.
|
||||
- Tests/security audit: sandbox `audit-exec-surface.test.ts` under a per-case OpenClaw home tempdir, redirecting `OPENCLAW_HOME` (which wins over `HOME`/`USERPROFILE` in `resolveRawHomeDir`) alongside `HOME` and `USERPROFILE`, so its `saveExecApprovals(...)` calls never touch the live `~/.openclaw/exec-approvals.json` on the host running the suite. Sibling exec-approvals tests already used the tempdir pattern; this file did not, so running `pnpm test` against a contributor's local checkout was silently truncating their real approvals to `{ "version": 1, "agents": {} }`. (#79885) Thanks @omarshahine.
|
||||
|
||||
## 2026.5.9
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { saveExecApprovals } from "../infra/exec-approvals.js";
|
||||
import { collectExecRuntimeFindings } from "./audit.js";
|
||||
@@ -27,11 +30,61 @@ function requireFinding(
|
||||
return finding;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
saveExecApprovals({ version: 1, agents: {} });
|
||||
});
|
||||
|
||||
describe("security audit exec surface findings", () => {
|
||||
// Redirect the OpenClaw home (OPENCLAW_HOME wins over HOME/USERPROFILE in
|
||||
// `resolveRawHomeDir`) to a per-test tempdir so `saveExecApprovals` never
|
||||
// touches the real `~/.openclaw/exec-approvals.json` on the host running
|
||||
// the suite.
|
||||
let previousOpenClawHome: string | undefined;
|
||||
let previousHome: string | undefined;
|
||||
let previousUserProfile: string | undefined;
|
||||
let tempRoot = "";
|
||||
let tempCaseIndex = 0;
|
||||
|
||||
beforeAll(async () => {
|
||||
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-exec-approvals-"));
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
previousOpenClawHome = process.env.OPENCLAW_HOME;
|
||||
previousHome = process.env.HOME;
|
||||
previousUserProfile = process.env.USERPROFILE;
|
||||
const tempDir = path.join(tempRoot, `case-${++tempCaseIndex}`);
|
||||
await fs.mkdir(path.join(tempDir, ".openclaw"), { recursive: true });
|
||||
// OPENCLAW_HOME takes precedence over HOME/USERPROFILE in resolveRawHomeDir,
|
||||
// so all three must point at the tempdir to neutralize whichever the host
|
||||
// happens to have set.
|
||||
process.env.OPENCLAW_HOME = tempDir;
|
||||
process.env.HOME = tempDir;
|
||||
// Windows uses USERPROFILE for os.homedir()
|
||||
process.env.USERPROFILE = tempDir;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
saveExecApprovals({ version: 1, agents: {} });
|
||||
if (previousOpenClawHome === undefined) {
|
||||
delete process.env.OPENCLAW_HOME;
|
||||
} else {
|
||||
process.env.OPENCLAW_HOME = previousOpenClawHome;
|
||||
}
|
||||
if (previousHome === undefined) {
|
||||
delete process.env.HOME;
|
||||
} else {
|
||||
process.env.HOME = previousHome;
|
||||
}
|
||||
if (previousUserProfile === undefined) {
|
||||
delete process.env.USERPROFILE;
|
||||
} else {
|
||||
process.env.USERPROFILE = previousUserProfile;
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
if (tempRoot) {
|
||||
await fs.rm(tempRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
||||
}
|
||||
});
|
||||
|
||||
it("warns when exec approvals enable autoAllowSkills", () => {
|
||||
saveExecApprovals({
|
||||
version: 1,
|
||||
|
||||
Reference in New Issue
Block a user