diff --git a/octopoes/octopoes/core/service.py b/octopoes/octopoes/core/service.py index 8b94efa01a9..9fcea0750fc 100644 --- a/octopoes/octopoes/core/service.py +++ b/octopoes/octopoes/core/service.py @@ -178,6 +178,19 @@ def save_origin( logger.debug("Affirmation source %s already deleted", origin.source) return + if origin.origin_type == OriginType.AFFIRMATION and not any( + other_origin + for other_origin in self.origin_repository.list_origins( + origin_type={OriginType.DECLARATION, OriginType.OBSERVATION, OriginType.INFERENCE}, + valid_time=valid_time, + result=origin.source, + ) + if not (other_origin.origin_type == OriginType.INFERENCE and [other_origin.source] == other_origin.result) + ): + logger.debug("Affirmation source %s seems dangling, deleting", origin.source) + self.ooi_repository.delete(origin.source, valid_time) + return + for ooi in oois: self.ooi_repository.save(ooi, valid_time=valid_time, end_valid_time=end_valid_time) self.origin_repository.save(origin, valid_time=valid_time) diff --git a/octopoes/octopoes/repositories/origin_repository.py b/octopoes/octopoes/repositories/origin_repository.py index 5c15f69cd0c..fa7c102b6f7 100644 --- a/octopoes/octopoes/repositories/origin_repository.py +++ b/octopoes/octopoes/repositories/origin_repository.py @@ -37,7 +37,7 @@ def list_origins( source: Reference | None = None, result: Reference | None = None, method: str | list[str] | None = None, - origin_type: OriginType | None = None, + origin_type: OriginType | list[OriginType] | set[OriginType] | None = None, ) -> list[Origin]: raise NotImplementedError @@ -77,7 +77,7 @@ def list_origins( source: Reference | None = None, result: Reference | None = None, method: str | list[str] | None = None, - origin_type: OriginType | None = None, + origin_type: OriginType | list[OriginType] | set[OriginType] | None = None, ) -> list[Origin]: where_parameters: dict[str, str | list[str]] = {"type": Origin.__name__} @@ -94,7 +94,10 @@ def list_origins( where_parameters["method"] = method if origin_type: - where_parameters["origin_type"] = origin_type.value + if isinstance(origin_type, OriginType): + where_parameters["origin_type"] = origin_type.value + elif isinstance(origin_type, list | set) and all(isinstance(otype, OriginType) for otype in origin_type): + where_parameters["origin_type"] = [otype.value for otype in origin_type] query = generate_pull_query(FieldSet.ALL_FIELDS, where_parameters, offset=offset, limit=limit) diff --git a/octopoes/tests/integration/test_ooi_deletion.py b/octopoes/tests/integration/test_ooi_deletion.py index 3bdfef317b6..1a3da5d68c8 100644 --- a/octopoes/tests/integration/test_ooi_deletion.py +++ b/octopoes/tests/integration/test_ooi_deletion.py @@ -15,6 +15,7 @@ from octopoes.models.ooi.dns.records import NXDOMAIN, DNSARecord from octopoes.models.ooi.dns.zone import Hostname from octopoes.models.ooi.findings import Finding, KATFindingType +from octopoes.models.ooi.monitoring import Application from octopoes.models.ooi.network import IPAddressV4, Network from octopoes.models.ooi.software import Software, SoftwareInstance from octopoes.models.origin import Origin, OriginType @@ -511,3 +512,75 @@ def test_delecration_ooi_delete(octopoes_api_connector: OctopoesAPIConnector, va octopoes_api_connector.delete(network.reference, valid_time) time.sleep(1) assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 1 + + +def test_dangling_affirmation_delete(xtdb_octopoes_service: OctopoesService, event_manager: Mock, valid_time: datetime): + app = Application(name="Acme") + + xtdb_octopoes_service.ooi_repository.save(app, valid_time) + time.sleep(1) + + declaration = Origin( + origin_type=OriginType.DECLARATION, + method="", + source=app.reference, + result=[app.reference], + task_id=uuid.uuid4(), + ) + + xtdb_octopoes_service.save_origin(declaration, [app], valid_time) + time.sleep(1) + event_manager.complete_process_events(xtdb_octopoes_service) + time.sleep(1) + + assert xtdb_octopoes_service.list_ooi({Application}, valid_time).count == 1 + assert ( + len( + xtdb_octopoes_service.origin_repository.list_origins( + origin_type=OriginType.DECLARATION, valid_time=valid_time + ) + ) + == 1 + ) + + xtdb_octopoes_service.origin_repository.delete(declaration, valid_time) + time.sleep(1) + event_manager.complete_process_events(xtdb_octopoes_service) + time.sleep(1) + + assert xtdb_octopoes_service.list_ooi({Application}, valid_time).count == 0 + assert ( + len( + xtdb_octopoes_service.origin_repository.list_origins( + origin_type=OriginType.DECLARATION, valid_time=valid_time + ) + ) + == 0 + ) + + xtdb_octopoes_service.ooi_repository.save(app, valid_time) + xtdb_octopoes_service.commit() + time.sleep(1) + + affirmation = Origin( + origin_type=OriginType.AFFIRMATION, + method="", + source=app.reference, + result=[app.reference], + task_id=uuid.uuid4(), + ) + + xtdb_octopoes_service.save_origin(affirmation, [app], valid_time) + time.sleep(1) + event_manager.complete_process_events(xtdb_octopoes_service) + time.sleep(1) + + assert xtdb_octopoes_service.list_ooi({Application}, valid_time).count == 0 + assert ( + len( + xtdb_octopoes_service.origin_repository.list_origins( + origin_type=OriginType.AFFIRMATION, valid_time=valid_time + ) + ) + == 0 + )