diff --git a/agents/codex.ts b/agents/codex.ts index 8638c6e..a7fa57b 100644 --- a/agents/codex.ts +++ b/agents/codex.ts @@ -43,17 +43,23 @@ function writeCodexConfig(ctx: AgentRunContext): string { } const featuresSection = features.length > 0 ? `[features]\n${features.join("\n")}` : ""; + // trust the project so codex loads repo-level .codex/config.toml + const cwd = process.cwd(); + const projectTrustSection = `[projects."${cwd}"]\ntrust_level = "trusted"`; + writeFileSync( configPath, `# written by pullfrog ${featuresSection} +${projectTrustSection} + ${mcpServerSections.join("\n\n")} `.trim() + "\n" ); log.info( - `» Codex config written to ${configPath} (shell: ${bash === "enabled" ? "enabled" : "disabled"})` + `» Codex config written to ${configPath} (shell: ${bash === "enabled" ? "enabled" : "disabled"}, project trusted: ${cwd})` ); return codexDir; @@ -133,7 +139,6 @@ export const codex = agent({ const env: NodeJS.ProcessEnv = { ...process.env, - HOME: ctx.tmpdir, CODEX_HOME: codexDir, CODEX_API_KEY: apiKey, }; diff --git a/entry b/entry index 7f10d86..9c2b362 100755 --- a/entry +++ b/entry @@ -144457,16 +144457,21 @@ url = "${ctx.mcpServerUrl}"`]; } const featuresSection = features.length > 0 ? `[features] ${features.join("\n")}` : ""; + const cwd = process.cwd(); + const projectTrustSection = `[projects."${cwd}"] +trust_level = "trusted"`; writeFileSync7( configPath, `# written by pullfrog ${featuresSection} +${projectTrustSection} + ${mcpServerSections.join("\n\n")} `.trim() + "\n" ); log.info( - `\xBB Codex config written to ${configPath} (shell: ${bash === "enabled" ? "enabled" : "disabled"})` + `\xBB Codex config written to ${configPath} (shell: ${bash === "enabled" ? "enabled" : "disabled"}, project trusted: ${cwd})` ); return codexDir; } @@ -144522,7 +144527,6 @@ var codex = agent({ const commandExecutionIds = /* @__PURE__ */ new Set(); const env3 = { ...process.env, - HOME: ctx.tmpdir, CODEX_HOME: codexDir, CODEX_API_KEY: apiKey }; diff --git a/test/crossagent/mcpmerge.ts b/test/crossagent/mcpmerge.ts index 95a820f..7eee194 100644 --- a/test/crossagent/mcpmerge.ts +++ b/test/crossagent/mcpmerge.ts @@ -2,27 +2,15 @@ import type { AgentResult, TestRunnerOptions, ValidationCheck } from "../utils.t import { defineFixture, generateAgentUuids, getStructuredOutput } from "../utils.ts"; /** - * MCP merge tests - validate MCP server configuration with repo-level MCP configs present. + * MCP merge test - validates repo-level MCP servers merge correctly with gh_pullfrog. * * uses GITHUB_REPOSITORY=pullfrog/test-repo-mcp which has robinMCP server. - * - * two variants: - * - mcpmerge-full: validates repo-level MCP servers merge correctly with gh_pullfrog - * (claude, cursor, gemini, opencode - agents that auto-discover repo MCPs) - * - mcpmerge-pullfrog-only: validates gh_pullfrog remains available when repo has MCP config - * (codex - doesn't auto-discover repo MCPs) + * all agents should auto-discover repo-level MCP configs and merge them with gh_pullfrog. */ -// shared env for both tests -const sharedEnv = { - GITHUB_REPOSITORY: "pullfrog/test-repo-mcp", -}; +const testUuids = generateAgentUuids(["PULLFROG_MCP_TEST"]); -// --- mcpmerge-full: test repo-level MCP discovery --- - -const fullTestUuids = generateAgentUuids(["PULLFROG_MCP_TEST"]); - -const fullFixture = defineFixture( +const fixture = defineFixture( { prompt: `Call the get_test_value tool from the robinMCP server, then call set_output with the exact value returned.`, effort: "mini", @@ -30,10 +18,10 @@ const fullFixture = defineFixture( { localOnly: true } ); -function fullValidator(result: AgentResult): ValidationCheck[] { +function validator(result: AgentResult): ValidationCheck[] { const output = getStructuredOutput(result); const setOutputCalled = output !== null; - const expectedUuid = fullTestUuids.getUuid(result.agent, "PULLFROG_MCP_TEST"); + const expectedUuid = testUuids.getUuid(result.agent, "PULLFROG_MCP_TEST"); const correctValue = setOutputCalled && output === expectedUuid; return [ @@ -42,46 +30,12 @@ function fullValidator(result: AgentResult): ValidationCheck[] { ]; } -// --- mcpmerge-pullfrog-only: test gh_pullfrog availability only --- - -const baseFixture = defineFixture( - { - prompt: `Call set_output with "PULLFROG_MCP_WORKS".`, - effort: "mini", - }, - { localOnly: true } -); - -function baseValidator(result: AgentResult): ValidationCheck[] { - const output = getStructuredOutput(result); - const setOutputCalled = output !== null; - const correctValue = setOutputCalled && output === "PULLFROG_MCP_WORKS"; - - return [ - { name: "set_output", passed: setOutputCalled }, - { name: "correct_value", passed: correctValue }, - ]; -} - -// --- exports --- - -export const tests: Record = { - "mcpmerge-full": { - name: "mcpmerge-full", - fixture: fullFixture, - validator: fullValidator, - tags: ["mcpmerge"], - agents: ["claude", "cursor", "gemini", "opencode"], - env: sharedEnv, - agentEnv: fullTestUuids.agentEnv, - fileAgentEnv: fullTestUuids.agentEnv, - }, - "mcpmerge-pullfrog-only": { - name: "mcpmerge-pullfrog-only", - fixture: baseFixture, - validator: baseValidator, - tags: ["mcpmerge"], - agents: ["codex"], - env: sharedEnv, - }, +export const test: TestRunnerOptions = { + name: "mcpmerge", + fixture, + validator, + tags: ["mcpmerge"], + env: { GITHUB_REPOSITORY: "pullfrog/test-repo-mcp" }, + agentEnv: testUuids.agentEnv, + fileAgentEnv: testUuids.agentEnv, }; diff --git a/utils/docker.ts b/utils/docker.ts index 4f09916..9818532 100644 --- a/utils/docker.ts +++ b/utils/docker.ts @@ -202,6 +202,9 @@ export function buildDockerRunArgs(config: DockerRunArgsContext): string[] { const setupCmd = [ // install sudo (node:24 is Debian-based) - check if already installed first `which sudo > /dev/null 2>&1 || (apt-get update -qq && apt-get install -qq -y sudo > /dev/null 2>&1)`, + // remove any existing user/group with the same uid/gid (e.g. node:24 has "node" at 1000:1000) + `existing_user=$(getent passwd ${config.ctx.uid} | cut -d: -f1) && [ -n "$existing_user" ] && [ "$existing_user" != "testuser" ] && userdel "$existing_user" 2>/dev/null || true`, + `existing_group=$(getent group ${config.ctx.gid} | cut -d: -f1) && [ -n "$existing_group" ] && [ "$existing_group" != "testuser" ] && groupdel "$existing_group" 2>/dev/null || true`, // create user matching host uid/gid for file permissions `id testuser > /dev/null 2>&1 || (groupadd -g ${config.ctx.gid} testuser 2>/dev/null || true; useradd -u ${config.ctx.uid} -g ${config.ctx.gid} -m -s /bin/bash testuser 2>/dev/null || true)`, // configure passwordless sudo (like GHA runners) - check if already configured