Fix fuzzer-runner missing transitive dependency and add tests (#459)

* Use openlit <1.36.6

Openlit >=1.36.6 has a bug with langgraph instrumentation.

Also add a test to seed-gen for when openlit is enabled

* Link to issue

* Fix CoverageBot.run_task and add test cases

* Add setuptools as an explicit dependency

This is because a transitive dependency via clusterfuzz depends on it

* Appease ruff
This commit is contained in:
Ronald Eytchison
2026-01-27 17:13:53 -05:00
committed by GitHub
parent e826b53530
commit 3c3ae36a11
4 changed files with 95 additions and 2 deletions
+1
View File
@@ -9,6 +9,7 @@ dependencies = [
"common",
"clusterfuzz ==2.6.0",
"pydantic ~=2.11.7",
"setuptools", # Required for pkg_resources used by google-cloud-ndb (clusterfuzz dep)
]
[project.urls]
-2
View File
@@ -1,2 +0,0 @@
def test_empty():
pass
+83
View File
@@ -0,0 +1,83 @@
"""Tests for the fuzzer runner module."""
from unittest.mock import MagicMock, patch
from buttercup.fuzzer_runner.runner import Conf, Runner
class TestRunner:
"""Tests for the Runner class."""
@patch("buttercup.fuzzer_runner.runner.patched_temp_dir")
@patch("buttercup.fuzzer_runner.runner.scratch_cwd")
@patch("os.makedirs")
def test_run_fuzzer_initializes_engine(self, mock_makedirs, mock_scratch_cwd, mock_patched_temp_dir):
"""Test run_fuzzer"""
from buttercup.common.types import FuzzConfiguration
from clusterfuzz._internal.bot.fuzzers.libFuzzer import engine as libfuzzer_engine
mock_patched_temp_dir.return_value.__enter__ = MagicMock()
mock_patched_temp_dir.return_value.__exit__ = MagicMock(return_value=False)
mock_scratch_cwd.return_value.__enter__ = MagicMock()
mock_scratch_cwd.return_value.__exit__ = MagicMock(return_value=False)
# Mock the engine methods that would fail without a real fuzzer binary
mock_opts = MagicMock()
mock_opts.corpus_dir = "/corpus"
mock_opts.arguments = []
mock_opts.strategies = []
mock_result = MagicMock()
mock_result.crashes = []
mock_result.logs = "test"
mock_result.stats = {}
mock_result.time_executed = 1.0
mock_result.timed_out = False
with (
patch.object(libfuzzer_engine.Engine, "prepare", return_value=mock_opts),
patch.object(libfuzzer_engine.Engine, "fuzz", return_value=mock_result),
):
conf = Conf(timeout=60)
runner = Runner(conf)
fuzzconf = FuzzConfiguration(
corpus_dir="/corpus",
target_path="/target",
engine="libfuzzer",
sanitizer="address",
)
result = runner.run_fuzzer(fuzzconf)
assert result.crashes == []
assert result.timed_out is False
@patch("buttercup.fuzzer_runner.runner.scratch_dir")
@patch("buttercup.fuzzer_runner.runner.patched_temp_dir")
@patch("buttercup.fuzzer_runner.runner.scratch_cwd")
def test_merge_corpus_initializes_engine(self, mock_scratch_cwd, mock_patched_temp_dir, mock_scratch_dir):
"""Test merge_corpus."""
from buttercup.common.types import FuzzConfiguration
from clusterfuzz._internal.bot.fuzzers.libFuzzer import engine as libfuzzer_engine
mock_patched_temp_dir.return_value.__enter__ = MagicMock()
mock_patched_temp_dir.return_value.__exit__ = MagicMock(return_value=False)
mock_scratch_cwd.return_value.__enter__ = MagicMock()
mock_scratch_cwd.return_value.__exit__ = MagicMock(return_value=False)
mock_td = MagicMock()
mock_td.path = "/tmp/scratch"
mock_scratch_dir.return_value.__enter__ = MagicMock(return_value=mock_td)
mock_scratch_dir.return_value.__exit__ = MagicMock(return_value=False)
with patch.object(libfuzzer_engine.Engine, "minimize_corpus"):
conf = Conf(timeout=60)
runner = Runner(conf)
fuzzconf = FuzzConfiguration(
corpus_dir="/corpus",
target_path="/target",
engine="libfuzzer",
sanitizer="address",
)
runner.merge_corpus(fuzzconf, "/output")
+11
View File
@@ -264,6 +264,7 @@ dependencies = [
{ name = "clusterfuzz" },
{ name = "common" },
{ name = "pydantic" },
{ name = "setuptools" },
]
[package.dev-dependencies]
@@ -281,6 +282,7 @@ requires-dist = [
{ name = "clusterfuzz", specifier = "==2.6.0" },
{ name = "common", editable = "../common" },
{ name = "pydantic", specifier = "~=2.11.7" },
{ name = "setuptools" },
]
[package.metadata.requires-dev]
@@ -1252,6 +1254,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" },
]
[[package]]
name = "setuptools"
version = "80.10.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/76/95/faf61eb8363f26aa7e1d762267a8d602a1b26d4f3a1e758e92cb3cb8b054/setuptools-80.10.2.tar.gz", hash = "sha256:8b0e9d10c784bf7d262c4e5ec5d4ec94127ce206e8738f29a437945fbc219b70", size = 1200343, upload-time = "2026-01-25T22:38:17.252Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl", hash = "sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173", size = 1064234, upload-time = "2026-01-25T22:38:15.216Z" },
]
[[package]]
name = "six"
version = "1.17.0"