Files
Open_Ultra_SAST/tests/test_obligation_policy.py
Marius CiepluchandClaude Opus 5 8e26dfd1e2 feat(authorization-obligations): group sibling handlers and find consistency anomalies
Task 2.2. Handlers on the same resource under the same module are siblings;
when at least min_siblings of them discharge an obligation and one does not,
that one is the anomaly and the discharging siblings are its evidence (Req 3.2).
A set with fewer members than the minimum is under-populated and never reported
(Req 3.3). A public route among authenticated siblings is a missing path guard
with the mapper's access classification as evidence (Req 3.4).

The sibling key is the module path without its suffix, so two same-named files
in different directories are never merged. Witness validity (an identity
constraint counts only when it binds the authenticated context) is one helper
shared by operations, siblings and the checker.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
2026-09-06 07:24:13 +02:00

50 lines
2.4 KiB
Python

"""authorization-obligations task 2.3: the declared policy has a closed schema (offline)."""
from __future__ import annotations
from pathlib import Path
import pytest
GOOD = (
'version = 1\nidentity_source = "request.user"\n\n'
'[[resource]]\nname = "book"\nsensitivity = "high"\nidentity_field = "user_id"\n\n'
'[[route]]\npath = "/health"\naccess = "public"\n\n[[route]]\npath = "/admin/*"\naccess = "role"\nroles = ["admin"]\n'
)
def test_valid_policy_loads_with_a_version_hash(tmp_path: Path) -> None:
from openultrasast.semantic.obligations.policy import load_declared_policy
path = tmp_path / "obligations.toml"
path.write_text(GOOD)
policy = load_declared_policy(path)
assert policy is not None and policy.version == 1 and policy.identity_source == "request.user"
assert policy.resources["book"].sensitivity == "high" and policy.resources["book"].identity_field == "user_id"
assert (
policy.route_access("/health") == "public"
and policy.route_access("/admin/users") == "role"
and policy.route_access("/books/1") is None
)
assert len(policy.version_hash) == 40 and policy.version_hash == load_declared_policy(path).version_hash # type: ignore[union-attr]
path.write_text(GOOD + "\n# comment\n")
assert load_declared_policy(path).version_hash == policy.version_hash # type: ignore[union-attr] # normalized: comments do not change the version
assert load_declared_policy(tmp_path / "missing.toml") is None
def test_unknown_fields_and_values_are_rejected_by_name(tmp_path: Path) -> None:
from openultrasast.semantic.obligations.policy import PolicyError, load_declared_policy
path = tmp_path / "obligations.toml"
for bad, needle in (
(GOOD.replace('access = "public"', 'access = "sometimes"'), "sometimes"),
(GOOD + '\n[[resource]]\nname = "x"\nsensitivity = "high"\nmood = "strict"\n', "mood"),
(GOOD.replace('sensitivity = "high"', 'sensitivity = "critical"'), "critical"),
(GOOD + "\nallow_everything = true\n", "allow_everything"),
(GOOD.replace('identity_source = "request.user"', 'identity_source = "whatever.works"'), "identity_source"),
(GOOD + '\n[[route]]\npath = "/x"\naccess = "public"\ncolor = "blue"\n', "color"),
):
path.write_text(bad)
with pytest.raises(PolicyError, match=needle):
load_declared_policy(path)