From d9ce35c9358b7cfda0ac12556b40b54c761767ea Mon Sep 17 00:00:00 2001 From: Lucenx9 <185146821+Lucenx9@users.noreply.github.com> Date: Wed, 19 Aug 2026 03:06:10 +0200 Subject: [PATCH 1/2] Fix `cost` SIGSEGV on Linux by gating Bundle.allBundles to macOS isRunningTests falls back to Bundle.allBundles to detect loaded .xctest bundles. On Linux (swift-corelibs-foundation) Bundle.allBundles crashes in _CFIsSwift (via CFBundleGetAllBundles -> CFArrayGetCount), so `codexbar cost` segfaults before producing output. On Linux, detect the test process from the main executable path instead: SwiftPM builds test executables with a `.xctest` suffix, so the intent survives without enumerating bundles. macOS behavior is unchanged. Fixes #3058 --- .../CodexBarCore/Generated/CodexParserHash.generated.swift | 2 +- .../Vendored/CostUsage/CostUsageCustomPricing.swift | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Sources/CodexBarCore/Generated/CodexParserHash.generated.swift b/Sources/CodexBarCore/Generated/CodexParserHash.generated.swift index 880bbc3474..315c9cdb1e 100644 --- a/Sources/CodexBarCore/Generated/CodexParserHash.generated.swift +++ b/Sources/CodexBarCore/Generated/CodexParserHash.generated.swift @@ -1,5 +1,5 @@ // Generated by Scripts/regenerate-codex-parser-hash.sh. Do not edit by hand. enum CodexParserHash { - static let value = "8050a4faf4fddb96" + static let value = "6293f505c4cbbce8" } diff --git a/Sources/CodexBarCore/Vendored/CostUsage/CostUsageCustomPricing.swift b/Sources/CodexBarCore/Vendored/CostUsage/CostUsageCustomPricing.swift index 7d5618a545..14805ec8c6 100644 --- a/Sources/CodexBarCore/Vendored/CostUsage/CostUsageCustomPricing.swift +++ b/Sources/CodexBarCore/Vendored/CostUsage/CostUsageCustomPricing.swift @@ -74,7 +74,14 @@ public struct CostUsageCustomPricing: Sendable, Equatable { if keys.contains(where: { ProcessInfo.processInfo.environment[$0] != nil }) { return true } + #if os(macOS) return Bundle.allBundles.contains { $0.bundlePath.hasSuffix(".xctest") } + #else + // Bundle.allBundles crashes on Linux (swift-corelibs-foundation). SwiftPM + // builds test executables with a `.xctest` suffix, so detect the test + // process from the main executable instead of enumerating bundles. + return Bundle.main.executableURL?.path.hasSuffix(".xctest") ?? false + #endif } public static func parse(_ data: Data) -> CostUsageCustomPricing { From a6b4e3401335a356428e2baf2b4f28942a1429d9 Mon Sep 17 00:00:00 2001 From: Lucenx9 <185146821+Lucenx9@users.noreply.github.com> Date: Wed, 19 Aug 2026 03:57:40 +0200 Subject: [PATCH 2/2] Fix remaining Bundle.allBundles fallback in OpenCodexUsage on Linux --- .../OpenCodexUsage/OpenCodexUsageModels.swift | 7 ++++++ TestsLinux/PlatformGatingTests.swift | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Sources/CodexBarCore/Vendored/OpenCodexUsage/OpenCodexUsageModels.swift b/Sources/CodexBarCore/Vendored/OpenCodexUsage/OpenCodexUsageModels.swift index f8a65eac57..b139b9394c 100644 --- a/Sources/CodexBarCore/Vendored/OpenCodexUsage/OpenCodexUsageModels.swift +++ b/Sources/CodexBarCore/Vendored/OpenCodexUsage/OpenCodexUsageModels.swift @@ -166,6 +166,13 @@ public enum OpenCodexUsageLog { if NSClassFromString("XCTestCase") != nil { return true } + #if os(macOS) return Bundle.allBundles.contains { $0.bundlePath.hasSuffix(".xctest") } + #else + // Bundle.allBundles crashes on Linux (swift-corelibs-foundation). SwiftPM + // builds test executables with a `.xctest` suffix, so detect the test + // process from the main executable instead of enumerating bundles. + return Bundle.main.executableURL?.path.hasSuffix(".xctest") ?? false + #endif } } diff --git a/TestsLinux/PlatformGatingTests.swift b/TestsLinux/PlatformGatingTests.swift index 95934ebfb3..a0aa7e59c4 100644 --- a/TestsLinux/PlatformGatingTests.swift +++ b/TestsLinux/PlatformGatingTests.swift @@ -236,6 +236,29 @@ struct PlatformGatingTests { #expect(Bool(true)) #endif } + + @Test + func `custom pricing test detector is safe on Linux without test markers`() { + #if os(Linux) + let pricing = CostUsageCustomPricing.load(environment: [:]) + #expect(pricing.fingerprint == "none" || !pricing.fingerprint.isEmpty) + #else + #expect(Bool(true)) + #endif + } + + @Test + func `OpenCodex usage log URL resolution is safe on Linux without test markers`() { + #if os(Linux) + // Under test runner, ProcessInfo has test markers, so isRunningTests returns true safely and returns nil without crashing + let logURL = OpenCodexUsageLog.usageLogURL(environment: [:]) + #expect(logURL == nil) + let overriddenURL = OpenCodexUsageLog.usageLogURL(environment: ["OPENCODEX_HOME": "/tmp/test"]) + #expect(overriddenURL?.path == "/tmp/test/usage.jsonl") + #else + #expect(Bool(true)) + #endif + } private func makeClaudeAutoContext(env: [String: String] = [:]) -> ProviderFetchContext { self.makeClaudeContext(sourceMode: .auto, env: env) }