--bare disables OAuth/keychain auth and requires ANTHROPIC_API_KEY, breaking Claude Pro/Max subscriptions. CLAUDE.md isolation is now achieved structurally: workspaces live under ~/.disclaw/workspaces/ (outside the repo) so walk-up never reaches DisClaw's CLAUDE.md. Update integration test to assert --bare is absent and verify correct args (-p, --output-format json). Fix sanitize-env tests to reflect CI=true removal (was breaking OAuth headless-mode detection). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
109 lines
3.8 KiB
TypeScript
109 lines
3.8 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
import { sanitizedEnv } from "../../src/runtime/env";
|
|
|
|
describe("sanitizedEnv", () => {
|
|
const originalEnv = process.env;
|
|
|
|
beforeEach(() => {
|
|
// Work with a clean clone so mutations don't bleed between tests
|
|
process.env = { ...originalEnv };
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.env = originalEnv;
|
|
});
|
|
|
|
it("(a) removes DISCORD_BOT_TOKEN from the child environment", () => {
|
|
process.env["DISCORD_BOT_TOKEN"] = "secret-bot-token";
|
|
process.env["DISCORD_CLIENT_SECRET"] = "secret-client";
|
|
process.env["DISCORD_PUBLIC_KEY"] = "public-key-value";
|
|
|
|
const result = sanitizedEnv();
|
|
|
|
expect(result["DISCORD_BOT_TOKEN"]).toBeUndefined();
|
|
expect(result["DISCORD_CLIENT_SECRET"]).toBeUndefined();
|
|
expect(result["DISCORD_PUBLIC_KEY"]).toBeUndefined();
|
|
});
|
|
|
|
it("(b) removes keys matching pattern blocklist: SECRET_*, TOKEN_*, API_KEY*, DISCLAW_SECRET_*", () => {
|
|
process.env["SECRET_FOO"] = "foo-value";
|
|
process.env["TOKEN_BAR"] = "bar-value";
|
|
process.env["API_KEY_TEST"] = "test-key";
|
|
process.env["API_KEY"] = "bare-key";
|
|
process.env["DISCLAW_SECRET_X"] = "x-value";
|
|
|
|
const result = sanitizedEnv();
|
|
|
|
expect(result["SECRET_FOO"]).toBeUndefined();
|
|
expect(result["TOKEN_BAR"]).toBeUndefined();
|
|
expect(result["API_KEY_TEST"]).toBeUndefined();
|
|
expect(result["API_KEY"]).toBeUndefined();
|
|
expect(result["DISCLAW_SECRET_X"]).toBeUndefined();
|
|
});
|
|
|
|
it("(c) preserves PATH, HOME, USERPROFILE and other safe env vars", () => {
|
|
process.env["PATH"] = "/usr/bin:/bin";
|
|
process.env["HOME"] = "/home/user";
|
|
process.env["USERPROFILE"] = "C:\\Users\\user";
|
|
process.env["SOME_SAFE_VAR"] = "safe-value";
|
|
|
|
const result = sanitizedEnv();
|
|
|
|
expect(result["PATH"]).toBe("/usr/bin:/bin");
|
|
expect(result["HOME"]).toBe("/home/user");
|
|
expect(result["USERPROFILE"]).toBe("C:\\Users\\user");
|
|
expect(result["SOME_SAFE_VAR"]).toBe("safe-value");
|
|
});
|
|
|
|
it("(c) sets DISCLAW_AGENT=1 but does NOT set CI=true (breaks Claude Code OAuth)", () => {
|
|
// CI=true was removed: Claude Code interprets it as headless CI mode
|
|
// and requires ANTHROPIC_API_KEY instead of OAuth/keychain login.
|
|
delete process.env["CI"];
|
|
const result = sanitizedEnv();
|
|
|
|
expect(result["CI"]).toBeUndefined();
|
|
expect(result["DISCLAW_AGENT"]).toBe("1");
|
|
});
|
|
|
|
it("(d) extra parameter overrides defaults and adds new keys", () => {
|
|
process.env["SOME_KEY"] = "original";
|
|
|
|
const result = sanitizedEnv({
|
|
DISCLAW_AGENT_NAME: "my-agent",
|
|
CI: "false", // override the mandatory default
|
|
EXTRA_CUSTOM: "custom-value",
|
|
});
|
|
|
|
expect(result["DISCLAW_AGENT_NAME"]).toBe("my-agent");
|
|
expect(result["CI"]).toBe("false");
|
|
expect(result["EXTRA_CUSTOM"]).toBe("custom-value");
|
|
// Keys not in extra are still present
|
|
expect(result["SOME_KEY"]).toBe("original");
|
|
});
|
|
|
|
it("(e) additionalBlocklist removes the specified keys after extras are merged", () => {
|
|
process.env["MY_INTERNAL_SECRET"] = "internal";
|
|
process.env["ANOTHER_KEY"] = "another";
|
|
|
|
const result = sanitizedEnv(
|
|
{ DISCLAW_AGENT_NAME: "test-agent" },
|
|
["MY_INTERNAL_SECRET", "ANOTHER_KEY"]
|
|
);
|
|
|
|
expect(result["MY_INTERNAL_SECRET"]).toBeUndefined();
|
|
expect(result["ANOTHER_KEY"]).toBeUndefined();
|
|
// Extras and standard vars should still be present
|
|
expect(result["DISCLAW_AGENT_NAME"]).toBe("test-agent");
|
|
expect(result["DISCLAW_AGENT"]).toBe("1");
|
|
});
|
|
|
|
it("does not mutate process.env", () => {
|
|
process.env["DISCORD_BOT_TOKEN"] = "sensitive";
|
|
const tokenBefore = process.env["DISCORD_BOT_TOKEN"];
|
|
|
|
sanitizedEnv({ DISCLAW_AGENT_NAME: "agent" }, ["DISCORD_BOT_TOKEN"]);
|
|
|
|
// process.env must be unchanged
|
|
expect(process.env["DISCORD_BOT_TOKEN"]).toBe(tokenBefore);
|
|
});
|
|
});
|