feat(access-control-prover): 11.1 entry-recognition strategy registry

This commit is contained in:
Marius Ciepluch
2026-10-29 20:19:31 +01:00
parent 82e4a1ad97
commit 86709daf2e
5 changed files with 248 additions and 6 deletions
+183
View File
@@ -0,0 +1,183 @@
"""Entry-recognition strategy registry (task 11.1, Reqs 1.1, 1.5, 1.7)."""
from __future__ import annotations
import inspect
from pathlib import Path
import pytest
from openultrasast.mapping import EntryPointRecord
from openultrasast.mapping.registry import (
EntryRecogniser,
register,
registered_strategies,
registry_entries,
)
from openultrasast.preprocess import FileTarget, detect_language
@pytest.fixture(autouse=True)
def _clean_registry() -> None:
"""Each test registers its own strategies into the shared module registry."""
from openultrasast.mapping import registry
registry._STRATEGIES.clear()
class FixtureRouteStrategy:
"""A recogniser defined by the test, named nowhere in engine code."""
identifier = "test-fixture"
languages: tuple[str, ...] = ("java",)
def recognize(self, target: FileTarget, text: str) -> list[EntryPointRecord]:
marker = "fixture marker line 3"
if marker not in text:
return []
return [
EntryPointRecord(
path=target.path,
line=3,
end_line=3,
function_name="fixtureHandler",
name="fixtureHandler",
kind="route",
access_level="unknown",
trust_boundary="external",
access_evidence=[marker],
conditions=[],
provenance="",
rationale="fixture strategy",
)
]
class SelfProvenanceStrategy:
identifier = "test-self-provenance"
languages: tuple[str, ...] = ("java",)
def recognize(self, target: FileTarget, text: str) -> list[EntryPointRecord]:
return [
EntryPointRecord(
path=target.path,
line=1,
end_line=1,
function_name="selfProvenanceHandler",
name="selfProvenanceHandler",
kind="route",
access_level="unknown",
trust_boundary="external",
access_evidence=["self provenance"],
conditions=[],
provenance="strategy-own:declaration",
rationale="fixture",
)
]
def _target(path: str, language: str) -> FileTarget:
return FileTarget(
path=path,
absolute_path=f"/repo/{path}",
language=language,
loc=8,
tags=[],
has_fuzz_entry_point=False,
)
JAVA_TEXT = "package p;\nclass H {\n // fixture marker line 3\n void fixtureHandler() {}\n}\n"
def test_registered_strategy_is_listed_for_its_language() -> None:
register(FixtureRouteStrategy())
strategies = registered_strategies("java")
assert [strategy.identifier for strategy in strategies] == ["test-fixture"]
assert registered_strategies("php") == ()
def test_registry_entries_stamp_strategy_identifier_and_keep_evidence() -> None:
register(FixtureRouteStrategy())
entries = registry_entries(_target("src/H.java", "java"), JAVA_TEXT)
assert len(entries) == 1
assert entries[0].provenance == "strategy:test-fixture"
assert entries[0].access_evidence == ["fixture marker line 3"]
assert entries[0].function_name == "fixtureHandler"
def test_strategy_set_provenance_is_preserved() -> None:
register(SelfProvenanceStrategy())
entries = registry_entries(_target("src/H.java", "java"), "class A {}")
assert entries[0].provenance == "strategy-own:declaration"
def test_re_registration_replaces_the_strategy() -> None:
register(FixtureRouteStrategy())
register(FixtureRouteStrategy())
assert [s.identifier for s in registered_strategies("java")] == ["test-fixture"]
def test_registry_entries_are_deterministic() -> None:
register(FixtureRouteStrategy())
first = registry_entries(_target("src/H.java", "java"), JAVA_TEXT)
second = registry_entries(_target("src/H.java", "java"), JAVA_TEXT)
assert first == second
def test_registry_module_names_no_targets() -> None:
from openultrasast.mapping import registry
source = inspect.getsource(registry)
for target_name in (
"symfony",
"laravel",
"tornado",
"wordpress",
"stapler",
"jetty",
"django",
"flask",
"rails",
"spring",
"express",
):
assert target_name not in source.lower()
def test_dispatch_runs_registered_strategies_alongside_legacy_blocks(tmp_path: Path) -> None:
from openultrasast.mapping import analyze_entry_points
(tmp_path / "H.java").write_text(
"package p;\n"
"import hudson.model.Descriptor;\n"
"class H extends Descriptor<Thing> {\n"
" // fixture marker line 3\n"
" public void doTest(org.kohsuke.stapler.StaplerRequest req) {}\n"
"}\n",
encoding="utf-8",
)
targets = [
FileTarget(
path="H.java",
absolute_path=str(tmp_path / "H.java"),
language=detect_language(tmp_path / "H.java"),
loc=6,
tags=[],
has_fuzz_entry_point=False,
)
]
register(FixtureRouteStrategy())
entries = analyze_entry_points(tmp_path, targets, include_manifests=False)
names = {entry.function_name for entry in entries}
assert "doTest" in names # legacy Stapler block still runs
assert "fixtureHandler" in names # registry strategy contributed
fixture = next(entry for entry in entries if entry.function_name == "fixtureHandler")
assert fixture.provenance == "strategy:test-fixture"
stapler = next(entry for entry in entries if entry.function_name == "doTest")
assert stapler.provenance != "strategy:test-fixture"
def test_entry_recogniser_protocol_is_runtime_implemented() -> None:
strategy = FixtureRouteStrategy()
assert isinstance(strategy, EntryRecogniser)