Skip to content

Phase 3: Attachment envelope parsing + binary-safe ingestion #233

Description

@ajianaz

Goal

Parse Sentry attachment envelope items (binary payloads like screenshots, log files) and make them viewable/downloadable from the TrapFall event detail page.

Context

Attachments are fundamentally different from other envelope items — they are binary, not JSON. The current parse_envelope_text() reads line-by-line which cannot handle binary data. This phase requires rewriting the envelope parser to be length-based (read N bytes) instead of purely line-based (read until \n).

Sentry SDKs (JS/SvelteKit, Flutter, Python) can auto-attach screenshots, minidumps, and log files to error events. This is especially useful for frontend errors via @sentry/sveltekit (attachScreenshot: true).

Depends on: Phase 1 (ParsedEnvelope return type)

Attachment Envelope Format

{"type":"attachment","length":24567,"filename":"screenshot.png","attachment_type":"event.attachment","content_type":"image/png"}
<binary PNG data — exactly 24567 bytes>

Header fields:

Field Type Description
type string Always "attachment"
length int Byte length of binary payload
filename string Original filename
attachment_type string? "event.attachment" (default), "event.minidump", custom
content_type string? MIME type (image/png, text/plain)

Tasks

3a. trapfall-proto — Wire types

  • Add Attachment struct: filename, content_type, attachment_type, data: Vec<u8>
  • Extend ParsedEnvelope with attachments: Vec<Attachment>

3b. trapfall-ingest — Binary-safe parser ⚠️ breaking change

  • Rewrite parse_envelope_text() to be length-aware:
    • When item_type == "attachment" and length is present → read exactly N bytes from raw buffer
    • When length is absent → fallback to line-based JSON parsing (backward compat)
  • This likely requires changing parse_envelope_text() to work on &[u8] instead of &str for the body extraction part
  • Handle case: envelope with event + attachment (SDK sends them together)
  • Add tests: JSON event + binary attachment in same envelope
  • Add tests: attachment with known bytes, verify exact round-trip
  • Add tests: malformed attachment (wrong length) → graceful skip

3c. trapfall-db — Schema + storage

  • SQLite migration: attachments table
  • Postgres migration: same
  • Storage strategy:
    • Small files (<1MB): base64 in data column
    • Large files: write to disk (/data/attachments/{project_id}/{event_id}/{filename}), DB stores storage_path
  • Add queries: get_attachments(event_id), insert_attachment()
  • Add cleanup: delete disk files when event/project is deleted

3d. Dashboard — Attachment UI

  • Event detail page: list attachments with filename, size, content_type
  • Image attachments: inline preview (thumbnail)
  • Other files: download link
  • Storage indicator: disk usage per project

Storage Considerations

  • Attachments can be large (screenshots ~200KB, minidumps ~10MB)
  • Need configurable max size limit (e.g., 50MB per file)
  • Consider retention policy: auto-delete attachments older than N days
  • SQLite data column with base64 = 33% size overhead — disk storage preferred for large files

Risks

  • Binary parsing is the most error-prone part of this entire milestone
  • Wrong length handling could misalign subsequent item parsing in the same envelope
  • Must handle gracefully: log warning, skip attachment, continue parsing remaining items

Dependencies

Effort

~1-2 days


Sub-issues:

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority:mediumP2 - Fix in next batchscope:dashboardSvelteKit dashboard UIscope:dbDatabase schema / migrationscope:ingestEnvelope ingest / parser changesscope:prototrapfall-proto wire typestype:envelopeSentry envelope item type expansion

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions