Commit graph

3 commits

Author SHA1 Message Date
e057255f4f fix(24): address code-review findings — PATCH identity guard, empty-array tombstone, health-check timeout, record-key normalization
Two critical issues from the post-phase code review:

- PATCH /api/route53/zones/[zoneId]/records/[recordId] never verified the
  request body's name/type/setIdentifier matched the record identified by
  the URL. A mismatch would silently UPSERT a brand-new AWS recordset
  (leaving the original live and untouched) while corrupting the mirror's
  record_key invariant. Now rejects with 400 if any of those three fields
  differ from the existing record — renaming/retyping is delete-plus-create,
  not an update.

- route53-sync-service.ts's syncZones()/syncRecords() tombstone queries used
  "id <> ALL(seenIds)" style queries with no empty-array guard — a
  successful-but-empty AWS response would soft-delete every previously
  synced zone/record in one shot. Same bug class already fixed in
  pax8-sync-service.ts; now guarded the same way here.

Two smaller fixes:

- checkRoute53()'s AWS auth probe had no timeout, unlike every other
  integration's liveCheck() (8s AbortController). Added the same bound via
  the SDK's abortSignal option.
- buildRecordKey() relied on every caller to pre-normalize name/type case
  before calling it. Now normalizes internally (lowercase name, uppercase
  type) so the record_key invariant holds regardless of caller discipline.

Full REVIEW.md findings in 24-REVIEW.md. Two remaining Warnings (alias
records un-editable/undeletable, no admin-UI surface for route53_audit_log)
deliberately left as backlog items for a follow-up phase — out of scope for
a post-execution fix pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 23:15:27 -04:00
a7d6a04110 feat(24-05): CRUD write routes with pending/committed/failed audit lifecycle
- app/api/route53/zones/[zoneId]/records/route.ts: add POST (create)
- app/api/route53/zones/[zoneId]/records/[recordId]/route.ts: PATCH (update), DELETE
- All three write handlers: requireAdmin() first (D-04), validateRecordWrite() before
  any AWS command (D-01), createPendingAuditLog() before submitRecordChange() (D-07/SC-3)
- Committed path: markAuditCommitted -> insertPulseCrudHistory (pulse_crud, SC-4) ->
  mirror refresh; failed path: sanitizeAwsError -> markAuditFailed -> 502, no history row
- DELETE submits the exact mirror-read recordset (name/type/ttl/resourceRecords), never
  client-supplied values, per Route 53's exact-match delete requirement
- recordId zone-prefix mismatch guard (T-24-17): 400 before any audit row or AWS call
- No staged-approval mechanism anywhere (D-03) — mutation executes on first request
- tsc clean; npm test 554/556 passing (2 pre-existing itglue-search failures, unrelated,
  logged in deferred-items.md, already documented by plans 24-01/24-03)
2026-08-05 20:36:54 -04:00
53ec51c5e0 feat(24-05): read routes for zones, records, history, and sync status
- app/api/route53/sync/route.ts: POST (requireAdmin, fire-and-forget) + GET (requireAuth, status/history)
- app/api/route53/zones/route.ts: GET (requireAuth) list mirrored hosted zones
- app/api/route53/zones/[zoneId]/records/route.ts: GET (requireAuth) list records with type/search filters
- app/api/route53/zones/[zoneId]/records/[recordId]/history/route.ts: GET (requireAuth) append-only change ledger
- None gated on integration_settings disable toggle (D-10 — route53 is not a PAX8-style exception)
- /api/route53 confirmed absent from middleware.ts public-route list
- tsc clean
2026-08-05 20:33:58 -04:00