evOo-local/packages/adapters/src/desktop-sandbox-env.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

31 lines
1.1 KiB
TypeScript

import { AGENT_SECRET_NAME_PATTERN } from "@rakazo/contracts";
/**
* Credential-shaped names from the evOo process. Docker exec starts from a fixed
* environment and then adds the command env; the desktop shell must not inherit
* deployment secrets that are absent from the run redaction list.
*/
const HOST_SECRET_ENV_NAME =
/(?:^|_)(?:secret|token|password|passwd|credential|api_key|private_key|database_url|encryption_key|auth_secret|authtoken|key)(?:_|$)|(?:password|passwd|secret|token|api_key)$/i;
export function desktopCommandEnvironment(
inherited: NodeJS.ProcessEnv,
requestEnv: Record<string, string> | undefined,
): NodeJS.ProcessEnv {
const env: NodeJS.ProcessEnv = {};
for (const [key, value] of Object.entries(inherited)) {
if (value === undefined || isHostSecretEnvName(key)) continue;
env[key] = value;
}
if (!requestEnv) return env;
for (const [key, value] of Object.entries(requestEnv)) {
if (!AGENT_SECRET_NAME_PATTERN.test(key) || value.includes("\0")) continue;
env[key] = value;
}
return env;
}
function isHostSecretEnvName(name: string): boolean {
return HOST_SECRET_ENV_NAME.test(name);
}