Skip to content

Fix review findings: injection, Windows doctor, config detection, worktree, docs#1

Merged
jmarette merged 11 commits into
masterfrom
fix/audit-findings
Jun 13, 2026
Merged

Fix review findings: injection, Windows doctor, config detection, worktree, docs#1
jmarette merged 11 commits into
masterfrom
fix/audit-findings

Conversation

@jmarette

Copy link
Copy Markdown
Owner

A full review of the codebase surfaced several correctness, cross-platform and
input-validation issues. This PR fixes them, adds regression tests, and corrects
a couple of stale doc claims. One focused commit per finding (the repo merges
with merge commits, so each commit is preserved).

Fixes

Security / input validation

  • Reject control characters in signing keys and escape them when rendering a
    fragment — a newline in --signing-key could otherwise inject an arbitrary
    gitconfig section (e.g. core.sshCommand) into the fragment git includes for
    every routed repo. The edit path was already safe (git config --file).

Cross-platform correctness

  • doctor compared a route's recomputed canonical path against the stored
    gitdir without to_git_path, so on Windows (\\?\C:\...) every routed
    directory was falsely flagged as non-canonical, with advice that never cleared.

Git-semantics correctness

  • init/doctor/uninstall detected the include and user.useConfigOnly via
    git config --global, which resolves to a single file; they went blind to the
    XDG global config once ~/.gitconfig appeared later (so uninstall could
    leave the include behind). They now scan the concrete global files directly.
  • use warns when routing a linked worktree's or submodule's own path, where
    git matches the main repository and the route would never apply.

Robustness

  • edit validates all fields before writing any (no partial write on a rejected
    patch).
  • delete rewrites the routes file (crash-safe) before removing the fragment.
  • doctor flags a duplicate gitdir route even when one side is a hand-added
    (preserved) [includeIf] block.
  • init no longer clobbers a same-second backup of the global config.

Docs

  • The "bare repo at a routed root is not matched" caveat was wrong — it is
    matched (routes are stored with a trailing slash). Corrected.
  • Reopened an ## [Unreleased] changelog section.
  • Noted that PRs are merged, not squashed, so each commit should be a clean
    Conventional Commit.

Tests

  • 12 new regression tests (unit + end-to-end), including a Windows-form unit
    test for the doctor canonical comparison that runs on the macOS/Linux hosts.
  • cargo fmt --check, cargo clippy --all-targets -- -D warnings, and
    cargo test (51 unit + 48 integration) all green.

jmarette added 11 commits June 14, 2026 01:11
Reject control characters in signing keys (a newline could otherwise inject an
arbitrary section — e.g. core.sshCommand — into the fragment git includes for
routed repos), escape control characters when rendering as defense in depth, and
validate every field of an edit up front so a rejected patch is a no-op instead
of leaving an earlier field already written.
git config --global resolves to a single file (~/.gitconfig once it exists), so
detecting and removing the include or user.useConfigOnly went blind to the XDG
file when ~/.gitconfig appeared later. Scan the concrete global files directly,
and let uninstall clean whichever one holds them.
doctor recomputed a route's canonical path and compared it to the stored gitdir
without to_git_path, so on Windows (where fs::canonicalize yields \\?\C:\...)
every routed directory was falsely flagged as non-canonical.
doctor counted only managed entries, so a duplicate split across a managed route
and a hand-added [includeIf] block (git applies both) went unreported.
git matches gitdir: against the .git directory under the main repository, so a
route on a linked worktree's or submodule's own path is never applied; use now
warns instead of silently recording a dead route.
The backup name used a 1-second-resolution timestamp and fs::copy overwrites, so
two mutating init runs in the same second lost a backup; pick a free name.
Saving routes (crash-safe via atomic_write) first means an interruption leaves a
present-but-unrouted fragment rather than a route pointing at a deleted fragment.
A bare repo at a routed root IS matched (routes are stored with a trailing
slash); correct the README caveat, and reopen an Unreleased changelog section
documenting these fixes.
End-to-end coverage for signing-key rejection, atomic edits, XDG include
detection/uninstall, useConfigOnly idempotency, a nonexistent GIT_CONFIG_GLOBAL
target, doctor's non-canonical and duplicate diagnostics, and the linked-worktree
warning.
The repo merges PRs with a merge commit (squash is disabled), so every commit is
preserved in master; tell contributors to make each commit a clean Conventional
Commit rather than relying on the PR title.
The setup commit in the (unrouted) dev/main repo had no user.name/email. CI
runners — unlike a dev machine, where git auto-derives an ident from the OS user
— have an empty ident, so the commit (and the test) failed on Linux and Windows.
@jmarette jmarette merged commit 82bf394 into master Jun 13, 2026
9 checks passed
@jmarette jmarette deleted the fix/audit-findings branch June 13, 2026 23:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant