Dashboard › cli › Session 1cG6oBsQNQKj
1cG6oBsQNQKj0Ec9OPerform an independent, read-only correctness review of the FINAL current worktree patch for getsentry/cli issue #1568. Do not edit files. Inspect the actual diff plus relevant source/call paths (including debug-files upload, resolveOrgRegion, sentry-client, token-host, db/auth, env-token-host) and targeted tests. Verify an env sntrys token claim routes all request paths needed by debug-files upload when no explicit URL exists; explicit SENTRY_HOST/SENTRY_URL precedence including blank host; stored OAuth versus env precedence and forced env behavior; malformed claims; region fallback. Report findings first, ordered by severity with exact file:line. If no blocking defect, state that plainly and list only concrete residual test gaps. End exactly PASS or MUST-FIX.
File not found: /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/.jj
M .lore.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/explore.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/feedback.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/issue.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/log.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/replay.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/span.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/trace.md M packages/cli/src/lib/constants.ts M packages/cli/src/lib/region.ts M packages/cli/src/lib/sentry-client.ts M packages/cli/test/lib/constants.test.ts M packages/cli/test/lib/security/sntrys-claim-mismatch.test.ts .lore.md | 700 ++++++++++++--------- ...
diff --git a/packages/cli/src/lib/constants.ts b/packages/cli/src/lib/constants.ts
index 4e707773a..843b7dcb1 100644
--- a/packages/cli/src/lib/constants.ts
+++ b/packages/cli/src/lib/constants.ts
@@ -1,155 +1,155 @@
/**
* Runtime constants for the CLI.
*/
import { getEnv } from "./env.js";
/** Build-time constant injected by esbuild/bun */
declare const SENTRY_CLI_VERSION: string | undefined;
/**
* Build-time debug ID for sourcemap resolution, injected by esbuild.
*
* During the build, esbuild's `define` replaces this identifier with a
* placeholder UUID string literal. After esbuild finishes, the build
* script replaces the placeholder with the real debug ID (derived from
* the minified JS + sourcemap content hash). The same-length swap keeps
* sourcemap character positions valid.
*/
declare const __SENTRY_DEBUG_ID__: string | undefined;
/** Default Sentry SaaS hostname */
export const DEFAULT_SENTRY_HOST = "sentry.io";
/** Default Sentry SaaS ...
605e8318d chore: regenerate docs 30ad8b075 ci: organize imports in bundle.ts (biome) a3921f773 ci: address Seer finding on bundle.ts WASM resolution 12bb0fa77 chore(cli): sync scripts + Bugbot fixes for #1254 (post-feedback rebase) ab3aa054f chore: address adversarial review findings for monorepo pre-shape 157184517 ci: fix check-generated job paths for monorepo layout cf165f5ba chore: pre-shape repo into pnpm-workspace monorepo layout 0b43edad4 chore: regenerate docs f1cc17934 meta: Bump new development version 7f4d217d1 Merge branch ...
Found 65 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/lib/security/sntrys-claim-mismatch.test.ts:
Line 137: const { getApiBaseUrl } = await import("../../../src/lib/sentry-client.js");
Line 141: const baseUrl = getApiBaseUrl();
Line 184: const { getApiBaseUrl } = await import("../../../src/lib/sentry-client.js");
Line 188: const baseUrl = getApiBaseUrl();
Line 214: const { getApiBaseUrl, getControlSiloUrl } = await import(
Line 220: const baseUrl = getApiBaseUrl();
Line 223: expect(getControlSiloUrl()).toBe(baseUrl);
Line 244: const { getApiBaseUrl } = await import("../../../src/lib/sentry-client.js");
Line 246: expect(getApiBaseUrl()).toBe("https://sentry.io");
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/lib/region.test.ts:
Line 15: import { getSentryBaseUrl } from ...
Found 100 matches (more matches available)
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/api/traces.ts:
Line 27: import { resolveOrgRegion } from "../region.js";
Line 117: const regionUrl = await resolveOrgRegion(orgSlug);
Line 157: const regionUrl = await resolveOrgRegion(orgSlug);
Line 201: const regionUrl = await resolveOrgRegion(orgSlug);
Line 425: const regionUrl = await resolveOrgRegion(orgSlug);
Line 562: const regionUrl = await resolveOrgRegion(orgSlug);
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/api/sourcemaps.ts:
Line 23: import { resolveOrgRegion } from "../region.js";
Line 323: const regionUrl = await resolveOrgRegion(org);
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/api/seer.ts:
Line 11: import { resolveOrgRegion } ...
Found 55 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/token-host.ts:
Line 21: import { getEnvTokenHost } from "./env-token-host.js";
Line 55: * token unless `SENTRY_FORCE_ENV_TOKEN` is set.
Line 57: export function getActiveTokenHost(): string | undefined {
Line 59: const forceEnv = hasEnvToken && !!getEnv().SENTRY_FORCE_ENV_TOKEN?.trim();
Line 67: return hasEnvToken ? getEnvTokenHost() : undefined;
Line 129: const tokenHost = getActiveTokenHost();
Line 138: * url instead of `getActiveTokenHost()`.
Line 158: if (getActiveTokenHost()) {
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/token-claims.ts:
Line 11: * modify the token bytes). `captureEnvTokenHost` uses the claim as ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/token-host.ts</path> <type>file</type> <content> 1: /** 2: * Host-Scoped Token Trust Model 3: * 4: * Tokens (env or stored OAuth) are bound to a specific Sentry host. The fetch 5: * layer (and the `.sentryclirc` / URL-arg entry points) check each request's 6: * destination against the token's recorded host and refuse to attach 7: * credentials when they don't match — so untrusted routing inputs can't leak 8: * credentials to an attacker's host. 9: * 10: * Host equivalence: 11: * - Exact origin match (scheme + host + explicit port). 12: * - SaaS equivalence class: a token scoped to `https://sentry.io` is valid for 13: * any `*.sentry.io` subdomain. Non-SaaS hosts match exactly — no subdomain 14: * suffix matching (a `sentry.acme.com` token does NOT match 15: * `sentry.acme.evil.com`). ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/env-token-host.ts</path> <type>file</type> <content> 1: /** 2: * Env-Token Host Snapshot 3: * 4: * Captures the host an env-var auth token (`SENTRY_AUTH_TOKEN` / 5: * `SENTRY_TOKEN`) is scoped to, BEFORE any post-boot code path can mutate 6: * `env.SENTRY_HOST`/`env.SENTRY_URL` (specifically before 7: * `applySentryCliRcEnvShim` writes from a `.sentryclirc` file). 8: * 9: * Trust model for the snapshot source: 10: * 11: * - `SENTRY_HOST`/`SENTRY_URL` from env are NOT unconditionally trusted. 12: * In layered CI environments (e.g. GitHub Actions `$GITHUB_ENV`), a 13: * low-privilege step can write env vars that a later high-privilege step 14: * inherits — without having read access to `SENTRY_AUTH_TOKEN`. So 15: * env-host and env-token may have different integrity levels. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/db/auth.ts</path>
<type>file</type>
<content>
1: /**
2: * Authentication credential storage (single-row table pattern).
3: */
4:
5: import { createHash } from "node:crypto";
6: import { DEFAULT_SENTRY_URL, getConfiguredSentryUrl } from "../constants.js";
7: import { getEnv } from "../env.js";
8: import { getEnvTokenHost } from "../env-token-host.js";
9: import { logger } from "../logger.js";
10: import { normalizeOrigin } from "../sentry-urls.js";
11: import { withDbSpan } from "../telemetry.js";
12: import { getDatabase } from "./index.js";
13: import { clearAllIssueOrgCache } from "./issue-org-cache.js";
14: import { clearTrustedHostState } from "./regions.js";
15: import { runUpsert } from "./utils.js";
16:
17: /** Refresh when less than 10% of token lifetime remains */
18: export const REFRESH_THRESHOLD = 0.1;
19:
20: /** Default token lifetime (1 hour) ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/db/auth.ts</path>
<type>file</type>
<content>
381: */
382: export type SetAuthTokenOptions = {
383: host?: string;
384: };
385:
386: export function setAuthToken(
387: token: string,
388: expiresIn?: number,
389: newRefreshToken?: string,
390: options?: SetAuthTokenOptions
391: ): void {
392: withDbSpan("setAuthToken", () => {
393: const db = getDatabase();
394: const now = Date.now();
395: const expiresAt = expiresIn ? now + expiresIn * 1000 : null;
396: const issuedAt = expiresIn ? now : null;
397:
398: // Host resolution precedence:
399: // 1. Explicit `options.host` (login command, tests)
400: // 2. Existing row's `host` (refresh flow preserves the original scope)
401: // 3. Currently-configured host (getConfiguredSentryUrl)
402: // 4. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/sentry-client.ts</path>
<type>file</type>
<content>
1: /**
2: * Sentry API Client Configuration
3: *
4: * Provides request configuration for @sentry/api SDK functions,
5: * including authentication, retry logic, timeout, and multi-region support.
6: *
7: * Instead of managing client instances, we pass configuration per-request
8: * through the SDK function options (baseUrl, fetch, headers).
9: */
10:
11: import { setTimeout as sleepMs } from "node:timers/promises";
12: import { getTraceData } from "@sentry/node-core/light";
13: import { maybeWarnEnvTokenIgnored } from "./auth-hint.js";
14: import { computeInvalidationPrefixes } from "./cache-keys.js";
15: import {
16: DEFAULT_SENTRY_URL,
17: getConfiguredSentryUrl,
18: getUserAgent,
19: } from "./constants.js";
20: import {
21: buildTlsErrorDetail,
22: getCustomTlsOptions,
23: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/sentry-client.ts</path>
<type>file</type>
<content>
400: /**
401: * Store a successful GET response in the cache (fire-and-forget).
402: * Clones the response so the original body stream is preserved for the caller.
403: *
404: * @param requestHeaders - Headers sent with the request, stored in CachePolicy
405: * for future `Vary`-aware freshness checks.
406: */
407: function cacheResponse(
408: method: string,
409: fullUrl: string,
410: requestHeaders: Record<string, string>,
411: response: Response
412: ): void {
413: if (method !== "GET" || !response.ok) {
414: return;
415: }
416: // Cast needed: Bun extends Response with extra properties (toJSON, count, getAll)
417: // that .clone() doesn't carry over, but our cache only reads standard Response API
418: storeCachedResponse(
419: method,
420: fullUrl,
421: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/api/debug-files.ts</path>
<type>file</type>
<content>
1: /**
2: * Debug Information File (DIF) Upload API
3: *
4: * Uploads native debug information files (Mach-O/dSYM, ELF, PE/PDB, Portable
5: * PDB, WASM, Breakpad, source bundles) via the DIF chunk-upload + assemble
6: * protocol shared with ProGuard and Dart symbol-map uploads.
7: *
8: * Protocol: each file's raw bytes are chunked directly (no ZIP wrapping) and
9: * assembled through `projects/{org}/{project}/files/difs/assemble/`. The body
10: * keys each file by its overall SHA-1 checksum, with `name`, optional
11: * `debug_id`, and the per-chunk checksum list. Multiple files are batched into
12: * a single assemble request, like ProGuard. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/api/chunk-upload.ts</path> <type>file</type> <content> 1: /** 2: * Shared chunk-upload protocol infrastructure. 3: * 4: * Implements the Sentry chunk-upload + assemble protocol used by 5: * artifact bundle (sourcemap) and DIF (proguard) uploads. Callers 6: * build their own ZIP and choose the appropriate assemble endpoint; 7: * this module handles chunking, hashing, codec selection, chunk 8: * upload, and assembly polling. 9: * 10: * Protocol overview: 11: * 1. GET chunk-upload options (chunk size, concurrency, compression) 12: * 2. (Caller builds the ZIP) 13: * 3. Split ZIP into chunks, compute SHA-1 checksums 14: * 4. POST assemble request -> server reports missing chunks 15: * 5. Upload missing chunks in parallel as multipart/form-data 16: * 6. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/api/chunk-upload.ts</path>
<type>file</type>
<content>
260: const init: RequestInit = { method: "POST", body: form };
261: if (encoding === "zstd") {
262: init.headers = { "Content-Encoding": "zstd" };
263: }
264:
265: const response = await authFetch(url, init);
266: if (!response.ok) {
267: throw new ApiError(
268: `Chunk upload failed: ${response.status} ${response.statusText}`,
269: response.status,
270: await response.text().catch(() => ""),
271: url
272: );
273: }
274: }
275:
276: /**
277: * Split a ZIP file into chunks and compute SHA-1 checksums.
278: *
279: * Reads the file sequentially — only one chunk buffer is live at a time. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/token-claims.ts</path>
<type>file</type>
<content>
1: /**
2: * Sentry Org-Auth-Token (`sntrys_`) Claim Extraction
3: *
4: * Format: `sntrys_<base64(JSON{iat, url, region_url, org})>_<random-secret>`
5: * (server-side: getsentry/sentry `orgauthtoken_token.py`).
6: *
7: * The claim is **NOT signed** — anyone can forge a `sntrys_` string with any
8: * `url`. However, for legitimate tokens the claim IS authoritative: the real
9: * server wrote it at issuance time, and it's immune to env-injection attacks
10: * (the attacker who can poison `SENTRY_HOST` via `$GITHUB_ENV` can't read or
11: * modify the token bytes). `captureEnvTokenHost` uses the claim as the
12: * primary trust source for `sntrys_` tokens, ahead of env vars. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/sentry-urls.ts</path>
<type>file</type>
<content>
1: /**
2: * Sentry URL Utilities
3: *
4: * Utilities for constructing Sentry web URLs.
5: * Supports self-hosted instances via SENTRY_URL environment variable.
6: */
7:
8: import {
9: DEFAULT_SENTRY_HOST,
10: DEFAULT_SENTRY_URL,
11: getConfiguredSentryUrl,
12: normalizeUrl,
13: } from "./constants.js";
14:
15: /**
16: * Get the Sentry web base URL.
17: * Supports self-hosted instances via SENTRY_URL env var.
18: */
19: export function getSentryBaseUrl(): string {
20: return getConfiguredSentryUrl() ?? DEFAULT_SENTRY_URL;
21: }
22:
23: /**
24: * Build the org-scoped base URL using the subdomain pattern.
25: * E.g. "https://sentry.io" + "my-org" → "https://my-org.sentry.io"
26: *
27: * @param orgSlug - Organization slug
28: * @returns Origin URL with org as subdomain
29: */
30: export ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/lib/security/sntrys-claim-mismatch.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Defense-in-depth: `sntrys_` token claim vs request-origin mismatch.
3: *
4: * The fetch-layer guard refuses to attach a `sntrys_` token when its
5: * embedded `url` claim disagrees with the request origin. Defends users
6: * with access to multiple Sentry instances against routing one
7: * instance's token to another. Claim is unsigned (see token-claims.ts),
8: * so this catches honest misconfigurations more than malicious attacks.
9: */
10:
11: import { afterEach, beforeEach, describe, expect, test } from "vitest";
12: import {
13: extractFetchUrl,
14: mintSntrysToken,
15: resetHostScopingState,
16: useEnvSandbox,
17: useTestConfigDir,
18: } from "../../helpers.js";
19:
20: const ENV_KEYS = [
21: "SENTRY_AUTH_TOKEN",
22: "SENTRY_TOKEN",
23: ...
Found 17 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/lib/security/sntrys-claim-mismatch.test.ts: Line 15: resetHostScopingState, Line 36: await resetHostScopingState(); Line 71: await resetHostScopingState(); Line 322: beforeEach(resetHostScopingState); Line 323: afterEach(resetHostScopingState); /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/lib/security/login-token-rc-poison.test.ts: Line 36: resetHostScopingState, Line 91: await resetHostScopingState(); Line 112: await resetHostScopingState(); /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/lib/security/auto-login-host-guard.test.ts: Line 28: resetHostScopingState, Line 40: await resetHostScopingState(); Line 44: await ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/helpers.ts</path>
<type>file</type>
<content>
140: });
141:
142: return () => dir;
143: }
144:
145: /**
146: * Save/restore a set of `process.env` keys around each test in a `describe`
147: * block. Saved values are restored verbatim in `afterEach`; missing keys are
148: * deleted on restore. Each test starts with all listed keys cleared.
149: *
150: * Use for security/host-scoping tests where env vars influence the code path
151: * being tested. Keeps the boilerplate `Object.fromEntries(KEYS.map(...))`
152: * out of every test file.
153: *
154: * Must be called at module scope or inside a `describe()` block.
155: */
156: export function useEnvSandbox(keys: readonly string[]): void {
157: let saved: Record<string, string | undefined>;
158:
159: beforeEach(() => {
160: saved = Object.fromEntries(keys.map((k) => [k, process.env[k]]));
161: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/api/infrastructure.ts</path>
<type>file</type>
<content>
1: /**
2: * API Client Infrastructure
3: *
4: * Shared helpers, types, constants, and raw request functions used by
5: * all domain-specific API modules. This is the foundation layer that
6: * other modules in `src/lib/api/` import from.
7: */
8:
9: import { promisify } from "node:util";
10: import { zstdCompress as zstdCompressCb } from "node:zlib";
11: import { parseSentryLinkHeader } from "@sentry/api";
12: // biome-ignore lint/performance/noNamespaceImport: Sentry SDK recommends namespace import
13: import * as Sentry from "@sentry/node-core/light";
14: import type { z } from "zod";
15:
16: import { extractRequiredScopes } from "../api-scope.js";
17: import { getActiveEnvVarName, isEnvTokenActive } from "../db/auth.js";
18: import { getEnv } from "../env.js";
19: import { ApiError, AuthError, ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/commands/debug-files/upload.ts</path>
<type>file</type>
<content>
60:
61: const log = logger.withTag("debug-files.upload");
62:
63: const USAGE_HINT = "sentry debug-files upload <path>...";
64:
65: /** Relative path to Xcode's DerivedData folder under the user's home dir. */
66: const DERIVED_DATA_SUBPATH = "Library/Developer/Xcode/DerivedData";
67:
68: /**
69: * Resolve the effective scan paths, optionally appending Xcode's DerivedData
70: * folder when `--derived-data` is set.
71: *
72: * DerivedData only exists on macOS; on other platforms the flag is a no-op
73: * (with a warning). The folder is appended only when it actually exists, so the
74: * stricter `scanPaths` existence check (which throws on a missing explicit
75: * path) is never tripped by an absent DerivedData directory. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/commands/debug-files/upload.ts</path>
<type>file</type>
<content>
560: "legacy Rust sentry-cli if you still need it.",
561: },
562: output: {
563: human: formatUploadResult,
564: },
565: parameters: {
566: positional: {
567: kind: "array",
568: parameter: {
569: brief: "Files or directories to scan for debug information files",
570: parse: String,
571: placeholder: "path",
572: },
573: },
574: flags: {
575: type: {
576: kind: "parsed",
577: parse: String,
578: brief:
579: "Only upload files of this type (repeatable): dsym, elf, pe, pdb, " +
580: "portablepdb, wasm, breakpad, sourcebundle, jvm",
581: optional: true,
582: variadic: true,
583: },
584: id: {
585: kind: "parsed",
586: parse: String,
587: ...
Found 41 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/commands/event/view.ts:
Line 55: resolveOrgAndProject,
Line 614: const autoTarget = await resolveOrgAndProject({ cwd, usageHint: USAGE_HINT });
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/commands/sourcemap/upload.ts:
Line 23: import { resolveOrgAndProject } from "../../lib/resolve-target.js";
Line 372: const resolved = await resolveOrgAndProject({
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/commands/debug-files/upload.ts:
Line 59: import { resolveOrgAndProject } from "../../lib/resolve-target.js";
Line 523: // resolveOrgAndProject which triggers auth resolution. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/resolve-target.ts</path>
<type>file</type>
<content>
1240: );
1241:
1242: // Resolve with concurrency limit to avoid overwhelming the Sentry API.
1243: // Without this, large repos can fire 100+ concurrent HTTP requests,
1244: // triggering rate limiting (429) and retry storms.
1245: const resolvedTargets = await resolveDsnsWithTimeout(uniqueDsns);
1246:
1247: // Filter out failed resolutions and deduplicate by org+project
1248: // (different orgId forms can resolve to the same org slug)
1249: const seen = new Set<string>();
1250: const targets = resolvedTargets.filter((t): t is ResolvedTarget => {
1251: if (t === null) {
1252: return false;
1253: }
1254: const key = `${t.org}:${t.project}`;
1255: if (seen.has(key)) {
1256: return false;
1257: }
1258: seen.add(key);
1259: return true;
1260: });
1261: ...
Found 19 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/telemetry.ts:
Line 23: getConfiguredSentryUrl,
Line 472: const customUrl = getConfiguredSentryUrl();
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/constants.ts:
Line 73: export function getConfiguredSentryUrl(): string | undefined {
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/sentry-urls.ts:
Line 11: getConfiguredSentryUrl,
Line 20: return getConfiguredSentryUrl() ?? DEFAULT_SENTRY_URL;
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/sentry-client.ts:
Line 17: getConfiguredSentryUrl,
Line 686: return getConfiguredSentryUrl() ?? getActiveTokenHost() ?? ...
...output truncated... Full output saved to: /home/byk/.local/share/opencode/tool-output/tool_08ac6e2c8001rrEaWzKCldm0EH already defined; injected freshness uses \`FRESH\_FLAG\` and \`applyFreshFlag()\`. Its first positional is always the org/project-pattern target and must pass through \`interceptSubcommand()\` to recover plural-alias confusion. Re-declaring or bypassing these conventions looks explicit but causes freshness, pagination, target resolution, and alias behavior to diverge. -<!-- lore:019e6874-7d63-710a-84ad-c86ef679744e --> -* **wizard-runner.ts: large shared context via initialState, not inputData — D1 row size limit**: In \`wizard-runner.ts\`, large shared context (\`dirListing\`, \`fileCache\`, \`existingSentry\`) travels via \`initialState\` (not \`inputData\`) to avoid D1 per-row size overflow (see getsentry/cli-init-api#98). \`MAX\_RESUME\_RETRIES = 3\`, \`RETRY\_BACKOFF\_MS = \[2000, 4000, 8000]\`. ...
<path>/home/byk/.local/share/opencode/tool-output/tool_08ac6e2c8001rrEaWzKCldm0EH</path> <type>file</type> <content> 1: diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md 2: index 75babca80..96ebe39a6 100644 3: --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md 4: +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md 5: @@ -42,7 +42,7 @@ View a dashboard 6: - `-w, --web - Open in browser` 7: - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` 8: - `-r, --refresh <value> - Auto-refresh interval in seconds (default: 60, min: 10)` 9: -- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01"` 10: +- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01"` 11: 12: **Examples:** 13: 14: diff --git ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "sentry",
3: "version": "0.40.0-dev.0",
4: "description": "Sentry CLI - A command-line interface for using Sentry built by robots and humans for robots and humans",
5: "repository": {
6: "type": "git",
7: "url": "git+https://github.com/getsentry/cli.git"
8: },
9: "main": "./dist/index.cjs",
10: "type": "module",
11: "types": "./dist/index.d.cts",
12: "exports": {
13: ".": {
14: "import": {
15: "types": "./dist/index.d.mts",
16: "default": "./dist/index.mjs"
17: },
18: "require": {
19: "types": "./dist/index.d.cts",
20: "default": "./dist/index.cjs"
21: }
22: }
23: },
24: "bin": {
25: "sentry": "./dist/bin.cjs"
26: },
27: "files": [
28: "dist/bin.cjs",
29: "dist/index.cjs",
30: ...
DEPRECATED `test.poolOptions` was removed in Vitest 4. All previous `poolOptions` are now top-level options. Please, refer to the migration guide: https://vitest.dev/guide/migration#pool-rework
RUN v4.1.10 /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli
[info] [auth] Detected SENTRY_AUTH_TOKEN env var but using stored login for stored OAuth user.
Set SENTRY_FORCE_ENV_TOKEN=1 to prefer the env var.
Test Files 2 passed (2)
Tests 35 passed (35)
Start at 10:05:12
Duration 3.43s (transform 2.32s, setup 138ms, import 2.06s, tests 1.18s, environment 0ms)
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/db/regions.ts</path>
<type>file</type>
<content>
1: /**
2: * Organization region cache for multi-region support.
3: *
4: * Sentry has multiple regions (US, EU, etc.) and organizations are bound
5: * to a specific region. This module caches the organization-to-region
6: * mapping to avoid repeated lookups.
7: *
8: * The `org_id` column (added in schema v8) enables offline resolution
9: * of numeric org IDs extracted from DSN hosts (e.g., `o1081365` →
10: * look up by `org_id = '1081365'` → get the slug).
11: */
12:
13: import { normalizeOrigin } from "../sentry-urls.js";
14: import { recordCacheHit } from "../telemetry.js";
15: import { getDatabase } from "./index.js";
16: import { runUpsert } from "./utils.js";
17:
18: const TABLE = "org_regions";
19:
20: /**
21: * Process-local trust extension: origins that were vouched for by the
22: * active ...
Found 100 matches (more matches available)
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/lib/auth-hint.test.ts:
Line 8: * or when SENTRY_FORCE_ENV_TOKEN is set.
Line 31: savedForceEnv = process.env.SENTRY_FORCE_ENV_TOKEN;
Line 34: delete process.env.SENTRY_FORCE_ENV_TOKEN;
Line 50: process.env.SENTRY_FORCE_ENV_TOKEN = savedForceEnv;
Line 52: delete process.env.SENTRY_FORCE_ENV_TOKEN;
Line 73: String(call[0] ?? "").includes("SENTRY_FORCE_ENV_TOKEN=1")
Line 105: test("does nothing when SENTRY_FORCE_ENV_TOKEN is set", () => {
Line 108: process.env.SENTRY_FORCE_ENV_TOKEN = "1";
Line 134: expect(text).toContain("SENTRY_FORCE_ENV_TOKEN=1");
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/test/lib/api/replays.test.ts:
Line 15: import { setOrgRegion } from "../../../src/lib/db/regions.js";
Line ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/glowing-cactus/packages/cli/src/lib/env.ts</path>
<type>file</type>
<content>
1: /**
2: * Environment variable registry for CLI/library isolation.
3: *
4: * CLI mode never calls `setEnv()`, so `getEnv()` returns `process.env`.
5: * Library mode calls `setEnv()` with a merged env copy — the consumer's
6: * `process.env` is never mutated.
7: */
8:
9: let _env: NodeJS.ProcessEnv = process.env;
10:
11: /** Get the active environment. Library mode overrides this; CLI uses process.env. */
12: export function getEnv(): NodeJS.ProcessEnv {
13: return _env;
14: }
15:
16: /** Set the active environment for this invocation. */
17: export function setEnv(env: NodeJS.ProcessEnv): void {
18: _env = env;
19: }
(End of file - total 19 lines)
</content>
<path>/tmp/opencode</path> <type>directory</type> <entries> cli-pr-1558-review-config/ principal-pre-rebase.diff principal-rebased.diff (3 entries) </entries>
M .lore.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/explore.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/feedback.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/issue.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/log.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/replay.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/span.md M packages/cli/plugins/sentry-cli/skills/sentry-cli/references/trace.md M packages/cli/src/lib/constants.ts M packages/cli/src/lib/region.ts M packages/cli/src/lib/sentry-client.ts M packages/cli/test/lib/constants.test.ts M packages/cli/test/lib/security/sntrys-claim-mismatch.test.ts
packages/cli/src/lib/region.ts:67-70 returns a cached region before consulting the claim-routed base URL. The persisted cache is not host- or identity-scoped (packages/cli/src/lib/db/regions.ts:141-149), and its entries are globally admitted as trusted regions (packages/cli/src/lib/db/regions.ts:34-53, packages/cli/src/lib/token-host.ts:111-120).
With stored OAuth for stored.example, a cached org region at that host, plus SENTRY_FORCE_ENV_TOKEN=1 and an env sntrys_ claim for claimed.example, debug-files upload calls getChunkUploadOptions() (src/commands/debug-files/upload.ts:697; src/lib/api/chunk-upload.ts:135-143). It receives the cached stored.example URL, and both host checks allow it through the global trusted-region set. prepareHeaders() then attaches the forced env token (src/lib/sentry-client.ts:121-149). The assemble and chunk-upload paths follow the same stale region.
This violates claim routing and can send the env token to the previous OAuth host. Scope persisted region trust by the active credential/host, or reject and refresh cached regions outside that trust class.
The new forced-env test only exercises a direct request (test/lib/security/sntrys-claim-mismatch.test.ts:201-231). Add a regression that seeds a foreign cached org region, forces an env sntrys_ token, runs the debug-files chunk-options/assemble path, and proves no request to the old host receives that token.
Verified otherwise: explicit URL precedence including blank SENTRY_HOST, direct stored-versus-forced-env host selection, malformed-claim fail-closed behavior, and uncached region fallback are correct. Targeted tests passed: 35/35.
MUST-FIX