Example #1
0
async def test_analysis_request_serialization(system):
    root = system.new_root()
    observable = root.add_observable("test", "1.2.3.4")
    request = observable.create_analysis_request(amt)

    assert request == AnalysisRequest.from_dict(request.to_dict(), system)
    assert request == AnalysisRequest.from_json(request.to_json(), system)

    other = AnalysisRequest.from_dict(request.to_dict(), system)
    assert request.id == other.id
    assert request.observable == other.observable
    assert request.type == other.type
    assert request.status == other.status
    assert request.owner == other.owner
    assert request.original_root == other.original_root
    assert request.modified_root == other.modified_root

    other = AnalysisRequest.from_json(request.to_json(), system)
    assert request.id == other.id
    assert request.observable == other.observable
    assert request.type == other.type
    assert request.status == other.status
    assert request.owner == other.owner
    assert request.original_root == other.original_root
    assert request.modified_root == other.modified_root
Example #2
0
async def test_EVENT_CACHE_NEW(system):
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_CACHE_NEW, handler)

    amt = AnalysisModuleType(name="test", description="", cache_ttl=600)
    root = system.new_root()
    observable = root.add_observable("test", "test")
    request = observable.create_analysis_request(amt)
    request.initialize_result()
    analysis = request.modified_observable.add_analysis(type=amt)

    assert await system.cache_analysis_result(request) is not None

    await handler.wait()
    assert handler.event.name == EVENT_CACHE_NEW
    assert handler.event.args[0] == generate_cache_key(observable, amt)
    assert AnalysisRequest.from_dict(handler.event.args[1], system) == request

    # we can potentially see duplicate cache hits
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_CACHE_NEW, handler)
    assert await system.cache_analysis_result(request) is not None
    await handler.wait()
    assert handler.event.name == EVENT_CACHE_NEW
    assert handler.event.args[0] == generate_cache_key(observable, amt)
    assert AnalysisRequest.from_dict(handler.event.args[1], system) == request
Example #3
0
    async def get_next_analysis_request(
        self,
        owner_uuid: str,
        amt: Union[AnalysisModuleType, str],
        timeout: Optional[int] = 0,
        version: Optional[str] = None,
        extended_version: Optional[dict[str, str]] = [],
    ) -> Union[AnalysisRequest, None]:
        if isinstance(amt, AnalysisModuleType):
            version = amt.version
            extended_version = amt.extended_version
            amt = amt.name

        async with self.get_client() as client:
            response = await client.post(
                "/work_queue",
                json=AnalysisRequestQueryModel(
                    owner=owner_uuid,
                    amt=amt,
                    timeout=timeout,
                    version=version,
                    extended_version=extended_version,
                ).dict(),
            )

        _raise_exception_on_error(response)

        if response.status_code == 204:
            return None
        else:
            return AnalysisRequest.from_dict(response.json(), self.system)
Example #4
0
async def test_EVENT_CACHE_HIT(system):
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_CACHE_HIT, handler)

    amt = AnalysisModuleType("test", "", cache_ttl=60)
    await system.register_analysis_module_type(amt)
    root = system.new_root()
    observable = root.add_observable("test", "test")
    root_request = root.create_analysis_request()
    await system.process_analysis_request(root_request)
    request = await system.get_next_analysis_request("owner", amt, 0)
    request.initialize_result()
    request.modified_observable.add_analysis(type=amt,
                                             details={"test": "test"})
    await system.process_analysis_request(request)
    assert handler.event is None

    root = system.new_root()
    observable = root.add_observable("test", "test")
    root_request = root.create_analysis_request()
    await system.process_analysis_request(root_request)

    await handler.wait()
    assert handler.event.name == EVENT_CACHE_HIT
    event_root = RootAnalysis.from_dict(handler.event.args[0], system)
    assert event_root.uuid == root.uuid and event_root.version is not None
    assert handler.event.args[1]["type"] == observable.type
    assert handler.event.args[1]["value"] == observable.value
    assert isinstance(AnalysisRequest.from_dict(handler.event.args[2], system),
                      AnalysisRequest)
async def api_process_analysis_request(request: AnalysisRequestModel):
    try:
        await app.state.system.process_analysis_request(
            AnalysisRequest.from_dict(request.dict(), app.state.system))
        return Response(status_code=200)
    except ACEError as e:
        return JSONResponse(status_code=400,
                            content=ErrorModel(code=e.code,
                                               details=str(e)).dict())
Example #6
0
async def test_cached_analysis_result(system):
    amt = AnalysisModuleType(ANALYSIS_TYPE_TEST, "blah", cache_ttl=60)
    assert await system.register_analysis_module_type(amt) == amt

    root = system.new_root()
    test_observable = root.add_observable("test", "test")

    root_request = root.create_analysis_request()
    await system.process_analysis_request(root_request)

    # we should have a single work entry in the work queue
    assert await system.get_queue_size(amt) == 1

    # request should be deleted
    assert await system.get_analysis_request(root_request.id) is None

    request = await system.get_next_analysis_request(OWNER_UUID, amt, 0)
    request.initialize_result()
    request.modified_observable.add_analysis(type=amt,
                                             details={"Hello": "World"})
    await system.process_analysis_request(
        AnalysisRequest.from_dict(request.to_dict(), system))

    # this analysis result for this observable should be cached now
    assert await system.get_cached_analysis_result(request.observable,
                                                   request.type) is not None

    # request should be deleted
    assert await system.get_analysis_request(request.id) is None

    # work queue should be empty
    assert await system.get_queue_size(amt) == 0

    # make another request for the same observable
    root = system.new_root()
    test_observable = root.add_observable("test", "test")

    root_request = root.create_analysis_request()
    await system.process_analysis_request(root_request)

    # request should be deleted
    assert await system.get_analysis_request(root_request.id) is None

    # work queue should be empty since the result was pulled from cache
    assert await system.get_queue_size(amt) == 0

    # get the root analysis and ensure this observable has the analysis now
    root = await system.get_root_analysis(root.uuid)
    assert root is not None
    observable = root.get_observable(request.observable)
    assert observable is not None
    analysis = observable.get_analysis(request.type)
    assert analysis is not None
    assert analysis.root == root
    assert analysis.observable == request.observable
    assert await analysis.get_details(
    ) == await request.modified_observable.get_analysis(amt).get_details()
 async def i_get_analysis_requests_by_root(
         self, key: str) -> list[AnalysisRequest]:
     async with self.get_db() as db:
         return [
             AnalysisRequest.from_dict(json.loads(_[0].json_data), self)
             for _ in (await db.execute(
                 select(AnalysisRequestTracking).where(
                     AnalysisRequestTracking.root_uuid == key))).all()
         ]
 async def i_get_expired_analysis_requests(self) -> list[AnalysisRequest]:
     async with self.get_db() as db:
         result = (await db.execute(
             select(AnalysisRequestTracking).where(datetime.datetime.now(
             ) > AnalysisRequestTracking.expiration_date))).all()
         return [
             AnalysisRequest.from_dict(json.loads(_[0].json_data), self)
             for _ in result
         ]
Example #9
0
async def test_EVENT_AR_NEW(system):
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_AR_NEW, handler)

    root = system.new_root()
    request = root.create_analysis_request()
    await system.track_analysis_request(request)

    await handler.wait()
    assert handler.event.name == EVENT_AR_NEW
    assert AnalysisRequest.from_dict(handler.event.args, system) == request

    handler = TestEventHandler()
    await system.register_event_handler(EVENT_AR_NEW, handler)
    await system.track_analysis_request(request)

    # you can re-track a request without harm
    await handler.wait()
    assert handler.event.name == EVENT_AR_NEW
    assert AnalysisRequest.from_dict(handler.event.args, system) == request
Example #10
0
async def test_EVENT_PROCESSING(system):
    root_handler = TestEventHandler()
    await system.register_event_handler(EVENT_PROCESSING_REQUEST_ROOT,
                                        root_handler)

    observable_request_handler = TestEventHandler()
    await system.register_event_handler(EVENT_PROCESSING_REQUEST_OBSERVABLE,
                                        observable_request_handler)

    amt = AnalysisModuleType("test", "", cache_ttl=60)
    await system.register_analysis_module_type(amt)
    root = system.new_root()
    observable = root.add_observable("test", "test")
    root_request = root.create_analysis_request()
    await system.process_analysis_request(root_request)

    await root_handler.wait()
    assert root_handler.event.name == EVENT_PROCESSING_REQUEST_ROOT
    assert AnalysisRequest.from_dict(root_handler.event.args,
                                     system) == root_request

    request = await system.get_next_analysis_request("owner", amt, 0)

    await observable_request_handler.wait()
    assert observable_request_handler.event.name == EVENT_PROCESSING_REQUEST_OBSERVABLE
    assert AnalysisRequest.from_dict(observable_request_handler.event.args,
                                     system) == request

    result_handler = TestEventHandler()
    await system.register_event_handler(EVENT_PROCESSING_REQUEST_RESULT,
                                        result_handler)

    request.initialize_result()
    request.modified_observable.add_analysis(type=amt,
                                             details={"test": "test"})
    await system.process_analysis_request(request)

    await result_handler.wait()
    assert result_handler.event.name == EVENT_PROCESSING_REQUEST_RESULT
    assert AnalysisRequest.from_dict(result_handler.event.args,
                                     system) == request
    async def i_get_analysis_request_by_request_id(
            self, key: str) -> Union[AnalysisRequest, None]:
        async with self.get_db() as db:
            result = (await db.execute(
                select(AnalysisRequestTracking).where(
                    AnalysisRequestTracking.id == key))).one_or_none()

            if result is None:
                return None

            return AnalysisRequest.from_dict(json.loads(result[0].json_data),
                                             self)
Example #12
0
async def test_EVENT_WORK_ASSIGNED(system):
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_WORK_ASSIGNED, handler)

    amt = AnalysisModuleType("test", "", cache_ttl=60)
    await system.register_analysis_module_type(amt)
    root = system.new_root()
    observable = root.add_observable("test", "test")
    root_request = root.create_analysis_request()
    await system.process_analysis_request(root_request)
    request = await system.get_next_analysis_request("owner", amt, 0)

    await handler.wait()
    assert handler.event.name == EVENT_WORK_ASSIGNED
    assert AnalysisRequest.from_dict(handler.event.args, system) == request
Example #13
0
async def test_EVENT_WORK_ADD(system):
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_WORK_ADD, handler)

    amt = AnalysisModuleType("test", "")
    await system.register_analysis_module_type(amt)
    root = system.new_root()
    observable = root.add_observable("test", "test")
    request = AnalysisRequest(system, root, observable, amt)
    await system.queue_analysis_request(request)

    await handler.wait()
    assert handler.event.name == EVENT_WORK_ADD
    assert handler.event.args[0] == amt.name
    assert AnalysisRequest.from_dict(handler.event.args[1], system) == request
    async def i_get_linked_analysis_requests(
            self, source: AnalysisRequest) -> list[AnalysisRequest]:
        async with self.get_db() as db:
            source_request = (
                # NOTE you cannot do lazy loading with async in sqlalchemy 1.4
                (await db.execute(
                    select(AnalysisRequestTracking).options(
                        selectinload(
                            AnalysisRequestTracking.linked_requests)).where(
                                AnalysisRequestTracking.id == source.id))
                 ).one_or_none())

            if source_request is None:
                return None

            # I think this is where you have to be careful with async
            return [
                AnalysisRequest.from_dict(json.loads(_.json_data), self)
                for _ in source_request[0].linked_requests
            ]
Example #15
0
async def test_EVENT_AR_EXPIRED(system):
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_AR_EXPIRED, handler)

    amt = AnalysisModuleType(name="test",
                             description="test",
                             version="1.0.0",
                             timeout=0,
                             cache_ttl=600)
    await system.register_analysis_module_type(amt)

    root = system.new_root()
    observable = root.add_observable("test", "test")
    request = observable.create_analysis_request(amt)
    await system.track_analysis_request(request)
    request.status = TRACKING_STATUS_ANALYZING
    await system.track_analysis_request(request)

    await system.process_expired_analysis_requests(amt)

    await handler.wait()
    assert handler.event.name == EVENT_AR_EXPIRED
    assert AnalysisRequest.from_dict(handler.event.args, system) == request
Example #16
0
async def test_EVENT_WORK_REMOVE(system):
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_WORK_REMOVE, handler)

    amt = AnalysisModuleType("test", "")
    await system.register_analysis_module_type(amt)
    root = system.new_root()
    observable = root.add_observable("test", "test")
    request = AnalysisRequest(system, root, observable, amt)
    await system.queue_analysis_request(request)
    work = await system.get_work(amt, 0)

    await handler.wait()
    assert handler.event.name == EVENT_WORK_REMOVE
    assert handler.event.args[0] == amt.name
    assert AnalysisRequest.from_dict(handler.event.args[1], system) == work

    # can't get fired if you ain't got no work
    handler = TestEventHandler()
    await system.register_event_handler(EVENT_WORK_REMOVE, handler)

    work = await system.get_work(amt, 0)

    assert handler.event is None