예제 #1
0
 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
예제 #3
0
    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
예제 #4
0
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)
예제 #5
0
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
예제 #6
0
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())
예제 #7
0
  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)
예제 #8
0
  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)
예제 #9
0
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(),
    }
예제 #10
0
 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
예제 #11
0
 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