Usage
Here's a simple example demonstrating how to use aws_resource_validator:
from aws_resource_validator.class_definitions import Acm, class_registry
# Use type hint so that you can use `api_registry` with full class definitions
acm: Acm = class_registry.Acm
print(acm.Arn.pattern)
print(acm.Arn.type)
print(acm.Arn.validate("example-arn"))
print(acm.Arn.generate())
Opt-in pattern validation on generated Pydantic models
Every string field on a generated Pydantic model that is backed by a botocore shape with a regex carries an opt-in validator. Default construction does not run it:
from aws_resource_validator.pydantic_models.acm_pca.acm_pca_classes import (
CreateCertificateAuthorityAuditReportRequestTypeDef as Req,
)
# No pattern check: "not-an-arn" is accepted.
Req.model_validate(
{
"CertificateAuthorityArn": "not-an-arn",
"S3BucketName": "my-bucket",
"AuditReportResponseFormat": "JSON",
}
)
Activate it per call by passing context={"aws_validate_patterns": True}:
from pydantic import ValidationError
try:
Req.model_validate(
{
"CertificateAuthorityArn": "not-an-arn",
"S3BucketName": "my-bucket",
"AuditReportResponseFormat": "JSON",
},
context={"aws_validate_patterns": True},
)
except ValidationError as exc:
for err in exc.errors():
print(err["loc"], err["type"]) # -> ('CertificateAuthorityArn',) aws_pattern
The check delegates to APIObject.validate(value) from the resource
validator, so the regex + length bounds are always consistent with
class_registry. Coverage is limited to annotations that are exactly
str, Optional[str], List[str], or Optional[List[str]]; other
shapes (Dict[str, T], Union[str, int], nested containers) pass
through unchanged. Unknown (service, shape) pairs resolve to a
permissive no-op so a stale emitter never breaks a caller.
Parsing, validating, and building ARNs
ARN replaces fragile arn.split(":") code. It splits on at most five
colons (so S3 keys, alarm names, and Lambda aliases containing : stay
intact), validates each segment, and decomposes the resource:
from aws_resource_validator import ARN, ARNParseError
arn = ARN.parse("arn:aws:s3:::my-bucket/logs/2026:10:09.gz")
arn.resource # 'my-bucket/logs/2026:10:09.gz'
arn.is_valid # True
ARN.parse("arn:aws:iam::12345:role/x").errors
# ("Account ID '12345' must be exactly 12 digits (got 5 characters), 'aws', or empty.",)
ARN.build(service="iam", account_id="123456789012", resource_type="role", resource_id="MyRole")
# ARN(partition='aws', service='iam', region='', account_id='123456789012', resource='role/MyRole')
ARN.parse(value)raisesARNParseErroronly whenvaluecannot be split into six ARN segments; segment problems are reported viaerrors/is_valid. Passstrict=Trueto raise on any error.ARN.build(...)raises on invalid results unlessstrict=False.arn.validate_against(service, shape)checks a specific botocore*Arnshape and returns aValidationResult;arn.matching_shapes()lists every service-specific botocore shape the ARN satisfies. Both load the class registry lazily — plain parsing never does.ARNcan be used directly as a Pydantic v2 field type.- CLI:
arv arn "<arn>" [--json] [--strict] [--no-shapes].
Scanning IaC and configuration files (arv scan)
aws_resource_validator provides static scanning for Infrastructure as Code (Terraform, CloudFormation, SAM, Serverless) and .env files:
from aws_resource_validator import scan_file, scan_paths, scan_text
# Scan text directly
candidate_count, findings = scan_text(
'''
resource "aws_s3_bucket" "b" {
bucket = "INVALID_NAME"
}
''',
file_path="main.tf",
)
# Recursively scan directories or files
report = scan_paths(["infra/"], exclude=["node_modules/*"])
print(report.is_valid) # False
print(report.error_count) # Number of naming violations
print(report.to_dict()) # JSON-serializable report
print(report.to_sarif()) # SARIF v2.1.0 output
CLI usage:
arv scan [paths]... [--format text|json|sarif|github] [--strict] [--exclude <glob>]
Pre-commit configuration (.pre-commit-config.yaml):
repos:
- repo: https://github.com/CoreOxide/aws_resource_validator
rev: v2.5.0
hooks:
- id: aws-resource-lint
Property-based testing with Hypothesis and Pytest
Install with testing extras:
pip install 'aws-resource-validator[testing]'
Hypothesis strategies
from hypothesis import given
from aws_resource_validator.testing import strategies as aws_st
# Fuzz your functions with valid edge-case AWS resource names:
@given(bucket=aws_st.resource_names("s3", "BucketName"))
def test_s3_pipeline(bucket: str):
...
# Generate valid ARNs (or strings) across AWS partitions, regions, and services:
@given(arn=aws_st.arns(service="sqs"))
def test_sqs_arn_processor(arn):
...
Pytest fixtures and assertions
The plugin is auto-registered with Pytest (pytest11 entry point):
from aws_resource_validator import assert_valid, assert_invalid
def test_service_setup(aws_name_factory, aws_arn_factory, aws_validator):
bucket = aws_name_factory("s3", "BucketName")
role_arn = aws_arn_factory("iam", resource_type="role", resource_id="AppRole")
assert_valid("s3", "BucketName", bucket)
assert_invalid("s3", "BucketName", "BAD_NAME")