| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- import { describe, expect, test } from "bun:test"
- import { OAUTH_DUMMY_KEY } from "../../src/auth"
- import { oauthScope, SnowflakeCortexAuthPlugin } from "../../src/plugin/snowflake-cortex"
- function makeInput() {
- let auth: any = {
- type: "oauth",
- access: "access-old",
- refresh: "refresh-old",
- expires: Date.now() + 3600_000,
- accountId: "myorg-myaccount",
- }
- const setCalls: Array<Record<string, unknown>> = []
- return {
- getAuth: async () => auth,
- setAuth: (next: any) => {
- auth = next
- },
- input: {
- client: {
- auth: {
- set: async (request: any) => {
- setCalls.push(request)
- auth = request.body
- },
- },
- },
- } as any,
- setCalls,
- }
- }
- describe("plugin.snowflake-cortex", () => {
- test("oauthScope uses Snowflake-compatible scope values", () => {
- expect(oauthScope(undefined)).toBe("refresh_token")
- expect(oauthScope("PUBLIC")).toBe("refresh_token session:role:PUBLIC")
- expect(oauthScope("AUTH SNOWFLAKE")).toBe("refresh_token session:role-encoded:AUTH%20SNOWFLAKE")
- })
- test("loader returns empty options when auth is not oauth", async () => {
- const hooks = await SnowflakeCortexAuthPlugin({} as any)
- const options = await hooks.auth!.loader!(async () => ({ type: "api", key: "token" }) as any, {} as any)
- expect(options).toEqual({})
- })
- test("loader injects bearer header and preserves custom headers", async () => {
- const { input, getAuth, setAuth } = makeInput()
- setAuth({
- type: "oauth",
- access: "access-live",
- refresh: "refresh-live",
- expires: Date.now() + 60 * 60 * 1000,
- accountId: "myorg-myaccount",
- })
- const hooks = await SnowflakeCortexAuthPlugin(input)
- const options = await hooks.auth!.loader!(getAuth as any, {} as any)
- expect(options.apiKey).toBe(OAUTH_DUMMY_KEY)
- const originalFetch = globalThis.fetch
- const captured: Headers[] = []
- globalThis.fetch = (async (_request, init) => {
- captured.push(new Headers(init?.headers))
- return new Response("{}", { status: 200, headers: { "content-type": "application/json" } })
- }) as typeof fetch
- try {
- await options.fetch("https://example.test/v1/chat", {
- headers: { Authorization: `Bearer ${OAUTH_DUMMY_KEY}`, "x-keep": "yes" },
- })
- } finally {
- globalThis.fetch = originalFetch
- }
- expect(captured).toHaveLength(1)
- expect(captured[0].get("authorization")).toBe("Bearer access-live")
- expect(captured[0].get("x-keep")).toBe("yes")
- expect(captured[0].get("user-agent")).toMatch(/^opencode\//)
- })
- test("loader refreshes expired token with single-flight and persists refreshed oauth", async () => {
- const { input, getAuth, setCalls } = makeInput()
- let refreshCalls = 0
- const apiAuthHeaders: string[] = []
- // Must mock fetch before calling loader because startup refresh triggers for expires: 0
- const originalFetch = globalThis.fetch
- globalThis.fetch = (async (request, init) => {
- const url =
- typeof request === "string" ? request : request instanceof URL ? request.toString() : String(request.url)
- if (url.includes("/oauth/token-request")) {
- refreshCalls += 1
- const body = new URLSearchParams(String(init?.body ?? ""))
- expect(body.get("grant_type")).toBe("refresh_token")
- expect(body.get("refresh_token")).toBe("refresh-old")
- expect(new Headers(init?.headers).get("authorization")).toMatch(/^Basic /)
- await new Promise((resolve) => setTimeout(resolve, 20))
- return Response.json({ access_token: "access-new", refresh_token: "refresh-new", expires_in: 3600 })
- }
- apiAuthHeaders.push(new Headers(init?.headers).get("authorization") || "")
- return new Response("{}", { status: 200, headers: { "content-type": "application/json" } })
- }) as typeof fetch
- try {
- const hooks = await SnowflakeCortexAuthPlugin(input)
- const options = await hooks.auth!.loader!(
- async () =>
- ({
- type: "oauth",
- access: "access-expired",
- refresh: "refresh-old",
- expires: 0,
- accountId: "myorg-myaccount",
- }) as any,
- {} as any,
- )
- await Promise.all([
- options.fetch("https://example.test/v1/chat", { headers: {} }),
- options.fetch("https://example.test/v1/chat", { headers: {} }),
- ])
- } finally {
- globalThis.fetch = originalFetch
- }
- expect(refreshCalls).toBe(1)
- expect(apiAuthHeaders).toEqual(["Bearer access-new", "Bearer access-new"])
- expect(setCalls).toHaveLength(1)
- expect((setCalls[0] as any).body).toMatchObject({
- type: "oauth",
- access: "access-new",
- refresh: "refresh-new",
- accountId: "myorg-myaccount",
- })
- })
- test("loader retries once after 401 by refreshing token", async () => {
- const { input, getAuth, setCalls } = makeInput()
- const hooks = await SnowflakeCortexAuthPlugin(input)
- const options = await hooks.auth!.loader!(
- async () =>
- ({
- type: "oauth",
- access: "access-stale",
- refresh: "refresh-old",
- expires: Date.now() + 60 * 60 * 1000,
- accountId: "myorg-myaccount",
- }) as any,
- {} as any,
- )
- let apiCalls = 0
- const seenAuth: string[] = []
- const originalFetch = globalThis.fetch
- globalThis.fetch = (async (request, init) => {
- const url =
- typeof request === "string" ? request : request instanceof URL ? request.toString() : String(request.url)
- if (url.includes("/oauth/token-request")) {
- return Response.json({ access_token: "access-fresh", refresh_token: "refresh-fresh", expires_in: 3600 })
- }
- apiCalls += 1
- seenAuth.push(new Headers(init?.headers).get("authorization") || "")
- if (apiCalls === 1) return new Response("unauthorized", { status: 401 })
- return new Response("{}", { status: 200, headers: { "content-type": "application/json" } })
- }) as typeof fetch
- try {
- const response = await options.fetch("https://example.test/v1/chat", { headers: {} })
- expect(response.status).toBe(200)
- } finally {
- globalThis.fetch = originalFetch
- }
- expect(apiCalls).toBe(2)
- expect(seenAuth).toEqual(["Bearer access-stale", "Bearer access-fresh"])
- expect(setCalls).toHaveLength(1)
- expect((setCalls[0] as any).body).toMatchObject({
- type: "oauth",
- access: "access-fresh",
- refresh: "refresh-fresh",
- accountId: "myorg-myaccount",
- })
- })
- test("loader converts max_tokens to max_completion_tokens in request body", async () => {
- const { input, getAuth } = makeInput()
- const hooks = await SnowflakeCortexAuthPlugin(input)
- const options = await hooks.auth!.loader!(getAuth as any, {} as any)
- let sentBody: string | undefined
- const originalFetch = globalThis.fetch
- globalThis.fetch = (async (request, init) => {
- sentBody = typeof init?.body === "string" ? init.body : undefined
- return new Response("{}", { status: 200, headers: { "content-type": "application/json" } })
- }) as typeof fetch
- try {
- await options.fetch("https://example.test/v1/chat", {
- method: "POST",
- body: JSON.stringify({ model: "claude-sonnet-4-5", max_tokens: 4096, messages: [] }),
- })
- } finally {
- globalThis.fetch = originalFetch
- }
- expect(sentBody).toBeDefined()
- const parsed = JSON.parse(sentBody!)
- expect(parsed.max_completion_tokens).toBe(4096)
- expect(parsed.max_tokens).toBeUndefined()
- expect(parsed.model).toBe("claude-sonnet-4-5")
- })
- test("loader maps 400 'conversation complete' to 200 stop", async () => {
- const { input, getAuth } = makeInput()
- const hooks = await SnowflakeCortexAuthPlugin(input)
- const options = await hooks.auth!.loader!(getAuth as any, {} as any)
- const originalFetch = globalThis.fetch
- globalThis.fetch = (async () => {
- return new Response(JSON.stringify({ message: "Conversation complete" }), {
- status: 400,
- headers: { "content-type": "application/json" },
- })
- }) as unknown as typeof fetch
- try {
- const response = await options.fetch("https://example.test/v1/chat", {
- method: "POST",
- body: JSON.stringify({ model: "test", messages: [] }),
- })
- expect(response.status).toBe(200)
- const body = await response.json()
- expect(body.choices[0].finish_reason).toBe("stop")
- } finally {
- globalThis.fetch = originalFetch
- }
- })
- test("loader fixes empty role in SSE stream", async () => {
- const { input, getAuth } = makeInput()
- const hooks = await SnowflakeCortexAuthPlugin(input)
- const options = await hooks.auth!.loader!(getAuth as any, {} as any)
- const originalFetch = globalThis.fetch
- const sseChunk = `data: {"choices":[{"delta":{"role":"","content":"hello"}}]}\n\n`
- globalThis.fetch = (async () => {
- const stream = new ReadableStream({
- start(ctrl) {
- ctrl.enqueue(new TextEncoder().encode(sseChunk))
- ctrl.close()
- },
- })
- return new Response(stream, {
- status: 200,
- headers: { "content-type": "text/event-stream" },
- })
- }) as unknown as typeof fetch
- try {
- const response = await options.fetch("https://example.test/v1/chat", {
- method: "POST",
- body: JSON.stringify({ model: "test", messages: [], stream: true }),
- })
- expect(response.status).toBe(200)
- const reader = response.body!.getReader()
- const { value } = await reader.read()
- const text = new TextDecoder().decode(value)
- expect(text).not.toContain('"role":""')
- expect(text).toContain('"role":"assistant"')
- } finally {
- globalThis.fetch = originalFetch
- }
- })
- })
|