Files
OmniRoute/tests/unit/grok-cli-proactive-refresh-7610.test.ts
Diego Rodrigues de Sa e Souza 313cbefda4 fix(sse): proactively refresh Grok Build OAuth token before dispatch (#7610) (#7715)
GrokCliExecutor.execute() dispatches via raw https.request (nativePost)
instead of the shared fetch path, so it never inherited (nor delegated to)
BaseExecutor.execute()'s proactive-refresh gate the way codex.ts does via
super.execute(). The only refresh that ever fired was the reactive one on a
401/403 from upstream — the rotating xAI refresh_token idled until real
expiry, matching the "unusable within minutes, must delete/re-add" report.

Wires in the same needsRefresh()/refreshCredentials() gate, using
runWithOnPersist + isUnrecoverableRefreshError to keep the [refresh +
persist] atomic under the same per-connection mutex Codex/Claude rely on
for rotating refresh tokens (base.ts:592-644).

Also fixes the smaller, separate bug #2 from the same report: grok-cli was
absent from OAUTH_TEST_CONFIG in the connection-test route, so "Test
Connection" always reported "Provider test not supported" regardless of
token health. Added a checkExpiry entry (same pattern as qwen/cline/
kilocode — Grok Build's proxy doesn't expose a lightweight probe endpoint
with the cli-specific headers this shared prober sends). Extracted
OAUTH_TEST_CONFIG into its own module (oauthTestConfig.ts) so the new entry
doesn't grow the frozen route.ts past its file-size cap.

Bug #3 (no browser/device-code login for Grok Build) and bug #4 (quota
display) from the same issue are feature gaps, not regressions — left as
follow-ups per the triage plan-file.

Refs #7610
2026-07-19 02:34:49 -03:00

65 lines
2.3 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { GrokCliExecutor } from "../../open-sse/executors/grok-cli.ts";
import type { ExecuteInput, ExecutorLog, ProviderCredentials } from "../../open-sse/executors/base.ts";
type TestableGrokCliExecutor = {
execute: (input: ExecuteInput) => Promise<{ response: Response }>;
refreshCredentials: (
credentials: ProviderCredentials,
log?: ExecutorLog | null
) => Promise<Partial<ProviderCredentials> | null>;
nativePost: (
url: string,
headers: Record<string, string>,
bodyStr: string,
signal?: AbortSignal | null
) => Promise<Response>;
};
test("GrokCliExecutor.execute() proactively refreshes an expired access token (#7610)", async () => {
const executor = new GrokCliExecutor() as unknown as TestableGrokCliExecutor;
// Stub the real network call (nativeHttpsPost → auth.x.ai) so the test never
// touches the network — only the wiring (does execute() call
// refreshCredentials() at all, and does the refreshed token reach the
// outgoing Authorization header) is under test here.
let refreshCalled = false;
executor.refreshCredentials = async () => {
refreshCalled = true;
return {
accessToken: "FRESH_ACCESS_TOKEN",
refreshToken: "rotated-refresh-token",
expiresAt: new Date(Date.now() + 3600_000).toISOString(),
};
};
let capturedHeaders: Record<string, string> | null = null;
executor.nativePost = async (_url, headers) => {
capturedHeaders = headers;
return new Response(JSON.stringify({ ok: true }), { status: 200 });
};
const expiredAt = new Date(Date.now() - 60_000).toISOString();
const credentials: ProviderCredentials = {
accessToken: "STALE_ACCESS_TOKEN",
refreshToken: "valid-refresh-token",
expiresAt: expiredAt,
};
await executor.execute({
model: "grok-composer-2.5-fast",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials,
} as ExecuteInput);
assert.equal(
refreshCalled,
true,
"expected GrokCliExecutor.execute() to proactively call refreshCredentials()"
);
assert.notEqual(capturedHeaders?.["Authorization"], "Bearer STALE_ACCESS_TOKEN");
assert.equal(capturedHeaders?.["Authorization"], "Bearer FRESH_ACCESS_TOKEN");
});