Fix: fail the license check when it inspected no files - #701
Open
AmaadMartin wants to merge 2 commits into
Open
Conversation
check_license.sh discarded find's exit status and iterated an unquoted string, so two conditions produced a silent pass: a find that printed no paths and exited non-zero still reported "All files have the correct license header", and a path containing a space was split into fragments that perl could not open, which also exits 0. The script now writes NUL-terminated paths to a temp file, checks find's exit status, rejects an empty result, and iterates a quoted bash array. Output and exit status on the clean-pass and missing-header paths are unchanged.
AmaadMartin
force-pushed
the
fix/check-license-fail-on-empty-file-list
branch
from
August 6, 2026 07:06
a590314 to
1318a9e
Compare
Address the complexity review: replace the write-only MISSING_FILES array with a flag, since the loop already prints each offending path, and drive the test's script runs with spawnSync instead of a hand-rolled spawn and Promise wrapper. The comment above the find guard described the empty-result case, which a different guard handles. It now describes the case the guard is for: find prints the paths it reached before it aborts, so a partial scan reads as a full one unless its exit status is checked.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Please ensure you have read the contribution guide before creating a pull request.
Link to Issue or Description of Change
No existing issue; description below.
Problem:
scripts/check_license.shcan report success without inspecting asingle file. It discards
find's exit status, so a broken search prints zeropaths and the script still prints
✅ All files have the correct license header.and exits 0. It also iterates the file list unquoted, so a path containing a
space splits into fragments, and
perl -0777 -neexits 0 on a file it cannotopen — an unlicensed file at such a path is accepted silently.
Solution: The script now writes NUL-terminated paths to a temp file, checks
find's exit status, rejects an empty result, and iterates a quoted bash array.The original report suggested
set -o pipefail, but the final design contains nopipeline, so an explicit status check replaces it and gives the stronger
guarantee. The two new errors go to stderr and are worded differently, so a
failing CI log says which guard fired. Output and exit status are unchanged on
the clean-pass and the missing-header paths.
The script stays bash-3.2 and BSD-
findcompatible for themacos-latestrunner:
while IFS= read -r -d ''instead ofmapfile, andmktempwith anexplicit template. A
trap 'rm -f "$FILE_LIST"' EXITremoves the temp file onevery exit path.
The temp file is what makes
find's exit status readable. A pipe or a processsubstitution hides it behind the read loop's own status, and that status is the
only way to catch a
findthat aborts partway: it prints the paths it reached,so a partial scan otherwise reads as a full one. The empty-result guard does not
cover that case, because the list is not empty.
MISSINGis a flag rather than a list of paths, because the loop already printseach offending path and nothing reads the collection back.
Collision check: I listed all 593 open PRs on the fork and searched the whole
fork history for commits touching this file. No PR implements this fix. #594
edits the same
findline for a separate cleanup, is not an ancestor ofmain,and has no upstream PR, so this change is based on
mainand leaves that line'sprune clauses exactly as they are.
Testing Plan
Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.
Unit Tests:
New file
tests/integration/scripts/check_license_test.tsruns the real scriptagainst five scratch directories. Every fixture is written at runtime into an
fs.mkdtempdirectory, because a committed unlicensed fixture would turn therepository's own License Header Check red. The suite is skipped on Windows.
A
.shfile is not instrumented by the v8 coverage provider andcoverage.includeinvitest.config.tslists onlycore/src,dev/srcandintegrations/src, so this change does not move the coverage numbers. Each newbranch of the script gets a dedicated test case instead.
Proof that the tests can fail. I ran the suite against the unfixed script and
against three single-line mutations.
mainfindfailure)expected '' to contain 'no .js or .ts files were found'if ! find ...status checkfails when find exits non-zero after printing a pathexpected 'find: ./denied: Permission denied\n/u…' to contain 'failed to list source files'[ "${#FILES[@]}" -eq 0 ]guardfails when the search matches no .js or .ts fileexpected '' to contain 'no .js or .ts files were found'for FILE in "${FILES[@]}"tofor FILE in ${FILES[@]}checks a file whose directory name contains a spaceexpected '🔍 Checking for license headers...\n✅…' to contain '❌ Missing or invalid license header: …'MISSING=1assignmentexpected '🔍 Checking…❌ Missing or invalid…' to contain 'Error: Some files are missing the required license header.'The two pre-existing behaviours (clean pass, missing header) pass under every
mutation, which is what they are there to pin.
Manual End-to-End (E2E) Tests:
bash scripts/check_license.shfrom the repositoryroot: exit 0 in 1.5s, empty stderr, and stdout byte-identical to the same
command run from
main(diffof the two captures is empty).the
findline and run the copy:find's own diagnostic on stderr, then❌ Error: failed to list source files; the license check did not run., exitmainprints✅and exits 0..tsfile gives the
❌ Missing or invalid license header:line, the separator, thesummary line, and exit 1.
ls "${TMPDIR:-/tmp}"/adk_license_files.*after all runsfinds nothing.
Checklist