Files
PaperClipAI/ui/src/lib/test-agent-setup.test.ts
T
Nicky LeachandPaperclip ad4f0b5867 Fix Codex API key authentication in tests and runs (#13260)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agent runtime settings can bind organization secrets to an adapter
environment
> - Paperclip redacts plain environment values when it returns a saved
agent to the UI
> - A saved-agent test sent the redacted `CODEX_HOME` value back to the
server
> - Codex ACP also received the API key without an ACP API-key
authentication request
> - This pull request restores saved environment values for tests and
selects API-key authentication for Codex ACP runs
> - The benefit is that Codex agents can test and run with an
organization-scoped OpenAI API key

## Linked Issues or Issue Description

**What happened?**

Testing a saved Codex agent sent `***REDACTED***` as `CODEX_HOME`.
Secret normalization rejected that placeholder. Remote Codex ACP runs
received `OPENAI_API_KEY`, but session creation stopped with
`Authentication required`.

**Expected behavior**

Paperclip must use the saved `CODEX_HOME` value when it tests an
existing agent. Codex ACP must select API-key authentication when
`OPENAI_API_KEY` is available.

**Steps to reproduce**

1. Create an organization-scoped secret named `OPENAI_API_KEY`.
2. Give a Codex agent access to the secret.
3. Save the agent runtime settings.
4. Test the saved agent again.
5. Run the agent in a remote sandbox through ACP.

**Paperclip version or commit**

Reproduced on master before commit
`68c17709d7c051a804a416263e2e08920f1dfcb1`.

**Deployment mode**

Self-hosted server with a remote sandbox environment.

**Installation method**

Built from source.

**Agent adapter(s) involved**

Codex.

## What Changed

- Send the saved agent ID with adapter environment tests.
- Restore redacted plain environment values from the saved agent before
test-time secret resolution.
- Select the Codex ACP `api-key` authentication method when
`OPENAI_API_KEY` is present.
- Add focused regression coverage for saved-agent tests and remote ACP
launch configuration.

## Verification

- `pnpm --filter @paperclipai/adapter-utils exec vitest run
src/acpx-engine/execute.test.ts`
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/agent-adapter-validation-routes.test.ts`
- `pnpm --filter @paperclipai/ui exec vitest run
src/lib/test-agent-setup.test.ts`
- `pnpm -r typecheck`
- `pnpm test:run`
- `pnpm build`
- `git diff --check`

## Risks

- Low risk. The test route reads saved configuration only when the
request supplies a compatible agent ID and the caller can update that
agent.
- The Codex ACP change applies only when `OPENAI_API_KEY` exists and no
explicit `DEFAULT_AUTH_REQUEST` exists.
- There are no schema migrations or telemetry changes.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex with `gpt-5`. The context-window size is not exposed in
this runtime. The model used reasoning, repository search, file editing,
command execution, and test execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-11 13:58:29 -07:00

82 lines
2.3 KiB
TypeScript

import { beforeEach, expect, it, vi } from "vitest";
import { testAgentSetup } from "./test-agent-setup";
const testEnvironment = vi.hoisted(() => vi.fn());
vi.mock("../api/agents", () => ({ agentsApi: { testEnvironment } }));
const input = {
companyId: "company-1",
agentId: "agent-1",
adapterType: "paperclip_runner",
providerAdapter: "claude_local",
environmentId: "sandbox-1",
adapterConfig: {
provider: "acpx",
acpxAgent: "claude",
env: {
ANTHROPIC_API_KEY: {
type: "user_secret_ref",
key: "ANTHROPIC_API_KEY",
version: "latest",
},
},
},
};
const ready = {
adapterType: "paperclip_runner",
status: "pass",
testedAt: "now",
checks: [{ code: "runtime", level: "info", message: "Ready" }],
};
beforeEach(() => testEnvironment.mockReset());
it("does not report a connection when runtime readiness passes but provider authentication fails", async () => {
testEnvironment
.mockResolvedValueOnce(ready)
.mockResolvedValueOnce({
...ready,
adapterType: "claude_local",
status: "fail",
checks: [
{
code: "claude_hello_probe_failed",
level: "error",
message: "Invalid API key",
},
],
});
const result = await testAgentSetup(input);
expect(result.status).toBe("fail");
expect(result.adapterType).toBe("paperclip_runner");
expect(testEnvironment).toHaveBeenLastCalledWith(
"company-1",
"claude_local",
{
agentId: "agent-1",
environmentId: "sandbox-1",
adapterConfig: { ...input.adapterConfig, engine: "cli" },
},
);
expect(result.checks.map((check) => check.code)).toEqual([
"runtime",
"claude_hello_probe_failed",
]);
});
it("does not repeat a completed model probe", async () => {
testEnvironment.mockResolvedValue({
...ready,
checks: [
{ code: "codex_hello_probe_passed", level: "info", message: "Hello" },
],
});
await testAgentSetup({
...input,
adapterType: "codex_local",
providerAdapter: "codex_local",
});
expect(testEnvironment).toHaveBeenCalledTimes(1);
});
it("preserves runtime warnings after a successful provider request", async () => {
testEnvironment
.mockResolvedValueOnce({ ...ready, status: "warn" })
.mockResolvedValueOnce(ready);
expect((await testAgentSetup(input)).status).toBe("warn");
});