From c303ac685182a84cb30e894b31221c9c6b45f480 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Fri, 7 Aug 2026 09:45:22 +0200 Subject: [PATCH 1/3] handle when folder doesnt exist (#3143) --- tests/test_run_task_adapter.py | 35 ++++++++++++++++++++++++++++++++++ utils/process.py | 8 ++++++++ 2 files changed, 43 insertions(+) diff --git a/tests/test_run_task_adapter.py b/tests/test_run_task_adapter.py index 4e27b6a2091..c7a931f5cc0 100644 --- a/tests/test_run_task_adapter.py +++ b/tests/test_run_task_adapter.py @@ -12,6 +12,9 @@ def fake_process(target=None, sample_sha256=None, task=None, report=False, auto= monkeypatch.setattr(proc, "process", fake_process) monkeypatch.setattr(proc, "db", db) + # Force path_exists to return True so the analysis path check succeeds + monkeypatch.setattr(proc, "path_exists", lambda *args, **kwargs: True) + with db.session.begin(): tid = db.add_path(temp_pe32) task = db.view_task(tid) @@ -20,3 +23,35 @@ def fake_process(target=None, sample_sha256=None, task=None, report=False, auto= assert captured["task_id"] == tid assert captured["auto"] is True and captured["report"] is True + + +def test_run_task_fails_gracefully_when_analysis_dir_missing(monkeypatch, db, temp_pe32): + process_called = False + + def fake_process(*args, **kwargs): + nonlocal process_called + process_called = True + + monkeypatch.setattr(proc, "process", fake_process) + monkeypatch.setattr(proc, "db", db) + + # Force path_exists to return False for the analysis path + original_path_exists = proc.path_exists + def fake_path_exists(path, *args, **kwargs): + if "storage/analyses" in str(path): + return False + return original_path_exists(path, *args, **kwargs) + + monkeypatch.setattr(proc, "path_exists", fake_path_exists) + + with db.session.begin(): + tid = db.add_path(temp_pe32) + task = db.view_task(tid) + + proc.run_task(task) + + assert not process_called, "process should not have been called when analysis dir is missing" + + with db.session.begin(): + updated_task = db.view_task(tid) + assert updated_task.status == proc.TASK_FAILED_PROCESSING diff --git a/utils/process.py b/utils/process.py index 5f58ae7ed29..8096dec8c66 100644 --- a/utils/process.py +++ b/utils/process.py @@ -40,6 +40,7 @@ from lib.cuckoo.common.utils import get_options, option_dict_enabled from lib.cuckoo.core.database import Database, init_database from lib.cuckoo.core.data.task import ( + TASK_FAILED_PROCESSING, TASK_FAILED_REPORTING, TASK_REPORTED ) @@ -190,6 +191,13 @@ def process( def run_task(task, memory_debugging=False, debug=False): """Run exactly one completed task to completion (processing -> report). Extracted from autoprocess so every engine shares identical per-task setup.""" + analysis_path = os.path.join(CUCKOO_ROOT, "storage", "analyses", str(task.id)) + if not path_exists(analysis_path): + log.error("Analysis directory %s does not exist. Marking task %s as failed.", analysis_path, task.id) + with db.session.begin(): + db.set_status(task.id, TASK_FAILED_PROCESSING) + return + sample_hash = "" if task.category != "url": with db.session.begin(): From ba94e0d96cc30d31dafca2fd068a10ecd6975b84 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Fri, 7 Aug 2026 08:02:06 +0000 Subject: [PATCH 2/3] Fix type hint for GCS client in download function --- lib/cuckoo/common/gcp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cuckoo/common/gcp.py b/lib/cuckoo/common/gcp.py index f3e047c96e4..e7950c78236 100644 --- a/lib/cuckoo/common/gcp.py +++ b/lib/cuckoo/common/gcp.py @@ -175,7 +175,7 @@ def check_exists(self, analysis_id: int) -> bool: GCS_ENABLED = False -def download_from_gcs(gcs_uri: str, destination_path: str, logger: Optional[Any] = None, client: Optional[storage.Client] = None) -> bool: +def download_from_gcs(gcs_uri: str, destination_path: str, logger: Optional[Any] = None, client: Optional["storage.Client"] = None) -> bool: """ Downloads a file from GCS. gcs_uri: gs://bucket_name/object_name From 9dbe3356e5947399d4f1b8eee9ad8ed5ef9f4509 Mon Sep 17 00:00:00 2001 From: doomedraven Date: Fri, 7 Aug 2026 08:32:20 +0000 Subject: [PATCH 3/3] Handle missing target files and update paths --- utils/dist.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/utils/dist.py b/utils/dist.py index d135dd0a694..5ea36d1474c 100644 --- a/utils/dist.py +++ b/utils/dist.py @@ -4,7 +4,6 @@ # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org # See the file 'docs/LICENSE' for copying permission. -# https://github.com/cuckoosandbox/cuckoo/pull/1694/files import argparse import distutils.util import hashlib @@ -1228,9 +1227,21 @@ def submit_tasks(self, node_name, pend_tasks_num, options_like=False, force_push # print(t.category, t.target) if t.category in ("file", "pcap", "static"): if not path_exists(t.target): - log.info("Task id: %d - File doesn't exist: %s", t.id, t.target) - main_db.set_status(t.id, TASK_BANNED) - continue + sample_sha256 = None + try: + if t.sample: + sample_sha256 = t.sample.sha256 + except Exception as e: + log.debug("Failed to lazy load sample relation for task %d: %s", t.id, e) + + bin_path = os.path.join(CUCKOO_ROOT, "storage", "binaries", sample_sha256) if sample_sha256 else None + if bin_path and path_exists(bin_path): + log.info("Task id: %d - Target file not found at original path, but found in binaries storage: %s. Updating target path.", t.id, bin_path) + t.target = bin_path + else: + log.info("Task id: %d - File doesn't exist: %s", t.id, t.target) + main_db.set_status(t.id, TASK_BANNED) + continue if not web_conf.general.allow_ignore_size and "ignore_size_check" not in t.options: # We can't upload size bigger than X to our workers. In case we extract archive that contains bigger file. file_size = path_get_size(t.target)