#157: redact remote-URL user-info before it reaches a log
The four log lines added with the worktree HTTPS rewrite echoed the origin URL verbatim, and one of them echoed the ssh:// authority, which carries user-info. An ssh authority is normally just git@, so in practice this changes nothing -- but a remote URL is not obviously a credential channel, and that is precisely why one has leaked here three times (#157, #182). Redact at the log call, not after it surprises someone.
This commit is contained in:
@@ -211,6 +211,17 @@ public final class GitWorktrees implements Worktrees {
|
||||
* guessing at it risks rewriting to the wrong place. A repo provisioned from that form keeps
|
||||
* today's (broken, if the policy blocks the agent) SSH-only behaviour rather than a wrong rewrite.
|
||||
*/
|
||||
/**
|
||||
* Blank the user-info of a remote URL before it reaches a log. A remote URL is not obviously a
|
||||
* credential channel, which is exactly why one has leaked here three times ({@code git remote -v}
|
||||
* printing a token inline, and fleetd #157 / #182). An {@code ssh://} authority normally carries
|
||||
* only {@code git@}, so this usually changes nothing — it is here so that the one origin that
|
||||
* does carry a secret cannot print it. Matches every {@code ://…@} pair, not just the first.
|
||||
*/
|
||||
private static String redactUserInfo(String url) {
|
||||
return url == null ? null : url.replaceAll("://[^@/]*@", "://<redacted>@");
|
||||
}
|
||||
|
||||
private void configureHttpsUrlRewriteForSshOrigin(String repoRoot, String worktreePath) {
|
||||
if (exitCode("git", "-C", repoRoot, "config", "--get", "remote.origin.url") != 0) {
|
||||
return;
|
||||
@@ -220,20 +231,20 @@ public final class GitWorktrees implements Worktrees {
|
||||
try {
|
||||
uri = new URI(origin);
|
||||
} catch (URISyntaxException e) {
|
||||
log.warn("origin URL {} is not a valid URI; skipping worktree HTTPS rewrite", origin);
|
||||
log.warn("origin URL {} is not a valid URI; skipping worktree HTTPS rewrite", redactUserInfo(origin));
|
||||
return;
|
||||
}
|
||||
String scheme = uri.getScheme();
|
||||
if (!"ssh".equalsIgnoreCase(scheme)) {
|
||||
// Already https:// (the credential helper covers it), or a scheme-less/scp-like origin
|
||||
// left alone on purpose — see the javadoc above.
|
||||
log.debug("origin scheme is not ssh ({}) — no worktree HTTPS rewrite needed", origin);
|
||||
log.debug("origin scheme is not ssh ({}) — no worktree HTTPS rewrite needed", redactUserInfo(origin));
|
||||
return;
|
||||
}
|
||||
String host = uri.getHost();
|
||||
String authority = uri.getRawAuthority();
|
||||
if (host == null || host.isBlank() || authority == null || authority.isBlank()) {
|
||||
log.warn("ssh origin {} has no resolvable host; skipping worktree HTTPS rewrite", origin);
|
||||
log.warn("ssh origin {} has no resolvable host; skipping worktree HTTPS rewrite", redactUserInfo(origin));
|
||||
return;
|
||||
}
|
||||
String sshBase = "ssh://" + authority + "/";
|
||||
@@ -241,7 +252,7 @@ public final class GitWorktrees implements Worktrees {
|
||||
exec("git", "-C", worktreePath, "config", "--worktree", "--replace-all",
|
||||
"url." + httpsBase + ".insteadOf", sshBase);
|
||||
log.info("worktree {} rewrites {} to {} (worktree-scoped; parent checkout untouched)",
|
||||
worktreePath, sshBase, httpsBase);
|
||||
worktreePath, redactUserInfo(sshBase), httpsBase);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user