← back to Cli Printing Press
fix(cli): scorer recognizes composed/cookie auth and apiKey header matching
e9d9daa53aed760d6051ccf584016389c50631f2 · 2026-04-03 14:04:45 -0700 · Trevin Chow
Auth Protocol scored 3/10 for composed cookie auth because the scorer
only credited Bearer/Basic/Bot prefix patterns, not custom apiKey
headers or browser cookie auth tooling.
Fixes:
- apiKey schemes with in=header get authHeaderMatched when the client
sets the correct header name (regardless of value format)
- Browser cookie auth (detectCookieTool, --chrome, chrome-composed)
credits envMatched since Chrome cookies replace env vars as the
credential source
- Reads auth.go alongside client.go and config.go for scoring
Also adds AGENTS.md guidance: when adding a capability that affects
scoring, update the scorer in the same change to fairly assess it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files touched
M AGENTS.mdM internal/pipeline/scorecard.go
Diff
commit e9d9daa53aed760d6051ccf584016389c50631f2
Author: Trevin Chow <trevin@trevinchow.com>
Date: Fri Apr 3 14:04:45 2026 -0700
fix(cli): scorer recognizes composed/cookie auth and apiKey header matching
Auth Protocol scored 3/10 for composed cookie auth because the scorer
only credited Bearer/Basic/Bot prefix patterns, not custom apiKey
headers or browser cookie auth tooling.
Fixes:
- apiKey schemes with in=header get authHeaderMatched when the client
sets the correct header name (regardless of value format)
- Browser cookie auth (detectCookieTool, --chrome, chrome-composed)
credits envMatched since Chrome cookies replace env vars as the
credential source
- Reads auth.go alongside client.go and config.go for scoring
Also adds AGENTS.md guidance: when adding a capability that affects
scoring, update the scorer in the same change to fairly assess it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
AGENTS.md | 2 ++
internal/pipeline/scorecard.go | 26 ++++++++++++++++++++++----
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index 7de64dde..db1a0775 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -13,6 +13,8 @@ This repo contains **the machine** (generator, templates, binary, skills) that p
**When iterating on a printed CLI to discover issues**, note which problems are systemic (retro findings) vs specific. The retro → plan → implement loop exists to feed discoveries from individual CLIs back into the machine.
+**When adding a capability that affects scoring**, update the scorer in the same change. The goal is not to inflate scores — it's to ensure the scorer accurately reflects the capability. If you add composed cookie auth but the scorer only recognizes Bearer/Basic, it will penalize a correctly-implemented CLI. Fix the scorer to recognize the new pattern, not to give it a free pass.
+
## Build, Test & Lint
```bash
diff --git a/internal/pipeline/scorecard.go b/internal/pipeline/scorecard.go
index c9382b98..82181b15 100644
--- a/internal/pipeline/scorecard.go
+++ b/internal/pipeline/scorecard.go
@@ -1056,6 +1056,7 @@ func evaluateAuthProtocol(dir string, spec *openAPISpecInfo) dimensionScore {
clientContent := readFileContent(filepath.Join(dir, "internal", "client", "client.go"))
configContent := readFileContent(filepath.Join(dir, "internal", "config", "config.go"))
+ authContent := readFileContent(filepath.Join(dir, "internal", "cli", "auth.go"))
if clientContent == "" {
return dimensionScore{scored: true}
}
@@ -1070,7 +1071,7 @@ func evaluateAuthProtocol(dir string, spec *openAPISpecInfo) dimensionScore {
bestScore := -1
scoreable := false
for _, alternative := range requirementSet.Alternatives {
- score, ok := scoreAuthAlternative(clientContent, configContent, spec.SecuritySchemes, alternative)
+ score, ok := scoreAuthAlternative(clientContent, configContent, authContent, spec.SecuritySchemes, alternative)
if !ok {
continue
}
@@ -1141,7 +1142,7 @@ func parseSecurityRequirementSet(value any) (securityRequirementSet, bool) {
return set, true
}
-func scoreAuthAlternative(clientContent, configContent string, schemes map[string]openAPISecurityScheme, alternative []string) (int, bool) {
+func scoreAuthAlternative(clientContent, configContent, authContent string, schemes map[string]openAPISecurityScheme, alternative []string) (int, bool) {
if len(alternative) == 0 {
return 0, false
}
@@ -1153,7 +1154,7 @@ func scoreAuthAlternative(clientContent, configContent string, schemes map[strin
if !ok {
continue
}
- score, scoreable := scoreAuthScheme(clientContent, configContent, scheme)
+ score, scoreable := scoreAuthScheme(clientContent, configContent, authContent, scheme)
if !scoreable {
continue
}
@@ -1166,7 +1167,7 @@ func scoreAuthAlternative(clientContent, configContent string, schemes map[strin
return total / scoreableSchemes, true
}
-func scoreAuthScheme(clientContent, configContent string, scheme openAPISecurityScheme) (int, bool) {
+func scoreAuthScheme(clientContent, configContent, authContent string, scheme openAPISecurityScheme) (int, bool) {
nameLower := strings.ToLower(scheme.Key)
headerName := "Authorization"
authHeaderMatched := false
@@ -1197,6 +1198,15 @@ func scoreAuthScheme(clientContent, configContent string, scheme openAPISecurity
}
case strings.EqualFold(scheme.Type, "apikey"):
scoreable = true
+ // For apiKey schemes, the header value format varies (Bearer, Bot, custom).
+ // Credit authHeaderMatched if the client sets the correct header name,
+ // since that proves the auth plumbing is wired correctly regardless of format.
+ if scheme.In == "header" && headerName != "" {
+ if strings.Contains(clientContent, `Header.Set("`+headerName+`"`) ||
+ strings.Contains(clientContent, `Header.Add("`+headerName+`"`) {
+ authHeaderMatched = true
+ }
+ }
case strings.EqualFold(scheme.Type, "oauth2"), strings.EqualFold(scheme.Type, "openidconnect"):
scoreable = true
if strings.Contains(clientContent, `"Bearer "`) || strings.Contains(clientContent, "`Bearer `") {
@@ -1220,6 +1230,14 @@ func scoreAuthScheme(clientContent, configContent string, scheme openAPISecurity
if envNeedle != "" && strings.Contains(strings.ToUpper(configContent), envNeedle) {
envMatched = true
}
+ // Browser cookie auth (composed or cookie type) uses Chrome cookie extraction
+ // instead of env vars. Credit envMatched if the auth code has cookie tooling.
+ if !envMatched && (strings.Contains(authContent, "detectCookieTool") ||
+ strings.Contains(authContent, "--chrome") ||
+ strings.Contains(configContent, "chrome-composed") ||
+ strings.Contains(configContent, `"browser"`)) {
+ envMatched = true
+ }
score := 0
if authHeaderMatched {
← 6d2d059d feat(cli): browser auth, composed cookies, smart output, and
·
back to Cli Printing Press
·
fix(skills): publish skill supports fork-based PRs for exter 5026f516 →