mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-05-01 06:36:23 +08:00
fix(codex): keep auth read diagnostics off stdout (#66451)
* fix(codex): keep auth read diagnostics off stdout * docs(changelog): fix codex auth entry * fix(codex): sanitize auth read diagnostics * Update CHANGELOG.md
This commit is contained in:
@@ -32,6 +32,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Telegram/media downloads: let Telegram media fetches trust an operator-configured explicit proxy for target DNS resolution after hostname-policy checks, so proxy-backed installs stop failing `could not download media` on Bot API file downloads after the DNS-pinning regression. (#66245) Thanks @dawei41468 and @vincentkoc.
|
||||
- Browser: keep loopback CDP readiness checks reachable under strict SSRF defaults so OpenClaw can reconnect to locally started managed Chrome. (#66354) Thanks @hxy91819.
|
||||
- Agents/context engine: compact engine-owned sessions from the first tool-loop delta and preserve ingest fallback when `afterTurn` is absent, so long-running tool loops can stay bounded without dropping engine state. (#63555) Thanks @Bikkies.
|
||||
- OpenAI Codex/auth: keep malformed Codex CLI auth-file diagnostics on the debug logger instead of stdout so interactive command output stays clean while auth read failures remain traceable. (#66451) Thanks @SimbaKingjoe.
|
||||
- Discord/native commands: return the real status card for native `/status` interactions instead of falling through to the synthetic `✅ Done.` ack when the generic dispatcher produces no visible reply. (#54629) Thanks @tkozzer and @vincentkoc.
|
||||
- Hooks/Ollama: let LLM-backed session-memory slug generation honor an explicit `agents.defaults.timeoutSeconds` override instead of always aborting after 15 seconds, so slow local Ollama runs stop silently dropping back to generic filenames. (#66237) Thanks @dmak and @vincentkoc.
|
||||
- Media/transcription: remap `.aac` filenames to `.m4a` for OpenAI-compatible audio uploads so AAC voice notes stop failing MIME-sensitive transcription endpoints. (#66446) Thanks @ben-z.
|
||||
|
||||
@@ -22,9 +22,15 @@ const runtimeMocks = vi.hoisted(() => ({
|
||||
refreshOpenAICodexToken: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/runtime-env", () => ({
|
||||
ensureGlobalUndiciEnvProxyDispatcher: runtimeMocks.ensureGlobalUndiciEnvProxyDispatcher,
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/runtime-env", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/runtime-env")>(
|
||||
"openclaw/plugin-sdk/runtime-env",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
ensureGlobalUndiciEnvProxyDispatcher: runtimeMocks.ensureGlobalUndiciEnvProxyDispatcher,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("@mariozechner/pi-ai/oauth", async () => {
|
||||
const actual = await vi.importActual<typeof import("@mariozechner/pi-ai/oauth")>(
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
import fs from "node:fs";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const runtimeMocks = vi.hoisted(() => ({
|
||||
debug: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/runtime-env", () => ({
|
||||
createSubsystemLogger: () => ({
|
||||
debug: runtimeMocks.debug,
|
||||
}),
|
||||
}));
|
||||
|
||||
import {
|
||||
OPENAI_CODEX_DEFAULT_PROFILE_ID,
|
||||
readOpenAICodexCliOAuthProfile,
|
||||
@@ -12,6 +23,10 @@ function buildJwt(payload: Record<string, unknown>) {
|
||||
}
|
||||
|
||||
describe("readOpenAICodexCliOAuthProfile", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
@@ -80,4 +95,54 @@ describe("readOpenAICodexCliOAuthProfile", () => {
|
||||
|
||||
expect(parsed).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null without logging when the Codex CLI auth file is missing", () => {
|
||||
const error = Object.assign(new Error("missing"), {
|
||||
code: "ENOENT",
|
||||
});
|
||||
vi.spyOn(fs, "readFileSync").mockImplementation(() => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
const parsed = readOpenAICodexCliOAuthProfile({
|
||||
store: { version: 1, profiles: {} },
|
||||
});
|
||||
|
||||
expect(parsed).toBeNull();
|
||||
expect(runtimeMocks.debug).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("logs a sanitized code for invalid auth JSON", () => {
|
||||
vi.spyOn(fs, "readFileSync").mockReturnValue("{");
|
||||
|
||||
const parsed = readOpenAICodexCliOAuthProfile({
|
||||
store: { version: 1, profiles: {} },
|
||||
});
|
||||
|
||||
expect(parsed).toBeNull();
|
||||
expect(runtimeMocks.debug).toHaveBeenCalledWith(
|
||||
"Failed to read Codex CLI auth file (code=INVALID_JSON)",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not leak auth file paths in debug logs for filesystem failures", () => {
|
||||
const error = Object.assign(
|
||||
new Error("EACCES: permission denied, open '/Users/alice/.codex/auth.json'"),
|
||||
{
|
||||
code: "EACCES",
|
||||
},
|
||||
);
|
||||
vi.spyOn(fs, "readFileSync").mockImplementation(() => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
const parsed = readOpenAICodexCliOAuthProfile({
|
||||
store: { version: 1, profiles: {} },
|
||||
});
|
||||
|
||||
expect(parsed).toBeNull();
|
||||
expect(runtimeMocks.debug).toHaveBeenCalledWith(
|
||||
"Failed to read Codex CLI auth file (code=EACCES)",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { AuthProfileStore, OAuthCredential } from "openclaw/plugin-sdk/provider-auth";
|
||||
import { resolveRequiredHomeDir } from "openclaw/plugin-sdk/provider-auth";
|
||||
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
||||
import {
|
||||
resolveCodexAccessTokenExpiry,
|
||||
resolveCodexAuthIdentity,
|
||||
@@ -9,6 +10,7 @@ import {
|
||||
import { trimNonEmptyString } from "./openai-codex-shared.js";
|
||||
|
||||
const PROVIDER_ID = "openai-codex";
|
||||
const log = createSubsystemLogger("openai/codex-cli-auth");
|
||||
|
||||
export const CODEX_CLI_PROFILE_ID = `${PROVIDER_ID}:codex-cli`;
|
||||
export const OPENAI_CODEX_DEFAULT_PROFILE_ID = `${PROVIDER_ID}:default`;
|
||||
@@ -42,7 +44,19 @@ function readCodexCliAuthFile(env: NodeJS.ProcessEnv): CodexCliAuthFile | null {
|
||||
const raw = fs.readFileSync(authPath, "utf8");
|
||||
const parsed = JSON.parse(raw);
|
||||
return parsed && typeof parsed === "object" ? (parsed as CodexCliAuthFile) : null;
|
||||
} catch {
|
||||
} catch (error) {
|
||||
const code =
|
||||
error instanceof SyntaxError
|
||||
? "INVALID_JSON"
|
||||
: error instanceof Error && "code" in error
|
||||
? (error as NodeJS.ErrnoException).code
|
||||
: undefined;
|
||||
if (code === "ENOENT") {
|
||||
return null;
|
||||
}
|
||||
log.debug(
|
||||
`Failed to read Codex CLI auth file (code=${typeof code === "string" ? code : "UNKNOWN"})`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user