Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion claw/packages/brain/src/sandbox/ensure-hands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,6 @@ async function provisionHands(
...(action.params.env ?? {}),
AUTH_CLAW_TOKEN: handsToken,
CLAW_SESSION_ID: sessionId,
HYPERLOOM_SESSION_ID: sessionId,
INFERENCE_OPTIMIZER_SESSION_LAYOUT: "per_model_ts",
MCP_PORT: mcpPort,
WORKSPACE_PATH: "/workspace",
Expand Down
7 changes: 7 additions & 0 deletions claw/packages/hands/src/runtime/child-privilege.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ function persistAllocations(table: Map<string, number>): void {
*/
const WORKSPACE_FACING = [
"PATH", "HOME", "SHELL", "TERM", "TZ", "LANG", "LC_ALL", "PWD", "USER", "LOGNAME",
// The session a command is running for. Named here because a command needs to
// be able to say which session it belongs to -- Hyperloom stamps it into its
// run manifest and its LLM attribution -- and because the alternative is what
// was there before: the same value reaching the child anyway under a
// second, application-specific name. An identifier, not a credential; the
// credential is AUTH_CLAW_TOKEN, which this list deliberately omits.
"CLAW_SESSION_ID",
];

/**
Expand Down
17 changes: 17 additions & 0 deletions claw/packages/hands/test/child-privilege.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,23 @@ test("the child environment carries no Brain-facing credential, over the whole e
assert.equal(env.PATH, process.env.PATH);
});

test("the child environment carries the session id", () => {
// Regression guard. This value used to reach a command only under a second,
// application-specific name, while the name every consumer actually reads was
// filtered out -- so a run could not say which session it belonged to, and the
// one document that told agents to branch on it was branching on a variable
// that is never set. It is an identifier and the same value is already on the
// sandbox, so naming it here costs no secrecy.
const previous = process.env.CLAW_SESSION_ID;
process.env.CLAW_SESSION_ID = "sess-visible-to-the-child";
try {
assert.equal(privilege.childEnvironment().CLAW_SESSION_ID, "sess-visible-to-the-child");
} finally {
if (previous === undefined) delete process.env.CLAW_SESSION_ID;
else process.env.CLAW_SESSION_ID = previous;
}
});

test("a spawned command cannot read the token out of its own environment", async () => {
bg.spawnBackground("sess-env", "run-env", "env; cat /proc/self/environ | tr '\\0' '\\n'", "envdump");
await settle(300);
Expand Down
1 change: 0 additions & 1 deletion claw/packages/protocol/src/user-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export const USER_ENV_DENY_LIST: ReadonlySet<string> = new Set([
"WORKSPACE_PATH",
"USER_ID_HEX",
"USER_DATA_PATH",
"HYPERLOOM_SESSION_ID",
"INFERENCE_OPTIMIZER_SESSION_LAYOUT",
"SAFE_API_URL",
"SAFE_API_KEY",
Expand Down
Loading