Ejemplo n.º 1
0
    def get_denylisted_srpms(self):
        src_config = get_source_container(self.workflow, fallback={})
        denylist_srpms = src_config.get('denylist_srpms')
        if not denylist_srpms:
            self.log.debug('denylist_srpms is not defined in reactor_config_map')
            return []

        denylist_url = denylist_srpms['denylist_url']
        denylist_key = denylist_srpms['denylist_key']
        req_session = get_retrying_requests_session()

        response = req_session.get(denylist_url)
        response.raise_for_status()
        response_json = response.json()

        if denylist_key not in response_json:
            self.log.debug('deny list json : %s', response_json)
            raise RuntimeError('Denylist key: {} missing in denylist json from : {}'.
                               format(denylist_key, denylist_url))

        deny_list = response_json[denylist_key]

        if not isinstance(deny_list, list):
            self.log.error('Wrong denylist: %s', repr(deny_list))
            raise RuntimeError('Denylist value in key: {} is not list: {}'.
                               format(denylist_key, type(deny_list)))

        wrong_types = [pkg for pkg in deny_list if not isinstance(pkg, str)]
        if wrong_types:
            self.log.error('Wrong types in denylist, should be str: %s', repr(deny_list))
            raise RuntimeError('Values in denylist has to be all strings')

        self.log.debug('denylisted srpms: %s', deny_list)
        return deny_list
    def exclude_files_from_remote_sources(self, remote_sources_map,
                                          remote_sources_dir):
        """
        :param remote_sources_map: dict, keys are filenames of sources from cachito,
                                         values are url with json from cachito
        :param remote_sources_dir: str, dir with downloaded sources from cachito
        """
        src_config = get_source_container(self.workflow, fallback={})
        denylist_sources_url = src_config.get('denylist_sources')

        if not denylist_sources_url:
            self.log.debug('no "denylist_sources" defined, not excluding any '
                           'files from remote sources')
            return

        request_session = get_retrying_requests_session()

        denylist_sources = self._get_denylist_sources(request_session,
                                                      denylist_sources_url)

        # key: full path to source archive, value: cachito json
        full_remote_sources_map = self._create_full_remote_sources_map(
            request_session, remote_sources_map, remote_sources_dir)
        for remote_archive, remote_json in full_remote_sources_map.items():
            unpack_dir = remote_archive + '_unpacked'

            with tarfile.open(remote_archive) as tf:
                tf.extractall(unpack_dir)

            delete_app = self._check_if_package_excluded(
                remote_json['packages'], denylist_sources, remote_archive)

            # if any package in cachito json matched excluded entry,
            # remove 'app' from sources, except 'app/vendor' when exists
            if delete_app and os.path.exists(os.path.join(unpack_dir, 'app')):
                self._delete_app_directory(remote_sources_dir, unpack_dir,
                                           remote_archive)

            # search for excluded matches
            matches = self._get_excluded_matches(unpack_dir, denylist_sources)

            self._remove_excluded_matches(matches)

            # delete former archive
            os.unlink(remote_archive)

            # re-create new archive without excluded content
            with tarfile.open(remote_archive, "w:gz") as tar:
                for add_file in os.listdir(unpack_dir):
                    tar.add(os.path.join(unpack_dir, add_file),
                            arcname=add_file)

            # cleanup unpacked dir
            shutil.rmtree(unpack_dir)
Ejemplo n.º 3
0
    def get_srpm_urls(self, sigkeys=None, insecure=False):
        """Fetch SRPM download URLs for each image generated by a build

        Build each possible SRPM URL and check if the URL is available,
        respecting the signing intent preference order.

        :param sigkeys: list, strings for keys which signed the srpms to be fetched
        :return: list, strings with URLs pointing to SRPM files
        """
        if not sigkeys:
            sigkeys = ['']

        self.log.debug('get srpm_urls: %s', self.koji_build_id)
        archives = self.session.listArchives(self.koji_build_id, type='image')
        self.log.debug('archives: %s', archives)
        rpms = [rpm for archive in archives
                for rpm in self.session.listRPMs(imageID=archive['id'])]

        src_config = get_source_container(self.workflow, fallback={})
        blacklist_srpms = src_config.get('blacklist_srpms', [])

        srpm_build_paths = {}
        for rpm in rpms:
            rpm_id = rpm['id']
            self.log.debug('Resolving SRPM for RPM ID: %s', rpm_id)

            if rpm['external_repo_name'] != 'INTERNAL':
                msg = ('RPM comes from an external repo (RPM ID: {}). '
                       'External RPMs are currently not supported.').format(rpm_id)
                raise RuntimeError(msg)

            rpm_hdr = self.session.getRPMHeaders(rpm_id, headers=['SOURCERPM'])
            if 'SOURCERPM' not in rpm_hdr:
                raise RuntimeError('Missing SOURCERPM header (RPM ID: {})'.format(rpm_id))

            srpm_name = rpm_hdr['SOURCERPM'].rsplit('-', 2)[0]

            if any(black == srpm_name for black in blacklist_srpms):
                self.log.debug('skipping blacklisted srpm %s', rpm_hdr['SOURCERPM'])
                continue

            srpm_filename = rpm_hdr['SOURCERPM']
            if srpm_filename in srpm_build_paths:
                continue
            rpm_build = self.session.getBuild(rpm['build_id'], strict=True)
            base_url = self.pathinfo.build(rpm_build)
            srpm_build_paths[srpm_filename] = base_url

        srpm_urls = []
        missing_srpms = []
        req_session = get_retrying_requests_session()
        for srpm_filename, base_url in srpm_build_paths.items():
            for sigkey in sigkeys:
                # koji uses lowercase for paths. We make sure the sigkey is in lower case
                url_candidate = self.assemble_srpm_url(base_url, srpm_filename, sigkey.lower())
                request = req_session.head(url_candidate, verify=not insecure)
                if request.ok:
                    srpm_urls.append({'url': url_candidate})
                    self.log.debug('%s is available for signing key "%s"', srpm_filename, sigkey)
                    break

            else:
                self.log.error('%s not found for the given signing intent: %s"', srpm_filename,
                               self.signing_intent)
                missing_srpms.append(srpm_filename)

        if missing_srpms:
            raise RuntimeError('Could not find files signed by any of {} for these SRPMS: {}'
                               .format(sigkeys, missing_srpms))

        return srpm_urls
Ejemplo n.º 4
0
    def run(self):
        # Only run if the build was successful
        if self.workflow.build_process_failed:
            self.log.info("Not running for failed build")
            return []

        # Work out the name of the image to pull
        if not self.workflow.tag_conf.unique_images:
            raise ValueError(
                "no unique image set, impossible to verify media types")
        image = self.workflow.tag_conf.unique_images[0]

        registries = deepcopy(get_registries(self.workflow, {}))
        media_in_registry = {}
        expect_list_only = self.get_manifest_list_only_expectation()

        for registry_name, registry in registries.items():
            expected_media_types = set(registry.get('expected_media_types',
                                                    []))
            media_types = set()

            if expect_list_only:
                expected_media_types = set(
                    [MEDIA_TYPE_DOCKER_V2_MANIFEST_LIST])

            media_in_registry[registry_name] = {
                'expected': expected_media_types
            }

            pullspec = image.copy()
            pullspec.registry = registry_name
            insecure = registry.get('insecure', False)
            secret = registry.get('secret', None)

            kwargs = {}
            if PLUGIN_FETCH_SOURCES_KEY in self.workflow.prebuild_results:
                # For source containers, limit the versions we ask
                # about (and, if necessary, the expected media types).
                # This can help to avoid issues with tooling that is
                # unable to deal with the number of layers in these
                # images.
                src_config = get_source_container(self.workflow, fallback={})
                limit_media_types = src_config.get('limit_media_types')
                if limit_media_types is not None:
                    short_name = {
                        v: k
                        for k, v in ManifestDigest.content_type.items()
                    }
                    versions = tuple(short_name[mt]
                                     for mt in limit_media_types)
                    kwargs['versions'] = versions

                    if expected_media_types:
                        expected_media_types.intersection_update(
                            set(limit_media_types))

            digests = get_manifest_digests(pullspec,
                                           registry_name,
                                           insecure,
                                           secret,
                                           require_digest=False,
                                           **kwargs)
            if digests:
                if digests.v2_list:
                    media_types.add(MEDIA_TYPE_DOCKER_V2_MANIFEST_LIST)
                if digests.v2:
                    media_types.add(MEDIA_TYPE_DOCKER_V2_SCHEMA2)
                if digests.v1:
                    media_types.add(MEDIA_TYPE_DOCKER_V2_SCHEMA1)
                if digests.oci:
                    media_types.add(MEDIA_TYPE_OCI_V1)
                if digests.oci_index:
                    media_types.add(MEDIA_TYPE_OCI_V1_INDEX)

            media_in_registry[registry_name]['found'] = media_types

        should_raise = False
        all_found = set()
        for registry_name, manifests in media_in_registry.items():
            all_found.update(manifests['found'])
            if manifests['expected'] - manifests['found']:
                should_raise = True
                self.log.error(
                    "expected media types %s not in available media types %s,"
                    " for registry %s",
                    sorted(manifests['expected'] - manifests['found']),
                    sorted(manifests['found']), registry_name)

        if should_raise:
            raise KeyError("expected media types were not found")

        if expect_list_only:
            return [MEDIA_TYPE_DOCKER_V2_MANIFEST_LIST]
        return sorted(all_found)