Dashboard › cli › Distillation
15407dde-f397-427f-91ca-64b8e43ff674["lore_tm_v1_D5zlF8spWzVkSztfrq-Ynsf7JNPJ3psQ9CNWKhDWUY0","lore_tm_v1_zvRNR7rVOg6BO3Vg64INfXOKydsvorX-Wd2prxjkxac","lore_tm_v1_3t9XCMmjgvmWth5DiSKh88gjEdBO9HLhu64YOVmUd8M","lore_tm_v1_1jZF6pfVvRaibEzy7Pi4owG6frQ-0Kylj1kORfNCSJY","lore_tm_v1_TplwNU2wecpuV5YtZ4fLGhStCMi8QaJvh4GuWl1es8w","lore_tm_v1_xUcrfJm2ukdwm4-zPaC8WxXaq1M5xbUqElb9eWpJ2X8","lore_tm_v1_wLq239uo7IADdCzlUA2UOZeQqkO5iYjIXAAyJhXbIW4","lore_tm_v1_s49cR8ZNxd_tdHf4dQGxz0pk14K7VxIWkieFnbzmh3A","lore_tm_v1_DxTkzvB5Trfjr5vuDTO9Itsbbj9rk5v5DIg4RJPxAvE","lore_tm_v1_1aBZxm1EnMjCgQ_eP-QpmF8Z4pX0tjW8biTRNP4-aCI","lore_tm_v1_zE1hZ72Ub22TDgFtNovGcrROwPA0-5GImsEq6pw9pwI","lore_tm_v1_Tdk4HPIrSgqFAS94ShPhHHS1kKDOF_onlzvqH0_-tOI","lore_tm_v1_g9GFRaNBGUjnII8w13-2kV04b47tXM1r5MeQn9xy2-A","lore_tm_v1_MurHFJ9LWMAThBHn75CdHhn58cXCz_d6_c0tYLqRKqk","lore_tm_v1_JQGZ1rSju_vuPUYmi9fdxy8DqrpHDvB0X7dJB2_u3Ls","lore_tm_v1_bRNNW_yeQJ5OAdDlK_3RgKjBAPgEXFZuXDIQdxIu8Uw","lore_tm_v1_dfgrVwnYN1mm6WhXlbfB96PiqpZbvibqP8eMujkrZ6w","lore_tm_v1_JVveOTcnVczTqjGmUR12s_o-kvMBUhpfDbC62EUVWVY"]
packages/cli/src/lib/binary.ts defines InstallationMethod as "curl" | "brew" | "npm" | "pnpm" | "bun" | "yarn" | "unknown"; VALID_METHODS excludes "unknown", and parseInstallationMethod(value) lowercases input and throws Invalid method: ${value}. Must be one of: ${VALID_METHODS.join(", ")} for unsupported methods.packages/cli/src/lib/binary.ts defines ordered UPGRADE_SOURCES: 1. { githubRepo: "getsentry/toolkit", ghcrRepo: "getsentry/toolkit", tagPrefix: "cli@" }, 2. { githubRepo: "getsentry/cli", ghcrRepo: "getsentry/cli", tagPrefix: "" }; PRIMARY_UPGRADE_SOURCE is the first entry.resolveUpgradeSource(fetchFn = customFetch, signal?) probes each source at ${getGitHubReleasesUrl(source)}/latest with getGitHubHeaders() and the abort signal. It returns both the selected source and successful response, so the caller never repeats the request. Only HTTP 404 falls through; every other HTTP or network failure aborts immediately, and all-source 404 failure throws UpgradeError("network_error", "No CLI upgrade source was found: every source returned HTTP 404").getBinaryDownloadUrl(version, source = PRIMARY_UPGRADE_SOURCE) builds https://github.com/${source.githubRepo}/releases/download/${source.tagPrefix}${version}/${getPlatformBinaryName()}; getGitHubReleasesUrl(source = PRIMARY_UPGRADE_SOURCE) builds https://api.github.com/repos/${source.githubRepo}/releases, and GITHUB_RELEASES_URL uses the primary source.isMusl() in packages/cli/src/lib/binary.ts caches its result and uses two ordered Linux heuristics: 1. check /lib/ld-musl-<arch>.so.1, with x86_64 for process.arch === "x64" and otherwise aarch64; 2. run ldd --version, combine stdout and stderr, and look case-insensitively for "musl". Non-Linux returns false, and a missing/failed ldd assumes glibc.getPlatformBinaryName() emits sentry-<os>-<arch>[-musl][.exe]: OS is darwin, windows, or linux; architecture is arm64 only when process.arch === "arm64", otherwise x64; musl adds -musl; Windows adds .exe.isNightlyVersion(version) identifies nightly builds by version.includes("-dev."), corresponding to format X.Y.Z-dev.<unix-seconds>.fetchLatestFromGitHub tests in packages/cli/test/lib/upgrade.test.ts cover: v1.2.3 β 1.2.3; stripping v from v0.5.0; accepting unprefixed 1.0.0; HTTP 404 producing UpgradeError with Failed to fetch from GitHub: 404; network TypeError("fetch failed") producing UpgradeError with Failed to connect to GitHub: fetch failed; and a successful response lacking tag_name producing No version found in GitHub release.packages/cli/test/lib/upgrade.test.ts contains nightly behavior tests asserting that nightly lookup uses a GHCR manifest rather than version.json, including for installation method "npm" because nightly is a curl-only distribution; versionExists() checks nightly versions through GHCR regardless of installation method.packages/cli/test/lib/upgrade.test.ts includes versionExists coverage for "curl", "npm", "pnpm", "bun", "brew", and "yarn"; nightly examples include 0.14.0-dev.1772661724 as existing and 0.14.0-dev.9999999999 as absent.fetchLatestNightlyVersion tests cover reading the version from a GHCR manifest annotation, GHCR token-exchange HTTP 401 with message GHCR token exchange failed: HTTP 401, abort handling, and downloading/decompressing a nightly binary from GHCR.packages/cli/test/lib/upgrade.test.ts dynamically imports ../../src/lib/upgrade.js after vi.mock() and extracts buildKnownCurlPaths, detectInstallationMethod, detectPackageManagerFromPath, downloadBinaryToTemp, executeUpgrade, fetchLatestFromGitHub, fetchLatestFromNpm, fetchLatestNightlyVersion, fetchLatestVersion, getCurlInstallPaths, parseInstallationMethod, startCleanupOldBinary, and versionExists.mockFetch(fn) replaces globalThis.fetch; beforeEach saves the original fetch and afterEach restores it. parseInstallationMethod tests cover all six valid methods, case-insensitive values including "NPM", "Curl", and "YARN", and invalid values "pip", "apt", and "".packages/cli/src/lib/custom-ca.ts resolves custom CA bundles in priority order: 1. the SQLite-stored path from sentry cli defaults ca-cert, 2. NODE_EXTRA_CA_CERTS. An environment-sourced CA targeting SaaS *.sentry.io triggers a one-time warning, while a stored default suppresses the warning as explicit acknowledgment.packages/cli/src/lib/custom-ca.ts supports Node 24+ process-wide tls.setDefaultCACertificates() when available; Node 22 lacks it, while Bun uses per-request tls.ca. CaSource is "default" | "env" | "none".readCaCertFile(path) synchronously reads UTF-8 PEM data and returns { ok: false, reason: "CA certificate file not found or not readable: ${path}" } on read failure or { ok: false, reason: "File does not contain PEM certificate data (expected -----BEGIN CERTIFICATE-----)." } when the certificate marker is absent; otherwise it returns { ok: true, content }.getCustomCaCerts() returns the resolved raw PEM string for Node https.RequestOptions.ca and Sentry SDK NodeTransportOptions.caCerts, or undefined when no custom CA is configured.customFetch(input, init?) in packages/cli/src/lib/custom-ca.ts is the drop-in fetch wrapper for non-authenticated calls: it calls bare fetch(input, init) without TLS options, or fetch(input, { ...init, ...tlsOpts }) when custom CA options exist. Authenticated calls instead use fetchWithTimeout() in sentry-client.ts.__resetForTests() resets custom-CA process state: resolved = undefined, resolvedSource = "none", resolvedLabel = "", hasResolved = false, and warnedSaas = false.packages/cli/test/lib/version-check.test.ts tests that shouldSuppressNotification() suppresses upgrade, upgrade --check, cli setup, cli fix, --version, -V, and any command containing --json.shouldSuppressNotification() tests account for global flags before a CLI management subcommand or before cli, including --verbose, -v, --log-level debug, --org acme, and --org=acme; a preceding positional token such as issue settles the command group, so ["issue", "cli", "setup"] is not suppressed.cli feedback, setup/fix used as ordinary arguments, regular commands issue list, auth status, and help, or empty arguments.getUpdateNotification tests use withStderrTTY(true), clear and later restore SENTRY_CLI_NO_UPDATE_CHECK, and reset the in-process notification latch through resetUpdateNotificationState(); no cached version information returns null.maybeCheckForUpdateInBackground initiates an update check when never checked before: with no prior state, getVersionCheckInfo().lastChecked is null, so shouldCheckForUpdate returns true.{ tag_name: "v0.0.0-dev" }, verify the function itself does not throw, and call abortPendingVersionCheck() for cleanup.setVersionCheckInfo("1.0.0"), lastChecked is non-null and latestVersion is exactly "1.0.0"; five immediate calls to maybeCheckForUpdateInBackground() exercise near-zero probabilistic checking after a recent check.abortPendingVersionCheck() is safe when called three times, and after immediately aborting one background check, another maybeCheckForUpdateInBackground() call can start without throwing.SENTRY_CLI_NO_UPDATE_CHECK=1 is tested in a subprocess because the environment variable is read at module-load time.packages/cli/test/commands/cli/upgrade.test.ts covers nightly channel selection and persistence: the positional "nightly" switches to nightly and fetches from GHCR; positional "stable" resets a persisted nightly channel; --check displays Channel: nightly, reports when already on target, and gives an upgrade hint when a newer nightly exists.0.0.0-dev.1740000000; because CLI_VERSION is "0.0.0-dev" and does not equal that nightly version, the test expects an upgrade hint."npm" triggers migration from the npm installation to a standalone binary. The test explicitly performs setReleaseChannel("nightly") and runs ["cli", "upgrade", "--method", "npm", "nightly"].mockGhcrNightlyVersion(version) in packages/cli/test/commands/cli/upgrade.test.ts mocks anonymous ghcr.io/token exchange with { token: "test-token" }, then returns an OCI manifest for /manifests/nightly with schemaVersion: 2, empty layers, and annotations: { version }; unmatched requests return HTTP 404.mockGitHubVersion(version) handles releases/latest, /releases/tags/, and registry.npmjs.org; its comment states the mocked GitHub repository uses unprefixed tags. Exact matching tag requests return 200 with { tag_name: version }, unmatched tags return 404, and the npm fallback returns { version }.mockNightlyVersion(version) replaces the old GitHub version.json mock with GHCR token exchange and a /manifests/nightly response containing annotations: { version } and content type application/vnd.oci.image.manifest.v1+json.getBinaryDownloadUrl("1.0.0") test in packages/cli/test/lib/upgrade.test.ts still expects an unprefixed /1.0.0/ URL beginning https://github.com/getsentry/cli/releases/download/, while the current packages/cli/src/lib/binary.ts primary source is getsentry/toolkit with tag prefix cli@.buildKnownCurlPaths("/home/user", {}) tests expect trailing path separators for /home/user/.local/bin and /home/user/.sentry/bin; an absolute XDG_BIN_HOME is included with a trailing separator, and a preexisting trailing slash is normalized to avoid a double separator.