def find_issues_url(self, keywords=None, only_open=None): search_text = 'project = {project_name}' + _get_search_text(keywords) search_text = search_text.format(project_name=self._itm.project_name) if only_open: search_text += ' AND resolution = Unresolved' config = db_config.get() return urljoin(config.jira_url, f'/issues/?jql={search_text}')
def _create_client(self): """Return a client object for querying the issue tracker.""" config = db_config.get() credentials = json.loads(config.jira_credentials) jira_url = config.jira_url jira_client = jira.JIRA(jira_url, auth=(credentials['username'], credentials['password'])) return jira_client
def issue_url(self, issue_id): """Return the issue URL with the given ID.""" issue = self.get_issue(issue_id) if not issue: return None config = db_config.get() url = urljoin(config.jira_url, f'/browse/{str(issue.key)}') return url
def configure(force_enable=False): """Configure airplane mode and wifi on device.""" # The reproduce tool shouldn't inherit wifi settings from jobs. if environment.get_value('REPRODUCE_TOOL'): return # Airplane mode should be disabled in all cases. This can get inadvertently # turned on via gestures. disable_airplane_mode() # Need to disable wifi before changing configuration. disable() # Check if wifi needs to be enabled. If not, then no need to modify the # supplicant file. wifi_enabled = force_enable or environment.get_value('WIFI', True) if not wifi_enabled: # No more work to do, we already disabled it at start. return # Wait 2 seconds to allow the wifi to be enabled. enable() time.sleep(2) # Install helper apk to configure wifi. wifi_util_apk_path = os.path.join( environment.get_platform_resources_directory(), 'wifi_util.apk') if not app.is_installed(WIFI_UTIL_PACKAGE_NAME): app.install(wifi_util_apk_path) # Get ssid and password from admin configuration. if environment.is_android_cuttlefish(): wifi_ssid = 'VirtWifi' wifi_password = '' else: config = db_config.get() if not config.wifi_ssid: logs.log('No wifi ssid is set, skipping wifi config.') return wifi_ssid = config.wifi_ssid wifi_password = config.wifi_password or '' connect_wifi_command = ( 'am instrument -e method connectToNetwork -e ssid {ssid} ') if wifi_password: connect_wifi_command += '-e psk {password} ' connect_wifi_command += '-w {call_path}' output = adb.run_shell_command( connect_wifi_command.format(ssid=quote(wifi_ssid), password=quote(wifi_password), call_path=WIFI_UTIL_CALL_PATH)) if 'result=true' not in output: logs.log_warn('Failed to connect to wifi.', output=output)
def can_user_access_testcase(testcase): """Checks if the current user can access the testcase.""" config = db_config.get() need_privileged_access = (testcase.security_flag and not config.relax_security_bug_restrictions) if has_access(fuzzer_name=testcase.actual_fuzzer_name(), job_type=testcase.job_type, need_privileged_access=need_privileged_access): return True user_email = helpers.get_user_email() if testcase.uploader_email and testcase.uploader_email == user_email: return True # Allow owners of bugs to see associated test cases and test case groups. issue_id = testcase.bug_information or testcase.group_bug_information if not issue_id: return False issue_tracker = issue_tracker_utils.get_issue_tracker_for_testcase( testcase) associated_issue = issue_tracker.get_issue(issue_id) if not associated_issue: return False # Look at both associated issue and original issue (if the associated one # is a duplicate of the original issue). issues_to_check = [associated_issue] if associated_issue.merged_into: original_issue = issue_tracker.get_original_issue(issue_id) if original_issue: issues_to_check.append(original_issue) relaxed_restrictions = (config.relax_testcase_restrictions or _is_domain_allowed(user_email)) for issue in issues_to_check: if relaxed_restrictions: if (any(utils.emails_equal(user_email, cc) for cc in issue.ccs) or utils.emails_equal(user_email, issue.assignee) or utils.emails_equal(user_email, issue.reporter)): return True elif utils.emails_equal(user_email, issue.assignee): return True return False
def add_test_accounts_if_needed(): """Add test account to work with GmsCore, etc.""" last_test_account_check_time = persistent_cache.get_value( constants.LAST_TEST_ACCOUNT_CHECK_KEY, constructor=datetime.datetime.utcfromtimestamp) needs_test_account_update = (last_test_account_check_time is None or dates.time_has_expired( last_test_account_check_time, seconds=ADD_TEST_ACCOUNT_CHECK_INTERVAL)) if not needs_test_account_update: return config = db_config.get() if not config: return test_account_email = config.test_account_email test_account_password = config.test_account_password if not test_account_email or not test_account_password: return adb.run_as_root() wifi.configure(force_enable=True) if not app.is_installed(ADD_TEST_ACCOUNT_PKG_NAME): logs.log('Installing helper apk for adding test account.') android_directory = environment.get_platform_resources_directory() add_test_account_apk_path = os.path.join(android_directory, ADD_TEST_ACCOUNT_APK_NAME) app.install(add_test_account_apk_path) logs.log('Trying to add test account.') output = adb.run_shell_command( 'am instrument -e account %s -e password %s -w %s' % (test_account_email, test_account_password, ADD_TEST_ACCOUNT_CALL_PATH), timeout=ADD_TEST_ACCOUNT_TIMEOUT) if not output or test_account_email not in output: logs.log('Failed to add test account, probably due to wifi issues.') return logs.log('Test account added successfully.') persistent_cache.set_value(constants.LAST_TEST_ACCOUNT_CHECK_KEY, time.time())
def get(self): """Handle a get request.""" external_user_permissions = list( data_types.ExternalUserPermission.query().order( data_types.ExternalUserPermission.entity_kind, data_types.ExternalUserPermission.entity_name, data_types.ExternalUserPermission.email)) template_values = { 'config': db_config.get(), 'permissions': external_user_permissions, 'fieldValues': { 'csrf_token': form.generate_csrf_token(), 'user_permission_entity_kinds': USER_PERMISSION_ENTITY_KINDS, 'user_permission_auto_cc_types': USER_PERMISSION_AUTO_CC_TYPES, 'add_permission_url': '/add-external-user-permission', 'delete_permission_url': '/delete-external-user-permission', } } helpers.log('Configuration', helpers.VIEW_OPERATION) return self.render('configuration.html', template_values)
def post(self): """Handle a post request.""" config = db_config.get() if not config: config = data_types.Config() previous_hash = request.get('previous_hash') if config.previous_hash and config.previous_hash != previous_hash: raise helpers.EarlyExitException( 'Your change conflicts with another configuration update. ' 'Please refresh and try again.', 500) build_apiary_service_account_private_key = request.get( 'build_apiary_service_account_private_key') bug_report_url = request.get('bug_report_url') client_credentials = request.get('client_credentials') jira_url = request.get('jira_url') jira_credentials = request.get('jira_credentials') component_repository_mappings = request.get('component_repository_mappings') contact_string = request.get('contact_string') documentation_url = request.get('documentation_url') github_credentials = request.get('github_credentials') oss_fuzz_robot_github_personal_access_token = request.get( 'oss_fuzz_robot_github_personal_access_token') platform_group_mappings = request.get('platform_group_mappings') privileged_users = request.get('privileged_users') blacklisted_users = request.get('blacklisted_users') relax_security_bug_restrictions = request.get( 'relax_security_bug_restrictions') relax_testcase_restrictions = request.get('relax_testcase_restrictions') reproduce_tool_client_id = request.get('reproduce_tool_client_id') reproduce_tool_client_secret = request.get('reproduce_tool_client_secret') reproduction_help_url = request.get('reproduction_help_url') test_account_email = request.get('test_account_email') test_account_password = request.get('test_account_password') wifi_ssid = request.get('wifi_ssid') wifi_password = request.get('wifi_password') sendgrid_api_key = request.get('sendgrid_api_key') sendgrid_sender = request.get('sendgrid_sender') config.build_apiary_service_account_private_key = ( build_apiary_service_account_private_key) config.bug_report_url = bug_report_url config.client_credentials = client_credentials config.component_repository_mappings = component_repository_mappings config.contact_string = contact_string config.documentation_url = documentation_url config.github_credentials = github_credentials config.oss_fuzz_robot_github_personal_access_token = ( oss_fuzz_robot_github_personal_access_token) config.jira_credentials = jira_credentials config.jira_url = jira_url config.platform_group_mappings = platform_group_mappings config.privileged_users = privileged_users config.blacklisted_users = blacklisted_users config.relax_security_bug_restrictions = bool( relax_security_bug_restrictions) config.relax_testcase_restrictions = bool(relax_testcase_restrictions) config.reproduce_tool_client_id = reproduce_tool_client_id config.reproduce_tool_client_secret = reproduce_tool_client_secret config.reproduction_help_url = reproduction_help_url config.test_account_email = test_account_email config.test_account_password = test_account_password config.wifi_ssid = wifi_ssid config.wifi_password = wifi_password config.sendgrid_api_key = sendgrid_api_key config.sendgrid_sender = sendgrid_sender helpers.log('Configuration', helpers.MODIFY_OPERATION) # Before hashing the entity, we must put it so that the internal maps are # updated. config.put() config.previous_hash = utils.entity_hash(config) config.put() template_values = { 'title': 'Success', 'message': ('Configuration is successfully updated. ' 'Redirecting to the configuration page...'), 'redirect_url': '/configuration', } return self.render('message.html', template_values)
def get_testcase_detail(testcase): """Get testcase detail for rendering the testcase detail page.""" config = db_config.get() crash_address = testcase.crash_address crash_state = testcase.crash_state crash_state_lines = crash_state.strip().splitlines() crash_type = data_handler.get_crash_type_string(testcase) external_user = not access.has_access(job_type=testcase.job_type) issue_url = issue_tracker_utils.get_issue_url(testcase) metadata = testcase.get_metadata() original_testcase_size = _get_blob_size_string(testcase.fuzzed_keys) minimized_testcase_size = _get_blob_size_string(testcase.minimized_keys) has_issue_tracker = bool(data_handler.get_issue_tracker_name()) fuzzer_display = data_handler.get_fuzzer_display(testcase) formatted_reproduction_help = _format_reproduction_help( data_handler.get_formatted_reproduction_help(testcase)) # When we have a HELP_TEMPLATE, ignore any default values set for HELP_URL. if not formatted_reproduction_help: reproduction_help_url = data_handler.get_reproduction_help_url( testcase, config) else: reproduction_help_url = None if not testcase.regression: regression = 'Pending' elif testcase.regression == 'NA': regression = 'NA' else: regression = _get_revision_range_html_from_string( testcase.job_type, testcase.platform_id, testcase.regression) fixed_full = None if 'progression_pending' in metadata: fixed = 'Pending' elif not testcase.fixed: fixed = 'NO' elif testcase.fixed == 'NA': fixed = 'NA' elif testcase.fixed == 'Yes': fixed = 'YES' else: fixed = 'YES' fixed_full = _get_revision_range_html_from_string( testcase.job_type, testcase.platform_id, testcase.fixed) last_tested = None last_tested_revision = (metadata.get('last_tested_revision') or testcase.crash_revision) if last_tested_revision: last_tested = _get_revision_range_html(testcase.job_type, testcase.platform_id, last_tested_revision) crash_revision = testcase.crash_revision crash_revisions_dict = revisions.get_component_revisions_dict( crash_revision, testcase.job_type, platform_id=testcase.platform_id) crash_stacktrace = data_handler.get_stacktrace(testcase) crash_stacktrace = filter_stacktrace(crash_stacktrace, testcase.crash_type, crash_revisions_dict, testcase.platform, testcase.job_type) crash_stacktrace = convert_to_lines(crash_stacktrace, crash_state_lines, crash_type) last_tested_crash_revision = metadata.get('last_tested_crash_revision') last_tested_crash_revisions_dict = revisions.get_component_revisions_dict( last_tested_crash_revision, testcase.job_type, platform_id=testcase.platform_id) last_tested_crash_stacktrace = data_handler.get_stacktrace( testcase, stack_attribute='last_tested_crash_stacktrace') last_tested_crash_stacktrace = filter_stacktrace( last_tested_crash_stacktrace, testcase.crash_type, last_tested_crash_revisions_dict, testcase.platform, testcase.job_type) last_tested_crash_stacktrace = convert_to_lines( last_tested_crash_stacktrace, crash_state_lines, crash_type) privileged_user = access.has_access(need_privileged_access=True) # Fix build url link. |storage.cloud.google.com| takes care of using the # right set of authentication credentials needed to access the link. if 'build_url' in metadata: metadata['build_url'] = metadata['build_url'].replace( 'gs://', 'https://storage.cloud.google.com/') pending_blame_task = (testcase.has_blame() and 'blame_pending' in metadata and metadata['blame_pending']) pending_impact_task = (testcase.has_impacts() and not testcase.is_impact_set_flag) pending_minimize_task = not testcase.minimized_keys pending_progression_task = ('progression_pending' in metadata and metadata['progression_pending']) pending_regression_task = not testcase.regression pending_stack_task = testcase.last_tested_crash_stacktrace == 'Pending' needs_refresh = (testcase.status == 'Pending' or ( (testcase.status == 'Processed' or testcase.status == 'Duplicate') and (pending_blame_task or pending_impact_task or pending_minimize_task or pending_progression_task or pending_regression_task or pending_stack_task))) if data_types.SecuritySeverity.is_valid(testcase.security_severity): security_severity = severity_analyzer.severity_to_string( testcase.security_severity) else: security_severity = None auto_delete_timestamp = None auto_close_timestamp = None if testcase.one_time_crasher_flag: last_crash_time = (crash_stats.get_last_crash_time(testcase) or testcase.timestamp) # Set auto-delete timestamp for unreproducible testcases with # no associated bug. if not testcase.bug_information: auto_delete_timestamp = utils.utc_datetime_to_timestamp( last_crash_time + datetime.timedelta( days=data_types.UNREPRODUCIBLE_TESTCASE_NO_BUG_DEADLINE)) # Set auto-close timestamp for unreproducible testcases with # an associated bug. if testcase.open and testcase.bug_information: auto_close_timestamp = utils.utc_datetime_to_timestamp( last_crash_time + datetime.timedelta( days=data_types.UNREPRODUCIBLE_TESTCASE_WITH_BUG_DEADLINE)) memory_tool_display_string = environment.get_memory_tool_display_string( testcase.job_type) memory_tool_display_label = memory_tool_display_string.split(':')[0] memory_tool_display_value = memory_tool_display_string.split( ':')[1].strip() helpers.log('Testcase %s' % testcase.key.id(), helpers.VIEW_OPERATION) return { 'id': testcase.key.id(), 'crash_type': crash_type, 'crash_address': crash_address, 'crash_state': crash_state, # Used by reproduce tool. 'crash_state_lines': crash_state_lines, 'crash_revision': testcase.crash_revision, 'csrf_token': form.generate_csrf_token(), 'external_user': external_user, 'footer': testcase.comments, 'formatted_reproduction_help': formatted_reproduction_help, 'fixed': fixed, 'fixed_full': fixed_full, 'issue_url': issue_url, 'is_admin': auth.is_current_user_admin(), 'metadata': metadata, 'minimized_testcase_size': minimized_testcase_size, 'needs_refresh': needs_refresh, 'original_testcase_size': original_testcase_size, 'privileged_user': privileged_user, 'regression': regression, 'crash_stacktrace': { 'lines': crash_stacktrace, 'revision': revisions.get_real_revision(crash_revision, testcase.job_type, display=True, platform_id=testcase.platform_id) }, 'last_tested_crash_stacktrace': { 'lines': last_tested_crash_stacktrace, 'revision': revisions.get_real_revision(last_tested_crash_revision, testcase.job_type, display=True, platform_id=testcase.platform_id) }, 'security_severity': security_severity, 'security_severities': data_types.SecuritySeverity.list(), 'stats': { 'min_hour': crash_stats.get_min_hour(), 'max_hour': crash_stats.get_max_hour(), }, 'suspected_cls': _parse_suspected_cls(metadata.get('predator_result')), 'testcase': testcase, 'timestamp': utils.utc_datetime_to_timestamp(testcase.timestamp), 'show_blame': testcase.has_blame(), 'show_impact': testcase.has_impacts(), 'impacts_production': testcase.impacts_production(), 'find_similar_issues_options': FIND_SIMILAR_ISSUES_OPTIONS, 'auto_delete_timestamp': auto_delete_timestamp, 'auto_close_timestamp': auto_close_timestamp, 'memory_tool_display_label': memory_tool_display_label, 'memory_tool_display_value': memory_tool_display_value, 'last_tested': last_tested, 'is_admin_or_not_oss_fuzz': is_admin_or_not_oss_fuzz(), 'has_issue_tracker': has_issue_tracker, 'reproduction_help_url': reproduction_help_url, 'is_local_development': environment.is_running_on_app_engine_development(), 'fuzzer_display': fuzzer_display._asdict(), }
def issue_url(self, issue_id): """Return the issue URL with the given ID.""" config = db_config.get() url = urljoin(config.jira_url, f'/browse/{str(issue_id)}') return url
def issue_url(self, issue_id): """Return the issue URL with the given ID.""" config = db_config.get() url = config.jira_url + '/browse/' + str(issue_id) return url