v3.0.2
git-tidy 3.0.2 — round fifteen
3.0.1 could tell you it had removed a credential when it had not.
git config --replace-all takes a POSIX regex as its third argument, not a
literal, so a password containing a +, ? or * did not match its own value and
git appended instead of replacing. The secret stayed in .git/config, the
remote grew a second push URL, every later run appended another copy, and the
summary said the credential had been taken out. Somebody who read that line and
decided not to rotate the token was worse off than before it ran. The pattern is
anchored and escaped now, and the value is read back before anything is called
applied — this is the one remedy whose silent failure leaves a person believing
they are safe.
Also in --fix:
- Answering
qat the second credential prompt threw away the record of the
first, which had really been rewritten, while the run printed "everything
already done is kept". _check_credentials was the only accumulator in the file
that returned a list instead of filling the caller's. - Both prompts read identically. They name the setting now, url or pushurl.
- A repository with no remote could never have its detached HEAD put back:
default_branch resolves through refs/remotes only, so the refusal said "no
branch to go back to" while local main sat there containing HEAD. A repository
with no remote is where a detached HEAD matters most.
YAML: yesterday's splitlines() → split("\n") traded one wrong set of line breaks
for another. splitlines() broke on \x0b, \x0c and \x1c-\x1e, which PyYAML
refuses; split("\n") ignored \r, \x85 and
, which PyYAML honours — so a
config with a lone CR loaded from a checkout and was refused by every shipped
binary. Exactly PyYAML's set now, and nothing else.
And two false positives visible on a real 256-repository workspace, where
trash.sensitive was holding 2.4 MB back:
- botocore/cacert.pem matched *.pem. It holds 130 public certificates and no
private key. A certificate file is read before it is believed. - eslint's source-code/token-store/ matched token. It is forty .js files. The
source-extension exemption reads a name, and a directory has no extension, so
it could never apply to one — while a mycreds/ holding a password file still
must be kept, and is, because it holds something that is not source.
Smaller: the "held back" tally silently dropped the refusal to move a linked
worktree's HEAD, because NOT_HELD_BACK matched it first. _guarded hardcoded
"origin" when counting unreachable remotes, and could raise a timeout from
inside an except clause.