Commit Graph

2 Commits

Author SHA1 Message Date
CarterPerez-dev 593433fc03 feat(canary): manage page handlers + DTOs (GET + DELETE /m/{manage_id})
Adds the HTTP layer for spec §8.4. The UUID in the URL is the
capability — no other auth required, by design.

- token/dto.go: ManageTokenView (slimmer than Response — no manage_id,
  no manage_url, no metadata, since the user is already on the manage
  page and those would be redundant), ManagePage{NextCursor, HasMore},
  ManageResponse{Token, Events, EventsTotal, EventsSilencedActive, Page}.
  Token.ToManageView(triggerURL) builder. Events use the existing
  event.Response (already matches spec shape exactly).
- token/handler.go: EventQuery + DedupCounter interfaces declared near
  the existing EventRecorder + FingerprintRecorder; same dependency-
  injection style. NewHandler signature gains the two new args (5 → 6;
  test sites + main.go updated).
- GetManage(w, r): parses ?cursor= (int64, must be >= 0) and ?limit=
  (defaults 20, capped at 100). Returns 404 envelope for unknown
  manage_id (envelope, not bare http.NotFound, so frontend gets a
  parseable error code). 400 BAD_CURSOR for non-numeric or negative.
  Calls svc.GetByManageID + eventQuery.ListByToken + CountByToken +
  dedupCounter.CountActiveDedup; assembles the manage payload.
- DeleteManage(w, r): 204 on success, 404 on miss. Cascade-delete is
  via the existing tokens-events FK ON DELETE CASCADE.
- buildPage helper: NextCursor is the string of the last event's ID
  iff len(events) == limit (matches spec example "next_cursor": "41").

Tests cover happy path, 404 on unknown id, 400 on bad/negative cursor,
?limit= respected, ?limit=999 capped at 100, DELETE happy + 404.
2026-05-14 01:07:09 -04:00
CarterPerez-dev 0a456f97ae feat(canary): token HTTP handlers (API + trigger routes)
Phase 9 task 9.6.

Routes:
  RegisterAPIRoutes(r):
    GET  /tokens/types  → static list of 7 type descriptors
    POST /tokens        → CreateToken (validation + service.Create)

  RegisterTriggerRoutes(r):
    GET  /c/{id}                 → HandleTrigger (webbug, slowredirect,
                                    docx, pdf, envfile use this path)
    POST /c/{id}/fingerprint     → HandleFingerprint (slowredirect)
    HandleFunc /k/{id}           → HandleTrigger (kubeconfig, bare path)
    HandleFunc /k/{id}/*         → HandleTrigger (kubeconfig wildcard,
                                    any HTTP method)

HandleTrigger flow:
  - extract token id from chi.URLParam
  - service.GetByID (returns nil-nil for not-found)
  - if token exists and !enabled, treat as unknown
  - resolve generator (known token → its type; unknown + path
    prefix /k/ → kubeconfig; unknown otherwise → webbug)
  - generator.Trigger(ctx, tok, r) → event + response
  - record event via EventRecorder interface if present (Phase 10
    wires real event.Service)
  - write response: headers + body OR 302 + Location for redirect

CreateToken flow:
  - 64KB body cap via http.MaxBytesReader
  - JSON decode (bad → 400 BAD_JSON)
  - extract fingerprint + real IP via middleware helpers
  - service.Create
  - error switch: validation/unknown-type/destination/include-keys
    map to 400; generator-failure to 500
  - happy path: 201 with {token, artifact} envelope per spec §8.2

ArtifactJSON discriminator pattern:
  - kind=url     → url + destination_url
  - kind=file    → filename + content_type + content_b64 (base64)
  - kind=text    → filename + content_type + content (raw)
  - kind=conn... → connection_string

Tests (~10 cases): 7-type list, happy path with envelope assertion,
bad JSON, validation failure, known-token records event + writes
response, unknown-token still returns shape (defense-in-depth),
disabled-token treated as unknown, fingerprint without recorder
returns 204, ArtifactJSON discriminator for all 4 kinds.

Phase 9 task 9.6 discharged. Wire-up + config + webbug refactor +
integration test next.
2026-05-13 15:16:41 -04:00