mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #231] [MERGED] feat(public-repo-hygiene): scan the tracked path string, not just file contents #237
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#237
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/231
Author: @mattmillerai
Created: 8/26/2026
Status: ✅ Merged
Merged: 8/26/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-9399-hygiene-scan-tracked-path📝 Commits (2)
0a2178ffeat(public-repo-hygiene): scan the tracked path string, not just file contents8dccd72fix(public-repo-hygiene): gate URL-syntax suppressors off the path surface, cap path findings, read surrogates as name (BE-9399)📊 Changes
6 files changed (+782 additions, -221 deletions)
View changed files
📝
.github/public-repo-hygiene/README.md(+60 -3)📝
.github/public-repo-hygiene/check_public_repo_hygiene.py(+353 -215)📝
.github/public-repo-hygiene/tests/test_check_public_repo_hygiene.py(+342 -0)📝
.github/workflows/public-repo-hygiene.yml(+3 -2)📝
README.md(+1 -1)📝
docs/callers/public-repo-hygiene.md(+23 -0)📄 Description
ELI-5
The leak checker reads what is inside your files. It never read the file names. So a public repo could contain a directory literally called
docs/Comfy-Org/<a-private-repo>/, with a completely empty file in it, and the check went green — while GitHub happily showed that private repo's name to anyone browsing the repository. This PR makes the checker read the tracked path as well as the contents, using the exact same matcher so every allowlist and every false-positive suppressor applies to both.What changed
_file_findings's per-line body is factored out into a shared_line_findings(location, line, ticket_allowlist, owner_span), andrun_checksnow runs it over the tracked path itself — right after the exclusion check, beforecheck_file. Deliberately one matcher, not two:TICKET_ALLOWLIST/TICKET_ALLOWED_PREFIXES, the--ticket-allowextension, the model-host and markdown-link-label suppressors, the homoglyph handling and the.git/period strips all reach the new surface for free, and there is no second place to forget an allowlist entry.Details worth knowing at review time:
check_filedeclines (binary, non-UTF-8, submodule gitlink, LFS stub, FIFO, unreadable). The path is published in the tree whatever the entry type. It does not make such an entry count asSCANNED:— that number is files read as text.owner_spanis alwaysNoneon a path. A path string is not a CODEOWNERS owner line, even the path of a CODEOWNERS file. I passed the precomputed span rather than anis_codeownersflag because deriving the span also needs the line number (the BOM-at-offset-0 rule), and a line number means nothing on a path —owner_span=Nonereads as the fact it is, wherelineno=1would have been a lie in the signature. Same behaviour either way.exclude_paths:covers the new surface, because the existing_is_excludedcontinuesits above the path scan. An excluded path is not scanned as a path either, and still reports its skipped-file count so the hole stays named in the log.<path> (tracked path):rather than<path>:<lineno>:— "rename the file" and "edit the file" are different fixes. Merged into the same per-runMAX_FINDINGS_TOTALcap./is not inREPO_REF_RE's left lookbehind, sodocs/Comfy-Org/x/y.mdmatches whileaComfy-Org/xdoes not;\bfires at both/and-, sonotes/TEAM-1234/plan.mdandTEAM-1234-notes.mdboth match. Same token rules as content, verified empirically rather than assumed._emitnow lists findings before the zero-coverage verdict. Until this PR, findings impliedscanned >= 1; now a repo of nothing but binaries can leak in its own file listing whilescannedstays0, and the old ordering returned exit 2 having printed the finding nowhere — sending the operator after a configuration problem instead of the leak. Exit codes are byte-for-byte unchanged (still 2 there); only the output is added. Pinned bytest_a_path_finding_is_listed_even_when_nothing_was_scanned.Rollout is the ordinary one: callers pin
workflows_refby SHA, so the new surface reaches them through the normalbump-public-repo-hygiene-callers.ymlflow.False-positive risk — measured, not asserted
Every tracked path of nine Comfy-Org public repos, fed through the real
_line_findings:Enabling this reddens no caller CI. This repo's own working tree (176 tracked paths, and it is deliberately not self-enrolled) also produces 0 path findings. Overhead is ~4 µs per path (47 ms across 11,187 paths), against a content scan that reads up to 5 MiB per file.
And the portion this does not cover, swept with the same tool: the checker reads the work tree, so a path that once existed and was renamed or deleted stays in every clone and is still not examined — nor are branch and tag names. Across the same nine repos that is 3,337 history-only paths, which likewise produce 0 would-be findings today. Real gap, empirically empty, now written down as a known limitation rather than left implicit. (Caveat: measured over the refs present in the local clones, which may not carry every remote branch.)
Verification
python3 -m unittest discover -s .github/public-repo-hygiene/tests -p 'test_*.py'— 178 passed, 0 failed (1 skipped, pre-existing; 165 → 178, +13 new). The pre-existing 165 pass unchanged, which is the zero-new-false-positive claim.run:step of.github/workflows/test-public-repo-hygiene.ymlextracted and executed locally — all 13 smoke steps pass, exit 0.python3 .github/workflow-pins/check_workflow_pins.py— OK, 11 workflows, 0 exempt.python3 .github/agents-md-integrity/check_agents_md.py --root .— passed (1 pre-existing CODEOWNERS warning).bash .github/bump-callers/tests/test_paths_contract.sh— 70 passed, 0 failed.New tests (13): a private repo name in a path fails; an allowlisted repo name in a path passes; ticket-shaped directory component and filename prefix both fail; built-in and caller-extended acronyms in a path pass; the
(tracked path)vs:<lineno>labels distinguish the two surfaces when a name appears in both;aComfy-Org/xdoes not flag (left-boundary pin); an internal-marker host in a path flags; the npm-scope and model-host suppressors carry over; the nested-model-host over-flag is pinned;exclude_paths:suppresses and still counts; a path finding fires on a binary entry and on a dangling symlink whose body is never read; and the zero-coverage output case above.Residual
.github/lint/README.mdKNOWN LIMITATION 8 is not updated. That file does not exist onmain— it arrives with PR #224, which is still open. Its limitation-8 sentence "neither checker scans the tracked path itself" becomes stale the moment this merges, and #224's branch will need that sentence corrected on rebase. I could not edit it here without touching another open PR's branch, so it is called out rather than done. Whichever of the two lands second owns the fix.models/hf.co/Comfy-Org/<model>/config.jsonis reported while the same mirror at the tree root is suppressed:MODEL_HOST_PREFIX_RE's left anchor rejects a preceding/, and every segment of a path has one. This is the over-flag direction (a leak guard should be wrong that way), oneexclude_paths:entry clears it, and the shape occurs zero times across the 11,415 paths measured — so it is pinned by a test and documented as a known limitation rather than narrowed. Narrowing it would mean loosening a suppressor, which fails open; that is a deliberate non-goal here and would want its own change with its own evidence.git ls-files, but it is the honest remaining hole and is now stated in both READMEs.bump-public-repo-hygiene-callers.ymlmoves their pinned SHA. Nothing here does that, and no caller CI changes until it happens.Provenance
_line_findingstakes a precomputedowner_spanrather than anis_codeownersflag plus a line number (same behaviour, no fakelineno=1on a path — rationale above);_emitoutput ordering changed so a finding is never swallowed by the zero-coverage verdict (exit codes unchanged);.github/lint/README.mdleft alone because PR #224 has not merged. Review round 1 (cursor-review panel, 9 threads): the two URL-syntax suppressors (model-host prefix, markdown link label) are now gated OFF the path surface viaurl_suppressors=False— a path has no authority, so they failed open there; a vendored mirror therefore over-flags at the root as well as nested. A surrogateescape code point (Cs) now continues a name in_nonascii_tail. Path findings are capped andPARTIAL-counted through_path_findings. Documented rather than changed:Comfy-Org/ComfyUI.mdover-flags, lowercase ticket ids in paths miss, category-2 hosts need a following/, exit 2 may carry findings, andexclude_paths:costs contents coverage.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.