howler-api 4.0.0.dev1110__tar.gz → 4.0.0.dev1115__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/PKG-INFO +1 -1
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v2/case.py +7 -3
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/base.py +26 -2
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/case.py +20 -2
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/random_data.py +3 -8
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/randomizer.py +6 -2
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/case_service.py +44 -3
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/correlation_service.py +48 -10
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/pyproject.toml +1 -1
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/README.md +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/add_label.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/add_to_bundle.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/add_to_case.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/change_field.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/demote.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/example_plugin.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/prioritization.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/promote.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/remove_from_bundle.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/remove_label.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/actions/transition.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/base.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/socket.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/action.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/analytic.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/auth.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/clue.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/configs.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/dossier.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/help.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/hit.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/notebook.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/overview.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/search.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/template.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/tool.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/user.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/utils/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/utils/etag.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/utils/params.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v1/view.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v2/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v2/fuzzy.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v2/ingest.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/api/v2/search.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/app.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/README.md +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/classification.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/classification.yml +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/exceptions.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/loader.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/logging/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/logging/audit.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/logging/format.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/net.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/net_static.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/random_user.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/common/swagger.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/config.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/cronjobs/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/cronjobs/action_queue_worker.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/cronjobs/correlation.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/cronjobs/retention.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/cronjobs/view_cleanup.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/README.md +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/bulk.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/collection.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/constants.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/exceptions.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/howler_store.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/migrations/fix_process.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/operations.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/schemas.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/store.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/support/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/support/build.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/support/schemas.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/types.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/error.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/external/README.md +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/external/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/external/generate_mitre.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/external/generate_sigma_rules.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/external/generate_tlds.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/external/reindex_data.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/external/wipe_databases.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/gunicorn_config.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/healthz.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/helper/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/helper/azure.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/helper/discover.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/helper/hit.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/helper/oauth.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/helper/search.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/helper/workflow.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/helper/ws.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/README.md +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/charter.txt +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/constants.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/helper.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/howler_enum.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/mixins.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/action.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/analytic.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/assemblyline.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/aws.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/azure.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/cbs.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/clue.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/config.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/dossier.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/agent.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/autonomous_system.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/client.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/cloud.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/code_signature.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/container.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/dns.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/egress.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/elf.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/email.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/error.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/event.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/faas.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/file.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/geo.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/group.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/hash.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/host.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/http.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/ingress.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/interface.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/network.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/observer.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/organization.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/os.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/pe.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/process.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/registry.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/related.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/rule.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/server.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/threat.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/tls.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/url.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/user.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/user_agent.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/ecs/vulnerability.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/event.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/gcp.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/hit.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/howler_data.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/lead.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/localized_label.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/overview.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/pivot.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/record.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/template.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/user.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/odm/models/view.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/patched.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/plugins/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/plugins/config.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/README.md +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/counters.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/events.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/hash.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/lock.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/queues/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/queues/comms.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/queues/multi.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/queues/named.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/queues/priority.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/set.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/remote/datatypes/user_quota_tracker.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/security/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/security/socket.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/security/utils.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/action_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/analytic_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/auth_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/bundle_compat_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/comms_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/config_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/docs_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/dossier_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/event_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/fuzzy_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/hit_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/jwt_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/lucene_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/notebook_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/overview_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/search_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/template_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/user_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/viewer_service.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/telemetry.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/__init__.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/annotations.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/chunk.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/compat.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/constants.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/dict_utils.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/isotime.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/list_utils.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/lucene.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/path.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/socket_utils.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/str_utils.py +0 -0
- {howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/utils/uid.py +0 -0
|
@@ -354,7 +354,8 @@ def add_rule(id: str, user: User, **kwargs):
|
|
|
354
354
|
{
|
|
355
355
|
"query": "howler.analytic:Suspicious*",
|
|
356
356
|
"destination": "alerts/{{howler.analytic}}",
|
|
357
|
-
"timeframe":
|
|
357
|
+
"timeframe": 14, // optional, days until expiry (null = no expiry)
|
|
358
|
+
"expire_after_resolved": true // optional, start countdown after case resolution
|
|
358
359
|
}
|
|
359
360
|
|
|
360
361
|
Result Example:
|
|
@@ -405,7 +406,8 @@ def delete_rule(id: str, rule_id: str, user: User, **kwargs):
|
|
|
405
406
|
def update_rule(id: str, rule_id: str, user: User, **kwargs):
|
|
406
407
|
"""Update a correlation rule on a case
|
|
407
408
|
|
|
408
|
-
Allows updating individual fields on a rule: enabled, query, destination,
|
|
409
|
+
Allows updating individual fields on a rule: enabled, query, destination,
|
|
410
|
+
timeframe, expire_after_resolved.
|
|
409
411
|
|
|
410
412
|
Variables:
|
|
411
413
|
id => The id of the case
|
|
@@ -416,7 +418,9 @@ def update_rule(id: str, rule_id: str, user: User, **kwargs):
|
|
|
416
418
|
|
|
417
419
|
Data Block:
|
|
418
420
|
{
|
|
419
|
-
"enabled": false
|
|
421
|
+
"enabled": false,
|
|
422
|
+
"timeframe": 7, // days until expiry
|
|
423
|
+
"expire_after_resolved": true // start countdown after resolution
|
|
420
424
|
}
|
|
421
425
|
|
|
422
426
|
Result Example:
|
|
@@ -637,6 +637,11 @@ class IndexText(_Field):
|
|
|
637
637
|
class Integer(_Field):
|
|
638
638
|
"""A field storing an integer value."""
|
|
639
639
|
|
|
640
|
+
def __init__(self, *args, min=None, max=None, **kwargs):
|
|
641
|
+
super().__init__(*args, **kwargs)
|
|
642
|
+
self.min = min
|
|
643
|
+
self.max = max
|
|
644
|
+
|
|
640
645
|
def check(self, value, context=[], **kwargs):
|
|
641
646
|
if self.optional and value is None:
|
|
642
647
|
return None
|
|
@@ -646,10 +651,17 @@ class Integer(_Field):
|
|
|
646
651
|
return self.default
|
|
647
652
|
|
|
648
653
|
try:
|
|
649
|
-
|
|
654
|
+
result = int(value)
|
|
650
655
|
except ValueError as e:
|
|
651
656
|
raise HowlerValueError(f"[{'.'.join(context)}]: {str(e)}")
|
|
652
657
|
|
|
658
|
+
if self.min is not None and result < self.min:
|
|
659
|
+
raise HowlerValueError(f"[{'.'.join(context)}]: {result} is less than minimum value {self.min}")
|
|
660
|
+
if self.max is not None and result > self.max:
|
|
661
|
+
raise HowlerValueError(f"[{'.'.join(context)}]: {result} is greater than maximum value {self.max}")
|
|
662
|
+
|
|
663
|
+
return result
|
|
664
|
+
|
|
653
665
|
|
|
654
666
|
class Long(_Field):
|
|
655
667
|
"""
|
|
@@ -658,6 +670,11 @@ class Long(_Field):
|
|
|
658
670
|
In Elasticsearch, Integer supports values from -2^31 to 2^31-1, while Long supports values from -2^63 to 2^63-1.
|
|
659
671
|
"""
|
|
660
672
|
|
|
673
|
+
def __init__(self, *args, min=None, max=None, **kwargs):
|
|
674
|
+
super().__init__(*args, **kwargs)
|
|
675
|
+
self.min = min
|
|
676
|
+
self.max = max
|
|
677
|
+
|
|
661
678
|
def check(self, value, context=[], **kwargs):
|
|
662
679
|
if self.optional and value is None:
|
|
663
680
|
return None
|
|
@@ -667,10 +684,17 @@ class Long(_Field):
|
|
|
667
684
|
return self.default
|
|
668
685
|
|
|
669
686
|
try:
|
|
670
|
-
|
|
687
|
+
result = int(value)
|
|
671
688
|
except ValueError as e:
|
|
672
689
|
raise HowlerValueError(f"[{'.'.join(context)}]: {str(e)}")
|
|
673
690
|
|
|
691
|
+
if self.min is not None and result < self.min:
|
|
692
|
+
raise HowlerValueError(f"[{'.'.join(context)}]: {result} is less than minimum value {self.min}")
|
|
693
|
+
if self.max is not None and result > self.max:
|
|
694
|
+
raise HowlerValueError(f"[{'.'.join(context)}]: {result} is greater than maximum value {self.max}")
|
|
695
|
+
|
|
696
|
+
return result
|
|
697
|
+
|
|
674
698
|
|
|
675
699
|
class Float(_Field):
|
|
676
700
|
"""A field storing a floating point value."""
|
|
@@ -88,16 +88,34 @@ class CaseRule(odm.Model):
|
|
|
88
88
|
query: str = odm.Keyword(description="Lucene query used by this rule.")
|
|
89
89
|
author: str = odm.Keyword(description="Username who created the rule.")
|
|
90
90
|
enabled: bool = odm.Boolean(default=True, description="Whether the rule is currently active.")
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
created_at: str = odm.Date(
|
|
92
|
+
default="NOW",
|
|
93
|
+
description="Timestamp when the rule was created.",
|
|
94
|
+
)
|
|
95
|
+
timeframe: Optional[int] = odm.Optional(
|
|
96
|
+
odm.Integer(min=1, description="Number of days the rule stays active. Null means no expiry."),
|
|
93
97
|
default=None,
|
|
94
98
|
)
|
|
99
|
+
expire_after_resolved: bool = odm.Boolean(
|
|
100
|
+
default=False,
|
|
101
|
+
description="When true, the timeframe countdown starts from the case's last "
|
|
102
|
+
"resolution time instead of from rule creation.",
|
|
103
|
+
)
|
|
95
104
|
indexes: list[str] = odm.List(
|
|
96
105
|
odm.Enum(values=RuleIndexTypes),
|
|
97
106
|
default=[RuleIndexTypes.HIT],
|
|
98
107
|
description="Indexes to run this rule against (hit, event, or both).",
|
|
99
108
|
)
|
|
100
109
|
|
|
110
|
+
def __init__(self, data: dict = None, *args, **kwargs):
|
|
111
|
+
timeframe = data.get("timeframe") if data else None
|
|
112
|
+
if timeframe is not None and (isinstance(timeframe, bool) or not isinstance(timeframe, int) or timeframe <= 0):
|
|
113
|
+
raise HowlerValueError("Rule timeframe must be a positive integer or None")
|
|
114
|
+
elif timeframe is None and data.get("expire_after_resolved", False):
|
|
115
|
+
raise HowlerValueError("Rule cannot expire after resolved when no timeframe is set")
|
|
116
|
+
|
|
117
|
+
super().__init__(data, *args, **kwargs)
|
|
118
|
+
|
|
101
119
|
|
|
102
120
|
@odm.model(index=True, store=True, description="Task associated with a case item path.")
|
|
103
121
|
class CaseTask(odm.Model):
|
|
@@ -19,7 +19,7 @@ import importlib
|
|
|
19
19
|
import json
|
|
20
20
|
import random
|
|
21
21
|
import textwrap
|
|
22
|
-
from datetime import datetime
|
|
22
|
+
from datetime import datetime
|
|
23
23
|
from random import choice, randint, sample
|
|
24
24
|
from typing import Any, Callable, cast
|
|
25
25
|
from uuid import uuid4
|
|
@@ -908,13 +908,8 @@ def create_cases(ds: HowlerDatastore, num_cases: int = 5):
|
|
|
908
908
|
),
|
|
909
909
|
"author": choice(selected_participants or ["admin"]),
|
|
910
910
|
"enabled": choice([True, True, True, False]),
|
|
911
|
-
"timeframe": choice(
|
|
912
|
-
|
|
913
|
-
(datetime.now() + timedelta(days=randint(7, 28))).isoformat(),
|
|
914
|
-
(datetime.now() + timedelta(days=randint(7, 28))).isoformat(),
|
|
915
|
-
None,
|
|
916
|
-
]
|
|
917
|
-
),
|
|
911
|
+
"timeframe": choice([7, 14, 28, None]),
|
|
912
|
+
"expire_after_resolved": choice([True, False]),
|
|
918
913
|
}
|
|
919
914
|
for _ in range(randint(1, 3))
|
|
920
915
|
],
|
|
@@ -490,10 +490,14 @@ def random_data_for_field(field: _Field, name: str, minimal: bool = False) -> _A
|
|
|
490
490
|
elif isinstance(field, Date):
|
|
491
491
|
return get_random_iso_date()
|
|
492
492
|
elif isinstance(field, Integer):
|
|
493
|
-
|
|
493
|
+
lo = field.min if field.min is not None else -2_147_483_648
|
|
494
|
+
hi = field.max if field.max is not None else 2_147_483_647
|
|
495
|
+
return random.randint(lo, hi)
|
|
494
496
|
elif isinstance(field, Long):
|
|
495
497
|
# Generate a random 64-bit signed integer
|
|
496
|
-
|
|
498
|
+
lo = field.min if field.min is not None else -9_223_372_036_854_775_808
|
|
499
|
+
hi = field.max if field.max is not None else 9_223_372_036_854_775_807
|
|
500
|
+
return random.randint(lo, hi)
|
|
497
501
|
elif isinstance(field, Float):
|
|
498
502
|
# Generate a random float in a reasonable range
|
|
499
503
|
return random.uniform(-1e6, 1e6)
|
|
@@ -4,6 +4,7 @@ This module provides functionality for creating, updating, retrieving, and manag
|
|
|
4
4
|
cases - collections of security alerts and investigation data organized by analysts.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from datetime import datetime, timezone
|
|
7
8
|
from typing import Any, overload
|
|
8
9
|
|
|
9
10
|
from prometheus_client import Counter
|
|
@@ -149,6 +150,34 @@ def delete_cases(case_ids: set[str]) -> bool:
|
|
|
149
150
|
return ds.case.delete_by_query(f"case_id:({' OR '.join(case_ids)})")
|
|
150
151
|
|
|
151
152
|
|
|
153
|
+
def get_last_resolved_time(case: Case) -> datetime | None:
|
|
154
|
+
"""Return the timestamp of the most recent resolution of a case.
|
|
155
|
+
|
|
156
|
+
Scans the case log newest-to-oldest for an entry where ``key='status'``
|
|
157
|
+
and ``new_value='resolved'``. In the case of multiple resolve/unresolve
|
|
158
|
+
cycles, returns the **final** resolved timestamp.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
case: The Case object whose log to scan.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
A timezone-aware datetime if the case was ever resolved, else None.
|
|
165
|
+
"""
|
|
166
|
+
for entry in reversed(case.log):
|
|
167
|
+
if entry.key == "status" and entry.new_value == "resolved":
|
|
168
|
+
ts = entry.timestamp
|
|
169
|
+
if isinstance(ts, datetime):
|
|
170
|
+
if ts.tzinfo is None:
|
|
171
|
+
return ts.replace(tzinfo=timezone.utc)
|
|
172
|
+
return ts
|
|
173
|
+
try:
|
|
174
|
+
dt = datetime.fromisoformat(str(ts).replace("Z", "+00:00"))
|
|
175
|
+
return dt
|
|
176
|
+
except (ValueError, TypeError):
|
|
177
|
+
continue
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
|
|
152
181
|
def _describe_field_change(
|
|
153
182
|
key: str, previous: Any, new: Any, compound_fields: set[str]
|
|
154
183
|
) -> tuple[str, str | None, str | None]:
|
|
@@ -823,10 +852,16 @@ def add_case_rule(case_id: str, rule_data: dict, user: User) -> Case:
|
|
|
823
852
|
raise InvalidDataException("Rule 'destination' is required")
|
|
824
853
|
|
|
825
854
|
rule_data.pop("rule_id", None)
|
|
855
|
+
rule_data.pop("created_at", None)
|
|
826
856
|
rule_data["author"] = user.uname
|
|
827
857
|
rule_data.setdefault("enabled", True)
|
|
858
|
+
rule_data.setdefault("expire_after_resolved", False)
|
|
859
|
+
|
|
860
|
+
try:
|
|
861
|
+
rule = CaseRule(rule_data)
|
|
862
|
+
except HowlerValueError as ex:
|
|
863
|
+
raise InvalidDataException(str(ex)) from ex
|
|
828
864
|
|
|
829
|
-
rule = CaseRule(rule_data)
|
|
830
865
|
_case.rules.append(rule)
|
|
831
866
|
|
|
832
867
|
_case.log.append(
|
|
@@ -890,7 +925,8 @@ def remove_case_rule(case_id: str, rule_id: str, user: User) -> Case:
|
|
|
890
925
|
def update_case_rule(case_id: str, rule_id: str, update_data: dict, user: User) -> Case:
|
|
891
926
|
"""Update fields on an existing correlation rule.
|
|
892
927
|
|
|
893
|
-
Allowed fields: ``enabled``, ``query``, ``destination``, ``timeframe
|
|
928
|
+
Allowed fields: ``enabled``, ``query``, ``destination``, ``timeframe``,
|
|
929
|
+
``expire_after_resolved``.
|
|
894
930
|
|
|
895
931
|
Args:
|
|
896
932
|
case_id: Unique identifier of the case.
|
|
@@ -911,7 +947,7 @@ def update_case_rule(case_id: str, rule_id: str, update_data: dict, user: User)
|
|
|
911
947
|
if _case is None:
|
|
912
948
|
raise NotFoundException(f"Case {case_id} does not exist")
|
|
913
949
|
|
|
914
|
-
allowed_fields = {"enabled", "query", "destination", "timeframe"}
|
|
950
|
+
allowed_fields = {"enabled", "query", "destination", "timeframe", "expire_after_resolved"}
|
|
915
951
|
patch = {k: v for k, v in update_data.items() if k in allowed_fields}
|
|
916
952
|
if not patch:
|
|
917
953
|
raise InvalidDataException(
|
|
@@ -928,6 +964,11 @@ def update_case_rule(case_id: str, rule_id: str, update_data: dict, user: User)
|
|
|
928
964
|
setattr(rule, key, value)
|
|
929
965
|
changes.append(f"{key}: '{old_value}' → '{value}'")
|
|
930
966
|
|
|
967
|
+
if rule.timeframe is not None and (not isinstance(rule.timeframe, int) or rule.timeframe <= 0):
|
|
968
|
+
raise HowlerValueError("Rule timeframe must be a positive integer or None")
|
|
969
|
+
elif rule.timeframe is None and rule.expire_after_resolved:
|
|
970
|
+
raise InvalidDataException("Rule cannot expire after resolved when no timeframe is set")
|
|
971
|
+
|
|
931
972
|
_case.log.append(
|
|
932
973
|
CaseLog(
|
|
933
974
|
{
|
{howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/services/correlation_service.py
RENAMED
|
@@ -8,7 +8,7 @@ The public API consists of three functions:
|
|
|
8
8
|
calls ``process_batch`` in debounced batches.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
from datetime import datetime, timezone
|
|
11
|
+
from datetime import datetime, timedelta, timezone
|
|
12
12
|
|
|
13
13
|
import chevron
|
|
14
14
|
from opentelemetry import trace
|
|
@@ -29,9 +29,24 @@ BATCH_SIZE: int = config.system.correlation.batch_size
|
|
|
29
29
|
BATCH_TIMEOUT: int = config.system.correlation.batch_timeout
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def
|
|
32
|
+
def _normalize_utc(ts: datetime) -> datetime:
|
|
33
|
+
"""Normalize a datetime to UTC, assuming naive timestamps are UTC."""
|
|
34
|
+
if ts.tzinfo is None:
|
|
35
|
+
return ts.replace(tzinfo=timezone.utc)
|
|
36
|
+
return ts
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_active_rules() -> list[tuple[str, CaseRule]]: # noqa: C901
|
|
33
40
|
"""Return all active (enabled, non-expired) rules across every case.
|
|
34
41
|
|
|
42
|
+
A rule's ``timeframe`` is an optional integer representing how many days
|
|
43
|
+
the rule stays active. When ``expire_after_resolved`` is False (default),
|
|
44
|
+
the countdown starts from ``rule.created_at``. When True, it starts from
|
|
45
|
+
the case's most recent resolution time (if the case has never been resolved
|
|
46
|
+
the timer has not started and the rule remains active).
|
|
47
|
+
|
|
48
|
+
If ``timeframe`` is None the rule never expires.
|
|
49
|
+
|
|
35
50
|
Returns:
|
|
36
51
|
A list of ``(case_id, rule)`` tuples for rules that should be evaluated.
|
|
37
52
|
"""
|
|
@@ -41,20 +56,43 @@ def get_active_rules() -> list[tuple[str, CaseRule]]:
|
|
|
41
56
|
|
|
42
57
|
# Only fetch cases that actually have rules.
|
|
43
58
|
for _case in ds.case.stream_search("_exists_:rules.rule_id"):
|
|
59
|
+
# Lazily compute last resolved time only if needed by at least one rule.
|
|
60
|
+
_last_resolved: datetime | None = None
|
|
61
|
+
_last_resolved_computed = False
|
|
62
|
+
|
|
44
63
|
for rule in _case.rules:
|
|
45
64
|
if not rule.enabled:
|
|
46
65
|
continue
|
|
47
66
|
|
|
48
|
-
if rule.timeframe is
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
67
|
+
if rule.timeframe is None:
|
|
68
|
+
# No expiry configured — rule is always active.
|
|
69
|
+
active.append((_case.case_id, rule))
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
# Skip rules whose timeframe is not a valid positive integer.
|
|
73
|
+
if isinstance(rule.timeframe, bool) or not isinstance(rule.timeframe, int) or rule.timeframe <= 0:
|
|
74
|
+
logger.warning("Skipping rule %s with invalid timeframe: %r", rule.rule_id, rule.timeframe)
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
start: datetime
|
|
78
|
+
if not rule.expire_after_resolved:
|
|
79
|
+
start = datetime.fromisoformat(str(rule.created_at).replace("Z", "+00:00"))
|
|
80
|
+
else:
|
|
81
|
+
# Timer starts from last resolution.
|
|
82
|
+
if not _last_resolved_computed:
|
|
83
|
+
_last_resolved = case_service.get_last_resolved_time(_case)
|
|
84
|
+
_last_resolved_computed = True
|
|
85
|
+
|
|
86
|
+
if _last_resolved is None:
|
|
87
|
+
# Case not yet resolved — timer hasn't started.
|
|
88
|
+
active.append((_case.case_id, rule))
|
|
55
89
|
continue
|
|
56
90
|
|
|
57
|
-
|
|
91
|
+
start = _normalize_utc(_last_resolved)
|
|
92
|
+
|
|
93
|
+
expiry = start + timedelta(days=rule.timeframe)
|
|
94
|
+
if expiry > now:
|
|
95
|
+
active.append((_case.case_id, rule))
|
|
58
96
|
|
|
59
97
|
return active
|
|
60
98
|
|
|
@@ -152,7 +152,7 @@ suppress-none-returning = true
|
|
|
152
152
|
[tool.poetry]
|
|
153
153
|
package-mode = true
|
|
154
154
|
name = "howler-api"
|
|
155
|
-
version = "4.0.0.
|
|
155
|
+
version = "4.0.0.dev1115"
|
|
156
156
|
description = "Howler - API server"
|
|
157
157
|
authors = [
|
|
158
158
|
"Canadian Centre for Cyber Security <howler@cyber.gc.ca>",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/cronjobs/action_queue_worker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/datastore/migrations/fix_process.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_api-4.0.0.dev1110 → howler_api-4.0.0.dev1115}/howler/external/generate_sigma_rules.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|