Skip to content

Crash reports can go to Sentry, with symbols from the release build - #74

Merged
IAmJSD merged 1 commit into
mainfrom
t3code/integrate-sentry-release-pipeline
Aug 29, 2026
Merged

Crash reports can go to Sentry, with symbols from the release build#74
IAmJSD merged 1 commit into
mainfrom
t3code/integrate-sentry-release-pipeline

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Aug 29, 2026

Copy link
Copy Markdown
Member

Schist could already write a crash report to the user's own machine and that was all it could do with one. On a stripped Linux release the result is nearly useless anyway — the backtrace is addresses. This adds an upload, and the symbols to read it against.

Two locks, not one

The upload needs both:

  • the user ticks it in Preferences ▸ Diagnostics, separately from the local report — writing a file to their machine and sending one to us are not the same decision;
  • and the build was given a DSN, which only the release workflow does. A build from source, or from a distribution's packaging, has none, never reaches sentry::init, and hides the checkbox rather than offering one that sends reports nowhere.

What leaves

No PII, no breadcrumbs, and no release-health sessions, logs or metrics — the SDK is taken with default-features = false and only the four integrations a crash needs. server_name is set rather than left alone, because sentry-contexts otherwise fills it with the machine's hostname, and a hostname is very often a person's name. The panic message has the home directory rewritten to ~: an image editor panic tends to quote the path it choked on, and that path is somebody's document.

Transport is ureq over rustls — the stack the update check already links — so this adds a reason to talk to the network but no new means of doing it, and no C dependency.

The flush is forced from inside the panic hook rather than left to the guard's Drop. A crash in a GUI often never gets as far as main returning: GPUI unwinds through platform callbacks, and an unwind across one of those aborts outright, so by then there may be no process left to flush in.

Symbols

Each platform in the form its object format keeps them:

  • Linux — uploaded before the strip that already happens, since ELF carries DWARF inside the executable and that is the last moment it exists. What ships keeps its build id, which is what the upload is matched on. That id is now pinned with --build-id=sha1 on both Linux targets instead of left to the toolchain: mold writes one by default and Ubuntu's GNU ld does not, and the two Linux jobs use one linker each.
  • macOSdsymutil after packaging, because bundle.sh invokes cargo again and a relink would change the LC_UUID the dSYM is matched on. Signing is harmless; it appends a signature and leaves the UUID alone.
  • Windows — the .pdbs MSVC writes beside the executables, matched rather than named because rustc derives their names from the binaries'.

SENTRY_AUTH_TOKEN is the one switch for all of it. Without it every step here is skipped and the release is built exactly as before, so forks and any repository without the secrets are unaffected.

Before this does anything

The Sentry project does not exist yet, and neither do the settings. Until they are added the pipeline runs green and uploads nothing:

Name Kind What it is
SENTRY_AUTH_TOKEN secret Token with project:releases. The master switch.
SCHIST_SENTRY_DSN secret The DSN compiled into the app.
SENTRY_ORG variable Organisation slug.
SENTRY_PROJECT variable Project slug.

Full mechanics in docs/versioning.md § Crash reporting and symbols.

Testing

cargo fmt --check, clippy -D warnings and all 43 tests pass. Five new unit tests cover the redaction and the fails-closed behaviour.

Verified by hand: the build id is byte-identical before and after strip --strip-debug and the DWARF is gone after; and a DSN produces an enabled client actually carrying server_name=redacted, no PII and no breadcrumbs.

Not verified, and not verifiable from here: the upload itself, and whether a stripped Linux release really symbolicates. The first tagged release after the settings land is the first real test of that path.

One judgement call worth a look

schist-mcp's debug files are uploaded too, though only the app links the SDK — the Linux strip is destructive, so it is the one chance to keep anything that could explain a fault there later. It costs quota for symbols nothing currently reports against. Easy to cut to schist alone if you would rather.

🤖 Generated with Claude Code

@IAmJSD
IAmJSD force-pushed the t3code/integrate-sentry-release-pipeline branch from 4c44223 to c17ac64 Compare August 29, 2026 21:17
…uild

Schist could already write a crash report to the user's own machine and
that was all it could do with one. A stripped Linux release makes the
result nearly useless anyway: the backtrace is addresses. This adds an
upload, and the symbols to read it against.

The upload is off behind two locks rather than one. The user has to tick
it in Preferences, separately from the local report, because writing a
file to their machine and sending one to ours are not the same decision.
And the build has to have been given a DSN, which only the release
workflow does -- so a build from source, or from a distribution's
packaging, has none, never reaches `sentry::init`, and does not even
show the checkbox rather than showing one that sends reports nowhere.

What leaves is scrubbed. No PII, no breadcrumbs, and no release-health
sessions, logs or metrics -- the SDK is taken with `default-features =
false` and only the four integrations a crash needs. `server_name` is
set rather than left alone, because `sentry-contexts` fills it with the
machine's hostname and a hostname is very often a person's name. The
panic message has the home directory rewritten to `~`: an image editor
panic tends to quote the path it choked on, and that path is somebody's
document.

The transport is ureq over rustls, which is the stack the update check
already links, so this adds a reason to talk to the network but no new
means of doing it and no C dependency.

The flush is forced from inside the panic hook rather than left to the
guard's `Drop`. A crash in a GUI often never gets as far as `main`
returning -- GPUI unwinds through platform callbacks and an unwind
across one of those aborts outright -- so by the time `Drop` would run
there may be no process left to run it in.

Symbols are uploaded per platform, each in the form its object format
keeps them in. Linux goes first, before the strip that already happens,
because ELF carries DWARF inside the executable and that is the last
moment it exists; what ships keeps its build id, which is what the
upload is matched on. That id is now pinned with `--build-id=sha1` on
both Linux targets instead of being left to the toolchain: mold writes
one by default and Ubuntu's GNU ld does not, and the two Linux jobs use
one linker each. macOS runs `dsymutil` after packaging, since
`bundle.sh` invokes cargo again and a relink there would change the
`LC_UUID` the dSYM is matched on; signing is harmless, it appends a
signature and leaves the UUID alone. Windows uploads the .pdb files MSVC
writes beside the executables, matched rather than named because rustc
derives their names from the binaries'.

`SENTRY_AUTH_TOKEN` is the one switch for all of it. Without it every
step here is skipped and the release is built exactly as it was before,
so forks and any repository without the secrets are unaffected.

Verified locally that the build id is byte-identical before and after
`strip --strip-debug` and that the DWARF is gone after, and that a DSN
produces an enabled client carrying each of these options. The upload
itself is not verifiable from here: the first tagged release after the
settings exist is the first real test of it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@IAmJSD
IAmJSD force-pushed the t3code/integrate-sentry-release-pipeline branch from c17ac64 to 7866127 Compare August 29, 2026 21:37
@IAmJSD
IAmJSD merged commit 1fe182b into main Aug 29, 2026
3 checks passed
@IAmJSD
IAmJSD deleted the t3code/integrate-sentry-release-pipeline branch August 29, 2026 22:07
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