diff --git a/packages/cli/src/lib/credential-redaction.ts b/packages/cli/src/lib/credential-redaction.ts index d119e080b..51eceb4fb 100644 --- a/packages/cli/src/lib/credential-redaction.ts +++ b/packages/cli/src/lib/credential-redaction.ts @@ -31,6 +31,9 @@ const SENTRY_CREDENTIAL = new RegExp( String.raw`\bsntry[suc]_[A-Za-z0-9._~+/=-]+(?:(?:\r\n|(?! )[\s\x00-\x1f\x7f-\x9f]|${ESCAPED_CONTROL})[ \t]*[A-Za-z0-9._~+/=-]+)*`, "gi", ); +// Onboarding run tokens grant write access to a run's progress. They have no +// prefix to match on, so match the field name instead. +const RUN_TOKEN = /(\brun_?token\\*["']?\s*[=:]\s*\\*["']?)[A-Za-z0-9]+/gi; /** * Use the runtime's final delimiter because an invalid token can contain quotes. @@ -87,5 +90,6 @@ export function redactCredentialText(text: string): string { : `${quote}[REDACTED]${quote}`, ) .replace(BEARER_CREDENTIAL, "Bearer [REDACTED]") - .replace(SENTRY_CREDENTIAL, "[REDACTED]"); + .replace(SENTRY_CREDENTIAL, "[REDACTED]") + .replace(RUN_TOKEN, "$1[REDACTED]"); } diff --git a/packages/cli/test/lib/credential-redaction.test.ts b/packages/cli/test/lib/credential-redaction.test.ts index 21c4eb9d1..f0e1fcd22 100644 --- a/packages/cli/test/lib/credential-redaction.test.ts +++ b/packages/cli/test/lib/credential-redaction.test.ts @@ -42,6 +42,19 @@ describe("credential redaction", () => { expect(redactCredentialText(message)).toBe(message); }); + test.each([ + [ + "runToken=SYNTHETIC0,stage=connect_agent", + "runToken=[REDACTED],stage=connect_agent", + ], + ['{"runToken":"SYNTHETIC0"}', '{"runToken":"[REDACTED]"}'], + ])("redacts onboarding run tokens: %s", (input, expected) => { + expect(redactCredentialText(input)).toBe(expected); + expect( + JSON.parse(redactCredentialText(JSON.stringify({ message: input }))), + ).toEqual({ message: expected }); + }); + test.each([ "sntrys_SYNTHETIC_PAYLOAD\n_SYNTHETIC_SECRET", "sntryu_SYNTHETIC_PAYLOAD\r\n_SYNTHETIC_SECRET",