chore(canary-phase6): kubeconfig generator complete

Phase 6 ships the fifth generator in the canary registry plus the
first fake-API style trigger response. kubeconfig canary tokens are
rendered YAML pointing kubectl at /k/{id}; on any HTTP call to that
path, the handler records kubectl_path/method/query/ua in event.Extra
and responds with a Kubernetes-shaped 403 Status JSON whose message is
parameterized by the resource and the HTTP verb so the attacker sees
real-looking "Error from server (Forbidden): X is forbidden..." output.

Implementation commits in this phase:
  - 6f994f37 feat(canary): kubeconfig generator + YAML template
  - bd0c6646 feat(canary): kubeconfig fake K8s API handler
    (forbidden response)
  - ceec4d37 feat(canary): register kubeconfig generator in registry
  - 982beafd fix(canary-phase6): address audit nit before rollup

Deliverables:
  - text/template-rendered kubeconfig with cluster=prod-cluster,
    user=svc-backup-reader, bearer=t.ID, server=baseURL+/k/+t.ID
  - template.yaml.tmpl convention (not template.yaml) so pre-commit
    check-yaml hook doesn't trip on Go template tokens
  - K8s Status JSON 403 response with verb derived from HTTP method
    (GET/HEAD → list, POST → create, PUT → update, PATCH → patch,
    DELETE → delete, others → list) — richer than spec §9.5's
    hardcoded "list", forensic enhancement
  - Resource extraction via path.Base with empty/root fallback to
    "resource"
  - Event.Extra captures kubectl_path/method/query/ua as JSON
  - Defense-in-depth: nil-token path returns 403 + valid Status JSON
    + nil event (FK-safe), response shape byte-identical to valid-
    token case modulo the resource/verb message slots
  - Registry expanded 4 → 5; pending list shrinks to {envfile, mysql}
  - ~36 test cases including YAML round-trip parsing, 11-subcase IP
    precedence parity with docx/pdf, verb-derivation table, status
    JSON shape validation, nil-token shape equivalence

Audit outcome (2 agents in parallel per standing pattern):
  - superpowers:code-reviewer: PASS (0 BLOCKER, 0 SHOULD-FIX, 5 NITs
    all marked optional / defensible / not-actionable)
  - general-purpose spec-adherence vs §9.5 + §8.5: PASS (0 BLOCKER,
    0 SHOULD-FIX, 1 actionable NIT cleared in 982beafd, 2 INFO items
    documenting sanctioned deferrals to later phases)

Pre-rollup acceptance gates clean at HEAD 982beafd:
  - go build ./... + go vet ./... clean
  - go test -race -timeout=60s ./... — all packages pass
  - go test -tags=integration -race -timeout=300s ./internal/token/...
    ./internal/event/... — all pass
  - golangci-lint run ./... → 0 issues.
  - grep -rn "//nolint" --include="*.go" returns nothing
  - BACKLOG.md open section still _(none)_

Forward state for Phase 7 (envfile generator + bait recipes): pure-
string-rendering generator using crypto/rand + math/rand seeded from
crypto/rand for shuffled bait sections (aws/stripe/github/db) plus
the actual canary URL line embedded as INTERNAL_METRICS_ENDPOINT.
Trigger pattern returns to webbug-style (/c/{id} GIF). No new HTTP
route shape needed.
This commit is contained in:
CarterPerez-dev 2026-05-13 14:26:34 -04:00
parent 982beafdc9
commit a36292b786

Diff Content Not Available