Implement USER-WP-0024 security layer conformance
Declare Engine/PIP machine-readably, publish a total fail-closed PEP stance map, stop minting local decision ids on engine-unavailable DENY, bind allows to a 30s request lifetime, confine the local authorization double, classify evidence and emit a denial/revocation heartbeat, and prove access-control facts remain claims. Assistant: grok Assistant-Session: 01a04cea-f0d6-7ab3-9ffd-881eb6bea6cb
This commit is contained in:
parent
c7b6148a70
commit
4349758608
22 changed files with 1242 additions and 89 deletions
134
src/user_engine/layer_yaml.py
Normal file
134
src/user_engine/layer_yaml.py
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
"""Minimal YAML mapping loader for layer and PEP-stance declarations.
|
||||
|
||||
Stdlib only. Handles the subset this repository actually writes: nested
|
||||
maps, lists of scalars, lists of maps, quoted strings, booleans, null,
|
||||
integers, and empty lists. Not a general YAML implementation.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
def load_mapping(path: Path) -> dict[str, Any]:
|
||||
data = load_mapping_text(path.read_text())
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError(f"{path} did not parse as a mapping")
|
||||
return data
|
||||
|
||||
|
||||
def load_mapping_text(text: str) -> dict[str, Any]:
|
||||
data = _parse(text)
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError("YAML text did not parse as a mapping")
|
||||
return data
|
||||
|
||||
|
||||
def _parse(text: str) -> Any:
|
||||
lines: list[tuple[int, str]] = []
|
||||
for raw in text.splitlines():
|
||||
stripped = raw.split("#", 1)[0].rstrip()
|
||||
if not stripped:
|
||||
continue
|
||||
indent = len(raw) - len(raw.lstrip(" "))
|
||||
lines.append((indent, stripped.lstrip(" ")))
|
||||
value, _ = _parse_block(lines, 0, 0)
|
||||
return value
|
||||
|
||||
|
||||
def _parse_block(
|
||||
lines: list[tuple[int, str]], index: int, indent: int
|
||||
) -> tuple[Any, int]:
|
||||
if index >= len(lines):
|
||||
return {}, index
|
||||
current_indent, content = lines[index]
|
||||
if current_indent < indent:
|
||||
return {}, index
|
||||
if content.startswith("- "):
|
||||
return _parse_list(lines, index, current_indent)
|
||||
return _parse_map(lines, index, current_indent)
|
||||
|
||||
|
||||
def _parse_map(
|
||||
lines: list[tuple[int, str]], index: int, indent: int
|
||||
) -> tuple[dict[str, Any], int]:
|
||||
result: dict[str, Any] = {}
|
||||
while index < len(lines):
|
||||
current_indent, content = lines[index]
|
||||
if current_indent < indent:
|
||||
break
|
||||
if current_indent > indent:
|
||||
raise ValueError(f"unexpected indent at {content!r}")
|
||||
if content.startswith("- "):
|
||||
break
|
||||
key, separator, remainder = content.partition(":")
|
||||
if not separator:
|
||||
raise ValueError(f"expected key: value, got {content!r}")
|
||||
key = _parse_scalar(key.strip())
|
||||
if not isinstance(key, str):
|
||||
key = str(key)
|
||||
remainder = remainder.strip()
|
||||
index += 1
|
||||
if remainder in ("", "|", ">"):
|
||||
if index < len(lines) and lines[index][0] > indent:
|
||||
value, index = _parse_block(lines, index, lines[index][0])
|
||||
else:
|
||||
value = None
|
||||
else:
|
||||
value = _parse_scalar(remainder)
|
||||
result[key] = value
|
||||
return result, index
|
||||
|
||||
|
||||
def _parse_list(
|
||||
lines: list[tuple[int, str]], index: int, indent: int
|
||||
) -> tuple[list[Any], int]:
|
||||
result: list[Any] = []
|
||||
while index < len(lines):
|
||||
current_indent, content = lines[index]
|
||||
if current_indent < indent:
|
||||
break
|
||||
if current_indent > indent:
|
||||
raise ValueError(f"unexpected indent at {content!r}")
|
||||
if not content.startswith("- "):
|
||||
break
|
||||
item = content[2:].strip()
|
||||
index += 1
|
||||
if not item:
|
||||
if index < len(lines) and lines[index][0] > indent:
|
||||
value, index = _parse_block(lines, index, lines[index][0])
|
||||
else:
|
||||
value = None
|
||||
result.append(value)
|
||||
continue
|
||||
if ":" in item and not item.startswith(("'", '"')):
|
||||
key, _, remainder = item.partition(":")
|
||||
mapping: dict[str, Any] = {key.strip(): _parse_scalar(remainder.strip())}
|
||||
if index < len(lines) and lines[index][0] > indent:
|
||||
nested, index = _parse_block(lines, index, lines[index][0])
|
||||
if isinstance(nested, dict):
|
||||
mapping.update(nested)
|
||||
result.append(mapping)
|
||||
else:
|
||||
result.append(_parse_scalar(item))
|
||||
return result, index
|
||||
|
||||
|
||||
def _parse_scalar(text: str) -> Any:
|
||||
if text in ("", "~", "null", "Null", "NULL"):
|
||||
return None
|
||||
if text in ("true", "True"):
|
||||
return True
|
||||
if text in ("false", "False"):
|
||||
return False
|
||||
if text == "[]":
|
||||
return []
|
||||
if text == "{}":
|
||||
return {}
|
||||
if len(text) >= 2 and text[0] == text[-1] and text[0] in "'\"":
|
||||
return text[1:-1]
|
||||
try:
|
||||
return int(text)
|
||||
except ValueError:
|
||||
return text
|
||||
Loading…
Add table
Add a link
Reference in a new issue