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
+45
View File
@@ -54,3 +54,48 @@ func TestLinkForGit(t *testing.T) {
t.Errorf("LinkFor git github = {%q,%s}", l.URL, l.Source)
}
}
// A GitHub PAT / Stripe key arrives from the env or file scanner with no host of
// its own, only a non-secret service hint. HostFor must turn that hint into the
// curated change-password host so the guided worklist gets a real link.
func TestHostForServiceHint(t *testing.T) {
cases := []struct {
service string
want string
}{
{"github", "github.com"},
{"stripe", "stripe.com"},
{"unknown", ""},
}
for _, c := range cases {
cred := discover.Credential{
Source: "env",
Identity: ".env / API_KEY",
Meta: map[string]string{discover.MetaService: c.service},
}
if got := HostFor(cred); got != c.want {
t.Errorf("HostFor(service=%q) = %q, want %q", c.service, got, c.want)
}
}
}
func TestLinkForServiceHint(t *testing.T) {
cases := []struct {
service string
wantURL string
}{
{"github", "https://github.com/settings/tokens"},
{"stripe", "https://dashboard.stripe.com/apikeys"},
}
for _, c := range cases {
cred := discover.Credential{
Source: "env",
Identity: ".env / TOKEN",
Meta: map[string]string{discover.MetaService: c.service},
}
l := LinkFor(cred)
if l.Source != SourceKnown || l.URL != c.wantURL {
t.Errorf("LinkFor(service=%q) = {%q,%s}, want {%q,known}", c.service, l.URL, l.Source, c.wantURL)
}
}
}