Skip to content
2 changes: 2 additions & 0 deletions src/appengine/handlers/fuzzers.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def apply_fuzzer_changes(self, fuzzer, upload_info):
differential = request.get('differential', False)
environment_string = request.get('additional_environment_string')
data_bundle_name = request.get('data_bundle_name')
primary_owner = request.get('primary_owner')

# Save the fuzzer file metadata.
if upload_info:
Expand All @@ -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.primary_owner = primary_owner
Comment thread
jr2bg marked this conversation as resolved.
fuzzer.differential = bool(differential)
fuzzer.additional_environment_string = environment_string
fuzzer.timestamp = datetime.datetime.now(tz=datetime.timezone.utc).replace(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@
title="Name of fuzzer. Allowed characters include letters, numbers, dashes and underscores.">
</paper-input>
</div>
<div class="inline narrow">
<paper-input
label="Primary owner (email)"
value="{{fuzzer.primary_owner}}"
title="Primary owner for VRP rewards.">
</paper-input>
</div>
<div class="inline narrow">
<paper-menu-button
class="job-select dropdown-filter"
Expand Down Expand Up @@ -252,6 +259,7 @@
'differential',
'executable_path',
'external_contribution',
'primary_owner',
'jobs',
'launcher_script',
'max_testcases',
Expand Down
3 changes: 3 additions & 0 deletions src/clusterfuzz/_internal/datastore/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ class Fuzzer(Model):
# reward flags.
external_contribution = ndb.BooleanProperty(default=False)

# Primary owner to be reported for bugs filed by CF
primary_owner = ndb.StringProperty()

# Max testcases to generate for this fuzzer.
max_testcases = ndb.IntegerProperty()

Expand Down
10 changes: 7 additions & 3 deletions src/clusterfuzz/_internal/issue_management/issue_filer.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ def file_issue(testcase,
logs.info(f'Filing new issue for testcase: {testcase.key.id()}.')

policy = issue_tracker_policy.get(issue_tracker.project)
fuzzer = data_types.Fuzzer.query(
data_types.Fuzzer.name == testcase.fuzzer_name).get()

is_crash = not utils.sub_string_exists_in(NON_CRASH_TYPES,
testcase.crash_type)
properties = policy.get_new_issue_properties(
Expand All @@ -343,8 +346,6 @@ def file_issue(testcase,
if issue_tracker.project in ('chromium', 'chromium-testing'):
if testcase.security_flag:
# Add reward labels if this is from an external fuzzer contribution.
fuzzer = data_types.Fuzzer.query(
data_types.Fuzzer.name == testcase.fuzzer_name).get()
if fuzzer and fuzzer.external_contribution:
issue.labels.add(policy.substitution_mapping('reward-topanel'))
issue.labels.add(
Expand Down Expand Up @@ -482,7 +483,10 @@ def file_issue(testcase,
testcase.one_time_crasher_flag and policy.unreproducible_component):
issue.components.add(policy.unreproducible_component)

issue.reporter = user_email
if fuzzer and fuzzer.primary_owner:
issue.reporter = fuzzer.primary_owner

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We sometimes use the reporter to determine whether clusterfuzz filed the bug. Is there another place where we are setting metadata of some kind, e.g. a label/hotlist that stays on the bug so that we can continue to track clusterfuzz filed bugs?

else:
issue.reporter = user_email

if issue_tracker.project in ('chromium', 'chromium-testing'):
logs.info(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def test_update_fuzzer(self):
'csrf_token': form.generate_csrf_token(),
'data_bundle_name': 'test_bundle',
'external_contribution': True,
'primary_owner': 'owner@example.com',
'jobs': [],
'key': fuzzer.key.id(),
'max_testcases': 100,
Expand All @@ -179,6 +180,7 @@ def test_update_fuzzer(self):
'additional_environment_string': 'args=123',
'data_bundle_name': 'test_bundle',
'external_contribution': True,
'primary_owner': 'owner@example.com',
'executable_path': 'executable',
'last_edited_by': 'editor@example.com',
'launcher_script': 'launcher',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,71 @@ def test_filed_issues_oss_fuzz_disable_disclose(self):
self.assertIn(FIX_NOTE, issue_tracker._itm.last_issue.body)
self.assertIn(QUESTIONS_NOTE, issue_tracker._itm.last_issue.body)

def test_filed_issues_external_fuzzer_author(self):
"""Tests issue filing for external fuzzer author."""
self.mock.get.return_value = CHROMIUM_POLICY

data_types.Fuzzer(
name='fuzzer',
external_contribution=True,
primary_owner='owner@example.com').put()

mock_client = mock.Mock()
issue_tracker = google_issue_tracker.IssueTracker('chromium', mock_client, {
'default_component_id': '123',
'url': 'mock'
})

issue_tracker._execute = mock.Mock(return_value={
'issueId': 12345,
'issueState': {
'componentId': '123',
'type': 'BUG',
},
})

self.testcase1.security_flag = True
self.testcase1.put()

issue_filer.file_issue(
self.testcase1, issue_tracker, user_email='reporter@example.com')

mock_create = mock_client.issues.return_value.create
body = mock_create.call_args[1]['body']
self.assertEqual('owner@example.com',
body['issueState']['reporter']['emailAddress'])

def test_filed_issues_external_fuzzer_no_author(self):
"""Tests issue filing for external fuzzer without author."""
self.mock.get.return_value = CHROMIUM_POLICY

data_types.Fuzzer(name='fuzzer', external_contribution=True).put()

mock_client = mock.Mock()
issue_tracker = google_issue_tracker.IssueTracker('chromium', mock_client, {
'default_component_id': '123',
'url': 'mock'
})

issue_tracker._execute = mock.Mock(return_value={
'issueId': 12345,
'issueState': {
'componentId': '123',
'type': 'BUG',
},
})

self.testcase1.security_flag = True
self.testcase1.put()

issue_filer.file_issue(
self.testcase1, issue_tracker, user_email='reporter@example.com')

mock_create = mock_client.issues.return_value.create
body = mock_create.call_args[1]['body']
self.assertEqual('reporter@example.com',
body['issueState']['reporter']['emailAddress'])

def test_testcase_metadata_labels_and_components(self):
"""Tests issue filing with additional labels and components."""
self.mock.get.return_value = CHROMIUM_POLICY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def test_get_config_dict(self):
'revision': 3,
'source': 'author',
'last_edited_by': 'editor',
'primary_owner': None,
},
config_dict,
)
Expand Down
Loading