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
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)')
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}')
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()))
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>'." )
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
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)
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()
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()
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)
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)
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)
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)
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()))
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}"' )
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')
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))
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)
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
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)
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
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")
def fail(msg): raise ModelValidationError(msg)
@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):
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.")