Example #1
0
def ensure_dict(d, allow_empty=True):
    if allow_empty and d is None:
        return {}
    if not allow_empty and not d:
        raise ModelValidationError('a non-empty dict is required')
    if not isinstance(d, dict):
        raise ModelValidationError('a dict is required')
    return d
Example #2
0
    def validate(self):
        super().validate()

        if self.platforms(
        ) and not self.oci_builder() is OciBuilder.DOCKER_BUILDX:
            raise ModelValidationError(
                'must not specify platforms unless using docker-buildx as oci-builder'
            )
        if not self.platforms() and not self.platforms() is None:
            raise ModelValidationError(
                'must not specify empty list of platforms (omit attr instead)')
Example #3
0
 def validate(self):
     img_ref = check_type(self.image_reference(), str)
     # XXX this is an incomplete validation that will only detect some obvious errors,
     # such as missing image tag
     if not ':' in img_ref:
         raise ModelValidationError(f'img ref does not contain tag separator (:): {img_ref}')
     name, tag = img_ref.rsplit(':', 1)
     if not name:
         raise ModelValidationError(f'img ref name must not be empty: {img_ref}')
     if not tag:
         raise ModelValidationError(f'img ref tag must not be empty: {img_ref}')
Example #4
0
 def validate(self):
     super().validate()
     # We check for the existence of the 'main'-team as it is the only team that is *required* to
     # exist for any concourse server.
     if not self.raw.get('teams').get('main'):
         raise ModelValidationError('No team "main" defined.')
     # implicitly validate main team
     self.team_credentials('main')
     # Check for valid versions
     if self.concourse_version() not in ConcourseApiVersion:
         raise ModelValidationError(
             'Concourse version {v} not supported'.format(
                 v=self.concourse_version()))
Example #5
0
    def validate(self):
        super().validate()
        if self.nextversion() == version.NOOP and self.next_version_callback_path():
            raise ModelValidationError(
                f'not possible to configure "next_version_callback" if version is "{version.NOOP}"'
            )
        if not self.github_release_tag():
            raise ModelValidationError('At least one tag must be configured for the release.')

        # ensure the form of the first tag is as expected - otherwise no release can be created
        if not self.github_release_tag()['ref_template'].startswith('refs/tags/'):
            raise ModelValidationError(
                "The first release-tag must be of the form 'refs/tags/<tagname>'."
            )
Example #6
0
    def validate(self):
        super().validate()

        available_protocols = self.available_protocols()
        if len(available_protocols) < 1:
            raise ModelValidationError(
                'At least one available protocol must be configured '
                f"for Github config '{self.name()}'")
        if Protocol.SSH in available_protocols and not self.ssh_url():
            raise ModelValidationError(
                f"SSH url is missing for Github config '{self.name()}'")
        if Protocol.HTTPS in available_protocols and not self.http_url():
            raise ModelValidationError(
                f"HTTP url is missing for Github config '{self.name()}'")

        self.credentials() and self.credentials().validate()  # XXX refactor
Example #7
0
    def _apply_traits(self, pipeline_def):
        transformers = [trait.transformer() for trait in pipeline_def._traits_dict.values()]
        transformers_dict = {t.name: t for t in transformers}
        transformer_names = set(transformers_dict.keys())

        for transformer in transformers:
            if not set(transformer.dependencies()).issubset(transformer_names):
                missing = set(transformer.dependencies()) - transformer_names
                raise ModelValidationError(
                    f'{pipeline_def}: trait requires missing traits: ' + ', '.join(missing)
                )

        # order transformers according to dependencies
        toposorter = graphlib.TopologicalSorter()
        for transformer in transformers:
            dependencies = transformer.order_dependencies() & transformer_names
            toposorter.add(transformer.name, *dependencies)

        ordered_transformers = [
            transformers_dict[name] for name in toposorter.static_order()
        ]

        # hardcode meta trait transformer
        ordered_transformers.append(MetaTraitTransformer())

        # inject new steps
        for transformer in ordered_transformers:
            for step in transformer.inject_steps():
                pipeline_def.add_step(step)

        # do remaining processing
        for transformer in ordered_transformers:
            transformer.process_pipeline_args(pipeline_def)
Example #8
0
 def validate(self):
     tgt_team_names = {jm.team_name() for jm in self}
     for team_name in (jm.team_name() for jm in self):
         if not team_name in tgt_team_names:
             raise ModelValidationError(
                 f'{team_name=} must only be specified once')
         tgt_team_names.remove(team_name)
 def validate(self):
     super().validate()
     if self.raw.get('merge_policy') and self.raw.get('merge_policies'):
         raise ModelValidationError(
             "Only one of 'merge_policy' and 'merge_policies' is allowed.")
     for config in self.merge_policies():
         config.validate()
Example #10
0
 def validate(self):
     # We check for the existence of the 'main'-team as it is the only team that is *required* to
     # exist for any concourse server.
     if not self.main_team():
         raise ModelValidationError("No team 'main' defined.")
     # explicitly validate main team
     self.main_team().validate()
Example #11
0
    def _apply_traits(self, pipeline_def):
        transformers = [
            trait.transformer()
            for trait in pipeline_def._traits_dict.values()
        ]
        transformers_dict = {t.name: t for t in transformers}
        transformer_names = set(transformers_dict.keys())

        for transformer in transformers:
            if not set(transformer.dependencies()).issubset(transformer_names):
                missing = set(transformer.dependencies()) - transformer_names
                raise ModelValidationError(
                    f'{pipeline_def}: trait requires missing traits: ' +
                    ', '.join(missing))

        # order transformers according to dependencies
        transformer_dependencies = {
            t.name: t.order_dependencies() & transformer_names
            for t in transformers
        }

        ordered_transformers = []
        for name in toposort.toposort_flatten(transformer_dependencies):
            ordered_transformers.append(transformers_dict[name])

        # inject new steps
        for transformer in ordered_transformers:
            for step in transformer.inject_steps():
                pipeline_def.add_step(step)

        # do remaining processing
        for transformer in ordered_transformers:
            transformer.process_pipeline_args(pipeline_def)
Example #12
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     if not isinstance(self.raw, dict):
         raise ModelValidationError(
             f'{self.__class__.__name__} expects a dict - got: {self.raw=}'
         )
     self._apply_defaults(raw_dict=self.raw)
Example #13
0
    def process_pipeline_args(self, pipeline_args: JobVariant):
        # our steps depends on dependency descriptor step
        component_descriptor_step = pipeline_args.step(
            concourse.model.traits.component_descriptor.DEFAULT_COMPONENT_DESCRIPTOR_STEP_NAME
        )
        if self.trait.protecode():
            self.image_scan_step._add_dependency(component_descriptor_step)
        if self.trait.clam_av():
            self.malware_scan_step._add_dependency(component_descriptor_step)

        for trait_name in self.trait.trait_depends():
            if not pipeline_args.has_trait(trait_name):
                raise ModelValidationError(f'dependency towards absent trait: {trait_name}')

            depended_on_trait = pipeline_args.trait(trait_name)
            # XXX refactor Trait/TraitTransformer
            transformer = depended_on_trait.transformer()
            # XXX step-injection may have (unintended) side-effects :-/
            depended_on_step_names = {step.name for step in transformer.inject_steps()}

            for step in pipeline_args.steps():
                if not step.name in depended_on_step_names:
                    continue
                if self.trait.protecode():
                    self.image_scan_step._add_dependency(step)
                    # prevent cyclic dependencies (from auto-injected depends)
                    if self.image_scan_step.name in step.depends():
                        step._remove_dependency(self.image_scan_step)

                if self.trait.clam_av():
                    self.malware_scan_step._add_dependency(step)
                    # prevent cyclic dependencies (from auto-injected depends)
                    if self.malware_scan_step.name in step.depends():
                        step._remove_dependency(self.malware_scan_step)
Example #14
0
    def process_pipeline_args(self, pipeline_args: JobVariant):
        # our step depends on dependency descriptor step
        component_descriptor_step = pipeline_args.step('component_descriptor')
        self.image_scan_step._add_dependency(component_descriptor_step)

        for trait_name in self.trait.trait_depends():
            if not pipeline_args.has_trait(trait_name):
                raise ModelValidationError(
                    f'dependency towards absent trait: {trait_name}')

            depended_on_trait = pipeline_args.trait(trait_name)
            # XXX refactor Trait/TraitTransformer
            transformer = depended_on_trait.transformer()
            # XXX step-injection may have (unintended) side-effects :-/
            depended_on_step_names = {
                step.name
                for step in transformer.inject_steps()
            }

            for step in pipeline_args.steps():
                if not step.name in depended_on_step_names:
                    continue
                self.image_scan_step._add_dependency(step)
                # prevent cyclic dependencies (from auto-injected depends)
                if self.image_scan_step.name in step.depends():
                    step._remove_dependency(self.image_scan_step)
Example #15
0
 def validate(self):
     super().validate()
     # Check for valid versions
     if self.concourse_version() not in ConcourseApiVersion:
         raise ModelValidationError(
             'Concourse version {v} not supported'.format(
                 v=self.concourse_version()))
Example #16
0
 def validate(self):
     super().validate()
     if self.nextversion(
     ) == version.NOOP and self.next_version_callback_path():
         raise ModelValidationError(
             f'not possible to configure "next_version_callback" if version is "{version.NOOP}"'
         )
Example #17
0
 def _validate_dict(self):
     super()._validate_dict()
     # We check for the existence of the 'main'-team as it is the only team that is *required* to
     # exist for any concourse server.
     if not self.snd.teams['main']:
         raise ModelValidationError('No team "main" defined.')
     # implicitly validate main team
     self.team_credentials('main')
Example #18
0
 def _validate_dict(self):
     super()._validate_dict()
     if self.has_github_oauth_credentials():
         github_org_and_team = self.github_auth_team(split=True)
         # explicitly check for expected structure, raise error if not found
         if github_org_and_team and len(github_org_and_team) == 2:
             github_org, github_team = github_org_and_team
             if github_org and github_team:
                 return
         raise ModelValidationError('Invalid github-oauth team. Expected <org>/<team>, got {t}'.format(t=github_org_and_team))
Example #19
0
    def credentials(self, technical_user_name: str = None):
        technical_users = self._technical_user_credentials()
        if technical_user_name:
            for credential in technical_users:
                if credential.username() == technical_user_name:
                    return credential
            raise ModelValidationError(
                f'Did not find technical user "{technical_user_name}" '
                f'for Github config "{self.name()}"')

        return random.choice(technical_users)
Example #20
0
 def validate(self):
     super().validate()
     for label in self.resource_labels():
         try:
             dacite.from_dict(
                 data_class=cm.Label,
                 data=label,
                 config=dacite.Config(strict=True),
             )
         except dacite.DaciteError as e:
             raise ModelValidationError(f"Invalid '{label=}'.") from e
Example #21
0
    def credentials(self, technical_user_name: str = None):
        technical_users = [
            GithubCredentials(user) for user in self.raw.get('technical_users')
        ]
        if technical_user_name:
            for user in technical_users:
                if user.username() == technical_user_name:
                    return user
            raise ModelValidationError(
                f'Did not find technical user "{technical_user_name}" '
                f'for Github config "{self.name()}"')

        return random.choice(technical_users)
Example #22
0
    def __init__(
        self,
        *args,
        platform: str = None,
        **kwargs,
    ):
        super().__init__(*args, **kwargs)
        if not isinstance(self.raw, dict):
            raise ModelValidationError(
                f'{self.__class__.__name__} expects a dict - got: {self.raw=}')
        self._apply_defaults(raw_dict=self.raw)
        self._platform = platform

        if platform:
            self._base_name = self._name
            self._name += f'-{platform.replace("/", "-")}'
        else:
            self._base_name = self._name
Example #23
0
 def _validate_required_attributes(self):
     super()._validate_required_attributes()
     key_attrs = [k for k in self.raw.keys() if k.startswith('key-')]
     if not 'key' in self.raw and not key_attrs:
         raise ModelValidationError(
             "Either 'key' or 'key-<number>' key must be present")
Example #24
0
def fail(msg):
    raise ModelValidationError(msg)
Example #25
0
    @staticmethod
    def from_dict(raw_dict: dict):
        # determine scheme version
        if not (meta_dict := raw_dict.get('meta')):
            schema_version = SchemaVersion.V1
        else:
            meta = dacite.from_dict(data_class=Meta,
                                    data=meta_dict,
                                    config=dacite.Config(cast=[SchemaVersion
                                                               ], ))
            schema_version = meta.schemaVersion

        if schema_version == SchemaVersion.V1:
            return ComponentDescriptorV1(**raw_dict)
        else:
            raise ModelValidationError(
                f'unknown schema version: {schema_version}')

    @deprecated.deprecated(reason='ComponentDescriptor is deprecated')
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if 'components' not in self.raw:
            self.raw['components'] = []
        if 'component_overwrites' not in self.raw:
            self.raw['component_overwrites'] = []
        if 'meta' not in self.raw:
            self.raw['meta'] = {'schemaVersion': SchemaVersion.V1.value}

    def _optional_attributes(self):
        return {'components', 'component_overwrites', 'meta'}

    def components(self):
Example #26
0
 def validate(self):
     super().validate()
     if not (self.protecode() or self.clam_av()):
         raise ModelValidationError(
             "at least one of 'protecode' or 'clam_av' must be defined.")