Skip to content

feat: add send-event and send-envelope commands with DSN auth#921

Open
BYK wants to merge 13 commits intomainfrom
feat/send-event-envelope
Open

feat: add send-event and send-envelope commands with DSN auth#921
BYK wants to merge 13 commits intomainfrom
feat/send-event-envelope

Conversation

@BYK
Copy link
Copy Markdown
Member

@BYK BYK commented May 5, 2026

Summary

Implements sentry send event and sentry send envelope for old sentry-cli parity. Ref #600.

These are the first commands in the new CLI that authenticate via a DSN (not a Bearer token), so no sentry auth login is needed — provide a DSN from --dsn, SENTRY_DSN env var, or auto-detection.

Command structure

sentry send event    ← canonical
sentry send envelope ← canonical

sentry send-event    ← hidden bw-compat alias (old sentry-cli users)
sentry send-envelope ← hidden bw-compat alias (old sentry-cli users)

sentry send event

Send a Sentry event from CLI flags or a JSON file:

# Inline from flags
sentry send event -m "Deployment failed" -l error --tag env:prod --tag region:us

# From a JSON event file
sentry send event ./crash.json

# Raw mode (send bytes without re-parsing)
sentry send event --raw ./event.json

Flags match the old sentry-cli: -m/--message, -l/--level, -r/--release, -E/--env, -t/--tag (variadic), -e/--extra (variadic), -u/--user (variadic, routes id/email/username/ip_address to known User fields, rest to user.data), -f/--fingerprint (variadic), --dist, --platform, --timestamp, --no-environ, --raw, --dsn.

sentry send envelope

Send a pre-built Sentry envelope file:

sentry send envelope ./captured.envelope
sentry send envelope --raw ./captured.envelope   # skip validation
sentry send envelope ./a.envelope ./b.envelope   # multiple files

Architecture

  • src/commands/send/index.ts — route group
  • src/lib/envelope/transport.ts — shared DSN-based sender using @sentry/core (makeDsn, getEnvelopeEndpointWithUrlEncodedAuth, serializeEnvelope) — no new dependencies
  • src/lib/envelope/event-builder.ts — builds a Sentry Event from CLI flags
  • auth: "dsn" on buildCommand — new option that skips Bearer token guard and .sentryclirc URL trust check, distinct from auth: false

Tests

48 new tests across 4 files, written TDD-first before implementation.

Implements sentry send-event and sentry send-envelope — the first
commands that authenticate via a DSN (not a Bearer token), matching
the old sentry-cli behaviour.

Architecture:
- src/lib/envelope/transport.ts: shared DSN-based envelope sender
  using @sentry/core (makeDsn, getEnvelopeEndpointWithUrlEncodedAuth,
  serializeEnvelope) — no new dependencies
- src/lib/envelope/event-builder.ts: builds a Sentry Event from CLI
  flags (message, level, tags, extras, user, fingerprint, etc.)
- auth: 'dsn' in buildCommand: skips Bearer token guard and RC URL
  check for DSN-only commands

send-event flags (matching old CLI):
  --dsn, -m/--message, -l/--level, -r/--release, -E/--env,
  -t/--tag (variadic), -e/--extra (variadic), -u/--user (variadic),
  -f/--fingerprint (variadic), --dist, --platform, --timestamp,
  --no-environ, --raw

send-envelope flags:
  --dsn, --raw (send bytes without parsing)

Tests: 48 new tests across 4 files (TDD — tests written first)
  - transport: URL construction, auth params, error handling
  - event-builder: parseKeyValue, parseUserFields, buildEventFromFlags
  - send-event command: inline, file, JSON output, missing DSN
  - send-envelope command: valid file, raw mode, invalid envelope,
    multiple files, missing DSN
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://cli.sentry.dev/_preview/pr-921/

Built to branch gh-pages at 2026-05-05 19:27 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Codecov Results 📊

6737 passed | Total: 6737 | Pass Rate: 100% | Execution Time: 0ms

📊 Comparison with Base Branch

Metric Change
Total Tests 📈 +55
Passed Tests 📈 +55
Failed Tests
Skipped Tests

All tests are passing successfully.

✅ Patch coverage is 82.02%. Project has 13593 uncovered lines.
✅ Project coverage is 76.75%. Comparing base (base) to head (head).

Files with missing lines (4)
File Patch % Lines
src/commands/send-event.ts 78.19% ⚠️ 53 Missing
src/lib/envelope/event-builder.ts 78.48% ⚠️ 17 Missing
src/lib/envelope/transport.ts 85.14% ⚠️ 11 Missing
src/commands/send-envelope.ts 87.65% ⚠️ 10 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    76.67%    76.75%    +0.08%
==========================================
  Files          303       308        +5
  Lines        57977     58473      +496
  Branches         0         0         —
==========================================
+ Hits         44454     44880      +426
- Misses       13523     13593       +70
- Partials         0         0         —

Generated by Codecov Action

Comment thread src/lib/envelope/event-builder.ts
Comment thread src/commands/send-event.ts
Comment thread src/commands/send-envelope.ts
sentry send event  -- canonical new interface
sentry send envelope

sentry send-event    -- hidden bw-compat alias (old sentry-cli)
sentry send-envelope -- hidden bw-compat alias (old sentry-cli)
Comment thread src/lib/envelope/event-builder.ts
Comment thread src/commands/send-event.ts Outdated
Comment thread src/lib/envelope/event-builder.ts
Comment thread src/commands/send-envelope.ts
Comment thread src/commands/send-event.ts
- parseTimestamp now throws ValidationError on invalid input instead of
  silently falling back to Date.now() (Seer/Cursor)
- Environ spread order fixed: process.env goes first so user --extra
  environ:val correctly overrides it (Cursor)
- Raw mode no longer reads file twice: decode bytes in-memory instead
  of re-reading (Cursor)
- Fixed --raw help text: sends raw bytes directly, not 'inside an envelope'
  (Sentry)
- send-envelope now errors when no files provided (Sentry)
- send-event --raw in inline mode now throws ValidationError (Sentry)
@BYK
Copy link
Copy Markdown
Member Author

BYK commented May 5, 2026

Fixed all 6 bot findings in 7e33546:

  • Invalid --timestamp now throws ValidationError (Cursor/Seer)
  • environ spread order fixed so user --extra environ:val is not overwritten (Cursor)
  • Raw mode decodes bytes in-memory instead of re-reading file (Cursor)
  • --raw help text corrected (Sentry)
  • send-envelope now errors when no files provided (Sentry)
  • send-event --raw in inline mode now throws ValidationError (Sentry)

Comment thread src/commands/send-event.ts Outdated
Comment thread src/lib/envelope/event-builder.ts
BYK added 2 commits May 5, 2026 17:30
- Remove undocumented DSN auto-detection claim from send-event.ts
  module comment and requireDsn error message (only --dsn and
  SENTRY_DSN are actually supported)
- Use Number.isFinite instead of !Number.isNaN to reject Infinity
  and -Infinity as timestamp values
- parseTimestamp: remove && num > 0 guard — epoch-0 and negative
  timestamps are valid; the old guard silently corrupted them to
  year 2000 / year 3600 via Date.parse fallthrough
- resolveDsn: trim whitespace from --dsn flag and SENTRY_DSN env var
  (leading space / trailing newline from shell caused confusing error)
- transport test: use .toThrow(ValidationError) not bare .toThrow()
- send.md: remove false claim that DSN auto-detects from project files
- buildFilePayload + send-envelope: wrap Bun.file reads in try/catch,
  surface ENOENT and parse errors as ValidationError not raw stacks
- Document that --message is ignored when file args are provided
- Add tests: ENOENT → ValidationError, --raw without file → error,
  no files for send-envelope → ValidationError, DSN whitespace trim,
  whitespace trim for SENTRY_DSN env var
Comment thread src/commands/send-event.ts Outdated
Comment thread src/commands/send-event.ts Outdated
Comment thread src/commands/send-envelope.ts Outdated
…eation in try/catch

- Centralise ENOENT/IO error handling into shared readFileBytes() in transport.ts
- Removes duplicated file-reading error block from both send-event.ts and send-envelope.ts
- Wrap makeDsn() call in try/catch to guard against future SDK internal throws
- Wrap createEventEnvelope()+serializeEnvelope() in try/catch with descriptive ValidationError

Addresses Sentry Seer findings (medium) and Cursor Bugbot finding (low) on PR #921.
Comment thread src/commands/send-event.ts Outdated
…atch

Mirrors the file-based path's error handling — catches any internal
SDK errors and re-throws as ValidationError.
Comment thread src/commands/send-envelope.ts
Calling buildEnvelopeUrl(dsn) before the file read loop ensures
invalid DSNs are caught upfront rather than after unnecessary I/O,
consistent with send-event's behavior.
Comment thread src/lib/envelope/transport.ts
getEnvelopeEndpointWithUrlEncodedAuth appends /<version> internally,
so passing 'sentry-cli/dev' produced the malformed identifier
sentry_client=sentry-cli/dev/dev on every envelope request.

Now passes bare name 'sentry-cli' and lets the SDK append '/dev'.
Copy link
Copy Markdown
Contributor

@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.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b6f5bab. Configure here.

Comment thread src/lib/envelope/transport.ts Outdated
Comment thread src/lib/envelope/transport.ts Outdated
BYK added 2 commits May 5, 2026 19:15
…r message

- makeDsn may throw SentryError internally; wrap in try/catch for safety
- requireDsn error message now uses canonical 'sentry send event' instead
  of hardcoded 'sentry send-event' (wrong for send-envelope callers)
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