Isolate Codex app-server state per agent (#74556)

* fix(codex): isolate app-server home per agent

* fix(codex): isolate native Codex assets per agent

* fix(channels): mark inbound system events untrusted

* fix(doctor): warn on personal Codex agent skills

* test(doctor): cover personal Codex agent skills warning

* fix(codex): forward auth profiles to harness runs

* fix(codex): preserve auto auth for harness runs

* fix(codex): auto-select harness auth profiles

* test(codex): type harness auth mock

* feat(codex): select migrated skills

* fix(codex): satisfy migration selection lint

* docs: add codex isolation changelog
This commit is contained in:
pashpashpash
2026-04-30 12:49:02 -07:00
committed by GitHub
parent 7d77680d9f
commit 027ea5f08b
35 changed files with 2299 additions and 49 deletions

View File

@@ -764,6 +764,73 @@ describe("embedded attempt harness pinning", () => {
);
});
it("auto-forwards OpenAI Codex auth profiles to configured Codex harness runs", async () => {
const sessionEntry: SessionEntry = {
sessionId: "codex-auth-session",
updatedAt: Date.now(),
};
await fs.writeFile(
path.join(tmpDir, "auth-profiles.json"),
JSON.stringify({
version: 1,
profiles: {
"openai-codex:work": {
type: "oauth",
provider: "openai-codex",
access: "access-token",
refresh: "refresh-token",
expires: Date.now() + 60_000,
},
},
}),
);
runEmbeddedPiAgentMock.mockResolvedValueOnce({
meta: { durationMs: 1 },
} satisfies EmbeddedPiRunResult);
await runAgentAttempt({
providerOverride: "openai",
originalProvider: "openai",
modelOverride: "gpt-5.4",
cfg: {
agents: {
defaults: {
agentRuntime: { id: "codex", fallback: "none" },
},
},
} as OpenClawConfig,
sessionEntry,
sessionId: sessionEntry.sessionId,
sessionKey: "agent:main:main",
sessionAgentId: "main",
sessionFile: path.join(tmpDir, "session.jsonl"),
workspaceDir: tmpDir,
body: "continue",
isFallbackRetry: false,
resolvedThinkLevel: "medium",
timeoutMs: 1_000,
runId: "run-codex-auto-auth-profile",
opts: { senderIsOwner: false } as Parameters<typeof runAgentAttempt>[0]["opts"],
runContext: {} as Parameters<typeof runAgentAttempt>[0]["runContext"],
spawnedBy: undefined,
messageChannel: undefined,
skillsSnapshot: undefined,
resolvedVerboseLevel: undefined,
agentDir: tmpDir,
onAgentEvent: vi.fn(),
authProfileProvider: "openai",
sessionHasHistory: true,
});
expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
expect.objectContaining({
agentHarnessId: "codex",
authProfileId: "openai-codex:work",
authProfileIdSource: "auto",
}),
);
});
it("pins a fresh unpinned session to the default PI harness", async () => {
const sessionEntry: SessionEntry = {
sessionId: "fresh-session",

View File

@@ -11,6 +11,8 @@ import { annotateInterSessionPromptText } from "../../sessions/input-provenance.
import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js";
import { sanitizeForLog } from "../../terminal/ansi.js";
import { resolveMessageChannel } from "../../utils/message-channel.js";
import { resolveAuthProfileOrder } from "../auth-profiles/order.js";
import { ensureAuthProfileStore } from "../auth-profiles/store.js";
import { resolveBootstrapWarningSignaturesSeen } from "../bootstrap-budget.js";
import { runCliAgent } from "../cli-runner.js";
import { getCliSessionBinding, setCliSessionBinding } from "../cli-session.js";
@@ -85,6 +87,82 @@ type PersistTextTurnTranscriptParams = {
};
};
type HarnessAuthProfileSelection = {
authProfileId?: string;
authProfileIdSource?: "auto" | "user";
authProfileProvider: string;
};
function resolveProfileProviderFromStore(params: {
agentDir: string;
profileId: string | undefined;
}): string | undefined {
const profileId = params.profileId?.trim();
if (!profileId) {
return undefined;
}
return ensureAuthProfileStore(params.agentDir, {
allowKeychainPrompt: false,
}).profiles[profileId]?.provider;
}
function resolveHarnessAuthProfileSelection(params: {
config: OpenClawConfig;
agentDir: string;
workspaceDir: string;
provider: string;
authProfileProvider: string;
sessionAuthProfileId?: string;
sessionAuthProfileSource?: "auto" | "user";
harnessId?: string;
harnessRuntime?: string;
allowHarnessAuthProfileForwarding: boolean;
}): HarnessAuthProfileSelection {
const sessionAuthProfileId = params.sessionAuthProfileId?.trim();
if (sessionAuthProfileId) {
return {
authProfileId: sessionAuthProfileId,
authProfileIdSource: params.sessionAuthProfileSource,
authProfileProvider:
resolveProfileProviderFromStore({
agentDir: params.agentDir,
profileId: sessionAuthProfileId,
}) ?? params.authProfileProvider,
};
}
const runtimeAuthPlan = buildAgentRuntimeAuthPlan({
provider: params.provider,
authProfileProvider: params.authProfileProvider,
config: params.config,
workspaceDir: params.workspaceDir,
harnessId: params.harnessId,
harnessRuntime: params.harnessRuntime,
allowHarnessAuthProfileForwarding: params.allowHarnessAuthProfileForwarding,
});
const harnessAuthProvider = runtimeAuthPlan.harnessAuthProvider;
if (!harnessAuthProvider) {
return { authProfileProvider: params.authProfileProvider };
}
const store = ensureAuthProfileStore(params.agentDir, {
allowKeychainPrompt: false,
});
const authProfileId = resolveAuthProfileOrder({
cfg: params.config,
store,
provider: harnessAuthProvider,
})[0];
return authProfileId
? {
authProfileId,
authProfileIdSource: "auto",
authProfileProvider: harnessAuthProvider,
}
: { authProfileProvider: params.authProfileProvider };
}
function resolveTranscriptUsage(usage: PersistTextTurnTranscriptParams["assistant"]["usage"]) {
if (!usage) {
return ACP_TRANSCRIPT_USAGE;
@@ -320,10 +398,22 @@ export function runAgentAttempt(params: {
agentId: params.sessionAgentId,
sessionKey: params.sessionKey ?? params.sessionId,
});
const runtimeAuthPlan = buildAgentRuntimeAuthPlan({
const harnessAuthSelection = resolveHarnessAuthProfileSelection({
config: params.cfg,
agentDir: params.agentDir,
workspaceDir: params.workspaceDir,
provider: params.providerOverride,
authProfileProvider: params.authProfileProvider,
sessionAuthProfileId: params.sessionEntry?.authProfileOverride,
sessionAuthProfileSource: params.sessionEntry?.authProfileOverrideSource,
harnessId: sessionPinnedAgentHarnessId,
harnessRuntime: agentHarnessPolicy.runtime,
allowHarnessAuthProfileForwarding: !isCliProvider(cliExecutionProvider, params.cfg),
});
const runtimeAuthPlan = buildAgentRuntimeAuthPlan({
provider: params.providerOverride,
authProfileProvider: harnessAuthSelection.authProfileProvider,
sessionAuthProfileId: harnessAuthSelection.authProfileId,
config: params.cfg,
workspaceDir: params.workspaceDir,
harnessId: sessionPinnedAgentHarnessId,
@@ -484,7 +574,7 @@ export function runAgentAttempt(params: {
provider: params.providerOverride,
model: params.modelOverride,
authProfileId,
authProfileIdSource: authProfileId ? params.sessionEntry?.authProfileOverrideSource : undefined,
authProfileIdSource: authProfileId ? harnessAuthSelection.authProfileIdSource : undefined,
thinkLevel: params.resolvedThinkLevel,
verboseLevel: params.resolvedVerboseLevel,
timeoutMs: params.timeoutMs,