mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #325] [MERGED] fix(lint): NUL-delimit the fallback org-repo-literal scan so a newline in a path cannot fabricate a record #328
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#328
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/325
Author: @mattmillerai
Created: 9/19/2026
Status: ✅ Merged
Merged: 9/19/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-15443-nul-delimited-fallback-scan📝 Commits (2)
4d9eec5fix(lint): NUL-delimit the fallback scan so a newline in a path cannot fabricate a record142c64bfix(lint): C-quote the fallback label exactly as git does, and fail closed on an unopenable re-scan📊 Changes
3 files changed (+313 additions, -79 deletions)
View changed files
📝
.github/lint/README.md(+12 -19)📝
.github/lint/check-org-repo-literals.sh(+129 -37)📝
.github/workflows/test-org-repo-literals.yml(+172 -23)📄 Description
ELI-5
This repo has a small guard script that scans tracked files for leaked private
Comfy-Org/<repo>names. It has two ways to scan: a fastgit greppath (usedinside a git checkout) and a plain
grep -rfallback (used when the targetisn't a git work tree).
The fallback had a hole. It fed one big
grep -rIoiEnblob into a loop thatsplits each line into
file:line:match. If a tracked file's own name containeda newline, that one match arrived as two lines — and the leading half looked
enough like a real
file:line:matchrecord to sail past the two "does thisrecord look sane?" checks, so the real hit got pinned to a filename that doesn't
exist (and could even be silently cleared against the allowlist). The
git greppath never had this problem because git C-quotes such a path.
This PR makes the fallback do what git does: list the matching files
NUL-delimited, then scan each file one at a time on stdin under a C-quoted
--label. Now a newline / tab /\/"in a path is reported as onefinding with a C-quoted location, identical on both scan paths.
What changed
check-org-repo-literals.sh(the fallbackhits=line). Replaced thesingle
grep -rIoiEn … .with: enumerate matching files withgrep -rIliE --null, piped straight into awhile read -r -d ''loop(never stored in a variable — bash
$(…)drops NUL bytes, which would run theloop zero times and fail open), and scan each file on stdin with
grep -oiEnH --label="$label".$labelis C-quoted (\→\\,"→\",LF→
\n, TAB→\t, wrapped in") exactly the waygit grepquotes a path, sothe per-hit loop body is unchanged and both paths emit identical records.
grep -lexit 1 (no match) flows through the existingscan_statuslogicas before; a per-file exit above 1 (e.g. an unreadable file) is
propagated so the existing "scan failed (exit N)" refusal still fires; a
per-file exit 1 on the re-scan is tolerated.
--null, not-Z(-Zis--decompresson BSD grep).org-prefix-shape
cases are kept as cheap parse invariants, but theircomments and error messages no longer describe a newline-in-a-path split
(unreachable now on either path). Dropped the two "BEST-EFFORT" sentences.
updated the
else-branch comment and the git-pathcore.quotePathcomment tosay both paths now C-quote the same four bytes / print bytes ≥ 0x80 raw;
rewrote the README paragraph that called the refusals best-effort.
test-org-repo-literals.yml). The two fallback fixtures thatexpected exit 2 now expect exit 1 with exactly one C-quoted
unapproved:line (e.g."a:bc\nd.md":1:, where\nis two literalcharacters). Added: the three spike fixtures from the source investigation under one root (exit 1,
three findings, every
::error file=quoted, nofile=a,/file=y.md); thesame three paths with an allowlisted body (exit 0 — pins that no fragment
survives to be cleared); a name with a tab,
",\and a leading-(pinsthe C-quoting and the
--/< "$path"handling); and a NUL-safety fixture(two matching files, one newline-named → two findings, guarding against a
future refactor that stores the file list in a variable).
Verification
shellcheck -x .github/lint/check-org-repo-literals.sh— clean.test-org-repo-literals.ymlextracted and run locally(with
GITHUB_WORKSPACEset) — green, including every new/flipped fixture.a:bc\nd.md→ exit 1, one finding at"a:bc\nd.md":1:; the three spike fixtures → exit 1, three C-quoted findings,no fabricated
file=a/y.md; allowlisted body → exit 0; unreadable sibling →exit 2 ("scan failed"); NUL-safety → two findings; git-path parity — the
same newline-named file in a git tree yields the identical
"a:bc\nd.md":1:location.
check_workflow_pins.pyOK, whole-treecheck-org-repo-literals.shscans clean on the real tree,check_agents_md.pypasses (its two warnings are pre-existing and unrelated — AGENTS.md untouched).
merged), so this is not the "script absent — stop" case.
Residual
investigation from this environment). This PR implements the recommended plan
verbatim and verifies it empirically instead; the "verified prototype" it
references was not re-opened.
ticket, not re-measured here (300 files × 5 hits 9.4s→9.6s; 1 file × 2000
hits 12.1s→12.2s). Functional correctness is verified; the exact timings are
not reproduced. The change adds one grep fork per matching file, so the
per-hit cost in KNOWN LIMITATIONS 11 is unchanged.
(ubuntu-latest, GNU grep 3.x).
--null/--labeland the bash patternsubstitutions are documented as portable to BSD grep / ugrep and bash 3.2, but
BSD grep and macOS
/bin/bashwere not run locally.Provenance
git-path parity and every ticket-named behavior reproduced by hand; repo-wide
lints pass.
belt-and-suspenders assertions in the flipped
num_dirfixture(
file=a,/:oomust not appear).🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.