Skip to content

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) raises ARNParseError only when value cannot be split into six ARN segments; segment problems are reported via errors / is_valid. Pass strict=True to raise on any error.
  • ARN.build(...) raises on invalid results unless strict=False.
  • arn.validate_against(service, shape) checks a specific botocore *Arn shape and returns a ValidationResult; arn.matching_shapes() lists every service-specific botocore shape the ARN satisfies. Both load the class registry lazily — plain parsing never does.
  • ARN can 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")