Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6.2.0
with:
python-version: '3.11'
python-version: '3.13'

- name: Install dependencies
run: |
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/dependency_review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ jobs:
- name: 'Checkout Repository'
uses: actions/checkout@v6.0.2
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
uses: actions/dependency-review-action@v4
with:
allow-dependencies-licenses: pkg:pypi/ppdeep=Apache-2.0
Comment thread
IshaanXCoder marked this conversation as resolved.
2 changes: 1 addition & 1 deletion .github/workflows/pull_request_automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6.2.0
with:
python-version: 3.11
python-version: 3.13

- name: Install Dependencies
run: |
Expand Down
4 changes: 2 additions & 2 deletions api_app/analyzers_manager/file_analyzers/file_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Optional

import magic
import pydeep
import ppdeep
Comment thread
IshaanXCoder marked this conversation as resolved.
import tlsh
from django.conf import settings
from django.utils.functional import cached_property
Expand Down Expand Up @@ -40,7 +40,7 @@ def run(self):
results["md5"] = calculate_md5(binary)
results["sha1"] = calculate_sha1(binary)
results["sha256"] = calculate_sha256(binary)
results["ssdeep"] = pydeep.hash_file(self.filepath).decode()
results["ssdeep"] = ppdeep.hash_from_file(self.filepath)
results["tlsh"] = tlsh.hash(binary)

if self.exiftool_path:
Expand Down
2 changes: 1 addition & 1 deletion api_app/analyzers_manager/observable_analyzers/maxmind.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def _get_api_key(cls):
def update(cls) -> bool:
auth_token = cls._get_api_key()
if auth_token:
return cls._maxmind_db_manager.update_all_dbs(cls._api_key_name)
return cls._maxmind_db_manager.update_all_dbs(auth_token)
Comment thread
IshaanXCoder marked this conversation as resolved.
return False

def _update_data_model(self, data_model) -> None:
Expand Down
15 changes: 7 additions & 8 deletions api_app/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import logging
import re
import typing
from pathlib import PosixPath

from django.db import models

Expand All @@ -15,17 +14,17 @@

class PythonModuleBasePaths(models.TextChoices):
ObservableAnalyzer = (
PosixPath("api_app.analyzers_manager.observable_analyzers"),
"api_app.analyzers_manager.observable_analyzers",
"Observable Analyzer",
)
FileAnalyzer = (
PosixPath("api_app.analyzers_manager.file_analyzers"),
"api_app.analyzers_manager.file_analyzers",
"File Analyzer",
)
Connector = PosixPath("api_app.connectors_manager.connectors"), "Connector"
Ingestor = PosixPath("api_app.ingestors_manager.ingestors"), "Ingestor"
Visualizer = PosixPath("api_app.visualizers_manager.visualizers"), "Visualizer"
Pivot = PosixPath("api_app.pivots_manager.pivots"), "Pivot"
Connector = "api_app.connectors_manager.connectors", "Connector"
Ingestor = "api_app.ingestors_manager.ingestors", "Ingestor"
Visualizer = "api_app.visualizers_manager.visualizers", "Visualizer"
Pivot = "api_app.pivots_manager.pivots", "Pivot"


class TLP(models.TextChoices):
Expand Down Expand Up @@ -79,7 +78,7 @@ class Status(models.TextChoices):
FAILED = "failed", "failed"

@classmethod
def get_enums_with_suffix(cls, suffix: str) -> typing.Generator[enum.Enum, None, None]:
def get_enums_with_suffix(cls, suffix: str) -> typing.Generator[enum.Enum]:
Comment thread
IshaanXCoder marked this conversation as resolved.
for key in cls:
if key.name.endswith(suffix):
yield key
Expand Down
2 changes: 1 addition & 1 deletion api_app/engines_manager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class EngineConfig(SingletonModel):
help_text="List of modules used by the engine. Each module has syntax `name_file.name_class`",
)

def get_modules_signatures(self, job) -> Generator[Signature, None, None]:
def get_modules_signatures(self, job) -> Generator[Signature]:
Comment thread
IshaanXCoder marked this conversation as resolved.
from api_app.engines_manager.tasks import execute_engine_module

for path in self.modules:
Expand Down
2 changes: 1 addition & 1 deletion api_app/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def create_jobs(
delay: datetime.timedelta = datetime.timedelta(),
send_task: bool = True,
parent_job=None,
) -> Generator["Job", None, None]:
) -> Generator["Job"]:
Comment thread
IshaanXCoder marked this conversation as resolved.
"""
Creates jobs from the given playbook configuration.

Expand Down
2 changes: 1 addition & 1 deletion api_app/serializers/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def plugins_to_execute(
self,
tlp,
plugins_requested: Union[List[Union[AnalyzerConfig, ConnectorConfig, VisualizerConfig]], QuerySet],
) -> Generator[Union[AnalyzerConfig, ConnectorConfig, VisualizerConfig], None, None]:
) -> Generator[Union[AnalyzerConfig, ConnectorConfig, VisualizerConfig]]:
Comment thread
IshaanXCoder marked this conversation as resolved.
if not plugins_requested:
return
if isinstance(plugins_requested, QuerySet):
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ RUN npm install npm@latest --location=global \
&& PUBLIC_URL=/static/reactapp/ npm run build

# Stage 2: Backend
FROM python:3.11.7 AS backend-build
FROM python:3.13.12 AS backend-build

ENV PYTHONUNBUFFERED=1
ENV DJANGO_SETTINGS_MODULE=intel_owl.settings
Expand Down
1 change: 0 additions & 1 deletion docker/test.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ services:
- DEBUG=True
- DJANGO_TEST_SERVER=True
- DJANGO_WATCHMAN_TIMEOUT=60

daphne:
Comment thread
IshaanXCoder marked this conversation as resolved.
image: intelowlproject/intelowl:test
volumes:
Expand Down
2 changes: 1 addition & 1 deletion integrations/malware_tools_analyzers/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.11-slim
FROM python:3.13.12
Comment thread
IshaanXCoder marked this conversation as resolved.

ARG TARGETARCH

Expand Down
2 changes: 1 addition & 1 deletion integrations/tor_analyzers/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.14-slim
FROM python:3.13.12

Copilot AI Feb 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several integration Dockerfiles still use older Python versions and have not been updated to Python 3.13. For consistency and to complete the Python upgrade, the following Dockerfiles should also be updated: integrations/bbot/Dockerfile (uses python:3.12-slim), integrations/phishing_analyzers/Dockerfile (uses python:3.12.3), and integrations/phunter/Dockerfile (uses python:3.12-slim). Note that integrations/pcap_analyzers, integrations/thug, integrations/nuclei_analyzer, and integrations/cyberchef use base images that don't directly specify Python versions.

Copilot uses AI. Check for mistakes.
Comment thread
IshaanXCoder marked this conversation as resolved.

ENV PROJECT_PATH=/opt/deploy
ENV LOG_PATH=/var/log/intel_owl/tor_analyzers
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.ruff]
line-length = 110
target-version = "py311"
target-version = "py313"
Comment thread
IshaanXCoder marked this conversation as resolved.

exclude = [
"venv",
Expand Down
32 changes: 16 additions & 16 deletions requirements/project-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# django libs
Django==4.2.27
psycopg2-binary==2.9.6
Django==5.2.1
Comment thread
IshaanXCoder marked this conversation as resolved.
Outdated
psycopg2-binary==2.9.11
django-auth-ldap==5.1.0
django-radius==1.5.0
django-filter==25.1
django-storages==1.14
django-celery-beat==2.7.0
django-celery-results==2.5.0
django-celery-beat==2.8.1
django-celery-results==2.6.0
django-ses == 4.6.0
django-iam-dbauth==0.2.1
django-prettyjson==0.4.1
Expand All @@ -17,19 +17,19 @@ django_extensions==3.2.3
jsonschema==4.25.1
# django rest framework libs
Authlib==1.6.5
djangorestframework==3.15.2
djangorestframework-filters==1.0.0.dev2
djangorestframework==3.16.1
djangorestframework-filters==1.0.0.dev2
Comment thread
IshaanXCoder marked this conversation as resolved.
Outdated
drf-spectacular==0.28.0
django-rest-email-auth==4.0.0
django-rest-email-auth==5.0.0

# infra
boto3==1.39.4
celery[sqs,redis]==5.4.0
celery[sqs,redis]==5.6.0
dataclasses==0.6
# https://github.com/advisories/GHSA-q4qm-xhf9-4p8f
# unpatched CVE: noproblem, we just use this for debugging purposes
flower==2.0.0
uWSGI==2.0.28
uWSGI==2.0.31
uwsgitop==0.12
whitenoise==6.9.0
daphne==4.2.1
Expand All @@ -42,10 +42,10 @@ GitPython==3.1.41
checkdmarc==5.13.1
dnspython==2.8.0
dnstwist[full]==20250130
google>=3.0.0
google==3.0.0
google-cloud-webrisk==1.20.0
intezer-sdk==1.24.0
lief==0.15.1
lief==0.17.3
maxminddb==2.6.0
geoip2==4.8.0
mwdblib==4.6.0
Expand All @@ -54,8 +54,8 @@ OTXv2==1.5.12
peepdf-fork==0.4.3
pdfid==1.1.0
pefile==2024.8.26
Pillow==11.0.0
pydeep==0.4
Pillow==12.0.0
Comment thread
IshaanXCoder marked this conversation as resolved.
Outdated
ppdeep==20251115
pyelftools==0.31
PyExifTool==0.5.0
pyhashlookup==1.2.0
Expand All @@ -67,7 +67,7 @@ pypssl==2.2
pysafebrowsing==0.1.1
PySocks==1.7.1
py-tlsh==4.7.2
quark-engine==25.1.1
quark-engine==26.1.1
speakeasy-emulator==1.5.9
telfhash==0.9.8
yara-python==4.5.1
Expand All @@ -76,11 +76,11 @@ XLMMacroDeobfuscator[secure]==0.2.3
thinkst-zippy==0.1.2
querycontacts==2.0.0
hfinger==0.2.2
blint==2.3.2
blint==3.1.1
permhash==0.1.4
ail_typo_squatting==2.7.4
iocextract==1.16.1
ioc-finder==7.0.0
ioc-finder==7.3.0
polyswarm-api==3.16.0
knock-subdomains==8.0.0
dotnetfile==0.2.4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class BaseFileAnalyzerTest(TestCase):
"application/zip": "test.zip",
"application/x-dex": "sample.dex",
"application/x-mach-binary": "macho_sample",
"application/x-elf": "ping.elf",
Comment thread
IshaanXCoder marked this conversation as resolved.
}

@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ def get_mocked_response():
# Return list of patches - focusing on what actually matters for the test
return [
# Mock the main Blint analysis engine
patch("blint.lib.runners.AnalysisRunner", return_value=mock_runner),
patch(
"api_app.analyzers_manager.file_analyzers.blint_scan.AnalysisRunner", return_value=mock_runner
),
# Mock file system operations to avoid actual directory creation/deletion
patch("api_app.analyzers_manager.file_analyzers.blint_scan.os.mkdir"),
patch("api_app.analyzers_manager.file_analyzers.blint_scan.shutil.rmtree"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ def get_mocked_response(self):
"api_app.helpers.calculate_sha256",
return_value="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
),
patch("pydeep.hash_file", return_value=b"3:AOn4:An"),
patch("tlsh.hash", return_value="T1234567890ABCDEF"),

Copilot AI Feb 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing mock for ppdeep in the test. The old pydeep mock was removed, but no mock for ppdeep.hash_from_file was added. This will cause the test to fail if ppdeep is not installed or if the test file path doesn't exist, as ppdeep.hash_from_file will be called with an actual file path. Consider adding a mock for ppdeep similar to the other hash function mocks.

Suggested change
patch("tlsh.hash", return_value="T1234567890ABCDEF"),
patch("tlsh.hash", return_value="T1234567890ABCDEF"),
patch("ppdeep.hash_from_file", return_value="PPDEEP_HASH_VALUE"),

Copilot uses AI. Check for mistakes.
# Disable exiftool to avoid subprocess issues
patch.object(FileInfo, "exiftool_path", None),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ class GreynoiseLabsTestCase(BaseAnalyzerTest):

@classmethod
def get_extra_config(cls):
return {"_auth_token": "demo_token", "report": {"errors": []}}
from types import SimpleNamespace

mock_report = SimpleNamespace(errors=[], save=lambda: None)
return {"_auth_token": "demo_token", "report": mock_report}

@staticmethod
def get_mocked_response():
Expand Down
7 changes: 4 additions & 3 deletions tests/api_app/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,10 @@ def test_download_sample_400(self):
content = response.json()
msg = (response, content)
self.assertEqual(response.status_code, 400, msg=msg)
self.assertDictContainsSubset(
{"detail": "Requested job does not have a sample associated with it."},
content["errors"],
self.assertIn("detail", content["errors"], msg=msg)
self.assertEqual(
content["errors"]["detail"],
"Requested job does not have a sample associated with it.",
msg=msg,
)
job.delete()
Expand Down
6 changes: 4 additions & 2 deletions tests/api_app/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,8 @@ def test_create_201(self):
msg = (response, content)

self.assertEqual(response.status_code, 201, msg=msg)
self.assertDictContainsSubset(data, content, msg=msg)
for key, value in data.items():
self.assertEqual(content[key], value, msg=msg)
self.assertEqual(Tag.objects.count(), 2)

def test_create_400(self):
Expand Down Expand Up @@ -512,7 +513,8 @@ def test_update_200(self):
msg = (response, content)

self.assertEqual(response.status_code, 200, msg=msg)
self.assertDictContainsSubset(new_data, content, msg=msg)
for key, value in new_data.items():
self.assertEqual(content[key], value, msg=msg)

def test_delete_204(self):
self.assertEqual(Tag.objects.count(), 1)
Expand Down
25 changes: 20 additions & 5 deletions tests/test_crons.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from intel_owl.tasks import check_stuck_analysis, remove_old_jobs

from . import CustomTestCase, get_logger
from .mock_utils import MockUpResponse, if_mock_connections, patch, skip
from .mock_utils import MockUpResponse, if_mock_connections, patch

logger = get_logger()

Expand Down Expand Up @@ -76,18 +76,33 @@ def test_remove_old_jobs(self):
)
self.assertEqual(remove_old_jobs(), 0)

_job.finished_analysis_time = now() - datetime.timedelta(days=10)
_job.finished_analysis_time = now() - datetime.timedelta(days=15)
_job.save()
self.assertEqual(remove_old_jobs(), 1)

_job.delete()
an.delete()

@if_mock_connections(skip("not working without connection"))
def test_maxmind_updater(self):
@if_mock_connections(
patch(
"api_app.analyzers_manager.observable_analyzers.maxmind.Maxmind._get_api_key",
return_value="test_key",
),
patch("api_app.analyzers_manager.observable_analyzers.maxmind.MaxmindDBManager.update_all_dbs"),
)
def test_maxmind_updater(self, mock_update, mock_key):
def create_dummy_dbs(*args, **kwargs):
for db_name in maxmind.MaxmindDBManager.get_supported_dbs():
path = os.path.join(settings.MEDIA_ROOT, db_name)
with open(path, "w") as f:
f.write("dummy")
return True

mock_update.side_effect = create_dummy_dbs

maxmind.Maxmind.update()
for db in maxmind.Maxmind.get_db_names():
self.assertTrue(os.path.exists(db))
self.assertTrue(os.path.exists(os.path.join(settings.MEDIA_ROOT, db)))

@if_mock_connections(patch("requests.get", return_value=MockUpResponse({}, 200, text="91.192.100.61")))
def test_talos_updater(self, mock_get=None):
Expand Down
Loading