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
4 changes: 4 additions & 0 deletions packages/coding-agent/src/tools/bash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import {
} from "../gjc-runtime/managed-owner-admission";
import {
MANAGED_OWNER_CHILD_TOKEN_ENV,
MANAGED_OWNER_COMMAND_ENV,
MANAGED_OWNER_GENERATION_ENV,
MANAGED_OWNER_INCARNATION_ENV,
MANAGED_OWNER_REDACT_COMMAND_ENV,
MANAGED_OWNER_RUN_ID_ENV,
MANAGED_OWNER_STATE_DIR_ENV,
} from "../gjc-runtime/managed-owner-supervisor";
Expand Down Expand Up @@ -118,6 +120,8 @@ export const MANAGED_OWNER_BASH_ENV = [
MANAGED_OWNER_RUN_ID_ENV,
MANAGED_OWNER_INCARNATION_ENV,
MANAGED_OWNER_CHILD_TOKEN_ENV,
MANAGED_OWNER_COMMAND_ENV,
MANAGED_OWNER_REDACT_COMMAND_ENV,
MANAGED_OWNER_PREDECESSOR_TOKEN_ENV,
MANAGED_OWNER_PREDECESSOR_GENERATION_ENV,
MANAGED_OWNER_PREDECESSOR_RUN_ID_ENV,
Expand Down
65 changes: 65 additions & 0 deletions packages/coding-agent/test/bash-executor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,71 @@ describe("executeBash", () => {
}
});

it("unsets all managed-owner env vars to allow nested admission to return fresh (issue #6139)", async () => {
const previousRun = process.env.GJC_MANAGED_OWNER_RUN_ID;
const previousIncarnation = process.env.GJC_MANAGED_OWNER_INCARNATION;
const previousToken = process.env.GJC_MANAGED_OWNER_CHILD_TOKEN;
const previousStateDir = process.env.GJC_TMUX_OWNER_STATE_DIR;
const previousGeneration = process.env.GJC_TMUX_OWNER_GENERATION;
const previousPredecessorToken = process.env.GJC_MANAGED_OWNER_PREDECESSOR_TOKEN;
const previousRedactCmd = process.env.GJC_MANAGED_OWNER_REDACT_COMMAND;

// Set managed-owner env vars to simulate nested environment
process.env.GJC_MANAGED_OWNER_RUN_ID = "test-run-id";
process.env.GJC_MANAGED_OWNER_INCARNATION = "test-incarnation";
process.env.GJC_MANAGED_OWNER_CHILD_TOKEN = "test-token";
process.env.GJC_TMUX_OWNER_STATE_DIR = "/test/state";
process.env.GJC_TMUX_OWNER_GENERATION = "test-gen";
process.env.GJC_MANAGED_OWNER_PREDECESSOR_TOKEN = "test-pred-token";
process.env.GJC_MANAGED_OWNER_REDACT_COMMAND = "1";

try {
await disposeAllShellSessions();
// Explicitly unset managed-owner vars like the bash tool does
const unsetEnv = [
"GJC_MANAGED_OWNER_CHILD_TOKEN",
"GJC_MANAGED_OWNER_COMMAND_JSON",
"GJC_COORDINATOR_SESSION_ID",
"GJC_TMUX_OWNER_GENERATION",
"GJC_TMUX_OWNER_STATE_DIR",
"GJC_MANAGED_OWNER_RUN_ID",
"GJC_MANAGED_OWNER_INCARNATION",
"GJC_MANAGED_OWNER_REDACT_COMMAND",
"GJC_MANAGED_OWNER_PREDECESSOR_TOKEN",
"GJC_MANAGED_OWNER_PREDECESSOR_GENERATION",
"GJC_MANAGED_OWNER_PREDECESSOR_RUN_ID",
"GJC_MANAGED_OWNER_PREDECESSOR_INCARNATION",
];
const result = await executeBash(
'printf "%s|%s|%s|%s|%s|%s|%s" "$(printenv GJC_MANAGED_OWNER_RUN_ID || printf unset)" "$(printenv GJC_MANAGED_OWNER_INCARNATION || printf unset)" "$(printenv GJC_MANAGED_OWNER_CHILD_TOKEN || printf unset)" "$(printenv GJC_TMUX_OWNER_STATE_DIR || printf unset)" "$(printenv GJC_TMUX_OWNER_GENERATION || printf unset)" "$(printenv GJC_MANAGED_OWNER_PREDECESSOR_TOKEN || printf unset)" "$(printenv GJC_MANAGED_OWNER_REDACT_COMMAND || printf unset)"',
{
cwd: tempDir,
timeout: 5000,
sessionKey: "managed-owner-unset-test",
unsetEnv,
},
);
expect(result.output).toBe("unset|unset|unset|unset|unset|unset|unset");
} finally {
// Restore previous env
if (previousRun === undefined) delete process.env.GJC_MANAGED_OWNER_RUN_ID;
else process.env.GJC_MANAGED_OWNER_RUN_ID = previousRun;
if (previousIncarnation === undefined) delete process.env.GJC_MANAGED_OWNER_INCARNATION;
else process.env.GJC_MANAGED_OWNER_INCARNATION = previousIncarnation;
if (previousToken === undefined) delete process.env.GJC_MANAGED_OWNER_CHILD_TOKEN;
else process.env.GJC_MANAGED_OWNER_CHILD_TOKEN = previousToken;
if (previousStateDir === undefined) delete process.env.GJC_TMUX_OWNER_STATE_DIR;
else process.env.GJC_TMUX_OWNER_STATE_DIR = previousStateDir;
if (previousGeneration === undefined) delete process.env.GJC_TMUX_OWNER_GENERATION;
else process.env.GJC_TMUX_OWNER_GENERATION = previousGeneration;
if (previousPredecessorToken === undefined) delete process.env.GJC_MANAGED_OWNER_PREDECESSOR_TOKEN;
else process.env.GJC_MANAGED_OWNER_PREDECESSOR_TOKEN = previousPredecessorToken;
if (previousRedactCmd === undefined) delete process.env.GJC_MANAGED_OWNER_REDACT_COMMAND;
else process.env.GJC_MANAGED_OWNER_REDACT_COMMAND = previousRedactCmd;
await disposeAllShellSessions();
}
});

it("retains then fully disposes persistent shell sessions (MEM-7)", async () => {
await disposeAllShellSessions();
expect(getShellSessionCount()).toBe(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,15 @@ import {
} from "../../src/gjc-runtime/managed-owner-admission";
import {
MANAGED_OWNER_CHILD_TOKEN_ENV,
MANAGED_OWNER_COMMAND_ENV,
MANAGED_OWNER_GENERATION_ENV,
MANAGED_OWNER_INCARNATION_ENV,
MANAGED_OWNER_REDACT_COMMAND_ENV,
MANAGED_OWNER_RUN_ID_ENV,
MANAGED_OWNER_STATE_DIR_ENV,
} from "../../src/gjc-runtime/managed-owner-supervisor";
import { GJC_TMUX_OWNER_SERVER_KEY_ENV } from "../../src/gjc-runtime/session-state-sidecar";
import { GJC_TMUX_LAUNCHED_ENV } from "../../src/gjc-runtime/windows-powershell-command";

const baseCoordinatorOnlyEnvNames = [
"GJC_COORDINATOR_SESSION_STATE_FILE",
Expand All @@ -102,14 +106,17 @@ const coordinatorOnlyEnvNames = [
MANAGED_OWNER_RUN_ID_ENV,
MANAGED_OWNER_INCARNATION_ENV,
MANAGED_OWNER_CHILD_TOKEN_ENV,
MANAGED_OWNER_COMMAND_ENV,
MANAGED_OWNER_REDACT_COMMAND_ENV,
// Managed-owner env family from managed-owner-admission.ts
MANAGED_OWNER_PREDECESSOR_TOKEN_ENV,
MANAGED_OWNER_PREDECESSOR_GENERATION_ENV,
MANAGED_OWNER_PREDECESSOR_RUN_ID_ENV,
MANAGED_OWNER_PREDECESSOR_INCARNATION_ENV,
MANAGED_OWNER_TRANSCRIPT_PATH_ENV,
"GJC_TMUX_OWNER_SERVER_KEY",
"GJC_TMUX_LAUNCHED",
// Managed-owner tmux markers from session-state-sidecar.ts and windows-powershell-command.ts
GJC_TMUX_OWNER_SERVER_KEY_ENV,
GJC_TMUX_LAUNCHED_ENV,
];

describe("issue #5374: session identity on the bash tool-env path", () => {
Expand Down Expand Up @@ -143,19 +150,24 @@ describe("issue #5802: coordinator env isolation at the bash boundary", () => {
process.env.GJC_SESSION_ID = "parent-session";

try {
const managedOwnerEnvList = [
MANAGED_OWNER_STATE_DIR_ENV,
MANAGED_OWNER_GENERATION_ENV,
MANAGED_OWNER_RUN_ID_ENV,
MANAGED_OWNER_INCARNATION_ENV,
MANAGED_OWNER_CHILD_TOKEN_ENV,
MANAGED_OWNER_COMMAND_ENV,
MANAGED_OWNER_REDACT_COMMAND_ENV,
MANAGED_OWNER_PREDECESSOR_TOKEN_ENV,
MANAGED_OWNER_PREDECESSOR_GENERATION_ENV,
MANAGED_OWNER_PREDECESSOR_RUN_ID_ENV,
MANAGED_OWNER_PREDECESSOR_INCARNATION_ENV,
MANAGED_OWNER_TRANSCRIPT_PATH_ENV,
GJC_TMUX_OWNER_SERVER_KEY_ENV,
GJC_TMUX_LAUNCHED_ENV,
];
const command = [
`for name in ${baseCoordinatorOnlyEnvNames.join(" ")} ${[
MANAGED_OWNER_STATE_DIR_ENV,
MANAGED_OWNER_GENERATION_ENV,
MANAGED_OWNER_RUN_ID_ENV,
MANAGED_OWNER_INCARNATION_ENV,
MANAGED_OWNER_CHILD_TOKEN_ENV,
MANAGED_OWNER_PREDECESSOR_TOKEN_ENV,
MANAGED_OWNER_PREDECESSOR_GENERATION_ENV,
MANAGED_OWNER_PREDECESSOR_RUN_ID_ENV,
MANAGED_OWNER_PREDECESSOR_INCARNATION_ENV,
MANAGED_OWNER_TRANSCRIPT_PATH_ENV,
].join(" ")}; do`,
`for name in ${baseCoordinatorOnlyEnvNames.join(" ")} ${managedOwnerEnvList.join(" ")}; do`,
` value=$(printenv "$name" 2>/dev/null || printf '<unset>')`,
` printf '%s=%s\\n' "$name" "$value"`,
"done",
Expand All @@ -175,18 +187,7 @@ describe("issue #5802: coordinator env isolation at the bash boundary", () => {
`${name}=${name === "GJC_COORDINATOR_SESSION_ID" ? "explicit-coordinator-id" : "<unset>"}`,
);
}
for (const name of [
MANAGED_OWNER_STATE_DIR_ENV,
MANAGED_OWNER_GENERATION_ENV,
MANAGED_OWNER_RUN_ID_ENV,
MANAGED_OWNER_INCARNATION_ENV,
MANAGED_OWNER_CHILD_TOKEN_ENV,
MANAGED_OWNER_PREDECESSOR_TOKEN_ENV,
MANAGED_OWNER_PREDECESSOR_GENERATION_ENV,
MANAGED_OWNER_PREDECESSOR_RUN_ID_ENV,
MANAGED_OWNER_PREDECESSOR_INCARNATION_ENV,
MANAGED_OWNER_TRANSCRIPT_PATH_ENV,
]) {
for (const name of managedOwnerEnvList) {
expect(output).toContain(`${name}=<unset>`);
}
expect(output).toContain("GJC_SESSION_ID=child-session");
Expand Down
2 changes: 1 addition & 1 deletion packages/natives/native/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ export declare function __piNativesPublishOutcomeV1(): void
* `packages/natives/native/index.js` (which derives the name from
* `package.json#version`).
*/
export declare function __piNativesV0_18_4(): void
export declare function __piNativesV0_18_5(): void

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 Keep the native sentinel declaration at 0.18.4

At this commit, packages/natives/package.json remains version 0.18.4 and both native/index.js and the Rust addon export __piNativesV0_18_4, so changing only the public declaration advertises a nonexistent __piNativesV0_18_5 export while hiding the actual sentinel. A TypeScript consumer importing the newly declared symbol will compile but fail when the ESM module is instantiated; keep this generated declaration synchronized with the package, wrapper, and addon.

Useful? React with 👍 / 👎.


/**
* Apply conservative pre-execution rewrites to a bash command.
Expand Down
Loading