Files
Open_Ultra_SAST/tests/test_obligation_resource_domain.py

223 lines
8.8 KiB
Python

"""access-control-prover task 7.2: resource abstract values and operation-fact sufficiency fields (offline).
Exact resources, finite alias sets, request-global scope and unknown resources per the design's "Abstract
evidence domain" section (Req 2.1, 2.5, 2.6, 2.7, 11.1), plus the additive operation-fact field that declares
a request-global witness kind sufficient at request scope (Req 2.6).
"""
from __future__ import annotations
import itertools
from pathlib import Path
import pytest
def _resource_fixtures():
from openultrasast.semantic.obligations.abstract_domain import (
REQUEST_GLOBAL_RESOURCE,
UNKNOWN_RESOURCE,
ResourceRef,
)
return (
ResourceRef(kind="exact", values=("book",)),
ResourceRef(kind="exact", values=("volume",)),
ResourceRef(kind="aliases", values=("book", "volume")),
ResourceRef(kind="aliases", values=("volume", "shelf")),
REQUEST_GLOBAL_RESOURCE,
UNKNOWN_RESOURCE,
)
_OPERATION_TOML = """version = "1"
language = "python"
[[operation]]
id = "orm-read"
kind = "protected_read"
calls = ["filter_by"]
requires = ["identity_constraint"]
sensitivity = "high"
request_global_kinds = ["path_guard"]
"""
def test_parse_resource_single_token_is_exact() -> None:
from openultrasast.semantic.obligations.abstract_domain import ResourceRef, parse_resource
binding = parse_resource("book")
assert binding == ResourceRef(kind="exact", values=("book",))
assert binding.kind == "exact"
assert binding.values == ("book",)
def test_parse_resource_token_collection_is_a_finite_alias_set() -> None:
from openultrasast.semantic.obligations.abstract_domain import ResourceRef, parse_resource
binding = parse_resource(["volume", "book", "volume"])
assert binding == ResourceRef(kind="aliases", values=("book", "volume"))
def test_parse_resource_without_a_binding_is_unknown() -> None:
from openultrasast.semantic.obligations.abstract_domain import UNKNOWN_RESOURCE, parse_resource
binding = parse_resource(None)
assert binding == UNKNOWN_RESOURCE
assert binding.kind == "unknown"
assert binding.values == ()
def test_request_global_resource_binds_the_whole_request() -> None:
from openultrasast.semantic.obligations.abstract_domain import REQUEST_GLOBAL_RESOURCE
assert REQUEST_GLOBAL_RESOURCE.kind == "request_global"
assert REQUEST_GLOBAL_RESOURCE.values == ()
def test_resource_kinds_distinguish_exact_alias_global_and_unknown() -> None:
# Req 2.7, 11.1: the four grades stay distinct; an unknown binding never collapses onto a concrete one.
from openultrasast.semantic.obligations.abstract_domain import (
REQUEST_GLOBAL_RESOURCE,
UNKNOWN_RESOURCE,
parse_resource,
)
grades = {parse_resource("book"), parse_resource(["book"]), REQUEST_GLOBAL_RESOURCE, UNKNOWN_RESOURCE}
assert {resource.kind for resource in grades} == {"exact", "aliases", "request_global", "unknown"}
def test_alias_values_are_normalized_deterministically() -> None:
from openultrasast.semantic.obligations.abstract_domain import ResourceRef
forward = ResourceRef(kind="aliases", values=("volume", "book", "volume"))
backward = ResourceRef(kind="aliases", values=("book", "volume"))
assert forward == backward
assert hash(forward) == hash(backward)
assert len({forward, backward}) == 1
def test_resource_ref_fails_loud_on_misshapen_kinds_and_arities() -> None:
from openultrasast.semantic.obligations.abstract_domain import ResourceRef
with pytest.raises(ValueError, match="sometimes"):
ResourceRef(kind="sometimes", values=("book",))
with pytest.raises(ValueError, match="exact"):
ResourceRef(kind="exact")
with pytest.raises(ValueError, match="exact"):
ResourceRef(kind="exact", values=("book", "volume"))
with pytest.raises(ValueError, match="alias"):
ResourceRef(kind="aliases", values=())
with pytest.raises(ValueError, match="request_global"):
ResourceRef(kind="request_global", values=("book",))
def test_parse_resource_rejects_misshapen_bindings() -> None:
from openultrasast.semantic.obligations.abstract_domain import parse_resource
with pytest.raises(ValueError):
parse_resource("")
with pytest.raises(ValueError):
parse_resource(())
with pytest.raises(ValueError):
parse_resource(["book", ""])
def test_join_resources_keeps_identical_exact_tokens_exact() -> None:
from openultrasast.semantic.obligations.abstract_domain import ResourceRef, join_resources
binding = ResourceRef(kind="exact", values=("book",))
assert join_resources(binding, ResourceRef(kind="exact", values=("book",))) == binding
def test_join_resources_merges_different_exact_tokens_into_an_alias_set() -> None:
# Req 2.5: a different resource never collapses onto one exact binding; it widens to the finite alias set.
from openultrasast.semantic.obligations.abstract_domain import ResourceRef, join_resources
joined = join_resources(
ResourceRef(kind="exact", values=("book",)),
ResourceRef(kind="exact", values=("volume",)),
)
assert joined == ResourceRef(kind="aliases", values=("book", "volume"))
def test_join_resources_adds_exact_tokens_into_alias_sets() -> None:
from openultrasast.semantic.obligations.abstract_domain import ResourceRef, join_resources
joined = join_resources(
ResourceRef(kind="exact", values=("shelf",)),
ResourceRef(kind="aliases", values=("book", "volume")),
)
assert joined == ResourceRef(kind="aliases", values=("book", "shelf", "volume"))
def test_join_resources_unions_alias_sets_to_their_superset() -> None:
from openultrasast.semantic.obligations.abstract_domain import ResourceRef, join_resources
subset = ResourceRef(kind="aliases", values=("book",))
superset = ResourceRef(kind="aliases", values=("book", "volume"))
assert join_resources(subset, superset) == superset
assert join_resources(superset, subset) == superset
disjoint = join_resources(subset, ResourceRef(kind="aliases", values=("volume",)))
assert disjoint == ResourceRef(kind="aliases", values=("book", "volume"))
def test_join_resources_request_global_absorbs_concrete_bindings() -> None:
# Req 2.6: request-global scope already covers every resource in the request.
from openultrasast.semantic.obligations.abstract_domain import (
REQUEST_GLOBAL_RESOURCE,
ResourceRef,
join_resources,
)
for concrete in (
ResourceRef(kind="exact", values=("book",)),
ResourceRef(kind="aliases", values=("book", "volume")),
):
assert join_resources(concrete, REQUEST_GLOBAL_RESOURCE) == REQUEST_GLOBAL_RESOURCE
assert join_resources(REQUEST_GLOBAL_RESOURCE, concrete) == REQUEST_GLOBAL_RESOURCE
assert join_resources(REQUEST_GLOBAL_RESOURCE, REQUEST_GLOBAL_RESOURCE) == REQUEST_GLOBAL_RESOURCE
def test_join_resources_unknown_absorbs_every_fixture() -> None:
# Req 2.7, 11.1: an unresolvable binding stays unresolvable; joining cannot manufacture precision.
from openultrasast.semantic.obligations.abstract_domain import UNKNOWN_RESOURCE, join_resources
for other in _resource_fixtures():
assert join_resources(other, UNKNOWN_RESOURCE) == UNKNOWN_RESOURCE, other
assert join_resources(UNKNOWN_RESOURCE, other) == UNKNOWN_RESOURCE, other
def test_join_resources_is_commutative_and_idempotent_over_fixtures() -> None:
from openultrasast.semantic.obligations.abstract_domain import join_resources
fixtures = _resource_fixtures()
for left, right in itertools.product(fixtures, repeat=2):
assert join_resources(left, right) == join_resources(right, left), (left, right)
for resource in fixtures:
assert join_resources(resource, resource) == resource, resource
def test_operation_fact_declares_request_global_sufficient_kinds(tmp_path: Path) -> None:
from openultrasast.semantic.obligations.facts import load_obligation_facts
(tmp_path / "python.toml").write_text(_OPERATION_TOML)
(row,) = load_obligation_facts(tmp_path).operations
assert row.request_global_kinds == ("path_guard",)
def test_operation_fact_without_sufficiency_declares_none(tmp_path: Path) -> None:
from openultrasast.semantic.obligations.facts import load_obligation_facts
(tmp_path / "python.toml").write_text(_OPERATION_TOML.replace('request_global_kinds = ["path_guard"]\n', ""))
(row,) = load_obligation_facts(tmp_path).operations
assert row.request_global_kinds == ()
def test_operation_fact_rejects_unknown_request_global_kind(tmp_path: Path) -> None:
from openultrasast.semantic.obligations.facts import ObligationFactsError, load_obligation_facts
(tmp_path / "python.toml").write_text(_OPERATION_TOML.replace('["path_guard"]', '["vibes"]'))
with pytest.raises(ObligationFactsError, match="vibes"):
load_obligation_facts(tmp_path)