mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 07:04:48 +00:00
fix: use sandbox-agent CLI for credential extraction in tests and add delay for permission approval
This commit is contained in:
parent
bfd2a80bf1
commit
0faa608822
3 changed files with 90 additions and 18 deletions
|
|
@ -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": [
|
||||||
|
|
|
||||||
|
|
@ -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`);
|
||||||
|
|
|
||||||
|
|
@ -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: {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue