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
5 changes: 5 additions & 0 deletions .changeset/blocked-403-not-the-key.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@qawolf/cli": patch
---

When a firewall in front of the QA Wolf API blocks a command's request with HTTP 403, the error no longer tells you to check your API key; it says the request was blocked before it reached the API.
2 changes: 2 additions & 0 deletions src/core/messages/authErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const authErrorMessages = {
`QA Wolf API refused the${noun ? ` ${noun}` : ""} request (HTTP 402): billing prevented it.`,
rejected403: (noun: string | undefined) =>
`QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 403). Check that your API key has access to this environment.`,
blocked403: (noun: string | undefined) =>
`The${noun ? ` ${noun}` : ""} request was blocked before it reached the QA Wolf API (HTTP 403), so your API key was not checked.`,
/**
* A 404 is answered by what the request named, because almost none of them
* are about an environment. Only `notFound404Environment` keeps the wording
Expand Down
11 changes: 11 additions & 0 deletions src/shell/platform/describeErrors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ describe("describeRequestError", () => {
expect(described.exitCode).toBe(exitCodes.auth);
});

it("does not blame the API key for a 403 the QA Wolf API did not send", () => {
const described = describeRequestError(
httpError(403, "<html>gateway</html>"),
baseUrl,
"runner.evaluateSnippet",
);

expect(described.error).not.toContain("API key has access");
expect(described.error).toContain("before it reached the QA Wolf API");
});

it("maps HTTP 402 to the payment exit code", () => {
const described = describeRequestError(
httpError(402),
Expand Down
6 changes: 5 additions & 1 deletion src/shell/platform/describeErrors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { formatSeconds } from "~/core/formatSeconds.js";
import { parseJson } from "~/core/parseJson.js";
import { authMessages } from "~/core/messages/index.js";
import type { NotFoundSubject } from "~/core/publicApi/notFoundSubject.js";
import { exitCodes } from "~/shell/exit.js";
Expand Down Expand Up @@ -64,8 +65,11 @@ export function describeRequestError(
exitCode: exitCodes.payment,
...body,
};
// The API answers errors with JSON, so any other 403 body came from a proxy.
if (err.status === 403)
return { error: m.request.rejected403(noun), ...body };
return parseJson(err.body) === undefined
? { error: m.request.blocked403(noun) }
: { error: m.request.rejected403(noun), ...body };
if (err.status === 404) return describeNotFound(notFound, noun, reason);
return { error: m.request.failedWithStatus(err.status, noun), ...body };
}
Expand Down
Loading