evOo-local/packages/adapters/src/desktop-sandbox-env.test.ts
cynarAI c746c51c78 fix(adapters): stop desktop shell from inheriting host secrets (#77)
* fix(adapters): stop desktop shell from inheriting host secrets

The this-mac shell spawned with the server process environment and ignored
the command environment, so Autopilot could read deployment credentials that
are not on the run redaction list. Drop credential-shaped host variables,
then apply the request environment.

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>

* style(adapters): biome format desktop-sandbox after env scrub

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
2026-09-22 14:32:18 +02:00

103 lines
3.6 KiB
TypeScript

import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { DesktopSandboxProvider } from "./desktop-sandbox.js";
import { desktopCommandEnvironment } from "./desktop-sandbox-env.js";
const ctx = {
operationId: "1",
traceId: "1",
spaceId: "w",
userId: "u",
signal: new AbortController().signal,
};
const HOST_DATABASE_URL = "postgres://desktop-host-secret@127.0.0.1/rakazo";
const HOST_API_KEY = "desktop-host-api-secret";
const AGENT_TOKEN = "agent-scoped-token";
describe("desktop shell environment", () => {
const previous = {
DATABASE_URL: process.env.DATABASE_URL,
OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY,
};
let root: string | undefined;
afterEach(async () => {
if (previous.DATABASE_URL === undefined) delete process.env.DATABASE_URL;
else process.env.DATABASE_URL = previous.DATABASE_URL;
if (previous.OPENROUTER_API_KEY === undefined) delete process.env.OPENROUTER_API_KEY;
else process.env.OPENROUTER_API_KEY = previous.OPENROUTER_API_KEY;
if (root) await rm(root, { recursive: true, force: true });
root = undefined;
});
it("keeps host secrets out of the shell and applies the command environment", async () => {
process.env.DATABASE_URL = HOST_DATABASE_URL;
process.env.OPENROUTER_API_KEY = HOST_API_KEY;
root = await mkdtemp(path.join(tmpdir(), "rakazo-desktop-env-"));
const desktop = new DesktopSandboxProvider({ root });
const computer = await desktop.provision({ botId: "env", homePath: "/unused" }, ctx);
let stdout = "";
let code = 1;
for await (const event of desktop.execute(
computer,
{
argv: ["bash", "-lc", 'printf \'%s|%s\' "$DATABASE_URL" "$BOT_TOKEN"'],
env: { BOT_TOKEN: AGENT_TOKEN },
},
ctx,
)) {
if (event.type === "stdout") stdout += event.data;
if (event.type === "exit") code = event.code;
}
expect(code).toBe(0);
expect(stdout).toBe(`|${AGENT_TOKEN}`);
await desktop.destroy(computer, ctx);
});
});
describe("desktopCommandEnvironment", () => {
it("drops host credentials and keeps the command environment", () => {
const env = desktopCommandEnvironment(
{
PATH: "/usr/bin",
HOME: "/home/user",
DATABASE_URL: HOST_DATABASE_URL,
OPENROUTER_API_KEY: HOST_API_KEY,
BETTER_AUTH_SECRET: "auth-secret",
ENCRYPTION_KEY: "encryption-key",
SANDBOX_SUPERVISOR_TOKEN: "supervisor-token",
PGPASSWORD: "pg-password",
AWS_ACCESS_KEY_ID: "aws-key",
SSH_AUTH_SOCK: "/tmp/ssh-agent",
},
{ BOT_TOKEN: AGENT_TOKEN, "not valid": "nope", LOWER_token: "nope" },
);
expect(env.PATH).toBe("/usr/bin");
expect(env.HOME).toBe("/home/user");
expect(env.SSH_AUTH_SOCK).toBe("/tmp/ssh-agent");
expect(env.BOT_TOKEN).toBe(AGENT_TOKEN);
expect(env.DATABASE_URL).toBeUndefined();
expect(env.OPENROUTER_API_KEY).toBeUndefined();
expect(env.BETTER_AUTH_SECRET).toBeUndefined();
expect(env.ENCRYPTION_KEY).toBeUndefined();
expect(env.SANDBOX_SUPERVISOR_TOKEN).toBeUndefined();
expect(env.PGPASSWORD).toBeUndefined();
expect(env.AWS_ACCESS_KEY_ID).toBeUndefined();
expect(env["not valid"]).toBeUndefined();
expect(env.LOWER_token).toBeUndefined();
});
it("lets an explicit command variable replace a scrubbed host secret", () => {
const env = desktopCommandEnvironment(
{ DATABASE_URL: HOST_DATABASE_URL },
{ DATABASE_URL: "postgres://agent@127.0.0.1/bot" },
);
expect(env.DATABASE_URL).toBe("postgres://agent@127.0.0.1/bot");
});
});