Skip to content

Fix UI form parsing that created invalid FuzzerJob entries#5381

Merged
dylanjew merged 2 commits into
masterfrom
dylanj/jobs-ui-fix
Jul 24, 2026
Merged

Fix UI form parsing that created invalid FuzzerJob entries#5381
dylanjew merged 2 commits into
masterfrom
dylanj/jobs-ui-fix

Conversation

@dylanjew

@dylanjew dylanjew commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

The /jobs form submission retrieved 'fuzzers' as a string and blindly called .split(','), meaning an empty field evaluated as [''] instead of [].

I tested in dev and the browser is actually sending a POST with the fuzzer key, i.e. ...&fuzzers=&description=... which results in an empty string fuzzers= "" in Flask . Since there is a value "", this overrides the default []

This fuzzers value of [''] leads to the creation of invalid FuzzerJob entries in Datastore with fuzzer=""

This updates the form ingestion to correctly ignore missing values as an empty list.

Testing

I verified this with the unit test by reverting the PR back to the old behavior:

Traceback (most recent call last):
  File "/workspaces/clusterfuzz/src/clusterfuzz/_internal/tests/appengine/handlers/jobs_test.py", line 240, in test_post_empty_fuzzers
    self.mock.update_mappings_for_job.assert_called_with(mock.ANY, [])
  File "/usr/local/python/current/lib/python3.11/unittest/mock.py", line 212, in assert_called_with
    return mock.assert_called_with(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/python/current/lib/python3.11/unittest/mock.py", line 939, in assert_called_with
    raise AssertionError(_error_message()) from cause
AssertionError: expected call not found.
Expected: update_mappings_for_job(<ANY>, [])
  Actual: update_mappings_for_job(Job(key=Key('Job', 1), base_os_version=None, custom_binary_filename=None, custom_binary_key=None, custom_binary_revision=None, description='', environment_string='', external_reproduction_topic=None, external_updates_subscription=None, keywords=['job', 'test_job', 'test', 'project', 'test-project'], name='test_job', platform='LINUX', project='test-project', templates=[]), [''])

The last parameter in the assert is the fuzzers ['']. We're passing an empty string into the list of fuzzers to map to the job

dev:

  • Verify in dev via the Jobs UI
  1. Create a FuzzerJob in dev by enabling the libfuzzer Fuzzer on the libfuzzer_chrome_asan_highend job in dev.
  2. Disable the Fuzzer by unchecking libfuzzer, then querying the Datastore to verify no dangling FuzzerJob was created with fuzzer='' SELECT * FROM FuzzerJob where job = 'libfuzzer_chrome_asan_highend'

@dylanjew
dylanjew requested a review from a team as a code owner July 23, 2026 17:11
@dylanjew
dylanjew force-pushed the dylanj/jobs-ui-fix branch from 896ff4a to a3d4d16 Compare July 23, 2026 17:12
@dylanjew dylanjew changed the title Fix UI form parsing that created ghost fuzzer entries Fix UI form parsing that created invalid FuzzerJob Jul 23, 2026
@dylanjew dylanjew changed the title Fix UI form parsing that created invalid FuzzerJob Fix UI form parsing that created invalid FuzzerJob entries Jul 23, 2026
@dylanjew
dylanjew requested a review from vitaliset July 23, 2026 17:16
@dylanjew
dylanjew force-pushed the dylanj/jobs-ui-fix branch from a3d4d16 to 562f99c Compare July 23, 2026 18:39
The /jobs form submission retrieved 'fuzzers' as a string and blindly called .split(','), meaning an empty field evaluated as [''] instead of []. This string parsed as a valid mapping attempt for a fuzzer named "", leading to the creation of orphaned FuzzerJob entries in Datastore.

This updates the form ingestion to correctly coerce missing values to an empty list.

A follow up commit will sweep Datastore to remove any existing ghost mappings.

TAG=agy
CONV=b5fdacea-8cda-4418-8906-dee99c91f929
@dylanjew
dylanjew force-pushed the dylanj/jobs-ui-fix branch from 562f99c to a048d85 Compare July 23, 2026 21:20
@dylanjew
dylanjew requested a review from g-ortuno July 24, 2026 14:29
@g-ortuno

Copy link
Copy Markdown
Collaborator

Making sure I understand the high level stuff: at some point we had a valid libfuzzer_chrome_asan_highend FuzzerJob with fuzzer = 'libfuzzer'. Since we can't remove jobs, we decided to uncheck the fuzzer from the UI instead. This triggered the bug this PR is addressing. We removed the FuzzerJob with fuzzer = 'libfuzzer' and added a new FuzzerJob with fuzzer = ''. This shouldn't have happened but we have a Fuzzer with an empty name.

This PR is addressing the issue, so when we uncheck all the boxes, we correctly pass an empty fuzzers list to the update_mappings_for_job() and we don't create invalid FuzzerJobs. Is that right? If so lgtm!

In http://b/538130903#comment17 you mentioned that the UI doesn't let you an invalid entity. That was the invalid Fuzzer with the empty name, right?

@dylanjew

Copy link
Copy Markdown
Collaborator Author

Making sure I understand the high level stuff: at some point we had a valid libfuzzer_chrome_asan_highend FuzzerJob with fuzzer = 'libfuzzer'. Since we can't remove jobs, we decided to uncheck the fuzzer from the UI instead. This triggered the bug this PR is addressing. We removed the FuzzerJob with fuzzer = 'libfuzzer' and added a new FuzzerJob with fuzzer = ''. This shouldn't have happened but we have a Fuzzer with an empty name.

This PR is addressing the issue, so when we uncheck all the boxes, we correctly pass an empty fuzzers list to the update_mappings_for_job() and we don't create invalid FuzzerJobs. Is that right? If so lgtm!

Yes, that's correct!

In http://b/538130903#comment17 you mentioned that the UI doesn't let you an invalid entity. That was the invalid Fuzzer with the empty name, right?

Yeah, the invalid Fuzzer is showing up in the https://clusterfuzz.com/fuzzers page but I couldn't disable the jobs from that UI. I opened crbug.com/538684224 to fix that Fuzzer

@dylanjew
dylanjew merged commit 43e1451 into master Jul 24, 2026
15 checks passed
@dylanjew
dylanjew deleted the dylanj/jobs-ui-fix branch July 24, 2026 21:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants