fix(robots-check): decode curl output as UTF-8 so non-ASCII responses stop reading as UNCONFIRMED on Windows (#506)

_fetch() ran curl with text=True and no encoding, so Python decoded the
response with the Windows ANSI code page. On a byte that code page leaves
undefined (0x81 in cp1252 and cp1254, 0x9e in cp1254) subprocess's pipe
reader thread died, stdout came back None, rpartition() raised
AttributeError, and the gate printed "UNCONFIRMED (AttributeError)". That
fails closed, but it blocked the browser-header retry 09-web-research.md
permits on hosts such as tr.indeed.com (a UTF-8 CJK Disallow rule) and
kap.org.tr (a UTF-8 Turkish 404 page).

Pin encoding='utf-8', errors='replace' on the call (RFC 9309: robots.txt
is UTF-8), as verify_pdf.py and verify_layout.py already do. Decision
rules and the fail-closed handling of real read failures are unchanged.

The regression tests swap curl for a child process that prints the real
bytes, so the actual subprocess decode path runs with _fetch's own
kwargs, and pin cp1254 when no encoding is passed so a UTF-8 host cannot
pass the bug by luck. Both fail on master.

Co-authored-by: Can Mugan <217335573+canmugan@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-09-29 20:18:48 +02:00
1 parent 97e2575795
commit 9bc71de5f8
3 files changed
+75 -1

No files matched your search

+17
View File
@@ -105,6 +105,23 @@ per-file diff commands.
### Fixed
- **`robots_check` decodes curl output as UTF-8, so a non-ASCII response no longer reads as
UNCONFIRMED on Windows** (`tools/robots_check.py`, `tests/test_robots_check.py`) -
`_fetch()` ran curl with `text=True` and no encoding, so Python decoded the response with
the ANSI code page. On a byte that code page leaves undefined (0x81 in cp1252 and cp1254,
0x9e in cp1254) subprocess's pipe reader thread died, `stdout` came back `None`, and the
gate printed `UNCONFIRMED (AttributeError)` - failing closed, but blocking the
browser-header retry `09-web-research.md` permits. Reproduced through the CLI on real
hosts: tr.indeed.com's robots.txt carries `Disallow: /職涯貼士/` (職 is `e8 81 b7`), and
kap.org.tr answers `/robots.txt` with a UTF-8 HTML 404 whose "A.Ş." carries `c5 9e`. The
call now pins `encoding='utf-8', errors='replace'` (RFC 9309: robots.txt is UTF-8), as
`verify_pdf.py` and `verify_layout.py` already do. That also closes a silent fail-open: a
UTF-8 rule whose bytes the code page does define (`Disallow: /şirket/` under cp1254)
decoded as `/ÅŸirket/`, never matched, and read as allowed. Decision rules are unchanged.
Two new tests swap curl for a child process that prints those bytes and pin cp1254 when no
encoding is passed, so the failure does not depend on the host's locale; both fail without
the fix.
- **The compile-warning check covers `tests/*.py` too** (`tests/test_verify_pdf.py`,
`tests/test_verify_layout.py`) - `FindNonAsciiDateRangesTests`' docstring quotes the regex
`\s*` unescaped, so Python 3.12+ prints a `SyntaxWarning` for the invalid escape `\s` when