def validate(options): load_resources() if len(options.configs) < 1: log.error('no config files specified') sys.exit(1) used_policy_names = set() schm = schema.generate() errors = [] for config_file in options.configs: config_file = os.path.expanduser(config_file) if not os.path.exists(config_file): raise ValueError("Invalid path for config %r" % config_file) options.dryrun = True fmt = config_file.rsplit('.', 1)[-1] with open(config_file) as fh: if fmt in ('yml', 'yaml'): data = yaml.safe_load(fh.read()) elif fmt in ('json', ): data = json.load(fh) else: log.error("The config file must end in .json, .yml or .yaml.") raise ValueError( "The config file must end in .json, .yml or .yaml.") errors += schema.validate(data, schm) conf_policy_names = { p.get('name', 'unknown') for p in data.get('policies', ()) } dupes = conf_policy_names.intersection(used_policy_names) if len(dupes) >= 1: errors.append( ValueError( "Only one policy with a given name allowed, duplicates: %s" % (", ".join(dupes)))) used_policy_names = used_policy_names.union(conf_policy_names) if not errors: null_config = Bag(dryrun=True, log_group=None, cache=None, assume_role="na") for p in data.get('policies', ()): try: policy = Policy(p, null_config, Bag()) policy.validate() except Exception as e: msg = "Policy: %s is invalid: %s" % (p.get( 'name', 'unknown'), e) errors.append(msg) if not errors: log.info("Configuration valid: {}".format(config_file)) continue log.error("Configuration invalid: {}".format(config_file)) for e in errors: log.error("%s" % e) if errors: sys.exit(1)
class Missing(Filter): """Assert the absence of a particular resource. Intended for use at a logical account/subscription/project level This works as an effectively an embedded policy thats evaluated. """ schema = type_schema('missing', policy={'type': 'object'}, required=['policy']) def __init__(self, data, manager): super(Missing, self).__init__(data, manager) self.data['policy']['name'] = self.manager.ctx.policy.name self.embedded_policy = Policy(self.data['policy'], self.manager.config, self.manager.session_factory) def validate(self): if 'mode' in self.data['policy']: raise PolicyValidationError("Execution mode can't be specified in " "embedded policy %s" % self.data) if 'actions' in self.data['policy']: raise PolicyValidationError("Actions can't be specified in " "embedded policy %s" % self.data) self.embedded_policy.validate() return self def get_permissions(self): return self.embedded_policy.get_permissions() def process(self, resources, event=None): provider = clouds[self.manager.ctx.policy.provider_name]() # if the embedded policy only specifies one region, or only # being executed on a single region. if self.embedded_policy.region or len( self.manager.config.regions) <= 1: if (self.embedded_policy.region and self.embedded_policy.region != self.manager.config.region): return [] self.embedded_policy.expand_variables( self.embedded_policy.get_variables()) return not self.embedded_policy.poll() and resources or [] # For regional resources and multi-region execution, the policy matches if # the resource is missing in any region. found = {} for p in provider.initialize_policies( PolicyCollection([self.embedded_policy], self.manager.config), self.manager.config): p.expand_variables(p.get_variables()) p.validate() found[p.options.region] = p.poll() if not all(found.values()): return resources return []
class Missing(Filter): """Assert the absence of a particular resource. Intended for use at a logical account/subscription/project level This works as an effectively an embedded policy thats evaluated. """ schema = type_schema( 'missing', policy={'type': 'object'}, required=['policy']) def __init__(self, data, manager): super(Missing, self).__init__(data, manager) self.data['policy']['name'] = self.manager.ctx.policy.name self.embedded_policy = Policy( self.data['policy'], self.manager.config, self.manager.session_factory) def validate(self): if 'mode' in self.data['policy']: raise PolicyValidationError( "Execution mode can't be specified in " "embedded policy %s" % self.data) if 'actions' in self.data['policy']: raise PolicyValidationError( "Actions can't be specified in " "embedded policy %s" % self.data) self.embedded_policy.validate() return self def get_permissions(self): return self.embedded_policy.get_permissions() def process(self, resources, event=None): provider = clouds[self.manager.ctx.policy.provider_name]() # if the embedded policy only specifies one region, or only # being executed on a single region. if self.embedded_policy.region or len(self.manager.config.regions) <= 1: if (self.embedded_policy.region and self.embedded_policy.region != self.manager.config.region): return [] self.embedded_policy.expand_variables(self.embedded_policy.get_variables()) return not self.embedded_policy.poll() and resources or [] # For regional resources and multi-region execution, the policy matches if # the resource is missing in any region. found = {} for p in provider.initialize_policies( PolicyCollection([self.embedded_policy], self.manager.config), self.manager.config): p.expand_variables(p.get_variables()) p.validate() found[p.options.region] = p.poll() if not all(found.values()): return resources return []
def validate(options): load_resources() if len(options.configs) < 1: log.error('no config files specified') sys.exit(1) used_policy_names = set() schm = schema.generate() errors = [] for config_file in options.configs: config_file = os.path.expanduser(config_file) if not os.path.exists(config_file): raise ValueError("Invalid path for config %r" % config_file) options.dryrun = True fmt = config_file.rsplit('.', 1)[-1] with open(config_file) as fh: if fmt in ('yml', 'yaml'): data = yaml.safe_load(fh.read()) elif fmt in ('json',): data = json.load(fh) else: log.error("The config file must end in .json, .yml or .yaml.") raise ValueError("The config file must end in .json, .yml or .yaml.") errors += schema.validate(data, schm) conf_policy_names = { p.get('name', 'unknown') for p in data.get('policies', ())} dupes = conf_policy_names.intersection(used_policy_names) if len(dupes) >= 1: errors.append(ValueError( "Only one policy with a given name allowed, duplicates: %s" % ( ", ".join(dupes) ) )) used_policy_names = used_policy_names.union(conf_policy_names) if not errors: null_config = Config.empty(dryrun=True, account_id='na', region='na') for p in data.get('policies', ()): try: policy = Policy(p, null_config, Bag()) policy.validate() except Exception as e: msg = "Policy: %s is invalid: %s" % ( p.get('name', 'unknown'), e) errors.append(msg) if not errors: log.info("Configuration valid: {}".format(config_file)) continue log.error("Configuration invalid: {}".format(config_file)) for e in errors: log.error("%s" % e) if errors: sys.exit(1)
def validate(options): from c7n import schema if len(options.configs) < 1: log.error('no config files specified') sys.exit(1) used_policy_names = set() structure = StructureParser() errors = [] for config_file in options.configs: config_file = os.path.expanduser(config_file) if not os.path.exists(config_file): raise ValueError("Invalid path for config %r" % config_file) options.dryrun = True fmt = config_file.rsplit('.', 1)[-1] with open(config_file) as fh: if fmt in ('yml', 'yaml', 'json'): data = yaml.load(fh.read(), Loader=DuplicateKeyCheckLoader) else: log.error("The config file must end in .json, .yml or .yaml.") raise ValueError("The config file must end in .json, .yml or .yaml.") try: structure.validate(data) except PolicyValidationError as e: log.error("Configuration invalid: {}".format(config_file)) log.error("%s" % e) errors.append(e) continue load_resources(structure.get_resource_types(data)) schm = schema.generate() errors += schema.validate(data, schm) conf_policy_names = { p.get('name', 'unknown') for p in data.get('policies', ())} dupes = conf_policy_names.intersection(used_policy_names) if len(dupes) >= 1: errors.append(ValueError( "Only one policy with a given name allowed, duplicates: %s" % ( ", ".join(dupes) ) )) used_policy_names = used_policy_names.union(conf_policy_names) if not errors: null_config = Config.empty(dryrun=True, account_id='na', region='na') for p in data.get('policies', ()): try: policy = Policy(p, null_config, Bag()) policy.validate() except Exception as e: msg = "Policy: %s is invalid: %s" % ( p.get('name', 'unknown'), e) errors.append(msg) if not errors: log.info("Configuration valid: {}".format(config_file)) continue log.error("Configuration invalid: {}".format(config_file)) for e in errors: log.error("%s" % e) if errors: sys.exit(1)
def validate(options): from c7n import schema if len(options.configs) < 1: log.error('no config files specified') sys.exit(1) used_policy_names = set() structure = StructureParser() errors = [] found_deprecations = False footnotes = deprecated.Footnotes() for config_file in options.configs: config_file = os.path.expanduser(config_file) if not os.path.exists(config_file): raise ValueError("Invalid path for config %r" % config_file) options.dryrun = True fmt = config_file.rsplit('.', 1)[-1] with open(config_file) as fh: if fmt in ('yml', 'yaml', 'json'): # our loader is safe loader derived. data = yaml.load( fh.read(), Loader=DuplicateKeyCheckLoader) # nosec nosemgrep else: log.error("The config file must end in .json, .yml or .yaml.") raise ValueError( "The config file must end in .json, .yml or .yaml.") try: structure.validate(data) except PolicyValidationError as e: log.error("Configuration invalid: {}".format(config_file)) log.error("%s" % e) errors.append(e) continue load_resources(structure.get_resource_types(data)) schm = schema.generate() errors += schema.validate(data, schm) conf_policy_names = { p.get('name', 'unknown') for p in data.get('policies', ()) } dupes = conf_policy_names.intersection(used_policy_names) if len(dupes) >= 1: errors.append( ValueError( "Only one policy with a given name allowed, duplicates: %s" % (", ".join(dupes)))) used_policy_names = used_policy_names.union(conf_policy_names) source_locator = None if fmt in ('yml', 'yaml'): # For yaml files there is at least the expectation that the policy # name is on a line by itself. With JSON, the file could be one big # line. At this stage we are only attempting to find line number for # policies in yaml files. source_locator = SourceLocator(config_file) if not errors: null_config = Config.empty(dryrun=True, account_id='na', region='na') for p in data.get('policies', ()): try: policy = Policy(p, null_config, Bag()) policy.validate() # If the policy is invalid, there isn't much point checking # for deprecated usage as there is no guarantee as to the # state of the policy. if options.check_deprecations != deprecated.SKIP: report = deprecated.report(policy) if report: found_deprecations = True log.warning( "deprecated usage found in policy\n" + report.format(source_locator=source_locator, footnotes=footnotes)) except Exception as e: msg = "Policy: %s is invalid: %s" % (p.get( 'name', 'unknown'), e) errors.append(msg) if not errors: log.info("Configuration valid: {}".format(config_file)) continue log.error("Configuration invalid: {}".format(config_file)) for e in errors: log.error("%s" % e) if found_deprecations: notes = footnotes() if notes: log.warning("deprecation footnotes:\n" + notes) if options.check_deprecations == deprecated.STRICT: sys.exit(1) if errors: sys.exit(1)