feat: GlitchTip error tracking (sentry, rustls, credential-scrubbing)#12
Conversation
- default-features=false drops native-tls + debug-images (both default) - features: reqwest + rustls transport, backtrace/contexts/panic - verified openssl-free: cargo tree -i openssl-sys / native-tls empty Co-Authored-By: Claude <noreply@anthropic.com>
…bber - GlitchTip error tracking: ClientOptions (dsn from SENTRY_DSN env, env from SENTRY_ENVIRONMENT, release=CARGO_PKG_VERSION, send_default_pii=false, traces_sample_rate=0.0) with a before_send that scrubs every event. - Fail-closed scrubber: URL user:pass@host creds, secret key=value/key: value (password|passwd|pwd|secret|token|dsn|pass), and PEM private-key blocks → ***REDACTED***. If any regex fails to compile, paranoid mode redacts whole strings. No unwrap/expect outside tests; init never panics (DSN parsed first, malformed → disabled no-op client, app still runs). - scrub_str (pure, testable), scrub_value (recursive JSON), scrub_event (message/exception/breadcrumb/extra). 10 unit tests cover all three patterns, paranoid mode, DSN parse, JSON recursion, and the no-op path. - Module wired via `mod sentry;`; init() call lands with the main.rs init-first refactor (next task) — guarded with #![allow(dead_code)] until then. Co-Authored-By: Claude <noreply@anthropic.com>
- Replace `#[tokio::main] async fn main` with a sync `fn main`: bind `let _sentry_guard = sentry::init()` FIRST (named binding so it outlives block_on, not a bare `let _ =`), then tracing init, then build a multi-thread runtime and block_on(run()). - Move the CLI dispatch body verbatim into `async fn run()`. - Gate the test-only `scrub_str` helper with `#[cfg(test)]` and drop the module-level `#![allow(dead_code)]` now that `init` is wired in. Sentry now captures for the whole process lifetime; unset/malformed DSN still yields a disabled no-op client. serve/set_auth/shutdown_signal and the unix test module are unchanged. Co-Authored-By: Claude <noreply@anthropic.com>
- Replace placeholder tests with spec-named cases: password assignment, user:pass URL, PEM private-key block, nested JSON secret, MCP_SSH_PASS env value, parse_dsn, no-op init. - Add real no-op test via init()+is_enabled() (disabled client when SENTRY_DSN unset), plus array-descent coverage. - Remove the real ingest key (16a3...) from the parse_dsn test; use a throwaway DSN shape so the secret never lands in source. Co-Authored-By: Claude <noreply@anthropic.com>
- Point MCP clients at the GlitchTip HTTP MCP endpoint - infra#499 Co-Authored-By: Claude <noreply@anthropic.com>
- .env.example: SENTRY_DSN/SENTRY_ENVIRONMENT after RUST_LOG - systemd unit: comment at EnvironmentFile noting env-file injection - docs/deploy.md: config table rows pointing to the env file Co-Authored-By: Claude <noreply@anthropic.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 32 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughAdds Sentry/GlitchTip error tracking to the Rust binary: new ChangesSentry error tracking with redaction
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant App
participant SentryClient
participant Scrubbers
participant GlitchTip
App->>SentryClient: emit Event (message, exception, breadcrumbs, extra)
SentryClient->>Scrubbers: before_send(event)
Scrubbers->>Scrubbers: scrub_event (regex + key-match redaction)
Scrubbers-->>SentryClient: redacted Event
SentryClient->>GlitchTip: send redacted Event
Related issues: None referenced in the provided diff. Related PRs: None referenced in the provided diff. Suggested labels: enhancement, observability, rust Suggested reviewers: No reviewer information available from provided context. Poem: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/deploy.md`:
- Around line 214-215: The documented default for SENTRY_ENVIRONMENT is out of
sync with the actual fallback used in src/sentry.rs. Update the deploy docs
table entry for SENTRY_ENVIRONMENT to match the code’s default behavior, and
verify the wording stays consistent with the environment handling in the sentry
initialization logic.
In `@src/main.rs`:
- Around line 34-37: The `main` function currently returns
`runtime.block_on(run())` directly, so `run()` failures bypass Sentry. Update
`main` to call `run()` through `runtime.block_on`, inspect the returned result,
and when it is an `Err`, capture that error with Sentry before returning it
unchanged. Use the `main` and `run` flow to place the capture logic without
altering the successful path.
In `@src/sentry.rs`:
- Around line 24-28: The scrubber in sentry.rs still misses Authorization and
cookie secrets, so extend both SECRET_KEYS and the free-text secret matcher used
by the sanitization logic to catch structured fields like authorization/cookie
and text forms like Authorization: Bearer ... . Update the relevant masking path
that uses SECRET_KEYS/SECRET_KV so these values are redacted before sending
events or crumbs, and add a regression test covering
event.extra["authorization"], crumb.data["cookie"], and free-text Authorization
headers.
- Around line 252-257: Replace the literal PEM-looking fixture in
scrubs_pem_private_key_block with a value assembled from split string fragments
so the runtime string still matches PEM_BLOCK but the source no longer contains
a scanner-detectable private key block. Keep the test logic unchanged and use
the existing scrubbing test name as the anchor for the fixture update.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 89083cb0-6d1b-4b19-b457-c9c1693b57f4
⛔ Files ignored due to path filters (2)
.env.exampleis excluded by!.env*Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (7)
.gitignore.mcp.jsonCargo.tomldeploy/mcp-ssh.servicedocs/deploy.mdsrc/main.rssrc/sentry.rs
- Scrubber now redacts `authorization`/`cookie` keys (structured + free-text, incl. full `Authorization: Bearer <tok>`); value capture spans to EOL to avoid leaking trailing tokens. Added regression test. - main captures run() errors to Sentry before propagating (capture_error wrapper in the local sentry module — it shadows the SDK crate from main). - PEM fixture built from split fragments so the source no longer trips secret scanners; runtime value unchanged. - docs: SENTRY_ENVIRONMENT default aligned to code (`development`). Co-Authored-By: Claude <noreply@anthropic.com>
Version bump for the v1.3.0 release: GlitchTip error tracking (#12) + bug-fix PRs #13–#16. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
sentrycrate, error-tracking only (no traces/profiling/spans,send_default_pii=false). Transport isreqwest+rustls— repo stays openssl-free (cargo tree -i openssl-sys/native-tlsboth empty).src/sentry.rs: runtimeinit()readingSENTRY_DSN/SENTRY_ENVIRONMENTfrom env (never hardcoded); unset/malformed DSN → disabled no-op client, app still runs. Mandatory fail-closedbefore_sendscrubber redacts from every event (message, exception, breadcrumbs, extra JSON): URLuser:pass@hostcreds,key=value/key: valuesecret pairs, and PEM private-key blocks. Nounwrap/expect, regex-compile failure → redact whole string.src/main.rs: refactored to syncfn main()bindinglet _sentry_guardbefore the tokio runtime, thenblock_on(run())— so the transport's own runtime works and the guard flushes on exit..mcp.json(GlitchTip MCP),.env.example+deploy/mcp-ssh.service+docs/deploy.mddocument theSENTRY_DSN/SENTRY_ENVIRONMENTruntime injection point.Tests
cargo fmt --check✓ ·cargo clippy --all-targets -D warnings✓ ·cargo test→ 122 passed, 0 failed (incl. 12 scrubber/no-op unit tests).upstream_status=200with an accepted event id, and the captured envelope showedMCP_SSH_PASS=***REDACTED***+token=***REDACTED***— delivery, flush, guard-before-runtime ordering, and in-flight scrubbing all confirmed. No event lands without the guard held.Ref: developerz-ai/infrastructure#499 (GlitchTip project id 10).
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Documentation