fix: use sandbox-agent CLI for credential extraction in tests and add delay for permission approval

This commit is contained in:
Nathan Flurry 2026-01-29 07:39:07 -08:00
parent bfd2a80bf1
commit 0faa608822
3 changed files with 90 additions and 18 deletions

View file

@ -1559,6 +1559,34 @@
} }
} }
}, },
"StderrOutput": {
"type": "object",
"required": [
"truncated"
],
"properties": {
"head": {
"type": "string",
"description": "First N lines of stderr (if truncated) or full stderr (if not truncated)",
"nullable": true
},
"tail": {
"type": "string",
"description": "Last N lines of stderr (only present if truncated)",
"nullable": true
},
"total_lines": {
"type": "integer",
"description": "Total number of lines in stderr",
"nullable": true,
"minimum": 0
},
"truncated": {
"type": "boolean",
"description": "Whether the output was truncated"
}
}
},
"TerminatedBy": { "TerminatedBy": {
"type": "string", "type": "string",
"enum": [ "enum": [

View file

@ -46,28 +46,58 @@ const log = {
section: (msg: string) => console.log(`\n\x1b[1m=== ${msg} ===\x1b[0m`), section: (msg: string) => console.log(`\n\x1b[1m=== ${msg} ===\x1b[0m`),
}; };
// Credentials extraction (mirrors agent-credentials logic) // Credentials extraction using sandbox-agent CLI
function getAnthropicApiKey(): string | undefined { function extractCredentials(): { anthropicApiKey?: string; openaiApiKey?: string } {
if (process.env.ANTHROPIC_API_KEY) return process.env.ANTHROPIC_API_KEY; // First check environment variables
const home = homedir(); const envCreds = {
for (const path of [join(home, ".claude.json"), join(home, ".claude.json.api")]) { anthropicApiKey: process.env.ANTHROPIC_API_KEY,
try { openaiApiKey: process.env.OPENAI_API_KEY,
const data = JSON.parse(readFileSync(path, "utf-8")); };
const key = data.primaryApiKey || data.apiKey || data.anthropicApiKey;
if (key?.startsWith("sk-ant-")) return key; // If both are set in env, use them
} catch {} if (envCreds.anthropicApiKey && envCreds.openaiApiKey) {
return envCreds;
} }
return undefined;
// Try to extract using sandbox-agent CLI
try {
const binaryPath = join(ROOT_DIR, "target/release/sandbox-agent");
const debugBinaryPath = join(ROOT_DIR, "target/debug/sandbox-agent");
const binary = existsSync(binaryPath) ? binaryPath : existsSync(debugBinaryPath) ? debugBinaryPath : null;
if (binary) {
const output = execSync(`${binary} credentials extract-env --export`, {
encoding: "utf-8",
stdio: ["pipe", "pipe", "pipe"],
});
// Parse export statements: export KEY="value"
for (const line of output.split("\n")) {
const match = line.match(/^export (\w+)="(.*)"/);
if (match) {
const [, key, value] = match;
if (key === "ANTHROPIC_API_KEY" && !envCreds.anthropicApiKey) {
envCreds.anthropicApiKey = value;
} else if (key === "OPENAI_API_KEY" && !envCreds.openaiApiKey) {
envCreds.openaiApiKey = value;
}
}
}
log.debug(`Extracted credentials via sandbox-agent CLI`);
}
} catch (err) {
log.debug(`Failed to extract credentials via CLI: ${err}`);
}
return envCreds;
}
function getAnthropicApiKey(): string | undefined {
return extractCredentials().anthropicApiKey;
} }
function getOpenAiApiKey(): string | undefined { function getOpenAiApiKey(): string | undefined {
if (process.env.OPENAI_API_KEY) return process.env.OPENAI_API_KEY; return extractCredentials().openaiApiKey;
const home = homedir();
try {
const data = JSON.parse(readFileSync(join(home, ".codex", "codex.json"), "utf-8"));
if (data.apiKey) return data.apiKey;
} catch {}
return undefined;
} }
// Build sandbox-agent // Build sandbox-agent
@ -520,6 +550,10 @@ async function testAgentActions(baseUrl: string, agent: string, sandbox: Sandbox
const fileMessage = `Create a file at ${testFile} with exactly this content (no quotes, no extra text): ${expectedContent}`; const fileMessage = `Create a file at ${testFile} with exactly this content (no quotes, no extra text): ${expectedContent}`;
await sendMessage(baseUrl, sessionId, fileMessage); await sendMessage(baseUrl, sessionId, fileMessage);
// Wait for agent to complete action after permission approval
log.info("Waiting for agent to complete action...");
await new Promise((r) => setTimeout(r, 5000));
// Verify file was created // Verify file was created
log.info("Verifying file was created..."); log.info("Verifying file was created...");
const fileCheck = await sandbox.exec(`cat ${testFile} 2>&1`); const fileCheck = await sandbox.exec(`cat ${testFile} 2>&1`);

View file

@ -286,6 +286,16 @@ export interface components {
SessionStartedData: { SessionStartedData: {
metadata?: unknown; metadata?: unknown;
}; };
StderrOutput: {
/** @description First N lines of stderr (if truncated) or full stderr (if not truncated) */
head?: string | null;
/** @description Last N lines of stderr (only present if truncated) */
tail?: string | null;
/** @description Total number of lines in stderr */
total_lines?: number | null;
/** @description Whether the output was truncated */
truncated: boolean;
};
/** @enum {string} */ /** @enum {string} */
TerminatedBy: "agent" | "daemon"; TerminatedBy: "agent" | "daemon";
TurnStreamQuery: { TurnStreamQuery: {