Round-8: the PyYAML-absent conservative recognizer proved STRUCTURE and implicit-resolver TYPE but not CONSTRUCTOR VALIDITY. PyYAML safe_load raises a constructor ValueError on the WHOLE document when a plain scalar matches a typed implicit resolver but is not constructible (e.g. bad calendar date 2023-99-99, empty-radix ints 0b_/0x_), yielding no token; the fallback instead treated such a scalar as a null-equivalent, ignored the malformed key, and still emitted the valid login token -- a credential fail-open in the dangerous direction. _scalar now checks constructibility via _constructible (replicating PyYAML 6.0.3 construct_yaml_int/float/timestamp, stdlib-only): a typed scalar that is not constructor-valid returns _FAIL, which the parser turns into _Bail so the WHOLE document fails closed exactly as PyYAML does. int and timestamp resolver patterns are byte-identical to PyYAML's; the float pattern is a strict superset whose extras are all float()-constructible (fuzz-verified 0/400k raise), so it never fails closed where PyYAML would emit. Also fail closed on plain scalars beginning with an indicator a plain scalar may not start with: '%' (directive) and ',' (flow), and the conditional block indicators '-'/'?'/':' when followed by whitespace or end-of-value (bare sequence/complex-key/value indicators PyYAML rejects), while '-x'/'-1'/'?x'/':x' remain valid plain strings. Differential fuzz through the real function: 0 fail-opens across 1499 diverse non-tab cases; targeted fixtures assert fallback == PyYAML == fail-closed for 2023-99-99, 2023-13-01, bad-hour timestamp, 0b_, 0x_, 0x__, %broken, ',bad', bare '-'/'- '/'? key', and assert the token STILL resolves for constructible/ string look-alikes (valid date/datetime, 0o_, 4.e8, 0x1f, -x, :x). Both PyYAML present and forced-absent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
28 KiB
Executable File
28 KiB
Executable File