| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "errors" |
| 5 | "strings" |
| 6 | "testing" |
| 7 | ) |
| 8 | |
| 9 | // TestDeferredReloadFailedTextRedactsCredentials is the regression for the |
| 10 | // CodeQL credential-disclosure finding: a deferred-reload failure may carry |
| 11 | // provider error text containing passwords or resolved API keys, and the |
| 12 | // user-visible notice must never repeat them. |
| 13 | func TestDeferredReloadFailedTextRedactsCredentials(t *testing.T) { |
| 14 | for _, tc := range []struct { |
| 15 | name string |
| 16 | err error |
| 17 | secret string |
| 18 | }{ |
| 19 | {"password field", errors.New(`provider auth failed: password=hunter2hunter2`), "hunter2hunter2"}, |
| 20 | {"api key assignment", errors.New(`401 unauthorized: api_key=sk-abcdef1234567890SECRETKEY`), "sk-abcdef1234567890SECRETKEY"}, |
| 21 | {"bearer token", errors.New(`upstream rejected: Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U`), "eyJhbGciOiJIUzI1NiJ9"}, |
| 22 | } { |
| 23 | t.Run(tc.name, func(t *testing.T) { |
| 24 | text := deferredReloadFailedText(tc.err) |
| 25 | if strings.Contains(text, tc.secret) { |
| 26 | t.Fatalf("notice leaks the credential: %q", text) |
| 27 | } |
| 28 | if !strings.HasPrefix(text, "runtime reload failed: ") { |
| 29 | t.Fatalf("notice lost its context prefix: %q", text) |
| 30 | } |
| 31 | }) |
| 32 | } |
| 33 | } |
| 34 |