diff options
Diffstat (limited to '.github/workflows')
| -rw-r--r-- | .github/workflows/ai-validation.yml | 33 |
1 files changed, 18 insertions, 15 deletions
diff --git a/.github/workflows/ai-validation.yml b/.github/workflows/ai-validation.yml index ea16a4fb..d7d93c37 100644 --- a/.github/workflows/ai-validation.yml +++ b/.github/workflows/ai-validation.yml @@ -69,21 +69,24 @@ jobs: # in changed-md.txt (which drives the bundling step). git diff "$BASE...HEAD" --name-only --diff-filter=ACMRT -z -- 'docs/**/*.md' > changed-md.z git diff "$BASE...HEAD" --name-only --diff-filter=ACMRT -z -- 'docs/**/*.rst' > changed-rst.z - # Reject paths containing control chars (newlines, CR, NUL inside the - # name, escape sequences etc) before generating the newline-delimited - # *.txt manifests. Without this guard, `tr '\0' '\n'` on a path like - # `docs/foo\nbar.md` would split it into two logical lines — - # downstream consumers reading line-by-line would miss validation - # coverage on the real file (or worse, attempt to act on a synthetic - # path). Filesystems and porcelain git typically reject these but a - # fork PR can still commit such a tree entry; fail fast. - # grep -z treats NUL as the record delimiter (NUL is a legitimate - # separator here, not a forbidden char). The pattern excludes - # 0x00 and rejects every other control byte 0x01-0x1F + 0x7F, - # so LF (0x0A) and CR (0x0D) inside a path are caught. - # An earlier `tr -d '\0\n\r' | grep [\x00-\x1F\x7F]` form would - # strip the very chars it was meant to reject before the grep - # ran — defeating the guard. + # Reject paths containing line-disrupting control bytes (LF, CR, + # other 0x01-0x1F + 0x7F) before generating the newline-delimited + # *.txt manifests. NUL itself can't appear in a git pathname + # (it's the on-disk tree-entry terminator), so it stays out of + # the rejection class and remains the legitimate record delimiter + # for `git diff -z` — `grep -z` honors that contract. + # + # POSIX filesystems generally allow LF/CR in filenames and git + # stores them fine; the hazard is purely in our line-delimited + # downstream tooling. Without this guard, `tr '\0' '\n'` on a + # path like `docs/foo\nbar.md` would split it into two logical + # lines — downstream consumers reading line-by-line would miss + # validation coverage on the real file (or worse, act on a + # synthetic path). Fail fast at this seam. + # + # An earlier `tr -d '\0\n\r' | grep [\x00-\x1F\x7F]` form + # stripped the very bytes it was meant to reject before the + # grep ran — defeating the guard. for z in changed-md.z changed-rst.z; do if LC_ALL=C grep -zPq '[\x01-\x1F\x7F]' "$z"; then echo "::error::Refusing to bundle: path in $z contains a control character. Reject the offending file name in the PR." |
