Skip to content

Commit 80b809d

Browse files
committed
Merge branch 'main' into feat/project-create
2 parents e357d8a + 42e4b88 commit 80b809d

File tree

14 files changed

+638
-10
lines changed

14 files changed

+638
-10
lines changed

CHANGELOG.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,47 @@
11
# Changelog
22

33
<!-- Craft will auto-populate this file -->
4+
## 0.11.0
5+
6+
### New Features ✨
7+
8+
#### Build
9+
10+
- Add hole-punch tool to reduce compressed binary size by @BYK in [#245](https://github.com/getsentry/cli/pull/245)
11+
- Add gzip-compressed binary downloads by @BYK in [#244](https://github.com/getsentry/cli/pull/244)
12+
13+
#### Other
14+
15+
- (args) Parse Sentry web URLs as CLI arguments by @BYK in [#252](https://github.com/getsentry/cli/pull/252)
16+
- (auth) Switch to /auth/ endpoint and add whoami command by @BYK in [#266](https://github.com/getsentry/cli/pull/266)
17+
- (list) Add pagination and consistent target parsing to all list commands by @BYK in [#262](https://github.com/getsentry/cli/pull/262)
18+
19+
### Bug Fixes 🐛
20+
21+
#### Telemetry
22+
23+
- Reduce noise from version-check JSON parse errors by @BYK in [#253](https://github.com/getsentry/cli/pull/253)
24+
- Skip Sentry reporting for 4xx API errors by @BYK in [#251](https://github.com/getsentry/cli/pull/251)
25+
- Handle EPIPE errors from piped stdout gracefully by @BYK in [#250](https://github.com/getsentry/cli/pull/250)
26+
- Upgrade Sentry SDK to 10.39.0 and remove custom patches by @BYK in [#249](https://github.com/getsentry/cli/pull/249)
27+
28+
#### Other
29+
30+
- (commands) Support org/project/id as single positional arg by @BYK in [#261](https://github.com/getsentry/cli/pull/261)
31+
- (db) Handle readonly database gracefully instead of crashing by @betegon in [#235](https://github.com/getsentry/cli/pull/235)
32+
- (errors) Show meaningful detail instead of [object Object] in API errors by @BYK in [#259](https://github.com/getsentry/cli/pull/259)
33+
- (issue-list) Propagate original errors instead of wrapping in plain Error by @BYK in [#254](https://github.com/getsentry/cli/pull/254)
34+
- (polyfill) Add exited promise and stdin to Bun.spawn Node.js polyfill by @BYK in [#248](https://github.com/getsentry/cli/pull/248)
35+
- (project-list) Add pagination and flexible target parsing by @BYK in [#221](https://github.com/getsentry/cli/pull/221)
36+
- (test) Prevent mock.module() leak from breaking test:isolated by @BYK in [#260](https://github.com/getsentry/cli/pull/260)
37+
- (upgrade) Remove v prefix from release URLs and work around Bun.write streaming bug by @BYK in [#243](https://github.com/getsentry/cli/pull/243)
38+
- Repair pagination_cursors composite PK and isolate test suites by @BYK in [#265](https://github.com/getsentry/cli/pull/265)
39+
40+
### Internal Changes 🔧
41+
42+
- (build) Replace local hole-punch script with binpunch package by @BYK in [#246](https://github.com/getsentry/cli/pull/246)
43+
- Use @sentry/api client for requests by @MathurAditya724 in [#226](https://github.com/getsentry/cli/pull/226)
44+
445
## 0.10.0
546

647
### New Features ✨

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sentry",
3-
"version": "0.11.0-dev.0",
3+
"version": "0.12.0-dev.0",
44
"description": "Sentry CLI - A command-line interface for using Sentry built by robots and humans for robots and humans",
55
"type": "module",
66
"bin": {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"name": "sentry-cli",
3-
"version": "0.11.0",
3+
"version": "0.12.0",
44
"description": "Skills for using the Sentry CLI to interact with Sentry from the command line"
55
}

plugins/sentry-cli/skills/sentry-cli/SKILL.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ sentry auth status
9494

9595
Print the stored authentication token
9696

97+
#### `sentry auth whoami`
98+
99+
Show the currently authenticated user
100+
101+
**Flags:**
102+
- `--json - Output as JSON`
103+
97104
### Org
98105

99106
Work with Sentry organizations
@@ -677,6 +684,17 @@ List recent traces in a project
677684
- `-s, --sort <value> - Sort by: date, duration - (default: "date")`
678685
- `--json - Output as JSON`
679686

687+
### Whoami
688+
689+
Show the currently authenticated user
690+
691+
#### `sentry whoami`
692+
693+
Show the currently authenticated user
694+
695+
**Flags:**
696+
- `--json - Output as JSON`
697+
680698
## Output Formats
681699

682700
### JSON Output

src/app.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from "@stricli/core";
99
import { apiCommand } from "./commands/api.js";
1010
import { authRoute } from "./commands/auth/index.js";
11+
import { whoamiCommand } from "./commands/auth/whoami.js";
1112
import { cliRoute } from "./commands/cli/index.js";
1213
import { eventRoute } from "./commands/event/index.js";
1314
import { helpCommand } from "./commands/help.js";
@@ -56,6 +57,7 @@ export const routes = buildRouteMap({
5657
teams: teamListCommand,
5758
logs: logListCommand,
5859
traces: traceListCommand,
60+
whoami: whoamiCommand,
5961
},
6062
defaultCommand: "help",
6163
docs: {

src/commands/auth/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { logoutCommand } from "./logout.js";
44
import { refreshCommand } from "./refresh.js";
55
import { statusCommand } from "./status.js";
66
import { tokenCommand } from "./token.js";
7+
import { whoamiCommand } from "./whoami.js";
78

89
export const authRoute = buildRouteMap({
910
routes: {
@@ -12,13 +13,15 @@ export const authRoute = buildRouteMap({
1213
refresh: refreshCommand,
1314
status: statusCommand,
1415
token: tokenCommand,
16+
whoami: whoamiCommand,
1517
},
1618
docs: {
1719
brief: "Authenticate with Sentry",
1820
fullDescription:
1921
"Manage authentication with Sentry. Use 'sentry auth login' to authenticate, " +
2022
"'sentry auth logout' to remove credentials, 'sentry auth refresh' to manually refresh your token, " +
2123
"'sentry auth status' to check your authentication status, " +
24+
"'sentry auth whoami' to show your current user identity, " +
2225
"and 'sentry auth token' to print your token for use in scripts.",
2326
},
2427
});

src/commands/auth/login.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ export const loginCommand = buildCommand({
6767
);
6868
}
6969

70-
// Try to get user info (works with API tokens, may not work with OAuth App tokens)
70+
// Fetch and cache user info via /auth/ (works with all token types).
71+
// A transient failure here must not block login — the token is already valid.
7172
let user: Awaited<ReturnType<typeof getCurrentUser>> | undefined;
7273
try {
7374
user = await getCurrentUser();
@@ -78,7 +79,7 @@ export const loginCommand = buildCommand({
7879
name: user.name,
7980
});
8081
} catch {
81-
// Ignore - user info is optional, token may not have permission
82+
// Non-fatal: user info is supplementary. Token remains stored and valid.
8283
}
8384

8485
stdout.write(`${success("✓")} Authenticated with API token\n`);

src/commands/auth/whoami.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* sentry auth whoami
3+
*
4+
* Display the currently authenticated user's identity by fetching live from
5+
* the /auth/ endpoint. Unlike `sentry auth status`, this command only shows
6+
* who you are — no token details, no defaults, no org verification.
7+
*/
8+
9+
import type { SentryContext } from "../../context.js";
10+
import { getCurrentUser } from "../../lib/api-client.js";
11+
import { buildCommand } from "../../lib/command.js";
12+
import { isAuthenticated } from "../../lib/db/auth.js";
13+
import { setUserInfo } from "../../lib/db/user.js";
14+
import { AuthError } from "../../lib/errors.js";
15+
import { formatUserIdentity, writeJson } from "../../lib/formatters/index.js";
16+
17+
type WhoamiFlags = {
18+
readonly json: boolean;
19+
};
20+
21+
export const whoamiCommand = buildCommand({
22+
docs: {
23+
brief: "Show the currently authenticated user",
24+
fullDescription:
25+
"Fetch and display the identity of the currently authenticated user.\n\n" +
26+
"This calls the Sentry API live (not cached) so the result always reflects " +
27+
"the current token. Works with all token types: OAuth, API tokens, and OAuth App tokens.",
28+
},
29+
parameters: {
30+
flags: {
31+
json: {
32+
kind: "boolean",
33+
brief: "Output as JSON",
34+
default: false,
35+
},
36+
},
37+
},
38+
async func(this: SentryContext, flags: WhoamiFlags): Promise<void> {
39+
const { stdout } = this;
40+
41+
if (!(await isAuthenticated())) {
42+
throw new AuthError("not_authenticated");
43+
}
44+
45+
const user = await getCurrentUser();
46+
47+
// Keep cached user info up to date. Non-fatal: display must succeed even
48+
// if the DB write fails (read-only filesystem, corrupted database, etc.).
49+
try {
50+
setUserInfo({
51+
userId: user.id,
52+
email: user.email,
53+
username: user.username,
54+
name: user.name,
55+
});
56+
} catch {
57+
// Cache update failure is non-essential — user identity was already fetched.
58+
}
59+
60+
if (flags.json) {
61+
writeJson(stdout, {
62+
id: user.id,
63+
name: user.name ?? null,
64+
username: user.username ?? null,
65+
email: user.email ?? null,
66+
});
67+
return;
68+
}
69+
70+
stdout.write(`${formatUserIdentity(user)}\n`);
71+
},
72+
});

src/lib/api-client.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,23 @@ export async function apiRequestToRegion<T>(
305305
}
306306

307307
const data = await response.json();
308-
const validated = schema ? schema.parse(data) : (data as T);
309308

310-
return { data: validated, headers: response.headers };
309+
if (schema) {
310+
const result = schema.safeParse(data);
311+
if (!result.success) {
312+
// Treat schema validation failures as API errors so they surface cleanly
313+
// through the central error handler rather than showing a raw ZodError
314+
// stack trace. This guards against unexpected API response format changes.
315+
throw new ApiError(
316+
`Unexpected response format from ${endpoint}`,
317+
response.status,
318+
result.error.message
319+
);
320+
}
321+
return { data: result.data, headers: response.headers };
322+
}
323+
324+
return { data: data as T, headers: response.headers };
311325
}
312326

313327
/**
@@ -1422,12 +1436,15 @@ export async function triggerSolutionPlanning(
14221436

14231437
/**
14241438
* Get the currently authenticated user's information.
1425-
* Uses the /users/me/ endpoint on the control silo.
1439+
*
1440+
* Uses the `/auth/` endpoint on the control silo, which works with all token
1441+
* types (OAuth, API tokens, OAuth App tokens). Unlike `/users/me/`, this
1442+
* endpoint does not return 403 for OAuth tokens.
14261443
*/
14271444
export async function getCurrentUser(): Promise<SentryUser> {
14281445
const { data } = await apiRequestToRegion<SentryUser>(
14291446
getControlSiloUrl(),
1430-
"/users/me/",
1447+
"/auth/",
14311448
{ schema: SentryUserSchema }
14321449
);
14331450
return data;

0 commit comments

Comments
 (0)