guide: wire GitHub PATs + Stripe keys into the guided worklist

GitHub PATs and Stripe secret keys have no scriptable rotation API (GitHub's
create-token API was removed in 2020; Stripe has no create-key endpoint), so
they belong in the guided change-password layer, not as Rotators. But they
arrive from the env/file scanner as generic Source="env" tokens with no host,
so the worklist showed them as "manual — no web page".

Recognise them by their well-known PUBLIC value prefixes (ghp_/gho_/ghs_/
github_pat_/…, sk_live_/sk_test_/rk_live_/…) at scan time and record a
non-secret Meta["service"] hint — a fixed service NAME, never the secret bytes.
discover.ServiceForSecret does the detection; env.go attaches it for generic
tokens, file.go before Store wipes the buffer. links.HostFor consults the hint
and maps github→github.com / stripe→stripe.com, so the curated change-password
URLs (already in the table) now light up for these credentials.

Leak-safe (service name is derived from a public prefix, not the secret) and
verified by the existing assertNoLeak checks. go build/vet clean; full suite
179 tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-06-20 15:35:42 -07:00
parent 88e603f3c0
commit d237098d83
7 changed files with 158 additions and 1 deletions
+5 -1
View File
@@ -118,8 +118,12 @@ func TestEnvScanner(t *testing.T) {
t.Fatalf("want 5 creds (secret-ish + DB URLs), got %d: %+v", len(creds), creds)
}
idents := byIdentity(creds)
if _, ok := idents[".env / STRIPE_API_KEY"]; !ok {
if sk, ok := idents[".env / STRIPE_API_KEY"]; !ok {
t.Errorf("missing STRIPE_API_KEY; got %v", idents)
} else if sk.Meta[MetaService] != "stripe" {
// The sk_live_ prefix must be recognised as a non-secret service hint so the
// worklist can offer a guided change-password page (Stripe has no rotate API).
t.Errorf("STRIPE_API_KEY missing service hint; Meta=%v", sk.Meta)
}
for id := range idents {
if strings.Contains(id, "PORT") || strings.Contains(id, "DEBUG") {