Skip to content

Commit 6a8a129

Browse files
committed
improve cli error handling
1 parent e441a06 commit 6a8a129

3 files changed

Lines changed: 90 additions & 7 deletions

File tree

packages/cli-v3/src/commands/deploy.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { DeploymentEventFromString } from "@trigger.dev/core/v3/schemas";
1111
import type { Command } from "commander";
1212
import { Option as CommandOption } from "commander";
1313
import { join, relative, resolve } from "node:path";
14-
import { env, isCI } from "std-env";
14+
import { isCI } from "std-env";
1515
import { x } from "tinyexec";
1616
import { z } from "zod";
1717
import chalk from "chalk";
@@ -270,8 +270,8 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
270270
verifyDirectory(dir, projectPath);
271271

272272
const authorization = await authenticateForDeploy({
273-
secretKey: env.TRIGGER_SECRET_KEY,
274-
apiUrl: env.TRIGGER_API_URL ?? options.apiUrl,
273+
secretKey: process.env.TRIGGER_SECRET_KEY,
274+
apiUrl: process.env.TRIGGER_API_URL ?? options.apiUrl,
275275
profile: options.profile,
276276
silent: options.plain,
277277
login,

packages/cli-v3/src/deploy/auth.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,62 @@ describe("authenticateForDeploy", () => {
7878
});
7979
expect(result).toEqual({ ok: false, error: "login result" });
8080
});
81+
82+
it("rejects a PAT in TRIGGER_SECRET_KEY with a helpful error", async () => {
83+
const result = await authenticateForDeploy({
84+
secretKey: "tr_pat_abc123",
85+
profile: "default",
86+
silent: true,
87+
login: async () => ({ ok: false, error: "should not be called" }),
88+
});
89+
90+
expect(result).toEqual({
91+
ok: false,
92+
error: expect.stringContaining("TRIGGER_ACCESS_TOKEN"),
93+
});
94+
});
95+
96+
it("rejects an OAT in TRIGGER_SECRET_KEY with a helpful error", async () => {
97+
const result = await authenticateForDeploy({
98+
secretKey: "tr_oat_abc123",
99+
profile: "default",
100+
silent: true,
101+
login: async () => ({ ok: false, error: "should not be called" }),
102+
});
103+
104+
expect(result).toEqual({
105+
ok: false,
106+
error: expect.stringContaining("TRIGGER_ACCESS_TOKEN"),
107+
});
108+
});
109+
110+
it("rejects a secret key that doesn't look like an API key", async () => {
111+
const result = await authenticateForDeploy({
112+
secretKey: "not-a-valid-key",
113+
profile: "default",
114+
silent: true,
115+
login: async () => ({ ok: false, error: "should not be called" }),
116+
});
117+
118+
expect(result).toEqual({
119+
ok: false,
120+
error: expect.stringContaining("does not look like a Trigger.dev API key"),
121+
});
122+
});
123+
124+
it("throws a descriptive error for an invalid API URL", async () => {
125+
await expect(
126+
authenticateForDeploy({
127+
secretKey: "tr_prod_sk_deploy",
128+
apiUrl: "not-a-url",
129+
profile: "default",
130+
silent: true,
131+
login: async () => ({ ok: false, error: "should not be called" }),
132+
})
133+
).rejects.toThrow(
134+
'Invalid API URL "not-a-url". Check your TRIGGER_API_URL environment variable or --api-url flag.'
135+
);
136+
});
81137
});
82138

83139
describe("userIdForDeploy", () => {

packages/cli-v3/src/deploy/auth.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { CLOUD_API_URL, CLOUD_WEB_URL } from "../consts.js";
22
import type { LoginResult, LoginResultOk } from "../utilities/session.js";
33

4+
const personalTokenPrefix = "tr_pat_";
5+
const organizationTokenPrefix = "tr_oat_";
6+
const apiKeyPrefix = "tr_";
7+
48
export type DeployAuthorization =
59
| LoginResultOk
610
| {
@@ -45,6 +49,23 @@ export async function authenticateForDeploy({
4549
});
4650
}
4751

52+
if (secretKey.startsWith(personalTokenPrefix) || secretKey.startsWith(organizationTokenPrefix)) {
53+
return {
54+
ok: false,
55+
error: `TRIGGER_SECRET_KEY is set to a ${
56+
secretKey.startsWith(personalTokenPrefix) ? "Personal" : "Organization"
57+
} Access Token. Use TRIGGER_ACCESS_TOKEN instead, or remove TRIGGER_SECRET_KEY and use \`trigger login\`.`,
58+
};
59+
}
60+
61+
if (!secretKey.startsWith(apiKeyPrefix)) {
62+
return {
63+
ok: false,
64+
error:
65+
"TRIGGER_SECRET_KEY does not look like a Trigger.dev API key. API keys start with \`tr_\` (e.g. \`tr_prod_...\`).",
66+
};
67+
}
68+
4869
return {
4970
ok: true,
5071
profile,
@@ -62,10 +83,16 @@ function dashboardUrlForApiUrl(apiUrl: string): string {
6283
return CLOUD_WEB_URL;
6384
}
6485

65-
const url = new URL(apiUrl);
66-
if (url.hostname.startsWith("api.") && url.hostname.endsWith(".trigger.dev")) {
67-
url.hostname = url.hostname.slice(4);
68-
return url.toString().replace(/\/$/, "");
86+
try {
87+
const url = new URL(apiUrl);
88+
if (url.hostname.startsWith("api.") && url.hostname.endsWith(".trigger.dev")) {
89+
url.hostname = url.hostname.slice(4);
90+
return url.toString().replace(/\/$/, "");
91+
}
92+
} catch {
93+
throw new Error(
94+
`Invalid API URL "${apiUrl}". Check your TRIGGER_API_URL environment variable or --api-url flag.`
95+
);
6996
}
7097

7198
return apiUrl;

0 commit comments

Comments
 (0)