git: generate and verify the git CLI surface, the way surface-diff does for the forge API #537
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
#544 Epic: madtea's external contracts are asserted, not verified
sixfold-space/madtea
Reference
sixfold-space/madtea#537
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?
madtea shells out to git across 42 distinct subcommands and hundreds of flags. Nothing verifies that any of those argv shapes are valid for the git version we pin. The test suite proves the paths the tests walk; it says nothing about the flags on the paths they do not.
This is the counterpart #525 asked for and never built.
surface-diffalready does exactly this for the forge:extractEndpointswalks the gitea client AST,loadSpecloads the vendored specs indocs/api-specs/, and a miss on every platform is a bug while a miss on some is drift. Git has no equivalent.The point is not "does madtea run on old git". The point is a generated guarantee that everything we hand to git is valid for the git we pin, so that when git moves for a CVE we can re-run one check and see what broke.
Shape
Mirror the forge side rather than invent something:
docs/api-specs/gitea-1.26.1.json,forgejo-15.0.jsondocs/git-specs/git-<version>.jsonextractEndpointsAST walk of the clientTestAPISurfaceMatchesSpecTestGitSurfaceMatchesSpecA generator belongs in
cmd/madtea-dev, alongsidedocs generate, so the spec is produced from a real installed git rather than hand-maintained.Where the option surface comes from, measured
git can emit its own option list, but the coverage is uneven. Measured against git 2.47.3 on 2026-09-17:
--git-completion-helperoptionsgrepbranchstatuscat-filemerge-baselogrev-parseworktreeThe helper only covers a command's own
parse_optionstable.log,showanddiffinherit most of their options from the revision-walking and diff machinery, so the helper omits them:--format=,--graph,--grep=,--max-count,--no-mergesand--first-parentare all absent from bothgit log --git-completion-helperandgit log -h, and madtea uses every one of them.worktreeneeds per-subcommand queries (git worktree add --git-completion-helperreturns 17 options,list7,prune7,remove0).So a check built on the completion helper alone would produce false positives on exactly the commands madtea leans on hardest. The complete source is git's own documentation:
Documentation/git-log.adocpulls inrev-list-options.adoc, which is where the missing flags are defined. A usable generator likely combines the helper where it is rich with the documentation where it is not, and the generator must state which source each entry came from.Open, and blocking under the no-deferred-checks rule
The option-source strategy above is not settled. Whatever this lands as must not pin a value while that is unresolved, and must not claim coverage it does not have. If the generator cannot cover a command, that command is reported as uncovered rather than silently passing.
Acceptance
Refs #525, #536.
One more measurement worth recording here, because it bears on how much a generated check can actually promise.
git's own test suite does not cover
grep --end-of-options. In git 2.55.0, fourteen files undert/exercise that flag:logis covered.grepis not, and neither arecat-file,merge-baseordiff. madtea uses--end-of-optionson all four of those plusrev-parseand the tree/show path.gitcli(7)documents the flag as a general convention across commands, so madtea's usage is correct against the documented contract. But upstream only tests it on some commands, which is consistent with what 2.43.1's note describes: the form "failed to interpret--revas a rev" for some commands and was "fixed for many programs likeresetandcheckout". Documented universally, implemented unevenly, tested partially.The implication for this issue: a generated surface check can verify that a flag exists on a command. It cannot verify that the flag behaves as documented on that command, and for
--end-of-optionsspecifically that gap is where the 2.38.0 failure lived.git grep --git-completion-helperlists--end-of-optionsquite happily on a git where using it fails.So the check should not be described as proving the invocations work. It proves they are accepted. Behaviour still needs a real test against a real repo, which is what
TestMadTRefInspectGrepAtLocalOnlyRefdoes for this one case.