Repository navigation
fix(gates): irrecoverable reads a substitution glued to a git global as its value; chmod reads its mode word only (GH #405) - #407
Merged
Conversation
…as its value; chmod reads its mode word only (GH #405)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #405.
Root cause (F1)
The issue suspected
_split_opsand brace handling. That is not the cause._blank_substitutionsturns${R},$(...)and backticks into one placeholder (PH) inside the word. So-C${R}reaches shlex as one plain token,-C\x01. It is never split, so it is never_Glued, and_git_words(GH #375) returns nothing. The git walk strips PH before it checks for a bare value global. So-C\x01reads as a bare-C: it takesresetas its value, and--hardbecomes the subcommand. The unbraced-C$Ris not blanked. It splits into glued$/Rtokens, so the #375 window already catches it.Real git rejects a glued
-C<path>. The shape still matters because an unquoted${R}word-splits: withR=" /repo",git -C${R} reset --hardrunsgit -C /repo reset --hard.Fix
_git_words(rest, ph_value)adds a second reading. In it, a value global followed by a PH (-C${R},--git-dir$(x)) holds its own value, so the next word is the subcommand.ph_value=Falsecall is unchanged. TheTruecall appends a window only when such a flag exists.git -C${D} /repo reset --hard,git -C${D} $R reset --hard).${X}-C,-${X}C) is not a value. Those shapes behave as on develop."$"stands in for the PH, the same way-C$Rreads. Keeping the PH would match again and append the same window forever (one mutant hangs)._chmod_world: the regex now runs only on the mode word, which is the first word that is not an option. It uses.matchon the words from there on, so it matches a subset of what the old.searchmatched. The recursive,/and~check is unchanged.Note: develop already allows
chmod 777 xandchmod a+rwx x(not recursive, not on/or~). The GH #336 rule never covered them. They stay allowed and are now allow controls.Differential (frozen develop copy vs this branch; compares exit code, stdout, stderr and journal calls)
${...},$(...), backticks and quotes (after, before and inside the flag), plus chmod modes, files and optionsDiff classes (fuzz + fixtures):
$(...),$((...))or backtick glued after a git global, allow -> deny: 275 + 1. Same blanking path, same root cause.Develop already denies all 911 new git denies from the fuzz when they are spelled
-C$R(the GH #375 reading). Fuzz verdicts are identical under Python 3.9.6. Under load, a fewgit addcases flaked on both sides in the gate's owngitmid-merge probe. They were identical on reruns.Mutation
The new asserts killed all 10 mutants.
Timing
Best of 3 runs, as a subprocess. The largest #375 timing fixture (
git+ 4000-C $R+reset --hard) took 0.11 s before and 0.08 s after (noise). 4000-C${R}took 0.10 s on both. 2000git -C${R} status;statements followed by a reset took 0.14 s before and 0.15 s after; that command is now denied and is added as a_timed_case.