mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-18 15:50:25 +02:00
fix(hooks): block-no-verify handles stuck optional values and long-option prefixes (#3073)
Two cases the word-level rewrite still got wrong. Short options that take an optional stuck value (-u[mode], -S[keyid]) end the cluster scan, so git commit -uno and -Sn are allowed while -nu stays blocked. Git accepts any unambiguous long-option prefix, so --no-veri and --no-verif on commit, push, merge and rebase are now blocked; --no-verbose stays allowed. Quoted data such as -m "--no-verify" is still treated as data. Independent exact-head review probed 34 commands in-process and against real git with no bypass and no false positive; hook test 35/35, eslint clean, CI 44/44 at the head.
This commit is contained in:
@@ -78,6 +78,10 @@ const COMMIT_OPTIONS_WITH_INLINE_VALUE = [
|
||||
// must stop at this character — anything after it is the inline value,
|
||||
// not another flag.
|
||||
const COMMIT_SHORT_OPTIONS_WITH_VALUE = new Set(['m', 'F', 'C', 'c', 't']);
|
||||
// Short options whose value is OPTIONAL and must be stuck to the flag
|
||||
// (`-uno`, `-S<keyid>`). The rest of the cluster is that value, so an `n`
|
||||
// after them is not the -n flag: `git commit -uno` means --untracked-files=no.
|
||||
const COMMIT_SHORT_OPTIONS_WITH_OPTIONAL_VALUE = new Set(['u', 'S']);
|
||||
|
||||
function tokenizeShellWords(input, start = 0, end = input.length) {
|
||||
const tokens = [];
|
||||
@@ -264,6 +268,7 @@ function isCommitNoVerifyShortFlag(value) {
|
||||
const option = options.charAt(i);
|
||||
if (option === 'n') return true;
|
||||
if (COMMIT_SHORT_OPTIONS_WITH_VALUE.has(option)) return false;
|
||||
if (COMMIT_SHORT_OPTIONS_WITH_OPTIONAL_VALUE.has(option)) return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -388,6 +393,16 @@ function detectGitCommand(input, start = 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* git's option parser accepts any unambiguous prefix of a long option, so
|
||||
* `--no-veri` and `--no-verif` run as --no-verify. Shorter prefixes such as
|
||||
* `--no-ver` are ambiguous with --no-verbose and git rejects them itself, so
|
||||
* refusing every prefix from `--no-v` up blocks nothing that would have run.
|
||||
*/
|
||||
function isNoVerifyLongFlag(value) {
|
||||
return value.length >= '--no-v'.length && '--no-verify'.startsWith(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the input contains a --no-verify flag for a specific git command.
|
||||
* Only inspects the portion of the input starting at `offset` (the position
|
||||
@@ -422,7 +437,7 @@ function hasNoVerifyFlag(input, command, offset) {
|
||||
}
|
||||
}
|
||||
|
||||
if (value === '--no-verify') return true;
|
||||
if (isNoVerifyLongFlag(value)) return true;
|
||||
|
||||
// For commit, -n is shorthand for --no-verify.
|
||||
if (command === 'commit' && isCommitNoVerifyShortFlag(value)) {
|
||||
|
||||
Reference in New Issue
Block a user