chore(canary-phase7): envfile generator complete
Phase 7 ships the sixth generator in the canary registry. envfile canary tokens are rendered .env-style text artifacts containing shuffled bait sections (aws/stripe/github/db) plus an INTERNAL_METRICS_ENDPOINT line carrying the actual canary URL. The bait keys look real enough to pass gitleaks-class regex scanners but are NOT live credentials — the detection mechanism is the embedded canary URL. Implementation commits in this phase: -003aa997feat(canary): envfile bait recipes (aws/stripe/github/db) -2a2a3c4dfeat(canary): envfile generator (shuffled bait + embedded canary URL) -1cde61effeat(canary): register envfile generator in registry Deliverables: - envfile/recipes/ sub-package with 4 bait recipes + shared crypto/rand helpers (RandomAlnumUpper/RandomAlnumMixed/ RandomHexLower/RandomBase64/RandomChoice) - aws.go: AKIA + 16-char [A-Z0-9] body + 40+ base64 secret + region + bucket - stripe.go: sk_live_/pk_live_/whsec_ + 24/24/32 base62 bodies - github.go: ghp_ + 42 base62 (36 body + 6 checksum) + base64 deploy key - db.go: postgres://app_writer:<24-char>@db.internal:5432/app_prod + redis://default:<32-char>@cache-prod.internal:6379/0 - envfile/generator.go: extractIncludeKeys with 7 defensive fallback cases (empty/invalid/wrong-type/null/empty-array/missing/whitespace) + Fisher-Yates shuffle on crypto/rand + canary section appended last before shuffle so canary URL can land at any position - Spec §9.6 deviation: crypto/rand throughout (vs spec's math/rand + rng.Shuffle) — matches Phase 0 supplement's discipline, no gosec G404 fight, consistent with Phase 5 (pdf) and Phase 6 (kubeconfig) - Trigger: byte-identical content-copy of webbug/docx/pdf (200 + pixel.Clone GIF + cache headers + realIP triplet) - Registry expanded 5 → 6; pending list shrinks to {mysql} (1 remaining — Phase 8) - ~60 test cases across recipes + generator including 11-subcase IP precedence parity, 6 malformed-metadata fallback subcases, shuffle variability across 30 invocations, format-regex assertions per recipe, URL parsing for postgres/redis (real net/url validation), token-id-leak invariant (uniqueprobe appears exactly once) Audit outcome (2 agents in parallel per standing pattern): - superpowers:code-reviewer: PASS (0 BLOCKER, 0 SHOULD-FIX, 6 NITs all marked informational / below-threshold / acceptable-trade) - general-purpose spec-adherence vs §9.6 + §8.5: PASS (0 BLOCKER, 0 SHOULD-FIX, 2 LOW informational items — hostname pick is one of spec's enumerated values, extra realism keys are additions not violations) No audit-fix commit needed this phase — zero actionable findings, matching the Phase 5 pattern (Phase 6 had one actionable header- filename NIT cleared before rollup; Phase 7 is fully clean). Pre-rollup gate clean at HEAD 1cde61ef: - go build / 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)_ - go.mod surface unchanged (no new deps for this phase) Forward state for Phase 8 (mysql fake server): the LAST generator. TCP wire-protocol listener (NOT HTTP) that accepts MySQL handshake, extracts username from the auth packet, looks up token by metadata.mysql_username, records event, returns ERR_Packet 1045. First time we spawn a non-HTTP listener from main.go (cmd/canary wire-up via `if cfg.MySQL.Enabled { go mysql.Run(...) }`). All 7 generators close after Phase 8.
This commit is contained in:
parent
1cde61efbb
commit
3d9b97da21