From 8d2a70ad76dd791a1f26c4c98f2e2073c9694f3f Mon Sep 17 00:00:00 2001 From: Paulo Borges Date: Wed, 17 Jun 2026 16:05:22 +0000 Subject: [PATCH 1/2] Add checkbox and new field 'untrusted' in fuzzer --- src/appengine/handlers/fuzzers.py | 12 ++++ .../components/fuzzers-page/edit-form.html | 10 ++- .../_internal/datastore/data_types.py | 3 + .../tests/appengine/handlers/fuzzers_test.py | 66 +++++++++++++++++++ .../tests/core/datastore/data_types_test.py | 1 + 5 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/appengine/handlers/fuzzers.py b/src/appengine/handlers/fuzzers.py index e1f5e1e1466..af09eec9649 100644 --- a/src/appengine/handlers/fuzzers.py +++ b/src/appengine/handlers/fuzzers.py @@ -174,6 +174,7 @@ def apply_fuzzer_changes(self, fuzzer, upload_info): timeout = self._get_integer_value('timeout') max_testcases = self._get_integer_value('max_testcases') external_contribution = request.get('external_contribution', False) + untrusted = request.get('untrusted', False) differential = request.get('differential', False) environment_string = request.get('additional_environment_string') data_bundle_name = request.get('data_bundle_name') @@ -193,6 +194,7 @@ def apply_fuzzer_changes(self, fuzzer, upload_info): fuzzer.sample_testcase = None fuzzer.console_output = None fuzzer.external_contribution = bool(external_contribution) + fuzzer.untrusted = bool(untrusted) fuzzer.differential = bool(differential) fuzzer.additional_environment_string = environment_string fuzzer.timestamp = datetime.datetime.now(tz=datetime.timezone.utc).replace( @@ -208,6 +210,16 @@ def apply_fuzzer_changes(self, fuzzer, upload_info): if launcher_script: fuzzer.launcher_script = launcher_script + if fuzzer.untrusted: + for job_name in jobs: + job = data_types.Job.query(data_types.Job.name == job_name).get() + if not job: + raise helpers.EarlyExitError(f'Job {job_name} not found.', 400) + if job.platform.lower() != 'linux': + raise helpers.EarlyExitError( + f'Untrusted fuzzers can only be run on Linux jobs. ' + f'Job "{job_name}" has platform "{job.platform}".', 400) + fuzzer.put() fuzzer_selection.update_mappings_for_fuzzer(fuzzer) diff --git a/src/appengine/private/components/fuzzers-page/edit-form.html b/src/appengine/private/components/fuzzers-page/edit-form.html index fb1e41886e8..e1aa340fa49 100644 --- a/src/appengine/private/components/fuzzers-page/edit-form.html +++ b/src/appengine/private/components/fuzzers-page/edit-form.html @@ -220,11 +220,16 @@
External contribution +
+
+ Untrusted +
- + --> Date: Wed, 17 Jun 2026 18:22:01 +0000 Subject: [PATCH 2/2] Mark testcases as untrusted if generated by untrusted fuzzers --- .../_internal/bot/tasks/utasks/fuzz_task.py | 10 ++++- .../core/bot/tasks/utasks/fuzz_task_test.py | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/clusterfuzz/_internal/bot/tasks/utasks/fuzz_task.py b/src/clusterfuzz/_internal/bot/tasks/utasks/fuzz_task.py index ff00797df65..8206d6056cc 100644 --- a/src/clusterfuzz/_internal/bot/tasks/utasks/fuzz_task.py +++ b/src/clusterfuzz/_internal/bot/tasks/utasks/fuzz_task.py @@ -1049,6 +1049,14 @@ def create_testcase(group: uworker_msg_pb2.FuzzTaskCrashGroup, comment = (f'Fuzzer {fully_qualified_fuzzer_name} generated testcase crashed ' f'in {crash.crash_time} seconds ' f'(r{fuzz_task_output.crash_revision})') + + is_trusted = True + if uworker_input.setup_input.HasField('fuzzer'): + fuzzer = uworker_io.entity_from_protobuf(uworker_input.setup_input.fuzzer, + data_types.Fuzzer) + if fuzzer.untrusted: + is_trusted = False + testcase_id = data_handler.store_testcase( crash=crash, fuzzed_keys=crash.fuzzed_key or None, @@ -1074,7 +1082,7 @@ def create_testcase(group: uworker_msg_pb2.FuzzTaskCrashGroup, minimized_arguments=crash.arguments, # TODO(https://github.com/google/clusterfuzz/issues/4175): Before enabling # oss-fuzz-on-demand change this. - trusted=True) + trusted=is_trusted) testcase = data_handler.get_testcase_by_id(testcase_id) events.emit( events.TestcaseCreationEvent( diff --git a/src/clusterfuzz/_internal/tests/core/bot/tasks/utasks/fuzz_task_test.py b/src/clusterfuzz/_internal/tests/core/bot/tasks/utasks/fuzz_task_test.py index 640d6057457..d057f228ddc 100644 --- a/src/clusterfuzz/_internal/tests/core/bot/tasks/utasks/fuzz_task_test.py +++ b/src/clusterfuzz/_internal/tests/core/bot/tasks/utasks/fuzz_task_test.py @@ -1762,6 +1762,48 @@ def test_create_testcase_event_emit(self): creation_origin=events.TestcaseOrigin.FUZZ_TASK, uploader=None)) + def test_create_testcase_trusted_fuzzer(self): + """Test creating a testcase with a trusted fuzzer.""" + fuzzer = data_types.Fuzzer(name='engine', untrusted=False) + fuzzer.put() + + self.uworker_input.setup_input.CopyFrom(uworker_msg_pb2.SetupInput()) + self.uworker_input.setup_input.fuzzer.CopyFrom( + uworker_io.entity_to_protobuf(fuzzer)) + + self.mock.store_testcase.side_effect = _store_generic_testcase + + fuzz_task.create_testcase( + group=self.group, + uworker_input=self.uworker_input, + uworker_output=self.uworker_output, + fully_qualified_fuzzer_name='engine') + + self.mock.store_testcase.assert_called_once() + kwargs = self.mock.store_testcase.call_args[1] + self.assertTrue(kwargs.get('trusted')) + + def test_create_testcase_untrusted_fuzzer(self): + """Test creating a testcase with an untrusted fuzzer.""" + fuzzer = data_types.Fuzzer(name='engine', untrusted=True) + fuzzer.put() + + self.uworker_input.setup_input.CopyFrom(uworker_msg_pb2.SetupInput()) + self.uworker_input.setup_input.fuzzer.CopyFrom( + uworker_io.entity_to_protobuf(fuzzer)) + + self.mock.store_testcase.side_effect = _store_generic_testcase + + fuzz_task.create_testcase( + group=self.group, + uworker_input=self.uworker_input, + uworker_output=self.uworker_output, + fully_qualified_fuzzer_name='engine') + + self.mock.store_testcase.assert_called_once() + kwargs = self.mock.store_testcase.call_args[1] + self.assertFalse(kwargs.get('trusted')) + def _store_generic_testcase(*args, **kwargs): # pylint: disable=unused-argument """Store a generic testcase and return its id."""