From 04cd8617328808b6ecac6968b0a0e7f840a16f7a Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 1 May 2026 16:05:40 -0700 Subject: [PATCH] fix(shared): redact repeated URL userinfo --- src/plugins/git-install.test.ts | 6 +++++- src/shared/net/redact-sensitive-url.test.ts | 8 ++++++++ src/shared/net/redact-sensitive-url.ts | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/plugins/git-install.test.ts b/src/plugins/git-install.test.ts index f07ad0d2bd5..056aa32ae43 100644 --- a/src/plugins/git-install.test.ts +++ b/src/plugins/git-install.test.ts @@ -204,7 +204,8 @@ describe("installPluginFromGitSpec", () => { runCommandWithTimeoutMock.mockResolvedValueOnce({ code: 1, stdout: "", - stderr: "fatal: could not read Username for 'https://token:secret@github.com/acme/demo.git'", + stderr: + "fatal: could not read Username for 'https://token:secret@github.com/acme/demo.git' while retrying https://other:credential@github.com/acme/fallback.git", }); const result = await installPluginFromGitSpec({ @@ -215,8 +216,11 @@ describe("installPluginFromGitSpec", () => { if (!result.ok) { expect(result.error).toContain("failed to clone github.com/acme/demo"); expect(result.error).toContain("https://***:***@github.com/acme/demo.git"); + expect(result.error).toContain("https://***:***@github.com/acme/fallback.git"); expect(result.error).not.toContain("token"); expect(result.error).not.toContain("secret"); + expect(result.error).not.toContain("other"); + expect(result.error).not.toContain("credential"); } expect(installPluginFromInstalledPackageDirMock).not.toHaveBeenCalled(); }); diff --git a/src/shared/net/redact-sensitive-url.test.ts b/src/shared/net/redact-sensitive-url.test.ts index 2e376349a64..a849475e208 100644 --- a/src/shared/net/redact-sensitive-url.test.ts +++ b/src/shared/net/redact-sensitive-url.test.ts @@ -35,6 +35,14 @@ describe("redactSensitiveUrlLikeString", () => { ); }); + it("redacts every URL-like userinfo occurrence in arbitrary text", () => { + expect( + redactSensitiveUrlLikeString( + "fatal https://a:b@github.com/one.git and https://c:d@github.com/two.git", + ), + ).toBe("fatal https://***:***@github.com/one.git and https://***:***@github.com/two.git"); + }); + it("redacts protocol URLs that are too malformed to parse", () => { expect( redactSensitiveUrlLikeString( diff --git a/src/shared/net/redact-sensitive-url.ts b/src/shared/net/redact-sensitive-url.ts index 9596517fd80..13701541ec5 100644 --- a/src/shared/net/redact-sensitive-url.ts +++ b/src/shared/net/redact-sensitive-url.ts @@ -70,7 +70,7 @@ export function redactSensitiveUrlLikeString(value: string): string { return redactedUrl; } return value - .replace(/\/\/([^@/?#]+)@/, "//***:***@") + .replace(/\/\/([^@/?#\s]+)@/g, "//***:***@") .replace(/([?&])([^=&]+)=([^&]*)/g, (match, prefix: string, key: string) => isSensitiveUrlQueryParamName(key) ? `${prefix}${key}=***` : match, );