Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

### Fixed
- Ollama: recognize current WorkOS AuthKit sessions during browser-cookie discovery and manual cookie validation. Thanks @joeVenner!
- Ollama: classify current WorkOS sign-in redirects as expired sessions, enabling cookie-candidate fallback instead of a parser error. Thanks @joeVenner!

## 0.41.0 — 2026-07-06

Expand Down
23 changes: 23 additions & 0 deletions Sources/CodexBarCore/Providers/Ollama/OllamaUsageFetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,10 @@ public struct OllamaUsageFetcher: Sendable {
statusCode: httpResponse.statusCode,
url: httpResponse.response.url?.absoluteString ?? "unknown")

if httpResponse.statusCode == 200, Self.isSignInRedirect(httpResponse.response.url) {
throw OllamaUsageError.invalidCredentials
}

guard httpResponse.statusCode == 200 else {
if httpResponse.statusCode == 401 || httpResponse.statusCode == 403 {
throw OllamaUsageError.invalidCredentials
Expand Down Expand Up @@ -628,6 +632,25 @@ public struct OllamaUsageFetcher: Sendable {
if host == "ollama.com" || host == "www.ollama.com" { return true }
return host.hasSuffix(".ollama.com")
}

static func isSignInRedirect(_ url: URL?) -> Bool {
guard url?.scheme?.lowercased() == "https" else { return false }
guard let url, let host = url.host?.lowercased() else { return false }
let path = url.path.lowercased()
if host == "ollama.com" || host == "www.ollama.com" {
return path == "/signin"
}
// WorkOS AuthKit ultimately bounces unauthenticated requests to a hosted
// Ollama sign-in page on the `signin.ollama.com` subdomain; any landing
// there means the session is expired and the user must sign in again.
if host == "signin.ollama.com" {
return true
}
// WorkOS AuthKit serves the hosted authorization flow from auth.workos.com
// (and historically api.workos.com); match any WorkOS host carrying the
// authorize path so the detection survives host changes or CNAMEs.
return host.hasSuffix(".workos.com") && path.hasPrefix("/user_management/authorize")
}
}

public struct OllamaAPISettingsReader: Sendable {
Expand Down
72 changes: 65 additions & 7 deletions Tests/CodexBarTests/OllamaUsageFetcherRetryMappingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,7 @@ struct OllamaUsageFetcherRetryMappingTests {
return Self.makeResponse(url: url, body: body, statusCode: 200)
}

let fetcher = OllamaUsageFetcher(
browserDetection: BrowserDetection(cacheTTL: 0),
makeURLSession: { delegate in
let config = URLSessionConfiguration.ephemeral
config.protocolClasses = [OllamaRetryMappingStubURLProtocol.self]
return URLSession(configuration: config, delegate: delegate, delegateQueue: nil)
})
let fetcher = self.makeCookieFetcher()
do {
_ = try await fetcher.fetch(
cookieHeaderOverride: "session=test-cookie",
Expand All @@ -145,6 +139,70 @@ struct OllamaUsageFetcherRetryMappingTests {
}
}

@Test
func `workos sign in landing surfaces invalid credentials before parsing`() async throws {
defer { OllamaRetryMappingStubURLProtocol.handler = nil }

let landingURL = try #require(URL(
string: "https://signin.ollama.com/?client_id=test&authorization_session_id=expired"))
OllamaRetryMappingStubURLProtocol.handler = { request in
#expect(request.url == URL(string: "https://ollama.com/settings"))
let body = "<html><body>Sign in to Ollama</body></html>"
return Self.makeResponse(url: landingURL, body: body, statusCode: 200)
}

let fetcher = self.makeCookieFetcher()
do {
_ = try await fetcher.fetch(
cookieHeaderOverride: "session=expired-cookie",
manualCookieMode: true)
Issue.record("Expected OllamaUsageError.invalidCredentials")
} catch let error as OllamaUsageError {
guard case .invalidCredentials = error else {
Issue.record("Expected invalidCredentials, got \(error)")
return
}
} catch {
Issue.record("Expected OllamaUsageError.invalidCredentials, got \(error)")
}
}

@Test
func `workos sign in service failure remains a network error`() async throws {
defer { OllamaRetryMappingStubURLProtocol.handler = nil }

let landingURL = try #require(URL(string: "https://signin.ollama.com/"))
OllamaRetryMappingStubURLProtocol.handler = { _ in
Self.makeResponse(url: landingURL, body: "Service unavailable", statusCode: 503)
}

let fetcher = self.makeCookieFetcher()
do {
_ = try await fetcher.fetch(
cookieHeaderOverride: "session=expired-cookie",
manualCookieMode: true)
Issue.record("Expected OllamaUsageError.networkError")
} catch let error as OllamaUsageError {
guard case let .networkError(message) = error else {
Issue.record("Expected networkError, got \(error)")
return
}
#expect(message == "HTTP 503")
} catch {
Issue.record("Expected OllamaUsageError.networkError, got \(error)")
}
}

private func makeCookieFetcher() -> OllamaUsageFetcher {
OllamaUsageFetcher(
browserDetection: BrowserDetection(cacheTTL: 0),
makeURLSession: { delegate in
let config = URLSessionConfiguration.ephemeral
config.protocolClasses = [OllamaRetryMappingStubURLProtocol.self]
return URLSession(configuration: config, delegate: delegate, delegateQueue: nil)
})
}

private static func makeResponse(
url: URL,
body: String,
Expand Down
21 changes: 21 additions & 0 deletions Tests/CodexBarTests/OllamaUsageFetcherTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,27 @@ struct OllamaUsageFetcherTests {
#expect(!OllamaUsageFetcher.shouldAttachCookie(to: URL(string: "http://app.ollama.com/path")))
}

@Test
func `recognizes current ollama sign in redirects`() {
#expect(OllamaUsageFetcher.isSignInRedirect(URL(string: "https://ollama.com/signin")))
#expect(OllamaUsageFetcher.isSignInRedirect(URL(
string: "https://api.workos.com/user_management/authorize?client_id=test")))
#expect(OllamaUsageFetcher.isSignInRedirect(URL(
string: "https://auth.workos.com/user_management/authorize?client_id=test")))
// The real unauthenticated chain lands on the WorkOS-hosted Ollama sign-in
// page on the `signin.ollama.com` subdomain (verified live); that terminal
// landing must also classify as a sign-in redirect.
#expect(OllamaUsageFetcher.isSignInRedirect(URL(
string: "https://signin.ollama.com/?client_id=test&authorization_session_id=x")))
#expect(!OllamaUsageFetcher.isSignInRedirect(URL(string: "https://ollama.com/settings")))
#expect(!OllamaUsageFetcher.isSignInRedirect(URL(string: "https://api.workos.com/other")))
#expect(!OllamaUsageFetcher.isSignInRedirect(URL(string: "http://ollama.com/signin")))
#expect(!OllamaUsageFetcher.isSignInRedirect(URL(
string: "http://auth.workos.com/user_management/authorize?client_id=test")))
#expect(!OllamaUsageFetcher.isSignInRedirect(URL(
string: "https://example.com/user_management/authorize?client_id=test")))
}

@Test
func `manual mode without valid header throws no session cookie`() {
do {
Expand Down
2 changes: 2 additions & 0 deletions docs/ollama.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Ollama API keys currently do not expire, but they can be revoked from the key se
- Cookie mode fetches `https://ollama.com/settings` using browser cookies.
- Cookie discovery recognizes the current WorkOS AuthKit `wos-session` cookie alongside legacy Ollama and NextAuth
session names.
- Redirects from settings to `/signin` or the WorkOS AuthKit authorization page are treated as expired sessions, so
CodexBar can try the next cookie candidate and show sign-in guidance instead of a parser error.
- Parses:
- Plan badge under **Cloud Usage**.
- **Session usage** and **Weekly usage** percentages.
Expand Down