From 29030b38fcae40c038b97d2c19eefba9347cc3fc Mon Sep 17 00:00:00 2001 From: Marius Ciepluch <11855163+norandom@users.noreply.github.com> Date: Sun, 1 Nov 2026 18:16:07 +0100 Subject: [PATCH] feat(access-control-prover): publish fact conformance handoff --- .kiro/specs/access-control-prover/tasks.md | 2 +- .../mapping/_entry_fact_conformance_fs.py | 128 ++++++ .../_entry_fact_conformance_negative.py | 300 ++++++++++++++ .../mapping/_entry_fact_conformance_replay.py | 96 +++++ .../mapping/_entry_fact_conformance_wire.py | 70 ++++ .../mapping/entry_fact_conformance.py | 390 ++++++++++++++++++ .../entry_fact_conformance_manifest.py | 284 +++++++++++++ tests/entry_fact_core_consumer.py | 202 +++++++++ tests/entry_fact_core_wire.py | 290 +++++++++++++ tests/entry_fact_evidence_wire.py | 130 ++++++ ...960fee55f5d9a15f0e4b73fbc3573d85622d0defa9 | 1 + ...e1db3971cfa700a41d9b5e11309d45eb529837d556 | 1 + ...3fe7aaf061c85494cd124d1338727c230ba91cc4bd | 1 + ...640373984d4227f0a657b9d03f841634c17d095262 | 1 + ...297d67117e4524a29870834190c13c3870f4d30aa6 | 1 + ...09d53f18ddc78efcc7a25c2417e38ff4600461bc9b | 1 + ...9e7519cba950f92c09b6410fbf713a16ec06eff43f | 1 + ...a096ebd1d0babfc0cd2491d966b7c2120a2e01ee22 | 1 + ...1470219bdb7b8cc5590c04d90401fede5bcd6e9064 | 1 + ...323c7aaa9cbd24b759b42bbf53af3805ec9be0149d | 1 + ...db5e1260995cac678261ce2734cbf048c7b33e9b12 | 1 + ...f745f223c7c3b09cad2714696bbc65cfd332170bbf | 1 + ...dd1513dc40c05b6649a2ff0a81b23175001560d490 | 1 + ...0af54701e4ab41044db5eb61cb812881a60e1b6370 | 1 + ...77816815570d9874d781ac06c5f33b9c75166fb7b4 | 1 + ...3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1 | 1 + ...9b1584daa07cf20552ea17c0b71948890aa88e9ece | 1 + ...a07b0e22a57a537ba6a05448158ef7d7615efb18d3 | 1 + ...99ed359553c7b761dbbff151b815cde6a572c6cc88 | 1 + ...8fde7f73ae2f60364d8b8fee22ecaee8342798d8ce | 33 ++ ...7eac4e2229a784e7cd76a51ab4fcc6db5151da6831 | 1 + .../conformance/v1/manifest.json | 1 + .../conformance/v1/sources/complete.js | 4 + .../conformance/v1/sources/legacy-only.js | 2 + .../conformance/v1/sources/name-only.js | 2 + .../conformance/v1/sources/partial.js | 3 + tests/test_entry_fact_conformance.py | 377 +++++++++++++++++ 37 files changed, 2333 insertions(+), 1 deletion(-) create mode 100644 src/openultrasast/mapping/_entry_fact_conformance_fs.py create mode 100644 src/openultrasast/mapping/_entry_fact_conformance_negative.py create mode 100644 src/openultrasast/mapping/_entry_fact_conformance_replay.py create mode 100644 src/openultrasast/mapping/_entry_fact_conformance_wire.py create mode 100644 src/openultrasast/mapping/entry_fact_conformance.py create mode 100644 src/openultrasast/mapping/entry_fact_conformance_manifest.py create mode 100644 tests/entry_fact_core_consumer.py create mode 100644 tests/entry_fact_core_wire.py create mode 100644 tests/entry_fact_evidence_wire.py create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/0494c5e2973965bbfc12cee1db3971cfa700a41d9b5e11309d45eb529837d556 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/0acf81eaebbf1c67bef9d93fe7aaf061c85494cd124d1338727c230ba91cc4bd create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/1010797dff4ba19deb6e95640373984d4227f0a657b9d03f841634c17d095262 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/3edf94ff896c1e8fb1ae5b297d67117e4524a29870834190c13c3870f4d30aa6 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/4a46c6164bc28bf737ed6109d53f18ddc78efcc7a25c2417e38ff4600461bc9b create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/4b657ac957f89e41f34c179e7519cba950f92c09b6410fbf713a16ec06eff43f create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/60fe67b0d61dbfcedf97ce1470219bdb7b8cc5590c04d90401fede5bcd6e9064 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/615552917e474d463b8af6323c7aaa9cbd24b759b42bbf53af3805ec9be0149d create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/752f84618a299286bd5a9fdd1513dc40c05b6649a2ff0a81b23175001560d490 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/a1c31def035a5c45d4c49f77816815570d9874d781ac06c5f33b9c75166fb7b4 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/aba7fbac17cbc9095715999b1584daa07cf20552ea17c0b71948890aa88e9ece create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/dfad0338dfda8dc13feeb699ed359553c7b761dbbff151b815cde6a572c6cc88 create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce create mode 100644 tests/fixtures/access_control/conformance/v1/artifacts/sha256/fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831 create mode 100644 tests/fixtures/access_control/conformance/v1/manifest.json create mode 100644 tests/fixtures/access_control/conformance/v1/sources/complete.js create mode 100644 tests/fixtures/access_control/conformance/v1/sources/legacy-only.js create mode 100644 tests/fixtures/access_control/conformance/v1/sources/name-only.js create mode 100644 tests/fixtures/access_control/conformance/v1/sources/partial.js create mode 100644 tests/test_entry_fact_conformance.py diff --git a/.kiro/specs/access-control-prover/tasks.md b/.kiro/specs/access-control-prover/tasks.md index 4e398b8..e80b34f 100644 --- a/.kiro/specs/access-control-prover/tasks.md +++ b/.kiro/specs/access-control-prover/tasks.md @@ -381,7 +381,7 @@ its final resolution, dominance, fact-acquisition and measurement semantics with - _Requirements: 1.1, 1.2, 1.3, 1.5, 7.2, 9.4, 13.5, 13.6_ - _Boundary: Structural Matcher_ - _Depends: 14.2, 14.5, 14.6_ -- [ ] 14.8 Produce the downstream conformance handoff +- [x] 14.8 Produce the downstream conformance handoff - Run detection-core fact-pack, fact-match, application and full-evidence validators over target-owned fixtures after proving nonzero fixture reads. - Publish an immutable manifest naming every fixture, artifact digest, validator result and negative-case reason for detection-core task 9.4 to accept; do not add target fixtures to core. - Exercise authority substitution, producer/reviewer conflict, resolver byte substitution, lineage omission, custody contamination and deterministic replay. diff --git a/src/openultrasast/mapping/_entry_fact_conformance_fs.py b/src/openultrasast/mapping/_entry_fact_conformance_fs.py new file mode 100644 index 0000000..5a378d8 --- /dev/null +++ b/src/openultrasast/mapping/_entry_fact_conformance_fs.py @@ -0,0 +1,128 @@ +"""No-follow filesystem primitives for the conformance handoff.""" + +from __future__ import annotations + +import os +import stat +from pathlib import Path + + +class ConformanceFilesystemError(ValueError): + """A handoff path was redirected or was not the required node type.""" + + +def _open_flags(*flags: int) -> int: + result = 0 + for flag in flags: + result |= flag + return result + + +def _read_fd(fd: int) -> bytes: + chunks: list[bytes] = [] + while chunk := os.read(fd, 1024 * 1024): + chunks.append(chunk) + return b"".join(chunks) + + +def read_regular_nofollow(path: Path) -> bytes: + """Read one regular file without following its final path component.""" + flags = _open_flags(os.O_RDONLY, os.O_NOFOLLOW, os.O_NONBLOCK) + try: + fd = os.open(path, flags) + except OSError as exc: + raise ConformanceFilesystemError("path is not a readable regular file") from exc + try: + if not stat.S_ISREG(os.fstat(fd).st_mode): + raise ConformanceFilesystemError("path is not a regular file") + return _read_fd(fd) + except OSError as exc: + raise ConformanceFilesystemError("regular file could not be read") from exc + finally: + os.close(fd) + + +def require_real_directory(path: Path) -> None: + """Require an existing directory whose final component is not a symlink.""" + flags = _open_flags(os.O_RDONLY, os.O_DIRECTORY, os.O_NOFOLLOW) + try: + fd = os.open(path, flags) + except OSError as exc: + raise ConformanceFilesystemError("path is not a real directory") from exc + try: + if not stat.S_ISDIR(os.fstat(fd).st_mode): + raise ConformanceFilesystemError("path is not a real directory") + finally: + os.close(fd) + + +def ensure_real_directory(path: Path) -> None: + """Create a directory if absent, then reject redirected final components.""" + try: + path.mkdir(parents=True, exist_ok=True) + except OSError as exc: + raise ConformanceFilesystemError("directory could not be created") from exc + require_real_directory(path) + + +def flat_regular_census(path: Path) -> tuple[str, ...]: + """Return direct regular-file names and reject every other entry. + + Whole-directory validation assumes no concurrent writer. Opening both the + directory and subsequently read files with ``O_NOFOLLOW`` closes the usual + check-to-open symlink race for each operation. + """ + flags = _open_flags(os.O_RDONLY, os.O_DIRECTORY, os.O_NOFOLLOW) + try: + fd = os.open(path, flags) + except OSError as exc: + raise ConformanceFilesystemError("census root is not a real directory") from exc + try: + if not stat.S_ISDIR(os.fstat(fd).st_mode): + raise ConformanceFilesystemError("census root is not a real directory") + with os.scandir(fd) as entries: + names = [] + for entry in entries: + if not entry.is_file(follow_symlinks=False) or entry.is_symlink(): + raise ConformanceFilesystemError("census contains an unsafe entry") + names.append(entry.name) + return tuple(sorted(names)) + except OSError as exc: + raise ConformanceFilesystemError("directory census failed") from exc + finally: + os.close(fd) + + +def persist_regular_nofollow(path: Path, content: bytes) -> None: + """Create an immutable-addressed file or verify an existing regular file.""" + flags = _open_flags(os.O_CREAT, os.O_EXCL, os.O_WRONLY, os.O_NOFOLLOW) + try: + fd = os.open(path, flags, 0o644) + except FileExistsError: + if read_regular_nofollow(path) != content: + raise ConformanceFilesystemError("existing digest file has different bytes") from None + return + except OSError as exc: + raise ConformanceFilesystemError("digest file could not be created") from exc + try: + view = memoryview(content) + while view: + written = os.write(fd, view) + if written <= 0: + raise ConformanceFilesystemError("digest file write made no progress") + view = view[written:] + os.fsync(fd) + except OSError as exc: + raise ConformanceFilesystemError("digest file could not be written") from exc + finally: + os.close(fd) + + +__all__ = [ + "ConformanceFilesystemError", + "ensure_real_directory", + "flat_regular_census", + "persist_regular_nofollow", + "read_regular_nofollow", + "require_real_directory", +] diff --git a/src/openultrasast/mapping/_entry_fact_conformance_negative.py b/src/openultrasast/mapping/_entry_fact_conformance_negative.py new file mode 100644 index 0000000..1e37cb5 --- /dev/null +++ b/src/openultrasast/mapping/_entry_fact_conformance_negative.py @@ -0,0 +1,300 @@ +"""Negative and replay cases for the downstream entry-fact handoff.""" + +from __future__ import annotations + +from dataclasses import replace +from pathlib import Path +from typing import Any, NoReturn + +from openultrasast.core import canonical, provenance +from openultrasast.core.factmatch import validate_fact_match +from openultrasast.core.factpack import derive_independence_attestation_digest +from openultrasast.mapping.authority_ceremony import load_installed_authority_ceremony +from openultrasast.mapping.entry_fact_matcher import EntryFactMatchResult, match_entry_fact +from openultrasast.mapping.entry_packs import load_entry_pack_patterns +from openultrasast.mapping.fact_authority import EntryFactAuthorityContext, authenticate_entry_fact_authority +from openultrasast.mapping.fact_match_store import FactMatchArtifactWriter +from openultrasast.mapping.installed_fact_authority import fact_pack_bytes, installed_authority_bytes + +_AUTHENTICATE = "openultrasast.mapping.fact_authority.authenticate_entry_fact_authority" + + +def negative_cases( + fixture_root: Path, + output: Path, + sources: dict[str, tuple[str, bytes]], + context: EntryFactAuthorityContext, + evaluation: str, + complete: EntryFactMatchResult, +) -> tuple[dict[str, canonical.JsonValue], ...]: + from openultrasast.mapping.entry_fact_conformance import ( + _CORE_ENTRY_POINTS, + _case, + _persist, + _validator, + ) + + common = (_persist(output, fact_pack_bytes(complete.pack), "fact-pack"),) + rows = _structural_refusals(fixture_root, output, sources, context, evaluation, common) + rows.extend(_authority_cases(output, sources, context)) + rows.append(_resolver_case(sources["resolver_byte_substitution"], common, context, evaluation, complete)) + rows.extend(_lineage_cases(sources, context, evaluation, complete, common)) + rows.append(_contaminated_case(sources["custody_contamination"], common, context, evaluation, complete)) + _legacy_only(fixture_root, output, sources, context, evaluation) + rows.append( + _case( + "legacy_projection_only", + sources["legacy_projection_only"], + "refused", + "name_only_match", + common, + (_validator(_CORE_ENTRY_POINTS[1], "refused", "name_only_match"),), + ) + ) + return tuple(rows) + + +def _authority_cases( + output: Path, + sources: dict[str, tuple[str, bytes]], + context: EntryFactAuthorityContext, +) -> tuple[dict[str, canonical.JsonValue], ...]: + from openultrasast.mapping.entry_fact_conformance import _case, _installed_entries, _persist, _validator + + bundle = context.bundle + ceremony = load_installed_authority_ceremony(_installed_entries()) + substituted = replace(bundle, bundle_digest="0" * 64) + _expect_error( + lambda: authenticate_entry_fact_authority(substituted, ceremony.bootstrap, context.custody, context.resolver), + "authority bundle digest", + ) + substituted_case = _case( + "authority_substitution", + sources["authority_substitution"], + "refused", + "match_pack_identity_substituted", + (_persist(output, installed_authority_bytes(substituted), "authority"),), + (_validator("openultrasast.core.factmatch.validate_fact_match", "refused", "match_pack_identity_substituted"),), + (_validator(_AUTHENTICATE, "refused", "authority_bundle_digest_substituted"),), + ) + review = replace(bundle.authority_review, producer_identity=bundle.authority_review.reviewer_identity, attestation_digest="0" * 64) + review = replace(review, attestation_digest=derive_independence_attestation_digest(review)) + conflicted = replace(bundle, authority_review=review) + _expect_error( + lambda: authenticate_entry_fact_authority(conflicted, ceremony.bootstrap, context.custody, context.resolver), + "producer and reviewer", + ) + conflict_case = _case( + "producer_reviewer_conflict", + sources["producer_reviewer_conflict"], + "refused", + "self_authored_review_evidence", + (_persist(output, installed_authority_bytes(conflicted), "authority"),), + (_validator("openultrasast.core.factpack.validate_fact_pack", "refused", "self_authored_review_evidence"),), + (_validator(_AUTHENTICATE, "refused", "producer_reviewer_conflict"),), + ) + return substituted_case, conflict_case + + +def _resolver_case( + source: tuple[str, bytes], + artifacts: tuple[dict[str, canonical.JsonValue], ...], + context: EntryFactAuthorityContext, + evaluation: str, + complete: EntryFactMatchResult, +) -> dict[str, canonical.JsonValue]: + from openultrasast.mapping.entry_fact_conformance import _CORE_ENTRY_POINTS, _case, _SubstitutingResolver, _validator + + bundle = context.bundle + target = complete.match.observations[0].evidence.content_digest + resolver = _SubstitutingResolver(complete.resolver, target) + _expect_error( + lambda: validate_fact_match( + complete.pack, + complete.match.fact_id, + complete.match, + evaluation, + bundle.lineages, + context.custody, + bundle.custody_policy, + bundle.review_policy, + resolver, + ), + "resolved content digest", + ) + return _case( + "resolver_byte_substitution", + source, + "refused", + "resolver_byte_substitution", + artifacts, + (_validator(_CORE_ENTRY_POINTS[1], "refused", "resolver_byte_substitution"),), + ) + + +def _structural_refusals( + root: Path, + output: Path, + sources: dict[str, tuple[str, bytes]], + context: EntryFactAuthorityContext, + evaluation: str, + artifacts: tuple[dict[str, canonical.JsonValue], ...], +) -> list[dict[str, canonical.JsonValue]]: + from openultrasast.mapping.entry_fact_conformance import _CORE_ENTRY_POINTS, _case, _match, _match_artifacts, _validator + + rows = [] + for case_id, reason in (("name_only", "missing_observation:receiver"), ("partial", "missing_observation:arguments")): + result = _match(root, output, context, evaluation, sources[case_id][0]) + if result.decision.effect_eligible or reason not in result.decision.reasons: + _fail(f"{case_id} did not refuse with its stable reason") + case_artifacts = (*artifacts, *_match_artifacts(output, result)) + rows.append( + _case( + case_id, + sources[case_id], + "refused", + reason, + case_artifacts, + (_validator(_CORE_ENTRY_POINTS[1], "refused", reason),), + ) + ) + return rows + + +def _lineage_cases( + sources: dict[str, tuple[str, bytes]], + context: EntryFactAuthorityContext, + evaluation: str, + complete: EntryFactMatchResult, + artifacts: tuple[dict[str, canonical.JsonValue], ...], +) -> tuple[dict[str, canonical.JsonValue], ...]: + from openultrasast.mapping.entry_fact_conformance import _CORE_ENTRY_POINTS, _case, _validator + + bundle = context.bundle + omitted = tuple(item for item in bundle.lineages if item.manifest_digest != complete.match.matcher_lineage_manifest_digest) + _expect_error( + lambda: validate_fact_match( + complete.pack, + complete.match.fact_id, + complete.match, + evaluation, + omitted, + context.custody, + bundle.custody_policy, + bundle.review_policy, + complete.resolver, + ), + "matcher lineage", + ) + omitted_case = _case( + "lineage_omission", + sources["lineage_omission"], + "refused", + "matcher_lineage_omitted", + artifacts, + (_validator(_CORE_ENTRY_POINTS[1], "refused", "matcher_lineage_omitted"),), + ) + replay = validate_fact_match( + complete.pack, + complete.match.fact_id, + complete.match, + evaluation, + bundle.lineages, + context.custody, + bundle.custody_policy, + bundle.review_policy, + complete.resolver, + ) + if not replay.effect_eligible: + _fail("deterministic replay did not remain complete") + replay_case = _case( + "deterministic_replay", sources["deterministic_replay"], "passed", None, artifacts, (_validator(_CORE_ENTRY_POINTS[1], "passed"),) + ) + return omitted_case, replay_case + + +def _contaminated_case( + source: tuple[str, bytes], + artifacts: tuple[dict[str, canonical.JsonValue], ...], + context: EntryFactAuthorityContext, + evaluation: str, + complete: EntryFactMatchResult, +) -> dict[str, canonical.JsonValue]: + from openultrasast.mapping.entry_fact_conformance import _CORE_ENTRY_POINTS, _case, _Custody, _validator + + custody = context.custody + if not isinstance(custody, _Custody): + _fail("conformance custody has the wrong type") + prior = custody.current_log(evaluation) + lineage = next(item for item in context.bundle.lineages if item.manifest_digest == complete.match.matcher_lineage_manifest_digest) + custody.append( + provenance.PopulationUseRequest( + evaluation, + lineage.arm_id, + provenance.LineagePurpose.MATCHING_BEHAVIOR, + True, + complete.match.matcher_behavior_digest, + prior.log_digest, + ) + ) + decision = validate_fact_match( + complete.pack, + complete.match.fact_id, + complete.match, + evaluation, + context.bundle.lineages, + custody, + context.bundle.custody_policy, + context.bundle.review_policy, + complete.resolver, + ) + reason = next((item for item in decision.reasons if item.startswith("protected_population_labels:")), None) + if decision.effect_eligible or reason is None: + _fail("protected population contamination was not refused") + return _case( + "custody_contamination", + source, + "refused", + "protected_population_contamination", + artifacts, + (_validator(_CORE_ENTRY_POINTS[1], "refused", "protected_population_contamination"),), + ) + + +def _legacy_only( + root: Path, output: Path, sources: dict[str, tuple[str, bytes]], context: EntryFactAuthorityContext, evaluation: str +) -> None: + content = sources["legacy_projection_only"][1].decode("utf-8") + patterns = load_entry_pack_patterns()["javascript"] + writer = FactMatchArtifactWriter( + output, context.bundle.review_policy.trusted_store_identities[0], canonical.content_digest("retain-access-control-conformance-v1") + ) + matches = match_entry_fact( + repository_root=root, + relative_path=sources["legacy_projection_only"][0], + language="javascript", + fact_id="entry:express:app-route:get", + authority=context, + writer=writer, + evaluation_population_digest=evaluation, + ) + if not any(pattern.search(content) for pattern in patterns) or matches: + _fail("legacy-only fixture did not isolate projection recognition") + + +def _expect_error(action: Any, fragment: str) -> None: + try: + action() + except (TypeError, ValueError) as exc: + if fragment not in str(exc): + _fail(f"validator refusal changed: {exc}", exc) + return + _fail("negative conformance case unexpectedly passed") + + +def _fail(message: str, cause: Exception | None = None) -> NoReturn: + from openultrasast.mapping.entry_fact_conformance import EntryFactConformanceError + + if cause is not None: + raise EntryFactConformanceError(message) from cause + raise EntryFactConformanceError(message) diff --git a/src/openultrasast/mapping/_entry_fact_conformance_replay.py b/src/openultrasast/mapping/_entry_fact_conformance_replay.py new file mode 100644 index 0000000..90ffabb --- /dev/null +++ b/src/openultrasast/mapping/_entry_fact_conformance_replay.py @@ -0,0 +1,96 @@ +"""Materialize the self-sufficient generic-core replay artifact.""" + +from __future__ import annotations + +from collections.abc import Mapping +from pathlib import Path + +from openultrasast.core import canonical, provenance +from openultrasast.mapping._installed_fact_authority_codec import wire_value +from openultrasast.mapping.authority_ceremony import INSTALLED_ARTIFACT_STORE_IDENTITY +from openultrasast.mapping.entry_fact_matcher import EntryFactMatchResult +from openultrasast.mapping.fact_authority import EntryFactAuthorityContext + + +def _resolver_material( + output: Path, + result: EntryFactMatchResult, +) -> tuple[tuple[dict[str, canonical.JsonValue], ...], tuple[dict[str, canonical.JsonValue], ...], str]: + from openultrasast.mapping.entry_fact_conformance import _persist + + refs = [item.content for item in result.pack.review_evidence] + refs.extend(item.independence.conflict_disclosure for item in result.pack.review_evidence) + refs.extend(item.evidence for item in result.match.observations) + refs.append(result.match_reference) + artifacts: list[dict[str, canonical.JsonValue]] = [] + entries: list[dict[str, canonical.JsonValue]] = [] + for reference in refs: + artifact = _persist(output, result.resolver.resolve(reference).content, "resolver-content") + artifacts.append(artifact) + entries.append( + { + "reference": wire_value(reference), + "path": artifact["path"], + "store_identity": INSTALLED_ARTIFACT_STORE_IDENTITY, + } + ) + target = result.match.observations[0].evidence + original = result.resolver.resolve(target).content + substituted = _persist(output, b"!" + original[1:], "substituted-content") + artifacts.append(substituted) + return tuple(entries), tuple(artifacts), str(substituted["path"]) + + +def replay_material( + output: Path, + context: EntryFactAuthorityContext, + evaluation: str, + result: EntryFactMatchResult, + source: tuple[str, bytes], +) -> tuple[dict[str, canonical.JsonValue], tuple[dict[str, canonical.JsonValue], ...]]: + from openultrasast.mapping._entry_fact_conformance_wire import replay_envelope_bytes + from openultrasast.mapping.entry_fact_conformance import EntryFactConformanceError, _Custody, _persist, _record + + custody = context.custody + if not isinstance(custody, _Custody): + raise EntryFactConformanceError("conformance custody has the wrong type") + contaminated = custody.current_log(evaluation) + custodian = context.bundle.custody_policy.reviewed_custodian_digests[0] + base_evaluation = provenance.empty_population_custody_log(evaluation, custodian) + base_logs = tuple(base_evaluation if digest == evaluation else log for digest, log in sorted(custody.logs.items())) + entries, artifacts, substituted_path = _resolver_material(output, result) + record = _record(result, evaluation, canonical.bytes_digest(source[1])) + content = replay_envelope_bytes( + context=context, + evaluation_population_digest=evaluation, + result=result, + record=record, + base_logs=base_logs, + contaminated_log=contaminated, + resolver_entries=entries, + substituted_content_path=substituted_path, + ) + return _persist(output, content, "core-replay-envelope"), artifacts + + +def attach_replay( + cases: tuple[dict[str, canonical.JsonValue], ...], + envelope: dict[str, canonical.JsonValue], + dependencies: tuple[dict[str, canonical.JsonValue], ...], +) -> tuple[dict[str, canonical.JsonValue], ...]: + values = [] + for case in cases: + artifacts = case["artifacts"] + if not isinstance(artifacts, tuple): + raise TypeError("case artifacts must be a tuple") + if not all(isinstance(item, Mapping) for item in artifacts): + raise TypeError("case artifact entries must be objects") + existing = {str(item["path"]): item for item in artifacts if isinstance(item, Mapping)} + existing[str(envelope["path"])] = envelope + if case["case_id"] == "complete": + existing.update({str(item["path"]): item for item in dependencies}) + values.append({**case, "artifacts": tuple(existing[path] for path in sorted(existing))}) + return tuple(values) + + +__all__ = ["attach_replay", "replay_material"] diff --git a/src/openultrasast/mapping/_entry_fact_conformance_wire.py b/src/openultrasast/mapping/_entry_fact_conformance_wire.py new file mode 100644 index 0000000..63e5cae --- /dev/null +++ b/src/openultrasast/mapping/_entry_fact_conformance_wire.py @@ -0,0 +1,70 @@ +"""Canonical generic-core replay envelope for the entry-fact handoff.""" + +from __future__ import annotations + +from collections.abc import Mapping, Sequence + +from openultrasast.core import canonical, evidence, provenance +from openultrasast.mapping._installed_fact_authority_codec import wire_value +from openultrasast.mapping.entry_fact_matcher import EntryFactMatchResult +from openultrasast.mapping.fact_authority import EntryFactAuthorityContext + +ENTRY_FACT_REPLAY_SCHEMA = "openultrasast.access-control.entry-fact-core-replay.v1" + + +def _case_plans() -> tuple[Mapping[str, canonical.JsonValue], ...]: + match = "openultrasast.core.factmatch.validate_fact_match" + return ( + {"case_id": "authority_substitution", "replay_kind": "core", "validator": match, "mutation": "match_pack_digest_substitution"}, + {"case_id": "complete", "replay_kind": "core", "validator": "all", "mutation": "none"}, + {"case_id": "custody_contamination", "replay_kind": "core", "validator": match, "mutation": "contaminated_custody"}, + {"case_id": "deterministic_replay", "replay_kind": "core", "validator": match, "mutation": "none"}, + {"case_id": "legacy_projection_only", "replay_kind": "core", "validator": match, "mutation": "qualified_name_only"}, + {"case_id": "lineage_omission", "replay_kind": "core", "validator": match, "mutation": "matcher_lineage_omission"}, + {"case_id": "name_only", "replay_kind": "core", "validator": match, "mutation": "qualified_name_only"}, + {"case_id": "partial", "replay_kind": "core", "validator": match, "mutation": "arguments_omission"}, + { + "case_id": "producer_reviewer_conflict", + "replay_kind": "core", + "validator": "openultrasast.core.factpack.validate_fact_pack", + "mutation": "self_authored_pack", + }, + {"case_id": "resolver_byte_substitution", "replay_kind": "core", "validator": match, "mutation": "resolver_byte_substitution"}, + ) + + +def replay_envelope_bytes( + *, + context: EntryFactAuthorityContext, + evaluation_population_digest: str, + result: EntryFactMatchResult, + record: evidence.EvidenceRecord, + base_logs: Sequence[provenance.PopulationCustodyLog], + contaminated_log: provenance.PopulationCustodyLog, + resolver_entries: Sequence[Mapping[str, canonical.JsonValue]], + substituted_content_path: str, +) -> bytes: + """Serialize every family-neutral input needed for independent core replay.""" + payload: Mapping[str, canonical.JsonValue] = { + "schema_version": ENTRY_FACT_REPLAY_SCHEMA, + "contract": wire_value(context.bundle.contract), + "pack": wire_value(result.pack), + "fact_id": result.match.fact_id, + "match": wire_value(result.match), + "match_reference": wire_value(result.match_reference), + "evidence_record": wire_value(record), + "evaluation_population_digest": evaluation_population_digest, + "lineages": wire_value(context.bundle.lineages), + "review_policy": wire_value(context.bundle.review_policy), + "custody_policy": wire_value(context.bundle.custody_policy), + "custody_logs": wire_value(tuple(base_logs)), + "contaminated_custody_log": wire_value(contaminated_log), + "resolver_entries": tuple(resolver_entries), + "substituted_content_path": substituted_content_path, + "case_plans": tuple(_case_plans()), + } + envelope = {**payload, "envelope_digest": canonical.content_digest(payload)} + return canonical.canonical_record_bytes(envelope, known_schema_versions=(ENTRY_FACT_REPLAY_SCHEMA,)) + + +__all__ = ["ENTRY_FACT_REPLAY_SCHEMA", "replay_envelope_bytes"] diff --git a/src/openultrasast/mapping/entry_fact_conformance.py b/src/openultrasast/mapping/entry_fact_conformance.py new file mode 100644 index 0000000..95ce93d --- /dev/null +++ b/src/openultrasast/mapping/entry_fact_conformance.py @@ -0,0 +1,390 @@ +"""Reproducible downstream conformance handoff for reviewed entry facts.""" + +from __future__ import annotations + +from dataclasses import dataclass, replace +from pathlib import Path + +from openultrasast.core import canonical, evidence, family, provenance, semantics +from openultrasast.core.factapply import apply_fact +from openultrasast.core.factmatch import validate_fact_match +from openultrasast.core.factpack import validate_fact_pack +from openultrasast.core.factvalidate import validate_fact_relations +from openultrasast.mapping._entry_fact_conformance_fs import ( + ConformanceFilesystemError, + ensure_real_directory, + persist_regular_nofollow, + read_regular_nofollow, + require_real_directory, +) +from openultrasast.mapping.entry_fact_matcher import EntryFactMatchResult, match_entry_fact +from openultrasast.mapping.entry_packs import load_installed_entry_fact_authority +from openultrasast.mapping.fact_authority import EntryFactAuthorityContext +from openultrasast.mapping.fact_match_store import FactMatchArtifactWriter +from openultrasast.mapping.installed_fact_authority import fact_pack_bytes + +ENTRY_FACT_CONFORMANCE_SCHEMA = "openultrasast.access-control.entry-fact-conformance.v1" +_CORE_ENTRY_POINTS = ( + "openultrasast.core.factapply.apply_fact", + "openultrasast.core.factmatch.validate_fact_match", + "openultrasast.core.factpack.validate_fact_pack", + "openultrasast.core.factvalidate.validate_fact_relations", +) +_SOURCE_CASES = { + "complete": "sources/complete.js", + "name_only": "sources/name-only.js", + "partial": "sources/partial.js", + "authority_substitution": "sources/complete.js", + "producer_reviewer_conflict": "sources/complete.js", + "resolver_byte_substitution": "sources/complete.js", + "lineage_omission": "sources/complete.js", + "custody_contamination": "sources/complete.js", + "legacy_projection_only": "sources/legacy-only.js", + "deterministic_replay": "sources/complete.js", +} + + +class EntryFactConformanceError(ValueError): + """The target-owned conformance fixture cannot be reproduced safely.""" + + +class _UnusedCustody: + def current_log(self, population_digest: str) -> provenance.PopulationCustodyLog: + raise AssertionError(f"authority load read custody: {population_digest}") + + +class _Custody: + def __init__(self, logs: tuple[provenance.PopulationCustodyLog, ...], policy: provenance.PopulationCustodyPolicy): + self.logs = {item.population_digest: item for item in logs} + self.policy = policy + + def current_log(self, population_digest: str) -> provenance.PopulationCustodyLog: + try: + return self.logs[population_digest] + except KeyError as exc: + raise provenance.PopulationCustodyError("population custody log not found") from exc + + def append(self, request: provenance.PopulationUseRequest) -> provenance.PopulationUseReceipt: + prior = self.current_log(request.population_digest) + custodian = self.policy.reviewed_custodian_digests[0] + receipt = provenance.record_population_use(request, prior, custodian, self.policy) + self.logs[request.population_digest] = provenance.append_population_use(prior, receipt, self.policy) + return receipt + + +@dataclass(frozen=True) +class _SubstitutingResolver: + delegate: canonical.ContentResolver + digest: str + + def resolve(self, reference: canonical.ContentRef) -> canonical.ResolvedContent: + resolved = self.delegate.resolve(reference) + if reference.content_digest != self.digest: + return resolved + return canonical.ResolvedContent(b"!" + resolved.content[1:], resolved.receipt) + + +def _installed_entries() -> Path: + import openultrasast + + return Path(openultrasast.__file__).resolve().parent / "ruleset" / "entries" + + +def _context() -> tuple[EntryFactAuthorityContext, str, _Custody]: + loaded = load_installed_entry_fact_authority(_UnusedCustody()) + bundle = loaded.bundle + custodian = bundle.custody_policy.reviewed_custodian_digests[0] + logs: dict[str, provenance.PopulationCustodyLog] = {} + for lineage in bundle.lineages: + for use in lineage.uses: + prior = logs.setdefault( + use.source_population_digest, + provenance.empty_population_custody_log(use.source_population_digest, custodian), + ) + request = provenance.PopulationUseRequest( + use.source_population_digest, + lineage.arm_id, + use.purpose, + use.labels_accessed, + use.influenced_artifact_digest, + prior.log_digest, + ) + receipt = provenance.record_population_use(request, prior, custodian, bundle.custody_policy) + if receipt.receipt_digest != use.population_use_receipt_digest: + raise EntryFactConformanceError("installed lineage receipt cannot be reproduced") + logs[use.source_population_digest] = provenance.append_population_use(prior, receipt, bundle.custody_policy) + evaluation = canonical.content_digest("access-control-entry-conformance-population-v1") + logs[evaluation] = provenance.empty_population_custody_log(evaluation, custodian) + custody = _Custody(tuple(logs.values()), bundle.custody_policy) + return replace(loaded, custody=custody), evaluation, custody + + +def _read_sources(root: Path) -> dict[str, tuple[str, bytes]]: + values: dict[str, tuple[str, bytes]] = {} + try: + require_real_directory(root / "sources") + except ConformanceFilesystemError as exc: + raise EntryFactConformanceError("sources require a real non-symlink directory") from exc + for case_id, relative in _SOURCE_CASES.items(): + try: + content = read_regular_nofollow(root / relative) + except ConformanceFilesystemError as exc: + raise EntryFactConformanceError(f"{case_id} requires a nonempty readable fixture") from exc + if not content: + raise EntryFactConformanceError(f"{case_id} requires a nonempty readable fixture") + values[case_id] = (relative, content) + return values + + +def _persist(output: Path, content: bytes, kind: str) -> dict[str, canonical.JsonValue]: + if not content: + raise EntryFactConformanceError("handoff artifacts must be nonempty") + digest = canonical.bytes_digest(content) + relative = f"artifacts/sha256/{digest}" + target = output / relative + try: + ensure_real_directory(output) + ensure_real_directory(output / "artifacts") + ensure_real_directory(target.parent) + persist_regular_nofollow(target, content) + except ConformanceFilesystemError as exc: + raise EntryFactConformanceError("artifact path is unsafe or not a regular file") from exc + return {"kind": kind, "path": relative, "content_digest": digest, "byte_length": len(content)} + + +def _validator(name: str, status: str, reason: str | None = None) -> dict[str, canonical.JsonValue]: + return {"name": name, "status": status, "reason": reason} + + +def _case( + case_id: str, + source: tuple[str, bytes], + expected: str, + reason: str | None, + artifacts: tuple[dict[str, canonical.JsonValue], ...], + validators: tuple[dict[str, canonical.JsonValue], ...], + downstream_validators: tuple[dict[str, canonical.JsonValue], ...] = (), +) -> dict[str, canonical.JsonValue]: + path, content = source + return { + "case_id": case_id, + "fixture_path": path, + "fixture_digest": canonical.bytes_digest(content), + "fixture_byte_length": len(content), + "expected_status": expected, + "reason": reason, + "artifacts": artifacts, + "validators": validators, + "downstream_validators": downstream_validators, + } + + +def _match(root: Path, output: Path, context: EntryFactAuthorityContext, evaluation: str, relative: str) -> EntryFactMatchResult: + writer = FactMatchArtifactWriter( + output, + context.bundle.review_policy.trusted_store_identities[0], + canonical.content_digest("retain-access-control-conformance-v1"), + ) + results = match_entry_fact( + repository_root=root, + relative_path=relative, + language="javascript", + fact_id="entry:express:app-route:get", + authority=context, + writer=writer, + evaluation_population_digest=evaluation, + ) + if len(results) != 1: + raise EntryFactConformanceError("fixture must produce exactly one structural candidate") + return results[0] + + +def _match_artifacts(output: Path, result: EntryFactMatchResult) -> tuple[dict[str, canonical.JsonValue], ...]: + refs = tuple(item.evidence for item in result.match.observations) + (result.match_reference,) + return tuple(_persist(output, result.resolver.resolve(ref).content, "match-evidence") for ref in refs) + + +def _stamp(contract: str, evaluation: str, source_digest: str, result: EntryFactMatchResult) -> provenance.ProvenanceStamp: + return provenance.ProvenanceStamp( + canonical.content_digest("entry-conformance-analyzer"), + contract, + canonical.content_digest((result.pack.normalized_content_digest,)), + canonical.content_digest("entry-conformance-acquisition"), + canonical.content_digest("entry-conformance-configuration"), + evaluation, + source_digest, + ) + + +def _record(result: EntryFactMatchResult, evaluation: str, source_digest: str) -> evidence.EvidenceRecord: + location = result.match.product_location + source = semantics.SemanticNode("constraint-source", "security_object", location) + target = semantics.SemanticNode("constraint-target", "operation", location) + product = semantics.EvidenceProvenance(semantics.ProvenanceKind.PRODUCT_CODE, source_digest, None, None, None) + constraint = semantics.make_relation( + kind=semantics.RelationKind.CONSTRAINT_EFFECT, + role="constraint", + source=source, + target=target, + location=location, + status=semantics.RelationStatus.INCOMPLETE, + conditions=(), + reasons=("missing_constraint_relation",), + provenance=product, + ) + fields = ( + semantics.FieldValue("operation", semantics.FieldKind.TEXT, "entry-registration"), + semantics.FieldValue("boundary", semantics.FieldKind.TEXT, "express"), + ) + scope = evidence.AnalyzedScope("base", "head", source_digest, (evidence.SourceRegion(location.path, 1, 4),)) + contract = result.pack.family_contract_digest + packet = evidence.EvidencePacket( + evidence.EVIDENCE_PACKET_SCHEMA, + result.pack.family_id, + contract, + family.derive_security_object_id(_context_contract().security_object, fields), + result.pack.ecosystem, + scope, + (*result.relations, constraint), + (), + fields, + ("missing_constraint_relation",), + _stamp(contract, evaluation, source_digest, result), + ) + decision = evidence.Decision( + "indeterminate", + evidence.NeutralOutcome.INDETERMINATE, + evidence.EvidenceBasis.DETERMINISTIC, + scope, + ("missing_constraint_relation",), + evidence.derive_packet_digest(packet), + provenance.DecisionProvenance(None, None, None, None, None, None), + ) + return evidence.EvidenceRecord(packet, decision, "") + + +def _context_contract() -> family.FamilyContract: + from openultrasast.semantic.obligations.core_contract import production_access_control_contract + + return production_access_control_contract() + + +def _complete_case( + fixture_root: Path, + output: Path, + source: tuple[str, bytes], + context: EntryFactAuthorityContext, + evaluation: str, +) -> tuple[dict[str, canonical.JsonValue], EntryFactMatchResult]: + result = _match(fixture_root, output, context, evaluation, source[0]) + record = _validate_complete(result, context, evaluation, source) + artifacts = _match_artifacts(output, result) + artifacts += (_persist(output, fact_pack_bytes(result.pack), "fact-pack"),) + artifacts += (_persist(output, evidence.evidence_record_bytes(record), "evidence-record"),) + validators = tuple(_validator(name, "passed") for name in _CORE_ENTRY_POINTS) + return _case("complete", source, "passed", None, artifacts, validators), result + + +def _validate_complete( + result: EntryFactMatchResult, + context: EntryFactAuthorityContext, + evaluation: str, + source: tuple[str, bytes], +) -> evidence.EvidenceRecord: + bundle = context.bundle + validate_fact_pack( + result.pack, + bundle.contract, + evaluation, + bundle.lineages, + context.custody, + bundle.custody_policy, + bundle.review_policy, + result.resolver, + ) + validate_fact_match( + result.pack, + result.match.fact_id, + result.match, + evaluation, + bundle.lineages, + context.custody, + bundle.custody_policy, + bundle.review_policy, + result.resolver, + ) + apply_fact( + result.pack, + result.match.fact_id, + result.match, + result.match_reference, + bundle.contract, + evaluation, + bundle.lineages, + context.custody, + bundle.custody_policy, + bundle.review_policy, + result.resolver, + ) + record = _record(result, evaluation, canonical.bytes_digest(source[1])) + _validate_record(record, result, context, evaluation) + return record + + +def _validate_record( + record: evidence.EvidenceRecord, + result: EntryFactMatchResult, + context: EntryFactAuthorityContext, + evaluation: str, +) -> None: + bundle = context.bundle + validate_fact_relations( + record, + bundle.contract, + bundle.packs, + evaluation, + bundle.lineages, + context.custody, + bundle.custody_policy, + bundle.review_policy, + result.resolver, + ) + + +def build_entry_fact_conformance(fixture_root: Path, output_root: Path) -> bytes: + """Run the target adapter and return its canonical immutable handoff manifest.""" + fixture_root, output_root = Path(fixture_root), Path(output_root) + sources = _read_sources(fixture_root) + context, evaluation, _ = _context() + complete, result = _complete_case(fixture_root, output_root, sources["complete"], context, evaluation) + from openultrasast.mapping._entry_fact_conformance_negative import negative_cases + from openultrasast.mapping._entry_fact_conformance_replay import attach_replay, replay_material + + cases = (complete, *negative_cases(fixture_root, output_root, sources, context, evaluation, result)) + replay, dependencies = replay_material(output_root, context, evaluation, result, sources["complete"]) + cases = attach_replay(tuple(sorted(cases, key=lambda item: str(item["case_id"]))), replay, dependencies) + payload: dict[str, canonical.JsonValue] = { + "schema_version": ENTRY_FACT_CONFORMANCE_SCHEMA, + "core_entry_points": _CORE_ENTRY_POINTS, + "cases": cases, + } + manifest = {**payload, "handoff_digest": canonical.content_digest(payload)} + return canonical.canonical_record_bytes(manifest, known_schema_versions=(ENTRY_FACT_CONFORMANCE_SCHEMA,)) + + +def write_entry_fact_conformance(fixture_root: Path, output_root: Path) -> Path: + """Generate artifacts and atomically-equivalent canonical manifest bytes.""" + output = Path(output_root) + content = build_entry_fact_conformance(fixture_root, output) + target = output / "manifest.json" + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(content) + return target + + +__all__ = [ + "ENTRY_FACT_CONFORMANCE_SCHEMA", + "EntryFactConformanceError", + "build_entry_fact_conformance", + "write_entry_fact_conformance", +] diff --git a/src/openultrasast/mapping/entry_fact_conformance_manifest.py b/src/openultrasast/mapping/entry_fact_conformance_manifest.py new file mode 100644 index 0000000..1ca570e --- /dev/null +++ b/src/openultrasast/mapping/entry_fact_conformance_manifest.py @@ -0,0 +1,284 @@ +"""Closed manifest validation for the downstream entry-fact handoff.""" + +from __future__ import annotations + +import json +import re +from collections.abc import Mapping +from pathlib import Path, PurePosixPath +from typing import cast + +from openultrasast.core import canonical +from openultrasast.mapping._entry_fact_conformance_fs import ( + ConformanceFilesystemError, + flat_regular_census, + read_regular_nofollow, + require_real_directory, +) +from openultrasast.mapping.entry_fact_conformance import ENTRY_FACT_CONFORMANCE_SCHEMA, EntryFactConformanceError + +_DIGEST = re.compile(r"[0-9a-f]{64}") +_TOP_FIELDS = {"schema_version", "handoff_digest", "core_entry_points", "cases"} +_CASE_FIELDS = { + "case_id", + "fixture_path", + "fixture_digest", + "fixture_byte_length", + "expected_status", + "reason", + "artifacts", + "validators", + "downstream_validators", +} +_ARTIFACT_FIELDS = {"kind", "path", "content_digest", "byte_length"} +_VALIDATOR_FIELDS = {"name", "status", "reason"} +_EXPECTED_CASES = { + "complete", + "name_only", + "partial", + "authority_substitution", + "producer_reviewer_conflict", + "resolver_byte_substitution", + "lineage_omission", + "custody_contamination", + "legacy_projection_only", + "deterministic_replay", +} +_CORE_ENTRY_POINTS = ( + "openultrasast.core.factapply.apply_fact", + "openultrasast.core.factmatch.validate_fact_match", + "openultrasast.core.factpack.validate_fact_pack", + "openultrasast.core.factvalidate.validate_fact_relations", +) +_MATCH = "openultrasast.core.factmatch.validate_fact_match" +_MATRIX = { + "authority_substitution": ((_MATCH, "refused", "match_pack_identity_substituted"),), + "complete": tuple((name, "passed", None) for name in _CORE_ENTRY_POINTS), + "custody_contamination": ((_MATCH, "refused", "protected_population_contamination"),), + "deterministic_replay": ((_MATCH, "passed", None),), + "legacy_projection_only": ((_MATCH, "refused", "name_only_match"),), + "lineage_omission": ((_MATCH, "refused", "matcher_lineage_omitted"),), + "name_only": ((_MATCH, "refused", "missing_observation:receiver"),), + "partial": ((_MATCH, "refused", "missing_observation:arguments"),), + "producer_reviewer_conflict": (("openultrasast.core.factpack.validate_fact_pack", "refused", "self_authored_review_evidence"),), + "resolver_byte_substitution": ((_MATCH, "refused", "resolver_byte_substitution"),), +} +_DOWNSTREAM_AUTHORITY = "openultrasast.mapping.fact_authority.authenticate_entry_fact_authority" +_DOWNSTREAM_MATRIX: dict[str, tuple[tuple[str, str, str], ...]] = {case_id: () for case_id in _EXPECTED_CASES} +_DOWNSTREAM_MATRIX["authority_substitution"] = ((_DOWNSTREAM_AUTHORITY, "refused", "authority_bundle_digest_substituted"),) +_DOWNSTREAM_MATRIX["producer_reviewer_conflict"] = ((_DOWNSTREAM_AUTHORITY, "refused", "producer_reviewer_conflict"),) + + +def _freeze(value: object) -> canonical.JsonValue: + if value is None or isinstance(value, (str, bool, int, float)): + return value + if isinstance(value, list): + return tuple(_freeze(item) for item in value) + if isinstance(value, Mapping) and all(isinstance(key, str) for key in value): + return {cast(str, key): _freeze(item) for key, item in value.items()} + raise EntryFactConformanceError("manifest contains a value outside canonical JSON") + + +def _object(value: object, fields: set[str], name: str) -> Mapping[str, object]: + if not isinstance(value, Mapping) or set(value) != fields or not all(isinstance(key, str) for key in value): + raise EntryFactConformanceError(f"{name} has unknown or missing fields") + return cast(Mapping[str, object], value) + + +def _array(value: object, name: str) -> list[object]: + if not isinstance(value, list) or not value: + raise EntryFactConformanceError(f"{name} must be a nonempty array") + return value + + +def _list(value: object, name: str) -> list[object]: + if not isinstance(value, list): + raise EntryFactConformanceError(f"{name} must be an array") + return value + + +def _text(value: object, name: str) -> str: + if not isinstance(value, str) or not value: + raise EntryFactConformanceError(f"{name} must be nonempty text") + return value + + +def _digest(value: object, name: str) -> str: + text = _text(value, name) + if _DIGEST.fullmatch(text) is None: + raise EntryFactConformanceError(f"{name} must be a lowercase SHA-256 digest") + return text + + +def _positive(value: object, name: str) -> None: + if isinstance(value, bool) or not isinstance(value, int) or value <= 0: + raise EntryFactConformanceError(f"{name} must be a positive integer") + + +def _relative(value: object, name: str) -> None: + text = _text(value, name) + path = PurePosixPath(text) + if path.is_absolute() or ".." in path.parts or path.as_posix() != text: + raise EntryFactConformanceError(f"{name} must be a normalized relative path") + + +def _validate_case(value: object) -> str: + row = _object(value, _CASE_FIELDS, "case") + case_id = _text(row["case_id"], "case_id") + if case_id not in _MATRIX: + raise EntryFactConformanceError("case identity is unknown") + _relative(row["fixture_path"], "fixture_path") + _digest(row["fixture_digest"], "fixture_digest") + _positive(row["fixture_byte_length"], "fixture_byte_length") + status = _text(row["expected_status"], "expected_status") + reason = row["reason"] + if status not in {"passed", "refused"} or (reason is None) is not (status == "passed"): + raise EntryFactConformanceError("case status and stable reason are inconsistent") + if reason is not None: + _text(reason, "reason") + _validate_artifacts(row["artifacts"]) + _validate_validators(case_id, row["validators"], status, reason) + _validate_downstream(case_id, row["downstream_validators"]) + return case_id + + +def _validate_artifacts(value: object) -> None: + for artifact in _array(value, "artifacts"): + item = _object(artifact, _ARTIFACT_FIELDS, "artifact") + _text(item["kind"], "artifact.kind") + _relative(item["path"], "artifact.path") + digest = _digest(item["content_digest"], "artifact.content_digest") + if item["path"] != f"artifacts/sha256/{digest}": + raise EntryFactConformanceError("artifact path does not equal its digest address") + _positive(item["byte_length"], "artifact.byte_length") + + +def _validate_validators(case_id: str, value: object, status: str, reason: object) -> None: + actual_validators = [] + for validator in _array(value, "validators"): + item = _object(validator, _VALIDATOR_FIELDS, "validator") + name = _text(item["name"], "validator.name") + if name not in _CORE_ENTRY_POINTS: + raise EntryFactConformanceError("validator is outside the exact core entry-point set") + validator_status = _text(item["status"], "validator.status") + if validator_status not in {"passed", "refused"}: + raise EntryFactConformanceError("validator status is unknown") + if item["reason"] is not None: + _text(item["reason"], "validator.reason") + if validator_status != status or item["reason"] != reason: + raise EntryFactConformanceError("validator result differs from its enclosing case") + actual_validators.append((name, validator_status, item["reason"])) + if tuple(actual_validators) != _MATRIX[case_id]: + raise EntryFactConformanceError("case validator matrix is incomplete or reordered") + + +def _validate_downstream(case_id: str, value: object) -> None: + actual = [] + for validator in _list(value, "downstream_validators"): + item = _object(validator, _VALIDATOR_FIELDS, "downstream validator") + actual.append( + ( + _text(item["name"], "downstream validator.name"), + _text(item["status"], "downstream validator.status"), + item["reason"], + ) + ) + if tuple(actual) != _DOWNSTREAM_MATRIX[case_id]: + raise EntryFactConformanceError("downstream validator matrix is incomplete or fabricated") + + +def _validate_files(root: Path, cases: list[object]) -> None: + declared_sources = {_text(_object(raw, _CASE_FIELDS, "case")["fixture_path"], "fixture_path") for raw in cases} + source_root = root / "sources" + try: + actual_sources = {f"sources/{name}" for name in flat_regular_census(source_root)} + except ConformanceFilesystemError as exc: + raise EntryFactConformanceError("source filesystem census differs from declared regular fixtures") from exc + if actual_sources != declared_sources: + raise EntryFactConformanceError("source filesystem census differs from declared regular fixtures") + declared = _declared_artifact_paths(cases) + artifact_root = root / "artifacts" / "sha256" + try: + require_real_directory(root / "artifacts") + actual = {f"artifacts/sha256/{name}" for name in flat_regular_census(artifact_root)} + except ConformanceFilesystemError as exc: + raise EntryFactConformanceError("artifact filesystem census differs from the manifest") from exc + if actual != declared: + raise EntryFactConformanceError("artifact filesystem census differs from the manifest") + _validate_materialized_bytes(root, cases) + + +def _declared_artifact_paths(cases: list[object]) -> set[str]: + declared: set[str] = set() + for raw in cases: + case = _object(raw, _CASE_FIELDS, "case") + for raw_artifact in _array(case["artifacts"], "artifacts"): + artifact = _object(raw_artifact, _ARTIFACT_FIELDS, "artifact") + declared.add(_text(artifact["path"], "artifact.path")) + return declared + + +def _safe_read(path: Path, kind: str) -> bytes: + try: + return read_regular_nofollow(path) + except ConformanceFilesystemError as exc: + raise EntryFactConformanceError(f"{kind} filesystem census differs from the manifest") from exc + + +def _validate_materialized_bytes(root: Path, cases: list[object]) -> None: + for raw in cases: + case = _object(raw, _CASE_FIELDS, "case") + fixture = root / _text(case["fixture_path"], "fixture_path") + fixture_content = _safe_read(fixture, "source") + if ( + not fixture_content + or len(fixture_content) != case["fixture_byte_length"] + or canonical.bytes_digest(fixture_content) != case["fixture_digest"] + ): + raise EntryFactConformanceError("fixture bytes do not match the manifest") + for raw_artifact in _array(case["artifacts"], "artifacts"): + artifact = _object(raw_artifact, _ARTIFACT_FIELDS, "artifact") + path = _text(artifact["path"], "artifact.path") + materialized = _safe_read(root / path, "artifact") + if ( + not materialized + or len(materialized) != artifact["byte_length"] + or canonical.bytes_digest(materialized) != artifact["content_digest"] + ): + raise EntryFactConformanceError("artifact bytes do not match the manifest") + + +def validate_entry_fact_conformance(content: bytes, root: Path | None = None) -> None: + """Refuse noncanonical, open-schema, redirected, or self-inconsistent manifests.""" + try: + parsed = json.loads(content) + except (UnicodeDecodeError, json.JSONDecodeError) as exc: + raise EntryFactConformanceError("manifest is not canonical JSON") from exc + row = _object(parsed, _TOP_FIELDS, "manifest") + if row["schema_version"] != ENTRY_FACT_CONFORMANCE_SCHEMA: + raise EntryFactConformanceError("manifest schema is unknown") + frozen = cast(Mapping[str, canonical.JsonValue], _freeze(parsed)) + if canonical.canonical_record_bytes(frozen, known_schema_versions=(ENTRY_FACT_CONFORMANCE_SCHEMA,)) != content: + raise EntryFactConformanceError("manifest bytes are not canonical") + entry_points = _array(row["core_entry_points"], "core_entry_points") + if not all(isinstance(item, str) and item for item in entry_points) or len(set(entry_points)) != len(entry_points): + raise EntryFactConformanceError("core entry points must be unique nonempty text") + core_entry_points = tuple(cast(str, item) for item in entry_points) + if core_entry_points != _CORE_ENTRY_POINTS: + raise EntryFactConformanceError("core entry points differ from the exact replay set") + cases = _array(row["cases"], "cases") + case_ids = tuple(_validate_case(item) for item in cases) + if set(case_ids) != _EXPECTED_CASES or case_ids != tuple(sorted(case_ids)): + raise EntryFactConformanceError("manifest cases are missing, duplicated, or unordered") + payload: Mapping[str, canonical.JsonValue] = { + "schema_version": ENTRY_FACT_CONFORMANCE_SCHEMA, + "core_entry_points": core_entry_points, + "cases": tuple(_freeze(item) for item in cases), + } + if _digest(row["handoff_digest"], "handoff_digest") != canonical.content_digest(payload): + raise EntryFactConformanceError("handoff digest cannot be re-derived") + if root is not None: + _validate_files(Path(root), cases) + + +__all__ = ["validate_entry_fact_conformance"] diff --git a/tests/entry_fact_core_consumer.py b/tests/entry_fact_core_consumer.py new file mode 100644 index 0000000..d90dcd6 --- /dev/null +++ b/tests/entry_fact_core_consumer.py @@ -0,0 +1,202 @@ +"""Isolated generic-core consumer for the downstream fact handoff.""" + +from __future__ import annotations + +import json +from dataclasses import replace +from pathlib import Path +from typing import Any + +from entry_fact_core_wire import ( + FileResolver, + MemoryCustody, + contract, + custody_log, + fact_match, + fact_pack, + lineage_manifest, + load_envelope, + obj, + reference, + seq, +) +from entry_fact_evidence_wire import record + +from openultrasast.core import custody +from openultrasast.core.factapply import apply_fact +from openultrasast.core.factmatch import derive_fact_match_digest, validate_fact_match +from openultrasast.core.factpack import ( + ReviewIndependencePolicy, + derive_independence_attestation_digest, + validate_fact_pack, +) +from openultrasast.core.factvalidate import validate_fact_relations + + +def _inputs(root: Path) -> tuple[dict[str, Any], dict[str, Any]]: + manifest = obj(json.loads((root / "manifest.json").read_bytes())) + envelope_path = next( + artifact["path"] for case in manifest["cases"] for artifact in case["artifacts"] if artifact["kind"] == "core-replay-envelope" + ) + return manifest, load_envelope(root / envelope_path) + + +def _review_policy(value: object) -> ReviewIndependencePolicy: + row = obj(value) + return ReviewIndependencePolicy( + tuple(seq(row["reviewed_reviewer_digests"])), + tuple(tuple(pair) for pair in seq(row["forbidden_identity_pairs"])), + tuple(seq(row["trusted_store_identities"])), + row["maximum_evidence_bytes"], + row["policy_digest"], + ) + + +def _custody_policy(value: object) -> custody.PopulationCustodyPolicy: + row = obj(value) + return custody.PopulationCustodyPolicy(tuple(seq(row["reviewed_custodian_digests"])), row["policy_digest"]) + + +def _resolver(root: Path, envelope: dict[str, Any]) -> FileResolver: + entries = {} + for raw in envelope["resolver_entries"]: + item = obj(raw) + ref = reference(item["reference"]) + entries[ref.content_digest] = (ref, item["path"], item["store_identity"]) + return FileResolver(root, entries) + + +def _changed_match(value: object, mutation: str): + match = fact_match(value) + if mutation in {"qualified_name_only", "receiver_omission", "arguments_omission"}: + keep = { + "qualified_name_only": {"qualified_target"}, + "receiver_omission": {"qualified_target", "call_shape", "arguments"}, + "arguments_omission": {"qualified_target", "call_shape", "receiver"}, + }[mutation] + match = replace( + match, observations=tuple(item for item in match.observations if item.requirement_id in keep), match_digest="0" * 64 + ) + elif mutation == "match_pack_digest_substitution": + match = replace(match, pack_digest="0" * 64, match_digest="0" * 64) + return replace(match, match_digest=derive_fact_match_digest(match)) if match.match_digest == "0" * 64 else match + + +def _self_authored(value: object): + pack = fact_pack(value) + first = pack.review_evidence[0] + attestation = replace( + first.independence, + producer_identity=first.reviewer_identity, + reviewer_identity=first.reviewer_identity, + attestation_digest="0" * 64, + ) + attestation = replace(attestation, attestation_digest=derive_independence_attestation_digest(attestation)) + evidence = replace(first, producer_identity=first.reviewer_identity, independence=attestation) + return replace(pack, review_evidence=(evidence, *pack.review_evidence[1:])) + + +def replay_all(root: Path) -> dict[str, tuple[str, str | None]]: + manifest, envelope = _inputs(root) + contract_value = contract(envelope["contract"]) + pack = fact_pack(envelope["pack"]) + base_match = fact_match(envelope["match"]) + match_reference = reference(envelope["match_reference"]) + lineages = tuple(lineage_manifest(item) for item in seq(envelope["lineages"])) + policy = _review_policy(envelope["review_policy"]) + custody_policy = _custody_policy(envelope["custody_policy"]) + base_logs = tuple(custody_log(item) for item in seq(envelope["custody_logs"])) + population = envelope["evaluation_population_digest"] + expected = {case["case_id"]: (case["expected_status"], case["reason"]) for case in manifest["cases"]} + results: dict[str, tuple[str, str | None]] = {} + for raw_plan in envelope["case_plans"]: + plan = obj(raw_plan) + case_id, mutation = plan["case_id"], plan["mutation"] + match = _changed_match(envelope["match"], mutation) + selected_lineages = lineages + logs = base_logs + resolver = _resolver(root, envelope) + selected_pack = pack + if mutation == "matcher_lineage_omission": + selected_lineages = tuple(item for item in lineages if item.manifest_digest != base_match.matcher_lineage_manifest_digest) + elif mutation == "contaminated_custody": + contaminated = custody_log(envelope["contaminated_custody_log"]) + logs = tuple(contaminated if item.population_digest == population else item for item in base_logs) + elif mutation == "resolver_byte_substitution": + resolver.substitution = (base_match.observations[0].evidence.content_digest, envelope["substituted_content_path"]) + elif mutation == "self_authored_pack": + selected_pack = _self_authored(envelope["pack"]) + current = MemoryCustody({item.population_digest: item for item in logs}) + results[case_id] = _run_case( + case_id, + plan["validator"], + selected_pack, + contract_value, + match, + match_reference, + population, + selected_lineages, + current, + custody_policy, + policy, + resolver, + record(envelope["evidence_record"]), + ) + assert results[case_id] == expected[case_id] + return results + + +def _run_case( + case_id, + validator, + pack, + contract_value, + match, + match_reference, + population, + lineages, + current, + custody_policy, + policy, + resolver, + evidence_record, +): + try: + if validator in {"all", "openultrasast.core.factpack.validate_fact_pack"}: + validate_fact_pack(pack, contract_value, population, lineages, current, custody_policy, policy, resolver) + if validator in {"all", "openultrasast.core.factmatch.validate_fact_match"}: + decision = validate_fact_match(pack, match.fact_id, match, population, lineages, current, custody_policy, policy, resolver) + if not decision.effect_eligible: + return "refused", _decision_reason(case_id, decision.reasons) + if validator == "all": + apply_fact( + pack, match.fact_id, match, match_reference, contract_value, population, lineages, current, custody_policy, policy, resolver + ) + validate_fact_relations( + evidence_record, contract_value, (pack,), population, lineages, current, custody_policy, policy, resolver + ) + return "passed", None + except (TypeError, ValueError) as exc: + return "refused", _error_reason(case_id, str(exc)) + + +def _decision_reason(case_id: str, reasons: tuple[str, ...]) -> str: + expected = { + "custody_contamination": "protected_population_contamination", + "legacy_projection_only": "name_only_match", + "name_only": "missing_observation:receiver", + "partial": "missing_observation:arguments", + }[case_id] + assert expected in reasons or any(item.startswith("protected_population_labels:") for item in reasons) + return expected + + +def _error_reason(case_id: str, message: str) -> str: + expected = { + "authority_substitution": ("match pack digest", "match_pack_identity_substituted"), + "lineage_omission": ("matcher lineage", "matcher_lineage_omitted"), + "producer_reviewer_conflict": ("producer and reviewer", "self_authored_review_evidence"), + "resolver_byte_substitution": ("resolved content digest", "resolver_byte_substitution"), + }[case_id] + assert expected[0] in message + return expected[1] diff --git a/tests/entry_fact_core_wire.py b/tests/entry_fact_core_wire.py new file mode 100644 index 0000000..2330bf8 --- /dev/null +++ b/tests/entry_fact_core_wire.py @@ -0,0 +1,290 @@ +"""Family-neutral decoders for the checked-in fact conformance envelope.""" + +from __future__ import annotations + +import json +from dataclasses import dataclass +from pathlib import Path +from typing import Any, cast + +from openultrasast.core import canonical, custody, evidence, family, lineage, semantics +from openultrasast.core.factmatch import FactMatchEvidence, StructuralObservation +from openultrasast.core.factpack import ( + FactPack, + IndependenceAttestation, + KnowledgeEvidence, + KnowledgeEvidenceKind, + RelationEffect, + SemanticFact, + StructuralRequirement, + StructuralRequirementKind, +) + +REPLAY_SCHEMA = "openultrasast.access-control.entry-fact-core-replay.v1" + + +def obj(value: object) -> dict[str, Any]: + assert isinstance(value, dict) + return cast(dict[str, Any], value) + + +def seq(value: object) -> tuple[Any, ...]: + assert isinstance(value, list) + return tuple(value) + + +def location(value: object) -> semantics.SourceLocation: + row = obj(value) + return semantics.SourceLocation(row["path"], row["line"], row["column"], row["symbol"]) + + +def reference(value: object) -> canonical.ContentRef: + row = obj(value) + return canonical.ContentRef( + row["artifact_id"], + row["content_digest"], + row["media_type"], + row["byte_length"], + row["retention_policy_digest"], + row["storage_receipt_digest"], + ) + + +def field_spec(value: object) -> family.FieldSpec: + row = obj(value) + return family.FieldSpec(row["name"], semantics.FieldKind(row["kind"]), row["required"]) + + +def contract(value: object) -> family.FamilyContract: + row = obj(value) + security = obj(row["security_object"]) + return family.FamilyContract( + row["family_id"], + row["family_version"], + row["schema_version"], + tuple(seq(row["ecosystems"])), + family.ObjectSpec( + security["kind"], + tuple(field_spec(item) for item in seq(security["fields"])), + tuple(seq(security["identity_fields"])), + ), + tuple( + family.RoleSpec( + item["role"], + tuple(field_spec(field) for field in seq(item["fields"])), + tuple(semantics.RelationKind(kind) for kind in seq(item["allowed_relation_kinds"])), + family.RelationOriginPolicy(item["origin_policy"]), + ) + for raw in seq(row["roles"]) + for item in (obj(raw),) + ), + tuple( + family.DecisionRule( + item["family_code"], + evidence.NeutralOutcome(item["outcome"]), + tuple(seq(item["required_roles"])), + tuple(semantics.RelationStatus(status) for status in seq(item["allowed_statuses"])), + ) + for raw in seq(row["decisions"]) + for item in (obj(raw),) + ), + tuple( + family.ResidualQuestion(item["question_id"], tuple(seq(item["required_roles"])), tuple(seq(item["allowed_decisions"]))) + for raw in seq(row["residual_questions"]) + for item in (obj(raw),) + ), + tuple(seq(row["indeterminate_reasons"])), + ) + + +def attestation(value: object) -> IndependenceAttestation: + row = obj(value) + return IndependenceAttestation( + row["subject_digest"], + row["producer_identity"], + row["reviewer_identity"], + reference(row["conflict_disclosure"]), + row["attestation_digest"], + ) + + +def knowledge(value: object) -> KnowledgeEvidence: + row = obj(value) + return KnowledgeEvidence( + KnowledgeEvidenceKind(row["kind"]), + reference(row["content"]), + row["producer_identity"], + row["reviewer_identity"], + attestation(row["independence"]), + row["lineage_manifest_digest"], + ) + + +def fact_pack(value: object) -> FactPack: + row = obj(value) + facts = tuple( + SemanticFact( + item["fact_id"], + item["role"], + tuple( + StructuralRequirement(req["requirement_id"], StructuralRequirementKind(req["kind"]), req["field"], req["expected"]) + for raw_req in seq(item["structural_requirements"]) + for req in (obj(raw_req),) + ), + tuple( + RelationEffect( + semantics.RelationKind(effect["kind"]), + effect["role"], + effect["source_role"], + effect["target_role"], + tuple(seq(effect["conditions"])), + ) + for raw_effect in seq(item["relation_effects"]) + for effect in (obj(raw_effect),) + ), + ) + for raw in seq(row["facts"]) + for item in (obj(raw),) + ) + return FactPack( + row["schema_version"], + row["family_contract_digest"], + row["family_id"], + row["ecosystem"], + row["language"], + facts, + row["normalized_content_digest"], + row["review_identity"], + tuple(knowledge(item) for item in seq(row["review_evidence"])), + row["review_evidence_digest"], + row["review_policy_digest"], + ) + + +def observation(value: object) -> StructuralObservation: + row = obj(value) + return StructuralObservation(row["requirement_id"], location(row["location"]), row["observed"], reference(row["evidence"])) + + +def fact_match(value: object) -> FactMatchEvidence: + row = obj(value) + return FactMatchEvidence( + row["pack_digest"], + row["fact_id"], + location(row["product_location"]), + tuple(observation(item) for item in seq(row["observations"])), + row["matcher_revision"], + row["matcher_behavior_digest"], + row["matcher_lineage_manifest_digest"], + row["match_digest"], + ) + + +def lineage_use(value: object) -> lineage.LineageUse: + row = obj(value) + return lineage.LineageUse( + custody.LineagePurpose(row["purpose"]), + row["source_population_digest"], + row["labels_accessed"], + row["influenced_artifact_digest"], + row["population_use_receipt_digest"], + ) + + +def lineage_manifest(value: object) -> lineage.LineageManifest: + row = obj(value) + return lineage.LineageManifest( + row["arm_id"], + row["subject_digest"], + tuple(lineage_use(item) for item in seq(row["uses"])), + row["manifest_digest"], + ) + + +def use_request(value: object) -> custody.PopulationUseRequest: + row = obj(value) + return custody.PopulationUseRequest( + row["population_digest"], + row["arm_id"], + custody.LineagePurpose(row["purpose"]), + row["labels_accessed"], + row["influenced_artifact_digest"], + row["expected_log_digest"], + ) + + +def use_receipt(value: object) -> custody.PopulationUseReceipt: + row = obj(value) + return custody.PopulationUseReceipt( + use_request(row["request"]), + row["request_digest"], + row["population_digest"], + row["custodian_identity"], + row["sequence"], + row["predecessor_digest"], + custody.PopulationStatus(row["prior_status"]), + custody.PopulationStatus(row["status"]), + tuple(seq(row["reasons"])), + row["receipt_digest"], + ) + + +def custody_log(value: object) -> custody.PopulationCustodyLog: + row = obj(value) + return custody.PopulationCustodyLog( + row["population_digest"], + row["custodian_identity"], + tuple(use_receipt(item) for item in seq(row["receipts"])), + row["receipt_count"], + row["head_receipt_digest"], + custody.PopulationStatus(row["status"]), + row["log_digest"], + ) + + +@dataclass +class MemoryCustody: + logs: dict[str, custody.PopulationCustodyLog] + + def current_log(self, population_digest: str) -> custody.PopulationCustodyLog: + return self.logs[population_digest] + + +@dataclass +class FileResolver: + root: Path + entries: dict[str, tuple[canonical.ContentRef, str, str]] + substitution: tuple[str, str] | None = None + + def resolve(self, value: canonical.ContentRef) -> canonical.ResolvedContent: + expected, path, store = self.entries[value.content_digest] + assert expected == value + if self.substitution is not None and value.content_digest == self.substitution[0]: + path = self.substitution[1] + content = (self.root / path).read_bytes() + receipt = canonical.StorageReceipt( + store, + value.content_digest, + value.byte_length, + value.retention_policy_digest, + value.storage_receipt_digest, + ) + return canonical.ResolvedContent(content, receipt) + + +def load_envelope(path: Path) -> dict[str, Any]: + content = path.read_bytes() + assert len(content) > 0 + row = obj(json.loads(content)) + assert row["schema_version"] == REPLAY_SCHEMA + payload = {key: value for key, value in row.items() if key != "envelope_digest"} + assert canonical.content_digest(_freeze(payload)) == row["envelope_digest"] + return row + + +def _freeze(value: object) -> canonical.JsonValue: + if isinstance(value, list): + return tuple(_freeze(item) for item in value) + if isinstance(value, dict): + return {key: _freeze(item) for key, item in value.items()} + return cast(canonical.JsonValue, value) diff --git a/tests/entry_fact_evidence_wire.py b/tests/entry_fact_evidence_wire.py new file mode 100644 index 0000000..bbe4053 --- /dev/null +++ b/tests/entry_fact_evidence_wire.py @@ -0,0 +1,130 @@ +"""Family-neutral evidence-record decoder for conformance replay.""" + +from __future__ import annotations + +from entry_fact_core_wire import location, obj, reference, seq + +from openultrasast.core import evidence, provenance, semantics + + +def node(value: object) -> semantics.SemanticNode: + row = obj(value) + return semantics.SemanticNode(row["node_id"], row["role"], location(row["location"])) + + +def semantic_provenance(value: object) -> semantics.EvidenceProvenance: + row = obj(value) + fact_match = None if row["fact_match"] is None else reference(row["fact_match"]) + return semantics.EvidenceProvenance( + semantics.ProvenanceKind(row["kind"]), + row["source_content_digest"], + row["semantic_pack_digest"], + row["semantic_fact_id"], + fact_match, + ) + + +def relation(value: object) -> semantics.SemanticRelation: + row = obj(value) + return semantics.SemanticRelation( + row["relation_id"], + semantics.RelationKind(row["kind"]), + row["role"], + node(row["source"]), + node(row["target"]), + location(row["location"]), + semantics.RelationStatus(row["status"]), + tuple(seq(row["conditions"])), + tuple(seq(row["reasons"])), + semantic_provenance(row["provenance"]), + ) + + +def field(value: object) -> semantics.FieldValue: + row = obj(value) + return semantics.FieldValue(row["name"], semantics.FieldKind(row["kind"]), row["value"]) + + +def observation(value: object) -> semantics.Observation: + row = obj(value) + return semantics.Observation( + row["observation_id"], + row["role"], + location(row["location"]), + tuple(field(item) for item in seq(row["fields"])), + semantics.RelationStatus(row["status"]), + semantic_provenance(row["provenance"]), + ) + + +def scope(value: object) -> evidence.AnalyzedScope: + row = obj(value) + return evidence.AnalyzedScope( + row["base_revision"], + row["head_revision"], + row["change_digest"], + tuple( + evidence.SourceRegion(item["path"], item["start_line"], item["end_line"]) for raw in seq(row["regions"]) for item in (obj(raw),) + ), + ) + + +def stamp(value: object) -> provenance.ProvenanceStamp: + row = obj(value) + return provenance.ProvenanceStamp( + row["analyzer_revision"], + row["family_contract_digest"], + row["fact_set_digest"], + row["acquisition_record_digest"], + row["configuration_digest"], + row["population_digest"], + row["change_input_digest"], + ) + + +def packet(value: object) -> evidence.EvidencePacket: + row = obj(value) + return evidence.EvidencePacket( + row["schema_version"], + row["family_id"], + row["family_contract_digest"], + row["security_object_id"], + row["ecosystem"], + scope(row["scope"]), + tuple(relation(item) for item in seq(row["transitions"])), + tuple(observation(item) for item in seq(row["observations"])), + tuple(field(item) for item in seq(row["family_fields"])), + tuple(seq(row["completeness_reasons"])), + stamp(row["provenance"]), + ) + + +def decision_provenance(value: object) -> provenance.DecisionProvenance: + row = obj(value) + assert row["model_identity"] is None + return provenance.DecisionProvenance( + None, + row["model_result_digest"], + row["model_declaration_digest"], + row["proof_record_digest"], + row["proof_producer_digest"], + row["lineage_manifest_digest"], + ) + + +def decision(value: object) -> evidence.Decision: + row = obj(value) + return evidence.Decision( + row["family_code"], + evidence.NeutralOutcome(row["outcome"]), + evidence.EvidenceBasis(row["basis"]), + scope(row["bounded_scope"]), + tuple(seq(row["reasons"])), + row["packet_digest"], + decision_provenance(row["provenance"]), + ) + + +def record(value: object) -> evidence.EvidenceRecord: + row = obj(value) + return evidence.EvidenceRecord(packet(row["packet"]), decision(row["decision"]), row["record_id"]) diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9 new file mode 100644 index 0000000..e6d84ef --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9 @@ -0,0 +1 @@ +{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"app.get","requirement_id":"qualified_target","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/0494c5e2973965bbfc12cee1db3971cfa700a41d9b5e11309d45eb529837d556 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/0494c5e2973965bbfc12cee1db3971cfa700a41d9b5e11309d45eb529837d556 new file mode 100644 index 0000000..4fbf8b0 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/0494c5e2973965bbfc12cee1db3971cfa700a41d9b5e11309d45eb529837d556 @@ -0,0 +1 @@ +{"location":{"column":0,"line":1,"path":"sources/name-only.js","symbol":"app.get->adminHandler@sources/name-only.js:2:9"},"observed":"app.get","requirement_id":"qualified_target","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/0acf81eaebbf1c67bef9d93fe7aaf061c85494cd124d1338727c230ba91cc4bd b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/0acf81eaebbf1c67bef9d93fe7aaf061c85494cd124d1338727c230ba91cc4bd new file mode 100644 index 0000000..305a3ce --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/0acf81eaebbf1c67bef9d93fe7aaf061c85494cd124d1338727c230ba91cc4bd @@ -0,0 +1 @@ +{"location":{"column":0,"line":3,"path":"sources/partial.js","symbol":"app.get"},"observed":"express_application","requirement_id":"receiver","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/1010797dff4ba19deb6e95640373984d4227f0a657b9d03f841634c17d095262 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/1010797dff4ba19deb6e95640373984d4227f0a657b9d03f841634c17d095262 new file mode 100644 index 0000000..87c11d4 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/1010797dff4ba19deb6e95640373984d4227f0a657b9d03f841634c17d095262 @@ -0,0 +1 @@ +{"authority_review":{"attestation_digest":"c07b5c22c2724b13dd34134b112c66ad9e2885e2e6947e23cde6245b3bbc9061","conflict_disclosure":{"artifact_id":"installed-entry-authority-conflicts-v1","byte_length":113,"content_digest":"a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"ee92fde020e9b4d316ad285f3f904032c52d902fe1c7c0a94cb0d61d9c0136ce"},"producer_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43","reviewer_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43","subject_digest":"0fa8f607297aa5364a0ca6c9b8d47bfcdef28456b7f062ddb251f8f8b9a67da4"},"bundle_digest":"0fa8f607297aa5364a0ca6c9b8d47bfcdef28456b7f062ddb251f8f8b9a67da4","custody_policy":{"policy_digest":"415b1c13adc918c162932a38e79548a7d9867f5331860eb409238c51b1cca1f0","reviewed_custodian_digests":["4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632"]},"lineages":[{"arm_id":"installed-entry-facts:javascript","manifest_digest":"f3b4b192dadd6b7d0d298286008480dadfd8640e9603020b0f24d13dce9bda04","subject_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","uses":[{"influenced_artifact_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","labels_accessed":false,"population_use_receipt_digest":"36ccebd06b60601775ab24a2f7ec9f2b49c2eac6b273816eaf9e867f6c445915","purpose":"semantic_fact","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]},{"arm_id":"installed-entry-facts:typescript","manifest_digest":"b7a6a95ddcdd8f6e6dbcd2b90cb707eda9833ec7479cb4d7aae3c91cfe0059ca","subject_digest":"b6d1157e99537bd4928303ec0d887628bc53f0aa9e770427580a32e3948babd9","uses":[{"influenced_artifact_digest":"b6d1157e99537bd4928303ec0d887628bc53f0aa9e770427580a32e3948babd9","labels_accessed":false,"population_use_receipt_digest":"7dc5fe36b1e111ab6cf979137c40bf67b885b2a9deda944aff78e3031cb5a553","purpose":"semantic_fact","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]},{"arm_id":"installed-entry-structural-matcher","manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","subject_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","uses":[{"influenced_artifact_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","labels_accessed":false,"population_use_receipt_digest":"a602c8bccc6afc2ff9d857119131a2847509bc693a80192bf8459b9dcba9cbda","purpose":"matching_behavior","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]}],"matcher_behavior_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","matcher_lineage_manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","matcher_revision":"entry-structural-matcher-v1","pack_files":["express.javascript.v2.json","express.typescript.v2.json"],"recognition_projection":{"artifact_id":"express-recognition-projection-v1","byte_length":628,"content_digest":"529d18ba2b351a8de985a9cf416261d717ef55a4b7a9d9d65bce53b97d59ab35","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"3a85c0641cddcfc8c926fd01e230360c042606bda78e14a39489de14f88944b4"},"review_policy":{"forbidden_identity_pairs":[],"maximum_evidence_bytes":1048576,"policy_digest":"cb023a4f7e727ec4abfee583256194fe3f11c064a10960f297c1f7bf2e6fecde","reviewed_reviewer_digests":["f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43"],"trusted_store_identities":["openultrasast-installed-entry-artifacts-v1"]},"schema_version":"openultrasast.access-control.installed-entry-authority.v1"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/3edf94ff896c1e8fb1ae5b297d67117e4524a29870834190c13c3870f4d30aa6 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/3edf94ff896c1e8fb1ae5b297d67117e4524a29870834190c13c3870f4d30aa6 new file mode 100644 index 0000000..66fc118 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/3edf94ff896c1e8fb1ae5b297d67117e4524a29870834190c13c3870f4d30aa6 @@ -0,0 +1 @@ +{"fact_id":"entry:express:app-route:get","matcher_behavior_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","matcher_lineage_manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","matcher_revision":"entry-structural-matcher-v1","observations":[{"evidence":{"artifact_id":"structural-observation:0494c5e2973965bbfc12cee1db3971cfa700a41d9b5e11309d45eb529837d556","byte_length":253,"content_digest":"0494c5e2973965bbfc12cee1db3971cfa700a41d9b5e11309d45eb529837d556","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"d364b9ac443e85a5cf7f4de2bea24f0a5d16719ede85486ef93800ac99702267"},"location":{"column":0,"line":1,"path":"sources/name-only.js","symbol":"app.get->adminHandler@sources/name-only.js:2:9"},"observed":"app.get","requirement_id":"qualified_target"},{"evidence":{"artifact_id":"structural-observation:60fe67b0d61dbfcedf97ce1470219bdb7b8cc5590c04d90401fede5bcd6e9064","byte_length":251,"content_digest":"60fe67b0d61dbfcedf97ce1470219bdb7b8cc5590c04d90401fede5bcd6e9064","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"305af51d6f3af6440f732ddcb13971c2ffe9f3327452915ca126061eb08c896b"},"location":{"column":0,"line":1,"path":"sources/name-only.js","symbol":"app.get->adminHandler@sources/name-only.js:2:9"},"observed":"member_call","requirement_id":"call_shape"},{"evidence":{"artifact_id":"structural-observation:aba7fbac17cbc9095715999b1584daa07cf20552ea17c0b71948890aa88e9ece","byte_length":261,"content_digest":"aba7fbac17cbc9095715999b1584daa07cf20552ea17c0b71948890aa88e9ece","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"c36686f481771721e444b10f632990f18951f4cdef1e0c0d02e5a3325b19c6d5"},"location":{"column":0,"line":1,"path":"sources/name-only.js","symbol":"app.get->adminHandler@sources/name-only.js:2:9"},"observed":"route_path_and_handler","requirement_id":"arguments"}],"pack_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","product_location":{"column":0,"line":1,"path":"sources/name-only.js","symbol":"app.get->adminHandler@sources/name-only.js:2:9"},"schema_version":"openultrasast.detection-core.fact-match.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/4a46c6164bc28bf737ed6109d53f18ddc78efcc7a25c2417e38ff4600461bc9b b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/4a46c6164bc28bf737ed6109d53f18ddc78efcc7a25c2417e38ff4600461bc9b new file mode 100644 index 0000000..fce2c1b --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/4a46c6164bc28bf737ed6109d53f18ddc78efcc7a25c2417e38ff4600461bc9b @@ -0,0 +1 @@ +{"decision":{"basis":"deterministic","bounded_scope":{"base_revision":"base","change_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","head_revision":"head","regions":[{"end_line":4,"path":"sources/complete.js","start_line":1}]},"family_code":"indeterminate","outcome":"indeterminate","packet_digest":"9d2e3db2b44ba56d5f017a5deab969abe8603aa9f3c6908d5412d2939432a235","provenance":{"lineage_manifest_digest":null,"model_declaration_digest":null,"model_identity":null,"model_result_digest":null,"proof_producer_digest":null,"proof_record_digest":null},"reasons":["missing_constraint_relation"]},"packet":{"completeness_reasons":["missing_constraint_relation"],"ecosystem":"express","family_contract_digest":"d3aea166bdad9186843b78ce1e3a6a4c135473f3d918ff580b096dbed61c787a","family_fields":[{"kind":"text","name":"operation","value":"entry-registration"},{"kind":"text","name":"boundary","value":"express"}],"family_id":"access_control","observations":[],"provenance":{"acquisition_record_digest":"f978265cdc2549cc1c5b2c757bb41934a467ddc9a042a10d1af67acd5bc6905a","analyzer_revision":"dc2816e78d1aca97801ab5a22fb316ae6c354a6e65260ade31ebcbbfa83f9fc0","change_input_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","configuration_digest":"3f167eebbd83522e30a8258e23a2b7bf3761880276a05965b0865c8f766b6214","fact_set_digest":"7438561f434fb5999d22aaccae44813d3d7c7cbff588a37cc497bb846c93bc75","family_contract_digest":"d3aea166bdad9186843b78ce1e3a6a4c135473f3d918ff580b096dbed61c787a","population_digest":"c03e2c11dd18a4a5ada83492740946ed9e1ff1201ded765e9e2c75d34a445fce"},"schema_version":"openultrasast.detection-core.evidence-packet.v2","scope":{"base_revision":"base","change_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","head_revision":"head","regions":[{"end_line":4,"path":"sources/complete.js","start_line":1}]},"security_object_id":"33bf0ef7a2efd0c79d89da501e49fe2f44a57931a0252bd95783bf9237256b6a","transitions":[{"conditions":[],"kind":"registration","location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"provenance":{"fact_match":{"artifact_id":"fact-match:db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","byte_length":3037,"content_digest":"db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"cd74cb0a824a618a2ae3f822e9988bb5703fdafc41e41e88bf941b71a31fd602"},"kind":"semantic_fact","semantic_fact_id":"entry:express:app-route:get","semantic_pack_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","source_content_digest":"db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3"},"reasons":[],"relation_id":"89785eb0e81e26cab8dbdb8c029290d46f47cae9454f21cf07f6a8157d279f8c","role":"entry_registration","source":{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"node_id":"3dbe3056740381221072862da39a5d10c3502ee776445560efcd27c54091fe29","role":"framework_instance"},"status":"complete","target":{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"node_id":"f17ecafe6356afc2325229cc686f3953e3bcbf8d37d9c5a24cc300ff43829547","role":"entry_handler"}},{"conditions":[],"kind":"constraint_effect","location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"provenance":{"fact_match":null,"kind":"product_code","semantic_fact_id":null,"semantic_pack_digest":null,"source_content_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27"},"reasons":["missing_constraint_relation"],"relation_id":"ac7cedfbee67ec3f24eefa0fe0cc88076367eb70873345f37f1b3f1ceb30712a","role":"constraint","source":{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"node_id":"constraint-source","role":"security_object"},"status":"incomplete","target":{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"node_id":"constraint-target","role":"operation"}}]},"schema_version":"openultrasast.detection-core.evidence-record.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/4b657ac957f89e41f34c179e7519cba950f92c09b6410fbf713a16ec06eff43f b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/4b657ac957f89e41f34c179e7519cba950f92c09b6410fbf713a16ec06eff43f new file mode 100644 index 0000000..700df37 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/4b657ac957f89e41f34c179e7519cba950f92c09b6410fbf713a16ec06eff43f @@ -0,0 +1 @@ +{"location":{"column":0,"line":3,"path":"sources/partial.js","symbol":"app.get"},"observed":"app.get","requirement_id":"qualified_target","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22 new file mode 100644 index 0000000..a85f91d --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22 @@ -0,0 +1 @@ +{"case_plans":[{"case_id":"authority_substitution","mutation":"match_pack_digest_substitution","replay_kind":"core","validator":"openultrasast.core.factmatch.validate_fact_match"},{"case_id":"complete","mutation":"none","replay_kind":"core","validator":"all"},{"case_id":"custody_contamination","mutation":"contaminated_custody","replay_kind":"core","validator":"openultrasast.core.factmatch.validate_fact_match"},{"case_id":"deterministic_replay","mutation":"none","replay_kind":"core","validator":"openultrasast.core.factmatch.validate_fact_match"},{"case_id":"legacy_projection_only","mutation":"qualified_name_only","replay_kind":"core","validator":"openultrasast.core.factmatch.validate_fact_match"},{"case_id":"lineage_omission","mutation":"matcher_lineage_omission","replay_kind":"core","validator":"openultrasast.core.factmatch.validate_fact_match"},{"case_id":"name_only","mutation":"qualified_name_only","replay_kind":"core","validator":"openultrasast.core.factmatch.validate_fact_match"},{"case_id":"partial","mutation":"arguments_omission","replay_kind":"core","validator":"openultrasast.core.factmatch.validate_fact_match"},{"case_id":"producer_reviewer_conflict","mutation":"self_authored_pack","replay_kind":"core","validator":"openultrasast.core.factpack.validate_fact_pack"},{"case_id":"resolver_byte_substitution","mutation":"resolver_byte_substitution","replay_kind":"core","validator":"openultrasast.core.factmatch.validate_fact_match"}],"contaminated_custody_log":{"custodian_identity":"4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632","head_receipt_digest":"0a3fefa700b1d5a144f83ba6e1f0933d87fd07ab628002a699008fd2fb4254fd","log_digest":"d483524c38005e5fb97a22009ee4b7ffe6579cea9d7f9334fecf831816c452f2","population_digest":"c03e2c11dd18a4a5ada83492740946ed9e1ff1201ded765e9e2c75d34a445fce","receipt_count":1,"receipts":[{"custodian_identity":"4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632","population_digest":"c03e2c11dd18a4a5ada83492740946ed9e1ff1201ded765e9e2c75d34a445fce","predecessor_digest":null,"prior_status":"available","reasons":["labels_accessed"],"receipt_digest":"0a3fefa700b1d5a144f83ba6e1f0933d87fd07ab628002a699008fd2fb4254fd","request":{"arm_id":"installed-entry-structural-matcher","expected_log_digest":"1e6a5a7ad68243a13c5148b34b4aa71a7415f653b2b9255a5c3e867ca6263fb4","influenced_artifact_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","labels_accessed":true,"population_digest":"c03e2c11dd18a4a5ada83492740946ed9e1ff1201ded765e9e2c75d34a445fce","purpose":"matching_behavior"},"request_digest":"48e17fb7026b5de0870ac2a8eae1dec6d66b173453caaebeb3d7c9e6def025d0","sequence":1,"status":"spent"}],"status":"spent"},"contract":{"decisions":[{"allowed_statuses":["complete"],"family_code":"unguarded","outcome":"violation","required_roles":["operation","constraint","security_object"]},{"allowed_statuses":["complete"],"family_code":"discharged","outcome":"satisfied","required_roles":["operation","constraint","security_object"]},{"allowed_statuses":["incomplete","unresolved"],"family_code":"indeterminate","outcome":"indeterminate","required_roles":["constraint"]}],"ecosystems":["express"],"family_id":"access_control","family_version":"2.0.0","indeterminate_reasons":["missing_constraint_relation","ambiguous_constraint_relation"],"residual_questions":[{"allowed_decisions":["unguarded","discharged","indeterminate"],"question_id":"is_path_authorized","required_roles":["operation","constraint","security_object"]}],"roles":[{"allowed_relation_kinds":["operation_effect"],"fields":[],"origin_policy":"product_or_reviewed_fact","role":"operation"},{"allowed_relation_kinds":["constraint_effect"],"fields":[],"origin_policy":"product_or_reviewed_fact","role":"constraint"},{"allowed_relation_kinds":[],"fields":[{"kind":"text","name":"operation","required":true},{"kind":"text","name":"boundary","required":true}],"origin_policy":"product_or_reviewed_fact","role":"security_object"},{"allowed_relation_kinds":["registration"],"fields":[],"origin_policy":"product_or_reviewed_fact","role":"framework_factory"},{"allowed_relation_kinds":["registration"],"fields":[],"origin_policy":"product_or_reviewed_fact","role":"framework_instance"},{"allowed_relation_kinds":["invocation"],"fields":[],"origin_policy":"product_or_reviewed_fact","role":"entry_handler"},{"allowed_relation_kinds":["registration"],"fields":[],"origin_policy":"product_or_reviewed_fact","role":"entry_registration"}],"schema_version":"openultrasast.detection-core.evidence-packet.v2","security_object":{"fields":[{"kind":"text","name":"operation","required":true},{"kind":"text","name":"boundary","required":true}],"identity_fields":["operation","boundary"],"kind":"entry_operation_authorization"}},"custody_logs":[{"custodian_identity":"4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632","head_receipt_digest":"a602c8bccc6afc2ff9d857119131a2847509bc693a80192bf8459b9dcba9cbda","log_digest":"7d3dd06940423c31a2f1472692ae26f8cfe2926644e3118b4dc6bb099941f240","population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce","receipt_count":3,"receipts":[{"custodian_identity":"4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632","population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce","predecessor_digest":null,"prior_status":"available","reasons":[],"receipt_digest":"36ccebd06b60601775ab24a2f7ec9f2b49c2eac6b273816eaf9e867f6c445915","request":{"arm_id":"installed-entry-facts:javascript","expected_log_digest":"055bdc33c465e1d8967b88acf05c8795c3e7ec2baccd66d601c29dc926b845df","influenced_artifact_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","labels_accessed":false,"population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce","purpose":"semantic_fact"},"request_digest":"f90508348a07ab6d62f34b52465d9575ffab80f0a1f33ee106f22f357ecb6c1a","sequence":1,"status":"available"},{"custodian_identity":"4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632","population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce","predecessor_digest":"36ccebd06b60601775ab24a2f7ec9f2b49c2eac6b273816eaf9e867f6c445915","prior_status":"available","reasons":[],"receipt_digest":"7dc5fe36b1e111ab6cf979137c40bf67b885b2a9deda944aff78e3031cb5a553","request":{"arm_id":"installed-entry-facts:typescript","expected_log_digest":"42335e347a68b81f29a3d63c034c992dad5aa0da696a3414a3a370d6c1b51040","influenced_artifact_digest":"b6d1157e99537bd4928303ec0d887628bc53f0aa9e770427580a32e3948babd9","labels_accessed":false,"population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce","purpose":"semantic_fact"},"request_digest":"795926623e6b500b34cc27d00db1f6f47e92e717e68bc6717323462708c11aa0","sequence":2,"status":"available"},{"custodian_identity":"4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632","population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce","predecessor_digest":"7dc5fe36b1e111ab6cf979137c40bf67b885b2a9deda944aff78e3031cb5a553","prior_status":"available","reasons":[],"receipt_digest":"a602c8bccc6afc2ff9d857119131a2847509bc693a80192bf8459b9dcba9cbda","request":{"arm_id":"installed-entry-structural-matcher","expected_log_digest":"d46f36b180e8bc263eb85513f448b42e763f5812afd1da69310a54888a5acf9a","influenced_artifact_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","labels_accessed":false,"population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce","purpose":"matching_behavior"},"request_digest":"aec99ff7956b51a5161565739e55cad39536e18550976ca1fb1ca5e924842255","sequence":3,"status":"available"}],"status":"available"},{"custodian_identity":"4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632","head_receipt_digest":null,"log_digest":"1e6a5a7ad68243a13c5148b34b4aa71a7415f653b2b9255a5c3e867ca6263fb4","population_digest":"c03e2c11dd18a4a5ada83492740946ed9e1ff1201ded765e9e2c75d34a445fce","receipt_count":0,"receipts":[],"status":"available"}],"custody_policy":{"policy_digest":"415b1c13adc918c162932a38e79548a7d9867f5331860eb409238c51b1cca1f0","reviewed_custodian_digests":["4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632"]},"envelope_digest":"60e0620731a03ffc83e5e813eb86cabad63ee45e4a50ab2dab554f0170bb4d34","evaluation_population_digest":"c03e2c11dd18a4a5ada83492740946ed9e1ff1201ded765e9e2c75d34a445fce","evidence_record":{"decision":{"basis":"deterministic","bounded_scope":{"base_revision":"base","change_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","head_revision":"head","regions":[{"end_line":4,"path":"sources/complete.js","start_line":1}]},"family_code":"indeterminate","outcome":"indeterminate","packet_digest":"9d2e3db2b44ba56d5f017a5deab969abe8603aa9f3c6908d5412d2939432a235","provenance":{"lineage_manifest_digest":null,"model_declaration_digest":null,"model_identity":null,"model_result_digest":null,"proof_producer_digest":null,"proof_record_digest":null},"reasons":["missing_constraint_relation"]},"packet":{"completeness_reasons":["missing_constraint_relation"],"ecosystem":"express","family_contract_digest":"d3aea166bdad9186843b78ce1e3a6a4c135473f3d918ff580b096dbed61c787a","family_fields":[{"kind":"text","name":"operation","value":"entry-registration"},{"kind":"text","name":"boundary","value":"express"}],"family_id":"access_control","observations":[],"provenance":{"acquisition_record_digest":"f978265cdc2549cc1c5b2c757bb41934a467ddc9a042a10d1af67acd5bc6905a","analyzer_revision":"dc2816e78d1aca97801ab5a22fb316ae6c354a6e65260ade31ebcbbfa83f9fc0","change_input_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","configuration_digest":"3f167eebbd83522e30a8258e23a2b7bf3761880276a05965b0865c8f766b6214","fact_set_digest":"7438561f434fb5999d22aaccae44813d3d7c7cbff588a37cc497bb846c93bc75","family_contract_digest":"d3aea166bdad9186843b78ce1e3a6a4c135473f3d918ff580b096dbed61c787a","population_digest":"c03e2c11dd18a4a5ada83492740946ed9e1ff1201ded765e9e2c75d34a445fce"},"schema_version":"openultrasast.detection-core.evidence-packet.v2","scope":{"base_revision":"base","change_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","head_revision":"head","regions":[{"end_line":4,"path":"sources/complete.js","start_line":1}]},"security_object_id":"33bf0ef7a2efd0c79d89da501e49fe2f44a57931a0252bd95783bf9237256b6a","transitions":[{"conditions":[],"kind":"registration","location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"provenance":{"fact_match":{"artifact_id":"fact-match:db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","byte_length":3037,"content_digest":"db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"cd74cb0a824a618a2ae3f822e9988bb5703fdafc41e41e88bf941b71a31fd602"},"kind":"semantic_fact","semantic_fact_id":"entry:express:app-route:get","semantic_pack_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","source_content_digest":"db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3"},"reasons":[],"relation_id":"89785eb0e81e26cab8dbdb8c029290d46f47cae9454f21cf07f6a8157d279f8c","role":"entry_registration","source":{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"node_id":"3dbe3056740381221072862da39a5d10c3502ee776445560efcd27c54091fe29","role":"framework_instance"},"status":"complete","target":{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"node_id":"f17ecafe6356afc2325229cc686f3953e3bcbf8d37d9c5a24cc300ff43829547","role":"entry_handler"}},{"conditions":[],"kind":"constraint_effect","location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"provenance":{"fact_match":null,"kind":"product_code","semantic_fact_id":null,"semantic_pack_digest":null,"source_content_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27"},"reasons":["missing_constraint_relation"],"relation_id":"ac7cedfbee67ec3f24eefa0fe0cc88076367eb70873345f37f1b3f1ceb30712a","role":"constraint","source":{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"node_id":"constraint-source","role":"security_object"},"status":"incomplete","target":{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"node_id":"constraint-target","role":"operation"}}]},"record_id":"4a46c6164bc28bf737ed6109d53f18ddc78efcc7a25c2417e38ff4600461bc9b"},"fact_id":"entry:express:app-route:get","lineages":[{"arm_id":"installed-entry-facts:javascript","manifest_digest":"f3b4b192dadd6b7d0d298286008480dadfd8640e9603020b0f24d13dce9bda04","subject_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","uses":[{"influenced_artifact_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","labels_accessed":false,"population_use_receipt_digest":"36ccebd06b60601775ab24a2f7ec9f2b49c2eac6b273816eaf9e867f6c445915","purpose":"semantic_fact","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]},{"arm_id":"installed-entry-facts:typescript","manifest_digest":"b7a6a95ddcdd8f6e6dbcd2b90cb707eda9833ec7479cb4d7aae3c91cfe0059ca","subject_digest":"b6d1157e99537bd4928303ec0d887628bc53f0aa9e770427580a32e3948babd9","uses":[{"influenced_artifact_digest":"b6d1157e99537bd4928303ec0d887628bc53f0aa9e770427580a32e3948babd9","labels_accessed":false,"population_use_receipt_digest":"7dc5fe36b1e111ab6cf979137c40bf67b885b2a9deda944aff78e3031cb5a553","purpose":"semantic_fact","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]},{"arm_id":"installed-entry-structural-matcher","manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","subject_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","uses":[{"influenced_artifact_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","labels_accessed":false,"population_use_receipt_digest":"a602c8bccc6afc2ff9d857119131a2847509bc693a80192bf8459b9dcba9cbda","purpose":"matching_behavior","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]}],"match":{"fact_id":"entry:express:app-route:get","match_digest":"db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","matcher_behavior_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","matcher_lineage_manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","matcher_revision":"entry-structural-matcher-v1","observations":[{"evidence":{"artifact_id":"structural-observation:02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9","byte_length":251,"content_digest":"02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"993681396623b12e3d9b6060c056b60c86e3027554ebe6eb403c6ec9ccb28142"},"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"app.get","requirement_id":"qualified_target"},{"evidence":{"artifact_id":"structural-observation:fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831","byte_length":249,"content_digest":"fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"7af07572d53abac371dbc1c5970ad5324ab23f1ef5744eeab7e3621b9f2c3f59"},"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"member_call","requirement_id":"call_shape"},{"evidence":{"artifact_id":"structural-observation:6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12","byte_length":255,"content_digest":"6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"a7ab3b129c07dedd077d877a3bc189b86f2da852a2b340c3496c1b729465002d"},"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"express_application","requirement_id":"receiver"},{"evidence":{"artifact_id":"structural-observation:88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370","byte_length":259,"content_digest":"88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"c2eec061e981fccdea378bf097a53b75de44916cd1bc908d899345cc30229bd5"},"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"route_path_and_handler","requirement_id":"arguments"}],"pack_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","product_location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"}},"match_reference":{"artifact_id":"fact-match:db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","byte_length":3037,"content_digest":"db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"cd74cb0a824a618a2ae3f822e9988bb5703fdafc41e41e88bf941b71a31fd602"},"pack":{"ecosystem":"express","facts":[{"fact_id":"entry:express:app-route:get","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.get","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:post","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.post","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:put","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.put","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:delete","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.delete","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:patch","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.patch","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:all","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.all","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:use","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.use","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:get","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.get","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:post","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.post","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:put","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.put","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:delete","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.delete","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:patch","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.patch","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:all","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.all","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:use","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.use","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:express-app","relation_effects":[{"conditions":[],"kind":"registration","role":"framework_instance","source_role":"framework_factory","target_role":"framework_instance"}],"role":"framework_instance","structural_requirements":[{"expected":"express","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"factory_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"application_instance_binding","field":"binding","kind":"argument_shape","requirement_id":"binding"}]}],"family_contract_digest":"d3aea166bdad9186843b78ce1e3a6a4c135473f3d918ff580b096dbed61c787a","family_id":"access_control","language":"javascript","normalized_content_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","review_evidence":[{"content":{"artifact_id":"reviewed-express-entry-data-2026-10-30","byte_length":963,"content_digest":"e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"3c675f58c7b62f41a4e123886287f60c8977fdfd6b85f3d8f4e85a1d9bfa8094"},"independence":{"attestation_digest":"9005a1b96ec40a2f0a61e2e1a74bd92a3d971d4b2555e3c88a17e5cf80381ff0","conflict_disclosure":{"artifact_id":"installed-entry-authority-conflicts-v1","byte_length":113,"content_digest":"a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"ee92fde020e9b4d316ad285f3f904032c52d902fe1c7c0a94cb0d61d9c0136ce"},"producer_identity":"9635025424be37e1615e597185a425a5443242fa210d6136c38250101088e7b4","reviewer_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43","subject_digest":"e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce"},"kind":"independent_behavior","lineage_manifest_digest":"f3b4b192dadd6b7d0d298286008480dadfd8640e9603020b0f24d13dce9bda04","producer_identity":"9635025424be37e1615e597185a425a5443242fa210d6136c38250101088e7b4","reviewer_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43"}],"review_evidence_digest":"2ab72937b003169d9061e16e4d35444d4653e1c587fbf95faaa8a085efbb1553","review_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43","review_policy_digest":"cb023a4f7e727ec4abfee583256194fe3f11c064a10960f297c1f7bf2e6fecde","schema_version":"openultrasast.detection-core.fact-pack.v2"},"resolver_entries":[{"path":"artifacts/sha256/e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce","reference":{"artifact_id":"reviewed-express-entry-data-2026-10-30","byte_length":963,"content_digest":"e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"3c675f58c7b62f41a4e123886287f60c8977fdfd6b85f3d8f4e85a1d9bfa8094"},"store_identity":"openultrasast-installed-entry-artifacts-v1"},{"path":"artifacts/sha256/a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1","reference":{"artifact_id":"installed-entry-authority-conflicts-v1","byte_length":113,"content_digest":"a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"ee92fde020e9b4d316ad285f3f904032c52d902fe1c7c0a94cb0d61d9c0136ce"},"store_identity":"openultrasast-installed-entry-artifacts-v1"},{"path":"artifacts/sha256/02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9","reference":{"artifact_id":"structural-observation:02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9","byte_length":251,"content_digest":"02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"993681396623b12e3d9b6060c056b60c86e3027554ebe6eb403c6ec9ccb28142"},"store_identity":"openultrasast-installed-entry-artifacts-v1"},{"path":"artifacts/sha256/fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831","reference":{"artifact_id":"structural-observation:fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831","byte_length":249,"content_digest":"fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"7af07572d53abac371dbc1c5970ad5324ab23f1ef5744eeab7e3621b9f2c3f59"},"store_identity":"openultrasast-installed-entry-artifacts-v1"},{"path":"artifacts/sha256/6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12","reference":{"artifact_id":"structural-observation:6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12","byte_length":255,"content_digest":"6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"a7ab3b129c07dedd077d877a3bc189b86f2da852a2b340c3496c1b729465002d"},"store_identity":"openultrasast-installed-entry-artifacts-v1"},{"path":"artifacts/sha256/88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370","reference":{"artifact_id":"structural-observation:88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370","byte_length":259,"content_digest":"88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"c2eec061e981fccdea378bf097a53b75de44916cd1bc908d899345cc30229bd5"},"store_identity":"openultrasast-installed-entry-artifacts-v1"},{"path":"artifacts/sha256/db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","reference":{"artifact_id":"fact-match:db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","byte_length":3037,"content_digest":"db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"cd74cb0a824a618a2ae3f822e9988bb5703fdafc41e41e88bf941b71a31fd602"},"store_identity":"openultrasast-installed-entry-artifacts-v1"}],"review_policy":{"forbidden_identity_pairs":[],"maximum_evidence_bytes":1048576,"policy_digest":"cb023a4f7e727ec4abfee583256194fe3f11c064a10960f297c1f7bf2e6fecde","reviewed_reviewer_digests":["f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43"],"trusted_store_identities":["openultrasast-installed-entry-artifacts-v1"]},"schema_version":"openultrasast.access-control.entry-fact-core-replay.v1","substituted_content_path":"artifacts/sha256/dfad0338dfda8dc13feeb699ed359553c7b761dbbff151b815cde6a572c6cc88"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/60fe67b0d61dbfcedf97ce1470219bdb7b8cc5590c04d90401fede5bcd6e9064 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/60fe67b0d61dbfcedf97ce1470219bdb7b8cc5590c04d90401fede5bcd6e9064 new file mode 100644 index 0000000..b865b6d --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/60fe67b0d61dbfcedf97ce1470219bdb7b8cc5590c04d90401fede5bcd6e9064 @@ -0,0 +1 @@ +{"location":{"column":0,"line":1,"path":"sources/name-only.js","symbol":"app.get->adminHandler@sources/name-only.js:2:9"},"observed":"member_call","requirement_id":"call_shape","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/615552917e474d463b8af6323c7aaa9cbd24b759b42bbf53af3805ec9be0149d b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/615552917e474d463b8af6323c7aaa9cbd24b759b42bbf53af3805ec9be0149d new file mode 100644 index 0000000..4d58dd0 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/615552917e474d463b8af6323c7aaa9cbd24b759b42bbf53af3805ec9be0149d @@ -0,0 +1 @@ +{"authority_review":{"attestation_digest":"aeeb9120c10d8bf83159a9cbd14ad8a070a0ceb99a53b5a1daa616a315c84b55","conflict_disclosure":{"artifact_id":"installed-entry-authority-conflicts-v1","byte_length":113,"content_digest":"a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"ee92fde020e9b4d316ad285f3f904032c52d902fe1c7c0a94cb0d61d9c0136ce"},"producer_identity":"9635025424be37e1615e597185a425a5443242fa210d6136c38250101088e7b4","reviewer_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43","subject_digest":"0fa8f607297aa5364a0ca6c9b8d47bfcdef28456b7f062ddb251f8f8b9a67da4"},"bundle_digest":"0000000000000000000000000000000000000000000000000000000000000000","custody_policy":{"policy_digest":"415b1c13adc918c162932a38e79548a7d9867f5331860eb409238c51b1cca1f0","reviewed_custodian_digests":["4fe8ca2923ee759a24fd8e5b91673faa6859a7a0c2df6e7c7ea5e23968708632"]},"lineages":[{"arm_id":"installed-entry-facts:javascript","manifest_digest":"f3b4b192dadd6b7d0d298286008480dadfd8640e9603020b0f24d13dce9bda04","subject_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","uses":[{"influenced_artifact_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","labels_accessed":false,"population_use_receipt_digest":"36ccebd06b60601775ab24a2f7ec9f2b49c2eac6b273816eaf9e867f6c445915","purpose":"semantic_fact","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]},{"arm_id":"installed-entry-facts:typescript","manifest_digest":"b7a6a95ddcdd8f6e6dbcd2b90cb707eda9833ec7479cb4d7aae3c91cfe0059ca","subject_digest":"b6d1157e99537bd4928303ec0d887628bc53f0aa9e770427580a32e3948babd9","uses":[{"influenced_artifact_digest":"b6d1157e99537bd4928303ec0d887628bc53f0aa9e770427580a32e3948babd9","labels_accessed":false,"population_use_receipt_digest":"7dc5fe36b1e111ab6cf979137c40bf67b885b2a9deda944aff78e3031cb5a553","purpose":"semantic_fact","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]},{"arm_id":"installed-entry-structural-matcher","manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","subject_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","uses":[{"influenced_artifact_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","labels_accessed":false,"population_use_receipt_digest":"a602c8bccc6afc2ff9d857119131a2847509bc693a80192bf8459b9dcba9cbda","purpose":"matching_behavior","source_population_digest":"0ec4bbe3712a691a76f6525aca59f15d0492adc1e7ec8d7e9bb42e8ee42795ce"}]}],"matcher_behavior_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","matcher_lineage_manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","matcher_revision":"entry-structural-matcher-v1","pack_files":["express.javascript.v2.json","express.typescript.v2.json"],"recognition_projection":{"artifact_id":"express-recognition-projection-v1","byte_length":628,"content_digest":"529d18ba2b351a8de985a9cf416261d717ef55a4b7a9d9d65bce53b97d59ab35","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"3a85c0641cddcfc8c926fd01e230360c042606bda78e14a39489de14f88944b4"},"review_policy":{"forbidden_identity_pairs":[],"maximum_evidence_bytes":1048576,"policy_digest":"cb023a4f7e727ec4abfee583256194fe3f11c064a10960f297c1f7bf2e6fecde","reviewed_reviewer_digests":["f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43"],"trusted_store_identities":["openultrasast-installed-entry-artifacts-v1"]},"schema_version":"openultrasast.access-control.installed-entry-authority.v1"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12 new file mode 100644 index 0000000..e78356c --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12 @@ -0,0 +1 @@ +{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"express_application","requirement_id":"receiver","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf new file mode 100644 index 0000000..43868ee --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf @@ -0,0 +1 @@ +{"ecosystem":"express","facts":[{"fact_id":"entry:express:app-route:get","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.get","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:post","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.post","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:put","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.put","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:delete","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.delete","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:patch","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.patch","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:all","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.all","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:app-route:use","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"app.use","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_application","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:get","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.get","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:post","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.post","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:put","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.put","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:delete","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.delete","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:patch","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.patch","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:all","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.all","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:router-route:use","relation_effects":[{"conditions":[],"kind":"registration","role":"entry_registration","source_role":"framework_instance","target_role":"entry_handler"}],"role":"entry_registration","structural_requirements":[{"expected":"router.use","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"member_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"express_router","field":"receiver","kind":"receiver_type","requirement_id":"receiver"},{"expected":"route_path_and_handler","field":"arguments","kind":"argument_shape","requirement_id":"arguments"}]},{"fact_id":"entry:express:express-app","relation_effects":[{"conditions":[],"kind":"registration","role":"framework_instance","source_role":"framework_factory","target_role":"framework_instance"}],"role":"framework_instance","structural_requirements":[{"expected":"express","field":"qualified_target","kind":"qualified_name","requirement_id":"qualified_target"},{"expected":"factory_call","field":"call_shape","kind":"ast_shape","requirement_id":"call_shape"},{"expected":"application_instance_binding","field":"binding","kind":"argument_shape","requirement_id":"binding"}]}],"family_contract_digest":"d3aea166bdad9186843b78ce1e3a6a4c135473f3d918ff580b096dbed61c787a","family_id":"access_control","language":"javascript","normalized_content_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","review_evidence":[{"content":{"artifact_id":"reviewed-express-entry-data-2026-10-30","byte_length":963,"content_digest":"e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"3c675f58c7b62f41a4e123886287f60c8977fdfd6b85f3d8f4e85a1d9bfa8094"},"independence":{"attestation_digest":"9005a1b96ec40a2f0a61e2e1a74bd92a3d971d4b2555e3c88a17e5cf80381ff0","conflict_disclosure":{"artifact_id":"installed-entry-authority-conflicts-v1","byte_length":113,"content_digest":"a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1","media_type":"application/json","retention_policy_digest":"09a0fe8a253780b3666ef016d575a212bf0570da392dd5bf1a834dce2edf703f","storage_receipt_digest":"ee92fde020e9b4d316ad285f3f904032c52d902fe1c7c0a94cb0d61d9c0136ce"},"producer_identity":"9635025424be37e1615e597185a425a5443242fa210d6136c38250101088e7b4","reviewer_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43","subject_digest":"e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce"},"kind":"independent_behavior","lineage_manifest_digest":"f3b4b192dadd6b7d0d298286008480dadfd8640e9603020b0f24d13dce9bda04","producer_identity":"9635025424be37e1615e597185a425a5443242fa210d6136c38250101088e7b4","reviewer_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43"}],"review_evidence_digest":"2ab72937b003169d9061e16e4d35444d4653e1c587fbf95faaa8a085efbb1553","review_identity":"f12a7e897cbaf3059619517e1f8a725b90049a0edf3af08efa12fb1ef7fdee43","review_policy_digest":"cb023a4f7e727ec4abfee583256194fe3f11c064a10960f297c1f7bf2e6fecde","schema_version":"openultrasast.detection-core.fact-pack.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/752f84618a299286bd5a9fdd1513dc40c05b6649a2ff0a81b23175001560d490 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/752f84618a299286bd5a9fdd1513dc40c05b6649a2ff0a81b23175001560d490 new file mode 100644 index 0000000..efdc1a4 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/752f84618a299286bd5a9fdd1513dc40c05b6649a2ff0a81b23175001560d490 @@ -0,0 +1 @@ +{"location":{"column":0,"line":3,"path":"sources/partial.js","symbol":"app.get"},"observed":"member_call","requirement_id":"call_shape","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370 new file mode 100644 index 0000000..12e556a --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370 @@ -0,0 +1 @@ +{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"route_path_and_handler","requirement_id":"arguments","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/a1c31def035a5c45d4c49f77816815570d9874d781ac06c5f33b9c75166fb7b4 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/a1c31def035a5c45d4c49f77816815570d9874d781ac06c5f33b9c75166fb7b4 new file mode 100644 index 0000000..f982de0 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/a1c31def035a5c45d4c49f77816815570d9874d781ac06c5f33b9c75166fb7b4 @@ -0,0 +1 @@ +{"fact_id":"entry:express:app-route:get","matcher_behavior_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","matcher_lineage_manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","matcher_revision":"entry-structural-matcher-v1","observations":[{"evidence":{"artifact_id":"structural-observation:4b657ac957f89e41f34c179e7519cba950f92c09b6410fbf713a16ec06eff43f","byte_length":212,"content_digest":"4b657ac957f89e41f34c179e7519cba950f92c09b6410fbf713a16ec06eff43f","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"e2c2971b375d018688a4aa7e1d86907d732a6eaac6649f397b92ec6896ddd3ea"},"location":{"column":0,"line":3,"path":"sources/partial.js","symbol":"app.get"},"observed":"app.get","requirement_id":"qualified_target"},{"evidence":{"artifact_id":"structural-observation:752f84618a299286bd5a9fdd1513dc40c05b6649a2ff0a81b23175001560d490","byte_length":210,"content_digest":"752f84618a299286bd5a9fdd1513dc40c05b6649a2ff0a81b23175001560d490","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"3b5f35240b90c610f28d093ad4ce49908e3650335d41ae7ae7e1b02c3eafe415"},"location":{"column":0,"line":3,"path":"sources/partial.js","symbol":"app.get"},"observed":"member_call","requirement_id":"call_shape"},{"evidence":{"artifact_id":"structural-observation:0acf81eaebbf1c67bef9d93fe7aaf061c85494cd124d1338727c230ba91cc4bd","byte_length":216,"content_digest":"0acf81eaebbf1c67bef9d93fe7aaf061c85494cd124d1338727c230ba91cc4bd","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"c1ab8ae696194ecf29c8af32cbd1f8649eceff8ab5106cae75881994a06e843e"},"location":{"column":0,"line":3,"path":"sources/partial.js","symbol":"app.get"},"observed":"express_application","requirement_id":"receiver"}],"pack_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","product_location":{"column":0,"line":3,"path":"sources/partial.js","symbol":"app.get"},"schema_version":"openultrasast.detection-core.fact-match.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1 new file mode 100644 index 0000000..08b02ab --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1 @@ -0,0 +1 @@ +{"conflicts":[],"resolved":true,"schema_version":"openultrasast.access-control.authority-conflict-disclosure.v1"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/aba7fbac17cbc9095715999b1584daa07cf20552ea17c0b71948890aa88e9ece b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/aba7fbac17cbc9095715999b1584daa07cf20552ea17c0b71948890aa88e9ece new file mode 100644 index 0000000..62be32a --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/aba7fbac17cbc9095715999b1584daa07cf20552ea17c0b71948890aa88e9ece @@ -0,0 +1 @@ +{"location":{"column":0,"line":1,"path":"sources/name-only.js","symbol":"app.get->adminHandler@sources/name-only.js:2:9"},"observed":"route_path_and_handler","requirement_id":"arguments","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3 new file mode 100644 index 0000000..4843146 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3 @@ -0,0 +1 @@ +{"fact_id":"entry:express:app-route:get","matcher_behavior_digest":"0ad18521beeb3708e12f8c9941b3f29b3e1312fe78b9320e5aaf15bc9db8831a","matcher_lineage_manifest_digest":"5f7ffd58a773b61d1f8e2ba0ca019e27d778166e13cec770e6f25c16b1f1a994","matcher_revision":"entry-structural-matcher-v1","observations":[{"evidence":{"artifact_id":"structural-observation:02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9","byte_length":251,"content_digest":"02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"993681396623b12e3d9b6060c056b60c86e3027554ebe6eb403c6ec9ccb28142"},"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"app.get","requirement_id":"qualified_target"},{"evidence":{"artifact_id":"structural-observation:fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831","byte_length":249,"content_digest":"fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"7af07572d53abac371dbc1c5970ad5324ab23f1ef5744eeab7e3621b9f2c3f59"},"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"member_call","requirement_id":"call_shape"},{"evidence":{"artifact_id":"structural-observation:6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12","byte_length":255,"content_digest":"6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"a7ab3b129c07dedd077d877a3bc189b86f2da852a2b340c3496c1b729465002d"},"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"express_application","requirement_id":"receiver"},{"evidence":{"artifact_id":"structural-observation:88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370","byte_length":259,"content_digest":"88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370","media_type":"application/json","retention_policy_digest":"445c538acfffe5dde50f57bc699da2732e237207f0953c59dd8559f66c1a6708","storage_receipt_digest":"c2eec061e981fccdea378bf097a53b75de44916cd1bc908d899345cc30229bd5"},"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"route_path_and_handler","requirement_id":"arguments"}],"pack_digest":"331e8c2261cb030f4257a8650448560eb94941554df47cb275882e24b8f8923f","product_location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"schema_version":"openultrasast.detection-core.fact-match.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/dfad0338dfda8dc13feeb699ed359553c7b761dbbff151b815cde6a572c6cc88 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/dfad0338dfda8dc13feeb699ed359553c7b761dbbff151b815cde6a572c6cc88 new file mode 100644 index 0000000..79a3ade --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/dfad0338dfda8dc13feeb699ed359553c7b761dbbff151b815cde6a572c6cc88 @@ -0,0 +1 @@ +!"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"app.get","requirement_id":"qualified_target","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce new file mode 100644 index 0000000..6a5dad4 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce @@ -0,0 +1,33 @@ +{ + "facts": [ + { + "defines_handler": true, + "handler_kind": "route", + "id": "entry:express:app-route", + "pattern": "app.(get|post|put|delete|patch|all|use)\\s*\\(" + }, + { + "defines_handler": true, + "handler_kind": "route", + "id": "entry:express:router-route", + "pattern": "router.(get|post|put|delete|patch|all|use)\\s*\\(" + }, + { + "defines_handler": false, + "handler_kind": "app", + "id": "entry:express:express-app", + "pattern": "express\\s*\\(\\s*\\)" + } + ], + "family": "access_control", + "framework": "express", + "kind": "entry_facts", + "languages": [ + "javascript", + "typescript" + ], + "review": { + "digest": "47866e5c15b286d7107b101bd396f78bbbda23788085676c590c3af937085e00", + "note": "Reviewed against Express 4/5 routing docs and the pilot pool's manifest-level framework usage (2026-10-30 recognition table). Entry patterns only; no sinks, no labels." + } +} diff --git a/tests/fixtures/access_control/conformance/v1/artifacts/sha256/fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831 b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831 new file mode 100644 index 0000000..599725b --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/artifacts/sha256/fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831 @@ -0,0 +1 @@ +{"location":{"column":0,"line":3,"path":"sources/complete.js","symbol":"app.get->adminHandler@sources/complete.js:4:9"},"observed":"member_call","requirement_id":"call_shape","schema_version":"openultrasast.detection-core.structural-observation.v2"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/manifest.json b/tests/fixtures/access_control/conformance/v1/manifest.json new file mode 100644 index 0000000..7a9e0c6 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/manifest.json @@ -0,0 +1 @@ +{"cases":[{"artifacts":[{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":3887,"content_digest":"615552917e474d463b8af6323c7aaa9cbd24b759b42bbf53af3805ec9be0149d","kind":"authority","path":"artifacts/sha256/615552917e474d463b8af6323c7aaa9cbd24b759b42bbf53af3805ec9be0149d"}],"case_id":"authority_substitution","downstream_validators":[{"name":"openultrasast.mapping.fact_authority.authenticate_entry_fact_authority","reason":"authority_bundle_digest_substituted","status":"refused"}],"expected_status":"refused","fixture_byte_length":144,"fixture_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","fixture_path":"sources/complete.js","reason":"match_pack_identity_substituted","validators":[{"name":"openultrasast.core.factmatch.validate_fact_match","reason":"match_pack_identity_substituted","status":"refused"}]},{"artifacts":[{"byte_length":251,"content_digest":"02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9","kind":"resolver-content","path":"artifacts/sha256/02b8aa4884cb356afa9ba7960fee55f5d9a15f0e4b73fbc3573d85622d0defa9"},{"byte_length":4421,"content_digest":"4a46c6164bc28bf737ed6109d53f18ddc78efcc7a25c2417e38ff4600461bc9b","kind":"evidence-record","path":"artifacts/sha256/4a46c6164bc28bf737ed6109d53f18ddc78efcc7a25c2417e38ff4600461bc9b"},{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":255,"content_digest":"6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12","kind":"resolver-content","path":"artifacts/sha256/6c750f6128bd698bb27dd6db5e1260995cac678261ce2734cbf048c7b33e9b12"},{"byte_length":12123,"content_digest":"749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf","kind":"fact-pack","path":"artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf"},{"byte_length":259,"content_digest":"88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370","kind":"resolver-content","path":"artifacts/sha256/88a8b08604bb7db69ccfc50af54701e4ab41044db5eb61cb812881a60e1b6370"},{"byte_length":113,"content_digest":"a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1","kind":"resolver-content","path":"artifacts/sha256/a8bf581d321560f2730aae3d5a7c9114c2d8f81f7a702fa3681a87e7be4cb9e1"},{"byte_length":3037,"content_digest":"db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3","kind":"resolver-content","path":"artifacts/sha256/db111c965603bb4cf9d83ba07b0e22a57a537ba6a05448158ef7d7615efb18d3"},{"byte_length":251,"content_digest":"dfad0338dfda8dc13feeb699ed359553c7b761dbbff151b815cde6a572c6cc88","kind":"substituted-content","path":"artifacts/sha256/dfad0338dfda8dc13feeb699ed359553c7b761dbbff151b815cde6a572c6cc88"},{"byte_length":963,"content_digest":"e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce","kind":"resolver-content","path":"artifacts/sha256/e8e149309abd78f24206c58fde7f73ae2f60364d8b8fee22ecaee8342798d8ce"},{"byte_length":249,"content_digest":"fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831","kind":"resolver-content","path":"artifacts/sha256/fc13dbdeea6d0909956de97eac4e2229a784e7cd76a51ab4fcc6db5151da6831"}],"case_id":"complete","downstream_validators":[],"expected_status":"passed","fixture_byte_length":144,"fixture_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","fixture_path":"sources/complete.js","reason":null,"validators":[{"name":"openultrasast.core.factapply.apply_fact","reason":null,"status":"passed"},{"name":"openultrasast.core.factmatch.validate_fact_match","reason":null,"status":"passed"},{"name":"openultrasast.core.factpack.validate_fact_pack","reason":null,"status":"passed"},{"name":"openultrasast.core.factvalidate.validate_fact_relations","reason":null,"status":"passed"}]},{"artifacts":[{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":12123,"content_digest":"749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf","kind":"fact-pack","path":"artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf"}],"case_id":"custody_contamination","downstream_validators":[],"expected_status":"refused","fixture_byte_length":144,"fixture_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","fixture_path":"sources/complete.js","reason":"protected_population_contamination","validators":[{"name":"openultrasast.core.factmatch.validate_fact_match","reason":"protected_population_contamination","status":"refused"}]},{"artifacts":[{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":12123,"content_digest":"749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf","kind":"fact-pack","path":"artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf"}],"case_id":"deterministic_replay","downstream_validators":[],"expected_status":"passed","fixture_byte_length":144,"fixture_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","fixture_path":"sources/complete.js","reason":null,"validators":[{"name":"openultrasast.core.factmatch.validate_fact_match","reason":null,"status":"passed"}]},{"artifacts":[{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":12123,"content_digest":"749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf","kind":"fact-pack","path":"artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf"}],"case_id":"legacy_projection_only","downstream_validators":[],"expected_status":"refused","fixture_byte_length":120,"fixture_digest":"76c0a1fe9713baa895f0787959a73960f52cb91620a8bc6c099f8bdb6532d127","fixture_path":"sources/legacy-only.js","reason":"name_only_match","validators":[{"name":"openultrasast.core.factmatch.validate_fact_match","reason":"name_only_match","status":"refused"}]},{"artifacts":[{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":12123,"content_digest":"749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf","kind":"fact-pack","path":"artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf"}],"case_id":"lineage_omission","downstream_validators":[],"expected_status":"refused","fixture_byte_length":144,"fixture_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","fixture_path":"sources/complete.js","reason":"matcher_lineage_omitted","validators":[{"name":"openultrasast.core.factmatch.validate_fact_match","reason":"matcher_lineage_omitted","status":"refused"}]},{"artifacts":[{"byte_length":253,"content_digest":"0494c5e2973965bbfc12cee1db3971cfa700a41d9b5e11309d45eb529837d556","kind":"match-evidence","path":"artifacts/sha256/0494c5e2973965bbfc12cee1db3971cfa700a41d9b5e11309d45eb529837d556"},{"byte_length":2427,"content_digest":"3edf94ff896c1e8fb1ae5b297d67117e4524a29870834190c13c3870f4d30aa6","kind":"match-evidence","path":"artifacts/sha256/3edf94ff896c1e8fb1ae5b297d67117e4524a29870834190c13c3870f4d30aa6"},{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":251,"content_digest":"60fe67b0d61dbfcedf97ce1470219bdb7b8cc5590c04d90401fede5bcd6e9064","kind":"match-evidence","path":"artifacts/sha256/60fe67b0d61dbfcedf97ce1470219bdb7b8cc5590c04d90401fede5bcd6e9064"},{"byte_length":12123,"content_digest":"749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf","kind":"fact-pack","path":"artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf"},{"byte_length":261,"content_digest":"aba7fbac17cbc9095715999b1584daa07cf20552ea17c0b71948890aa88e9ece","kind":"match-evidence","path":"artifacts/sha256/aba7fbac17cbc9095715999b1584daa07cf20552ea17c0b71948890aa88e9ece"}],"case_id":"name_only","downstream_validators":[],"expected_status":"refused","fixture_byte_length":90,"fixture_digest":"0e3f7e5073d386f06ba8d90a74c9029bed32e5c0bec50a678e5a77a7aad5e5e9","fixture_path":"sources/name-only.js","reason":"missing_observation:receiver","validators":[{"name":"openultrasast.core.factmatch.validate_fact_match","reason":"missing_observation:receiver","status":"refused"}]},{"artifacts":[{"byte_length":216,"content_digest":"0acf81eaebbf1c67bef9d93fe7aaf061c85494cd124d1338727c230ba91cc4bd","kind":"match-evidence","path":"artifacts/sha256/0acf81eaebbf1c67bef9d93fe7aaf061c85494cd124d1338727c230ba91cc4bd"},{"byte_length":212,"content_digest":"4b657ac957f89e41f34c179e7519cba950f92c09b6410fbf713a16ec06eff43f","kind":"match-evidence","path":"artifacts/sha256/4b657ac957f89e41f34c179e7519cba950f92c09b6410fbf713a16ec06eff43f"},{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":12123,"content_digest":"749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf","kind":"fact-pack","path":"artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf"},{"byte_length":210,"content_digest":"752f84618a299286bd5a9fdd1513dc40c05b6649a2ff0a81b23175001560d490","kind":"match-evidence","path":"artifacts/sha256/752f84618a299286bd5a9fdd1513dc40c05b6649a2ff0a81b23175001560d490"},{"byte_length":2259,"content_digest":"a1c31def035a5c45d4c49f77816815570d9874d781ac06c5f33b9c75166fb7b4","kind":"match-evidence","path":"artifacts/sha256/a1c31def035a5c45d4c49f77816815570d9874d781ac06c5f33b9c75166fb7b4"}],"case_id":"partial","downstream_validators":[],"expected_status":"refused","fixture_byte_length":73,"fixture_digest":"18067cdf4c3f7a1674c4ce45efed5ea9d50d1b3de7bdf5ce5522d19478f372c7","fixture_path":"sources/partial.js","reason":"missing_observation:arguments","validators":[{"name":"openultrasast.core.factmatch.validate_fact_match","reason":"missing_observation:arguments","status":"refused"}]},{"artifacts":[{"byte_length":3887,"content_digest":"1010797dff4ba19deb6e95640373984d4227f0a657b9d03f841634c17d095262","kind":"authority","path":"artifacts/sha256/1010797dff4ba19deb6e95640373984d4227f0a657b9d03f841634c17d095262"},{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"}],"case_id":"producer_reviewer_conflict","downstream_validators":[{"name":"openultrasast.mapping.fact_authority.authenticate_entry_fact_authority","reason":"producer_reviewer_conflict","status":"refused"}],"expected_status":"refused","fixture_byte_length":144,"fixture_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","fixture_path":"sources/complete.js","reason":"self_authored_review_evidence","validators":[{"name":"openultrasast.core.factpack.validate_fact_pack","reason":"self_authored_review_evidence","status":"refused"}]},{"artifacts":[{"byte_length":34917,"content_digest":"56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22","kind":"core-replay-envelope","path":"artifacts/sha256/56d8517c0bb2c8e9296a7fa096ebd1d0babfc0cd2491d966b7c2120a2e01ee22"},{"byte_length":12123,"content_digest":"749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf","kind":"fact-pack","path":"artifacts/sha256/749ff8b59bb778be1d8b2bf745f223c7c3b09cad2714696bbc65cfd332170bbf"}],"case_id":"resolver_byte_substitution","downstream_validators":[],"expected_status":"refused","fixture_byte_length":144,"fixture_digest":"531bb28a24082947325ef7b3108f5586a4e8187dbf094409be514d6510bb9f27","fixture_path":"sources/complete.js","reason":"resolver_byte_substitution","validators":[{"name":"openultrasast.core.factmatch.validate_fact_match","reason":"resolver_byte_substitution","status":"refused"}]}],"core_entry_points":["openultrasast.core.factapply.apply_fact","openultrasast.core.factmatch.validate_fact_match","openultrasast.core.factpack.validate_fact_pack","openultrasast.core.factvalidate.validate_fact_relations"],"handoff_digest":"9cea45880ff14f9475ec08233ddb5aed83f33419a3183abfc906202114eccf01","schema_version":"openultrasast.access-control.entry-fact-conformance.v1"} \ No newline at end of file diff --git a/tests/fixtures/access_control/conformance/v1/sources/complete.js b/tests/fixtures/access_control/conformance/v1/sources/complete.js new file mode 100644 index 0000000..cb71c3e --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/sources/complete.js @@ -0,0 +1,4 @@ +import express from "express"; +const app = express(); +app.get("/admin", adminHandler); +function adminHandler(req, res) { res.sendStatus(204); } diff --git a/tests/fixtures/access_control/conformance/v1/sources/legacy-only.js b/tests/fixtures/access_control/conformance/v1/sources/legacy-only.js new file mode 100644 index 0000000..56d2212 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/sources/legacy-only.js @@ -0,0 +1,2 @@ +// Legacy recognition text only: app.get("/admin", adminHandler) +export const marker = "not a structural registration"; diff --git a/tests/fixtures/access_control/conformance/v1/sources/name-only.js b/tests/fixtures/access_control/conformance/v1/sources/name-only.js new file mode 100644 index 0000000..f70c743 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/sources/name-only.js @@ -0,0 +1,2 @@ +app.get("/admin", adminHandler); +function adminHandler(req, res) { res.sendStatus(204); } diff --git a/tests/fixtures/access_control/conformance/v1/sources/partial.js b/tests/fixtures/access_control/conformance/v1/sources/partial.js new file mode 100644 index 0000000..eb87705 --- /dev/null +++ b/tests/fixtures/access_control/conformance/v1/sources/partial.js @@ -0,0 +1,3 @@ +import express from "express"; +const app = express(); +app.get("/admin"); diff --git a/tests/test_entry_fact_conformance.py b/tests/test_entry_fact_conformance.py new file mode 100644 index 0000000..61e0445 --- /dev/null +++ b/tests/test_entry_fact_conformance.py @@ -0,0 +1,377 @@ +"""Immutable downstream conformance handoff for detection-core Task 9.4.""" + +from __future__ import annotations + +import json +import os +import shutil +import subprocess +import sys +from pathlib import Path + +import pytest + +from openultrasast.core import canonical +from openultrasast.mapping.entry_fact_conformance import ( + ENTRY_FACT_CONFORMANCE_SCHEMA, + EntryFactConformanceError, + build_entry_fact_conformance, + write_entry_fact_conformance, +) +from openultrasast.mapping.entry_fact_conformance_manifest import validate_entry_fact_conformance + +FIXTURE_ROOT = Path(__file__).parent / "fixtures" / "access_control" / "conformance" / "v1" +EXPECTED_CASES = { + "complete", + "name_only", + "partial", + "authority_substitution", + "producer_reviewer_conflict", + "resolver_byte_substitution", + "lineage_omission", + "custody_contamination", + "legacy_projection_only", + "deterministic_replay", +} +EXPECTED_VALIDATORS = { + "openultrasast.core.factpack.validate_fact_pack", + "openultrasast.core.factmatch.validate_fact_match", + "openultrasast.core.factapply.apply_fact", + "openultrasast.core.factvalidate.validate_fact_relations", +} + + +def _freeze(value: object) -> object: + if isinstance(value, list): + return tuple(_freeze(item) for item in value) + if isinstance(value, dict): + return {key: _freeze(item) for key, item in value.items()} + return value + + +def _parsed(content: bytes) -> dict[str, object]: + parsed = json.loads(content) + assert isinstance(parsed, dict) + assert ( + canonical.canonical_record_bytes( + _freeze(parsed), + known_schema_versions=(ENTRY_FACT_CONFORMANCE_SCHEMA,), + ) + == content + ) + return parsed + + +def _assert_materialized(cases: list[dict[str, object]], root: Path) -> None: + for case in cases: + content = (FIXTURE_ROOT / case["fixture_path"]).read_bytes() + assert len(content) == case["fixture_byte_length"] > 0 + assert canonical.bytes_digest(content) == case["fixture_digest"] + assert case["validators"] + for artifact in case["artifacts"]: + artifact_content = (root / artifact["path"]).read_bytes() + assert len(artifact_content) == artifact["byte_length"] > 0 + assert canonical.bytes_digest(artifact_content) == artifact["content_digest"] + declared = {artifact["path"] for case in cases for artifact in case["artifacts"]} + materialized = {path.relative_to(root).as_posix() for path in (root / "artifacts" / "sha256").iterdir()} + assert declared == materialized + + +def _assert_downstream_results(cases: list[dict[str, object]]) -> None: + authority = next(case for case in cases if case["case_id"] == "authority_substitution") + conflict = next(case for case in cases if case["case_id"] == "producer_reviewer_conflict") + name = "openultrasast.mapping.fact_authority.authenticate_entry_fact_authority" + assert authority["downstream_validators"] == [{"name": name, "status": "refused", "reason": "authority_bundle_digest_substituted"}] + assert conflict["downstream_validators"] == [{"name": name, "status": "refused", "reason": "producer_reviewer_conflict"}] + excluded = {"authority_substitution", "producer_reviewer_conflict"} + assert all(not case["downstream_validators"] for case in cases if case["case_id"] not in excluded) + + +def test_handoff_is_canonical_complete_and_reproducible(tmp_path: Path) -> None: + first = build_entry_fact_conformance(FIXTURE_ROOT, tmp_path / "first") + second = build_entry_fact_conformance(FIXTURE_ROOT, tmp_path / "second") + + assert first == second + manifest = _parsed(first) + assert set(manifest) == { + "schema_version", + "handoff_digest", + "core_entry_points", + "cases", + } + assert set(manifest["core_entry_points"]) == EXPECTED_VALIDATORS + cases = manifest["cases"] + assert isinstance(cases, list) + assert {case["case_id"] for case in cases} == EXPECTED_CASES + assert ( + canonical.content_digest( + { + "schema_version": manifest["schema_version"], + "core_entry_points": tuple(manifest["core_entry_points"]), + "cases": _freeze(cases), + } + ) + == manifest["handoff_digest"] + ) + _assert_materialized(cases, tmp_path / "first") + complete = next(case for case in cases if case["case_id"] == "complete") + assert {row["name"] for row in complete["validators"]} == EXPECTED_VALIDATORS + assert {row["status"] for row in complete["validators"]} == {"passed"} + assert complete["reason"] is None + _assert_downstream_results(cases) + refused = [case for case in cases if case["case_id"] not in {"complete", "deterministic_replay"}] + assert all(case["expected_status"] == "refused" and case["reason"] for case in refused) + + +def test_checked_in_handoff_equals_fresh_generation(tmp_path: Path) -> None: + generated = write_entry_fact_conformance(FIXTURE_ROOT, tmp_path / "fresh") + checked_in = FIXTURE_ROOT / "manifest.json" + + assert generated.read_bytes() == checked_in.read_bytes() + validate_entry_fact_conformance(checked_in.read_bytes(), FIXTURE_ROOT) + manifest = _parsed(checked_in.read_bytes()) + declared = {artifact["path"] for case in manifest["cases"] for artifact in case["artifacts"]} + materialized = {path.relative_to(FIXTURE_ROOT).as_posix() for path in (FIXTURE_ROOT / "artifacts" / "sha256").iterdir()} + assert declared == materialized + + +def test_manifest_refuses_open_schema_and_digest_substitution(tmp_path: Path) -> None: + content = build_entry_fact_conformance(FIXTURE_ROOT, tmp_path / "output") + manifest = json.loads(content) + manifest["cases"][0]["artifacts"][0]["unexpected"] = True + opened = canonical.canonical_record_bytes( + _freeze(manifest), + known_schema_versions=(ENTRY_FACT_CONFORMANCE_SCHEMA,), + ) + with pytest.raises(EntryFactConformanceError, match="unknown or missing fields"): + validate_entry_fact_conformance(opened) + + manifest = json.loads(content) + manifest["handoff_digest"] = "0" * 64 + substituted = canonical.canonical_record_bytes( + _freeze(manifest), + known_schema_versions=(ENTRY_FACT_CONFORMANCE_SCHEMA,), + ) + with pytest.raises(EntryFactConformanceError, match="cannot be re-derived"): + validate_entry_fact_conformance(substituted) + + +def test_manifest_refuses_bogus_entry_point_and_fabricated_case_result(tmp_path: Path) -> None: + content = build_entry_fact_conformance(FIXTURE_ROOT, tmp_path / "output") + + def redigest(manifest: dict[str, object]) -> bytes: + manifest["handoff_digest"] = canonical.content_digest( + { + "schema_version": manifest["schema_version"], + "core_entry_points": tuple(manifest["core_entry_points"]), + "cases": _freeze(manifest["cases"]), + } + ) + return canonical.canonical_record_bytes(_freeze(manifest), known_schema_versions=(ENTRY_FACT_CONFORMANCE_SCHEMA,)) + + bogus = json.loads(content) + bogus["core_entry_points"][0] = "openultrasast.core.fake.accept_everything" + with pytest.raises(EntryFactConformanceError, match="exact replay set"): + validate_entry_fact_conformance(redigest(bogus)) + + fabricated = json.loads(content) + complete = next(case for case in fabricated["cases"] if case["case_id"] == "complete") + complete["expected_status"] = "refused" + complete["reason"] = "fabricated" + complete["validators"][0]["status"] = "refused" + complete["validators"][0]["reason"] = "fabricated" + with pytest.raises(EntryFactConformanceError, match="matrix|enclosing case"): + validate_entry_fact_conformance(redigest(fabricated)) + + downstream = json.loads(content) + authority = next(case for case in downstream["cases"] if case["case_id"] == "authority_substitution") + authority["downstream_validators"][0]["reason"] = "fabricated" + with pytest.raises(EntryFactConformanceError, match="downstream validator matrix"): + validate_entry_fact_conformance(redigest(downstream)) + + +@pytest.mark.parametrize("mutation", ("extra", "extra_directory", "missing", "non_file")) +def test_manifest_requires_exact_regular_source_census(tmp_path: Path, mutation: str) -> None: + root = tmp_path / mutation + shutil.copytree(FIXTURE_ROOT, root) + if mutation == "extra": + (root / "sources" / "undeclared.js").write_text("export const extra = true;\n", encoding="utf-8") + elif mutation == "extra_directory": + (root / "sources" / "undeclared").mkdir() + elif mutation == "missing": + (root / "sources" / "partial.js").unlink() + else: + target = root / "sources" / "partial.js" + target.unlink() + target.mkdir() + + with pytest.raises(EntryFactConformanceError, match="source filesystem census"): + validate_entry_fact_conformance((root / "manifest.json").read_bytes(), root) + + +@pytest.mark.parametrize("declared", (False, True)) +def test_manifest_refuses_source_symlinks(tmp_path: Path, declared: bool) -> None: + root = tmp_path / "source-symlink" + shutil.copytree(FIXTURE_ROOT, root) + external = tmp_path / "external.js" + external.write_bytes((root / "sources" / "partial.js").read_bytes()) + target = root / "sources" / ("partial.js" if declared else "undeclared.js") + if declared: + target.unlink() + os.symlink(external, target) + + with pytest.raises(EntryFactConformanceError, match="source filesystem census"): + validate_entry_fact_conformance((root / "manifest.json").read_bytes(), root) + + +@pytest.mark.parametrize("entry_kind", ("directory", "symlink")) +def test_manifest_refuses_extra_artifact_entries(tmp_path: Path, entry_kind: str) -> None: + root = tmp_path / "artifact-entry" + shutil.copytree(FIXTURE_ROOT, root) + target = root / "artifacts" / "sha256" / "unexpected" + if entry_kind == "directory": + target.mkdir() + else: + external = tmp_path / "external-artifact" + external.write_bytes(b"external") + os.symlink(external, target) + + with pytest.raises(EntryFactConformanceError, match="artifact filesystem census"): + validate_entry_fact_conformance((root / "manifest.json").read_bytes(), root) + + +def test_manifest_refuses_declared_artifact_symlink_to_identical_bytes(tmp_path: Path) -> None: + root = tmp_path / "artifact-symlink" + shutil.copytree(FIXTURE_ROOT, root) + manifest = json.loads((root / "manifest.json").read_bytes()) + relative = manifest["cases"][0]["artifacts"][0]["path"] + target = root / relative + external = tmp_path / "identical-artifact" + external.write_bytes(target.read_bytes()) + target.unlink() + os.symlink(external, target) + + with pytest.raises(EntryFactConformanceError, match="artifact filesystem census"): + validate_entry_fact_conformance((root / "manifest.json").read_bytes(), root) + + +@pytest.mark.parametrize("directory", ("sources", "artifacts", "artifacts/sha256")) +def test_manifest_refuses_symlinked_census_root(tmp_path: Path, directory: str) -> None: + root = tmp_path / "redirected-root" + shutil.copytree(FIXTURE_ROOT, root) + target = root / directory + external = tmp_path / directory.replace("/", "-") + shutil.copytree(target, external) + shutil.rmtree(target) + os.symlink(external, target) + reason = "source filesystem census" if directory == "sources" else "artifact filesystem census" + + with pytest.raises(EntryFactConformanceError, match=reason): + validate_entry_fact_conformance((root / "manifest.json").read_bytes(), root) + + +def test_builder_refuses_declared_source_symlink(tmp_path: Path) -> None: + root = tmp_path / "builder-source" + shutil.copytree(FIXTURE_ROOT, root) + target = root / "sources" / "complete.js" + external = tmp_path / "builder-external.js" + external.write_bytes(target.read_bytes()) + target.unlink() + os.symlink(external, target) + + with pytest.raises(EntryFactConformanceError, match="nonempty readable fixture"): + build_entry_fact_conformance(root, tmp_path / "builder-output") + + +def test_builder_refuses_symlinked_source_root(tmp_path: Path) -> None: + root = tmp_path / "builder-source-root" + shutil.copytree(FIXTURE_ROOT, root) + external = tmp_path / "external-sources" + shutil.copytree(root / "sources", external) + shutil.rmtree(root / "sources") + os.symlink(external, root / "sources") + + with pytest.raises(EntryFactConformanceError, match="real non-symlink directory"): + build_entry_fact_conformance(root, tmp_path / "builder-output") + + +def test_builder_refuses_existing_digest_symlink(tmp_path: Path) -> None: + output = tmp_path / "builder-artifacts" + build_entry_fact_conformance(FIXTURE_ROOT, output) + target = next((output / "artifacts" / "sha256").iterdir()) + external = tmp_path / "builder-identical-artifact" + external.write_bytes(target.read_bytes()) + target.unlink() + os.symlink(external, target) + + with pytest.raises(EntryFactConformanceError, match="artifact.*regular|unsafe"): + build_entry_fact_conformance(FIXTURE_ROOT, output) + + +def test_builder_refuses_symlinked_artifact_root(tmp_path: Path) -> None: + output = tmp_path / "builder-artifact-root" + (output / "artifacts").mkdir(parents=True) + external = tmp_path / "external-artifacts" + external.mkdir() + os.symlink(external, output / "artifacts" / "sha256") + + with pytest.raises(EntryFactConformanceError, match="artifact.*regular|unsafe"): + build_entry_fact_conformance(FIXTURE_ROOT, output) + + +def test_builder_refuses_symlinked_artifacts_directory(tmp_path: Path) -> None: + output = tmp_path / "builder-artifacts-directory" + output.mkdir() + external = tmp_path / "external-artifacts-directory" + (external / "sha256").mkdir(parents=True) + os.symlink(external, output / "artifacts") + + with pytest.raises(EntryFactConformanceError, match="artifact.*regular|unsafe"): + build_entry_fact_conformance(FIXTURE_ROOT, output) + + +def test_unreadable_or_empty_fixture_fails_before_validator_results(tmp_path: Path) -> None: + fixture_root = tmp_path / "fixtures" + sources = fixture_root / "sources" + sources.mkdir(parents=True) + for name in ("complete.js", "name-only.js", "partial.js", "legacy-only.js"): + (sources / name).write_bytes(b"" if name == "complete.js" else b"x") + + with pytest.raises(EntryFactConformanceError, match="nonempty readable fixture"): + build_entry_fact_conformance(fixture_root, tmp_path / "output") + + +def test_isolated_consumer_replays_without_mapping_or_target_imports() -> None: + script = """ +import importlib.abc +import pathlib +import sys +class BlockTargetImports(importlib.abc.MetaPathFinder): + def find_spec(self, fullname, path=None, target=None): + if fullname.startswith(('openultrasast.mapping', 'openultrasast.semantic')): + raise ImportError(f'forbidden target import: {fullname}') + return None +sys.meta_path.insert(0, BlockTargetImports()) +sys.path.insert(0, sys.argv[2]) +sys.path.insert(0, sys.argv[3]) +from entry_fact_core_consumer import replay_all +results = replay_all(pathlib.Path(sys.argv[1])) +assert len(results) == 10 +print('isolated-core-replay=10') +""" + completed = subprocess.run( + [ + sys.executable, + "-I", + "-c", + script, + str(FIXTURE_ROOT), + str(Path(__file__).parent), + str(Path(__file__).parents[1] / "src"), + ], + check=False, + capture_output=True, + text=True, + ) + assert completed.returncode == 0, completed.stderr + assert completed.stdout.strip() == "isolated-core-replay=10"