PoppyPetitions

repo: ~/Projects/PoppyPetitions · 6 commits · 0 in last 24h, 0 in last 7d ·

Search the build

6 commits indexed

  1. 77c4ca8 2026-05-31 PoppyPetitions P1: dedicated audit_events table + lib/audit.ts best-effort logger
  2. 438eef6 2026-05-30 P1-F: compute_usage NULL race — safeNumber + petition_id backfill
  3. b444995 2026-05-30 P1-E: agent_id session-binding via validate-and-audit (DTD verdict B)
  4. f771a91 2026-05-30 docs: redact secret literal from db.ts scrub-comment (gitleaks hygiene)
  5. 7f44f02 2026-05-30 P1-B: defensive input-length caps on petition write endpoints
  6. f3826a6 2026-05-06 initial scaffold (2026-05-06 overnight session)

Authors

Agents used

  • none detected

Skills used

  • /comment3
  • /audit2
  • /vote2
  • /seed2
  • /write1
  • /cleaned1
  • /gemini1
  • /undefined1
  • /bigint1
  • /route1
  • /active1
  • /validate1
  • /reason1
  • /non-string1

Creative ideas + design notes

Commits with substantial prose (≥120 chars) — the rationale behind each move.

77c4ca8 · 2026-05-31 · PoppyPetitions P1: dedicated audit_events table + lib/audit.ts best-effort logger
Fills the gap from P1-E (b444995), which stored the session<->agent binding
in compute_usage.metadata - that only has rows when Gemini bills compute, so
non-billing audit-worthy actions (denied agent lookups, rejected oversized
writes, logins) left no trail. New poppy.audit_events table + logAudit() cover
all AI/write routes, best-effort (never throws, never blocks the request).

- migrations/0001_audit_events.sql: idempotent, additive-only, no down-migration.
  Apply manually to the poppy DB. NOT to be applied to the compromised prod
  Kamatera host until it is rebuilt/cleaned.
- lib/audit.ts: logAudit / requestProvenance / auditFromRequest.
- Full-project tsc --noEmit: zero errors.
- Wiring logAudit into the petitions/vote/comment POST routes is a separate
  follow-up, beyond this board item's scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
438eef6 · 2026-05-30 · P1-F: compute_usage NULL race — safeNumber + petition_id backfill
Two NULL-race / data-integrity issues in compute_usage:

1. petitions POST always wrote compute_usage.petition_id=NULL even on
   success — INSERT order was compute_usage → petition, so the FK wasn't
   known when the audit row landed. Fix: capture compute_usage.id via
   RETURNING, then UPDATE petition_id after the petition INSERT succeeds.
   Best-effort backfill — if the UPDATE fails the audit row stays unlinked
   (same as today), but on the happy path analytics can now join the two.

2. All four routes (petitions/vote/comment/seed) read geminiResult.{input,
   output,total}Tokens raw from lib/gemini.ts which uses ?? 0 — catches
   null/undefined but NOT NaN. A malformed Gemini response can leak NaN
   into pg INSERTs (int/bigint columns throw, numeric throws, double
   precision accepts silently). Fix: safeNumber() coerces NaN/Infinity to
   0 at the boundary before every compute_usage / agents UPDATE.

Also rolled the existing buildAuditMetadata() into agents/seed/route.ts
(the P1-E change covered the three write routes but missed seed).

All five files esbuild-parse clean.
b444995 · 2026-05-30 · P1-E: agent_id session-binding via validate-and-audit (DTD verdict B)
Add lib/agentGuard.ts (resolveActingAgent + buildAuditMetadata) and wire into
the three write routes (petitions POST, vote POST, comment POST). Closes two
gaps in the previous existence-only check:

1. resolveActingAgent now requires is_active=true. Returns 404 not-found,
   409 inactive, 500 db-error — distinct codes so callers can branch.

2. compute_usage metadata JSONB now carries acting_session (the verifyAuth
   user) + ts. Forensic queries can reconstruct the session ↔ agent ↔ action
   triple from one row.

DTD picked B over A (true session-binding via cookie) and C (mixed default+
override): single-admin loopback model doesn't justify the UX refactor A
requires; the threat being closed is the agent existence/active gap + the
absence of forensic traceability, and B handles both without schema change.

No UI changes. No schema migration (metadata is JSONB). All four files
esbuild-parse clean.
7f44f02 · 2026-05-30 · P1-B: defensive input-length caps on petition write endpoints
Add lib/validate.ts (clampLen / firstLengthViolation + LIMITS) and reject
oversized free-text inputs with HTTP 400 before any DB write or Gemini call,
hardening against prompt-injection / abuse payloads.

Caps: title 200, summary/comment/reason 2000, body 5000, identifiers 200.
- petitions POST: title, summary, body, author_id
- vote POST: agent_id, petition id (rationale is AI-generated)
- comment POST: comment_body, agent_id, parent_id, petition id

Guards only reject present oversized strings; absent/non-string values pass
through so ai_generate paths and existing required-field errors are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

File tree

48 files tracked. Click any to browse the source at HEAD.

Other build journals

← Patty  ·  all 4 projects  ·  SDCC Stories →

Export

commits.csv · feed.atom · project.json · commits.json

rendered in 1ms