Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@sentry/core": "10.50.0",
"@sentry/node-core": "10.50.0",
"@sentry/sqlish": "^1.0.1",
"@sentry/symbolic": "13.5.0",
"@sentry/symbolic": "13.7.0",
"@spotlightjs/spotlight": "^4.11.7",
"@stricli/auto-complete": "^1.2.8",
"@stricli/core": "1.2.7",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ View a dashboard
- `-w, --web - Open in browser`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
- `-r, --refresh <value> - Auto-refresh interval in seconds (default: 60, min: 10)`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01"`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01"`

**Examples:**

Expand Down
2 changes: 1 addition & 1 deletion plugins/sentry-cli/skills/sentry-cli/references/event.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ List events for an issue
- `-n, --limit <value> - Number of events (1-1000) - (default: "25")`
- `-q, --query <value> - Search query (Sentry search syntax)`
- `--full - Include full event body (stacktraces)`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01" - (default: "7d")`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01" - (default: "7d")`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
- `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
2 changes: 1 addition & 1 deletion plugins/sentry-cli/skills/sentry-cli/references/explore.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Query aggregate event data (Explore)
- `-s, --sort <value> - Sort field (prefix with - for desc, e.g., "-count()")`
- `-e, --environment <value>... - Replay environment filter for --dataset replays (repeatable, comma-separated)`
- `-n, --limit <value> - Number of rows (1-1000) - (default: "25")`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01" - (default: "24h")`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01" - (default: "24h")`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
- `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
4 changes: 2 additions & 2 deletions plugins/sentry-cli/skills/sentry-cli/references/issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List issues in a project
- `-q, --query <value> - Search query (Sentry syntax, implicit AND, no OR operator)`
- `-n, --limit <value> - Maximum number of issues to list - (default: "25")`
- `-s, --sort <value> - Sort by: recommended, date, new, freq, user (default: recommended on sentry.io, else date)`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01" - (default: "90d")`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01" - (default: "90d")`
- `-c, --cursor <value> - Pagination cursor (use "next" for next page, "prev" for previous)`
- `--compact - Single-line rows for compact output (auto-detects if omitted)`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
Expand Down Expand Up @@ -92,7 +92,7 @@ List events for a specific issue
- `-n, --limit <value> - Number of events (1-1000) - (default: "25")`
- `-q, --query <value> - Search query (Sentry search syntax)`
- `--full - Include full event body (stacktraces)`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01" - (default: "7d")`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01" - (default: "7d")`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
- `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
2 changes: 1 addition & 1 deletion plugins/sentry-cli/skills/sentry-cli/references/log.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List logs from a project
- `-n, --limit <value> - Number of log entries (1-1000) - (default: "100")`
- `-q, --query <value> - Filter query (e.g., "level:error", "project:backend", "project:[a,b]")`
- `-f, --follow <value> - Stream logs (optionally specify poll interval in seconds)`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01"`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01"`
- `-s, --sort <value> - Sort order: "newest" (default) or "oldest" - (default: "newest")`
- `--fresh - Bypass cache, re-detect projects, and fetch fresh data`

Expand Down
2 changes: 1 addition & 1 deletion plugins/sentry-cli/skills/sentry-cli/references/replay.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ List recent Session Replays
- `-q, --query <value> - Search query (Sentry replay search syntax)`
- `-e, --environment <value>... - Filter by environment (repeatable, comma-separated)`
- `-s, --sort <value> - Sort by: date, oldest, duration, errors, activity, or a raw replay sort field - (default: "date")`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01" - (default: "7d")`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01" - (default: "7d")`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
- `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
2 changes: 1 addition & 1 deletion plugins/sentry-cli/skills/sentry-cli/references/span.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List spans in a project or trace
- `-n, --limit <value> - Number of spans (<=1000) - (default: "25")`
- `-q, --query <value> - Filter spans (e.g., "op:db", "project:backend", "project:[cli,api]")`
- `-s, --sort <value> - Sort order: date, duration - (default: "date")`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01" - (default: "7d")`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01" - (default: "7d")`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
- `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
4 changes: 2 additions & 2 deletions plugins/sentry-cli/skills/sentry-cli/references/trace.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List recent traces in a project
- `-n, --limit <value> - Number of traces (1-1000) - (default: "25")`
- `-q, --query <value> - Search query (Sentry search syntax)`
- `-s, --sort <value> - Sort by: date, duration - (default: "date")`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01" - (default: "7d")`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01" - (default: "7d")`
- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data`
- `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down Expand Up @@ -91,7 +91,7 @@ View logs associated with a trace

**Flags:**
- `-w, --web - Open trace in browser`
- `-t, --period <value> - Time range: "7d", "2026-05-01..2026-06-01", ">=2026-05-01" - (default: "14d")`
- `-t, --period <value> - Time range: "7d", "2026-06-01..2026-07-01", ">=2026-06-01" - (default: "14d")`
- `-n, --limit <value> - Number of log entries (<=1000) - (default: "100")`
- `-q, --query <value> - Filter query (e.g., "level:error", "project:backend", "project:[a,b]")`
- `-s, --sort <value> - Sort order: "newest" (default) or "oldest" - (default: "newest")`
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions src/commands/debug-files/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
* Honors the server-advertised `max_file_size` (oversized files are skipped)
* and `max_wait` (clamps the processing wait). `.zip` archives are scanned in
* place (disable with `--no-zips`); `--derived-data` additionally scans Xcode's
* DerivedData folder on macOS. `--symbol-maps` (BCSymbolMap resolution) and
* `--il2cpp-mapping` line mappings are deferred to follow-up PRs (see the
* command's full description).
* DerivedData folder on macOS. Managed PE assemblies that embed a Portable PDB
* have it extracted and uploaded automatically as a separate DIF. `--symbol-maps`
* (BCSymbolMap resolution) and `--il2cpp-mapping` line mappings are deferred to
* follow-up PRs (see the command's full description).
*/

import { createHash } from "node:crypto";
Expand Down Expand Up @@ -173,6 +174,9 @@ function difKey(dif: DebugFileUpload): string {
* Convert prepared files into the DIF upload list, optionally appending a
* source bundle per file when `--include-sources` is set.
*
* Embedded Portable PDBs (extracted from managed PE assemblies during scanning)
* arrive here as ordinary prepared DIFs, so no special handling is needed.
*
* Source files are read synchronously from the paths recorded in each object's
* debug info; files not present locally are skipped. A bundle is only added
* when it contains at least one source file.
Expand Down Expand Up @@ -454,6 +458,8 @@ export const uploadCommand = buildCommand({
" --no-zips Do not scan inside .zip archives\n\n" +
".zip archives are scanned in place by default; nested archives are not " +
"recursed.\n\n" +
"Managed PE assemblies (.NET) that embed a Portable PDB have it extracted " +
"and uploaded automatically as a separate <name>.pdb debug file.\n\n" +
"Usage:\n" +
" sentry debug-files upload ./build\n" +
" sentry debug-files upload ./symbols.zip\n" +
Expand Down
54 changes: 54 additions & 0 deletions src/lib/dif/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,60 @@ export function peekFormat(data: Uint8Array): string {
return Archive.peek(data) ?? "unknown";
}

/** An embedded Portable PDB extracted from a managed PE object. */
export type EmbeddedPpdbResult = {
/** The decompressed, standalone Portable PDB bytes. */
ppdb: Uint8Array;
/** Debug id of the PE the Portable PDB was embedded in (its advisory id). */
debugId: string;
};

/**
* Extract a Portable PDB embedded inside a managed Windows PE (.NET assembly).
*
* Managed PE images can carry their Portable PDB debug companion inline (debug
* directory entry type 17, deflate-compressed). This narrows each object in the
* archive to a PE via `ObjectFile.asPe()` and, for the first PE that embeds a
* Portable PDB, decompresses and returns those bytes together with that PE's
* debug id. The returned bytes are themselves a standalone Portable PDB that can
* be parsed and uploaded as a separate debug information file.
*
* Non-PE objects (and PEs without an embedded PPDB) are skipped, so this is safe
* to call unconditionally on any object file. A decompression/extraction error
* for an individual object is swallowed (logged at debug level) and treated as
* "no embedded PPDB", mirroring legacy `sentry-cli`, where a failed extraction
* never aborts the surrounding upload.
*
* @param data - The full contents of the object file (archive).
* @returns The embedded Portable PDB bytes plus the PE's debug id, or `null`
* when no object in the archive embeds a Portable PDB.
* @throws If the buffer cannot be parsed as a known object format.
*/
export function extractEmbeddedPpdb(
data: Uint8Array
): EmbeddedPpdbResult | null {
ensureInitialized();
const archive = new Archive(data);
for (const object of archive.objects()) {
const pe = object.asPe();
if (!pe) {
continue;
}
try {
const ppdb = pe.embeddedPpdb();
if (ppdb) {
return { ppdb, debugId: object.debugId };
}
} catch (err) {
log.debug(
`Failed to extract embedded Portable PDB for ${object.debugId}`,
err
);
}
}
return null;
}

/**
* Select the single object that source-bundling operates on: the first object
* that carries debug info, falling back to the first object in the archive.
Expand Down
Loading
Loading