web lint hook: a check run from the reviewed copy may start only git, from outside the tree
Summary
Stacked on #34060, which is stacked on #34046. Land those first; until then this diff also shows their commits. The new change is one commit, 73329295cc7.
#34060's runner runs a reviewed check from the hook's copy on a pushed tree. It allowed some ways for such a check to start a program that the push controls. A review rule is not a boundary, so the runner now refuses every program start except one: git, found outside the tree.
- Every
subprocess,os.exec*,os.spawn*,os.posix_spawn*andos.systemcall is resolved first:- a bare name through the PATH that the call runs with;
- a relative path from the folder that the call starts in;
- symlinks followed.
- The runner then refuses the call unless the program is in
TRUSTED_PROGRAMS = ("git",)and is found outside the tree. - A shell (
shell=True,os.system,os.popen) or an interpreter is never allowed, so the runner also refuses an interpreter started on a tree script. - Of the ten declared checks, only
check-xcstrings-keysstarts a program, and it starts onlygit.
Testing
Red on 37b91f10452 (#34060's head), green on the head:
(cd tests && python3 -m unittest -k refuses_every_way -k still_reads test_web_lint_prepush)
On the base, 6 ways start pushed code: a bare name on PATH, shell=True, os.system, os.popen, os.posix_spawnp, and an interpreter on a tree script. The test also holds two cases that the base already refused: os.execvp on PATH and a relative path from the call's cwd. The data-file test checks that git -C <tree> still runs.
Observed / Not run
Observed:
python3 tests/test_web_lint_prepush.py: 71 tests OK.- The ten declared webviews checks give the same exit code and output through the runner (with
package_env) as when run directly. python3 scripts/cmux-next/prepush-gate.py: no new violations.
Not run:
- Python 3.9 (this host has only 3.12). The audit events used exist on 3.8 and later.
- A real push through an installed hook on a Mac.
Changelog
none
Proof
No capture: hook tooling only.
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
The web lint prepush runner now refuses to let a check it runs for a push start any program except git found outside the pushed tree — a review rule is not a boundary.
Trusted runner
- Every program start (
subprocess,os.exec*,os.spawn*,os.posix_spawn*,os.system) is resolved the way the system resolves it: a bare name from the folder it starts in for calls that exec, from the PATH the call searches otherwise, an empty or relative PATH entry from the folder the program starts in, a relative path from that folder, symlinks followed. - The call is refused unless every file the system may run for it is
git, found in a folder outside the tree (a tree link to a program outside still refuses); shells and interpreters are never allowed, so neither a tree program nor an interpreter on a tree script can start. A refusal in a forked child ends the runner too, so the check fails.
Piece selection
- Each check script now declares the files it reads as a module-level
INPUTStuple, read withastand never run. - A change that touches a declared input but no package trigger runs only those pieces, with no install; a Swift-only push now runs
check:text-focusinstead of nothing. - When a push changes files a check executes under
scripts/cmux-next/, the hook runs the declared pieces from its reviewed copy on the pushed tree; a check whose own script the push changes is never run.