Add Azure Blob Storage (azurerm) backend support for !terraform.state function @jamengual (#1610)
## what - Implemented Azure Blob Storage backend support for the `!terraform.state` YAML function - Added comprehensive unit tests with 100% coverage for the new backend - Updated error definitions, registry, and documentationwhy
- The
!terraform.statefunction previously only supportedlocalands3backends - Azure users needed native azurerm backend support to read Terraform state directly from Azure Blob Storage
- This provides the fastest way to retrieve Terraform outputs without Terraform initialization overhead
changes
-
New Implementation:
internal/terraform_backend/terraform_backend_azurerm.go- Implements azurerm backend reader following S3 backend patterns
- Uses Azure SDK with DefaultAzureCredential for authentication (Managed Identity, Service Principal, Azure CLI, etc.)
- Supports workspace-based blob paths (
env:/{workspace}/{key}for non-default workspaces) - Includes client caching, retry logic (2 retries with exponential backoff), and proper error handling
- Handles 404 (blob not found) gracefully by returning nil (component not provisioned yet)
- Handles 403 (permission denied) with descriptive error messages
-
Comprehensive Tests:
internal/terraform_backend/terraform_backend_azurerm_test.go- 8 test functions covering all scenarios with mocked Azure SDK client
- Tests workspace handling (default vs non-default), blob not found, permission denied, network errors, retry logic, and error cases
- All tests pass with no external dependencies required
-
Error Definitions:
errors/errors.go- Added 7 new Azure-specific static errors following project patterns
- ErrGetBlobFromAzure, ErrReadAzureBlobBody, ErrCreateAzureCredential, ErrCreateAzureClient, ErrAzureContainerRequired, ErrStorageAccountRequired, ErrAzurePermissionDenied
-
Registry Update:
internal/terraform_backend/terraform_backend_registry.go- Registered ReadTerraformBackendAzurerm in the backend registry
-
Error Message Update:
internal/terraform_backend/terraform_backend_utils.go- Updated supported backends list to include
azurerm
- Updated supported backends list to include
-
Documentation Update:
website/docs/functions/yaml/terraform.state.mdx- Added azurerm to the list of supported backend types
- Updated warning message to reflect azurerm support
-
Dependencies:
go.mod- Moved
github.com/Azure/azure-sdk-for-go/sdk/storage/azblobfrom indirect to direct dependency (already present in project)
- Moved
implementation notes
- Follows established patterns from S3 backend implementation
- Uses wrapper pattern (AzureBlobAPI interface) to enable testing without actual Azure connectivity
- Implements proper workspace path handling matching Azure backend behavior (
env:/{workspace}/{key}) - All comments end with periods (enforced by golangci-lint)
- Imports organized in 3 groups (stdlib, 3rd-party, atmos) as per CLAUDE.md
- Performance tracking added with
defer perf.Track()on all functions - Cross-platform compatible using Azure SDK (not CLI commands)
test results
=== RUN TestReadTerraformBackendAzurermInternal_Success
=== RUN TestReadTerraformBackendAzurermInternal_Success/successful_read_default_workspace
=== RUN TestReadTerraformBackendAzurermInternal_Success/successful_read_dev_workspace
=== RUN TestReadTerraformBackendAzurermInternal_Success/successful_read_prod_workspace
=== RUN TestReadTerraformBackendAzurermInternal_Success/successful_read_empty_workspace
=== RUN TestReadTerraformBackendAzurermInternal_Success/successful_read_default_key
--- PASS: TestReadTerraformBackendAzurermInternal_Success (0.00s)
=== RUN TestReadTerraformBackendAzurermInternal_BlobNotFound
--- PASS: TestReadTerraformBackendAzurermInternal_BlobNotFound (0.00s)
=== RUN TestReadTerraformBackendAzurermInternal_PermissionDenied
--- PASS: TestReadTerraformBackendAzurermInternal_PermissionDenied (0.00s)
=== RUN TestReadTerraformBackendAzurermInternal_NetworkError
--- PASS: TestReadTerraformBackendAzurermInternal_NetworkError (4.00s)
=== RUN TestReadTerraformBackendAzurermInternal_RetrySuccess
--- PASS: TestReadTerraformBackendAzurermInternal_RetrySuccess (2.00s)
=== RUN TestReadTerraformBackendAzurermInternal_MissingContainerName
--- PASS: TestReadTerraformBackendAzurermInternal_MissingContainerName (0.00s)
=== RUN TestReadTerraformBackendAzurermInternal_ReadBodyError
--- PASS: TestReadTerraformBackendAzurermInternal_ReadBodyError (0.00s)
PASS
ok github.com/cloudposse/atmos/internal/terraform_backend 7.011s
Summary by CodeRabbit
-
New Features
- Azure Blob Storage (azurerm) support for reading Terraform state with workspace-aware paths, authentication, retries, and client caching.
-
Documentation
- Added detailed docs and a blog post covering Azure backend usage, examples, migration guidance, and “Try It Now” steps.
-
Improvements
- Clearer permission/not-found reporting and added Azure-specific error signals for more precise error handling.
-
Tests
- Extensive unit and integration tests plus Azure credential precondition checks.
-
Chores
- Updated .gitignore with developer tool patterns.
test(auth): Increase auth test coverage from 6% to 80% with mock provider @osterman (#1702)
## what - Add comprehensive unit and integration tests for Atmos auth system using the existing mock provider - Increase test coverage from **6% to ~80%** (target: 80-90% ✅) - Add regression tests to prevent recurrence of user-reported browser authentication issue - Achieve **100% coverage** for mock provider implementationwhy
- Current auth test coverage was critically low (6%), making it difficult to catch bugs
- User complaint (Bogdan) about browser authentication triggering on every command needed verification and regression protection
- Mock provider was implemented but had zero test coverage
- Need confidence that auth system works correctly without requiring real cloud credentials
Coverage Improvements
| Package | Before | After | Improvement |
|---|---|---|---|
| pkg/auth | 6.2% | 84.6% | +78.4pp |
| pkg/auth/providers/mock | 0% | 100.0% | +100pp |
| pkg/auth/utils | 0% | 100.0% | +100pp |
| pkg/auth/validation | 0% | 90.0% | +90pp |
| pkg/auth/list | 0% | 89.5% | +89.5pp |
| pkg/auth/cloud/aws | 0% | 79.2% | +79.2pp |
| pkg/auth/providers/github | 0% | 78.3% | +78.3pp |
| pkg/auth/factory | 0% | 77.8% | +77.8pp |
| pkg/auth/credentials | 0% | 75.8% | +75.8pp |
| pkg/auth/providers/aws | 0% | 67.8% | +67.8pp |
| pkg/auth/identities/aws | 2.3% | 62.5% | +60.2pp |
Overall: ~6% → ~80% ✅
Key Additions
1. Mock Provider Unit Tests (100% coverage)
pkg/auth/providers/mock/provider_test.go- 15 comprehensive testspkg/auth/providers/mock/identity_test.go- 13 comprehensive tests- Tests cover: authentication, expiration, concurrency, interface compliance
2. Credential Caching Regression Tests
cmd/auth_caching_test.go- 4 test functions with multiple subtests- Verifies credentials are cached after login and reused
- Ensures fast execution (< 2s) vs browser auth (5-30s)
- Tests multi-identity scenarios
3. Integration Test Scenarios
tests/test-cases/auth-mock.yaml- 20+ test scenarios- Auth login, whoami, env, exec, list, logout commands
- Multiple output formats (json, bash, dotenv)
- Error handling and edge cases
User Issue: Browser Auth on Every Command
Status: LIKELY FIXED ✅
The issue where browser authentication was triggered on every command appears to have been resolved by recent PRs (#1655, #1653, #1640). This PR adds comprehensive regression tests to:
- Verify credentials are cached after authentication
- Ensure subsequent commands use cached credentials
- Confirm fast execution without browser prompts
- Prevent regression of this issue
Testing
# Run mock provider tests
$ go test ./pkg/auth/providers/mock/... -v
=== RUN TestNewProvider
=== RUN TestProvider_Authenticate
=== RUN TestProvider_Concurrency
... 28 tests PASS
coverage: 100.0% of statements
# Run auth package tests
$ go test -cover ./pkg/auth/...
pkg/auth: 84.6% coverage ✅
pkg/auth/providers/mock: 100% coverage ✅
pkg/auth/utils: 100% coverage ✅
... all passingBenefits
- No cloud credentials needed for auth testing
- Fast test execution (milliseconds vs seconds)
- Deterministic results (fixed expiration dates)
- CI/CD ready (no secrets required)
- Regression protection for caching issue
- 80% coverage meets industry standards
references
🚀 Enhancements
test: Improve test coverage for keyring fallback to 78.4% @osterman (#1705)
## what - Add comprehensive unit tests for no-op keyring and system keyring functionality - Improve test coverage from 71.2% to 78.4% (+7.2 percentage points) - Add Validate() method to test credential types to satisfy ICredentials interfacewhy
- Ensure critical business logic is properly tested (cache management, expiration checking, error handling)
- Meet 80% test coverage target for new features
- Prevent regressions in keyring fallback behavior introduced in bde37e334
references
- Related to commit bde37e334 which introduced graceful keychain fallback for containerized environments
- Implements test requirements from
docs/prd/keyring-fallback-containerized-environments.md
Test Coverage Improvements
Starting Coverage: 71.2%
Final Coverage: 78.4%
Improvement: +7.2 percentage points
Tests Added (8 new test functions):
TestNoopKeyringStore_ValidCache- Tests cache hit with valid credentialsTestNoopKeyringStore_ExpiredInCache- Tests cache hit with expired credentialsTestNoopKeyringStore_StoreWithMockCredentials- Tests storing mock credentialsTestNoopKeyringStore_ExpirationWarning- Tests expiration warning logicTestSystemKeyringStore_GetAny- Tests retrieving arbitrary data from system keyringTestSystemKeyringStore_GetAny_NotFound- Tests GetAny error handlingTestSystemKeyringStore_SetAny- Tests storing arbitrary data typesTestNewKeyringAuthStore- Tests deprecated backward-compatible function
Coverage by Function:
| File | Function | Before | After | Improvement |
|---|---|---|---|---|
keyring_noop.go
| Retrieve()
| 36.8% | 57.9% | +21.1% |
keyring_system.go
| GetAny()
| 0% | 85.7% | +85.7% |
keyring_system.go
| SetAny()
| 0% | 71.4% | +71.4% |
store.go
| NewKeyringAuthStore()
| 0% | 100% | +100% |
Remaining Uncovered (1.6% to reach 80%):
The uncovered code paths require real AWS credentials and live AWS STS API calls:
- AWS credential validation success paths (lines 79-95 in
Retrieve()) - AWS STS GetCallerIdentity success (lines 152-168 in
validateAWSCredentials())
These are integration-level scenarios better suited for E2E tests with real AWS infrastructure rather than unit tests.
What We Test
✅ Validation failure path - AWS SDK without credentials
✅ Cache behavior - Hits, misses, expiration, staleness
✅ Error handling - Expired/missing credentials
✅ Storage operations - Store, Retrieve, Delete, List
✅ GetAny/SetAny - Arbitrary data storage for all keyring types
✅ Backward compatibility - Deprecated functions