|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Development Commands |
| 6 | + |
| 7 | +### Setup |
| 8 | +- `poetry install --with=dev --with=main` - Install all dependencies including dev tools |
| 9 | +- `poetry shell` - Activate virtual environment for development |
| 10 | + |
| 11 | +### Testing |
| 12 | +- `poetry run pytest` - Run unit tests |
| 13 | +- `poetry run pytest --verbose --cov=./ --cov-report=xml` - Run unit tests with coverage |
| 14 | +- `make test-unit` - Run unit tests in Docker (with coverage) |
| 15 | +- `make test-unit-no-cov` - Run unit tests in Docker (no coverage) |
| 16 | +- `make test-int` - Run integration tests using bats in Docker |
| 17 | +- `make tests` - Run full test suite (unit + integration) |
| 18 | + |
| 19 | +### Code Quality |
| 20 | +- `poetry run black .` - Format code with Black (line length: 120) |
| 21 | +- `poetry run pylint leverage/` - Run linting |
| 22 | +- `poetry run pre-commit install` - Install pre-commit hooks |
| 23 | +- `poetry run pre-commit run --all-files` - Run pre-commit checks manually |
| 24 | + |
| 25 | +### Build and Distribution |
| 26 | +- `make build` - Build distributables (cleans first) |
| 27 | +- `make check` - Check distributables with twine |
| 28 | +- `poetry build` - Build package using Poetry |
| 29 | +- `make clean` - Clean build artifacts |
| 30 | + |
| 31 | +### Docker |
| 32 | +- `make build-image` - Build Docker testing image |
| 33 | +- All test commands can run in Docker using the testing image |
| 34 | + |
| 35 | +## Architecture |
| 36 | + |
| 37 | +Leverage CLI is a Python-based command-line tool for managing Binbash Leverage projects. It uses a dockerized approach to encapsulate infrastructure tools. |
| 38 | + |
| 39 | +### Core Structure |
| 40 | +- `leverage/leverage.py` - Main CLI entry point using Click framework |
| 41 | +- `leverage/modules/` - Command modules (aws, terraform, kubectl, etc.) |
| 42 | +- `leverage/container.py` - Docker container management and execution |
| 43 | +- `leverage/conf.py` - Configuration loading from build.env files |
| 44 | +- `leverage/tasks.py` - Task system for build scripts |
| 45 | +- `leverage/path.py` - Path utilities and git repository handling |
| 46 | + |
| 47 | +### Key Components |
| 48 | +- **Module System**: Commands are organized in modules under `leverage/modules/` |
| 49 | +- **Container Integration**: Heavy use of Docker containers for tool execution |
| 50 | +- **Configuration Management**: Hierarchical loading of build.env files |
| 51 | +- **Task System**: Decorator-based task definition system for build scripts |
| 52 | +- **AWS Integration**: Extensive AWS credential and service management |
| 53 | + |
| 54 | +### Command Structure |
| 55 | +The CLI follows this pattern: |
| 56 | +``` |
| 57 | +leverage [global-options] <module> <subcommand> [args] |
| 58 | +``` |
| 59 | + |
| 60 | +Key modules include: |
| 61 | +- `project` - Project initialization and management |
| 62 | +- `terraform`/`tf`/`tofu` - Terraform/OpenTofu operations |
| 63 | +- `aws` - AWS service interactions |
| 64 | +- `credentials` - Credential management |
| 65 | +- `kubectl`/`kc` - Kubernetes operations |
| 66 | +- `run` - Custom task execution |
| 67 | +- `shell` - Interactive shell access |
| 68 | + |
| 69 | +### Version Management |
| 70 | +- Supports Python 3.9-3.13 |
| 71 | +- Version defined in `leverage/__init__.py` |
| 72 | +- Minimum tool versions enforced via `MINIMUM_VERSIONS` |
| 73 | +- Docker image versioning through `__toolbox_version__` |
| 74 | + |
| 75 | +### Configuration |
| 76 | +- Uses `build.env` files for project configuration |
| 77 | +- Hierarchical loading from project root to current directory |
| 78 | +- Environment-specific overrides supported |
| 79 | + |
| 80 | +## Docker Container Architecture for Terraform/OpenTofu |
| 81 | + |
| 82 | +The CLI uses a containerized approach for all Terraform/OpenTofu operations to ensure consistent tool versions and isolated execution environments. |
| 83 | + |
| 84 | +### Container Classes |
| 85 | + |
| 86 | +#### TFContainer (`leverage/container.py:436-687`) |
| 87 | +Primary container for Terraform/OpenTofu execution: |
| 88 | +- **Image**: `binbash/leverage-toolbox` with user-specific permissions |
| 89 | +- **Binaries**: `/bin/terraform` (when `terraform=True`) or `/bin/tofu` (default) |
| 90 | +- **Mount Points**: |
| 91 | + - Project root → `/leverage` (guest base path) |
| 92 | + - AWS credentials directory → `/tmp/.aws` |
| 93 | + - Git config file → `/etc/gitconfig` |
| 94 | + - Optional: TF plugin cache directory (maintains symlinks) |
| 95 | + - Optional: SSH agent socket → `/ssh-agent` |
| 96 | + |
| 97 | +#### TFautomvContainer (`leverage/container.py:689-717`) |
| 98 | +Extends TFContainer for TFAutomv operations: |
| 99 | +- **Binary**: `/usr/local/bin/tfautomv` |
| 100 | +- Inherits all TFContainer mounts and configuration |
| 101 | + |
| 102 | +### Configuration File Management |
| 103 | + |
| 104 | +#### Environment Variables in Containers: |
| 105 | +- `COMMON_CONFIG_FILE` → `common.tfvars` |
| 106 | +- `ACCOUNT_CONFIG_FILE` → `account.tfvars` |
| 107 | +- `BACKEND_CONFIG_FILE` → `backend.tfvars` |
| 108 | +- `AWS_SHARED_CREDENTIALS_FILE` → `/tmp/.aws/credentials` |
| 109 | +- `AWS_CONFIG_FILE` → `/tmp/.aws/config` |
| 110 | +- `SSO_CACHE_DIR` → `/tmp/.aws/sso/cache` |
| 111 | + |
| 112 | +#### Terraform Variable Files: |
| 113 | +The `tf_default_args` property automatically includes: |
| 114 | +- All `*.tfvars` files from `common/` directory |
| 115 | +- All `*.tfvars` files from account-specific directory |
| 116 | + |
| 117 | +### Docker Execution Points |
| 118 | + |
| 119 | +#### Terraform/OpenTofu Commands (`leverage/modules/tf.py`) |
| 120 | +- Container creation for `tofu` and `terraform` commands (lines 38, 56) |
| 121 | +- Command execution via `tf.start()` for all operations |
| 122 | +- **Supported Commands**: `init`, `plan`, `apply`, `destroy`, `output`, `version`, `shell`, `format`, `validate`, `import`, `refresh-credentials` |
| 123 | + |
| 124 | +#### TFAutomv Commands (`leverage/modules/tfautomv.py`) |
| 125 | +- Container creation for `tfautomv` commands (line 24) |
| 126 | +- Command execution via `tf.start_in_layer()` (line 36) |
| 127 | + |
| 128 | +### Container Lifecycle |
| 129 | + |
| 130 | +1. **Image Verification**: `ensure_image()` builds local image with user permissions |
| 131 | +2. **Container Creation**: `_create_container()` with mounted volumes and environment |
| 132 | +3. **Authentication Setup**: SSO token validation or MFA credential handling |
| 133 | +4. **Command Execution**: Interactive (`_start()`) or silent (`_exec()`) |
| 134 | +5. **Cleanup**: Automatic container stop and removal |
| 135 | + |
| 136 | +### Authentication & Credentials |
| 137 | + |
| 138 | +#### SSO Authentication: |
| 139 | +- Token validation before container execution |
| 140 | +- Automatic credential refresh via `refresh_layer_credentials()` |
| 141 | +- Browser-based authentication flow with user code |
| 142 | + |
| 143 | +#### MFA Authentication: |
| 144 | +- Script-based authentication via `aws-mfa-entrypoint.sh` |
| 145 | +- Environment variable adjustments for credential paths |
| 146 | + |
| 147 | +#### Credential Mounting: |
| 148 | +- Host AWS credentials directory mounted to container |
| 149 | +- Separate credential files for different authentication methods |
| 150 | + |
| 151 | +### Backend Configuration Management |
| 152 | + |
| 153 | +#### S3 Backend Handling: |
| 154 | +- Automatic `backend.tfvars` parameter injection for `init` commands |
| 155 | +- Dynamic state key generation based on layer path structure |
| 156 | +- Backend block validation in `config.tf` files |
| 157 | +- Support for legacy naming conventions (tf- vs terraform-) |
| 158 | + |
| 159 | +**IMPORTANT**: As of the latest update, Leverage CLI now uses **host-based execution** instead of Docker containers: |
| 160 | + |
| 161 | +## Host-Based Execution Architecture |
| 162 | + |
| 163 | +The CLI has been updated to use host-based execution for improved performance and flexibility while maintaining all functionality. |
| 164 | + |
| 165 | +### Core Runner Classes |
| 166 | + |
| 167 | +#### Runner (`leverage/modules/runner.py`) |
| 168 | +Generic command runner base class: |
| 169 | +- **Purpose**: Provides common execution functionality for all binary runners |
| 170 | +- **Binary Discovery**: Searches for binaries in PATH or accepts absolute paths |
| 171 | +- **Environment Management**: Merges instance-level and run-time environment variables |
| 172 | +- **Execution Modes**: |
| 173 | + - `run()` - Interactive execution (returns exit code) or silent (returns exit code, stdout, stderr) |
| 174 | + - `exec()` - Convenience method for non-interactive execution with output capture |
| 175 | +- **Working Directory**: Supports execution in any specified directory |
| 176 | +- **Validation**: Automatic binary existence validation on initialization |
| 177 | + |
| 178 | +#### TFRunner (`leverage/modules/tfrunner.py`) |
| 179 | +Terraform/OpenTofu-specific runner extending Runner: |
| 180 | +- **Binaries**: Uses system-installed `terraform` or `tofu` binaries |
| 181 | +- **Configuration**: Accepts `terraform=True` for Terraform, defaults to OpenTofu |
| 182 | +- **Error Messages**: Provides installation URLs when binaries are not found |
| 183 | + - Terraform: https://developer.hashicorp.com/terraform/install |
| 184 | + - OpenTofu: https://opentofu.org/docs/intro/install/ |
| 185 | +- **Environment Variables**: Initialized with AWS credential file paths via `env_vars` parameter |
| 186 | +- **No Containers**: Direct binary execution on host system |
| 187 | + |
| 188 | +### Command Flow Architecture |
| 189 | + |
| 190 | +#### Terraform/OpenTofu Command Flow (`leverage/modules/tf.py`) |
| 191 | + |
| 192 | +1. **CLI Entry Points**: |
| 193 | + - `@click.group() tofu()` (lines 22-35) - Creates TFRunner with OpenTofu binary |
| 194 | + - `@click.group() terraform()` (lines 38-51) - Creates TFRunner with Terraform binary |
| 195 | + - Both set up credential environment variables for AWS config and credentials files |
| 196 | + |
| 197 | +2. **Command Decoration**: |
| 198 | + - `@pass_runner` - Injects TFRunner instance from Click context |
| 199 | + - `@pass_paths` - Injects PathsHandler instance for file/directory management |
| 200 | + |
| 201 | +3. **Supported Commands**: |
| 202 | + - `init` - Layer initialization with backend configuration injection |
| 203 | + - `plan` - Execution plan generation with auto-discovered tfvars |
| 204 | + - `apply` - Infrastructure changes with conditional tfvars injection |
| 205 | + - `destroy` - Infrastructure destruction |
| 206 | + - `output` - Output variable display |
| 207 | + - `version` - Binary version display |
| 208 | + - `format` - Code formatting (recursive by default) |
| 209 | + - `force-unlock` - State file lock removal |
| 210 | + - `validate` - Configuration validation |
| 211 | + - `validate-layout` - Leverage convention validation |
| 212 | + - `import` - Resource import |
| 213 | + - `refresh-credentials` - AWS credential refresh |
| 214 | + |
| 215 | +4. **Multi-Layer Support**: |
| 216 | + - `--layers` option for operating on multiple layers from account directory |
| 217 | + - Layer validation and backend key management via `invoke_for_all_commands()` |
| 218 | + - Automatic backend key generation based on layer path structure |
| 219 | + |
| 220 | +### Authentication Management |
| 221 | + |
| 222 | +#### SSO Authentication (`leverage/modules/auth.py`) |
| 223 | + |
| 224 | +**Token Validation** (`check_sso_token()` - lines 98-127): |
| 225 | +- Validates SSO token existence in cache directory |
| 226 | +- Checks token expiration against current time |
| 227 | +- Provides clear error messages for missing or expired tokens |
| 228 | +- Token file location: `~/.aws/sso/cache/<sso_role>` |
| 229 | + |
| 230 | +**Credential Refresh** (`refresh_layer_credentials()` - lines 130-204): |
| 231 | +- Parses Terraform files to discover required AWS profiles |
| 232 | +- Uses boto3 SSO client to retrieve temporary credentials |
| 233 | +- Updates AWS config file with credential expiration timestamps |
| 234 | +- Writes temporary credentials to AWS credentials file |
| 235 | +- Implements 30-minute early renewal to avoid mid-operation expiration |
| 236 | +- Supports cross-account profile resolution |
| 237 | + |
| 238 | +**Profile Discovery** (`get_profiles()` - lines 68-88): |
| 239 | +- Scans `config.tf`, `locals.tf`, `runtime.tf` for profile references |
| 240 | +- Extracts profile variables from Terraform configurations |
| 241 | +- Reads backend profile from `backend.tfvars` |
| 242 | + |
| 243 | +### Configuration Management |
| 244 | + |
| 245 | +#### Automatic tfvars Discovery (`tf_default_args()` - lines 133-154): |
| 246 | +- Discovers all `*.tfvars` files in `common/` directory |
| 247 | +- Discovers all `*.tfvars` files in account-specific directory |
| 248 | +- Returns as `-var-file=<path>` arguments for Terraform/OpenTofu |
| 249 | +- Used automatically in plan, destroy, validate, and conditionally in apply |
| 250 | + |
| 251 | +#### Backend Configuration: |
| 252 | +- Backend config file path injected during `init` command (line 336) |
| 253 | +- Automatic backend key generation in `invoke_for_all_commands()` (lines 291-294) |
| 254 | +- Backend key validation in `validate_layout()` (lines 538-550) |
| 255 | +- Support for legacy naming conventions (tf- vs terraform-, base- vs tools-) |
| 256 | + |
| 257 | +### Execution Flow |
| 258 | + |
| 259 | +**Standard Command Execution**: |
| 260 | +1. User runs `leverage tofu|terraform <command> [args]` |
| 261 | +2. Click creates TFRunner instance with credential environment variables |
| 262 | +3. Command function decorated with `@pass_runner` and `@pass_paths` |
| 263 | +4. Authentication check via `check_sso_token(paths)` |
| 264 | +5. Credential refresh via `refresh_layer_credentials(paths)` |
| 265 | +6. TFRunner.run() executes binary with: |
| 266 | + - Merged environment variables (instance + runtime) |
| 267 | + - Specified working directory |
| 268 | + - Auto-discovered tfvars (for applicable commands) |
| 269 | + - User-provided arguments |
| 270 | +7. Exit code returned to CLI |
| 271 | + |
| 272 | +**Multi-Layer Execution**: |
| 273 | +1. User runs command with `--layers layer1,layer2` from account directory |
| 274 | +2. `invoke_for_all_commands()` validates all layers |
| 275 | +3. Backend keys generated/validated for each layer |
| 276 | +4. Command executed sequentially for each layer with layer-specific working directory |
| 277 | + |
| 278 | +### Benefits of Host-Based Execution |
| 279 | + |
| 280 | +- **Performance**: No container startup overhead or image building |
| 281 | +- **Flexibility**: Use any installed tool version (including custom builds) |
| 282 | +- **IDE Integration**: Better debugging and tooling support |
| 283 | +- **Simplicity**: Direct binary execution with standard environment variables |
| 284 | +- **Plugin Compatibility**: Native Terraform/OpenTofu plugin caching |
| 285 | +- **Development Speed**: Faster iteration during development |
| 286 | + |
| 287 | +### Host Requirements |
| 288 | + |
| 289 | +For full functionality, ensure the following binaries are installed and available in PATH: |
| 290 | +- `terraform` or `tofu` (for Terraform/OpenTofu operations) |
| 291 | +- `aws` CLI (for SSO authentication via boto3) |
| 292 | + |
| 293 | +Optional binaries: |
| 294 | +- `tfautomv` (for TFAutomv operations) |
0 commit comments