Skip to content
Open
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
28 changes: 22 additions & 6 deletions plugins/codex/scripts/session-lifecycle-hook.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,27 @@ function shellEscape(value) {
return `'${String(value).replace(/'/g, `'\"'\"'`)}'`;
}

function appendEnvVar(name, value) {
if (!process.env.CLAUDE_ENV_FILE || value == null || value === "") {
function setEnv(name, value) {
const envFile = process.env.CLAUDE_ENV_FILE;
if (!envFile || value == null || value === "") {
return;
}
fs.appendFileSync(process.env.CLAUDE_ENV_FILE, `export ${name}=${shellEscape(value)}\n`, "utf8");
const prefix = `export ${name}=`;
const line = `${prefix}${shellEscape(value)}`;

let content = "";
try {
content = fs.readFileSync(envFile, "utf8");
} catch (err) {
if (err.code !== "ENOENT") throw err;
}

const lines = content.split(/\r?\n/).filter((l) => l && !l.startsWith(prefix));
lines.push(line);

const tmp = `${envFile}.${process.pid}.tmp`;
fs.writeFileSync(tmp, lines.join("\n") + "\n", "utf8");
fs.renameSync(tmp, envFile);
Comment on lines +53 to +55

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid overwriting concurrent SessionStart hook updates

When another matching SessionStart hook writes to the shared CLAUDE_ENV_FILE after this read, the subsequent whole-file rename silently discards that hook's export. This can occur in installations with additional user or plugin SessionStart hooks, leaving later commands without their persisted environment variables; use an append-based update or otherwise serialize read-modify-write access.

Useful? React with 👍 / 👎.

Comment on lines +53 to +55

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve restrictive permissions on the environment file

When Claude created the existing environment file with a restrictive mode such as 0600 and its parent directory is traversable, writeFileSync creates the replacement using the default 0666 & umask mode—commonly 0644—and the rename installs those broader permissions. Because this file may contain exports from other hooks, including credentials, replacing it should preserve the original mode or explicitly create the temporary file with equally restrictive permissions.

Useful? React with 👍 / 👎.

}

function cleanupSessionJobs(cwd, sessionId) {
Expand Down Expand Up @@ -75,9 +91,9 @@ function cleanupSessionJobs(cwd, sessionId) {
}

function handleSessionStart(input) {
appendEnvVar(SESSION_ID_ENV, input.session_id);
appendEnvVar(TRANSCRIPT_PATH_ENV, input.transcript_path);
appendEnvVar(PLUGIN_DATA_ENV, process.env[PLUGIN_DATA_ENV]);
setEnv(SESSION_ID_ENV, input.session_id);
setEnv(TRANSCRIPT_PATH_ENV, input.transcript_path);
setEnv(PLUGIN_DATA_ENV, process.env[PLUGIN_DATA_ENV]);
}

async function handleSessionEnd(input) {
Expand Down