Skip to content

Comments

fix(brew): handle root-owned config dir from sudo installs#288

Merged
BYK merged 1 commit intomainfrom
byk/fix-brew-postinstall
Feb 24, 2026
Merged

fix(brew): handle root-owned config dir from sudo installs#288
BYK merged 1 commit intomainfrom
byk/fix-brew-postinstall

Conversation

@BYK
Copy link
Member

@BYK BYK commented Feb 24, 2026

Problem

Two errors were reported during Homebrew post-install of v0.12.0:

  1. SQLiteError: unable to open database file (SQLITE_CANTOPEN) — setup aborts
  2. Warning: read-only database + EPERM on zsh completions — setup aborts

Root cause: sudo brew install creates root-owned ~/.sentry/ and ~/.local/share/zsh/ files. The setup command had no error handling, so any failure aborted the entire post-install script and Homebrew showed a scary error even though the binary installed fine.

The same root cause explains the recurring "attempt to write a readonly database" Sentry telemetry issues (8 issues, 19 events, 100% macOS). Moving the config directory would not help — the same permission problems would occur at any path if created by root. macOS TCC does not restrict ~/.sentry/.

Changes

Non-fatal setup steps (setup.ts)

Added a bestEffort() wrapper around each post-install configuration step. Permission failures now log a warning instead of aborting. The binary is already installed — these steps are nice-to-have side effects.

Root-owned file detection in tryRepairReadonly (telemetry.ts)

Before attempting chmod (which fails silently on root-owned files), now checks stat().uid. If the file is owned by root, emits a targeted actionable message with the actual username:

Warning: Sentry CLI config directory is owned by root.
  Path:  /Users/am/.sentry
  Fix:   sudo chown -R am "/Users/am/.sentry"
  Or:    sudo sentry cli fix

Username is inferred from SUDO_USERUSERUSERNAMEos.userInfo().

Ownership repair in sentry cli fix (fix.ts)

  • Ownership check runs before permissions (chmod fails on root-owned files anyway)
  • Not root: prints sudo chown -R <user> <configDir> and sudo sentry cli fix instructions, exits with code 1
  • Running as root (sudo sentry cli fix): resolves the real user's UID via id -u <username>, then performs chown to transfer ownership back

Fixes CLI-7Q, CLI-7K, CLI-6N, CLI-6D, CLI-4Z, CLI-51, CLI-4E, CLI-2E

@github-actions
Copy link
Contributor

github-actions bot commented Feb 24, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


Bug Fixes 🐛

  • (brew) Handle root-owned config dir from sudo installs by BYK in #288
  • (setup) Show actual shell name instead of "unknown" for unsupported shells by BYK in #287

Internal Changes 🔧

  • Only showing status about changed files in codecov by MathurAditya724 in #286

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 24, 2026

Codecov Results 📊

❌ Patch coverage is 78.31%. Project has 3639 uncovered lines.
❌ Project coverage is 75.35%. Comparing base (base) to head (head).

Files with missing lines (3)
File Patch % Lines
fix.ts 80.65% ⚠️ 77 Missing
telemetry.ts 90.75% ⚠️ 38 Missing
setup.ts 98.08% ⚠️ 5 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
- Coverage    75.38%    75.35%    -0.03%
==========================================
  Files          115       115         —
  Lines        14518     14760      +242
  Branches         0         0         —
==========================================
+ Hits         10943     11121      +178
- Misses        3575      3639       +64
- Partials         0         0         —

Generated by Codecov Action

@BYK BYK force-pushed the byk/fix-brew-postinstall branch from fd8a30e to 55e7118 Compare February 24, 2026 10:58
@BYK BYK force-pushed the byk/fix-brew-postinstall branch from 55e7118 to b965269 Compare February 24, 2026 11:20
@BYK
Copy link
Member Author

BYK commented Feb 24, 2026

Addressed both review comments in b965269:

Promise.allSettled in checkOwnership: Refactored to use Promise.allSettled — stat all 4 paths in parallel, then iterate the settled results. Fulfilled results with a foreign uid become ownership issues; rejected results with ENOENT/EACCES are silently skipped; any other rejection is re-thrown. Removes the nested async try/catch in favour of a cleaner loop.

Bun.$ in resolveUid: Replaced with execSync from node:child_process (same pattern already used in the Bun.which polyfill). This works on both the Bun binary and the npm/node distribution with no shim needed. Also simplified resolveUid from async to sync since execSync is blocking.

@BYK BYK force-pushed the byk/fix-brew-postinstall branch from b965269 to 165c919 Compare February 24, 2026 11:23
@BYK BYK marked this pull request as ready for review February 24, 2026 11:25
@BYK BYK force-pushed the byk/fix-brew-postinstall branch from 165c919 to c4d7ea1 Compare February 24, 2026 11:49
@BYK
Copy link
Member Author

BYK commented Feb 24, 2026

Addressed all four review comments in c4d7ea1:

Command injection in resolveUid (Seer + Cursor BugBot — high): Replaced execSync(id -u ${username}) with execFileSync("id", ["-u", "--", username]). execFileSync bypasses the shell entirely — the username is passed as a discrete argument, so no metacharacters can escape. The -- separator also guards against usernames starting with -.

Ownership check wrong when running as sudo (Cursor BugBot — high): Real bug. When sudo sentry cli fix runs, process.getuid() returns 0, and files from sudo brew install are also uid 0 — so the mismatch check always passed. Fix: handleOwnershipIssues now resolves the real user's UID via resolveUid(getRealUsername()) before calling checkOwnership, and passes that as the comparison UID instead of the process UID. If resolveUid returns null (unknown user), we fall back to 0 and still detect the mismatch correctly.

Duplicated getRealUsername (Cursor BugBot — low): Moved to src/lib/utils.ts and imported in both fix.ts and telemetry.ts. Single source of truth.

@BYK BYK force-pushed the byk/fix-brew-postinstall branch from c4d7ea1 to 2a41fca Compare February 24, 2026 12:04
@BYK
Copy link
Member Author

BYK commented Feb 24, 2026

Addressed two more comments in 2a41fca:

fix can chown files to root (Cursor BugBot — high): Added an explicit guard: if resolveUid(username) returns 0 (e.g. when getRealUsername() resolves to "root" because no SUDO_USER/USER env var is set and userInfo().username is "root"), we now refuse to chown and print manual instructions instead. Chowning to uid 0 would worsen the situation, not fix it.

getRealUsername may throw (Cursor BugBot — medium): Wrapped userInfo() in a try/catch in src/lib/utils.ts. If it throws (e.g. corrupted passwd entry), the call silently yields ""\ and the fallback chain continues to $(whoami)`.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

- Make all post-install setup steps non-fatal using a bestEffort() wrapper
  so Homebrew's post_install never aborts on permission errors
- In tryRepairReadonly(), detect root-owned files (uid 0) and emit a
  targeted message with the actual username instead of falling through
  to the generic warning
- Add ownership detection and repair to `sentry cli fix`:
  - Checks config dir / DB / WAL / SHM file ownership
  - When run as root (sudo sentry cli fix), performs chown to transfer
    ownership back to the real user (inferred from SUDO_USER env var)
  - When not root, prints the exact sudo chown command to run
@BYK BYK force-pushed the byk/fix-brew-postinstall branch from 2a41fca to 620f800 Compare February 24, 2026 12:23
@BYK
Copy link
Member Author

BYK commented Feb 24, 2026

Addressed two more comments in 620f800:

fix can chown files to root (Seer — critical): The previous fallback comparisonUid = targetUid ?? currentUid was wrong: when resolveUid returns null and currentUid === 0, comparisonUid became 0, making root-owned files look correctly-owned. Fixed by bailing early (before calling checkOwnership) when we can't resolve a non-root UID — we print manual instructions and return. This also removes the later redundant null/0 check since it's now impossible to reach the chown code without a valid non-root resolvedUid.

isOwnedByRoot always returns true on Windows (Cursor BugBot — medium): fs.stat().uid always returns 0 on Windows regardless of actual ownership. Added an early process.platform === "win32" guard that returns false immediately, matching the behavior of the fix command itself (which skips ownership checks on Windows via process.getuid() returning undefined).

@BYK BYK merged commit 3d88174 into main Feb 24, 2026
23 checks passed
@BYK BYK deleted the byk/fix-brew-postinstall branch February 24, 2026 14:31
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