Dashboard › cli › Session 1WH9u5zo5AvN
1WH9u5zo5AvNstQW4Perform an independent, read-only security and supply-chain review of getsentry/cli PR #1569 pinned to exact base ec83887a16f780f32fba4b7d710bad262dba3a22 and exact head dbee7e9f2a4555e044f74dfebad002cccfa43a1f in worktree /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade. Do not modify files, VCS, or PR state. Inspect every changed file in base..head plus relevant surrounding code/tests. Focus on source fallback only after genuine typed HTTP 404; terminal handling for 401/403/429/5xx/transport/malformed responses; source affinity preventing mixed repository binaries, patches, manifests, tokens, prefetches, and changelogs; GitHub tag-prefix/release metadata validation; SemVer handling; GHCR token scopes and redirect authorization stripping; untrusted JSON, tags, URLs, and redirects; SHA-256 and delta-chain integrity; cancellation and cache behavior; and the unchanged installer boundary. You MUST return a substantive structured report. Report every point first as PASS, CONCERN, or MUST-FIX with exact file:line evidence and a deterministic regression for each defect. If no defects, state PASS explicitly and list residual risks or test gaps. If blocked, state BLOCKED first with the exact tool/error. End exactly MERGE or DO-NOT-MERGE. Never return an empty response.
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade</path> <type>directory</type> <entries> .craft.yml .git .github/ .gitignore .lore.md .nojekyll .npmrc AGENTS.md apps/ CHANGELOG.md codemods/ docs/ LICENSE.md node_modules/ package.json packages/ pnpm-lock.yaml pnpm-workspace.yaml README.md (19 entries) </entries>
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/AGENTS.md</path> <type>file</type> <content> 1: # Jared (Outpost agent) 2: 3: Autonomous GitHub coding agent. Work in `/workspace/repo`. 4: 5: ## Model tiers 6: 7: The primary model is chosen per event (see `src/agents/models.ts`): heavy for 8: code-producing situations, cheaper for lightweight ones. 9: 10: | Role | Subagent | Model | 11: | --- | --- | --- | 12: | Triage / plan / review (heavy) | (primary Jared) | Claude Opus 4.8 | 13: | Triage / plan / review (light) | (primary Jared) | xAI Grok 4.3 | 14: | Explore | `explore` | OpenAI gpt-5-mini | 15: | Implement | `implement` | Moonshot kimi-k2.7-code | 16: | Ship (commit/push/PR) | `ship` | xAI Grok (`grok-build-0.1`) | 17: 18: Pipeline: triage → explore → plan → implement → review → ship. 19: (`worker` is a deprecated alias of `implement`.) 20: 21: Operators also talk to Jared directly from the Outpost dashboard. ...
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade dbee7e9f2a4555e044f74dfebad002cccfa43a1f M packages/cli/src/commands/cli/upgrade.ts M packages/cli/src/lib/binary.ts M packages/cli/src/lib/delta-upgrade.ts M packages/cli/src/lib/ghcr.ts M packages/cli/src/lib/release-notes.ts M packages/cli/src/lib/upgrade.ts M packages/cli/src/lib/version-check.ts M packages/cli/test/commands/cli.test.ts M packages/cli/test/commands/cli/upgrade.test.ts M packages/cli/test/lib/binary.test.ts M packages/cli/test/lib/delta-upgrade.mocked.test.ts M packages/cli/test/lib/delta-upgrade.test.ts M packages/cli/test/lib/ghcr.test.ts M packages/cli/test/lib/release-notes.test.ts M packages/cli/test/lib/upgrade.test.ts M packages/cli/test/lib/version-check.test.ts a84a52f92f46526431f9d1572166676d68542683797142d9116d2bee61de48ea -
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/CONTRIBUTING.md
No files found
No files found
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/CONTRIBUTING.md</path> <type>file</type> <content> 1: # Contributing to Sentry CLI 2: 3: This guide documents the patterns and conventions used in this CLI for consistency. 4: 5: ## Command Patterns 6: 7: We follow [gh CLI](https://cli.github.com/) conventions for best-in-class developer experience. 8: 9: ### List Commands 10: 11: List commands use **optional positional arguments** for context with smart auto-detection. 12: 13: ```bash 14: sentry org list [--limit N] [--json] 15: sentry project list [org] [--limit N] [--json] 16: sentry issue list [<org>/<project>] [--json] 17: ``` 18: 19: **Target syntax**: 20: - `<org>/<project>` - Explicit organization and project (e.g., `my-org/frontend`) 21: - `<org>/` - All projects in the specified organization 22: - `<project>` - Search for project by name across all accessible organizations 23: - *(omit)* - ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "toolkit-cli-workspace",
3: "version": "0.0.0",
4: "private": true,
5: "type": "module",
6: "packageManager": "pnpm@10.11.0",
7: "engines": {
8: "node": ">=20.0"
9: },
10: "scripts": {
11: "tsx": "pnpm --filter sentry run tsx",
12: "cli": "pnpm --filter sentry run cli",
13: "dev": "pnpm --filter sentry run dev",
14: "build": "pnpm --filter sentry run build",
15: "build:all": "pnpm --filter sentry run build:all",
16: "bundle": "pnpm --filter sentry run bundle",
17: "typecheck": "pnpm --filter sentry run typecheck",
18: "lint": "pnpm --filter sentry run lint",
19: "lint:fix": "pnpm --filter sentry run lint:fix",
20: "test": "pnpm --filter sentry run test",
21: "test:unit": "pnpm --filter sentry run test:unit",
22: "test:changed": "pnpm --filter ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "sentry",
3: "version": "0.45.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: ...
Found 27 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/.lore.md:
Line 8: * **API output binary and HTTP contracts**: Always preserve strict output-mode and binary-safety contracts. `sentry api` must preserve `rawApiRequest()` status text; empty textual non-2xx bodies must produce an HTTP status/request fallback, and JSON mode must expose `{status, statusText, body}` so empty success and error responses are distinguishable. Binary `Uint8Array` successes bypass formatters and remain raw; binary errors emit only status/content-type/byte-count summaries, never bytes or JSON coercion. Prompts must never block scripted runs or interleave with stdout JSON.
Line 20: * **bspatch.ts in-memory chain refactor: transformPatch callback + three public APIs**: Core patching logic extracted into \`transformPatch(oldFile, patchData, onChunk)\` callback-based function. ...
packages/cli/src/commands/cli/upgrade.ts | 114 +++++--- packages/cli/src/lib/binary.ts | 154 +++++++++- packages/cli/src/lib/delta-upgrade.ts | 139 +++++++-- packages/cli/src/lib/ghcr.ts | 68 +++-- packages/cli/src/lib/release-notes.ts | 119 +++++--- packages/cli/src/lib/upgrade.ts | 309 +++++++++++++++----- packages/cli/src/lib/version-check.ts | 21 +- packages/cli/test/commands/cli.test.ts | 23 +- packages/cli/test/commands/cli/upgrade.test.ts | 71 ++++- packages/cli/test/lib/binary.test.ts | 130 ++++++++- packages/cli/test/lib/delta-upgrade.mocked.test.ts | 14 +- packages/cli/test/lib/delta-upgrade.test.ts | 201 ++++++++++++- packages/cli/test/lib/ghcr.test.ts | 40 ++- packages/cli/test/lib/release-notes.test.ts | 113 ++++++- packages/cli/test/lib/upgrade.test.ts | 323 ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
1: /**
2: * Binary Management
3: *
4: * Shared utilities for installing, replacing, and managing the CLI binary.
5: * Used by both `setup --install` (fresh installs) and `upgrade` (self-updates).
6: */
7:
8: import { spawnSync } from "node:child_process";
9: import {
10: existsSync,
11: mkdirSync,
12: readFileSync,
13: renameSync,
14: unlinkSync,
15: writeFileSync,
16: } from "node:fs";
17: import { chmod, copyFile, mkdir, realpath, unlink } from "node:fs/promises";
18: import { delimiter, dirname, isAbsolute, join, resolve, sep } from "node:path";
19: import { compare as semverCompare } from "semver";
20: import { getUserAgent } from "./constants.js";
21: import {
22: buildTlsErrorDetail,
23: customFetch,
24: isTlsCertError,
25: } from "./custom-ca.js";
26: import { stringifyUnknown, ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
1: /**
2: * Upgrade Module
3: *
4: * Detects how the CLI was installed and provides self-upgrade functionality.
5: * Binary management helpers (download URLs, locking, replacement) live in
6: * binary.ts and are shared with the setup --install flow.
7: */
8:
9: import { spawn } from "node:child_process";
10: import {
11: chmodSync,
12: closeSync,
13: existsSync,
14: openSync,
15: realpathSync,
16: statSync,
17: unlinkSync,
18: writeSync,
19: } from "node:fs";
20: import { writeFile } from "node:fs/promises";
21: import { homedir } from "node:os";
22: import { dirname, isAbsolute, join, sep } from "node:path";
23: import { setTimeout } from "node:timers/promises";
24: import { valid as semverValid } from "semver";
25: import {
26: acquireLock,
27: cleanupOldBinary,
28: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/ghcr.ts</path> <type>file</type> <content> 1: /** 2: * GHCR (GitHub Container Registry) Client 3: * 4: * Encapsulates the OCI download protocol for fetching nightly CLI binaries 5: * from ghcr.io/getsentry/cli. Nightly builds are pushed as OCI artifacts 6: * via ORAS with the version baked into the manifest annotation. 7: * 8: * Key design decisions: 9: * - Anonymous access: nightly package is public; no token needed beyond the 10: * standard ghcr.io anonymous token exchange. 11: * - Version discovery from manifest annotation: `annotations.version` in the 12: * OCI manifest holds the nightly version. Checking the latest version only 13: * requires a token exchange + manifest fetch (2 HTTP requests total). 14: * - Redirect quirk: ghcr.io blob downloads return 307 to Azure Blob Storage. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts</path>
<type>file</type>
<content>
1: /** Delta upgrade discovery and application backed by binpatch. */
2:
3: import { join } from "node:path";
4: // biome-ignore lint/performance/noNamespaceImport: Sentry SDK recommends namespace import
5: import * as Sentry from "@sentry/node-core/light";
6: import {
7: applyPatchChainInMemory,
8: extractStableChain as binpatchExtractStableChain,
9: filterAndSortChainTags as binpatchFilterAndSortChainTags,
10: validateChainStep as binpatchValidateChainStep,
11: type DeltaTelemetry,
12: type DeltaUnavailableReason,
13: type ExtractStableChainOpts,
14: type GitHubRelease,
15: getPatchFromVersion,
16: getPatchTargetSha256,
17: ghcrSource,
18: githubReleaseSource,
19: type InstrumentHook,
20: MAX_NIGHTLY_CHAIN_DEPTH,
21: makeCache,
22: OciClient,
23: type OciManifest,
24: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts</path> <type>file</type> <content> 1: /** 2: * Release Notes Parser & Aggregation 3: * 4: * Extracts user-facing changelog entries from GitHub Release bodies (stable) 5: * or conventional commit messages (nightly). Uses `marked.lexer()` for 6: * AST-based section extraction and produces structured data that can be 7: * re-serialized as filtered markdown for rendering via `renderMarkdown()`. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts</path>
<type>file</type>
<content>
1: /**
2: * Background version check for "new version available" notifications.
3: *
4: * For nightly builds (CLI_VERSION contains "-dev.<timestamp>"), checks GHCR for the
5: * latest nightly version via the OCI manifest annotation. For stable builds,
6: * checks GitHub Releases. Results are cached in the database and shown on
7: * subsequent runs.
8: */
9:
10: // biome-ignore lint/performance/noNamespaceImport: Sentry SDK recommends namespace import
11: import * as Sentry from "@sentry/node-core/light";
12: import { compare as semverCompare } from "semver";
13: import type { UpgradeSource } from "./binary.js";
14: import { CLI_VERSION } from "./constants.js";
15: import { getReleaseChannel } from "./db/release-channel.js";
16: import {
17: getVersionCheckInfo,
18: markUpdateNotified,
19: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path> <type>file</type> <content> 1: /** 2: * sentry cli upgrade 3: * 4: * Self-update the Sentry CLI to the latest or a specific version. 5: * After upgrading, spawns the NEW binary with `cli setup` to update 6: * completions, agent skills, and record installation metadata. 7: * 8: * Supports two release channels: 9: * - stable (default): tracks the latest GitHub release 10: * - nightly: tracks the rolling nightly prerelease built from main 11: * 12: * The channel can be set via --channel or by passing "nightly"/"stable" 13: * as the version argument. The choice is persisted in the local database 14: * so that subsequent bare `sentry cli upgrade` calls use the same channel. ...
Found 25 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:
Line 607: await expect(versionExists("curl", "1.0.0")).resolves.toBe(true);
Line 622: await expect(versionExists("curl", "1.0.0")).resolves.toBe(true);
Line 649: versionExists("curl", "1.0.0", UPGRADE_SOURCES[0])
Line 659: const exists = await versionExists("curl", "1.0.0");
Line 666: const exists = await versionExists("curl", "99.99.99");
Line 673: const exists = await versionExists("npm", "1.0.0");
Line 680: const exists = await versionExists("npm", "99.99.99");
Line 687: const exists = await versionExists("pnpm", "1.0.0");
Line 694: const exists = await versionExists("bun", "1.0.0");
Line 701: const exists = await versionExists("brew", "1.0.0");
Line 708: const exists = await versionExists("brew", "99.99.99");
Line 715: const exists = await ...
No files found
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules</path> <type>directory</type> <entries> .modules.yaml .pnpm-workspace-state.json .pnpm/ (3 entries) </entries>
No files found
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules/.pnpm</path> <type>directory</type> <entries> @a2a-js+sdk@0.3.14_express@5.2.1/ @ai-sdk+provider-utils@2.2.8_zod@4.4.3/ @ai-sdk+provider-utils@3.0.30_zod@4.4.3/ @ai-sdk+provider-utils@4.0.40_zod@4.4.3/ @ai-sdk+provider-utils@5.0.13_zod@4.4.3/ @ai-sdk+provider@1.1.3/ @ai-sdk+provider@2.0.3/ @ai-sdk+provider@3.0.14/ @ai-sdk+provider@4.0.4/ @ai-sdk+ui-utils@1.2.11_zod@4.4.3/ @alcalzone+ansi-tokenize@0.3.0/ @anthropic-ai+sdk@0.39.0/ @apm-js-collab+code-transformer-bundler-plugins@0.5.0/ @apm-js-collab+code-transformer-bundler-plugins@0.7.3/ @apm-js-collab+code-transformer@0.15.0/ @apm-js-collab+code-transformer@0.18.1/ @apm-js-collab+tracing-hooks@0.10.1/ @apm-js-collab+tracing-hooks@0.13.0/ @astrojs+compiler-binding-linux-x64-gnu@0.3.2/ @astrojs+compiler-binding-linux-x64-musl@0.3.2/ @astrojs+compiler-binding@0.3.2_@emnapi+core@1.10.0_@emnapi+runtime@1.10.0/ @astrojs...
Found 2 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/pnpm-lock.yaml:
Line 2696: binpatch@0.4.2:
Line 7801: binpatch@0.4.2: {}
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules/.pnpm</path> <type>directory</type> <entries> @vercel+analytics@2.0.1_react@19.2.8/ @vercel+speed-insights@2.0.0_react@19.2.8/ @vitest+coverage-v8@4.1.10_vitest@4.1.10/ @vitest+expect@4.1.10/ @vitest+mocker@4.1.10_vite@8.0.16_@types+node@22.20.1_esbuild@0.28.1_tsx@4.23.5_yaml@2.9.0_/ @vitest+pretty-format@4.1.10/ @vitest+runner@4.1.10/ @vitest+snapshot@4.1.10/ @vitest+spy@4.1.10/ @vitest+utils@4.1.10/ @workflow+serde@4.1.0-beta.2/ @workflow+serde@4.1.0/ abort-controller@3.0.0/ accepts@2.0.0/ acorn-jsx@5.3.2_acorn@8.17.0/ acorn@8.17.0/ agent-base@6.0.2/ agentkeepalive@4.6.0/ ajv-formats@3.0.1_ajv@8.20.0/ ajv@8.20.0/ am-i-vibing@0.4.0/ anser@2.3.5/ ansi-escapes@7.3.0/ ansi-regex@5.0.1/ ansi-regex@6.2.2/ ansi-styles@4.3.0/ ansi-styles@6.2.3/ any-promise@1.3.0/ anymatch@3.1.3/ arg@5.0.2/ argparse@1.0.10/ argparse@2.0.1/ aria-query@5.3.2/ array-iterate@2.0.1/ assertion...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules/.pnpm/binpatch@0.4.2/node_modules/binpatch</path> <type>directory</type> <entries> dist/ LICENSE package.json README.md (4 entries) </entries>
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules/.pnpm/binpatch@0.4.2/node_modules/binpatch/dist</path> <type>directory</type> <entries> index.d.ts index.js index.js.map (3 entries) </entries>
Found 23 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules/.pnpm/binpatch@0.4.2/node_modules/binpatch/dist/index.js:
Line 440: expectedSha256: chain.expectedSha256,
Line 510: let expectedSha256 = "";
Line 512: if (meta.toVersion === targetVersion && meta.expectedSha256) {
Line 513: expectedSha256 = meta.expectedSha256;
Line 517: if (!expectedSha256) return null;
Line 540: return { patches, totalSize, expectedSha256 };
Line 610: function makeCache(cacheDir) {
Line 654: async function resolveAndApply(opts) {
Line 707: return await cache.load(currentVersion, targetVersion);
Line 734: if (sha256 !== chain.expectedSha256) {
Line 736: `SHA-256 mismatch after patching: got ${sha256}, expected ${chain.expectedSha256}`
Line 890: async downloadBlob(token, digest, signal) {
Line 949: async downloadBlobBuffer(token, digest, signal) {
Line ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules/.pnpm/binpatch@0.4.2/node_modules/binpatch/dist/index.js</path>
<type>file</type>
<content>
380: if (patches.length === 0) {
381: throw new Error("Cannot apply an empty patch chain");
382: }
383: let reader = await loadOldBinary(oldPath);
384: try {
385: for (let i = 0; i < patches.length - 1; i++) {
386: const patch = patches[i];
387: if (!patch) {
388: throw new Error(`Missing patch at index ${i}`);
389: }
390: const next = await applyReaderToMemory(reader, patch, onBytes);
391: await reader.close();
392: reader = new MemoryOldReader(next);
393: }
394: const finalPatch = patches.at(-1);
395: if (!finalPatch) {
396: throw new Error("Missing final patch");
397: }
398: return await applyReaderToFile(reader, finalPatch, destPath, onBytes);
399: } finally {
400: await ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules/.pnpm/binpatch@0.4.2/node_modules/binpatch/dist/index.js</path>
<type>file</type>
<content>
747: // src/sources/oci.ts
748: var REQUEST_TIMEOUT = 1e4;
749: var MAX_RETRIES = 1;
750: var BLOB_TIMEOUT = 3e4;
751: var TAGS_PAGE_SIZE = 100;
752: var OCI_MANIFEST_TYPE = "application/vnd.oci.image.manifest.v1+json";
753: function isRetryableError(error) {
754: if (error.name === "TimeoutError" || error.name === "AbortError") {
755: return true;
756: }
757: const msg = error.message.toLowerCase();
758: return msg.includes("timeout") || msg.includes("econnreset") || msg.includes("econnrefused") || msg.includes("network") || msg.includes("fetch failed");
759: }
760: function buildSignal(timeout, externalSignal) {
761: const timeoutSignal = AbortSignal.timeout(timeout);
762: return externalSignal ? AbortSignal.any([timeoutSignal, externalSignal]) : ...
Found 6 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts: Line 204: export async function fetchRecentReleases( /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts: Line 580: * Uses a higher `per_page` than `fetchRecentReleases()` in delta-upgrade /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts: Line 844: const result = await fetchRecentReleases(); Line 856: await fetchRecentReleases(undefined, LEGACY_UPGRADE_SOURCE); Line 866: const result = await fetchRecentReleases(); Line 875: const result = await fetchRecentReleases();
diff --git a/packages/cli/src/lib/binary.ts b/packages/cli/src/lib/binary.ts
index 75582612a..61e10568d 100644
--- a/packages/cli/src/lib/binary.ts
+++ b/packages/cli/src/lib/binary.ts
@@ -65,80 +65,107 @@ function stripTrailingSep(p: string): string {
* Compare two filesystem paths for equality. Tolerates a trailing separator on
* either side, and is case-insensitive on case-insensitive filesystems
* (Windows, macOS) — a stored path can differ in casing from a freshly computed
* one (e.g. `C:\Users\User` vs `C:\Users\user`) yet point at the same location,
* so a strict `===` would wrongly differ.
*
* The implementation is chosen once at module load from
* {@link IS_CASE_INSENSITIVE_FS} so there is no per-call platform check.
*/
export const samePath: (a: string, b: string) => boolean =
IS_CASE_INSENSITIVE_FS
? (a, b) =>
stripTrailingSep(a).toLowerCase() === stripTrailingSep(b).toLowerCase()
: (a, b) => stripTrailingSep(a) === ...
diff --git a/packages/cli/src/lib/upgrade.ts b/packages/cli/src/lib/upgrade.ts
index 945adc48d..64228ba41 100644
--- a/packages/cli/src/lib/upgrade.ts
+++ b/packages/cli/src/lib/upgrade.ts
@@ -1,124 +1,163 @@
/**
* Upgrade Module
*
* Detects how the CLI was installed and provides self-upgrade functionality.
* Binary management helpers (download URLs, locking, replacement) live in
* binary.ts and are shared with the setup --install flow.
*/
import { spawn } from "node:child_process";
import {
chmodSync,
closeSync,
existsSync,
openSync,
realpathSync,
statSync,
unlinkSync,
writeSync,
} from "node:fs";
import { writeFile } from "node:fs/promises";
import { homedir } from "node:os";
import { dirname, isAbsolute, join, sep } from "node:path";
import { setTimeout } from "node:timers/promises";
+import { valid as semverValid } from "semver";
import {
acquireLock,
cleanupOldBinary,
+ compareVersions,
determineInstallDir,
...
diff --git a/packages/cli/src/lib/delta-upgrade.ts b/packages/cli/src/lib/delta-upgrade.ts
index ec709b8c8..37f4b7d54 100644
--- a/packages/cli/src/lib/delta-upgrade.ts
+++ b/packages/cli/src/lib/delta-upgrade.ts
@@ -1,209 +1,272 @@
/** Delta upgrade discovery and application backed by binpatch. */
import { join } from "node:path";
// biome-ignore lint/performance/noNamespaceImport: Sentry SDK recommends namespace import
import * as Sentry from "@sentry/node-core/light";
import {
applyPatchChainInMemory,
extractStableChain as binpatchExtractStableChain,
filterAndSortChainTags as binpatchFilterAndSortChainTags,
validateChainStep as binpatchValidateChainStep,
type DeltaTelemetry,
type DeltaUnavailableReason,
type ExtractStableChainOpts,
type GitHubRelease,
getPatchFromVersion,
getPatchTargetSha256,
ghcrSource,
githubReleaseSource,
type InstrumentHook,
MAX_NIGHTLY_CHAIN_DEPTH,
makeCache,
OciClient,
type OciManifest,
...
diff --git a/packages/cli/src/lib/ghcr.ts b/packages/cli/src/lib/ghcr.ts index 43d6deb7e..5bc671a6a 100644 --- a/packages/cli/src/lib/ghcr.ts +++ b/packages/cli/src/lib/ghcr.ts @@ -1,59 +1,60 @@ /** * GHCR (GitHub Container Registry) Client * * Encapsulates the OCI download protocol for fetching nightly CLI binaries * from ghcr.io/getsentry/cli. Nightly builds are pushed as OCI artifacts * via ORAS with the version baked into the manifest annotation. * * Key design decisions: * - Anonymous access: nightly package is public; no token needed beyond the * standard ghcr.io anonymous token exchange. * - Version discovery from manifest annotation: `annotations.version` in the * OCI manifest holds the nightly version. Checking the latest version only * requires a token exchange + manifest fetch (2 HTTP requests total). * - Redirect quirk: ghcr.io blob downloads return 307 to Azure Blob Storage. ...
diff --git a/packages/cli/src/lib/release-notes.ts b/packages/cli/src/lib/release-notes.ts index ddf617535..fb32efd78 100644 --- a/packages/cli/src/lib/release-notes.ts +++ b/packages/cli/src/lib/release-notes.ts @@ -1,54 +1,56 @@ /** * Release Notes Parser & Aggregation * * Extracts user-facing changelog entries from GitHub Release bodies (stable) * or conventional commit messages (nightly). Uses `marked.lexer()` for * AST-based section extraction and produces structured data that can be * re-serialized as filtered markdown for rendering via `renderMarkdown()`. ...
Found 5 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts:
Line 630: const { fromVersion, toVersion, maxItems, prefetchedReleases, source } =
Line 633: prefetchedReleases ?? (await fetchReleasesForChangelog(source));
Line 737: prefetchedReleases?: GitHubRelease[];
Line 761: prefetchedReleases,
Line 777: prefetchedReleases,
diff --git a/packages/cli/src/commands/cli/upgrade.ts b/packages/cli/src/commands/cli/upgrade.ts index 8d8282368..610a12025 100644 --- a/packages/cli/src/commands/cli/upgrade.ts +++ b/packages/cli/src/commands/cli/upgrade.ts @@ -1,91 +1,94 @@ /** * sentry cli upgrade * * Self-update the Sentry CLI to the latest or a specific version. * After upgrading, spawns the NEW binary with `cli setup` to update * completions, agent skills, and record installation metadata. * * Supports two release channels: * - stable (default): tracks the latest GitHub release * - nightly: tracks the rolling nightly prerelease built from main * * The channel can be set via --channel or by passing "nightly"/"stable" * as the version argument. The choice is persisted in the local database * so that subsequent bare `sentry cli upgrade` calls use the same channel. ...
diff --git a/packages/cli/test/commands/cli.test.ts b/packages/cli/test/commands/cli.test.ts
index cd1514eb0..187ae70f4 100644
--- a/packages/cli/test/commands/cli.test.ts
+++ b/packages/cli/test/commands/cli.test.ts
@@ -102,135 +102,138 @@ describe("feedbackCommand.func", () => {
});
});
// Test the upgrade command func
describe("upgradeCommand.func", () => {
let originalFetch: typeof globalThis.fetch;
let restoreStderr: (() => void) | undefined;
beforeEach(() => {
originalFetch = globalThis.fetch;
});
afterEach(() => {
restoreStderr?.();
restoreStderr = undefined;
globalThis.fetch = originalFetch;
});
// Note: We skip testing "unknown installation method" case because
// detectInstallationMethod() runs actual shell commands (npm list, etc.)
// which can be slow/flaky in CI. The unknown method handling is tested
// indirectly through the upgrade.ts unit tests in lib/upgrade.test.ts. ...
diff --git a/packages/cli/test/lib/delta-upgrade.mocked.test.ts b/packages/cli/test/lib/delta-upgrade.mocked.test.ts
index cd0a2fddc..f6186ab59 100644
--- a/packages/cli/test/lib/delta-upgrade.mocked.test.ts
+++ b/packages/cli/test/lib/delta-upgrade.mocked.test.ts
@@ -77,75 +77,75 @@ function versionHex(version: string): string {
.map((c) => c.charCodeAt(0).toString(16).padStart(2, "0"))
.join("");
}
function tempFile(name: string): string {
return join(
tmpdir(),
`delta-iso-${Date.now()}-${Math.random().toString(36).slice(2)}-${name}`
);
}
// ============================================================================
// resolveStableDelta
// ============================================================================
describe("resolveStableDelta", () => {
test("resolves and applies a stable delta patch", async () => {
// Create a "current binary" to patch from
const oldBinaryPath = tempFile("old-binary.bin");
const destPath = ...
diff --git a/packages/cli/test/lib/release-notes.test.ts b/packages/cli/test/lib/release-notes.test.ts
index 78963b471..d60066802 100644
--- a/packages/cli/test/lib/release-notes.test.ts
+++ b/packages/cli/test/lib/release-notes.test.ts
@@ -1,46 +1,49 @@
/**
* Unit Tests for Release Notes Parser & Aggregation
*
* Tests core invariants (section extraction, version filtering, truncation)
* that are hard to express as property-based tests due to format specifics.
*
* Core random-input invariants (category validity, filtering, commit parsing)
* are tested via property-based tests in release-notes.property.test.ts.
*/
import { marked } from "marked";
-import { describe, expect, test } from "vitest";
+import { afterEach, beforeEach, describe, expect, test } from "vitest";
+import { UPGRADE_SOURCES } from "../../src/lib/binary.js";
import type { GitHubRelease } from "../../src/lib/delta-upgrade.js";
import {
buildChangelogSummary,
type ChangeCategory,
...
No files found
No files found
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/install /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/install-script.test.ts /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/db/install-info.test.ts /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/db/install-info.ts
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/install</path> <type>file</type> <content> 1: #!/bin/bash 2: set -euo pipefail 3: 4: RED='\033[0;31m' 5: MUTED='\033[0;2m' 6: NC='\033[0m' 7: 8: # Sentry error telemetry — fire-and-forget error reporting via envelope API. 9: # Uses the CLI's public write-only DSN. No PII collected. 10: # Opt-out: SENTRY_CLI_NO_TELEMETRY=1 11: SENTRY_DSN_KEY="1188a86f3f8168f089450587b00bca66" 12: SENTRY_INGEST="https://o1.ingest.us.sentry.io" 13: SENTRY_PROJECT_ID="4510776311808000" 14: 15: # Generate a UUID for the event. Tries /proc, uuidgen, then awk fallback. ...
Found 100 matches (more matches available)
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:
Line 123: UPGRADE_SOURCES,
Line 214: test("falls back to the legacy latest release only on Toolkit HTTP 404", async () => {
Line 219: return new Response("Not Found", { status: 404 });
Line 293: status: 404,
Line 299: "No CLI upgrade source was found: every source returned HTTP 404"
Line 352: status: 500,
Line 358: "Failed to fetch from npm: 500"
Line 426: test("creates error with default message for offline_cache_miss", () => {
Line 427: const error = new UpgradeError("offline_cache_miss");
Line 428: expect(error.reason).toBe("offline_cache_miss");
Line 546: annotations: { version: "0.0.0-dev.1740393600" },
Line 551: return new Response("Not Found", { status: 404 });
Line 555: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts</path>
<type>file</type>
<content>
1630: () => false
1631: )
1632: ).toBe(false);
1633: });
1634:
1635: // Note: cleanupOldBinary intentionally does NOT clean up .download files
1636: // because an upgrade may be in progress in another process. The .download
1637: // cleanup is handled inside the upgrade flow under the exclusive lock.
1638:
1639: test("does not throw if files do not exist", () => {
1640: // Ensure files don't exist by attempting cleanup first
1641: startCleanupOldBinary();
1642:
1643: // Should not throw when called again
1644: expect(() => startCleanupOldBinary()).not.toThrow();
1645: });
1646: });
1647:
1648: describe("isNightlyVersion", () => {
1649: test("returns true for nightly version strings", () => {
1650: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts</path>
<type>file</type>
<content>
170: test("parses valid methods", () => {
171: expect(parseInstallationMethod("curl")).toBe("curl");
172: expect(parseInstallationMethod("brew")).toBe("brew");
173: expect(parseInstallationMethod("npm")).toBe("npm");
174: expect(parseInstallationMethod("pnpm")).toBe("pnpm");
175: expect(parseInstallationMethod("bun")).toBe("bun");
176: expect(parseInstallationMethod("yarn")).toBe("yarn");
177: });
178:
179: test("parses case-insensitively", () => {
180: expect(parseInstallationMethod("NPM")).toBe("npm");
181: expect(parseInstallationMethod("Curl")).toBe("curl");
182: expect(parseInstallationMethod("YARN")).toBe("yarn");
183: });
184:
185: test("throws on invalid method", () => {
186: expect(() => parseInstallationMethod("pip")).toThrow("Invalid method: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/custom-ca.ts</path> <type>file</type> <content> 1: /** 2: * Custom CA certificate loading for corporate TLS proxies. 3: * 4: * Reads CA bundles from (in priority order): 5: * 1. `sentry cli defaults ca-cert` (stored path in SQLite) 6: * 2. `NODE_EXTRA_CA_CERTS` env var 7: * 8: * Returns a `tls` options object for Bun's `fetch()`. On the Node.js npm 9: * distribution, Node natively honors `NODE_EXTRA_CA_CERTS` so the extra 10: * `tls.ca` option is harmless (ignored by Node's fetch). 11: * 12: * Security model: When the CA source is an env var (not a stored default) 13: * AND the target is SaaS (`*.sentry.io`), a one-time warning is logged. 14: * `sentry cli defaults ca-cert` silences the warning — the user has 15: * explicitly acknowledged the custom CA. See CLI-1K6 plan for the full 16: * threat model discussion. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/patch-cache.ts</path>
<type>file</type>
<content>
1: import { join } from "node:path";
2: import { makeCache, type PatchCache, type PatchChain } from "binpatch";
3: import { getConfigDir } from "./db/index.js";
4:
5: export type { ChainMeta, PatchStepMeta } from "binpatch";
6: // biome-ignore lint/performance/noBarrelFile: preserve the existing cache API
7: export { chainFileName, patchFileName } from "binpatch";
8:
9: function cache(): PatchCache {
10: return makeCache(join(getConfigDir(), "patch-cache"));
11: }
12:
13: export function savePatchesToCache(
14: chain: Pick<PatchChain, "patches" | "expectedSha256">,
15: steps: { fromVersion: string; toVersion: string }[]
16: ): Promise<void> {
17: return cache().save(chain, steps);
18: }
19:
20: export async function loadCachedChain(
21: currentVersion: string,
22: targetVersion: string
23: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/db/version-check.ts</path>
<type>file</type>
<content>
1: /**
2: * Version check state persistence.
3: *
4: * Stores the last time we checked for updates and the latest known version
5: * in the metadata table for the "new version available" notification.
6: */
7:
8: import { getDatabase } from "./index.js";
9: import { clearMetadata, getMetadata, setMetadata } from "./utils.js";
10:
11: const KEY_LAST_CHECKED = "version_check.last_checked";
12: const KEY_LATEST_VERSION = "version_check.latest_version";
13: /**
14: * Timestamp (ms) when we last printed the "new version available"
15: * notification to stderr. Separate from `last_checked` so the cached
16: * latest-version can stay hot for faster subsequent checks while the
17: * notification itself is rate-limited to once per day.
18: */
19: const KEY_LAST_NOTIFIED = ...
Found 35 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 462: export async function fetchLatestFromGitHub(
Line 547: const token = await getAnonymousToken(source, signal);
Line 548: const manifest = await fetchManifest(token, tag, signal, source);
Line 561: export async function fetchLatestNightlyVersion(
Line 590: return fetchLatestNightlyVersion();
Line 593: ? fetchLatestFromGitHub()
Line 598: export function resolveLatestUpgradeVersion(
Line 608: export async function resolveExistingUpgradeVersion(
Line 648: const token = await getAnonymousToken(source);
Line 650: await fetchManifest(token, `nightly-${version}`, undefined, source);
Line 676: const resolved = await resolveExistingUpgradeVersion(version);
Line 866: const token = await getAnonymousToken(source);
Line 868: ? ...