Generate validation rules for map attributes - #1020
Conversation
Extend the generator to traverse Smithy model structure types (Tags → Tag → TagKey/TagValue) to extract pattern and length constraints for map attributes. - Add shape traversal functions to follow list/map/structure types - Add generateMapRuleFile for map[string]string validation rules - Add map_rule.go.tmpl template for generated map rules - Handle PCRE negative lookaheads by stripping (Go regexp incompatible) - Skip malformed Unicode patterns with error message Generates 149 new tag validation rules plus additional map rules for environment_variables, attributes, labels, etc. Closes #1019
- Extract tagStructureMembers config with godoc explaining case variations - Add getMemberCaseInsensitive for case-insensitive member lookup - Add getTarget helper to simplify shape reference extraction - Extract resolveKeyValuePair to deduplicate map/structure handling - Reduce traverseToTagConstraints from 80 to 30 lines
- Add shapes_test.go with tests for extractShapeName, getTarget, and traverseToMapConstraints - Cover map, list, and structure shape types - Test case variations (Key/Value vs key/value vs Name/Value) - Test edge cases (non-string members, mixed members, list values) - Rename traverseToTagConstraints to traverseToMapConstraints
Adds `listmap()` function to HCL mapping syntax for explicitly specifying list, key, and value constraint shapes. This enables tag validation rules for services where Smithy models use list-of-structure patterns. Changes: - Extends generator to support `listmap(ListShape, KeyShape, ValueShape)` syntax in mapping files - Shapes in eval context are now rich objects carrying all constraint info - Transform functions (`uppercase`, `replace`) operate on shape enum values - Adds 124 new tag validation rules across 48 services Closes #1019
- Add safe type assertions in validMapping, findRawShape, fetchNumber, fetchString to prevent panics on unexpected types - Add nil check for schema in generateRuleFile - Remove dead code: validListMapping, resolveStructureMembers, parseListMapExpr, makeListTransformFunction - Remove tests for deleted functions - Fix variable shadowing: rename shapeType to typeStr in makeShapeValue - Update HCL Transform System documentation comments - Remove unused hclsyntax import
- Add safe type assertions and error logging throughout generator - Compose map result type from nested shapes instead of flat fields - Rename listmap() to map() for Terraform-idiomatic syntax - Validate max tag count per resource using Smithy length traits - Collapse listmap rule generation into thin adapter over generateMapRuleFile - Add table-driven tests for replacePattern - Move compiled regexps to package level - Replace deprecated ioutil.ReadFile with os.ReadFile - Write pattern validation errors to stderr consistently
Resolve conflicts: - Adopt genutils package rename (generator-utils → genutils) - Adopt generatedFiles tracking with CleanDir - Drop removed elastictranscoder rules - Regenerate provider.go and docs/rules/README.md
Instead of silently stripping negative lookahead patterns like (?\!aws:), extract literal prefix strings and generate strings.HasPrefix checks in the map rule template. 18 tag rules across 8 services now enforce the aws: prefix restriction. Also improves generator code quality: - Return nil from convertSmithyShape on marshal/unmarshal error - Remove unused KeyEnum/ValueEnum fields from mapRuleMeta - Fix "1 characters" grammar in map rule template messages - Update TestTransformComposition to test shape object path - Suppress repeated extractServiceNamespace warnings - Simplify schema lookup, rule meta construction, and compatibility transforms via extracted helpers - Warn and skip incompatible map rule patterns (e.g., surrogate pairs)
Cover three representative rule shapes: - ECS: items max, key/value pattern and length constraints - Signer: prefix deny (aws:) and key pattern - S3: minimal constraints (key min length only)
There was a problem hiding this comment.
Pull request overview
This PR expands the rule generator to emit validation rules for map(string) attributes (notably tags, plus other map attributes like labels, parameters, and attributes) by extracting key/value constraints from AWS Smithy models, resulting in a large set of newly generated rule files and a few related rule updates.
Changes:
- Adds many generated
*_invalid_tags.goand othermap(string)validation rule files across AWS resources/services. - Adds/updates a small set of tests for representative generated rules (e.g., Signer, S3) and updates ECR pattern expectations.
- Updates supporting utilities and models (API models submodule bump;
LoadProviderSchemausesos.ReadFile; some enum/pattern/limit adjustments in existing rules).
Reviewed changes
Copilot reviewed 166 out of 248 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| rules/models/aws_sns_topic_invalid_tags.go | Adds generated tag map validation for aws_sns_topic.tags (length checks). |
| rules/models/aws_signer_signing_profile_invalid_tags.go | Adds generated tag rule with prefix deny (aws:) and pattern enforcement. |
| rules/models/aws_signer_signing_profile_invalid_tags_test.go | Adds tests for Signer tag prefix deny + pattern validation. |
| rules/models/aws_shield_protection_group_invalid_tags.go | Adds generated tag rule including max tag count and key/value length checks. |
| rules/models/aws_sfn_state_machine_invalid_tags.go | Adds generated tag map validation for Step Functions state machines. |
| rules/models/aws_sfn_activity_invalid_tags.go | Adds generated tag map validation for Step Functions activities. |
| rules/models/aws_servicecatalog_service_action_invalid_definition.go | Adds generated map validation for definition (currently uses tag-oriented messages). |
| rules/models/aws_servicecatalog_provisioned_product_invalid_provisioning_parameters.go | Adds generated map validation for provisioning_parameters (currently uses tag-oriented messages). |
| rules/models/aws_service_discovery_instance_invalid_attributes.go | Adds generated map validation for attributes including key/value patterns (currently uses tag-oriented messages). |
| rules/models/aws_secretsmanager_secret_invalid_tags.go | Adds generated tag map validation for Secrets Manager secrets. |
| rules/models/aws_s3_bucket_object_invalid_tags.go | Adds generated tag key min-length validation for S3 bucket objects. |
| rules/models/aws_s3_bucket_invalid_tags.go | Adds generated tag key min-length validation for S3 buckets. |
| rules/models/aws_s3_bucket_invalid_tags_test.go | Adds tests for S3 bucket tag key min-length behavior. |
| rules/models/aws_route53_zone_invalid_tags.go | Adds generated tag rule including max tag count for Route53 zones. |
| rules/models/aws_route53_resolver_rule_invalid_tags.go | Adds generated tag rule including max tag count for Route53 Resolver rules. |
| rules/models/aws_route53_resolver_query_log_config_invalid_tags.go | Adds generated tag rule including max tag count for query log configs. |
| rules/models/aws_route53_resolver_firewall_rule_group_invalid_tags.go | Adds generated tag rule including max tag count for firewall rule groups. |
| rules/models/aws_route53_resolver_firewall_rule_group_association_invalid_tags.go | Adds generated tag rule including max tag count for firewall rule group associations. |
| rules/models/aws_route53_resolver_firewall_domain_list_invalid_tags.go | Adds generated tag rule including max tag count for firewall domain lists. |
| rules/models/aws_route53_resolver_endpoint_invalid_tags.go | Adds generated tag rule including max tag count for Resolver endpoints. |
| rules/models/aws_route53_health_check_invalid_tags.go | Adds generated tag rule including max tag count for health checks. |
| rules/models/aws_redshift_subnet_group_invalid_tags.go | Adds generated tag validation for Redshift subnet groups (very large max constraints). |
| rules/models/aws_redshift_snapshot_schedule_invalid_tags.go | Adds generated tag validation for Redshift snapshot schedules (very large max constraints). |
| rules/models/aws_redshift_snapshot_copy_grant_invalid_tags.go | Adds generated tag validation for Redshift snapshot copy grants (very large max constraints). |
| rules/models/aws_redshift_parameter_group_invalid_tags.go | Adds generated tag validation for Redshift parameter groups (very large max constraints). |
| rules/models/aws_redshift_event_subscription_invalid_tags.go | Adds generated tag validation for Redshift event subscriptions (very large max constraints). |
| rules/models/aws_redshift_cluster_invalid_tags.go | Adds generated tag validation for Redshift clusters (very large max constraints). |
| rules/models/aws_quicksight_data_source_invalid_tags.go | Adds generated tag validation for QuickSight data sources (includes value min-length). |
| rules/models/aws_kinesisanalyticsv2_application_invalid_tags.go | Adds generated tag validation for Kinesis Analytics v2 applications (includes max tag count). |
| rules/models/aws_kinesis_stream_invalid_tags.go | Adds generated tag validation for Kinesis streams (includes max tag count). |
| rules/models/aws_kinesis_analytics_application_invalid_tags.go | Adds generated tag validation for Kinesis Analytics applications (includes max tag count). |
| rules/models/aws_iot_thing_invalid_attributes.go | Adds generated map validation for attributes including key/value patterns (currently uses tag-oriented messages). |
| rules/models/aws_inspector_resource_group_invalid_tags.go | Adds generated tag validation for Inspector resource groups (includes max tag count/value min-length). |
| rules/models/aws_imagebuilder_image_recipe_invalid_tags.go | Adds generated tag rule with reserved prefix deny, pattern, and length checks. |
| rules/models/aws_imagebuilder_image_pipeline_invalid_tags.go | Adds generated tag rule with reserved prefix deny, pattern, and length checks. |
| rules/models/aws_imagebuilder_image_invalid_tags.go | Adds generated tag rule with reserved prefix deny, pattern, and length checks. |
| rules/models/aws_imagebuilder_distribution_configuration_invalid_tags.go | Adds generated tag rule with reserved prefix deny, pattern, and length checks. |
| rules/models/aws_imagebuilder_component_invalid_tags.go | Adds generated tag rule with reserved prefix deny, pattern, and length checks. |
| rules/models/aws_guardduty_filter_invalid_tags.go | Adds generated tag rule with reserved prefix deny, pattern, and length checks. |
| rules/models/aws_glue_workflow_invalid_tags.go | Adds generated tag validation for Glue workflows. |
| rules/models/aws_glue_workflow_invalid_default_run_properties.go | Adds generated map validation for default_run_properties (currently uses tag-oriented messages). |
| rules/models/aws_glue_schema_invalid_tags.go | Adds generated tag validation for Glue schemas. |
| rules/models/aws_glue_registry_invalid_tags.go | Adds generated tag validation for Glue registries. |
| rules/models/aws_glue_partition_invalid_parameters.go | Adds generated map validation for parameters (currently uses tag-oriented messages). |
| rules/models/aws_glue_ml_transform_invalid_tags.go | Adds generated tag validation for Glue ML transforms. |
| rules/models/aws_glue_dev_endpoint_invalid_tags.go | Adds generated tag validation for Glue dev endpoints. |
| rules/models/aws_glue_catalog_table_invalid_parameters.go | Adds generated map validation for parameters (currently uses tag-oriented messages). |
| rules/models/aws_glue_catalog_database_invalid_parameters.go | Adds generated map validation for parameters (currently uses tag-oriented messages). |
| rules/models/aws_elasticsearch_domain_invalid_tags.go | Adds generated tag validation for Elasticsearch domains. |
| rules/models/aws_elastic_beanstalk_environment_invalid_tags.go | Adds generated tag validation for Elastic Beanstalk environments (includes value min-length). |
| rules/models/aws_elastic_beanstalk_application_version_invalid_tags.go | Adds generated tag validation for Elastic Beanstalk app versions (includes value min-length). |
| rules/models/aws_elastic_beanstalk_application_invalid_tags.go | Adds generated tag validation for Elastic Beanstalk applications (includes value min-length). |
| rules/models/aws_eks_node_group_invalid_tags.go | Adds generated tag validation for EKS node groups. |
| rules/models/aws_eks_node_group_invalid_labels.go | Adds generated map validation for EKS node group labels (currently uses tag-oriented messages). |
| rules/models/aws_eks_node_group_invalid_ami_type.go | Updates allowed AMI type enum values (removes several). |
| rules/models/aws_eks_identity_provider_config_invalid_tags.go | Adds generated tag validation for EKS identity provider configs. |
| rules/models/aws_eks_fargate_profile_invalid_tags.go | Adds generated tag validation for EKS Fargate profiles. |
| rules/models/aws_eks_addon_invalid_tags.go | Adds generated tag validation for EKS addons. |
| rules/models/aws_ecs_account_setting_default_invalid_name.go | Updates allowed ECS account setting names (removes fargateEventWindows). |
| rules/models/aws_ecr_repository_policy_invalid_repository.go | Updates ECR repository name regex and emitted pattern string. |
| rules/models/aws_ecr_repository_invalid_name.go | Updates ECR repository name regex and emitted pattern string. |
| rules/models/aws_ecr_pull_through_cache_rule_invalid_ecr_repository_prefix.go | Updates pull-through cache repository prefix regex and emitted pattern string. |
| rules/models/aws_ecr_lifecycle_policy_invalid_repository.go | Updates ECR lifecycle policy repository regex and emitted pattern string. |
| rules/models/aws_ecr_lifecycle_policy_invalid_repository_test.go | Updates test expected pattern string to match new ECR regex. |
| rules/models/aws_dynamodb_table_invalid_tags.go | Adds generated tag validation for DynamoDB tables. |
| rules/models/aws_devicefarm_network_profile_invalid_tags.go | Adds generated tag validation for Device Farm network profiles (includes max tag count). |
| rules/models/aws_devicefarm_device_pool_invalid_tags.go | Adds generated tag validation for Device Farm device pools (includes max tag count). |
| rules/models/aws_datapipeline_pipeline_invalid_tags.go | Adds generated tag validation for Data Pipeline pipelines (includes max tag count). |
| rules/models/aws_connect_contact_flow_invalid_tags.go | Adds generated tag validation for Connect contact flows (includes prefix deny + unicode pattern). |
| rules/models/aws_config_organization_managed_rule_invalid_input_parameters.go | Adds generated string-length validation for input_parameters. |
| rules/models/aws_config_organization_custom_rule_invalid_input_parameters.go | Adds generated string-length validation for input_parameters. |
| rules/models/aws_cloudwatch_log_resource_policy_invalid_policy_document.go | Adjusts max length constraint and message for policy_document. |
| rules/models/aws_cloudwatch_event_bus_invalid_tags.go | Adds generated tag validation for CloudWatch event buses. |
| rules/models/aws_athena_workgroup_invalid_tags.go | Adds generated tag validation for Athena workgroups. |
| rules/models/aws_appmesh_virtual_gateway_invalid_tags.go | Adds generated tag validation for App Mesh virtual gateways (includes max tag count). |
| rules/models/aws_appmesh_gateway_route_invalid_tags.go | Adds generated tag validation for App Mesh gateway routes (includes max tag count). |
| rules/models/aws_appconfig_environment_invalid_tags.go | Adds generated tag validation for AppConfig environments. |
| rules/models/aws_appconfig_deployment_strategy_invalid_tags.go | Adds generated tag validation for AppConfig deployment strategies. |
| rules/models/aws_appconfig_deployment_invalid_tags.go | Adds generated tag validation for AppConfig deployments. |
| rules/models/aws_appconfig_configuration_profile_invalid_tags.go | Adds generated tag validation for AppConfig configuration profiles. |
| rules/models/aws_appconfig_application_invalid_tags.go | Adds generated tag validation for AppConfig applications. |
| rules/models/aws_api_gateway_domain_name_invalid_security_policy.go | Updates allowed security policy enum values (removes one). |
| rules/models/aws_amplify_branch_invalid_environment_variables.go | Adds generated map validation for Amplify branch environment_variables (match-all patterns). |
| rules/models/aws_amplify_app_invalid_environment_variables.go | Adds generated map validation for Amplify app environment_variables (match-all patterns). |
| rules/models/api-models-aws | Updates the api-models-aws submodule revision used by the generator. |
| rules/genutils/schema.go | Replaces deprecated ioutil.ReadFile with os.ReadFile. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use attribute name in messages instead of hardcoded "tag" (e.g., "definition key" for non-tag map attributes) - Fix "1 characters" pluralization to "1 character" - Skip match-all patterns (^.*$, ^(?s).*$) instead of compiling them - Treat Smithy sentinel max (2147483647) as no constraint, removing 6 Redshift rules that had no real validation - Fix generated file header to use standard Go generate comment format so CleanDir can detect stale files - Fix extra space in pattern_rule template (func (val → func(val) - Fix import ordering in pattern_rule_test template - Add gofmt check to generated_code_checks CI workflow - Scope .gitignore generator entry to root directory only
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 88 out of 1730 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Strip ^(^...$)$ patterns where outer anchors duplicate inner ones - Update map rule template comments from "checks the pattern is valid" to "validates map keys and values" - Keep gofmt -w in CI since git diff catches any unintended rewrites
Generates validation rules for
tagsand othermap(string)attributes by extracting key/value constraints from AWS Smithy models. This catches invalid tags at plan time rather than waiting for API errors at apply.For example, given:
The rule reports each violation with the specific constraint (pattern, length, or prefix) that failed. The same approach applies to other map attributes like
labels,parameters,attributes, anddefault_run_properties.In total, this adds 157 rules: 145 tag rules across 48 services, plus 12 rules for other map attributes (EKS labels, Glue parameters, X-Ray attributes, etc.).
Changes
map(ItemsShape, KeyShape, ValueShape)function to mapping file syntax for services that define tags as list-of-structure typesuppercase,replace) operate on shape enum valuesmap_rule.go.tmpltemplate for map validation rules(?!aws:)) and generatesstrings.HasPrefixchecks, since Go's regexp doesn't support lookahead2147483647) to avoid generating no-op checksImplementation
AWS services define tags using two different patterns in their Smithy models.
Smithy
mapTypeSome services use a
maptype with explicitkeyandvaluetargets:The generator traverses this automatically via
traverseToMapConstraints(). No mapping file changes are needed.List of Structures
Most services use a list containing a structure with named members:
This pattern cannot be inferred automatically because member names vary across services. The
map()function explicitly specifies which shapes provide items, key, and value constraints:Prefix Deny Patterns
Tag key patterns often include negative lookahead like
(?!aws:)to prevent reserved prefixes. Since Go's regexp doesn't support lookahead, the generator extracts literal prefix strings and emitsstrings.HasPrefixchecks in the template. This preserves the validation rather than silently dropping it.Testing
Handwritten tests cover three representative generated rules, each exercising a distinct constraint shape:
aws:) combined with key pattern validationGenerator-level tests cover shape traversal (map, list, structure types),
replacePatterntransforms (unicode escapes, lookahead extraction, anchors), and shape object composition.References
tagsattributes #1019