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
2 changes: 2 additions & 0 deletions src/cli/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const flagSchema = {
provider: { type: "string" },
branch: { type: "string", short: "b" },
"no-attach": { type: "boolean" },
"debug-egress": { type: "boolean" },
help: { type: "boolean", short: "h" },
} as const satisfies ParseArgsOptionsConfig;

Expand All @@ -31,6 +32,7 @@ export function sandboxCmd(args: string[]): void {
provider: values.provider,
branch: values.branch,
noAttach: values["no-attach"] === true,
debugEgress: values["debug-egress"] === true,
}),
);
}
12 changes: 12 additions & 0 deletions src/sandbox/container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,18 @@ describe("buildOpenshellCreateArgv", () => {
expect(argv).not.toContain("--volume");
});

it("appends --log-level debug when debugEgress is set", () => {
const argv = buildOpenshellCreateArgv({ ...base, debugEgress: true });
const idx = argv.indexOf("--log-level");
expect(idx).toBeGreaterThan(-1);
expect(argv[idx + 1]).toBe("debug");
});

it("omits --log-level by default", () => {
const argv = buildOpenshellCreateArgv(base);
expect(argv).not.toContain("--log-level");
});

it("passes providerId verbatim as --provider", () => {
const argv = buildOpenshellCreateArgv({ ...base, providerId: "openrouter" });
const idx = argv.indexOf("--provider");
Expand Down
4 changes: 4 additions & 0 deletions src/sandbox/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ export interface OpenshellCreateArgs {
providerId: ProviderId;
command: string[];
volumeArgs?: readonly string[];
/** Opt-in: run the in-container supervisor at debug so the L7 egress
* request/response header lines surface via `openlock logs`. Off by default. */
debugEgress?: boolean;
}

export interface OpenshellHandle {
Expand All @@ -153,6 +156,7 @@ export function buildOpenshellCreateArgv(args: OpenshellCreateArgs): string[] {
args.policy,
"--provider",
args.providerId,
...(args.debugEgress === true ? ["--log-level", "debug"] : []),
"--no-tty",
...(args.volumeArgs ?? []),
"--",
Expand Down
2 changes: 1 addition & 1 deletion src/sandbox/fork-binaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { forkDir } from "../paths";
// release ships, alongside any matching changes in openlock that depend
// on fork-side behavior.
const OPENSHELL_FORK_REPO = "vessux/OpenShell";
export const OPENSHELL_FORK_TAG = "v0.6.5";
export const OPENSHELL_FORK_TAG = "v0.6.6";

type ForkBinary = "openshell-gateway" | "openshell-sandbox" | "openshell";

Expand Down
16 changes: 15 additions & 1 deletion src/sandbox/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ export interface SandboxOpts {
/** Detached create: create/resolve the session but do NOT attach the harness,
* so a scripted/CI caller can drive it via `openlock exec`. */
noAttach?: boolean;
/** Opt-in supervisor debug for L7 egress header capture (see container.ts).
* Applies only at container creation; ignored when reattaching an existing one. */
debugEgress?: boolean;
}

async function buildSandboxImage(openlockFolderPath: string): Promise<string> {
Expand Down Expand Up @@ -144,6 +147,7 @@ async function createSession(
harness: Harness,
providerId: ProviderId,
branch: string | undefined,
debugEgress: boolean,
): Promise<NewSession> {
const { policy, mounts } = resolved;

Expand Down Expand Up @@ -232,6 +236,7 @@ async function createSession(
providerId,
command: ["/bin/bash", "-c", setupCmd],
volumeArgs: bindMountArgs(mounts),
debugEgress,
});

// Don't await handle.exited — it blocks until the container stops.
Expand Down Expand Up @@ -556,11 +561,19 @@ async function resolveOrCreateSession(
harness: Harness,
providerId: ProviderId,
branch: string | undefined,
debugEgress: boolean,
): Promise<ResolvedSession> {
const matches = findSessionsByPath(sessionsDir(), projectPath);
exitOnAmbiguousSessions(projectPath, matches);
if (matches.length === 0) {
const created = await createSession(projectPath, resolved, harness, providerId, branch);
const created = await createSession(
projectPath,
resolved,
harness,
providerId,
branch,
debugEgress,
);
updateSessionMeta(sessionsDir(), created.id, {
attachedPid: process.pid,
lastAttachedAt: new Date().toISOString(),
Expand Down Expand Up @@ -696,6 +709,7 @@ export async function runSandbox(opts: SandboxOpts): Promise<void> {
harness,
providerId,
opts.branch,
opts.debugEgress === true,
);

if (opts.noAttach === true) {
Expand Down