Problem
_heredoc_opener in gh-write-guard.py refuses to recognise a heredoc on any opener line whose tokens hold ((. When that happens the heredoc body is never stripped. It is then tokenized as part of the command, and requirement 7 can read a comparison in the body as a loop's bound. The docstring says the skip "costs a false deny". Here it costs a false allow.
Reproduce (constructed)
while [ -e /nonexistent ] <<EOF ; : $((0))
[ x -lt 5 ]
EOF
do sleep 1; echo tick; done
This is allowed on develop at dd4ca98e. Run from a file under timeout 3 bash, it prints tick until the timeout kills it. The condition is [ -e /nonexistent ] with a heredoc as its stdin, so the loop has no bound. The [ x -lt 5 ] line is heredoc data that bash never evaluates.
Done looks like
The command above is denied, and a self-test row pins it. The docstring then describes what the (( skip actually costs.
Found by the local strict review of the #1998 fix (handoff #2057). It does not depend on that branch.
Problem
_heredoc_openeringh-write-guard.pyrefuses to recognise a heredoc on any opener line whose tokens hold((. When that happens the heredoc body is never stripped. It is then tokenized as part of the command, and requirement 7 can read a comparison in the body as a loop's bound. The docstring says the skip "costs a false deny". Here it costs a false allow.Reproduce (constructed)
This is allowed on develop at
dd4ca98e. Run from a file undertimeout 3 bash, it printstickuntil the timeout kills it. The condition is[ -e /nonexistent ]with a heredoc as its stdin, so the loop has no bound. The[ x -lt 5 ]line is heredoc data that bash never evaluates.Done looks like
The command above is denied, and a self-test row pins it. The docstring then describes what the
((skip actually costs.Found by the local strict review of the #1998 fix (handoff #2057). It does not depend on that branch.