mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 23:28:27 +00:00
refactor(agents): dedupe config and truncation guards
This commit is contained in:
@@ -39,6 +39,25 @@ describe("shell env fallback", () => {
|
||||
return { res, exec };
|
||||
}
|
||||
|
||||
function makeUnsafeStartupEnv(): NodeJS.ProcessEnv {
|
||||
return {
|
||||
SHELL: "/bin/bash",
|
||||
HOME: "/tmp/evil-home",
|
||||
ZDOTDIR: "/tmp/evil-zdotdir",
|
||||
BASH_ENV: "/tmp/evil-bash-env",
|
||||
PS4: "$(touch /tmp/pwned)",
|
||||
};
|
||||
}
|
||||
|
||||
function expectSanitizedStartupEnv(receivedEnv: NodeJS.ProcessEnv | undefined) {
|
||||
expect(receivedEnv).toBeDefined();
|
||||
expect(receivedEnv?.BASH_ENV).toBeUndefined();
|
||||
expect(receivedEnv?.PS4).toBeUndefined();
|
||||
expect(receivedEnv?.ZDOTDIR).toBeUndefined();
|
||||
expect(receivedEnv?.SHELL).toBeUndefined();
|
||||
expect(receivedEnv?.HOME).toBe(os.homedir());
|
||||
}
|
||||
|
||||
it("is disabled by default", () => {
|
||||
expect(shouldEnableShellEnvFallback({} as NodeJS.ProcessEnv)).toBe(false);
|
||||
expect(shouldEnableShellEnvFallback({ OPENCLAW_LOAD_SHELL_ENV: "0" })).toBe(false);
|
||||
@@ -167,13 +186,7 @@ describe("shell env fallback", () => {
|
||||
});
|
||||
|
||||
it("sanitizes startup-related env vars before shell fallback exec", () => {
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
SHELL: "/bin/bash",
|
||||
HOME: "/tmp/evil-home",
|
||||
ZDOTDIR: "/tmp/evil-zdotdir",
|
||||
BASH_ENV: "/tmp/evil-bash-env",
|
||||
PS4: "$(touch /tmp/pwned)",
|
||||
};
|
||||
const env = makeUnsafeStartupEnv();
|
||||
let receivedEnv: NodeJS.ProcessEnv | undefined;
|
||||
const exec = vi.fn((_shell: string, _args: string[], options: { env: NodeJS.ProcessEnv }) => {
|
||||
receivedEnv = options.env;
|
||||
@@ -189,23 +202,12 @@ describe("shell env fallback", () => {
|
||||
|
||||
expect(res.ok).toBe(true);
|
||||
expect(exec).toHaveBeenCalledTimes(1);
|
||||
expect(receivedEnv).toBeDefined();
|
||||
expect(receivedEnv?.BASH_ENV).toBeUndefined();
|
||||
expect(receivedEnv?.PS4).toBeUndefined();
|
||||
expect(receivedEnv?.ZDOTDIR).toBeUndefined();
|
||||
expect(receivedEnv?.SHELL).toBeUndefined();
|
||||
expect(receivedEnv?.HOME).toBe(os.homedir());
|
||||
expectSanitizedStartupEnv(receivedEnv);
|
||||
});
|
||||
|
||||
it("sanitizes startup-related env vars before login-shell PATH probe", () => {
|
||||
resetShellPathCacheForTests();
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
SHELL: "/bin/bash",
|
||||
HOME: "/tmp/evil-home",
|
||||
ZDOTDIR: "/tmp/evil-zdotdir",
|
||||
BASH_ENV: "/tmp/evil-bash-env",
|
||||
PS4: "$(touch /tmp/pwned)",
|
||||
};
|
||||
const env = makeUnsafeStartupEnv();
|
||||
let receivedEnv: NodeJS.ProcessEnv | undefined;
|
||||
const exec = vi.fn((_shell: string, _args: string[], options: { env: NodeJS.ProcessEnv }) => {
|
||||
receivedEnv = options.env;
|
||||
@@ -220,12 +222,7 @@ describe("shell env fallback", () => {
|
||||
|
||||
expect(result).toBe("/usr/local/bin:/usr/bin");
|
||||
expect(exec).toHaveBeenCalledTimes(1);
|
||||
expect(receivedEnv).toBeDefined();
|
||||
expect(receivedEnv?.BASH_ENV).toBeUndefined();
|
||||
expect(receivedEnv?.PS4).toBeUndefined();
|
||||
expect(receivedEnv?.ZDOTDIR).toBeUndefined();
|
||||
expect(receivedEnv?.SHELL).toBeUndefined();
|
||||
expect(receivedEnv?.HOME).toBe(os.homedir());
|
||||
expectSanitizedStartupEnv(receivedEnv);
|
||||
});
|
||||
|
||||
it("returns null without invoking shell on win32", () => {
|
||||
|
||||
@@ -106,7 +106,7 @@ describe("update-startup", () => {
|
||||
suiteCase = 0;
|
||||
});
|
||||
|
||||
async function runUpdateCheckAndReadState(channel: "stable" | "beta") {
|
||||
function mockPackageUpdateStatus(tag = "latest", version = "2.0.0") {
|
||||
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw");
|
||||
vi.mocked(checkUpdateStatus).mockResolvedValue({
|
||||
root: "/opt/openclaw",
|
||||
@@ -114,9 +114,13 @@ describe("update-startup", () => {
|
||||
packageManager: "npm",
|
||||
} satisfies UpdateCheckResult);
|
||||
vi.mocked(resolveNpmChannelTag).mockResolvedValue({
|
||||
tag: "latest",
|
||||
version: "2.0.0",
|
||||
tag,
|
||||
version,
|
||||
});
|
||||
}
|
||||
|
||||
async function runUpdateCheckAndReadState(channel: "stable" | "beta") {
|
||||
mockPackageUpdateStatus("latest", "2.0.0");
|
||||
|
||||
const log = { info: vi.fn() };
|
||||
await runGatewayUpdateCheck({
|
||||
@@ -136,6 +140,13 @@ describe("update-startup", () => {
|
||||
return { log, parsed };
|
||||
}
|
||||
|
||||
function createAutoUpdateSuccessMock() {
|
||||
return vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
code: 0,
|
||||
});
|
||||
}
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "stable channel",
|
||||
@@ -252,33 +263,25 @@ describe("update-startup", () => {
|
||||
});
|
||||
|
||||
it("defers stable auto-update until rollout window is due", async () => {
|
||||
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw");
|
||||
vi.mocked(checkUpdateStatus).mockResolvedValue({
|
||||
root: "/opt/openclaw",
|
||||
installKind: "package",
|
||||
packageManager: "npm",
|
||||
} satisfies UpdateCheckResult);
|
||||
vi.mocked(resolveNpmChannelTag).mockResolvedValue({
|
||||
tag: "latest",
|
||||
version: "2.0.0",
|
||||
});
|
||||
mockPackageUpdateStatus("latest", "2.0.0");
|
||||
|
||||
const runAutoUpdate = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
code: 0,
|
||||
});
|
||||
|
||||
await runGatewayUpdateCheck({
|
||||
cfg: {
|
||||
update: {
|
||||
channel: "stable",
|
||||
auto: {
|
||||
enabled: true,
|
||||
stableDelayHours: 6,
|
||||
stableJitterHours: 12,
|
||||
},
|
||||
const stableAutoConfig = {
|
||||
update: {
|
||||
channel: "stable" as const,
|
||||
auto: {
|
||||
enabled: true,
|
||||
stableDelayHours: 6,
|
||||
stableJitterHours: 12,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await runGatewayUpdateCheck({
|
||||
cfg: stableAutoConfig,
|
||||
log: { info: vi.fn() },
|
||||
isNixMode: false,
|
||||
allowInTests: true,
|
||||
@@ -288,16 +291,7 @@ describe("update-startup", () => {
|
||||
|
||||
vi.setSystemTime(new Date("2026-01-18T07:00:00Z"));
|
||||
await runGatewayUpdateCheck({
|
||||
cfg: {
|
||||
update: {
|
||||
channel: "stable",
|
||||
auto: {
|
||||
enabled: true,
|
||||
stableDelayHours: 6,
|
||||
stableJitterHours: 12,
|
||||
},
|
||||
},
|
||||
},
|
||||
cfg: stableAutoConfig,
|
||||
log: { info: vi.fn() },
|
||||
isNixMode: false,
|
||||
allowInTests: true,
|
||||
@@ -313,21 +307,8 @@ describe("update-startup", () => {
|
||||
});
|
||||
|
||||
it("runs beta auto-update checks hourly when enabled", async () => {
|
||||
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw");
|
||||
vi.mocked(checkUpdateStatus).mockResolvedValue({
|
||||
root: "/opt/openclaw",
|
||||
installKind: "package",
|
||||
packageManager: "npm",
|
||||
} satisfies UpdateCheckResult);
|
||||
vi.mocked(resolveNpmChannelTag).mockResolvedValue({
|
||||
tag: "beta",
|
||||
version: "2.0.0-beta.1",
|
||||
});
|
||||
|
||||
const runAutoUpdate = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
code: 0,
|
||||
});
|
||||
mockPackageUpdateStatus("beta", "2.0.0-beta.1");
|
||||
const runAutoUpdate = createAutoUpdateSuccessMock();
|
||||
|
||||
await runGatewayUpdateCheck({
|
||||
cfg: {
|
||||
@@ -354,20 +335,8 @@ describe("update-startup", () => {
|
||||
});
|
||||
|
||||
it("runs auto-update when checkOnStart is false but auto-update is enabled", async () => {
|
||||
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw");
|
||||
vi.mocked(checkUpdateStatus).mockResolvedValue({
|
||||
root: "/opt/openclaw",
|
||||
installKind: "package",
|
||||
packageManager: "npm",
|
||||
} satisfies UpdateCheckResult);
|
||||
vi.mocked(resolveNpmChannelTag).mockResolvedValue({
|
||||
tag: "beta",
|
||||
version: "2.0.0-beta.1",
|
||||
});
|
||||
const runAutoUpdate = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
code: 0,
|
||||
});
|
||||
mockPackageUpdateStatus("beta", "2.0.0-beta.1");
|
||||
const runAutoUpdate = createAutoUpdateSuccessMock();
|
||||
|
||||
await runGatewayUpdateCheck({
|
||||
cfg: {
|
||||
@@ -450,16 +419,7 @@ describe("update-startup", () => {
|
||||
});
|
||||
|
||||
it("scheduleGatewayUpdateCheck returns a cleanup function", async () => {
|
||||
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw");
|
||||
vi.mocked(checkUpdateStatus).mockResolvedValue({
|
||||
root: "/opt/openclaw",
|
||||
installKind: "package",
|
||||
packageManager: "npm",
|
||||
} satisfies UpdateCheckResult);
|
||||
vi.mocked(resolveNpmChannelTag).mockResolvedValue({
|
||||
tag: "latest",
|
||||
version: "2.0.0",
|
||||
});
|
||||
mockPackageUpdateStatus("latest", "2.0.0");
|
||||
|
||||
const stop = scheduleGatewayUpdateCheck({
|
||||
cfg: { update: { channel: "stable" } },
|
||||
|
||||
Reference in New Issue
Block a user