mirror of
https://github.com/openclaw/openclaw.git
synced 2026-09-28 14:12:28 +08:00
## Summary Native Codex sign-in now supplies model availability without copying its credentials into OpenClaw profiles. CLI, chat, status, and Gateway model controls use one prepared owner for per-model runtime eligibility, physical routes, and authentication mode. Selections are revalidated before session persistence. Native sign-in observations no longer masquerade as host-prepared credentials when the registered runtime evaluates model eligibility. Native credentials remain with Codex. Explicit profiles, account pins, authored routes, isolated agent homes, and remote server accounts retain their existing boundaries. Native local stdio uses the user home only when no prepared OpenClaw credential or explicit home selection owns the route. The separate Gateway authentication projection and ordinary-read Codex credential import are removed. Explicit import preserves the supported declared `openai:default` profile reference. Apply now rechecks inherited account identity and usability at the destination, so an account inserted under the same profile ID after planning cannot be silently replaced. Matching shared accounts stay inherited. Native authentication enumeration also follows the captured plugin generation, including an explicitly empty generation, instead of unrelated ambient registry state. Default local discovery asks the existing ordered-profile owner first and carries its selected profile and store into the shared client. Native login is the fallback when that owner selects no profile; an explicitly selected native home retains its authority. Stdio proxies keep the destination server’s account and model catalog. Local login probing and the native user-home default apply only to owned local stdio runtimes; proxy arguments from configuration and environment use the existing proxy classifier. Login-status probing also retains the official Node launcher prefix and native configuration arguments while removing the app-server transport suffix. Runtime verification rules are unchanged. ## Compatibility The approved native-owner cutover requires explicit import or reselection for old CLI-backed pins outside the supported declared default-profile recovery. The credential documentation describes that recovery. Existing explicitly isolated homes and remote connections retain their selection. No configuration key, protocol version, or SQLite schema is added. Dependency contract personally inspected in Codex at `e5769939113536eb72752660bf7d1903f799d198`: [`codex-rs/app-server-protocol/src/protocol/v2/account.rs:524`](https://github.com/openai/codex/blob/e5769939113536eb72752660bf7d1903f799d198/codex-rs/app-server-protocol/src/protocol/v2/account.rs#L524) (`GetAccountParams` and `GetAccountResponse`), [`codex-rs/app-server/src/request_processors/account_processor.rs:826`](https://github.com/openai/codex/blob/e5769939113536eb72752660bf7d1903f799d198/codex-rs/app-server/src/request_processors/account_processor.rs#L826) (managed refresh and client-supplied token login), and [`codex-rs/cli/src/login.rs:443`](https://github.com/openai/codex/blob/e5769939113536eb72752660bf7d1903f799d198/codex-rs/cli/src/login.rs#L443) (native login status). `account/read` supplies account identity; an unknown remote subscription mode remains unknown. [`codex-rs/cli/src/main.rs:1344`](https://github.com/openai/codex/blob/e5769939113536eb72752660bf7d1903f799d198/codex-rs/cli/src/main.rs#L1344) confirms that stdio proxy forwards to the selected Unix socket. ## Validation - Native Testbox: 300 selected tests passed across import/auth bridge, native login/logout, per-model choices, captured generation ownership, status, Gateway metadata, and CLI cleanup. - The inherited-account and captured-registry regressions failed before their fixes and pass afterward. - The registered-harness correction passed 60 focused tests. The proxy correction failed six regression cases before the fix, then passed all 76 focused tests. - The profile-owned discovery correction passed 18 catalog cases and two selected shared-client cases after two expected regression failures. The launcher correction passed 31 native/transport cases after its expected regression failure. - A required merge-conflict rebase retained all 17 PR patches. The auth-pin and selected-model setup tests passed all 23 cases on the rebased head; retained runtime captures keep their original tested build identities. - Formatting and syntax lint passed for each correction. Type checks and full CI run on GitHub. - Telegram Test Server commands on the compiled candidate: native runtime selection succeeds; status agrees; a missing explicit profile rejects without changing selection; verified native logout plus public catalog refresh rejects the native runtime. No inference requests were made. - Enabled-discovery proof with the real Codex binary selects the profile-owned catalog while native login is absent or different, and the native catalog for explicit user-home selection. An official Node-launcher control with no host profiles reports native auth and an available native model. Synthetic host-token cases retain vendor auth-rejection diagnostics; this proof establishes catalog ownership, not vendor credential validity. - Public interactive migration was paused at confirmation while a same-ID inherited account was inserted. A different account reports conflict; a matching usable account is reused; neither writes a child-local shadow. The unrelated shared profile and native source remain intact. - Public CLI migration preserves the declared `openai:default` reference, configured model, and native source bytes. Repeating import with a separate backup output retains one profile and reports no credential write. - Synthetic native credentials prove local command and ownership behavior; they do not establish vendor authentication or inference. Full GitHub CI and the exact-head landing review are tracked by the required checks and landing receipt. Related: #136257. Builds on explicit import from #142933. Discord #143322 is a separate consumer lane. Co-authored-by: Ayaan Zaidi <hi@obviy.us>
75 lines
3.2 KiB
TypeScript
75 lines
3.2 KiB
TypeScript
import { fileURLToPath } from "node:url";
|
|
import { createTestPluginApi } from "openclaw/plugin-sdk/plugin-test-api";
|
|
import { createPluginRuntimeMock } from "openclaw/plugin-sdk/plugin-test-runtime";
|
|
import { describe, expect, it, onTestFinished } from "vitest";
|
|
import codexPlugin from "../../extensions/codex/index.js";
|
|
import {
|
|
dualRoutes,
|
|
routeResolverFactory,
|
|
} from "../../src/agents/model-auth-availability.test-support.js";
|
|
import { createModelCatalogDecisions } from "../../src/agents/model-catalog-decisions.js";
|
|
import type { OpenClawConfig } from "../../src/config/types.openclaw.js";
|
|
import { createPluginMetadataSnapshotFixture } from "../../src/plugins/plugin-metadata.test-support.js";
|
|
import { createEmptyPluginRegistry } from "../../src/plugins/registry-empty.js";
|
|
import { withOpenClawTestState } from "../../src/test-utils/openclaw-test-state.js";
|
|
|
|
describe("registered Codex runtime choices", () => {
|
|
it.each(["api_key", "oauth", "token"] as const)(
|
|
"keeps native %s authentication with its registered harness",
|
|
async (mode) => {
|
|
await withOpenClawTestState(
|
|
{ layout: "state-only", prefix: "native-choice-" },
|
|
async (state) => {
|
|
const config: OpenClawConfig = {
|
|
plugins: { entries: { codex: { enabled: true } } },
|
|
agents: {
|
|
defaults: { models: { "openai/gpt-5.5": { agentRuntime: { id: "codex" } } } },
|
|
},
|
|
};
|
|
const registry = createEmptyPluginRegistry();
|
|
codexPlugin.register(
|
|
createTestPluginApi({
|
|
id: "codex",
|
|
rootDir: fileURLToPath(new URL("../../extensions/codex/", import.meta.url)),
|
|
config,
|
|
runtime: createPluginRuntimeMock({ config: { current: () => config } }),
|
|
registerAgentHarness: (harness) => {
|
|
registry.agentHarnesses.push({ pluginId: "codex", source: "test", harness });
|
|
onTestFinished(() => harness.dispose?.());
|
|
},
|
|
}),
|
|
);
|
|
const entry = { provider: "openai", id: "gpt-5.5", name: "GPT-5.5" };
|
|
const params = {
|
|
cfg: config,
|
|
agentId: "main",
|
|
agentDir: state.agentDir(),
|
|
workspaceDir: state.workspaceDir,
|
|
snapshot: { entries: [entry], routeVariants: [entry] },
|
|
metadataSnapshot: createPluginMetadataSnapshotFixture({
|
|
plugins: [{ id: "codex", providers: ["codex"], syntheticAuthRefs: ["codex"] }],
|
|
}),
|
|
preparedAuthStore: { version: 1, profiles: {} },
|
|
preparedSyntheticAuthComplete: true,
|
|
pluginRegistry: registry,
|
|
isCurrent: () => true,
|
|
routeResolverFactory: routeResolverFactory(dualRoutes),
|
|
};
|
|
const owner = createModelCatalogDecisions({
|
|
...params,
|
|
preparedRuntimeAuthModes: { codex: { source: "native", mode } },
|
|
});
|
|
|
|
expect(await owner.runtimeChoices(entry)).toEqual(["codex"]);
|
|
expect(
|
|
await createModelCatalogDecisions({
|
|
...params,
|
|
preparedRuntimeAuthModes: {},
|
|
}).runtimeChoices(entry),
|
|
).toEqual([]);
|
|
},
|
|
);
|
|
},
|
|
);
|
|
});
|