コード例 #1
0
ファイル: errata.py プロジェクト: smunilla/elliott
def new_erratum(et_data,
                kind=None,
                release_date=None,
                create=False,
                assigned_to=None,
                manager=None,
                package_owner=None):
    """5.2.1.1. POST /api/v1/erratum

    Create a new advisory.
    Takes an unrealized advisory object and related attributes using the following format:

    https://errata.devel.redhat.com/developer-guide/api-http-api.html#api-post-apiv1erratum

    :param string kind: One of 'rpm' or 'image', effects boilerplate text
    :param string release_date: A date in the form YYYY-m-DD
    :param bool create: If true, create the erratum in the Errata
        tool, by default just the DATA we would have POSTed is
        returned
    :param str/int minor: The minor release to substitute into the
        errata boilerplate text (see:
        :mod:`constants`). E.g., if this is a '3.9'
        release, you would provide '9' as the value for 'minor'
    :param string assigned_to: The email address of the group responsible for
        examining and approving the advisory entries
    :param string manager: The email address of the manager responsible for
        managing the contents and status of this advisory
    :param string package_owner: The email address of the person who is handling
        the details and status of this advisory

    :return: An Erratum object
    :raises: exceptions.ErrataToolUnauthenticatedException if the user is not authenticated to make the request
    """
    if release_date is None:
        release_date = datetime.datetime.now() + datetime.timedelta(days=21)

    if kind is None:
        kind = 'rpm'

    e = Erratum(product=et_data['product'],
                release=et_data['release'],
                errata_type=et_data.get('errata_type', 'RHBA'),
                synopsis=et_data['synopsis'][kind],
                topic=et_data['topic'],
                description=et_data['description'],
                solution=et_data['solution'],
                qe_email=assigned_to,
                qe_group=et_data['quality_responsibility_name'],
                owner_email=package_owner,
                manager_email=manager,
                date=release_date)

    if create:
        # THIS IS NOT A DRILL
        e.commit()
        return e
    else:
        return e
コード例 #2
0
ファイル: conftest.py プロジェクト: vfreex/errata-tool
def rhsa(monkeypatch, mock_get):
    """ Like the advisory() fixture above, but an RHSA. """
    monkeypatch.delattr('requests.sessions.Session.request')
    monkeypatch.setattr(ErrataConnector, '_auth', None)
    monkeypatch.setattr(ErrataConnector, '_username', 'test')
    monkeypatch.setattr(requests, 'get', mock_get)
    return Erratum(errata_id=36762)
コード例 #3
0
ファイル: add_metadata_cli.py プロジェクト: vfreex/elliott
def add_metadata_cli(runtime, kind, impetus, advisory):
    """Add metadata to an advisory. This is usually called by
create immediately after creation. It is only useful to you if
you are going back and adding metadata to older advisories.

    Note: Requires you provide a --group

Example to add standard metadata to a 3.10 images release

\b
    $ elliott --group=openshift-3.10 add-metadata --impetus standard --kind image
"""
    runtime.initialize()
    release = release_from_branch(runtime.group_config.branch)

    try:
        advisory = Erratum(errata_id=advisory)
    except GSSError:
        exit_unauthenticated()

    result = elliottlib.errata.add_comment(
        advisory.errata_id, {'release': release, 'kind': kind, 'impetus': impetus})

    if result.status_code == 201:
        green_prefix("Added metadata successfully")
        click.echo()
    elif result.status_code == 403:
        exit_unauthorized()
    else:
        red_print("Something weird may have happened")
        raise ElliottFatalError(
            "Unexpected response from ET API: {code}".format(code=result.status_code))
コード例 #4
0
ファイル: build.py プロジェクト: smunilla/errata-tool
    def _fetch(self):
        """
        Fetch build data from Errata Tool API and store them to properties
        """
        self._data = self._get(self.url)

        if self._data['released_errata'] is not None:
            self._released_errata = Erratum(errata_id=self._data[
                'released_errata']['id'])

        for errata_dict in self._data['all_errata']:
            errata = Erratum(errata_id=errata_dict['id'])
            self._all_errata.append(errata)

        self._signed_rpms = self._data.get('rpms_signed')

        for et_file in self._data['files']:
            self._files.append(et_file['path'])
コード例 #5
0
    def released_errata(self):
        """Released Errata

        :return: Errata object
        """
        if self.released_errata_id and self._released_errata is None:
            self._released_errata = Erratum(errata_id=self.released_errata_id)

        return self._released_errata
コード例 #6
0
    def all_errata(self):
        """List of all Erratas where the build is attached

        :return: list of Errata objects
        """
        if self._all_errata is None:
            self._all_errata = []
            for errata_id in self.all_errata_ids:
                errata = Erratum(errata_id=errata_id)
                self._all_errata.append(errata)

        return self._all_errata
コード例 #7
0
def _update_to_advisory(builds, kind, advisory, remove, clean):
    click.echo(f"Attaching to advisory {advisory}...")
    if kind not in {"rpm", "image"}:
        raise ValueError(f"{kind} should be one of 'rpm' or 'image'")
    try:
        erratum = Erratum(errata_id=advisory)
        file_type = 'tar' if kind == 'image' else 'rpm'
        product_version_set = {build.product_version for build in builds}
        for pv in product_version_set:
            erratum.addBuilds(buildlist=[
                build.nvr for build in builds if build.product_version == pv
            ],
                              release=pv,
                              file_types={
                                  build.nvr: [file_type]
                                  for build in builds
                              })
            erratum.commit()

        build_nvrs = sorted(build.nvr for build in builds)
        green_print('Attached build(s) successfully:')
        for b in build_nvrs:
            click.echo(' ' + b)
        return erratum

    except GSSError:
        exit_unauthenticated()
    except elliottlib.exceptions.BrewBuildException as ex:
        raise ElliottFatalError(f'Error attaching/removing builds: {str(ex)}')
コード例 #8
0
def add_bugs_with_retry(advisory, bug_list, retried):
    """
    adding specified bug_list into advisory, retry 2 times: first time
    parse the exception message to get failed bug id list, remove from original
    list then add bug to advisory again, if still has failures raise exceptions

    :param advisory: advisory id
    :param bug_list: bug id list which suppose to attach to advisory
    :param retried: retry 2 times, first attempt fetch failed bugs sift out then attach again
    :return:
    """
    try:
        advs = Erratum(errata_id=advisory)
    except GSSError:
        exit_unauthenticated()

    if advs is False:
        raise exceptions.ElliottFatalError(
            "Error: Could not locate advisory {advs}".format(advs=advisory))

    green_prefix("Adding {count} bugs to advisory {retry_times} times:".format(
        count=len(bug_list), retry_times=1 if retried is False else 2))
    print(" {advs}".format(advs=advs))
    try:
        advs.addBugs(bug_list)
        advs.commit()
    except ErrataException as e:
        print("ErrataException Message: {}, retry it again".format(e))
        if retried is not True:
            black_list = parse_exception_error_message(e)
            retry_list = [x for x in bug_list if x not in black_list]
            if len(retry_list) > 0:
                add_bugs_with_retry(advisory, retry_list, True)
        else:
            raise exceptions.ElliottFatalError(getattr(e, 'message', repr(e)))
コード例 #9
0
def _attach_to_advisory(builds, kind, advisory):
    if kind is None:
        raise ElliottFatalError(
            'Need to specify with --kind=image or --kind=rpm with packages: {}'
            .format(builds))

    try:
        erratum = Erratum(errata_id=advisory)
        file_type = 'tar' if kind == 'image' else 'rpm'

        product_version_set = {build.product_version for build in builds}
        for pv in product_version_set:
            erratum.addBuilds(buildlist=[
                build.nvr for build in builds if build.product_version == pv
            ],
                              release=pv,
                              file_types={
                                  build.nvr: [file_type]
                                  for build in builds
                              })
            erratum.commit()

        build_nvrs = sorted(build.nvr for build in builds)
        green_print('Attached build(s) successfully:')
        for b in build_nvrs:
            click.echo(' ' + b)

    except GSSError:
        exit_unauthenticated()
    except elliottlib.exceptions.BrewBuildException as ex:
        raise ElliottFatalError('Error attaching builds: {}'.format(
            getattr(ex, 'message', repr(ex))))
コード例 #10
0
ファイル: errata.py プロジェクト: sosiouxme/elliott
def new_erratum(et_data, errata_type=None, kind=None, release_date=None, create=False,
                assigned_to=None, manager=None, package_owner=None, impact=None, cve=None):
    """5.2.1.1. POST /api/v1/erratum

    Create a new advisory.
    Takes an unrealized advisory object and related attributes using the following format:

    https://errata.devel.redhat.com/developer-guide/api-http-api.html#api-post-apiv1erratum

    :param et_data: The ET data dump we got from our erratatool.yaml file
    :param errata_type: The type of advisory to create (RHBA, RHSA, or RHEA)
    :param string kind: One of 'rpm' or 'image', effects boilerplate text
    :param string release_date: A date in the form YYYY-MM-DD
    :param bool create: If true, create the erratum in the Errata
        tool, by default just the DATA we would have POSTed is
        returned
    :param string assigned_to: The email address of the group responsible for
        examining and approving the advisory entries
    :param string manager: The email address of the manager responsible for
        managing the contents and status of this advisory
    :param string package_owner: The email address of the person who is handling
        the details and status of this advisory
    :param impact: The security impact. Only applies to RHSA
    :param cve: The CVE to attach to the advisory. Only applies to RHSA

    :return: An Erratum object
    :raises: exceptions.ErrataToolUnauthenticatedException if the user is not authenticated to make the request
    """
    if release_date is None:
        release_date = datetime.datetime.now() + datetime.timedelta(days=21)

    if kind is None:
        kind = 'rpm'

    e = Erratum(
            product = et_data['product'],
            release = et_data['release'],
            errata_type = errata_type,
            synopsis = et_data['synopsis'][kind],
            topic = et_data['topic'],
            description = et_data['description'],
            solution = et_data['solution'],
            qe_email = assigned_to,
            qe_group = et_data['quality_responsibility_name'],
            owner_email = package_owner,
            manager_email = manager,
            date = release_date
        )

    if errata_type == 'RHSA':
        e.security_impact = impact
        e.cve_names = cve

    if create:
        # THIS IS NOT A DRILL
        e.commit()
        return e
    else:
        return e
コード例 #11
0
 def get_erratum(self):
     return Erratum(
         product=self.cfg.get('product'),
         release=self._release,
         topic=self.cfg.get('topic'),
         synopsis=self.cfg.get('synopsis'),
         description=self.cfg.get('description'),
         solution=self.cfg.get('solution'),
         qe_email=self.cfg.get('qe_email'),
         qe_group=self.cfg.get('qe_group'),
         owner_email=self.cfg.get('owner_email'),
         manager_email=self.cfg.get('manager_email'),
     )
コード例 #12
0
def _get_attached_image_builds(brew_session, advisories):
    # get all attached image builds
    build_nvrs = []
    try:
        for advisory in advisories:
            green_print(f"Retrieving builds from advisory {advisory}")
            advisory = Erratum(errata_id=advisory)
            for build_list in advisory.errata_builds.values():  # one per product version
                build_nvrs.extend(build_list)
    except GSSError:
        exit_unauthenticated()

    green_print(f"Found {len(build_nvrs)} builds")
    return [build for build in brew.get_build_objects(build_nvrs, brew_session) if _is_image(build)]
コード例 #13
0
async def attach_cve_flaws_cli(runtime: Runtime, advisory_id: int, noop: bool, default_advisory_type: str):
    """Attach corresponding flaw bugs for trackers in advisory (first-fix only).

    Also converts advisory to RHSA, if not already.

    Example:

    $ elliott --group openshift-4.6 attach-cve-flaws --use-default-advisory image
    INFO Cloning config data from https://github.com/openshift/ocp-build-data.git
    INFO Using branch from group.yml: rhaos-4.6-rhel-8
    INFO found 114 tracker bugs attached to the advisory
    INFO found 58 corresponding flaw bugs
    INFO 23 out of 58 flaw bugs considered "first-fix"
    INFO Adding the following BZs to the advisory: [1880456, 1858827, 1880460,
    1847310, 1857682, 1857550, 1857551, 1857559, 1848089, 1848092, 1849503,
    1851422, 1866148, 1858981, 1852331, 1861044, 1857081, 1857977, 1848647,
    1849044, 1856529, 1843575, 1840253]
    """
    if sum(map(bool, [advisory_id, default_advisory_type])) != 1:
        raise click.BadParameter("Use one of --use-default-advisory or --advisory")
    runtime.initialize()
    if not advisory_id and default_advisory_type is not None:
        advisory_id = find_default_advisory(runtime, default_advisory_type)

    runtime.logger.info("Getting advisory %s", advisory_id)
    advisory = Erratum(errata_id=advisory_id)
    exit_code = 0

    # Flaw bugs associated with jira tracker bugs
    # exist in bugzilla. so to work with jira trackers
    # we need both bugzilla and jira instances initialized
    if runtime.only_jira:
        runtime.use_jira = True

    tasks = []
    for bug_tracker in runtime.bug_trackers.values():
        flaw_bug_tracker = runtime.bug_trackers['bugzilla']
        tasks.append(asyncio.get_event_loop().create_task(get_flaws(runtime, advisory, bug_tracker,
                                                          flaw_bug_tracker, noop)))
    try:
        lists_of_flaw_bugs = await asyncio.gather(*tasks)
        flaw_bugs = list(set(sum(lists_of_flaw_bugs, [])))
        if flaw_bugs:
            bug_tracker = runtime.bug_trackers['bugzilla']
            _update_advisory(runtime, advisory, flaw_bugs, bug_tracker, noop)
    except Exception as e:
        runtime.logger.error(traceback.format_exc())
        runtime.logger.error(f'Exception: {e}')
        exit_code = 1
    sys.exit(exit_code)
コード例 #14
0
def add_bugs_with_retry(advisory, bugs, retried=False, noop=False):
    """
    adding specified bugs into advisory, retry 2 times: first time
    parse the exception message to get failed bug id list, remove from original
    list then add bug to advisory again, if still has failures raise exceptions

    :param advisory: advisory id
    :param bugs: iterable of bzutil.bug to attach to advisory
    :param retried: retry 2 times, first attempt fetch failed bugs sift out then attach again
    :return:
    """
    print(f'Request to attach {len(bugs)} bugs to the advisory {advisory}')

    try:
        advs = Erratum(errata_id=advisory)
    except GSSError:
        exit_unauthenticated()

    if advs is False:
        raise exceptions.ElliottFatalError(
            "Error: Could not locate advisory {advs}".format(advs=advisory))

    existing_bugs = advs.errata_bugs
    new_bugs = set(bug.id for bug in bugs) - set(existing_bugs)
    print(f'Bugs already attached: {len(existing_bugs)}')
    print(f'New bugs ({len(new_bugs)}) : {sorted(new_bugs)}')

    if noop:
        print('Dry run. Exiting.')
        return

    if not new_bugs:
        print('No new bugs to attach. Exiting.')
        return

    green_prefix("Adding {count} bugs to advisory {retry_times} times:".format(
        count=len(bugs), retry_times=1 if retried is False else 2))

    try:
        advs.addBugs([bug.id for bug in bugs])
        advs.commit()
    except ErrataException as e:
        print("ErrataException Message: {}, retry it again".format(e))
        if retried is not True:
            block_list = parse_exception_error_message(e)
            retry_list = [x for x in bugs if x.id not in block_list]
            if len(retry_list) > 0:
                add_bugs_with_retry(advisory,
                                    retry_list,
                                    retried=True,
                                    noop=noop)
        else:
            raise exceptions.ElliottFatalError(getattr(e, 'message', repr(e)))
コード例 #15
0
ファイル: __main__.py プロジェクト: sfowl/elliott
def remove_bugs(runtime, advisory, default_advisory_type, id):
    """Remove given BUGS from ADVISORY.

    Remove bugs that have been attached an advisory:

\b
    $ elliott --group openshift-3.7 remove-bugs --id 123456 --advisory 1234123

    Remove two bugs from default rpm advisory. Note that --group is required
    because default advisory is from ocp-build-data:

\b
    $ elliott --group openshift-3.7 remove-bugs --id 123456 --id 3412311 --use-default-advisory rpm


"""
    if bool(advisory) == bool(default_advisory_type):
        raise click.BadParameter(
            "Specify exactly one of --use-default-advisory or advisory arg")

    runtime.initialize()
    bz_data = runtime.gitdata.load_data(key='bugzilla').data
    bzapi = elliottlib.bzutil.get_bzapi(bz_data)

    bug_ids = [bzapi.getbug(i) for i in cli_opts.id_convert(id)]

    green_prefix("Found {} bugs:".format(len(bug_ids)))
    click.echo(" {}".format(", ".join([str(b.bug_id) for b in bug_ids])))

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    if advisory is not False:
        try:
            advs = Erratum(errata_id=advisory)
        except GSSError:
            exit_unauthenticated()

        if advs is False:
            raise ElliottFatalError(
                "Error: Could not locate advisory {advs}".format(
                    advs=advisory))

        try:
            green_prefix("Removing {count} bugs from advisory:".format(
                count=len(bug_ids)))
            click.echo(" {advs}".format(advs=advisory))
            advs.removeBugs([bug.id for bug in bug_ids])
            advs.commit()
        except ErrataException as ex:
            raise ElliottFatalError(getattr(ex, 'message', repr(ex)))
コード例 #16
0
ファイル: errata.py プロジェクト: vfreex/elliott
def add_jira_bugs_with_retry(
        advisory_id: int,
        bugids: List[str],
        noop: bool = False,
        batch_size: int = constants.BUG_ATTACH_CHUNK_SIZE):
    """
    :param advisory_id: advisory id
    :param bugids: iterable of jira bug ids to attach to advisory
    :param noop: do not modify anything
    :param batch_size: perform operation in batches of given size
    """
    logger.info(
        f'Request to attach {len(bugids)} bugs to the advisory {advisory_id}')
    try:
        advisory = Erratum(errata_id=advisory_id)
    except GSSError:
        exit_unauthenticated()

    if not advisory:
        raise exceptions.ElliottFatalError(
            f"Error: Could not locate advisory {advisory_id}")

    existing_bugs = bzutil.JIRABugTracker.advisory_bug_ids(advisory)
    new_bugs = set(bugids) - set(existing_bugs)
    logger.info(
        f'Bugs already attached: {len(existing_bugs)}. New bugs: {len(new_bugs)}'
    )
    if not new_bugs:
        return
    for chunk_of_bugs in chunk(bugids, batch_size):
        if noop:
            logger.info('Dry run: Would have attached bugs')
            continue
        results = add_multi_jira_issues(advisory_id, chunk_of_bugs)
        for i, result in enumerate(results):
            if result.status_code != 201:
                rt = add_jira_issue(advisory_id, chunk_of_bugs[i])
                if rt.status_code != 201:
                    raise exceptions.ElliottFatalError(
                        f"attach jira bug {chunk_of_bugs[i]} failed with "
                        f"status={rt.status_code}: {rt.json()}")
        logger.info("All jira bugs attached")
コード例 #17
0
def create_placeholder_cli(runtime, kind, advisory, default_advisory_type):
    """Create a placeholder bug for attaching to an advisory.

    KIND - The kind of placeholder to create ({}).
    ADVISORY - Optional. The advisory to attach the bug to.

    $ elliott --group openshift-4.1 create-placeholder --kind rpm --attach 12345
""".format('/'.join(elliottlib.constants.standard_advisory_types))

    runtime.initialize()
    if advisory and default_advisory_type:
        raise click.BadParameter(
            "Use only one of --use-default-advisory or --advisory")

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)
        kind = default_advisory_type

    if kind is None:
        raise click.BadParameter(
            "--kind must be specified when not using --use-default-advisory")

    bz_data = runtime.gitdata.load_data(key='bugzilla').data
    target_release = bz_data['target_release'][0]
    newbug = elliottlib.bzutil.create_placeholder(bz_data, kind,
                                                  target_release)

    click.echo("Created BZ: {} {}".format(newbug.id, newbug.weburl))

    if advisory is not False:
        click.echo("Attaching to advisory...")

        try:
            advs = Erratum(errata_id=advisory)
        except GSSError:
            exit_unauthenticated()

        if advs is False:
            raise ElliottFatalError(
                "Error: Could not locate advisory {advs}".format(
                    advs=advisory))

        try:
            green_prefix("Adding placeholder bug to advisory:")
            click.echo(" {advs}".format(advs=advisory))
            advs.addBugs([newbug.id])
            advs.commit()
        except ErrataException as ex:
            raise ElliottFatalError(getattr(ex, 'message', repr(ex)))
コード例 #18
0
def create_placeholder(kind, advisory_id, bug_tracker, noop):
    newbug = bug_tracker.create_placeholder(kind, noop)
    if noop:
        return

    click.echo(f"Created Bug: {newbug.id} {newbug.weburl}")

    if not advisory_id:
        return

    try:
        advisory = Erratum(errata_id=advisory_id)
    except GSSError:
        exit_unauthenticated()

    if advisory is False:
        raise ElliottFatalError(
            f"Error: Could not locate advisory {advisory_id}")

    click.echo("Attaching bug to advisory...")
    bug_tracker.attach_bugs(advisory_id, [newbug.id])
コード例 #19
0
ファイル: validate_rhsa.py プロジェクト: vfreex/elliott
def validate_rhsa_cli(runtime, advisory):
    """
    Validates an RHSA by returning the 'alerts' generated by Product Security's central SFM2 server.

    Usage:
\b
    $ elliott validate-rhsa ID
"""

    try:
        if Erratum(errata_id=advisory).errata_type != 'RHSA':
            print(f"Advisory {advisory} is not an RHSA. Nothing to check.")
            exit(0)
    except GSSError:
        exit_unauthenticated()

    session = requests.Session()
    url = constants.SFM2_ERRATA_ALERTS_URL.format(id=advisory)
    print(url)
    print("Validating..")
    print()
    resp = session.get(url)

    # Will fail if id invalid, not an RHSA or RHSA has embargoed data
    if resp.status_code != 200:
        print(f"HTTP {resp.status_code}: Could not validate rhsa {advisory} (is it an RHSA? without embargo?)")
        exit(1)
        return
    alerts = resp.json()

    if alerts:
        for a in alerts:
            print("E: {text}".format(text=a.get("text")))
            howto = a.get("how_to_resolve")
            if howto:
                print(textwrap.indent(howto, "  > "))
            print()
        exit(2)
    else:
        print("No issues found")
コード例 #20
0
ファイル: advisory_drop_cli.py プロジェクト: vfreex/elliott
def advisory_drop_cli(advisory):
    """Drop advisory

    Advisories can only be dropped by the creators, and program management.
    This script can get run on buildvm with the credentials of the creator of
    ART's advisories, so the bot account can drop them.
    """

    url = errata_drop_url.format(id=advisory)
    data = 'utf8=%E2%9C%93&reason=Dropping+unused+advisory%21&commit=Dropping+unused+advisory'
    headers = {"Content-Type": "text/plain"}

    r = requests.post(url, auth=HTTPKerberosAuth(), data=data, headers=headers)
    adv = Erratum(errata_id=advisory)
    if adv.errata_state == "DROPPED_NO_SHIP":
        click.echo(f'Succesfully dropped advisory {advisory}')
        sys.exit(0)
    else:
        click.echo(
            f'Failed to drop advisory {advisory}. Got status code {r.status_code}'
        )
        click.echo(r.text)
        sys.exit(1)
コード例 #21
0
ファイル: errata.py プロジェクト: smunilla/elliott
def get_filtered_list(filter_id=constants.errata_default_filter, limit=5):
    """return a list of Erratum() objects from results using the provided
filter_id

    :param filter_id: The ID number of the pre-defined filter
    :param int limit: How many erratum to list
    :return: A list of Erratum objects

    :raises exceptions.ErrataToolUnauthenticatedException: If the user is not authenticated to make the request
    :raises exceptions.ErrataToolError: If the given filter does not exist, and, any other unexpected error

    Note: Errata filters are defined in the ET web interface
    """
    filter_endpoint = constants.errata_filter_list_url.format(id=filter_id)
    res = requests.get(filter_endpoint,
                       verify=ssl.get_default_verify_paths().openssl_cafile,
                       auth=HTTPKerberosAuth())
    if res.status_code == 200:
        # When asked for an advisory list which does not exist
        # normally you would expect a code like '404' (not
        # found). However, the Errata Tool sadistically returns a 200
        # response code. That leaves us with one option: Decide that
        # successfully parsing the response as a JSONinfo object indicates
        # a successful API call.
        try:
            return [Erratum(errata_id=advs['id'])
                    for advs in res.json()][:limit]
        except Exception:
            raise exceptions.ErrataToolError(
                "Could not locate the given advisory filter: {fid}".format(
                    fid=filter_id))
    elif res.status_code == 401:
        raise exceptions.ErrataToolUnauthenticatedException(res.text)
    else:
        raise exceptions.ErrataToolError(
            "Other error (status_code={code}): {msg}".format(
                code=res.status_code, msg=res.text))
コード例 #22
0
def create_textonly(runtime, errata_type, date, assigned_to, manager,
                    package_owner, topic, synopsis, description, solution,
                    bug_title, bug_description, yes, bug_tracker: BugTracker):
    et_data = runtime.gitdata.load_data(key='erratatool').data
    try:
        erratum = Erratum(
            product=et_data['product'],
            release=et_data['release'],
            qe_group=et_data['quality_responsibility_name'],
            synopsis=synopsis,
            topic=topic,
            description=description,
            solution=solution,
            qe_email=assigned_to,
            errata_type=errata_type,
            owner_email=package_owner,
            manager_email=manager,
            date=date,
            text_only=1,
        )
    except elliottlib.exceptions.ErrataToolUnauthorizedException:
        exit_unauthorized()
    except elliottlib.exceptions.ErrataToolError as ex:
        raise repr(ex)

    cdn_repos = et_data.get('cdn_repos')
    if cdn_repos:
        click.echo(f"Configuring CDN repos {', '.join(cdn_repos)}...")
        erratum.textOnlyRepos(enable=cdn_repos)
    if yes:
        erratum.commit()
        green_prefix("Created new text only advisory: ")
        click.echo(str(erratum))
        bug = bug_tracker.create_textonly(bug_title, bug_description)
        click.echo(f"Created placeholder bug: {bug.id} {bug.webur}")
        click.echo("Attaching placeholder bug...")
        bug_tracker.attach_bugs(erratum.errata_id, [bug.id])
    else:
        green_prefix("Would have created advisory: ")
        click.echo("")
        click.echo(erratum)
コード例 #23
0
ファイル: conftest.py プロジェクト: ralphbean/errata-tool
def advisory(monkeypatch, mock_get):
    monkeypatch.delattr('requests.sessions.Session.request')
    monkeypatch.setattr(ErrataConnector, '_auth', None)
    monkeypatch.setattr(requests, 'get', mock_get)
    return Erratum(errata_id=26175)
コード例 #24
0
ファイル: errata.py プロジェクト: smunilla/elliott
def find_latest_erratum(kind, major, minor):
    """Find an erratum in a given release series, in ANY state.

    Put simply, this tells you the erratum that has the most recent,
    or furthest in the future, release date set.

    This is useful for determining the release date of a new
    erratum. This combines the functionality provided by
    find_mutable_erratum and extends it by including searching closed
    or immutable erratum. These two functions can work well in tandem.

    Contrast this with find_mutable_erratum (best suited for elliott
    actions explicitly designed to UPDATE an erratum), this function
    promises to tell you the freshest release date of erratum in any
    state in a given release series.

    Example:

    You are creating a new erratum. The latest erratum in that series
    MAY or MAY NOT have gone to SHIPPED_LIVE state yet. Regardless of
    that, this function will tell you what the latest ship date is for
    an erratum in that series.

    If erratum exists matching your search:
    :return: An `Erratum` object of the erratum

    If no erratum can be found matching your search:
    :return: `None`
    """
    release = "{}.{}".format(major, minor)
    found_advisory = None

    # List of hashes because we will scan the Mutable advisories first
    filters = [{
        'Mutable Advisories': constants.errata_default_filter
    }, {
        'Immutable Advisories':
        constants.errata_immutable_advisory_filter
    }]

    # Fetch initial lists of advisories in each pre-defined filter
    advisory_list = []
    print("Running initial advisory fetching")
    for f in filters:
        state_desc, filter_id = f.items()[0]
        print("Fetching {state}".format(state=state_desc))
        advisories = get_filtered_list(filter_id, limit=50)
        # Filter out advisories that aren't for this release
        advisory_list.extend([
            advs for advs in advisories
            if " {} ".format(release) in advs.synopsis
        ])
        print("Advisory list has {n} items after this fetch".format(
            n=len(advisory_list)))

    print("Looking for elliott metadata in comments:")
    matched_advisories = []
    for advisory in advisory_list:
        print("Scanning advisory {}".format(str(advisory)))

        for c in get_comments(advisory.errata_id):
            try:
                metadata = json.loads(c['attributes']['text'])
            except Exception as e:
                pass
            else:
                if str(metadata['release']) == str(release) and metadata[
                        'kind'] == kind and metadata['impetus'] == 'standard':
                    matched_advisories.append(advisory)
                    # Don't scan any more comments
                    break

    if matched_advisories == []:
        return None
    else:
        # loop over discovered advisories, select one with max() date
        real_advisories = [
            Erratum(errata_id=e.advisory_id) for e in matched_advisories
        ]
        sorted_dates = sorted(real_advisories,
                              key=lambda advs: advs.release_date)
        return sorted_dates[-1]
コード例 #25
0
ファイル: change_state_cli.py プロジェクト: vfreex/elliott
def change_state_cli(runtime, state, advisory, default_advisories,
                     default_advisory_type, noop):
    """Change the state of an ADVISORY. Additional permissions may be
required to change an advisory to certain states.

An advisory may not move between some states until all criteria have
been met. For example, an advisory can not move from NEW_FILES to QE
unless Bugzilla Bugs or JIRA Issues have been attached.

    NOTE: The two advisory options are mutually exclusive and can not
    be used together.

See the find-bugs help for additional information on adding
Bugs.

    Move assembly release advisories to QE

    $ elliott -g openshift-4.10 --assembly 4.10.4 change-state -s QE

    Move group release advisories to QE:

    $ elliott -g openshift-4.5 change-state -s QE --default-advisories

    Move the advisory 123456 to QE:

    $ elliott change-state --state QE --advisory 123456

    Move the advisory 123456 back to NEW_FILES (short option flag):

    $ elliott change-state -s NEW_FILES -a 123456

    Do not actually change state, just check that the command could
    have ran (for example, when testing out pipelines)

    $ elliott change-state -s NEW_FILES -a 123456 --noop
"""
    count_flags = sum(
        map(bool, [advisory, default_advisory_type, default_advisories]))
    if count_flags > 1:
        raise click.BadParameter(
            "Use only one of --use-default-advisory or --advisory or --default-advisories"
        )

    runtime.initialize(no_group=bool(advisory))

    advisories = []
    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    if advisory:
        advisories.append(advisory)

    if not advisories:
        advisories = list(runtime.group_config.advisories.values())

    click.echo(f"Attempting to move advisories {advisories} to {state}")
    errors = []
    for advisory in advisories:
        try:
            e = Erratum(errata_id=advisory)

            if e.errata_state == state:
                green_prefix(f"No Change ({advisory}): ")
                click.echo(f"Target state is same as current state: {state}")
            # we have 5 different states we can only change the state if it's in NEW_FILES or QE
            # "NEW_FILES",
            # "QE",
            # "REL_PREP",
            # "PUSH_READY",
            # "IN_PUSH"
            elif e.errata_state != 'NEW_FILES' and e.errata_state != 'QE':
                red_prefix(f"Error ({advisory}): ")
                if default_advisory_type is not None:
                    click.echo(
                        f"Could not change '{e.errata_state}', group.yml is probably pointing at old one"
                    )
                else:
                    click.echo(
                        f"Can only change the state if it's in NEW_FILES or QE, current state is {e.errata_state}"
                    )
            else:
                if noop:
                    green_prefix(f"NOOP ({advisory}): ")
                    click.echo(
                        f"Would have changed state {e.errata_state} ➔ {state}")
                else:
                    # Capture current state because `e.commit()` will
                    # refresh the `e.errata_state` attribute
                    old_state = e.errata_state
                    e.setState(state)
                    e.commit()
                    green_prefix(f"Changed state ({advisory}): ")
                    click.echo(f"{old_state} ➔ {state}")
        except ErrataException as ex:
            click.echo(f'Error fetching/changing state of {advisory}: {ex}')
            errors.append(ex)

    if errors:
        raise Exception(errors)
コード例 #26
0
def get_updated_advisory_rhsa(logger, cve_boilerplate: dict, advisory: Erratum, flaw_bugs):
    """Given an advisory object, get updated advisory to RHSA

    :param logger: logger object from runtime
    :param cve_boilerplate: cve template for rhsa
    :param advisory: advisory object to update
    :param flaw_bugs: Collection of flaw bug objects to be attached to the advisory
    :returns: updated advisory object and a boolean indicating if advisory was updated
    """
    updated = False
    if not is_security_advisory(advisory):
        logger.info('Advisory type is {}, converting it to RHSA'.format(advisory.errata_type))
        updated = True
        advisory.update(
            errata_type='RHSA',
            security_reviewer=cve_boilerplate['security_reviewer'],
            synopsis=cve_boilerplate['synopsis'],
            topic=cve_boilerplate['topic'].format(IMPACT="Low"),
            solution=cve_boilerplate['solution'],
            security_impact='Low',
        )

    cve_names = [b.alias[0] for b in flaw_bugs]
    if not advisory.cve_names:
        cve_str = ' '.join(cve_names)
        advisory.update(cve_names=cve_str)
        updated = True
    else:
        cves_not_in_cve_names = [n for n in cve_names if n not in advisory.cve_names]
        if cves_not_in_cve_names:
            s = ' '.join(cves_not_in_cve_names)
            cve_str = f"{advisory.cve_names} {s}".strip()
            advisory.update(cve_names=cve_str)
            updated = True

    if updated:
        formatted_cve_list = '\n'.join([
            f'* {b.summary.replace(b.alias[0], "").strip()} ({b.alias[0]})' for b in flaw_bugs
        ])
        formatted_description = cve_boilerplate['description'].format(CVES=formatted_cve_list)
        advisory.update(description=formatted_description)

    highest_impact = get_highest_security_impact(flaw_bugs)
    if highest_impact != advisory.security_impact:
        logger.info(f'Adjusting advisory security impact from {advisory.security_impact} to {highest_impact}')
        advisory.update(security_impact=highest_impact)
        updated = True

    if highest_impact not in advisory.topic:
        topic = cve_boilerplate['topic'].format(IMPACT=highest_impact)
        logger.info('Topic updated to include impact of {}'.format(highest_impact))
        advisory.update(topic=topic)

    return advisory, updated
コード例 #27
0
ファイル: errata.py プロジェクト: vfreex/elliott
def add_bugzilla_bugs_with_retry(
        advisory_id: int,
        bugids: List,
        noop: bool = False,
        batch_size: int = constants.BUG_ATTACH_CHUNK_SIZE):
    """
    adding specified bugs into advisory, retry 2 times: first time
    parse the exception message to get failed bug id list, remove from original
    list then add bug to advisory again, if still has failures raise exceptions

    :param advisory_id: advisory id
    :param bugids: iterable of bugzilla bug ids to attach to advisory
    :param noop: do not modify anything
    :param batch_size: perform operation in batches of given size
    :return:
    """
    logger.info(
        f'Request to attach {len(bugids)} bugs to the advisory {advisory_id}')
    try:
        advisory = Erratum(errata_id=advisory_id)
    except GSSError:
        exit_unauthenticated()

    if not advisory:
        raise exceptions.ElliottFatalError(
            f"Error: Could not locate advisory {advisory_id}")

    existing_bugs = bzutil.BugzillaBugTracker.advisory_bug_ids(advisory)
    new_bugs = set(bugids) - set(existing_bugs)
    logger.info(
        f'Bugs already attached: {len(existing_bugs)}. New bugs: {len(new_bugs)}'
    )
    if not new_bugs:
        return

    for chunk_of_bugs in chunk(list(new_bugs), batch_size):
        if noop:
            logger.info('Dry run: Would have attached bugs')
            continue
        try:
            advisory.addBugs(chunk_of_bugs)
            advisory.commit()
        except ErrataException as e:
            logger.info(f"ErrataException Message: {e}\nRetrying...")
            block_list = parse_exception_error_message(e)
            retry_list = [x for x in chunk_of_bugs if x not in block_list]
            if len(retry_list) == 0:
                continue
            try:
                advisory = Erratum(errata_id=advisory_id)
                advisory.addBugs(retry_list)
                advisory.commit()
            except ErrataException as e:
                raise exceptions.ElliottFatalError(
                    getattr(e, 'message', repr(e)))
            logger.info("remaining bugs attached")
        logger.info("All bugzilla bugs attached")
コード例 #28
0
def change_state_cli(runtime, state, advisory, default_advisory_type, noop):
    """Change the state of an ADVISORY. Additional permissions may be
required to change an advisory to certain states.

An advisory may not move between some states until all criteria have
been met. For example, an advisory can not move from NEW_FILES to QE
unless Bugzilla Bugs or JIRA Issues have been attached.

    NOTE: The two advisory options are mutually exclusive and can not
    be used together.

See the find-bugs help for additional information on adding
Bugzilla Bugs.

    Move the advisory 123456 from NEW_FILES to QE state:

    $ elliott change-state --state QE --advisory 123456

    Move the advisory 123456 back to NEW_FILES (short option flag):

    $ elliott change-state -s NEW_FILES -a 123456

    Do not actually change state, just check that the command could
    have ran (for example, when testing out pipelines)

    $ elliott change-state -s NEW_FILES -a 123456 --noop
"""
    if not (bool(advisory) ^ bool(default_advisory_type)):
        raise click.BadParameter(
            "Use only one of --use-default-advisory or --advisory")

    runtime.initialize(no_group=default_advisory_type is None)

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    if noop:
        prefix = "[NOOP] "
    else:
        prefix = ""

    try:
        e = Erratum(errata_id=advisory)

        if e.errata_state == state:
            green_prefix("{}No change to make: ".format(prefix))
            click.echo("Target state is same as current state")
            return
        # we have 5 different states we can only change the state if it's in NEW_FILES or QE
        # "NEW_FILES",
        # "QE",
        # "REL_PREP",
        # "PUSH_READY",
        # "IN_PUSH"
        if e.errata_state != 'NEW_FILES' and e.errata_state != 'QE':
            if default_advisory_type is not None:
                raise ElliottFatalError(
                    "Error: Could not change '{state}' advisory {advs}, group.yml is probably pointing at old one"
                    .format(state=e.errata_state, advs=advisory))
            else:
                raise ElliottFatalError(
                    "Error: we can only change the state if it's in NEW_FILES or QE, current state is {s}"
                    .format(s=e.errata_state))
        else:
            if noop:
                green_prefix("{}Would have changed state: ".format(prefix))
                click.echo("{} ➔ {}".format(e.errata_state, state))
                return
            else:
                # Capture current state because `e.commit()` will
                # refresh the `e.errata_state` attribute
                old_state = e.errata_state
                e.setState(state)
                e.commit()
                green_prefix("Changed state: ")
                click.echo("{old_state} ➔ {new_state}".format(
                    old_state=old_state, new_state=state))
    except ErrataException as ex:
        raise ElliottFatalError(getattr(ex, 'message', repr(ex)))

    green_print("Successfully changed advisory state")
コード例 #29
0
elif args.errata_type == "RHSA":
    pass

# Ensure bugs are in proper state (MODIFIED or VERIFIED) and that they have
# the appropriate rhel-fast-datapath flag set.
s = utilities.open_session()
bz_bugs = utilities.get_bz_bugs(s, args.bugs)
for bug in bz_bugs:
    if bug['status'] != 'MODIFIED' and bug['status'] != 'VERIFIED':
        utilities.update_bz(s, bug['id'], json={'status': 'MODIFIED'})
    utilities.set_bz_flag(s, bug['id'], f'fast-datapath-rhel-{release[-1]}',
                          '+')

e = Erratum(product='Fast-Datapath',
            release=release,
            errata_type=args.errata_type,
            security_impact=args.security_impact,
            synopsis=synopsis,
            topic=topic,
            description=description,
            solution=solution,
            qe_email='*****@*****.**',
            qe_group='OVS QE',
            owner_email=args.owner_email,
            manager_email='*****@*****.**')

e.addBugs(args.bugs)
e.commit()
e.addBuilds([args.build], release=f"RHEL-{release[-1]}-Fast-Datapath")
print(e.url())
コード例 #30
0
def ensure_erratatool_auth():
    """Test (cheaply) that we at least have authentication to erratatool"""
    try:
        Erratum(errata_id=1)
    except GSSError:
        exit_unauthenticated()