import Foundationimport Testing@testable import CodexBarCore @Suite(.serialized)@MainActorstruct CodexWebDashboardStrategyAuthorityTests { @Test func `web dashboard attach converts snapshot with authority attachment email`() throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome( email: "owner@example.com", accountId: "acct-owner") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-owner"), normalizedEmail: "owner@example.com"), ]) let result = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: self.makeDashboard(email: "owner@example.com"), context: context, routingTargetEmail: "route@example.com") #expect(result.usage.accountEmail(for: .codex) == "owner@example.com") #expect(result.credits?.remaining == 42) } @Test func `web dashboard attach preserves credits when usage limits are absent`() throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome( email: "owner@example.com", accountId: "acct-owner") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-owner"), normalizedEmail: "owner@example.com"), ]) let dashboard = self.makeDashboardWithoutUsageLimits(email: "owner@example.com") let result = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: dashboard, context: context, routingTargetEmail: "route@example.com") #expect(result.usage.primary == nil) #expect(result.usage.secondary == nil) #expect(result.usage.updatedAt == dashboard.updatedAt) #expect(result.usage.identity?.accountEmail == "owner@example.com") #expect(result.usage.identity?.loginMethod == "pro") #expect(result.credits?.remaining == 42) #expect(result.dashboard == dashboard) } @Test func `web dashboard display only throws typed policy error`() throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome(email: "shared@example.com") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-alpha"), normalizedEmail: "shared@example.com"), CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-beta"), normalizedEmail: "shared@example.com"), ]) let dashboard = self.makeDashboard(email: "shared@example.com") let expectedDecision = CodexDashboardAuthority.evaluate( CodexCLIDashboardAuthorityContext.makeLiveWebInput( dashboard: dashboard, context: context, routingTargetEmail: "route@example.com")) do { _ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: dashboard, context: context, routingTargetEmail: "route@example.com") Issue.record("Expected CodexDashboardPolicyError.displayOnly") } catch let error as CodexDashboardPolicyError { #expect(error == .displayOnly(expectedDecision)) } catch { Issue.record("Expected CodexDashboardPolicyError.displayOnly, got \(error)") } } @Test func `web dashboard fail closed throws policy rejection`() throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome( email: "owner@example.com", accountId: "acct-owner") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-other"), normalizedEmail: "owner@example.com"), ]) let dashboard = self.makeDashboard(email: "owner@example.com") let expectedDecision = CodexDashboardAuthority.evaluate( CodexCLIDashboardAuthorityContext.makeLiveWebInput( dashboard: dashboard, context: context, routingTargetEmail: "route@example.com")) do { _ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: dashboard, context: context, routingTargetEmail: "route@example.com") Issue.record("Expected OpenAIWebCodexError.policyRejected") } catch let error as OpenAIWebCodexError { #expect(error == .policyRejected(expectedDecision)) } catch { Issue.record("Expected OpenAIWebCodexError.policyRejected, got \(error)") } } @Test func `web dashboard wrong email throws policy rejection`() throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome( email: "owner@example.com", accountId: "acct-owner") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-owner"), normalizedEmail: "owner@example.com"), ]) let dashboard = self.makeDashboard(email: "other@example.com") let expectedDecision = CodexDashboardAuthority.evaluate( CodexCLIDashboardAuthorityContext.makeLiveWebInput( dashboard: dashboard, context: context, routingTargetEmail: "owner@example.com")) do { _ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: dashboard, context: context, routingTargetEmail: "owner@example.com") Issue.record("Expected OpenAIWebCodexError.policyRejected") } catch let error as OpenAIWebCodexError { #expect(error == .policyRejected(expectedDecision)) if case let .policyRejected(decision) = error { #expect(decision.reason == .wrongEmail(expected: "owner@example.com", actual: "other@example.com")) } } catch { Issue.record("Expected OpenAIWebCodexError.policyRejected, got \(error)") } } @Test func `web dashboard provider account without scoped auth email fail closes on dashboard collision`() throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome(email: nil, accountId: "acct-owner") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-alpha"), normalizedEmail: "shared@example.com"), CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-beta"), normalizedEmail: "shared@example.com"), ]) let dashboard = self.makeDashboard(email: "shared@example.com") let expectedDecision = CodexDashboardAuthority.evaluate( CodexCLIDashboardAuthorityContext.makeLiveWebInput( dashboard: dashboard, context: context, routingTargetEmail: "shared@example.com")) do { _ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: dashboard, context: context, routingTargetEmail: "shared@example.com") Issue.record("Expected OpenAIWebCodexError.policyRejected") } catch let error as OpenAIWebCodexError { #expect(error == .policyRejected(expectedDecision)) if case let .policyRejected(decision) = error { #expect(decision.reason == .providerAccountMissingScopedEmail) } } catch { Issue.record("Expected OpenAIWebCodexError.policyRejected, got \(error)") } } @Test func `web dashboard attach saves cache with attached email not routing fallback`() throws { OpenAIDashboardCacheStore.clear() defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome( email: "owner@example.com", accountId: "acct-owner") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-owner"), normalizedEmail: "owner@example.com"), ]) _ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: self.makeDashboard(email: "owner@example.com"), context: context, routingTargetEmail: "route@example.com") let cache = try #require(OpenAIDashboardCacheStore.load()) #expect(cache.accountEmail == "owner@example.com") #expect(cache.accountEmail != "route@example.com") } @Test func `web dashboard fail closed clears stale cache`() throws { OpenAIDashboardCacheStore.save(OpenAIDashboardCache( accountEmail: "stale@example.com", snapshot: self.makeDashboard(email: "stale@example.com"))) defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome( email: "owner@example.com", accountId: "acct-owner") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-other"), normalizedEmail: "owner@example.com"), ]) do { _ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: self.makeDashboard(email: "owner@example.com"), context: context, routingTargetEmail: "route@example.com") Issue.record("Expected OpenAIWebCodexError.policyRejected") } catch is OpenAIWebCodexError {} #expect(OpenAIDashboardCacheStore.load() == nil) } @Test func `web dashboard display only clears stale cache`() throws { OpenAIDashboardCacheStore.save(OpenAIDashboardCache( accountEmail: "stale@example.com", snapshot: self.makeDashboard(email: "stale@example.com"))) defer { OpenAIDashboardCacheStore.clear() } let authHome = try self.makeAuthHome(email: "shared@example.com") defer { try? FileManager.default.removeItem(at: authHome) } let context = self.makeContext( authHome: authHome, knownOwners: [ CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-alpha"), normalizedEmail: "shared@example.com"), CodexDashboardKnownOwnerCandidate( identity: .providerAccount(id: "acct-beta"), normalizedEmail: "shared@example.com"), ]) do { _ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting( dashboard: self.makeDashboard(email: "shared@example.com"), context: context, routingTargetEmail: "route@example.com") Issue.record("Expected CodexDashboardPolicyError.displayOnly") } catch is CodexDashboardPolicyError {} #expect(OpenAIDashboardCacheStore.load() == nil) } private func makeContext( authHome: URL? = nil, knownOwners: [CodexDashboardKnownOwnerCandidate]) -> ProviderFetchContext { let env = authHome.map { ["CODEX_HOME": $0.path] } ?? [:] let browserDetection = BrowserDetection(cacheTTL: 0) return ProviderFetchContext( runtime: .cli, sourceMode: .auto, includeCredits: true, webTimeout: 60, webDebugDumpHTML: false, verbose: false, env: env, settings: ProviderSettingsSnapshot.make( codex: .init( usageDataSource: .auto, cookieSource: .auto, manualCookieHeader: nil, dashboardAuthorityKnownOwners: knownOwners)), fetcher: UsageFetcher(environment: env), claudeFetcher: ClaudeUsageFetcher(browserDetection: browserDetection), browserDetection: browserDetection) } private func makeDashboard(email: String) -> OpenAIDashboardSnapshot { OpenAIDashboardSnapshot( signedInEmail: email, codeReviewRemainingPercent: 75, codeReviewLimit: RateWindow( usedPercent: 25, windowMinutes: 60, resetsAt: Date(timeIntervalSince1970: 3600), resetDescription: nil), creditEvents: [ CreditEvent( date: Date(timeIntervalSince1970: 1000), service: "codex", creditsUsed: 3), ], dailyBreakdown: [], usageBreakdown: [], creditsPurchaseURL: nil, primaryLimit: RateWindow( usedPercent: 10, windowMinutes: 300, resetsAt: Date(timeIntervalSince1970: 7200), resetDescription: nil), secondaryLimit: nil, creditsRemaining: 42, accountPlan: "pro", updatedAt: Date(timeIntervalSince1970: 2000)) } private func makeDashboardWithoutUsageLimits(email: String) -> OpenAIDashboardSnapshot { OpenAIDashboardSnapshot( signedInEmail: email, codeReviewRemainingPercent: nil, creditEvents: [], dailyBreakdown: [], usageBreakdown: [], creditsPurchaseURL: nil, primaryLimit: nil, secondaryLimit: nil, creditsRemaining: 42, accountPlan: "pro", updatedAt: Date(timeIntervalSince1970: 2000)) } private func makeAuthHome(email: String?, accountId: String? = nil) throws -> URL { let homeURL = FileManager.default.temporaryDirectory.appendingPathComponent( UUID().uuidString, isDirectory: true) try self.writeCodexAuthFile(homeURL: homeURL, email: email, accountId: accountId) return homeURL } private func writeCodexAuthFile( homeURL: URL, email: String?, accountId: String?) throws { try FileManager.default.createDirectory(at: homeURL, withIntermediateDirectories: true) var tokens: [String: Any] = [ "accessToken": "access-token", "refreshToken": "refresh-token", "idToken": Self.fakeJWT(email: email, accountId: accountId), ] if let accountId { tokens["accountId"] = accountId } let auth = ["tokens": tokens] let data = try JSONSerialization.data(withJSONObject: auth) try data.write(to: homeURL.appendingPathComponent("auth.json")) } private static func fakeJWT(email: String?, accountId: String?) -> String { let header = (try? JSONSerialization.data(withJSONObject: ["alg": "none"])) ?? Data() var authClaims: [String: Any] = [ "chatgpt_plan_type": "pro", ] if let accountId { authClaims["chatgpt_account_id"] = accountId } var claims: [String: Any] = [ "chatgpt_plan_type": "pro", "https://api.openai.com/auth": authClaims, ] if let email { claims["email"] = email } let payload = (try? JSONSerialization.data(withJSONObject: claims)) ?? Data() func base64URL(_ data: Data) -> String { data.base64EncodedString() .replacingOccurrences(of: "=", with: "") .replacingOccurrences(of: "+", with: "-") .replacingOccurrences(of: "/", with: "_") } return "\(base64URL(header)).\(base64URL(payload))." }}
import Foundation
import Testing
@testable import CodexBarCore
@Suite(.serialized)
@MainActor
struct CodexWebDashboardStrategyAuthorityTests {
@Test
func `web dashboard attach converts snapshot with authority attachment email`() throws {
OpenAIDashboardCacheStore.clear()
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(
email: "owner@example.com",
accountId: "acct-owner")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-owner"),
normalizedEmail: "owner@example.com"),
])
let result = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: self.makeDashboard(email: "owner@example.com"),
context: context,
routingTargetEmail: "route@example.com")
#expect(result.usage.accountEmail(for: .codex) == "owner@example.com")
#expect(result.credits?.remaining == 42)
}
@Test
func `web dashboard attach preserves credits when usage limits are absent`() throws {
OpenAIDashboardCacheStore.clear()
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(
email: "owner@example.com",
accountId: "acct-owner")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-owner"),
normalizedEmail: "owner@example.com"),
])
let dashboard = self.makeDashboardWithoutUsageLimits(email: "owner@example.com")
let result = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: dashboard,
context: context,
routingTargetEmail: "route@example.com")
#expect(result.usage.primary == nil)
#expect(result.usage.secondary == nil)
#expect(result.usage.updatedAt == dashboard.updatedAt)
#expect(result.usage.identity?.accountEmail == "owner@example.com")
#expect(result.usage.identity?.loginMethod == "pro")
#expect(result.credits?.remaining == 42)
#expect(result.dashboard == dashboard)
}
@Test
func `web dashboard display only throws typed policy error`() throws {
OpenAIDashboardCacheStore.clear()
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(email: "shared@example.com")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-alpha"),
normalizedEmail: "shared@example.com"),
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-beta"),
normalizedEmail: "shared@example.com"),
])
let dashboard = self.makeDashboard(email: "shared@example.com")
let expectedDecision = CodexDashboardAuthority.evaluate(
CodexCLIDashboardAuthorityContext.makeLiveWebInput(
dashboard: dashboard,
context: context,
routingTargetEmail: "route@example.com"))
do {
_ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: dashboard,
context: context,
routingTargetEmail: "route@example.com")
Issue.record("Expected CodexDashboardPolicyError.displayOnly")
} catch let error as CodexDashboardPolicyError {
#expect(error == .displayOnly(expectedDecision))
} catch {
Issue.record("Expected CodexDashboardPolicyError.displayOnly, got \(error)")
}
}
@Test
func `web dashboard fail closed throws policy rejection`() throws {
OpenAIDashboardCacheStore.clear()
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(
email: "owner@example.com",
accountId: "acct-owner")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-other"),
normalizedEmail: "owner@example.com"),
])
let dashboard = self.makeDashboard(email: "owner@example.com")
let expectedDecision = CodexDashboardAuthority.evaluate(
CodexCLIDashboardAuthorityContext.makeLiveWebInput(
dashboard: dashboard,
context: context,
routingTargetEmail: "route@example.com"))
do {
_ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: dashboard,
context: context,
routingTargetEmail: "route@example.com")
Issue.record("Expected OpenAIWebCodexError.policyRejected")
} catch let error as OpenAIWebCodexError {
#expect(error == .policyRejected(expectedDecision))
} catch {
Issue.record("Expected OpenAIWebCodexError.policyRejected, got \(error)")
}
}
@Test
func `web dashboard wrong email throws policy rejection`() throws {
OpenAIDashboardCacheStore.clear()
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(
email: "owner@example.com",
accountId: "acct-owner")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-owner"),
normalizedEmail: "owner@example.com"),
])
let dashboard = self.makeDashboard(email: "other@example.com")
let expectedDecision = CodexDashboardAuthority.evaluate(
CodexCLIDashboardAuthorityContext.makeLiveWebInput(
dashboard: dashboard,
context: context,
routingTargetEmail: "owner@example.com"))
do {
_ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: dashboard,
context: context,
routingTargetEmail: "owner@example.com")
Issue.record("Expected OpenAIWebCodexError.policyRejected")
} catch let error as OpenAIWebCodexError {
#expect(error == .policyRejected(expectedDecision))
if case let .policyRejected(decision) = error {
#expect(decision.reason == .wrongEmail(expected: "owner@example.com", actual: "other@example.com"))
}
} catch {
Issue.record("Expected OpenAIWebCodexError.policyRejected, got \(error)")
}
}
@Test
func `web dashboard provider account without scoped auth email fail closes on dashboard collision`() throws {
OpenAIDashboardCacheStore.clear()
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(email: nil, accountId: "acct-owner")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-alpha"),
normalizedEmail: "shared@example.com"),
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-beta"),
normalizedEmail: "shared@example.com"),
])
let dashboard = self.makeDashboard(email: "shared@example.com")
let expectedDecision = CodexDashboardAuthority.evaluate(
CodexCLIDashboardAuthorityContext.makeLiveWebInput(
dashboard: dashboard,
context: context,
routingTargetEmail: "shared@example.com"))
do {
_ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: dashboard,
context: context,
routingTargetEmail: "shared@example.com")
Issue.record("Expected OpenAIWebCodexError.policyRejected")
} catch let error as OpenAIWebCodexError {
#expect(error == .policyRejected(expectedDecision))
if case let .policyRejected(decision) = error {
#expect(decision.reason == .providerAccountMissingScopedEmail)
}
} catch {
Issue.record("Expected OpenAIWebCodexError.policyRejected, got \(error)")
}
}
@Test
func `web dashboard attach saves cache with attached email not routing fallback`() throws {
OpenAIDashboardCacheStore.clear()
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(
email: "owner@example.com",
accountId: "acct-owner")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-owner"),
normalizedEmail: "owner@example.com"),
])
_ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: self.makeDashboard(email: "owner@example.com"),
context: context,
routingTargetEmail: "route@example.com")
let cache = try #require(OpenAIDashboardCacheStore.load())
#expect(cache.accountEmail == "owner@example.com")
#expect(cache.accountEmail != "route@example.com")
}
@Test
func `web dashboard fail closed clears stale cache`() throws {
OpenAIDashboardCacheStore.save(OpenAIDashboardCache(
accountEmail: "stale@example.com",
snapshot: self.makeDashboard(email: "stale@example.com")))
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(
email: "owner@example.com",
accountId: "acct-owner")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-other"),
normalizedEmail: "owner@example.com"),
])
do {
_ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: self.makeDashboard(email: "owner@example.com"),
context: context,
routingTargetEmail: "route@example.com")
Issue.record("Expected OpenAIWebCodexError.policyRejected")
} catch is OpenAIWebCodexError {}
#expect(OpenAIDashboardCacheStore.load() == nil)
}
@Test
func `web dashboard display only clears stale cache`() throws {
OpenAIDashboardCacheStore.save(OpenAIDashboardCache(
accountEmail: "stale@example.com",
snapshot: self.makeDashboard(email: "stale@example.com")))
defer { OpenAIDashboardCacheStore.clear() }
let authHome = try self.makeAuthHome(email: "shared@example.com")
defer { try? FileManager.default.removeItem(at: authHome) }
let context = self.makeContext(
authHome: authHome,
knownOwners: [
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-alpha"),
normalizedEmail: "shared@example.com"),
CodexDashboardKnownOwnerCandidate(
identity: .providerAccount(id: "acct-beta"),
normalizedEmail: "shared@example.com"),
])
do {
_ = try CodexWebDashboardStrategy.makeAuthorizedDashboardResultForTesting(
dashboard: self.makeDashboard(email: "shared@example.com"),
context: context,
routingTargetEmail: "route@example.com")
Issue.record("Expected CodexDashboardPolicyError.displayOnly")
} catch is CodexDashboardPolicyError {}
#expect(OpenAIDashboardCacheStore.load() == nil)
}
private func makeContext(
authHome: URL? = nil,
knownOwners: [CodexDashboardKnownOwnerCandidate]) -> ProviderFetchContext
{
let env = authHome.map { ["CODEX_HOME": $0.path] } ?? [:]
let browserDetection = BrowserDetection(cacheTTL: 0)
return ProviderFetchContext(
runtime: .cli,
sourceMode: .auto,
includeCredits: true,
webTimeout: 60,
webDebugDumpHTML: false,
verbose: false,
env: env,
settings: ProviderSettingsSnapshot.make(
codex: .init(
usageDataSource: .auto,
cookieSource: .auto,
manualCookieHeader: nil,
dashboardAuthorityKnownOwners: knownOwners)),
fetcher: UsageFetcher(environment: env),
claudeFetcher: ClaudeUsageFetcher(browserDetection: browserDetection),
browserDetection: browserDetection)
}
private func makeDashboard(email: String) -> OpenAIDashboardSnapshot {
OpenAIDashboardSnapshot(
signedInEmail: email,
codeReviewRemainingPercent: 75,
codeReviewLimit: RateWindow(
usedPercent: 25,
windowMinutes: 60,
resetsAt: Date(timeIntervalSince1970: 3600),
resetDescription: nil),
creditEvents: [
CreditEvent(
date: Date(timeIntervalSince1970: 1000),
service: "codex",
creditsUsed: 3),
],
dailyBreakdown: [],
usageBreakdown: [],
creditsPurchaseURL: nil,
primaryLimit: RateWindow(
usedPercent: 10,
windowMinutes: 300,
resetsAt: Date(timeIntervalSince1970: 7200),
resetDescription: nil),
secondaryLimit: nil,
creditsRemaining: 42,
accountPlan: "pro",
updatedAt: Date(timeIntervalSince1970: 2000))
}
private func makeDashboardWithoutUsageLimits(email: String) -> OpenAIDashboardSnapshot {
OpenAIDashboardSnapshot(
signedInEmail: email,
codeReviewRemainingPercent: nil,
creditEvents: [],
dailyBreakdown: [],
usageBreakdown: [],
creditsPurchaseURL: nil,
primaryLimit: nil,
secondaryLimit: nil,
creditsRemaining: 42,
accountPlan: "pro",
updatedAt: Date(timeIntervalSince1970: 2000))
}
private func makeAuthHome(email: String?, accountId: String? = nil) throws -> URL {
let homeURL = FileManager.default.temporaryDirectory.appendingPathComponent(
UUID().uuidString,
isDirectory: true)
try self.writeCodexAuthFile(homeURL: homeURL, email: email, accountId: accountId)
return homeURL
}
private func writeCodexAuthFile(
homeURL: URL,
email: String?,
accountId: String?) throws
{
try FileManager.default.createDirectory(at: homeURL, withIntermediateDirectories: true)
var tokens: [String: Any] = [
"accessToken": "access-token",
"refreshToken": "refresh-token",
"idToken": Self.fakeJWT(email: email, accountId: accountId),
]
if let accountId {
tokens["accountId"] = accountId
}
let auth = ["tokens": tokens]
let data = try JSONSerialization.data(withJSONObject: auth)
try data.write(to: homeURL.appendingPathComponent("auth.json"))
}
private static func fakeJWT(email: String?, accountId: String?) -> String {
let header = (try? JSONSerialization.data(withJSONObject: ["alg": "none"])) ?? Data()
var authClaims: [String: Any] = [
"chatgpt_plan_type": "pro",
]
if let accountId {
authClaims["chatgpt_account_id"] = accountId
}
var claims: [String: Any] = [
"chatgpt_plan_type": "pro",
"https://api.openai.com/auth": authClaims,
]
if let email {
claims["email"] = email
}
let payload = (try? JSONSerialization.data(withJSONObject: claims)) ?? Data()
func base64URL(_ data: Data) -> String {
data.base64EncodedString()
.replacingOccurrences(of: "=", with: "")
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
}
return "\(base64URL(header)).\(base64URL(payload))."
}
}