* ci(release): bake Sentry DSN into shipped tauri bundle
Released builds weren't reporting anything to Sentry. Root cause: the
tauri.conf.json `beforeBuildCommand` re-runs `vite build` inside
`cargo tauri build`. The prior `yarn build` step set `VITE_SENTRY_DSN`
for its own run, but the tauri step did not — so the rebuild produced
a DSN-less `dist/` that overwrote the good one, and the shipped web UI
initialized Sentry with an empty DSN (`initSentry` returns early when
`!SENTRY_DSN`).
Fix:
- `release.yml` / `build-desktop` — declare `VITE_SENTRY_DSN` and
`VITE_DEBUG` on the tauri-build step so the `beforeBuildCommand`
rebuild bakes them into the final bundle.
- `release-packages.yml` / `build-cli-linux-arm64` — guard against a
missing `vars.OPENHUMAN_SENTRY_DSN` so the Linux arm64 CLI tarball
cannot ship without error reporting baked in via `option_env!`.
The core sidecar's `option_env!("OPENHUMAN_SENTRY_DSN")` already gets
the value from the dedicated "Build sidecar core binary" step; the
tauri shell doesn't rebuild it (separate crate, not a workspace dep),
so the baked DSN survives into the bundled installer.
* feat(observability): Sentry release tracking + source maps (#405)
Tags every Sentry event with a canonical release identifier shared by
the frontend and Rust core, uploads source maps so stack traces are
symbolicated in the dashboard, and adds a CLI probe for repeatable
verification of any future release.
Release identifier
openhuman@<semver>[+<short_git_sha>]
- Frontend (`app/src/utils/config.ts::SENTRY_RELEASE`) builds the tag
from `VITE_BUILD_SHA`.
- Core sidecar (`src/main.rs::build_release_tag`) builds the same tag
from `option_env!("OPENHUMAN_BUILD_SHA")`, so events from both
surfaces group under one release. Cargo's fingerprint already tracks
`option_env!` changes.
Environment separation
- Frontend: new `APP_ENVIRONMENT` export (`development` | `staging` |
`production`) derived from `VITE_OPENHUMAN_APP_ENV`, passed to
`Sentry.init`.
- Core: `resolve_environment` honors `OPENHUMAN_APP_ENV` at runtime,
falling back to `debug_assertions` detection.
Source-map upload
- `@sentry/vite-plugin` added as an app devDependency.
- `vite.config.ts` emits source maps unconditionally and registers the
plugin only when `SENTRY_AUTH_TOKEN` is present, so local dev skips
silently. The plugin uploads `dist/**/*.js{,.map}` under the
canonical release name and then deletes the on-disk `.map` files so
they never ship to end users.
CI wiring (`release.yml` + `release-packages.yml`)
- `Build frontend` and `Build and package Tauri app` both receive
`VITE_BUILD_SHA`, `SENTRY_RELEASE`, `SENTRY_AUTH_TOKEN`, `SENTRY_ORG`,
`SENTRY_PROJECT_FRONTEND`. The tauri step needs the same env because
its `beforeBuildCommand` re-runs `vite build`.
- `Build sidecar core binary` receives `OPENHUMAN_BUILD_SHA` so
`option_env!` bakes the short SHA into the release tag.
- `build-cli-linux-arm64` mirrors `OPENHUMAN_BUILD_SHA` and
`OPENHUMAN_APP_ENV` for the arm64 CLI tarball.
Verification support
- New `openhuman sentry-test` CLI subcommand captures an `Error`-level
event against the currently-initialized client, flushes, and prints
the event UUID. Optional `--panic` flag exercises the panic
integration. Requires a DSN resolvable at runtime or baked in at
compile time; exits non-zero otherwise so misconfiguration is loud.
- `src/main.rs` now loads `.env` before `sentry::init`, so a DSN
defined only in the repo-local dotenv file (common dev case) is
honored by the startup-time Sentry client.
Docs
- `docs/sentry.md` covers the release identifier, environment table,
source-map pipeline, required CI variables, and a verification
runbook with troubleshooting tips.
- `.env.example` + `app/.env.example` document the new build-time vars.
6.2 KiB
Sentry Release Tracking & Source Maps
Tracks issue #405.
OpenHuman reports crashes and errors from two surfaces that must group under a single Sentry release so a new deploy's regressions are easy to see:
- Frontend —
@sentry/reactinapp/src/services/analytics.ts. - Rust core sidecar —
sentry::initinsrc/main.rs.
The Tauri shell binary (app/src-tauri) has no Sentry wiring today.
Canonical release identifier
Both surfaces report the same release tag:
openhuman@<semver>+<short_git_sha>
Where:
<semver>ispackageJson.version/env!("CARGO_PKG_VERSION").<short_git_sha>is the first 12 chars of the commit that produced the build. When the SHA is absent (local dev), the tag collapses toopenhuman@<semver>with no+suffix.
The frontend computes this in app/src/utils/config.ts::SENTRY_RELEASE
from VITE_BUILD_SHA. The core does the same in
src/main.rs::build_release_tag() from option_env!("OPENHUMAN_BUILD_SHA").
Environments
Reported as the Sentry environment tag:
| Value | When |
|---|---|
development |
Local yarn tauri dev / debug builds |
staging |
VITE_OPENHUMAN_APP_ENV=staging or OPENHUMAN_APP_ENV=staging |
production |
Release builds from workflow_dispatch with build_target=production |
Fallback precedence for the core:
OPENHUMAN_APP_ENVenv var at runtime (override).- Compile-time
debug_assertions→development. - Otherwise →
production.
Source-map upload
The frontend emits source maps (vite.config.ts sets build.sourcemap = true). When SENTRY_AUTH_TOKEN is present at build time
@sentry/vite-plugin:
- Uploads every
dist/**/*.jsand its.mapsibling. - Tags the upload with the canonical release name above.
- Deletes the on-disk
.mapfiles after upload so users never receive them in the shipped bundle.
If SENTRY_AUTH_TOKEN is empty (local dev, smoke CI, forks without
secrets), the plugin registers as a no-op — the build still produces source
maps on disk but nothing is uploaded. This keeps the local dev loop zero-
config.
CI configuration
release.yml + release-packages.yml thread the following through to the
build steps. Any subset can be set on a per-environment basis in the
Production / Staging GitHub Actions environment:
Required for upload to work
| Name | Type | Scope | Purpose |
|---|---|---|---|
secrets.SENTRY_AUTH_TOKEN |
secret | build-desktop | Auth for @sentry/vite-plugin uploads |
vars.SENTRY_ORG |
variable | build-desktop | Sentry org slug |
vars.SENTRY_PROJECT_FRONTEND |
variable | build-desktop | Sentry project slug for the frontend bundle |
vars.OPENHUMAN_SENTRY_DSN |
variable | build-desktop | Core sidecar DSN (baked via option_env!) |
vars.VITE_SENTRY_DSN |
variable | build-desktop | Frontend DSN (baked by Vite define) |
Provided automatically
| Name | Source |
|---|---|
VITE_BUILD_SHA |
needs.prepare-build.outputs.sha (tag commit) |
OPENHUMAN_BUILD_SHA |
Same — passed to cargo build for the sidecar |
SENTRY_RELEASE |
openhuman@<version>+<sha> — same on both steps |
Personal Sentry DSN (local)
Drop the DSN into your repo-local .env:
# .env
OPENHUMAN_SENTRY_DSN=https://<key>@o<org>.ingest.sentry.io/<project>
src/main.rs now loads .env before sentry::init, so the runtime
env var is visible to the client at startup without needing a manual
source scripts/load-dotenv.sh.
For the frontend, put VITE_SENTRY_DSN in app/.env.local.
Verification runbook
- Event arrives. Trigger a test event from the core CLI:
The command prints an event UUID on success; search it in the Sentry dashboard.
./target/release/openhuman-core sentry-test # or on an installed release (Windows): # "%LOCALAPPDATA%\Programs\OpenHuman\OpenHuman.exe" core sentry-test # or (macOS): # /Applications/OpenHuman.app/Contents/MacOS/openhuman-core-* sentry-test - Release tag is right. On the event detail page, the
Releasefield should readopenhuman@<version>+<short_sha>(matching the tag that cut the release). - Environment tag is right. Production CI dispatch →
production. Staging dispatch →staging. Localyarn tauri dev→development. - Stack traces are symbolicated. Force a frontend error from the
installed app; the event's stack trace should show original
TypeScript file names and line numbers (not hashed
assets/index-*.js). - CI failure is loud when misconfigured. If
SENTRY_AUTH_TOKENis missing and the release is supposed to upload source maps, the CI run will warn in the Vite build log rather than silently producing an un-symbolicated release.
Troubleshooting
- Events arrive without a release tag — check the Vite build log for
SENTRY_RELEASE; if empty, the CI workflow didn't pass it through. - Events arrive without symbolication — open the release in Sentry →
"Source Maps" tab. Missing artifacts mean either
SENTRY_AUTH_TOKENwas empty, or the plugin ran but theassets:glob didn't match (inspect the upload summary printed duringyarn build). - Frontend and core show different releases — verify
needs.prepare-build.outputs.shais identical between the core build step (OPENHUMAN_BUILD_SHA) and the frontend build step (VITE_BUILD_SHA/SENTRY_RELEASE). - No events from a release build, only from local —
vars.*probably isn't defined on theProductionenvironment. Set it and re-cut the release.