Sentry log enrichment for backend Workers#568
Conversation
Issue: AP-384
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds a structured worker logging module ( ChangesWorker logging, Sentry sanitization, and app adoption
Sequence Diagram(s)sequenceDiagram
participant Worker as Worker (api/content/jobs/mcp/upload)
participant captureWorkerError
participant emitWorkerLog
participant sanitizeWorkerLogAttributes
participant Console
participant Sentry
rect rgba(255, 100, 100, 0.5)
note over Worker,Sentry: Unhandled error in app.onError
Worker->>captureWorkerError: {component, event, error, env, request, requestId}
captureWorkerError->>sanitizeWorkerLogAttributes: error name/message + caller attributes
sanitizeWorkerLogAttributes-->>captureWorkerError: sanitized scalar attributes
captureWorkerError->>emitWorkerLog: level=error, merged attributes
emitWorkerLog->>Console: JSON.stringify({level, component, event, ...attributes})
captureWorkerError->>Sentry: captureException(error, {extra: {errorMessage}})
emitWorkerLog->>Sentry: logger.error(event, {requestId, errorName})
end
rect rgba(100, 150, 255, 0.5)
note over Worker,Sentry: Sentry beforeSend / beforeSendLog hooks
Sentry->>Sentry: sanitizeSentryEvent(ErrorEvent)
Sentry-->>Sentry: redacted ErrorEvent (tokens/URLs scrubbed)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
First-pass review (AP-384)
Risk: medium
Decision: Needs human review
Ticket triage
- Intended change: Add sanitized Sentry SDK logs + structured worker logging for backend Workers when
SENTRY_DSNis set, while keeping JSON console logs for Axiom and redacting secrets/tokens/URLs. - Scope match: Yes. Shared helpers in
@agent-paste/worker-runtime, backendonErrormigration (api/upload/content/jobs/mcp), jobs op-log refactor, optionalSENTRY_DSNrouting for backend workers, and redaction tests all align with AP-384 acceptance criteria.
Review findings
Blocking: None found in the diff.
Non-blocking:
captureWorkerErrorreports the same failure via bothSentry.captureExceptionandSentry.logger.*— confirm this is the desired Sentry shape and won't create noisy duplicates.streamnow receives optionalSENTRY_DSNprovisioning but still has no structuredcaptureWorkerErrorpath (unlike api/upload/content/jobs/mcp). Likely acceptable given stream's response style, but worth a quick human sanity check.- CI
Validatewas still pending at review time (Postgres smoke/CodeQL/secret scan passed). Author checklist claimspnpm verify/ coverage passed locally.
Merge checklist
| Item | Status |
|---|---|
| Ticket linked | ✅ AP-384 |
| Scope matches | ✅ |
| Checks green | |
| Tests/docs appropriate | ✅ Strong unit coverage for sanitizers + logging |
| No blocking findings | ✅ |
| No high-risk areas | ❌ See below |
| Merge-safe for automation | ❌ |
Needs human review
This PR is well-scoped and the redaction/tests look thoughtful, but it should not be auto-approved because it touches:
- Security-sensitive observability —
beforeSend/beforeSendLogare the last line of defense for tokens, signed URLs, and credential material (ticket labeledrisk-security-sensitive). - Deploy secret routing — optional
SENTRY_DSNprovisioning expanded across backend workers. - Cross-cutting worker runtime — shared logging/Sentry behavior affects the whole backend fleet.
Recommend a human pass focused on redaction completeness (especially real failure payloads/breadcrumbs) and confirming Sentry event shape in preview once SENTRY_DSN is configured.
Sent by Cursor Automation: First Pass PR Reviewer
| emitConsoleLine(level, attributes); | ||
|
|
||
| try { | ||
| Sentry.captureException(input.error, { extra: attributes }); |
There was a problem hiding this comment.
Non-blocking: this path emits both captureException and sendSentryLog for the same failure. Worth confirming with Sentry that exception + structured log is intentional and won't double-count/noise alerts.
| }, | ||
| stream: { | ||
| STREAM_INTERNAL_SECRET: { required: true }, | ||
| SENTRY_DSN: { required: false, source: "sentry" }, // Optional backend monitoring; enabled only when configured. |
There was a problem hiding this comment.
Non-blocking scope note: stream now gets optional SENTRY_DSN, but apps/stream wasn't migrated to captureWorkerError like the Hono workers. If stream unhandled throws should carry the same component/request context, that follow-up may belong here or a tiny stream handler wrap.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@packages/worker-runtime/src/logging.ts`:
- Around line 49-50: The SECRET_ASSIGNMENT_PATTERN regex at line 49-50 only
matches unquoted assignment forms and misses JSON-style secret assignments with
quoted keys and values like "token":"secret". Update the
SECRET_ASSIGNMENT_PATTERN regex to handle both unquoted forms (existing pattern)
and quoted JSON-style forms where both the key and value are enclosed in double
quotes, ensuring that the pattern at line 220 will properly redact all
variations of secret assignments before they are emitted to logs and Sentry.
In `@packages/worker-runtime/src/sentry-sanitize.ts`:
- Around line 4-48: The sanitizeSentryEvent function does not handle the
event.user field, allowing unsanitized user information like email and IP
addresses to be included in the Sentry event. Add a check for event.user in the
sanitizeSentryEvent function following the existing pattern for other event
fields, and either sanitize it using sanitizeSentryRecord (or an appropriate
helper) or remove it entirely from the safe object to prevent user data leakage.
In `@packages/worker-runtime/src/sentry.test.ts`:
- Around line 75-143: The test for sanitizing Sentry error events in the
beforeSend callback is missing validation for the user field, which could
contain PII. Add a user field to the event object passed to beforeSend (e.g.,
with properties like id, email, or ip_address), then add an assertion after the
existing toMatchObject check to verify that the user field is either removed
from the returned event or properly sanitized to prevent PII leakage.
🪄 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 Plus
Run ID: a5d06f73-01be-4814-84c9-490b5ebc1b5b
📒 Files selected for processing (16)
apps/api/src/index.tsapps/content/src/index.tsapps/jobs/src/index.tsapps/jobs/src/op-log-sentry.test.tsapps/jobs/src/op-log.tsapps/mcp/src/index.tsapps/upload/src/index.tspackages/worker-runtime/src/index.tspackages/worker-runtime/src/logging.test.tspackages/worker-runtime/src/logging.tspackages/worker-runtime/src/sentry-sanitize.tspackages/worker-runtime/src/sentry.test.tspackages/worker-runtime/src/sentry.tsscripts/deploy.test.mjsscripts/lib/secret-routing.mjsscripts/lib/secret-routing.test.mjs
Issue: AP-384
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/worker-runtime/src/logging.ts (1)
217-224:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRedact before applying the 2KB truncation.
Line 218 truncates before the redaction chain, so a secret assignment that starts near the 2048-character boundary can lose its closing delimiter and skip the Line 222/223 patterns, leaking the secret prefix.
🛡️ Proposed fix
export function sanitizeString(value: string): string { - const trimmed = value.length > 2048 ? `${value.slice(0, 2048)}...[truncated]` : value; - return trimmed + const redacted = value .replace(API_KEY_PATTERN, "[redacted_api_key]") .replace(BEARER_PATTERN, "Bearer [redacted]") .replace(JSON_SECRET_ASSIGNMENT_PATTERN, '"$1":"[redacted]"') .replace(SECRET_ASSIGNMENT_PATTERN, "$1=[redacted]") .replace(URL_PATTERN, (match) => `[url:${pathFromUrl(match)}]`); + return redacted.length > 2048 ? `${redacted.slice(0, 2048)}...[truncated]` : redacted; }🤖 Prompt for 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. In `@packages/worker-runtime/src/logging.ts` around lines 217 - 224, The sanitizeString function truncates the string to 2048 characters before applying the redaction patterns, which can break secret patterns that span the truncation boundary and cause secrets to leak. Reverse the order of operations in the sanitizeString function: first apply all the redaction patterns using the replace() calls for API_KEY_PATTERN, BEARER_PATTERN, JSON_SECRET_ASSIGNMENT_PATTERN, SECRET_ASSIGNMENT_PATTERN, and URL_PATTERN against the original value, then apply the 2048-character truncation logic to the redacted result.
🤖 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 `@packages/worker-runtime/src/logging.ts`:
- Around line 51-52: The JSON_SECRET_ASSIGNMENT_PATTERN regex uses [^"]* to
match secret values, which stops at escaped quotes within the value, leaving
part of the secret unredacted. For example, a token value like abc\"def gets
only partially redacted. Replace the [^"]* pattern in the
JSON_SECRET_ASSIGNMENT_PATTERN constant with a pattern that properly handles
escaped characters, such as (?:\\.|[^"\\])* or (?:[^"\\]|\\.)*. This ensures
that escaped quotes and other escaped characters within JSON string values are
treated as part of the value rather than terminators, so the entire secret is
redacted correctly.
---
Outside diff comments:
In `@packages/worker-runtime/src/logging.ts`:
- Around line 217-224: The sanitizeString function truncates the string to 2048
characters before applying the redaction patterns, which can break secret
patterns that span the truncation boundary and cause secrets to leak. Reverse
the order of operations in the sanitizeString function: first apply all the
redaction patterns using the replace() calls for API_KEY_PATTERN,
BEARER_PATTERN, JSON_SECRET_ASSIGNMENT_PATTERN, SECRET_ASSIGNMENT_PATTERN, and
URL_PATTERN against the original value, then apply the 2048-character truncation
logic to the redacted result.
🪄 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 Plus
Run ID: ecd9ebf5-0e0d-403f-9804-d557c4fbe2ab
📒 Files selected for processing (3)
packages/worker-runtime/src/logging.tspackages/worker-runtime/src/sentry-sanitize.tspackages/worker-runtime/src/sentry.test.ts
Issue: AP-384
|
agent-paste PR preview resources were cleaned up. The shared Preview GitHub Environment is retained for future preview deploys. |


Summary
Add targeted sanitized Sentry SDK logging for backend Workers so failures carry request/component context without turning Sentry into a full log drain.
Changes
beforeSendLogandbeforeSendsanitizers whenSENTRY_DSNis configured.onErrorpaths and jobs op logging through the helper.SENTRY_DSNto api, upload, content, jobs, stream, mcp, and apex without making deploy require it.Risk: HIGH
beforeSend/beforeSendLogstrip banned fields and tokenized paths.SENTRY_DSNremains optional.Test plan
pnpm --filter @agent-paste/worker-runtime build && pnpm --filter @agent-paste/worker-runtime testpnpm --filter @agent-paste/content testpnpm --filter @agent-paste/jobs testpnpm verifypnpm smoke:localpnpm test:coveragepnpm test:coverage:strictpnpm verifygit diff --checkgitleaks protect --staged --redactIssue: AP-384
Summary by CodeRabbit
infoevents to Sentry when a valid DSN is available.