fix(okf): a mapping construct no longer degrades into a string, and there were two routes
T2 gives the mapping class no expressible form by design. Two routes escaped that by parsing "successfully" into the wrong TYPE instead of raising: sources:\n - uri: https://e.com/a -> the string 'uri: https://e.com/a' attester: resource: attesters/x.py -> the string 'resource: attesters/x.py' Only the first was documented (LIMITATIONS.md:43). The inline second colon was found by measurement while closing it -- a real YAML parser refuses that line outright, ours accepted it. Shipping the list half alone would have left a LIMITATIONS rewrite that overclaims. Same consequence either way: a pointer parked in a degraded mapping rides through in a key the `resource` allowlist never inspects, and mode-b import_bundle wrote the merged concept verbatim (WARN). Both now FAIL_SECURE at T2, before the allowlist is reached. The boundary is where YAML puts it, ground-truthed against PyYAML 6.0.3 rather than reasoned: ": " and a trailing ":" are exactly the two shapes where a plain scalar becomes a mapping. A colon carrying neither a space nor a line end opens no mapping -- domain:security and https://e.com:8443/a still parse -- and a quoted scalar is still a scalar. Over-blocking a conformant bundle is itself a failure mode, so the seven admitted shapes get rows of their own. Iron Law: the four rejected rows and both import_bundle rows were written first and seen red (7 failures, each DID NOT RAISE) before okf.py was touched. Suite 792 -> 802. LIMITATIONS stays at 35: the bullet is reworded, not retired -- the restricted grammar is still a limitation, the silent misparse is no longer part of it.
This commit is contained in:
parent
6cd4694613
commit
da30211bc7
3 changed files with 122 additions and 39 deletions
|
|
@ -64,6 +64,10 @@ _KEY_RE = re.compile(r"^[A-Za-z0-9_][A-Za-z0-9_-]*$")
|
|||
# scalar (|, >), flow collection ([ ] { }), directive (%) or reserved char
|
||||
# (@ `) — all outside the supported subset and all rejected.
|
||||
_DANGEROUS_VALUE_STARTS = frozenset("&*!|>[]{}%@`")
|
||||
# A quoted scalar is a scalar in YAML however many colons it carries, so the
|
||||
# mapping check steps aside for one. The quotes are retained rather than
|
||||
# stripped — a pre-existing divergence, pinned in tests/test_okf.py.
|
||||
_QUOTE_STARTS = frozenset("\"'")
|
||||
|
||||
|
||||
class OKFError(Exception):
|
||||
|
|
@ -576,6 +580,7 @@ def _parse_flat(fm_lines):
|
|||
continue
|
||||
|
||||
_reject_dangerous_value(value)
|
||||
_reject_mapping_construct(value)
|
||||
result[key] = value
|
||||
i += 1
|
||||
|
||||
|
|
@ -601,6 +606,7 @@ def _consume_block_list(fm_lines, start):
|
|||
if raw[:1] in (" ", "\t") and stripped.startswith("- "):
|
||||
item = stripped[2:].strip()
|
||||
_reject_dangerous_value(item)
|
||||
_reject_mapping_construct(item)
|
||||
items.append(item)
|
||||
i += 1
|
||||
continue
|
||||
|
|
@ -616,3 +622,29 @@ def _reject_dangerous_value(value):
|
|||
"value begins with a disallowed YAML indicator %r: %r"
|
||||
% (value[0], value)
|
||||
)
|
||||
|
||||
|
||||
def _reject_mapping_construct(value):
|
||||
"""Reject a scalar that YAML reads as a mapping rather than as a string.
|
||||
|
||||
T2 gives the mapping *class* no expressible form — flow, nested-block and
|
||||
dotted-key routes all raise. Two routes used to escape that by degrading
|
||||
into a string instead: a block-sequence item carrying exactly one key
|
||||
(``- uri: x``), and an inline second colon (``attester: resource: x``).
|
||||
Both parsed "successfully" into the wrong *type*, and a pointer parked in
|
||||
one rode through in a key the ``resource`` allowlist never inspects.
|
||||
|
||||
``": "`` and a trailing ``":"`` are exactly the two shapes where a plain
|
||||
scalar stops being one — ground-truthed against PyYAML 6.0.3, which reads
|
||||
``- uri: x`` as ``[{'uri': 'x'}]``, ``- uri:`` as ``[{'uri': None}]``, and
|
||||
refuses ``k: sub: v`` outright. A colon carrying neither a space nor a line
|
||||
end opens no mapping (``domain:security``, ``https://e.com:8443/a``) and is
|
||||
left alone, as is a quoted scalar — over-blocking a conformant bundle is
|
||||
itself a failure mode.
|
||||
"""
|
||||
if not value or value[0] in _QUOTE_STARTS:
|
||||
return
|
||||
if ": " in value or value.endswith(":"):
|
||||
raise OKFFrontmatterError(
|
||||
"a mapping is not expressible in OKF frontmatter: %r" % (value,)
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue