Dashboard › cli › Distillation
2f1308ac-fb80-4a32-98f7-cf1a467e19c0["lore_tm_v1_3PZynJesKuQB3reec-1n1yxX-iIyrUDZ1Ny7C_DOSyA","lore_tm_v1_zmAFA_owXON5mgJ4Vq9Y3gMr-hok76DHxvMxse1kU-c","lore_tm_v1_VKH0R97IeXH35vHVbXMee0u4r-unG9Y0x33TMKPNjug","lore_tm_v1_d6a7vsrD77mkhvaC9lsUKBmh68M1vUyJr-lrohF_ujI","lore_tm_v1_WaND1Wt8QEB-NhazwsOEd_1GTa1X8Fl0vu2m7fwSF9A","lore_tm_v1_I8AW6fAJByKQtY8js-HpYWE1xo-89n8o4LEzjC1ut-4","lore_tm_v1_gkP1EEvur0bUfwoaBnevGKNw4jRmSxcH7AZnVk_CLgk","lore_tm_v1_U3Wu2tfy_JNzO0uWLKJggtS3C4-b4VXcOTsffUDgcOg","lore_tm_v1_GXwTAg3SfKKfHT5sjN-PQMCi9nxGwXMVO9hxEFWnJIU"]
Date: Sep 10, 2026
ses_f756de1edffeKDWiwJCIyo7X3C completed with DO-NOT-MERGE. It found that packages/cli/src/lib/constants.ts:83-84 lets any env sntrys_ claim select getConfiguredSentryUrl() even when getAuthConfig() in packages/cli/src/lib/db/auth.ts:158-201 selects stored OAuth unless SENTRY_FORCE_ENV_TOKEN is set; getActiveTokenHost() in packages/cli/src/lib/token-host.ts:54-67 correctly scopes requests to stored OAuth. Failure scenario: stored OAuth for sentry.io, an unforced env sntrys_ token claiming self-hosted.example, and no explicit URL routes API calls to the claim URL while authenticating with stored OAuth, causing host-scoping rejection before a request is sent. Review required a regression proving routing follows the active stored credential.normalizeUrl(env.SENTRY_HOST || env.SENTRY_URL) in packages/cli/src/lib/constants.ts:79 chooses whitespace SENTRY_HOST before normalization; because normalizeUrl() returns undefined for whitespace at constants.ts:52-64, a valid SENTRY_URL is skipped and token-claim fallback is used. Required regression: SENTRY_HOST=" ", SENTRY_URL=https://configured.example, and a distinct claim URL; configured URL must win.parseSntrysClaim() accepts any non-empty url string in packages/cli/src/lib/token-claims.ts:82-90, while normalizeUrl() in packages/cli/src/lib/constants.ts:52-64 only adds a scheme without origin validation. A structurally valid claim with an invalid URL can become global configured routing for API, OAuth, DSN scanning, web links, telemetry, region, and custom headers. Recommendation: validate claim URL as an origin before accepting claim fallback and add coverage; malformed token syntax already safely falls through.SENTRY_HOST precedence over SENTRY_URL and claim at packages/cli/src/lib/constants.ts:79-84; verified no import cycle because token-claims.ts has no imports; verified new happy-path regressions fail on the base revision and request-level coverage exercises getApiBaseUrl() plus authenticated routing. Focused constants.test.ts and sntrys-claim-mismatch.test.ts tests passed 32/32.SENTRY_URL-versus-claim precedence including whitespace SENTRY_HOST; SENTRY_TOKEN fallback and env-token-variable precedence; stored OAuth shadowing an env sntrys_ token; malformed claim syntax; and malformed claim URL behavior through getConfiguredSentryUrl().SENTRY_HOST hiding SENTRY_URLβand stated it would trace the active-auth/base-URL boundary and revise routing fallback to follow the actually active credential.ses_f756db152ffeSEN6MYxxAnaITc completed. It independently found that shadowed env sntrys_ tokens can control base-URL routing via packages/cli/src/lib/constants.ts:83-84 while stored OAuth remains active unless SENTRY_FORCE_ENV_TOKEN is set (packages/cli/src/lib/db/auth.ts:158-203, 633-656).https://sentry.io, unforced differently scoped env sntrys_ token, and no configured URL cause getApiBaseUrl() (packages/cli/src/lib/sentry-client.ts:684-686) to route to the claim; prepareHeaders() (sentry-client.ts:121-140) rejects before credentials are sent. This prevents exfiltration but lets an inactive env token cause command-wide denial of service and violate credential precedence. Required regression must show the inactive token cannot choose base URL or block a stored-credential request.packages/cli/test/lib/security/sntrys-claim-mismatch.test.ts:127-147 covers an env token without stored OAuth and misses the conflicting-token case. It found explicit host/URL still wins at constants.ts:79-82; fetch-layer host and claim guards at sentry-client.ts:121-167 prevent bearer-token and custom-header leakage to mismatched origins; no credential leak or host-scope bypass was found.getAuthConfig() in packages/cli/src/lib/db/auth.ts:158-203 gives stored OAuth precedence over env tokens by default; SENTRY_FORCE_ENV_TOKEN forces env-first behavior. It returns stored DB auth when the row has a token that is unexpired, has no expiry, or is expired with a refresh token; otherwise it falls back to env auth.getActiveEnvVarName() uses SENTRY_AUTH_TOKEN first, then SENTRY_TOKEN, returning "SENTRY_AUTH_TOKEN" if neither is set (packages/cli/src/lib/db/auth.ts:147-156).getUsableStoredTokenHost() in packages/cli/src/lib/db/auth.ts:272-288 atomically checks stored-token usability and retrieves its host in one DB read, avoiding an inconsistent result if concurrent clearAuth() interleaves; it migrates pre-v16 NULL hosts through migrateNullHost(row) and returns undefined on no usable token or DB failure.getActiveTokenHost() in packages/cli/src/lib/token-host.ts:57-68 mirrors getAuthConfig() precedence: it uses stored OAuth host unless both an env token exists and SENTRY_FORCE_ENV_TOKEN is nonblank; otherwise it uses getEnvTokenHost() only when an env token exists.packages/cli/src/lib/token-host.ts:31-49 accepts exact normalized-origin matches, plus only the strict SaaS equivalence class where both trusted and candidate origins are HTTPS default-port sentry.io or *.sentry.io; non-SaaS origins require exact match.isRequestOriginTrusted() returns true when no token is active; otherwise it requires the request origin to trust-match the active token host or be a dynamically discovered trusted region origin (packages/cli/src/lib/token-host.ts:122-134).getSdkConfig(regionUrl) in packages/cli/src/lib/sentry-client.ts:716-728 strips one trailing slash, uses the singleton authenticated fetch, and returns throwOnError: false as const; SDK functions include /api/0/ themselves, so baseUrl must be the plain region URL. throwOnError is always false because errors are handled by the CLI itself.getApiBaseUrl() and getControlSiloUrl() both resolve getConfiguredSentryUrl() ?? DEFAULT_SENTRY_URL (packages/cli/src/lib/sentry-client.ts:684-696). getControlSdkConfig() is for endpoints always on the control silo, specifically OAuth, user accounts, and regions (sentry-client.ts:737-743).packages/cli/src/lib/env-token-host.ts:58-76: resolution order is (1) normalized sntrys_ token claim url, (2) normalized SENTRY_HOST?.trim() || SENTRY_URL?.trim() for non-sntrys_ tokens, then (3) DEFAULT_SENTRY_URL.sntrys_ org-auth tokens, embedded url claim is authoritative over environment host settings because it is token-embedded and resistant to env injection; for non-sntrys_ tokens, environment host is the only host signal. .sentryclirc is never consulted for env-token host capture because it has weaker integrity than env or token claims.captureEnvTokenHost(); findProjectRoot populating .sentryclirc cache; applySentryCliRcEnvShim potentially writing env.SENTRY_URL; then getDefaultUrl() fallback potentially writing env.SENTRY_URL (packages/cli/src/lib/env-token-host.ts:30-35).getRawEnvToken() in packages/cli/src/lib/db/auth.ts:95-100 always returns the environment token when set, including when stored OAuth is active; env-token priority remains SENTRY_AUTH_TOKEN before SENTRY_TOKEN.