mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-14 12:27:18 +01:00
fix(careful): scan the command as one string, so a newline still separates commands from the message (#1060)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
35160763b0
commit
e496f234b9
2 files changed
+36
-12
No files matched your search
@@ -1,6 +1,8 @@
|
||||
# mask-commit-message.awk — read by careful/bin/check-careful.sh (#1060).
|
||||
# Prints the command with the quoted message argument of git commit
|
||||
# (-m, -am, --message) replaced by an empty quoted string.
|
||||
# (-m, -am, --message) replaced by an empty quoted string. The command is
|
||||
# scanned as one string: newlines are kept, since bash runs each line as its
|
||||
# own command, and quote state carries across lines.
|
||||
function handle_msg(s, n, i, j, safe) {
|
||||
if (i > n) return i
|
||||
if (substr(s, i, 1) == "'") {
|
||||
@@ -24,34 +26,36 @@ function handle_msg(s, n, i, j, safe) {
|
||||
}
|
||||
return i
|
||||
}
|
||||
{
|
||||
n = length($0); sq = 0; dq = 0; bs = 0; i = 1
|
||||
{ cmd = (NR > 1) ? cmd "\n" $0 : $0 }
|
||||
END {
|
||||
s = cmd
|
||||
n = length(s); sq = 0; dq = 0; bs = 0; i = 1
|
||||
while (i <= n) {
|
||||
c = substr($0, i, 1)
|
||||
c = substr(s, i, 1)
|
||||
if (bs) { result = result c; bs = 0; i++; continue }
|
||||
if (!sq && dq && c == "\\") { result = result c; bs = 1; i++; continue }
|
||||
if (!dq && c == "'") { sq = !sq; result = result c; i++; continue }
|
||||
if (!sq && c == "\"") { dq = !dq; result = result c; i++; continue }
|
||||
if (sq || dq) { result = result c; i++; continue }
|
||||
rest = substr($0, i)
|
||||
rest = substr(s, i)
|
||||
if (rest ~ /^--message=/) {
|
||||
result = result "--message="; i += 10
|
||||
i = handle_msg($0, n, i); continue
|
||||
i = handle_msg(s, n, i); continue
|
||||
}
|
||||
if (rest ~ /^--message([ \t]|$)/) {
|
||||
result = result "--message"; i += 9
|
||||
while (i <= n && substr($0,i,1) ~ /[ \t]/) { result = result substr($0,i,1); i++ }
|
||||
i = handle_msg($0, n, i); continue
|
||||
while (i <= n && substr(s,i,1) ~ /[ \t]/) { result = result substr(s,i,1); i++ }
|
||||
i = handle_msg(s, n, i); continue
|
||||
}
|
||||
if (rest ~ /^-am([ \t]|$)/) {
|
||||
result = result "-am"; i += 3
|
||||
while (i <= n && substr($0,i,1) ~ /[ \t]/) { result = result substr($0,i,1); i++ }
|
||||
i = handle_msg($0, n, i); continue
|
||||
while (i <= n && substr(s,i,1) ~ /[ \t]/) { result = result substr(s,i,1); i++ }
|
||||
i = handle_msg(s, n, i); continue
|
||||
}
|
||||
if (rest ~ /^-m([ \t]|$)/) {
|
||||
result = result "-m"; i += 2
|
||||
while (i <= n && substr($0,i,1) ~ /[ \t]/) { result = result substr($0,i,1); i++ }
|
||||
i = handle_msg($0, n, i); continue
|
||||
while (i <= n && substr(s,i,1) ~ /[ \t]/) { result = result substr(s,i,1); i++ }
|
||||
i = handle_msg(s, n, i); continue
|
||||
}
|
||||
result = result c; i++
|
||||
}
|
||||
|
||||
@@ -434,6 +434,26 @@ describe('check-careful.sh', () => {
|
||||
expect(fs.existsSync(path.join(path.dirname(CAREFUL_SCRIPT), 'mask-commit-message.awk'))).toBe(true);
|
||||
});
|
||||
|
||||
// Newlines separate commands, and quote state carries across them. The
|
||||
// per-line scanner joined lines (`-m xtruncate`) and restarted quote
|
||||
// state on every line, so a quoted line break could hide a real command.
|
||||
test.each([
|
||||
['git commit -m x\ntruncate -s 0 f', 'SQL TRUNCATE'],
|
||||
['git commit -m wip\nrm -rf build', 'recursive delete'],
|
||||
["git commit -m \"a\n-m 'x\" && rm -rf build && echo '", 'recursive delete'],
|
||||
])('a command on the next line still asks: %j', (command, reason) => {
|
||||
const { exitCode, output } = runHook(CAREFUL_SCRIPT, carefulInput(command));
|
||||
expect(exitCode).toBe(0);
|
||||
expect(output.hookSpecificOutput?.permissionDecision).toBe('ask');
|
||||
expect(output.hookSpecificOutput?.permissionDecisionReason).toContain(reason);
|
||||
});
|
||||
|
||||
test('a multi-line quoted message is masked as one message', () => {
|
||||
const { exitCode, output } = runHook(CAREFUL_SCRIPT, carefulInput('git commit -m "fix: guard migrations\n\nNo more drop table in the seed script."'));
|
||||
expect(exitCode).toBe(0);
|
||||
expect(output.hookSpecificOutput?.permissionDecision).toBeUndefined();
|
||||
});
|
||||
|
||||
test('a partial install without the masking program still asks on the message text', () => {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-careful-nomask-'));
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user