Skip to content

Codex binary preflight runs an uncached spctl --assess on every lookup (~2.5 s of syspolicyd CPU each; ~55% of a core when refresh cadence rises) #4078

Description

@dustball

Summary

CodexLaunchPreflight.isLaunchCandidateAllowed spawns spctl --assess --type execute --verbose=4 on the native codex binary every time BinaryLocator.resolveCodexBinary runs, and nothing caches the verdict. On this Mac each assessment of the 281 MB x86_64 standalone codex costs ~2.5 s of syspolicyd CPU, and Gatekeeper does not cache a rejected (the code is valid but does not seem to be an app) verdict either, so the cost is linear in how often CodexBar looks codex up.

The CPU is billed to syspolicyd, not to CodexBar, so CodexBar's own CPU column looks idle while the fan runs. That made it hard to attribute.

Same class as #3837 (uncached signature validation on every refresh), on a different path.

Environment

  • CodexBar 0.57.0 when observed. spctlAssessment(path:) and isLaunchCandidateAllowed(...) in Sources/CodexBarCore/PathEnvironment.swift are unchanged on v0.68.0 / main.
  • macOS 15.7.7 (24G720), Intel Core i7-4790K, x86_64
  • Codex CLI 0.145.0, standalone install: ~/.local/bin/codex → ~/.codex/packages/standalone/current/bin/codex (Developer ID Application: OpenAI OpCo, LLC (2DC432GLL2), 281 MB, no quarantine xattr)
  • Refresh frequency: 5 minutes (not Adaptive)

Measurements

Three back-to-back runs of spctl --assess --type execute --verbose=4 ~/.local/bin/codex, with syspolicyd otherwise idle:

run wall syspolicyd CPU verdict
1 11.5 s 4.9 s rejected (the code is valid but does not seem to be an app)
2 2.7 s 2.6 s same
3 2.6 s 2.5 s same

From the unified log (log show --predicate 'process == "spctl"'), every spctl parented by CodexBar:

  • Normal: one pair per 5-minute refresh, 24 per hour, which is about 1.7% of a core in syspolicyd, continuously.
  • Elevated: at one point the pairs started arriving every ~12 s (494 in one hour) and stayed there for 52 minutes. syspolicyd measured 16.5 s of CPU per 30 s (~55% of a core). Quitting CodexBar took it to 0.00 s per 30 s. The trigger for the faster cadence was not identified, but whatever raises the lookup rate, every lookup pays the full assessment.

Source-level cause

PathEnvironment.swift: resolveBinary → find / well-known paths → launchCandidateFilter (CodexLaunchPreflight.isLaunchCandidateAllowed) → spctlAssessment(path:), which launches /usr/sbin/spctl on every call. There is no memoization. Callers include CodexStatusProbe.fetch, resolveCodexExecutableForRPC, the Codex descriptor's binaryLocator, and CodexLoginRunner.

Expected

Cache the preflight verdict per resolved native binary, keyed on something that changes when the binary does (path + inode + size + mtime, or the code-directory hash), as #3857 did for the Chromium gate. An unchanged binary should not be re-assessed on every refresh.

Workaround

Set CODEX_CLI_PATH in CodexBar's environment, e.g. open --env CODEX_CLI_PATH=$HOME/.local/bin/codex -a CodexBar. resolveBinary returns an existing override before the preflight runs. Verified: 0 spctl children over a 6-minute window spanning a refresh, and Codex usage still fetched. Caveat: a Sparkle relaunch drops open --env variables, so the workaround has to be re-applied after each update.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions