generated from coulomb/repo-seed
relationship persistence, context entities, idempotent asset creation, audit/version handling for relationship changes
This commit is contained in:
@@ -9,6 +9,8 @@ from kontextual_engine import (
|
||||
AssetRepresentation,
|
||||
AuthorizationError,
|
||||
Classification,
|
||||
ContextEntity,
|
||||
ContextEntityType,
|
||||
InMemoryAssetRegistryRepository,
|
||||
LifecycleState,
|
||||
MetadataRecord,
|
||||
@@ -93,6 +95,86 @@ def test_asset_registry_lifecycle_policy_denial_fails_closed_and_audits() -> Non
|
||||
assert repo.get_asset("asset-governed").lifecycle == LifecycleState.ACTIVE
|
||||
|
||||
|
||||
def test_asset_registry_create_is_idempotent_for_same_key_and_payload() -> None:
|
||||
repo = InMemoryAssetRegistryRepository()
|
||||
service = AssetRegistryService(repo)
|
||||
context = operation_context()
|
||||
classification = Classification(asset_type="document", sensitivity=Sensitivity.PUBLIC)
|
||||
source_ref = SourceReference(source_system="repo", path="README.md")
|
||||
representation = AssetRepresentation.from_content(
|
||||
"asset-readme",
|
||||
RepresentationKind.SOURCE,
|
||||
"text/markdown",
|
||||
"# Readme\n",
|
||||
)
|
||||
|
||||
first = service.create_asset(
|
||||
"Readme",
|
||||
classification,
|
||||
context,
|
||||
asset_id="asset-readme",
|
||||
source_refs=[source_ref],
|
||||
representations=[representation],
|
||||
idempotency_key="create-readme",
|
||||
)
|
||||
second = service.create_asset(
|
||||
"Readme",
|
||||
classification,
|
||||
context,
|
||||
asset_id="asset-readme",
|
||||
source_refs=[source_ref],
|
||||
representations=[representation],
|
||||
idempotency_key="create-readme",
|
||||
)
|
||||
|
||||
assert second.asset.id == first.asset.id
|
||||
assert second.version.version_id == first.version.version_id
|
||||
assert second.audit_event.event_id == first.audit_event.event_id
|
||||
assert len(repo.list_versions("asset-readme")) == 1
|
||||
assert len(repo.list_audit_events(target="asset:asset-readme")) == 1
|
||||
|
||||
with pytest.raises(ValidationError, match="Idempotency key"):
|
||||
service.create_asset(
|
||||
"Readme renamed",
|
||||
classification,
|
||||
context,
|
||||
asset_id="asset-readme",
|
||||
source_refs=[source_ref],
|
||||
representations=[representation],
|
||||
idempotency_key="create-readme",
|
||||
)
|
||||
|
||||
|
||||
def test_asset_registry_relationships_create_versions_and_audit() -> None:
|
||||
repo = InMemoryAssetRegistryRepository()
|
||||
service = AssetRegistryService(repo)
|
||||
context = operation_context()
|
||||
classification = Classification(asset_type="document", sensitivity=Sensitivity.INTERNAL)
|
||||
source = service.create_asset("Source", classification, context, asset_id="asset-source")
|
||||
target = service.create_asset("Target", classification, context, asset_id="asset-target")
|
||||
|
||||
result = service.link_asset_to_asset(
|
||||
source.asset.id,
|
||||
target.asset.id,
|
||||
"depends_on",
|
||||
context,
|
||||
confidence=0.91,
|
||||
provenance={"producer": "test"},
|
||||
)
|
||||
|
||||
relationships = repo.list_relationships(source_id=source.asset.id)
|
||||
versions = repo.list_versions(source.asset.id)
|
||||
|
||||
assert relationships == [result.relationship]
|
||||
assert result.relationship.target_id == target.asset.id
|
||||
assert result.relationship.confidence == 0.91
|
||||
assert versions[-1].change_type.value == "relationship_changed"
|
||||
assert versions[-1].relationship_delta["added"]["predicate"] == "depends_on"
|
||||
assert repo.get_asset(source.asset.id).current_version_id == result.version.version_id
|
||||
assert repo.get_asset(target.asset.id).current_version_id == target.version.version_id
|
||||
assert repo.list_audit_events(target=f"asset:{source.asset.id}")[-1].operation == "asset.relationship.add"
|
||||
|
||||
|
||||
def test_sqlite_asset_registry_survives_reinstantiation(tmp_path: Path) -> None:
|
||||
db_path = tmp_path / "registry.sqlite"
|
||||
repo = SQLiteAssetRegistryRepository(db_path)
|
||||
@@ -138,6 +220,42 @@ def test_sqlite_asset_registry_survives_reinstantiation(tmp_path: Path) -> None:
|
||||
]
|
||||
|
||||
|
||||
def test_sqlite_registry_persists_context_entities_relationships_and_idempotency(tmp_path: Path) -> None:
|
||||
db_path = tmp_path / "registry.sqlite"
|
||||
repo = SQLiteAssetRegistryRepository(db_path)
|
||||
service = AssetRegistryService(repo)
|
||||
context = operation_context()
|
||||
created = service.create_asset(
|
||||
"Knowledge Policy",
|
||||
Classification(asset_type="policy", sensitivity=Sensitivity.INTERNAL),
|
||||
context,
|
||||
asset_id="asset-policy",
|
||||
idempotency_key="create-policy",
|
||||
)
|
||||
entity = ContextEntity(
|
||||
entity_type=ContextEntityType.PROJECT,
|
||||
name="Kontextual Engine",
|
||||
entity_id="entity-kontextual",
|
||||
)
|
||||
linked = service.link_asset_to_context_entity(
|
||||
created.asset.id,
|
||||
entity,
|
||||
"about_project",
|
||||
context,
|
||||
)
|
||||
|
||||
reloaded = SQLiteAssetRegistryRepository(db_path)
|
||||
|
||||
assert reloaded.get_idempotency_record("create-policy").result_refs["asset_id"] == "asset-policy"
|
||||
assert reloaded.list_context_entities()[0].entity_id == "entity-kontextual"
|
||||
assert reloaded.list_relationships(source_id="asset-policy")[0].relationship_id == linked.relationship.relationship_id
|
||||
assert reloaded.list_versions("asset-policy")[-1].relationship_delta["added"]["target_kind"] == "context_entity"
|
||||
assert [event.operation for event in reloaded.list_audit_events(target="asset:asset-policy")] == [
|
||||
"asset.create",
|
||||
"asset.relationship.add",
|
||||
]
|
||||
|
||||
|
||||
def test_sqlite_registry_enforces_representation_asset_reference(tmp_path: Path) -> None:
|
||||
repo = SQLiteAssetRegistryRepository(tmp_path / "registry.sqlite")
|
||||
representation = AssetRepresentation.from_content(
|
||||
@@ -179,4 +297,3 @@ class DenyLifecyclePolicy:
|
||||
context={"resource_metadata": resource_metadata or {}},
|
||||
)
|
||||
return PolicyDecision.allow(context.actor.id, action, resource)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user