mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-11-13 01:48:17 +00:00
feat(access-control-prover): publish fact conformance handoff
This commit is contained in:
@@ -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]
|
||||
@@ -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)
|
||||
@@ -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"])
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"conflicts":[],"resolved":true,"schema_version":"openultrasast.access-control.authority-conflict-disclosure.v1"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+1
@@ -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"}
|
||||
+33
@@ -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."
|
||||
}
|
||||
}
|
||||
+1
@@ -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"}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
import express from "express";
|
||||
const app = express();
|
||||
app.get("/admin", adminHandler);
|
||||
function adminHandler(req, res) { res.sendStatus(204); }
|
||||
@@ -0,0 +1,2 @@
|
||||
// Legacy recognition text only: app.get("/admin", adminHandler)
|
||||
export const marker = "not a structural registration";
|
||||
@@ -0,0 +1,2 @@
|
||||
app.get("/admin", adminHandler);
|
||||
function adminHandler(req, res) { res.sendStatus(204); }
|
||||
@@ -0,0 +1,3 @@
|
||||
import express from "express";
|
||||
const app = express();
|
||||
app.get("/admin");
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user