Skip to content

feat(hub): central mapDBError/writeDBErr error-sanitization helper (#74 foundation)#280

Merged
physercoe merged 1 commit into
mainfrom
fix/db-error-mapper
Jun 14, 2026
Merged

feat(hub): central mapDBError/writeDBErr error-sanitization helper (#74 foundation)#280
physercoe merged 1 commit into
mainfrom
fix/db-error-mapper

Conversation

@physercoe

Copy link
Copy Markdown
Owner

What

#74 (CRITICAL): ~470 handler sites do writeErr(w, http.StatusInternalServerError, err.Error()), returning raw SQLite/driver text (constraint details, table/column names, query fragments, syntax errors) verbatim in JSON responses — information disclosure.

This PR lands the foundation the sweep will build on (no behavior change to existing sites yet):

  • mapDBError(err) → (status, safeMsg): sql.ErrNoRows→404, SQLITE_CONSTRAINT→409, SQLITE_FULL→507, SQLITE_READONLY→503, context cancel/deadline→408, everything else (incl. syntax errors)→500 "internal error". Raw driver text never reaches the client.
  • (*Server).writeDBErr(w, err): the safe drop-in for the leaky pattern — maps via mapDBError, logs the raw error server-side on any 5xx (operators keep full diagnostics), writes the sanitized envelope.

Test

Drives a real in-memory UNIQUE violation → asserts 409 + message does not leak SQL; plus ErrNoRows (and wrapped) → 404, context cancel → 408, opaque error → 500 generic.

Follow-up (same issue, staged next)

Sweep the ~470 writeErr(w, 500, err.Error()) sites → s.writeDBErr(w, err), plus the per-handler status-code fixes (#74.4: search FTS syntax → 400; agent_turns ErrNoRows → 404). Mechanical; runs as its own reviewable PR.

🤖 Generated with Claude Code

…ients (#74)

#74: ~470 handler sites do writeErr(w, 500, err.Error()), returning raw
SQLite/driver text (constraint details, table/column names, query fragments,
syntax errors) verbatim in JSON responses — information disclosure.

This lands the foundation the sweep will use:
- mapDBError(err) → client-safe (status, message): sql.ErrNoRows→404,
  SQLITE_CONSTRAINT→409, SQLITE_FULL→507, SQLITE_READONLY→503, context
  cancel/deadline→408, everything else (incl. syntax errors)→500
  "internal error". No raw driver text ever reaches the client.
- (*Server).writeDBErr(w, err): the safe drop-in for
  `writeErr(w, http.StatusInternalServerError, err.Error())` — maps via
  mapDBError, logs the RAW error server-side on any 5xx (operators keep full
  diagnostics), writes the sanitized envelope.

Test drives a real in-memory UNIQUE violation → 409 and asserts the message
does not leak SQL; plus ErrNoRows(+wrapped)→404, cancel→408, opaque→500.

Follow-up (same issue): sweep the ~470 `writeErr(w, 500, err.Error())` sites
to `s.writeDBErr(w, err)`, and the per-handler status-code fixes (#74.4:
search FTS syntax→400, agent_turns ErrNoRows→404).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@physercoe physercoe merged commit 7ecfde0 into main Jun 14, 2026
4 checks passed
@physercoe physercoe deleted the fix/db-error-mapper branch June 14, 2026 02:37
physercoe pushed a commit that referenced this pull request Jun 14, 2026
Hub robustness sweep (#74#79) + Projects-tab segmented sub-tabs.
- ADR-045 D4 storage maintenance (#288)
- raw-SQL-error no-leak sweep (#280/#283), rows.Err audit (#286),
  FTS/routing status codes (#287), owner-or-steward gate (#281),
  read-pool cap + rows.Close defer (#292), additive pagination (#293)
- segmented Projects | Workspaces tabs (#289)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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