From 564622872b8144026996168ee725c669f7f0d363 Mon Sep 17 00:00:00 2001 From: jonathanmetzman <31354670+jonathanmetzman@users.noreply.github.com> Date: Thu, 26 Dec 2024 09:08:29 -0500 Subject: [PATCH] Fix OSS-fuzz builds status reporting. (#4378) (#4538) There were some hardcoded constants that needed to be updated for the Google Issue Tracker migration. We'll also stop adding the 'Project' custom field for now, because it's hard to propagate custom field values and it's not essential for build failure issues. This should hopefully fix https://github.com/google/oss-fuzz/issues/12536#issuecomment-2447332796. Cherry-pick of #4378 Co-authored-by: Oliver Chang --- .../_internal/cron/oss_fuzz_build_status.py | 18 +++-- .../cron/oss_fuzz_build_status_test.py | 65 +++++++++++++++++-- 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/clusterfuzz/_internal/cron/oss_fuzz_build_status.py b/src/clusterfuzz/_internal/cron/oss_fuzz_build_status.py index 887a950b48..38147fdb44 100644 --- a/src/clusterfuzz/_internal/cron/oss_fuzz_build_status.py +++ b/src/clusterfuzz/_internal/cron/oss_fuzz_build_status.py @@ -22,6 +22,7 @@ from clusterfuzz._internal.base import utils from clusterfuzz._internal.datastore import data_types +from clusterfuzz._internal.issue_management import issue_tracker_policy from clusterfuzz._internal.issue_management import issue_tracker_utils from clusterfuzz._internal.metrics import logs @@ -135,7 +136,7 @@ def get_build_time(build): stripped_timestamp.group(0), TIMESTAMP_FORMAT) -def file_bug(issue_tracker, project_name, build_id, ccs, build_type): +def file_bug(issue_tracker, policy, project_name, build_id, ccs, build_type): """File a new bug for a build failure.""" logs.info('Filing bug for new build failure (project=%s, build_type=%s, ' 'build_id=%s).' % (project_name, build_type, build_id)) @@ -144,8 +145,7 @@ def file_bug(issue_tracker, project_name, build_id, ccs, build_type): issue.title = '{project_name}: {build_type} build failure'.format( project_name=project_name, build_type=build_type.capitalize()) issue.body = _get_issue_body(project_name, build_id, build_type) - issue.status = 'New' - issue.labels.add('Proj-' + project_name) + issue.status = policy.status('new') for cc in ccs: issue.ccs.add(cc) @@ -154,13 +154,13 @@ def file_bug(issue_tracker, project_name, build_id, ccs, build_type): return str(issue.id) -def close_bug(issue_tracker, issue_id, project_name): +def close_bug(issue_tracker, policy, issue_id, project_name): """Close a build failure bug.""" logs.info('Closing build failure bug (project=%s, issue_id=%s).' % (project_name, issue_id)) issue = issue_tracker.get_original_issue(issue_id) - issue.status = 'Fixed' + issue.status = policy.status('verified') issue.save( new_comment='The latest build has succeeded, closing this issue.', notify=True) @@ -184,6 +184,8 @@ def _close_fixed_builds(projects, build_type): if not issue_tracker: raise OssFuzzBuildStatusError('Failed to get issue tracker.') + policy = issue_tracker_policy.get('oss-fuzz') + for project in projects: project_name = project['name'] builds = project['history'] @@ -205,7 +207,7 @@ def _close_fixed_builds(projects, build_type): continue if build_failure.issue_id is not None: - close_bug(issue_tracker, build_failure.issue_id, project_name) + close_bug(issue_tracker, policy, build_failure.issue_id, project_name) close_build_failure(build_failure) @@ -216,6 +218,8 @@ def _process_failures(projects, build_type): if not issue_tracker: raise OssFuzzBuildStatusError('Failed to get issue tracker.') + policy = issue_tracker_policy.get('oss-fuzz') + for project in projects: project_name = project['name'] builds = project['history'] @@ -255,7 +259,7 @@ def _process_failures(projects, build_type): 'Project %s is disabled, skipping bug filing.' % project_name) continue - build_failure.issue_id = file_bug(issue_tracker, project_name, + build_failure.issue_id = file_bug(issue_tracker, policy, project_name, build['build_id'], oss_fuzz_project.ccs, build_type) elif (build_failure.consecutive_failures - diff --git a/src/clusterfuzz/_internal/tests/appengine/handlers/cron/oss_fuzz_build_status_test.py b/src/clusterfuzz/_internal/tests/appengine/handlers/cron/oss_fuzz_build_status_test.py index 30faf9cb31..b13bacf884 100644 --- a/src/clusterfuzz/_internal/tests/appengine/handlers/cron/oss_fuzz_build_status_test.py +++ b/src/clusterfuzz/_internal/tests/appengine/handlers/cron/oss_fuzz_build_status_test.py @@ -20,11 +20,66 @@ from clusterfuzz._internal.cron import oss_fuzz_build_status from clusterfuzz._internal.datastore import data_types +from clusterfuzz._internal.issue_management import issue_tracker_policy from clusterfuzz._internal.issue_management import monorail from clusterfuzz._internal.issue_management.monorail.issue import Issue from clusterfuzz._internal.tests.test_libs import helpers as test_helpers from clusterfuzz._internal.tests.test_libs import test_utils +OSS_FUZZ_POLICY = issue_tracker_policy.IssueTrackerPolicy({ + 'status': { + 'assigned': 'Assigned', + 'duplicate': 'Duplicate', + 'verified': 'Verified', + 'new': 'New', + 'wontfix': 'WontFix', + 'fixed': 'Fixed' + }, + 'all': { + 'status': 'new', + 'labels': ['ClusterFuzz', 'Stability-%SANITIZER%'], + 'issue_body_footer': + 'When you fix this bug, please\n' + ' * mention the fix revision(s).\n' + ' * state whether the bug was a short-lived regression or an old ' + 'bug in any stable releases.\n' + ' * add any other useful information.\n' + 'This information can help downstream consumers.\n\n' + 'If you need to contact the OSS-Fuzz team with a question, ' + 'concern, or any other feedback, please file an issue at ' + 'https://github.com/google/oss-fuzz/issues.' + }, + 'non_security': { + 'labels': ['Type-Bug'] + }, + 'labels': { + 'ignore': 'ClusterFuzz-Ignore', + 'verified': 'ClusterFuzz-Verified', + 'security_severity': 'Security_Severity-%SEVERITY%', + 'needs_feedback': 'Needs-Feedback', + 'invalid_fuzzer': 'ClusterFuzz-Invalid-Fuzzer', + 'reported': 'Reported-%YYYY-MM-DD%', + 'wrong': 'ClusterFuzz-Wrong', + 'fuzz_blocker': 'Fuzz-Blocker', + 'reproducible': 'Reproducible', + 'auto_cc_from_owners': 'ClusterFuzz-Auto-CC', + 'os': 'OS-%PLATFORM%', + 'unreproducible': 'Unreproducible', + 'restrict_view': 'Restrict-View-Commit' + }, + 'security': { + 'labels': ['Type-Bug-Security'] + }, + 'deadline_policy_message': + 'This bug is subject to a 90 day disclosure deadline. If 90 days ' + 'elapse\n' + 'without an upstream patch, then the bug report will automatically\n' + 'become visible to the public.', + 'existing': { + 'labels': ['Stability-%SANITIZER%'] + } +}) + class MockResponse: """Mock url request's response.""" @@ -67,6 +122,8 @@ def setUp(self): test_helpers.patch(self, [ 'clusterfuzz._internal.base.utils.utcnow', 'handlers.base_handler.Handler.is_cron', + ('policy_get', + 'clusterfuzz._internal.issue_management.issue_tracker_policy.get'), 'clusterfuzz._internal.issue_management.issue_tracker_utils.get_issue_tracker', 'clusterfuzz._internal.metrics.logs.error', 'requests.get', @@ -77,6 +134,7 @@ def setUp(self): self.itm = IssueTrackerManager('oss-fuzz') self.mock.get_issue_tracker.return_value = monorail.IssueTracker(self.itm) + self.mock.policy_get.return_value = OSS_FUZZ_POLICY self.maxDiff = None @@ -386,8 +444,6 @@ def _mock_requests_get(url, timeout=None): '**This bug will be automatically closed within a ' 'day once it is fixed.**', issue.body) - self.assertTrue(issue.has_label('Proj-proj2')) - issue = self.itm.issues[2] self.assertCountEqual(['b@user.com'], issue.cc) self.assertEqual('New', issue.status) @@ -407,8 +463,6 @@ def _mock_requests_get(url, timeout=None): '**This bug will be automatically closed within a ' 'day once it is fixed.**', issue.body) - self.assertTrue(issue.has_label('Proj-proj6')) - def test_recovered_build_failure(self): """Test fixed build failures.""" # Use the same status for all build types. @@ -436,7 +490,6 @@ def test_recovered_build_failure(self): issue = Issue() issue.open = True issue.add_label('Type-Build-Failure') - issue.add_label('Proj-proj2') issue.summary = 'Build failure in proj2' issue.body = 'Build failure' @@ -446,7 +499,7 @@ def test_recovered_build_failure(self): self.assertEqual(0, data_types.OssFuzzBuildFailure.query().count()) issue = self.itm.issues[1] - self.assertEqual('Fixed', issue.status) + self.assertEqual('Verified', issue.status) self.assertEqual('The latest build has succeeded, closing this issue.', issue.comment)