From f7fd8033b49ca64f5fcaae5b45b59a39d4b24456 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 1 May 2026 15:43:59 -0700 Subject: [PATCH] fix(plugins): redact git install failure urls --- src/plugins/git-install.test.ts | 21 +++++++++++++++++++++ src/plugins/git-install.ts | 4 +++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/plugins/git-install.test.ts b/src/plugins/git-install.test.ts index a63a7d8485e..f07ad0d2bd5 100644 --- a/src/plugins/git-install.test.ts +++ b/src/plugins/git-install.test.ts @@ -200,6 +200,27 @@ describe("installPluginFromGitSpec", () => { } }); + it("redacts authenticated git URLs from command failure details", async () => { + runCommandWithTimeoutMock.mockResolvedValueOnce({ + code: 1, + stdout: "", + stderr: "fatal: could not read Username for 'https://token:secret@github.com/acme/demo.git'", + }); + + const result = await installPluginFromGitSpec({ + spec: "git:https://token:secret@github.com/acme/demo.git", + }); + + expect(result.ok).toBe(false); + 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).not.toContain("token"); + expect(result.error).not.toContain("secret"); + } + expect(installPluginFromInstalledPackageDirMock).not.toHaveBeenCalled(); + }); + it("keeps the existing managed repo when replacement install fails", async () => { const gitDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-git-install-preserve-")); const normalizedSpec = "git:https://github.com/acme/demo.git"; diff --git a/src/plugins/git-install.ts b/src/plugins/git-install.ts index 1bb5482cdf0..4298a1c6f8c 100644 --- a/src/plugins/git-install.ts +++ b/src/plugins/git-install.ts @@ -235,7 +235,9 @@ function formatGitCommandFailure(params: { stdout: string; stderr: string; }): string { - const detail = sanitizeForLog(params.stderr.trim() || params.stdout.trim() || "git failed"); + const detail = sanitizeForLog( + redactSensitiveUrlLikeString(params.stderr.trim() || params.stdout.trim() || "git failed"), + ); return `failed to ${params.action} ${sanitizeForLog(redactSensitiveUrlLikeString(params.source.label))}: ${detail}`; }