Skip to content

✨ Add CloudFormation-based infrastructure deployment#8

Merged
sodre merged 6 commits intomainfrom
feat/cloudformation-stack-management
Jan 10, 2026
Merged

✨ Add CloudFormation-based infrastructure deployment#8
sodre merged 6 commits intomainfrom
feat/cloudformation-stack-management

Conversation

@sodre
Copy link
Member

@sodre sodre commented Jan 10, 2026

Summary

This PR migrates zae-limiter from programmatic DynamoDB table creation to CloudFormation-based stack management, making it easier for users to manage and delete infrastructure.

Changes

New Components

  • StackManager (): Manages CloudFormation stack lifecycle with auto-detection of local DynamoDB environments
  • CLI Module (): Provides infrastructure management commands
    • zae-limiter deploy: Deploy CloudFormation stack
    • zae-limiter delete: Delete CloudFormation stack
    • zae-limiter status: Check stack status
    • zae-limiter cfn-template: Export template for custom deployment

API Updates

  • Added create_stack parameter to RateLimiter and SyncRateLimiter
  • Deprecated create_table parameter (with deprecation warning)
  • Added create_stack() and delete_stack() methods
  • Added CloudFormation exceptions: StackCreationError, StackAlreadyExistsError

Documentation

  • Updated README.md with CloudFormation deployment instructions
  • Updated CLAUDE.md with infrastructure management guide
  • Added comprehensive tests (25 passing tests)

Key Features

Auto-Detection: Automatically detects local DynamoDB (via endpoint_url) and skips CloudFormation
Backward Compatible: Existing code continues to work with deprecation warnings
CLI Convenience: Simple commands for infrastructure management
Easy Cleanup: Users can delete entire stack via CloudFormation

Usage Examples

Deploy via CLI (Recommended)

zae-limiter deploy --table-name rate_limits --region us-east-1

Auto-create in code

limiter = RateLimiter(
    table_name="rate_limits",
    create_stack=True,  # Auto-creates CloudFormation stack
)

Local development (auto-detects)

limiter = RateLimiter(
    table_name="rate_limits",
    endpoint_url="http://localhost:8000",
    create_table=True,  # Uses direct table creation
)

Testing

All tests pass:

pytest tests/test_cli.py tests/test_stack_manager.py -v
# 25 passed, 4 skipped

Breaking Changes

None - fully backward compatible with deprecation warnings.

🤖 Generated with Claude Code

@claude
Copy link

claude bot commented Jan 10, 2026

Code Review

Found 1 issue that needs attention:

Resource Leak in StackManager._get_client()

File: src/zae_limiter/infra/stack_manager.py:61-72

Issue: The _get_client() method creates a new aioboto3 client on every call without caching or proper cleanup. Each client enters the async context manager via __aenter__() but never calls the corresponding __aexit__(), causing resource leaks.

Problem:

  1. No client caching - creates a new client on every call
  2. Missing __aexit__() calls - resources are never cleaned up
  3. Empty close() method - no cleanup mechanism

Reference: The correct pattern is demonstrated in repository.py:34-50

Suggested fix: Cache the client in self._client and implement proper cleanup in close() method, similar to Repository class.


Additional notes:

  • Also checked for CLAUDE.md compliance - no violations found
  • The one-line docstrings for sync wrapper methods follow the existing codebase pattern

sodre and others added 3 commits January 9, 2026 23:24
Migrate from programmatic DynamoDB table creation to CloudFormation
stack management for easier infrastructure lifecycle management.

Changes:
- Add StackManager for CloudFormation operations with auto-detection
  of local DynamoDB environments
- Add CLI commands: deploy, delete, status, cfn-template
- Update RateLimiter with create_stack parameter (deprecates create_table)
- Add backward compatibility with deprecation warnings
- Update documentation with CloudFormation deployment instructions
- Add comprehensive tests for stack manager and CLI

Benefits:
- Users can easily delete all infrastructure via CloudFormation
- Infrastructure-as-code best practices
- Auto-detects local vs cloud environments
- Maintains backward compatibility for existing users

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Remove unused mock_aws import from test_stack_manager.py
- Add type casts for DynamoDB response to fix mypy errors
@sodre sodre force-pushed the feat/cloudformation-stack-management branch from 441e8e3 to b74b40a Compare January 10, 2026 04:25
sodre added 3 commits January 9, 2026 23:35
Critical fixes:
- Make StackManager an async context manager with proper __aenter__/__aexit__
- Fix _get_client() to reuse client and properly manage lifecycle
- Implement close() method to actually cleanup client and session
- Update all usage sites to use async with pattern (repository, limiter, CLI)
- Update test mocks to support async context manager protocol

Resource leaks fixed:
1. CloudFormation client now properly closed via __aexit__
2. Client reused across multiple API calls instead of creating new ones
3. All StackManager instances now closed after use in repository/limiter/CLI

Test changes:
- All CLI test mocks now include __aenter__/__aexit__ methods
- All tests passing (17/17 CLI tests, 12/12 stack manager tests)
Fixes test failures caused by missing transitive dependency.

Issue:
- moto's cloudformation parsing imports apigateway models
- apigateway models require openapi-spec-validator
- moto[dynamodb] doesn't declare this dependency

Solution:
- Add openapi-spec-validator>=0.7.1 to dev dependencies
- All previously failing tests now pass

Test results:
- test_limiter.py: All tests passing
- test_sync_limiter.py: All 6 tests passing
- No more ModuleNotFoundError
Issue:
- Test fixtures were triggering CloudFormation stack creation
- Moto doesn't properly mock CloudFormation in these tests
- Caused cascade tests and others to fail

Solution:
- Update limiter fixtures to manually create table via direct API
- Remove auto-creation flags (create_table/create_stack)
- Call _repository.create_table() directly before entering context

Test results:
- All 86 tests passing
- 4 skipped (require real AWS CloudFormation)
- Cascade tests now working correctly
@sodre sodre merged commit ad52cb0 into main Jan 10, 2026
5 checks passed
@sodre sodre deleted the feat/cloudformation-stack-management branch January 10, 2026 05:04
@sodre sodre added this to the v0.1.0 milestone Jan 14, 2026
@sodre sodre mentioned this pull request Jan 14, 2026
7 tasks
@sodre sodre changed the title Add CloudFormation-based infrastructure deployment ✨ Add CloudFormation-based infrastructure deployment Jan 15, 2026
sodre added a commit that referenced this pull request Feb 15, 2026
- Add RepositoryBuilder .namespace() example to deployment.md (#8)
- Add namespace ID discovery tip to cloudformation.md outputs (#13)
- Migrate legacy StackOptions to RepositoryBuilder in auditing.md,
  testing.md, localstack.md, and version.md (#22)
- Add migration guide link to deployment.md Next Steps (#24)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant