Follow-up items from the code review of #46. None are blockers for that PR; tracking them here so they aren't lost.
Issues / Suggestions
1. Dead condition in unrecognised-subcommand guard
In did-git-sign/src/main.rs (the None => { ... } arm), the guard reads:
if let Some(f) = &cli.sign_file {
if cli.operation.is_none() {
anyhow::bail!(...);
}
}
The outer -Y handling returns early before this arm is reached, so cli.operation.is_none() is always true here. The inner check is dead — the outer if let Some(f) alone is sufficient. Minor, but the condition reads as defensive code for a branch that can't occur.
2. -Y verify args beyond -s/-I/-O could break again
Git's man page currently documents these flags, but any future flag (e.g. -U, -r) will hit the same clap rejection that fixes 6/7 solved. Consider #[arg(trailing_var_arg = true, allow_hyphen_values = true)] on a catch-all Vec<OsString> for the delegation path so new flags forward automatically — matching the "catch-all operation" split philosophy already applied one level up.
3. process::exit(code) after #[tokio::main] — stdio flushing note
The inline safety note is good, but stderr/stdout flushing behaviour is worth calling out explicitly: inherited stdio doesn't buffer in-process, so it's safe as-is. If future code adds any println! between delegation and exit, the Drop-skip becomes relevant. Consider adding that nuance to the existing comment.
4. DID_GIT_SIGN_SSH_KEYGEN trust boundary
An attacker with write access to the user's env can redirect verification to a fake binary that always returns 0. Given the tool already runs in the user's shell context this is not a new attack surface, but a one-line warning in the README (or rejecting the override when DID_GIT_SIGN_STRICT=1) would match defense-in-depth expectations for signing tooling.
5. user.signingKey set to a .json path
The init notice mitigates UX surprise, but some third-party git GUIs parse user.signingKey assuming it's a key path and may error/warn. Acceptable trade-off as documented — worth tracking if users report it.
6. setup_git_never_writes_user_email CWD invariant is implicit
The CwdGuard is dropped before the assertion and the verify command uses -C dir.path(), so the test is correct — but the invariant depends on a reader noticing the drop-point comment. Adding assert_eq!(std::env::current_dir().unwrap(), original) after the inner block would make the invariant explicit and catch future edits that move the assertion inside the guard's scope. Nit.
7. PR description / code mismatch on --email flag
The #46 description states the --email flag was removed, but no such field appears to be removed in the diff. Either the removal is missing or the description is inaccurate — worth confirming which, and correcting whichever is wrong.
Risks
R1. Leftover local user.email on upgrade
After upgrade, setup_git no longer writes user.email, but it also does not unset an existing DID value from a prior install. Users who previously ran init still have the broken email locally until they clear it manually. Options:
- (a) Actively
git config --local --unset user.email in setup_git when the current value looks like a DID.
- (b) Document the cleanup step in the init output.
R2. No integration test exercising the full git commit → sign → log --show-signature loop
Unit tests cover each piece, but the seven bugs fixed in #46 all originated from the integration gap. A shell-based e2e test (even gated behind #[ignore]) would prevent recurrence.
Source: review of #46.
Follow-up items from the code review of #46. None are blockers for that PR; tracking them here so they aren't lost.
Issues / Suggestions
1. Dead condition in unrecognised-subcommand guard
In
did-git-sign/src/main.rs(theNone => { ... }arm), the guard reads:The outer
-Yhandling returns early before this arm is reached, socli.operation.is_none()is always true here. The inner check is dead — the outerif let Some(f)alone is sufficient. Minor, but the condition reads as defensive code for a branch that can't occur.2.
-Y verifyargs beyond-s/-I/-Ocould break againGit's man page currently documents these flags, but any future flag (e.g.
-U,-r) will hit the same clap rejection that fixes 6/7 solved. Consider#[arg(trailing_var_arg = true, allow_hyphen_values = true)]on a catch-allVec<OsString>for the delegation path so new flags forward automatically — matching the "catch-all operation" split philosophy already applied one level up.3.
process::exit(code)after#[tokio::main]— stdio flushing noteThe inline safety note is good, but stderr/stdout flushing behaviour is worth calling out explicitly: inherited stdio doesn't buffer in-process, so it's safe as-is. If future code adds any
println!between delegation and exit, theDrop-skip becomes relevant. Consider adding that nuance to the existing comment.4.
DID_GIT_SIGN_SSH_KEYGENtrust boundaryAn attacker with write access to the user's env can redirect verification to a fake binary that always returns 0. Given the tool already runs in the user's shell context this is not a new attack surface, but a one-line warning in the README (or rejecting the override when
DID_GIT_SIGN_STRICT=1) would match defense-in-depth expectations for signing tooling.5.
user.signingKeyset to a.jsonpathThe init notice mitigates UX surprise, but some third-party git GUIs parse
user.signingKeyassuming it's a key path and may error/warn. Acceptable trade-off as documented — worth tracking if users report it.6.
setup_git_never_writes_user_emailCWD invariant is implicitThe
CwdGuardis dropped before the assertion and the verify command uses-C dir.path(), so the test is correct — but the invariant depends on a reader noticing the drop-point comment. Addingassert_eq!(std::env::current_dir().unwrap(), original)after the inner block would make the invariant explicit and catch future edits that move the assertion inside the guard's scope. Nit.7. PR description / code mismatch on
--emailflagThe #46 description states the
--emailflag was removed, but no such field appears to be removed in the diff. Either the removal is missing or the description is inaccurate — worth confirming which, and correcting whichever is wrong.Risks
R1. Leftover local
user.emailon upgradeAfter upgrade,
setup_gitno longer writesuser.email, but it also does not unset an existing DID value from a prior install. Users who previously raninitstill have the broken email locally until they clear it manually. Options:git config --local --unset user.emailinsetup_gitwhen the current value looks like a DID.R2. No integration test exercising the full git commit → sign →
log --show-signatureloopUnit tests cover each piece, but the seven bugs fixed in #46 all originated from the integration gap. A shell-based e2e test (even gated behind
#[ignore]) would prevent recurrence.Source: review of #46.