Files
shockbot/utils/codexRefreshDetect.test.ts
T
David Blass d3b5340583 fix: audit batch — MCP timeouts, entryPost, vip_audit 404s, and 6 more (#824)
* fix: 9 unaddressed log-audit / run-audit findings

Co-authored-by: Cursor <cursoragent@cursor.com>

#815 entryPost stdlib-only imports; #823 MCP timeoutMs on checkout_pr/shell;
#816 FREE_FALLBACK → opencode/big-pickle; #822 chunk GraphQL nodes ≤100;
#817/#821 vip_audit 404 skip paths; #813 longer serializable retries;
#818 run-context handler-entered log; #805 audit severity template.

* fix: update footer test for big-pickle fallback slug

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: anneal round 1 — ghaCore getState casing, post-hook timeout

Match @actions/core STATE_ key semantics (no uppercasing), cap
postApiFetch at 30s, trim serializable retries to stay under GitHub's
10s webhook window, log Clerk failures in getUserTokenByGithubLogin.

Co-authored-by: Cursor <cursoragent@cursor.com>

* revert: drop run-context handler log (#818 deferred)

The #692 client-side fix is already on main; residual SyntaxError hits
are old action pins. Per-request log added noise without fixing anything.

Co-authored-by: Cursor <cursoragent@cursor.com>

* document per-issue Closes syntax for audit PRs

GitHub only auto-closes the first issue when numbers are comma-separated;
/audits and AGENTS.md now require Closes before each issue number.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: anneal round 2 — outreach privacy, alert resilience, vertex cleanup

Filter private repos from VIP authority output, harden console alert
lines against DB failures, drop spoofable changesets body check, and
unset GOOGLE_APPLICATION_CREDENTIALS after vertex credential cleanup.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: drop codexHome re-export of detectCodexRefresh

Import detectCodexRefresh directly from codexRefreshDetect.ts everywhere;
rename the unit test file to match. codexHome.ts stays install-only.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: drop deprecated minimax-m2.5-free; add paid minimax-m2.5

Remove the deprecated free MiniMax promo from the catalog, docs, and
tests. BYOK fallback and picker copy stay on opencode/big-pickle. Add
opencode/minimax-m2.5 and openrouter/minimax-m2.5 for Zen BYOK and
Router. Pin #816 regressions with freeFallbackCatalog and runErrorRenderer
unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: hidden minimax-m2.5-free fallback for stored slugs

Re-add opencode/minimax-m2.5-free as a hidden fallback alias to big-pickle
so repos with the legacy slug still resolve as free. Drop live Zen API
experiment tests in freeFallbackCatalog.test.ts.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 16:48:25 +00:00

86 lines
3.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { detectCodexRefresh } from "./codexRefreshDetect.ts";
// installCodexAuth touches the filesystem (mkdir + writeFile) — leaving it
// untested here per AGENTS.md guidance ("be highly dubious of any test that
// relies on mocks"). The conversion math is what we actually want to
// protect; the disk write is one writeFileSync call.
describe("detectCodexRefresh", () => {
const original = "rt_original_chain";
it("returns Codex-shape JSON when openai.refresh advanced", () => {
const authFileContent = JSON.stringify({
openai: {
type: "oauth",
refresh: "rt_new_chain",
access: "at_new",
expires: 9_999_999_999_999,
accountId: "acc_123",
},
});
const result = detectCodexRefresh({ authFileContent, originalRefresh: original });
expect(result).not.toBeNull();
const parsed = JSON.parse(result ?? "{}");
expect(parsed.auth_mode).toBe("chatgpt");
expect(parsed.tokens.refresh_token).toBe("rt_new_chain");
expect(parsed.tokens.access_token).toBe("at_new");
expect(parsed.tokens.account_id).toBe("acc_123");
expect(typeof parsed.last_refresh).toBe("string");
});
it("omits account_id when accountId is absent from OpenCode shape", () => {
const authFileContent = JSON.stringify({
openai: {
type: "oauth",
refresh: "rt_new",
access: "at_new",
expires: 0,
},
});
const result = detectCodexRefresh({ authFileContent, originalRefresh: original });
const parsed = JSON.parse(result ?? "{}");
expect("account_id" in parsed.tokens).toBe(false);
});
it("returns null when refresh token unchanged (no rotation happened)", () => {
const authFileContent = JSON.stringify({
openai: { type: "oauth", refresh: original, access: "at_same", expires: 0 },
});
expect(detectCodexRefresh({ authFileContent, originalRefresh: original })).toBeNull();
});
it("returns null when openai entry is missing", () => {
const authFileContent = JSON.stringify({
anthropic: { type: "oauth", refresh: "rt_other", access: "at_other", expires: 0 },
});
expect(detectCodexRefresh({ authFileContent, originalRefresh: original })).toBeNull();
});
it("returns null when openai is api-key type (no refresh chain)", () => {
const authFileContent = JSON.stringify({
openai: { type: "api", key: "sk-something" },
});
expect(detectCodexRefresh({ authFileContent, originalRefresh: original })).toBeNull();
});
it("returns null for malformed JSON", () => {
expect(
detectCodexRefresh({ authFileContent: "{not json", originalRefresh: original })
).toBeNull();
});
it("returns null for non-object content", () => {
expect(
detectCodexRefresh({ authFileContent: '"a string"', originalRefresh: original })
).toBeNull();
});
it("returns null when refresh field is missing", () => {
const authFileContent = JSON.stringify({
openai: { type: "oauth", access: "at_new", expires: 0 },
});
expect(detectCodexRefresh({ authFileContent, originalRefresh: original })).toBeNull();
});
});