mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(coderd/x/chatd/chatdebug): allow Anthropic per-modality ratelimit headers (#24592)
Previously, Anthropic's per-modality, Priority Tier, and fast-mode rate-limit headers (`Anthropic-Ratelimit-Input-Tokens-*`, `Anthropic-Ratelimit-Output-Tokens-*`, `Anthropic-Priority-Input-Tokens-*`, `Anthropic-Priority-Output-Tokens-*`, `Anthropic-Fast-Input-Tokens-*`, and `Anthropic-Fast-Output-Tokens-*`) were shown as `[REDACTED]` in the Debug panel because they contain `"token"` in the name and fell through the generic credential filter. Add them to the allowlist in `coderd/x/chatd/chatdebug/redaction.go` alongside the existing `Anthropic-Ratelimit-Tokens-*` entries so the limits/remaining/reset values surface in the raw response view.
This commit is contained in:
@@ -162,19 +162,44 @@ func consumeJSONEOF(decoder *json.Decoder) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// safeRateLimitHeaderNames lists rate-limit headers that contain
|
||||
// "token" in the name but carry numeric usage counters, not
|
||||
// credentials. They are checked in isSensitiveName before the
|
||||
// generic "token" substring match so they pass through unredacted.
|
||||
// Add new entries here when a provider introduces a rate-limit
|
||||
// header family containing "token" (e.g. Anthropic's per-modality,
|
||||
// Priority Tier, or fast-mode headers).
|
||||
var safeRateLimitHeaderNames = map[string]struct{}{
|
||||
"anthropic-ratelimit-requests-limit": {},
|
||||
"anthropic-ratelimit-requests-remaining": {},
|
||||
"anthropic-ratelimit-requests-reset": {},
|
||||
"anthropic-ratelimit-tokens-limit": {},
|
||||
"anthropic-ratelimit-tokens-remaining": {},
|
||||
"anthropic-ratelimit-tokens-reset": {},
|
||||
"x-ratelimit-limit-requests": {},
|
||||
"x-ratelimit-limit-tokens": {},
|
||||
"x-ratelimit-remaining-requests": {},
|
||||
"x-ratelimit-remaining-tokens": {},
|
||||
"x-ratelimit-reset-requests": {},
|
||||
"x-ratelimit-reset-tokens": {},
|
||||
"anthropic-ratelimit-requests-limit": {},
|
||||
"anthropic-ratelimit-requests-remaining": {},
|
||||
"anthropic-ratelimit-requests-reset": {},
|
||||
"anthropic-ratelimit-tokens-limit": {},
|
||||
"anthropic-ratelimit-tokens-remaining": {},
|
||||
"anthropic-ratelimit-tokens-reset": {},
|
||||
"anthropic-ratelimit-input-tokens-limit": {},
|
||||
"anthropic-ratelimit-input-tokens-remaining": {},
|
||||
"anthropic-ratelimit-input-tokens-reset": {},
|
||||
"anthropic-ratelimit-output-tokens-limit": {},
|
||||
"anthropic-ratelimit-output-tokens-remaining": {},
|
||||
"anthropic-ratelimit-output-tokens-reset": {},
|
||||
"anthropic-priority-input-tokens-limit": {},
|
||||
"anthropic-priority-input-tokens-remaining": {},
|
||||
"anthropic-priority-input-tokens-reset": {},
|
||||
"anthropic-priority-output-tokens-limit": {},
|
||||
"anthropic-priority-output-tokens-remaining": {},
|
||||
"anthropic-priority-output-tokens-reset": {},
|
||||
"anthropic-fast-input-tokens-limit": {},
|
||||
"anthropic-fast-input-tokens-remaining": {},
|
||||
"anthropic-fast-input-tokens-reset": {},
|
||||
"anthropic-fast-output-tokens-limit": {},
|
||||
"anthropic-fast-output-tokens-remaining": {},
|
||||
"anthropic-fast-output-tokens-reset": {},
|
||||
"x-ratelimit-limit-requests": {},
|
||||
"x-ratelimit-limit-tokens": {},
|
||||
"x-ratelimit-remaining-requests": {},
|
||||
"x-ratelimit-remaining-tokens": {},
|
||||
"x-ratelimit-reset-requests": {},
|
||||
"x-ratelimit-reset-tokens": {},
|
||||
}
|
||||
|
||||
// isSensitiveName reports whether a name (header or query parameter)
|
||||
|
||||
@@ -88,18 +88,54 @@ func TestRedactHeaders(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
headers := http.Header{
|
||||
"Anthropic-Ratelimit-Tokens-Limit": {"1000000"},
|
||||
"Anthropic-Ratelimit-Tokens-Remaining": {"999000"},
|
||||
"Anthropic-Ratelimit-Tokens-Reset": {"2026-03-31T08:55:26Z"},
|
||||
"X-RateLimit-Limit-Tokens": {"120000"},
|
||||
"X-RateLimit-Remaining-Tokens": {"119500"},
|
||||
"X-RateLimit-Reset-Tokens": {"12ms"},
|
||||
"Anthropic-Ratelimit-Tokens-Limit": {"1000000"},
|
||||
"Anthropic-Ratelimit-Tokens-Remaining": {"999000"},
|
||||
"Anthropic-Ratelimit-Tokens-Reset": {"2026-03-31T08:55:26Z"},
|
||||
"Anthropic-Ratelimit-Input-Tokens-Limit": {"200000"},
|
||||
"Anthropic-Ratelimit-Input-Tokens-Remaining": {"199000"},
|
||||
"Anthropic-Ratelimit-Input-Tokens-Reset": {"2026-03-31T08:55:26Z"},
|
||||
"Anthropic-Ratelimit-Output-Tokens-Limit": {"80000"},
|
||||
"Anthropic-Ratelimit-Output-Tokens-Remaining": {"79500"},
|
||||
"Anthropic-Ratelimit-Output-Tokens-Reset": {"2026-03-31T08:55:26Z"},
|
||||
"Anthropic-Priority-Input-Tokens-Limit": {"10000"},
|
||||
"Anthropic-Priority-Input-Tokens-Remaining": {"9618"},
|
||||
"Anthropic-Priority-Input-Tokens-Reset": {"2026-03-31T08:55:26Z"},
|
||||
"Anthropic-Priority-Output-Tokens-Limit": {"10000"},
|
||||
"Anthropic-Priority-Output-Tokens-Remaining": {"6000"},
|
||||
"Anthropic-Priority-Output-Tokens-Reset": {"2026-03-31T08:55:26Z"},
|
||||
"Anthropic-Fast-Input-Tokens-Limit": {"50000"},
|
||||
"Anthropic-Fast-Input-Tokens-Remaining": {"49000"},
|
||||
"Anthropic-Fast-Input-Tokens-Reset": {"2026-03-31T08:55:26Z"},
|
||||
"Anthropic-Fast-Output-Tokens-Limit": {"25000"},
|
||||
"Anthropic-Fast-Output-Tokens-Remaining": {"24000"},
|
||||
"Anthropic-Fast-Output-Tokens-Reset": {"2026-03-31T08:55:26Z"},
|
||||
"X-RateLimit-Limit-Tokens": {"120000"},
|
||||
"X-RateLimit-Remaining-Tokens": {"119500"},
|
||||
"X-RateLimit-Reset-Tokens": {"12ms"},
|
||||
}
|
||||
|
||||
redacted := chatdebug.RedactHeaders(headers)
|
||||
require.Equal(t, "1000000", redacted["Anthropic-Ratelimit-Tokens-Limit"])
|
||||
require.Equal(t, "999000", redacted["Anthropic-Ratelimit-Tokens-Remaining"])
|
||||
require.Equal(t, "2026-03-31T08:55:26Z", redacted["Anthropic-Ratelimit-Tokens-Reset"])
|
||||
require.Equal(t, "200000", redacted["Anthropic-Ratelimit-Input-Tokens-Limit"])
|
||||
require.Equal(t, "199000", redacted["Anthropic-Ratelimit-Input-Tokens-Remaining"])
|
||||
require.Equal(t, "2026-03-31T08:55:26Z", redacted["Anthropic-Ratelimit-Input-Tokens-Reset"])
|
||||
require.Equal(t, "80000", redacted["Anthropic-Ratelimit-Output-Tokens-Limit"])
|
||||
require.Equal(t, "79500", redacted["Anthropic-Ratelimit-Output-Tokens-Remaining"])
|
||||
require.Equal(t, "2026-03-31T08:55:26Z", redacted["Anthropic-Ratelimit-Output-Tokens-Reset"])
|
||||
require.Equal(t, "10000", redacted["Anthropic-Priority-Input-Tokens-Limit"])
|
||||
require.Equal(t, "9618", redacted["Anthropic-Priority-Input-Tokens-Remaining"])
|
||||
require.Equal(t, "2026-03-31T08:55:26Z", redacted["Anthropic-Priority-Input-Tokens-Reset"])
|
||||
require.Equal(t, "10000", redacted["Anthropic-Priority-Output-Tokens-Limit"])
|
||||
require.Equal(t, "6000", redacted["Anthropic-Priority-Output-Tokens-Remaining"])
|
||||
require.Equal(t, "2026-03-31T08:55:26Z", redacted["Anthropic-Priority-Output-Tokens-Reset"])
|
||||
require.Equal(t, "50000", redacted["Anthropic-Fast-Input-Tokens-Limit"])
|
||||
require.Equal(t, "49000", redacted["Anthropic-Fast-Input-Tokens-Remaining"])
|
||||
require.Equal(t, "2026-03-31T08:55:26Z", redacted["Anthropic-Fast-Input-Tokens-Reset"])
|
||||
require.Equal(t, "25000", redacted["Anthropic-Fast-Output-Tokens-Limit"])
|
||||
require.Equal(t, "24000", redacted["Anthropic-Fast-Output-Tokens-Remaining"])
|
||||
require.Equal(t, "2026-03-31T08:55:26Z", redacted["Anthropic-Fast-Output-Tokens-Reset"])
|
||||
require.Equal(t, "120000", redacted["X-RateLimit-Limit-Tokens"])
|
||||
require.Equal(t, "119500", redacted["X-RateLimit-Remaining-Tokens"])
|
||||
require.Equal(t, "12ms", redacted["X-RateLimit-Reset-Tokens"])
|
||||
|
||||
Reference in New Issue
Block a user