[object Object]

← back to Cli Printing Press

fix(skills): canonicalize auth env var when slug-derived differs (#1428)

2988814e0585f9ede348ffbeb80c6cdf219f92d9 · 2026-05-14 23:43:12 -0700 · Trevin Chow

* fix(skills): canonicalize auth env var when slug-derived differs

Extend Pre-Generation Auth Enrichment so the canonical-env-var check
also fires when auth IS present, not only when auth is missing or
auth.type is none. Agents now compute the slug-derived env var the
generator will pick, compare against canonical names surfaced in Phase
1 research / Phase 1.5a MCP source analysis / community wrapper docs,
and add x-auth-env-vars on the security scheme before running generate
when they diverge.

Avoids the post-generation patching pattern (editing config.go Load
plus doctor.go env-var checks after a doctor FAIL against the
operator's real environment) that retro #1157 surfaced on Keap and
that recurs across Stripe, HubSpot, Twilio, and other established APIs
where the canonical token name differs from the security-scheme slug.

x-auth-env-vars parsing already exists in internal/openapi/parser.go;
no generator-code change needed.

Refs #1157

* fix(skills): correct Twilio example and note OAuth2 client_credentials trap

Addresses Greptile review on PR #1428:

- Twilio HTTP Basic actually derives TWILIO_USERNAME + TWILIO_PASSWORD
  (per TestOpenAPIHTTPBasicAuthDefaultEnvVars), and the canonical pair
  is TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN. Old bullet showed a single
  TWILIO_AUTH_TOKEN override against a wrong TWILIO_API_KEY slug-form,
  which would silently break the Basic {username}:{password} format
  string for an agent following the example verbatim.
- applyAuthEnvVarDefaults in internal/openapi/parser.go re-applies the
  default CLIENT_ID / CLIENT_SECRET pair for OAuth2 client_credentials
  whenever x-auth-env-vars has fewer than 2 entries. A single canonical
  override on that grant would be silently lost. Step 3 now calls out
  the threshold and points agents at x-auth-vars for the single-
  service-account-token case.

Also expands the YAML example block to cover the HTTP Basic two-var
pair alongside the single-token bearer/oauth2-authorization-code case,
so the examples match the corrected bullets directly.

Refs #1157

Files touched

Diff

commit 2988814e0585f9ede348ffbeb80c6cdf219f92d9
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Thu May 14 23:43:12 2026 -0700

    fix(skills): canonicalize auth env var when slug-derived differs (#1428)
    
    * fix(skills): canonicalize auth env var when slug-derived differs
    
    Extend Pre-Generation Auth Enrichment so the canonical-env-var check
    also fires when auth IS present, not only when auth is missing or
    auth.type is none. Agents now compute the slug-derived env var the
    generator will pick, compare against canonical names surfaced in Phase
    1 research / Phase 1.5a MCP source analysis / community wrapper docs,
    and add x-auth-env-vars on the security scheme before running generate
    when they diverge.
    
    Avoids the post-generation patching pattern (editing config.go Load
    plus doctor.go env-var checks after a doctor FAIL against the
    operator's real environment) that retro #1157 surfaced on Keap and
    that recurs across Stripe, HubSpot, Twilio, and other established APIs
    where the canonical token name differs from the security-scheme slug.
    
    x-auth-env-vars parsing already exists in internal/openapi/parser.go;
    no generator-code change needed.
    
    Refs #1157
    
    * fix(skills): correct Twilio example and note OAuth2 client_credentials trap
    
    Addresses Greptile review on PR #1428:
    
    - Twilio HTTP Basic actually derives TWILIO_USERNAME + TWILIO_PASSWORD
      (per TestOpenAPIHTTPBasicAuthDefaultEnvVars), and the canonical pair
      is TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN. Old bullet showed a single
      TWILIO_AUTH_TOKEN override against a wrong TWILIO_API_KEY slug-form,
      which would silently break the Basic {username}:{password} format
      string for an agent following the example verbatim.
    - applyAuthEnvVarDefaults in internal/openapi/parser.go re-applies the
      default CLIENT_ID / CLIENT_SECRET pair for OAuth2 client_credentials
      whenever x-auth-env-vars has fewer than 2 entries. A single canonical
      override on that grant would be silently lost. Step 3 now calls out
      the threshold and points agents at x-auth-vars for the single-
      service-account-token case.
    
    Also expands the YAML example block to cover the HTTP Basic two-var
    pair alongside the single-token bearer/oauth2-authorization-code case,
    so the examples match the corrected bullets directly.
    
    Refs #1157
---
 skills/printing-press/SKILL.md | 66 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index d6bb4b18..df9006a5 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -1642,6 +1642,72 @@ name in `env_vars`; do not add guessed slug-based aliases. For OpenAPI specs,
 prefer `x-auth-env-vars` on the selected security scheme when the wrapper slug
 differs from the underlying API brand.
 
+**If auth IS present** in the spec but Phase 1 evidence shows the slug-derived
+env var will differ from the canonical name users have already set for this
+API, enrich the spec with the canonical name before generation. The
+slug-derivation rule (security-scheme slug uppercased plus `_TOKEN` /
+`_API_KEY` / `_OAUTH2` per type) rarely matches the canonical name for
+established APIs. Common shapes:
+
+- Stripe (bearer): canonical `STRIPE_SECRET_KEY`, not slug-derived `STRIPE_OAUTH2`
+- HubSpot (bearer): canonical `HUBSPOT_PRIVATE_APP_TOKEN`, not slug-derived `HUBSPOT_API_KEY`
+- Twilio (HTTP Basic, two-var pair): canonical `TWILIO_ACCOUNT_SID` + `TWILIO_AUTH_TOKEN`, not slug-derived `TWILIO_USERNAME` + `TWILIO_PASSWORD`
+- Keap (OAuth2 authorization-code): canonical `KEAP_SERVICE_ACCOUNT_KEY`, not slug-derived `KEAP_OAUTH2`
+
+Walk through:
+
+1. Compute the slug-derived env var the generator will pick (security-scheme
+   slug, uppercased, plus the type-suffix above; HTTP Basic produces a
+   `_USERNAME` + `_PASSWORD` pair; OAuth2 `client_credentials` produces a
+   `_CLIENT_ID` + `_CLIENT_SECRET` pair).
+2. Check Phase 1 research, Phase 1.5a MCP source code analysis, and community
+   wrapper READMEs for a canonical env var name documented by the vendor or
+   in widespread use.
+3. If they differ, add `x-auth-env-vars` on the selected security scheme
+   (OpenAPI) or set `auth.env_vars` to the canonical name (internal YAML).
+   Use only the canonical name; do not retain the slug-derived form as an
+   alias. For HTTP Basic, supply the full two-entry canonical pair
+   (username position first, password position second). For OAuth2
+   `client_credentials`, the parser silently re-applies the
+   `CLIENT_ID`/`CLIENT_SECRET` default when `x-auth-env-vars` has fewer
+   than two entries (see `applyAuthEnvVarDefaults` in
+   `internal/openapi/parser.go`); if the canonical secret is a single
+   service-account token for a `client_credentials` flow, use
+   `x-auth-vars` instead (next section) so the override is preserved.
+4. If research surfaces no canonical name distinct from the slug-derived
+   form, do nothing. The slug-derived name is fine, and a spurious
+   `x-auth-env-vars` would just shadow it with the same value.
+
+```yaml
+# Bearer / API-key single-token case (Stripe, HubSpot, Keap on
+# authorization-code grant, most apiKey schemes).
+components:
+  securitySchemes:
+    keapOAuth2:
+      type: oauth2
+      flows:
+        authorizationCode: { ... }
+      x-auth-env-vars:
+        - KEAP_SERVICE_ACCOUNT_KEY
+```
+
+```yaml
+# HTTP Basic two-var canonical pair (Twilio).
+components:
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
+      x-auth-env-vars:
+        - TWILIO_ACCOUNT_SID
+        - TWILIO_AUTH_TOKEN
+```
+
+Skipping this step pushes the agent into hand-patching
+`internal/config/config.go` Load and `internal/cli/doctor.go` env-var
+checks after a `doctor` FAIL against the operator's real environment.
+Enriching the spec avoids that round-trip.
+
 For OpenAPI specs that need richer env-var metadata (kind classification,
 optional credentials, OR-group relationships), use `x-auth-vars` on the
 security scheme. See `docs/SPEC-EXTENSIONS.md` for the canonical schema.

← 55b0f16b feat(skills): contain session-state.json outside DISCOVERY_D  ·  back to Cli Printing Press  ·  fix(cli): derive doctor auth.verify_path from me-shaped endp 95f03501 →