Skip to content

fix: scope log file to bundle ID on unsandboxed macOS#202

Open
czottmann wants to merge 3 commits intoAvdLee:mainfrom
czottmann:fix/app-scoped-log-path-unsandboxed
Open

fix: scope log file to bundle ID on unsandboxed macOS#202
czottmann wants to merge 3 commits intoAvdLee:mainfrom
czottmann:fix/app-scoped-log-path-unsandboxed

Conversation

@czottmann
Copy link
Copy Markdown

@czottmann czottmann commented Apr 17, 2026

Summary

On unsandboxed macOS apps, diagnostics_log.txt is written to the shared ~/Library/Application Support/ directory, so every app embedding this package writes to — and overwrites — the same file. Sandboxed processes (iOS, tvOS, watchOS, sandboxed macOS) aren't affected because the system already scopes that directory per container.

This PR scopes the log file per app on unsandboxed macOS by appending Bundle.main.bundleIdentifier as a subdirectory.

Behavior

  • Sandboxed (iOS / tvOS / watchOS / sandboxed macOS): unchanged.
  • Unsandboxed macOS with a bundle ID: ~/Library/Application Support/<bundleID>/diagnostics_log.txt.
  • Unsandboxed macOS without a bundle ID (rare — headless / CLI tools): unchanged fallback to the current path.

Implementation notes

  • Sandbox detection uses SecTaskCreateFromSelf + SecTaskCopyValueForEntitlement("com.apple.security.app-sandbox"), so the check reflects the actual code signature rather than environment variables (which can be inherited or spoofed).
  • All sandbox / bundle-ID logic is wrapped in #if os(macOS) — non-macOS platforms compile identically to before.
  • The existing createDirectory(..., withIntermediateDirectories: true) call at the setup site handles the new intermediate path — no call-site changes needed.
  • The file-private FileManager extension is now internal so the test target can reach applicationSupportDirectory and isSandboxed. It is not part of the public API.

Test plan

  • swift build green
  • Existing test suite still passes (one unrelated pre-existing failure in AppSystemMetadataReporterTests/testMetadata exists on main and is not affected by this change)
  • New regression test DiagnosticsLoggerTests.testApplicationSupportDirectoryIsScopedByBundleIDWhenUnsandboxed (macOS-gated) asserts the resolved Application Support directory ends with /<Bundle.main.bundleIdentifier> when running unsandboxed (which the swift test runner always is)
  • Verified in two downstream apps: one sandboxed (macOS + iOS), one unsandboxed macOS — logs now land at per-app paths on the unsandboxed build

The log path resolved via `FileManager.applicationSupportDirectory` lands in
the shared `~/Library/Application Support/` directory on unsandboxed macOS
apps, so `diagnostics_log.txt` collides between every app that embeds the
package. Sandboxed processes (iOS, tvOS, watchOS, sandboxed macOS) are
unaffected because the system already scopes that directory per container.

When the current process lacks the `com.apple.security.app-sandbox`
entitlement (detected via `SecTaskCopyValueForEntitlement`), append
`Bundle.main.bundleIdentifier` as a subdirectory so each app gets its own
log file. `createDirectory(... withIntermediateDirectories: true)` already
handles creating the new intermediate path.
Flip the private `FileManager` extension in `DiagnosticsLogger.swift` to
internal so the test target can see `applicationSupportDirectory` and
`isSandboxed`. Add a macOS-gated regression test that asserts the resolved
Application Support directory is scoped by `Bundle.main.bundleIdentifier`
when the current process is unsandboxed (`swift test` always is), so any
future change that reintroduces the shared-path regression fails loudly.

Only the unsandboxed branch is exercised — the sandboxed branch isn't
reachable from a test process without a real sandboxed app host.
@czottmann czottmann requested a review from AvdLee as a code owner April 17, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant