git: replace the 17 Run* variants with one call that takes options #527
Labels
No labels
breaking
bug
documentation
enhancement
epic
good first issue
help wanted
refactoring
resolution/duplicate
resolution/invalid
resolution/wontfix
security
severity/critical
severity/high
severity/low
severity/medium
status/abandoned
status/blocked
status/needs-decision
status/needs-info
status/needs-verification
testing
upstream
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
Depends on
#524 git: pin the git output contract and declare a minimum git version
sixfold-space/madtea
#535 git: ssh and ssh-only mode are ignored by six credential-bearing git legs
sixfold-space/madtea
Reference
sixfold-space/madtea#527
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What happens
internal/gitexports 17 functions that run git. Each one is a fixed mix of three options: a working directory or not, forge auth or not, and a way to capture output (stdout only, stdout and stderr, stderr only, or passthrough). Examples:RunGit,RunGitDir,RunGitWithStderr,RunGitDirWithStderr,RunGitAuth,RunGitAuthWithCredentials,RunGitAuthDirWithCredentials,RunGitAuthPassthrough,RunGitAuthCaptureStderr,RunGitAuthDirCaptureStderr,RunGitAuthDirCaptureStderrOnly,RunGitAuthDirWithStderr,RunGitAuthWithStderr, andRunGitCloneUnauthenticated.A new need means a new function name, and a caller must find the right one of 17.
Callers also repeat a test seam per file, about 30 times, for example:
Depends on
Issue 524 adds one shared function that starts every git process (it sets
LC_ALL=Cand checks the minimum git version) and removes the directexec.Command("git", ...)calls. This issue builds on that function.Ask
git.Run(ctx, git.Opts{Dir: dir, Auth: true, Capture: git.Stderr}, args...). The exact shape is part of the work.Run*caller moves to it, and the 17 variants go.GIT_ASKPASS,GIT_TERMINAL_PROMPT=0, and no credential on argv.Acceptance
internal/gitexports one run call, plus any helper that is not a run variant.xxxRunGit* = libgit.RunGit*seam variables remain.Plan: this lands as six PRs, not one. A single diff here would be over a thousand lines and would mix a security-sensitive API design with a mechanical caller sweep, which is not reviewable in one read.
The enabling trick is that the 15 variants become one-line wrappers over the new call first. Nothing breaks, so the callers move in small batches afterwards and every step compiles and gates green on its own.
internal/git: addOptsandRun, the 15 variants delegate to itinternal/cmd/gitcallersinternal/service/gitcallersinternal/mcpand the remaining callersStep 1 is the only one that needs hard review. The rest are sweeps.
What step 1 has to get right
The issue text describes three options: a directory, auth, and a capture mode. Reading the source, the variants actually differ on six axes, and three of them are security-relevant. A three-axis collapse would silently change behaviour:
ErrNotConfiguredfallback to the unguarded plain runner, or explicit credentials passed in.remoteVerbGuard- applied byRunGitDirandRunGitDirWithStderronly. Not byRunGitCloneUnauthenticated(a deliberate exemption, #163), not by any auth variant, not by the unauthenticated fallback.RunGitAuthPassthrough,RunGitAuthDirCaptureStderrandRunGitAuthDirWithStderr. Not inRunGitAuthDirCaptureStderrOnly, not inRunGitAuthDirWithCredentials.GIT_TERMINAL_PROMPT=0- set byRunGitCloneUnauthenticatedand bysetupAuthCmd.Step 1 carries a table with one row per variant naming its value on all six axes, taken from the source rather than inferred from the name, plus table tests that lock each axis. Axes 4 and 5 are the ones a careless collapse gets wrong, and
remoteVerbGuardis a non-overridable guard under ADR 0009, soOptsmust not expose a way to turn it off where it is on today.RunSSHAGitPushinagit.gois out of scope throughout. It is a composed AGit push operation, not a generic run variant.Every PR references this issue; the last one closes it.