# AGENTS.md — LocalStack Pro

LocalStack is a fully functional local AWS cloud stack that emulates AWS services (S3, Lambda, DynamoDB, etc.) for development and testing. It runs in Docker, provides AWS-like APIs locally, enabling offline workflows, integration testing, and CI without calling real AWS endpoints.

This codebase contains both the AWS emulator in `localstack-core`.

---

## ⚠️ Critical Hard Constraints

**NEVER:**
- Modify `*.snapshot.json` or `*.validation.json` files manually — generated by running tests against AWS
- Use plain `assert` in validated tests — **ALWAYS** use `snapshot.match()`
- Create AWS resources directly in test bodies — **ALWAYS** use fixtures
- Hardcode account IDs or region names — use `account_id` and `region_name` fixtures
- Modify files in `aws/api/` — auto-generated from AWS API definitions
- Add new project dependencies without approval
- Run `git push` or modify repository history

---

## Commands

```bash
# Testing
pytest <path/to/test_file.py>                # Run test file
pytest <path/to/test_file.py> -k <test_name> # Run specific test
AWS_PROFILE=ls-sandbox TEST_TARGET=AWS_CLOUD SNAPSHOT_UPDATE=1 pytest <path>  # Run against AWS

# Code quality
make lint           # Lint check
make format         # Format all
make format-modified # Format staged only
```

---

## Project Structure

```
localstack-core/
├── localstack/core/
│   ├── services/<service>/        # Service implementations
│   │   ├── provider.py            # API handlers
│   │   ├── models.py              # State stores
│   │   └── resource_providers/    # CloudFormation resources
│   ├── aws/api/<service>/         # Auto-generated API types (DO NOT EDIT)
│   └── providers.py               # Service registration & Moto fallbacks
├── tests/aws/services/<service>/  # Integration tests
├── tests/unit/                    # Unit tests (prefer integration tests)
├── tests/bootstrap/               # Container startup tests
```

### Moto Fallback

Moto is a library used to implement services not fully implemented in LocalStack. Requests can fall back to Moto operations, with the disadvantage that state is kept in Moto and Moto changes may break the implementation. Check `providers.py` for fallback configurations.

---

## Implementing AWS Operations

### Reference Implementation

For a complete example of provider patterns, state management, and error handling, see the **CodeBuild** service:

- **Provider:** `localstack-pro-core/localstack/pro/core/services/codebuild/provider.py`
- **Models (state store):** `localstack-pro-core/localstack/pro/core/services/codebuild/models.py`

Refer to this implementation when:
- Creating a new service from scratch
- Understanding the `@handler` decorator pattern (with and without `expand=False`)
- Learning the `AccountRegionBundle` state management pattern
- Implementing service-specific exceptions
- Using helper functions like `get_store(context)` and utility functions outside the class

### Key Conventions

- **Types:** Import from `localstack.pro.core.aws.api.<service>` (auto-generated, don't modify)
- **Errors:** Use service-specific exceptions from API module, or `CommonServiceException`
- **IDs:** Use `short_uid()` from `localstack.utils.strings`
- **ARNs:** Use helpers from `localstack.utils.aws.arns`
- **Logging:** `LOG = logging.getLogger(__name__)` at module top

---

## Writing Parity Tests

### Reference Implementation

For complete examples of test patterns, fixtures, and snapshots, see the **Pipes** tests:

- **Validation tests:** `localstack-pro-core/tests/aws/services/pipes/test_pipes_validation.py`
- **Integration tests:** `localstack-pro-core/tests/aws/services/pipes/test_pipes.py`
- **Fixtures (conftest):** `localstack-pro-core/tests/aws/services/pipes/conftest.py`

Refer to these when:
- Writing `@markers.aws.validated` tests with snapshot matching
- Creating fixture factories with cleanup (see `pipes_create_pipe` in conftest)
- Understanding the `@pytest.mark.parametrize` pattern
- Testing error cases with `pytest.raises` and `snapshot.match`

### Test Markers

Use `@markers.aws.validated` for tests that run against AWS (preferred), or `@markers.aws.only_localstack` for implementation-specific assertions.

### Core Patterns

All test patterns are demonstrated in the reference files. Refer to:

- **Validation tests with error handling:** `test_pipes_validation.py:9-35` — shows `@markers.aws.validated`, `pytest.raises`, and `snapshot.match` for error responses
- **Parametrized tests:** `test_pipes_validation.py:304-377` — shows `@pytest.mark.parametrize` with multiple test cases
- **Fixture with cleanup:** `conftest.py:55-76` — shows the `pipes_create_pipe` fixture factory pattern with `LOG.debug()` cleanup
- **Async resource handling:** `test_pipes.py:134-139` — shows `poll_condition` for waiting on resource state

### Fixture Rules

- **Return the entire response** from create operations
- **Store only names/ARNs** in cleanup list (not full responses)
- **Log cleanup errors** with `LOG.debug()` for debugging with `-s`

### Transformers

Add transformers **before** `snapshot.match()` for non-deterministic values:

- **By key (preferred):** `snapshot.add_transformer(snapshot.transform.key_value("FooArn"))`
- **By regex:** `snapshot.add_transformer(snapshot.transform.regex(dynamic_value, "<placeholder>"))`
- **For sorting:** Use `SortingTransformer` from `localstack.testing.snapshots.transformer`

### Key Fixtures

- `aws_client` — Boto3 clients (e.g., `aws_client.s3`, `aws_client.lambda_`)
- `snapshot` — Snapshot matching and transformers
- `account_id`, `region_name` — Current account/region (never hardcode)
- `deploy_cfn_template` — Deploy CloudFormation with lifecycle management
- `cleanups` — Register arbitrary cleanup code for teardown

For common resource fixtures (S3 buckets, KMS keys, etc.), check `localstack-core/localstack/testing/pytest/fixtures.py`

---

## Development Process

1. **Write a failing test first** — Capture AWS behavior with `TEST_TARGET=AWS_CLOUD SNAPSHOT_UPDATE=1`
2. **Find the provider** — Look in `services/<service>/provider.py` for the handler
3. **Check the store** — State issues often in `models.py`
4. **Compare with AWS docs** — Verify expected behavior
5. **Run test against LocalStack** — Ensure snapshot matches
6. **Iterate** — Run tests individually, see failures, fix, re-run

**Important:** When developing tests for functionality that doesn't exist in LocalStack yet, run tests against AWS to ensure validity. Don't run with `TEST_TARGET=LOCALSTACK` until the functionality exists.

---

## Best Practices

### Always

- Run new tests against AWS first
- Use fixtures for resource creation with cleanup
- Add transformers for dynamic values
- Follow patterns in nearby existing code
- Use simple, concise, Sphinx docstrings
- Use type hints
- Start simple (CRUD), then add edge cases, errors, pagination

### Avoid

- Over-commenting tests — test name and structure should be self-explanatory
- Adding comments for standard steps (transformers, snapshot matching)
- Creating new markers without discussion

---

## Reference

- **Testing Docs:** https://github.com/localstack/localstack/tree/main/docs/testing
- **Architecture:** https://github.com/localstack/localstack/blob/main/docs/localstack-concepts/README.md
- **Common Fixtures:** `localstack-core/localstack/testing/pytest/fixtures.py`
