Gab a8b73fd754 refactor: apply minimal tfcode branding
- Rename packages/opencode → packages/tfcode (directory only)
- Rename bin/opencode → bin/tfcode (CLI binary)
- Rename .opencode → .tfcode (config directory)
- Update package.json name and bin field
- Update config directory path references (.tfcode)
- Keep internal code references as 'opencode' for easy upstream sync
- Keep @opencode-ai/* workspace package names

This minimal branding approach allows clean merges from upstream
opencode repository while providing tfcode branding for users.
2026-03-24 13:20:14 +11:00

124 lines
4.0 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import {
parseJwtClaims,
extractAccountIdFromClaims,
extractAccountId,
type IdTokenClaims,
} from "../../src/plugin/codex"
function createTestJwt(payload: object): string {
const header = Buffer.from(JSON.stringify({ alg: "none" })).toString("base64url")
const body = Buffer.from(JSON.stringify(payload)).toString("base64url")
return `${header}.${body}.sig`
}
describe("plugin.codex", () => {
describe("parseJwtClaims", () => {
test("parses valid JWT with claims", () => {
const payload = { email: "test@example.com", chatgpt_account_id: "acc-123" }
const jwt = createTestJwt(payload)
const claims = parseJwtClaims(jwt)
expect(claims).toEqual(payload)
})
test("returns undefined for JWT with less than 3 parts", () => {
expect(parseJwtClaims("invalid")).toBeUndefined()
expect(parseJwtClaims("only.two")).toBeUndefined()
})
test("returns undefined for invalid base64", () => {
expect(parseJwtClaims("a.!!!invalid!!!.b")).toBeUndefined()
})
test("returns undefined for invalid JSON payload", () => {
const header = Buffer.from("{}").toString("base64url")
const invalidJson = Buffer.from("not json").toString("base64url")
expect(parseJwtClaims(`${header}.${invalidJson}.sig`)).toBeUndefined()
})
})
describe("extractAccountIdFromClaims", () => {
test("extracts chatgpt_account_id from root", () => {
const claims: IdTokenClaims = { chatgpt_account_id: "acc-root" }
expect(extractAccountIdFromClaims(claims)).toBe("acc-root")
})
test("extracts chatgpt_account_id from nested https://api.openai.com/auth", () => {
const claims: IdTokenClaims = {
"https://api.openai.com/auth": { chatgpt_account_id: "acc-nested" },
}
expect(extractAccountIdFromClaims(claims)).toBe("acc-nested")
})
test("prefers root over nested", () => {
const claims: IdTokenClaims = {
chatgpt_account_id: "acc-root",
"https://api.openai.com/auth": { chatgpt_account_id: "acc-nested" },
}
expect(extractAccountIdFromClaims(claims)).toBe("acc-root")
})
test("extracts from organizations array as fallback", () => {
const claims: IdTokenClaims = {
organizations: [{ id: "org-123" }, { id: "org-456" }],
}
expect(extractAccountIdFromClaims(claims)).toBe("org-123")
})
test("returns undefined when no accountId found", () => {
const claims: IdTokenClaims = { email: "test@example.com" }
expect(extractAccountIdFromClaims(claims)).toBeUndefined()
})
})
describe("extractAccountId", () => {
test("extracts from id_token first", () => {
const idToken = createTestJwt({ chatgpt_account_id: "from-id-token" })
const accessToken = createTestJwt({ chatgpt_account_id: "from-access-token" })
expect(
extractAccountId({
id_token: idToken,
access_token: accessToken,
refresh_token: "rt",
}),
).toBe("from-id-token")
})
test("falls back to access_token when id_token has no accountId", () => {
const idToken = createTestJwt({ email: "test@example.com" })
const accessToken = createTestJwt({
"https://api.openai.com/auth": { chatgpt_account_id: "from-access" },
})
expect(
extractAccountId({
id_token: idToken,
access_token: accessToken,
refresh_token: "rt",
}),
).toBe("from-access")
})
test("returns undefined when no tokens have accountId", () => {
const token = createTestJwt({ email: "test@example.com" })
expect(
extractAccountId({
id_token: token,
access_token: token,
refresh_token: "rt",
}),
).toBeUndefined()
})
test("handles missing id_token", () => {
const accessToken = createTestJwt({ chatgpt_account_id: "acc-123" })
expect(
extractAccountId({
id_token: "",
access_token: accessToken,
refresh_token: "rt",
}),
).toBe("acc-123")
})
})
})