fix(arg-parser): take the arguments as stdin text, and block a heredoc that closes early
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
738efa3e24
commit
f1704f0800
4 changed files with 287 additions and 16 deletions
|
|
@ -258,6 +258,43 @@ const deobfuscated = normalizeBashExpansion(command);
|
|||
const normalized = normalizeCommand(deobfuscated);
|
||||
const commandView = commandPositionView(deobfuscated.replace(/\x1B\[[0-9;]*m/g, ''));
|
||||
|
||||
// BEGIN args-heredoc-closed-early
|
||||
// The commands hand $ARGUMENTS to lib/parsers/arg-parser.mjs (--stdin) through
|
||||
// a quoted heredoc closed by VOYAGE_ARGS_EOF_7F3C9E. A typed line equal to that
|
||||
// delimiter would close the heredoc there, and the shell would run every line
|
||||
// after it as a command (fix round 4.5b, R6). This check reads the raw
|
||||
// command: `normalized` and `commandView` collapse lines and drop heredoc
|
||||
// bodies (hooks/lib/bash-view.mjs). Openers <<'D', <<"D" and <<\D are quoted
|
||||
// (the body is not expanded); any other opener of the delimiter is treated as
|
||||
// unquoted and blocked, since its body would expand. A quoted opener passes
|
||||
// only when exactly one line, trimmed, equals the delimiter and every line
|
||||
// after it is empty.
|
||||
const ARGS_DELIM = 'VOYAGE_ARGS_EOF_7F3C9E';
|
||||
const argsOpener = /<<-?\s*(['"\\]?)VOYAGE_ARGS_EOF_7F3C9E(['"]?)/.exec(command);
|
||||
if (argsOpener) {
|
||||
const [, open, close] = argsOpener;
|
||||
const quoted = (open === '\\' && close === '') || (open !== '' && open !== '\\' && close === open);
|
||||
const lines = command.split('\n');
|
||||
const closing = [];
|
||||
lines.forEach((line, i) => { if (line.trim() === ARGS_DELIM) closing.push(i); });
|
||||
const closesOnceAtEnd = closing.length === 1 &&
|
||||
lines.slice(closing[0] + 1).every((line) => line.trim() === '');
|
||||
if (!quoted || !closesOnceAtEnd) {
|
||||
const why = !quoted
|
||||
? `The heredoc that hands the arguments to the arg parser opens ${ARGS_DELIM} unquoted, so the shell would expand its body. ` +
|
||||
`Way forward: open it as <<'${ARGS_DELIM}'.`
|
||||
: `The arguments hold a line equal to the heredoc's closing line ${ARGS_DELIM}, or text follows that closing line, ` +
|
||||
'so the shell would run what follows as commands. Way forward: take that line out of the arguments and run the command again.';
|
||||
process.stderr.write(
|
||||
'[voyage] BLOCKED: args-heredoc-closed-early\n' +
|
||||
` Command: ${normalized.slice(0, 200)}${normalized.length > 200 ? '...' : ''}\n` +
|
||||
` ${why}\n`
|
||||
);
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
// END args-heredoc-closed-early
|
||||
|
||||
// Check BLOCK rules first
|
||||
for (const rule of BLOCK_RULES) {
|
||||
if (rule.pattern.test(rule.commandView ? commandView : normalized)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue