Skip to content

fix: prevent invalid empty backend.tf.json generation#1833

Merged
aknysh merged 10 commits intomainfrom
osterman/fix-empty-backend-json
Dec 6, 2025
Merged

fix: prevent invalid empty backend.tf.json generation#1833
aknysh merged 10 commits intomainfrom
osterman/fix-empty-backend-json

Conversation

@osterman
Copy link
Member

@osterman osterman commented Dec 3, 2025

what

  • Prevent serialization of invalid empty backend {"": {}} in backend.tf.json
  • Add validation to reject empty backend_type in generateComponentBackendConfig()
  • Log warnings when skipping backend generation due to missing config
  • Add new error type ErrBackendTypeRequired for proper error handling
  • Comprehensive test coverage for missing backend configuration scenarios

why

When backend_type is empty (due to missing config or failed template processing), Atmos was generating invalid Terraform backend configuration {"terraform": {"backend": {"": {}}}}. This causes "Duplicate backend configuration" errors because an empty string is not a valid backend type. The fix prevents invalid config generation and provides helpful warnings directing users to the auto_generate_backend_file: false setting.

references

Fixes the issue where empty backend configuration caused "Duplicate backend configuration" errors in terraform init.

Summary by CodeRabbit

  • New Features

    • Added distinct error values to signal missing or empty backend configuration fields.
  • Bug Fixes

    • Validation now detects missing/empty backend types after processing, emits warnings, and skips backend file generation for invalid components.
  • Tests

    • Expanded coverage for backend validation, empty-backend scenarios, warning logs, and skipped-generation behavior.
  • Documentation

    • Added blog post explaining the new backend validation, examples, and migration guidance.

✏️ Tip: You can customize this high-level summary in your review settings.

@osterman osterman requested a review from a team as a code owner December 3, 2025 23:46
@github-actions github-actions bot added the size/m Medium size PR label Dec 3, 2025
@github-actions
Copy link

github-actions bot commented Dec 3, 2025

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@codecov
Copy link

codecov bot commented Dec 4, 2025

Codecov Report

❌ Patch coverage is 76.66667% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.19%. Comparing base (ed4c02b) to head (df923b1).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
internal/exec/terraform_generate_backends.go 75.00% 7 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1833      +/-   ##
==========================================
+ Coverage   72.16%   72.19%   +0.03%     
==========================================
  Files         475      475              
  Lines       45713    45740      +27     
==========================================
+ Hits        32988    33022      +34     
+ Misses      10103    10094       -9     
- Partials     2622     2624       +2     
Flag Coverage Δ
unittests 72.19% <76.66%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
errors/errors.go 100.00% <ø> (ø)
internal/exec/utils.go 79.22% <100.00%> (+0.08%) ⬆️
internal/exec/terraform_generate_backends.go 19.42% <75.00%> (+10.20%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 2025

📝 Walkthrough

Walkthrough

Adds new backend-related sentinel errors and runtime validation to detect missing or empty backend sections / backend_type. Backend generation now skips components with invalid backend configs (with warnings). Tests and documentation updated to cover the new validation and behaviors.

Changes

Cohort / File(s) Summary
Error definitions
errors/errors.go
Adds exported sentinel errors: ErrBackendTypeRequired, ErrBackendSectionMissing, ErrBackendTypeMissing, ErrBackendTypeEmptyAfterRender, ErrBackendConfigEmpty.
Backend generation & validation
internal/exec/terraform_generate_backends.go, internal/exec/utils.go
Introduces backendConfig struct, extractBackendConfig(...), checkBackendTypeAfterProcessing(...); validate/extract backend config, return ErrBackendTypeRequired for empty backend_type, emit warnings and skip backend generation when backend section or backend_type are missing or empty after template processing.
Tests
internal/exec/terraform_generate_backends_test.go, internal/exec/utils_test.go
Adds and expands tests: extractBackendConfig, checkBackendTypeAfterProcessing, ensure empty backend_type errors with ErrBackendTypeRequired, and assert skipped backend generation with log warnings and no backend files.
Documentation / Website
website/blog/2025-12-03-empty-backend-config-validation.mdx
New blog post documenting empty-remote-backend validation, examples of incorrect/correct configs, warning text, and upgrade guidance.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Check new sentinel names/messages and export visibility in errors/errors.go.
  • Verify extractBackendConfig and checkBackendTypeAfterProcessing handle non-map, non-string, empty, and post-render cases.
  • Confirm callers correctly handle errors and that log/warning text matches tests.
  • Review new tests for determinism (path handling, log capture) to avoid flakiness.

Possibly related PRs

Suggested reviewers

  • aknysh

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main fix: preventing invalid empty backend.tf.json generation when backend_type is empty.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch osterman/fix-empty-backend-json

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f13287c and 42a773d.

📒 Files selected for processing (1)
  • website/blog/2025-12-03-empty-backend-config-validation.mdx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/blog/2025-12-03-empty-backend-config-validation.mdx
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Acceptance Tests (macos)
  • GitHub Check: Acceptance Tests (linux)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Summary

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 4, 2025
@osterman osterman added the patch A minor, backward compatible change label Dec 4, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
internal/exec/terraform_generate_backends_test.go (1)

820-820: Add periods to end comments.

Several inline comments lack periods, which violates the godot linter requirement. As per coding guidelines, all comments must end with periods.

Apply this diff:

-		// Create a minimal main.tf so the component exists
+		// Create a minimal main.tf so the component exists.

-		// Create a minimal main.tf
+		// Create a minimal main.tf.

-		// Create stack file with component that has backend but NO backend_type
+		// Create stack file with component that has backend but NO backend_type.

-		// Check that warning was logged - note: the YAML processor sets backend_type to empty string
-		// so we hit the "empty after template processing" path, not the "not configured" path
+		// Check that warning was logged - note: the YAML processor sets backend_type to empty string
+		// so we hit the "empty after template processing" path, not the "not configured" path.

Also applies to: 891-891, 896-896, 943-944

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 37aecde and 2187140.

📒 Files selected for processing (1)
  • internal/exec/terraform_generate_backends_test.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Use functional options pattern to avoid functions with many parameters. Define Option functions that modify a Config struct and pass variadic options to New functions.
Use context.Context for cancellation signals, deadlines/timeouts, and request-scoped values (trace IDs). Context should be first parameter in functions that accept it. DO NOT use context for configuration, dependencies, or avoiding proper function parameters.
All comments must end with periods. This is enforced by the godot linter.
NEVER delete existing comments without a very strong reason. Preserve helpful comments, update them to match code changes, refactor for clarity, and add context when modifying code. Only remove factually incorrect, duplicated, or outdated comments.
Organize imports in three groups separated by blank lines (Go stdlib, 3rd-party excluding cloudposse/atmos, Atmos packages), sorted alphabetically. Maintain aliases: cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() + blank line to all public functions. Use nil if no atmosConfig parameter.
All errors MUST be wrapped using static errors defined in errors/errors.go. Use errors.Join for combining multiple errors, fmt.Errorf with %w for adding string context, error builder for complex errors, and errors.Is() for error checking. NEVER use dynamic errors directly.
Use go.uber.org/mock/mockgen with //go:generate directives for mock generation. Never create manual mocks.
Use viper.BindEnv with ATMOS_ prefix for environment variables.
Use colors from pkg/ui/theme/colors.go for theme consistency.
Ensure Linux/macOS/Windows compatibility. Use SDKs over binaries. Use filepath.Join(), not hardcoded path separators.
Small focused files (<600 lines). One cmd/impl per file. Co-locate tests. Never use //revive:disable:file-length-limit.

**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider us...

Files:

  • internal/exec/terraform_generate_backends_test.go
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*_test.go: Prefer unit tests with mocks over integration tests. Use interfaces + dependency injection for testability. Generate mocks with go.uber.org/mock/mockgen. Use table-driven tests for comprehensive coverage. Target >80% code coverage.
Test behavior, not implementation. Never test stub functions. Avoid tautological tests. Make code testable with DI to avoid os.Exit and external systems. Use assert.ErrorIs(err, ErrSentinel) for stdlib/our errors.

**/*_test.go: Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages
Use table-driven tests for testing multiple scenarios in Go
Include integration tests for command flows and test CLI end-to-end when possible with test fixtures

Files:

  • internal/exec/terraform_generate_backends_test.go
🧠 Learnings (14)
📓 Common learnings
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.
📚 Learning: 2024-11-12T03:16:02.910Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 775
File: internal/exec/template_funcs_component.go:157-159
Timestamp: 2024-11-12T03:16:02.910Z
Learning: In the Go code for `componentFunc` in `internal/exec/template_funcs_component.go`, the function `cleanTerraformWorkspace` does not return errors, and it's acceptable if the file does not exist. Therefore, error handling for `cleanTerraformWorkspace` is not needed.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Include integration tests for command flows and test CLI end-to-end when possible with test fixtures

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:20.297Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T17:35:20.297Z
Learning: Applies to internal/exec/template_funcs.go : New configs support Go templating with FuncMap() from internal/exec/template_funcs.go. Implement template functions in internal/exec/template_funcs.go, register them, add tests, and update documentation.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:20.297Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T17:35:20.297Z
Learning: Applies to **/*_test.go : Test behavior, not implementation. Never test stub functions. Avoid tautological tests. Make code testable with DI to avoid os.Exit and external systems. Use assert.ErrorIs(err, ErrSentinel) for stdlib/our errors.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2024-12-05T22:33:40.955Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 820
File: cmd/list_components.go:53-54
Timestamp: 2024-12-05T22:33:40.955Z
Learning: In the Atmos CLI Go codebase, using `u.LogErrorAndExit` within completion functions is acceptable because it logs the error and exits the command execution.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-04-11T22:06:46.999Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1147
File: internal/exec/validate_schema.go:42-57
Timestamp: 2025-04-11T22:06:46.999Z
Learning: The "ExecuteAtmosValidateSchemaCmd" function in internal/exec/validate_schema.go has been reviewed and confirmed to have acceptable cognitive complexity despite static analysis warnings. The function uses a clean structure with only three if statements for error handling and delegates complex operations to helper methods.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-08T19:56:18.660Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-11T03:47:59.576Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2024-10-28T01:51:30.811Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:329-332
Timestamp: 2024-10-28T01:51:30.811Z
Learning: In the Atmos Go code, when deleting directories or handling file paths (e.g., in `terraform_clean.go`), always resolve the absolute path using `filepath.Abs` and use the logger `u.LogWarning` for logging messages instead of using `fmt.Printf`.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-08-15T14:43:41.030Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Use table-driven tests for testing multiple scenarios in Go

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (3)
internal/exec/terraform_generate_backends_test.go (3)

3-18: LGTM! Import organization follows guidelines.

The new imports support log capture testing and error validation. Organization correctly groups stdlib, 3rd-party, and Atmos packages with proper aliases.


786-796: LGTM! Proper error validation.

Test correctly verifies that empty backend_type returns ErrBackendTypeRequired using assert.ErrorIs, aligning with error handling guidelines.


798-958: Excellent test coverage for skip behavior.

These integration tests thoroughly validate that components without backend configuration are properly skipped with helpful warnings. The log capture pattern and file non-existence checks effectively verify the fix prevents invalid backend generation.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 4, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
internal/exec/terraform_generate_backends.go (1)

349-355: Post-template empty backend_type guard closes the invalid JSON hole.

The checkBackendTypeAfterProcessing call ensures you never reach generateComponentBackendConfig with an empty backend type, and the warning message mirrors the pre‑validation skip behavior. One small optional tweak would be to re-use validateBackendConfig on the post-processed componentSection (or a variant of it) so that all backend/backend_type checks live in a single helper, but the current targeted backend_type check is perfectly acceptable for this bugfix.

internal/exec/terraform_generate_backends_test.go (2)

798-911: validateBackendConfig tests cover the key shapes and failure modes.

This suite does a nice job exercising valid config, missing sections, wrong types, empty maps, and nil values. Direct equality checks on SkipReason are OK here given it’s an internal helper, but be aware that changing those strings later will require updating these expectations.


934-1093: Skip‑with‑warning tests exercise the full stack path and filesystem side effects.

Both subtests build realistic stack/component layouts, swap in a test logger to capture warnings, and assert that:

  • the warning mentions skipping backend generation and the user hint, and
  • no backend.tf / backend.tf.json files are produced.

That gives good confidence the new validation/skip logic is wired correctly end‑to‑end without over‑specifying the implementation.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2187140 and d726881.

📒 Files selected for processing (2)
  • internal/exec/terraform_generate_backends.go (3 hunks)
  • internal/exec/terraform_generate_backends_test.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Use functional options pattern to avoid functions with many parameters. Define Option functions that modify a Config struct and pass variadic options to New functions.
Use context.Context for cancellation signals, deadlines/timeouts, and request-scoped values (trace IDs). Context should be first parameter in functions that accept it. DO NOT use context for configuration, dependencies, or avoiding proper function parameters.
All comments must end with periods. This is enforced by the godot linter.
NEVER delete existing comments without a very strong reason. Preserve helpful comments, update them to match code changes, refactor for clarity, and add context when modifying code. Only remove factually incorrect, duplicated, or outdated comments.
Organize imports in three groups separated by blank lines (Go stdlib, 3rd-party excluding cloudposse/atmos, Atmos packages), sorted alphabetically. Maintain aliases: cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() + blank line to all public functions. Use nil if no atmosConfig parameter.
All errors MUST be wrapped using static errors defined in errors/errors.go. Use errors.Join for combining multiple errors, fmt.Errorf with %w for adding string context, error builder for complex errors, and errors.Is() for error checking. NEVER use dynamic errors directly.
Use go.uber.org/mock/mockgen with //go:generate directives for mock generation. Never create manual mocks.
Use viper.BindEnv with ATMOS_ prefix for environment variables.
Use colors from pkg/ui/theme/colors.go for theme consistency.
Ensure Linux/macOS/Windows compatibility. Use SDKs over binaries. Use filepath.Join(), not hardcoded path separators.
Small focused files (<600 lines). One cmd/impl per file. Co-locate tests. Never use //revive:disable:file-length-limit.

**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider us...

Files:

  • internal/exec/terraform_generate_backends.go
  • internal/exec/terraform_generate_backends_test.go
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*_test.go: Prefer unit tests with mocks over integration tests. Use interfaces + dependency injection for testability. Generate mocks with go.uber.org/mock/mockgen. Use table-driven tests for comprehensive coverage. Target >80% code coverage.
Test behavior, not implementation. Never test stub functions. Avoid tautological tests. Make code testable with DI to avoid os.Exit and external systems. Use assert.ErrorIs(err, ErrSentinel) for stdlib/our errors.

**/*_test.go: Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages
Use table-driven tests for testing multiple scenarios in Go
Include integration tests for command flows and test CLI end-to-end when possible with test fixtures

Files:

  • internal/exec/terraform_generate_backends_test.go
🧠 Learnings (17)
📓 Common learnings
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.
📚 Learning: 2025-09-29T02:20:11.636Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/validate_component.go:117-118
Timestamp: 2025-09-29T02:20:11.636Z
Learning: The ValidateComponent function in internal/exec/validate_component.go had its componentSection parameter type refined from `any` to `map[string]any` without adding new parameters. This is a type safety improvement, not a signature change requiring call site updates.

Applied to files:

  • internal/exec/terraform_generate_backends.go
📚 Learning: 2025-01-09T22:27:25.538Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 914
File: cmd/validate_stacks.go:20-23
Timestamp: 2025-01-09T22:27:25.538Z
Learning: The validate commands in Atmos can have different help handling implementations. Specifically, validate_component.go and validate_stacks.go are designed to handle help requests differently, with validate_stacks.go including positional argument checks while validate_component.go does not.

Applied to files:

  • internal/exec/terraform_generate_backends.go
📚 Learning: 2024-11-12T03:16:02.910Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 775
File: internal/exec/template_funcs_component.go:157-159
Timestamp: 2024-11-12T03:16:02.910Z
Learning: In the Go code for `componentFunc` in `internal/exec/template_funcs_component.go`, the function `cleanTerraformWorkspace` does not return errors, and it's acceptable if the file does not exist. Therefore, error handling for `cleanTerraformWorkspace` is not needed.

Applied to files:

  • internal/exec/terraform_generate_backends.go
  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Include integration tests for command flows and test CLI end-to-end when possible with test fixtures

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:20.297Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T17:35:20.297Z
Learning: Applies to **/*_test.go : Prefer unit tests with mocks over integration tests. Use interfaces + dependency injection for testability. Generate mocks with go.uber.org/mock/mockgen. Use table-driven tests for comprehensive coverage. Target >80% code coverage.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2024-12-05T22:33:40.955Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 820
File: cmd/list_components.go:53-54
Timestamp: 2024-12-05T22:33:40.955Z
Learning: In the Atmos CLI Go codebase, using `u.LogErrorAndExit` within completion functions is acceptable because it logs the error and exits the command execution.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:20.297Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T17:35:20.297Z
Learning: Applies to **/*_test.go : Test behavior, not implementation. Never test stub functions. Avoid tautological tests. Make code testable with DI to avoid os.Exit and external systems. Use assert.ErrorIs(err, ErrSentinel) for stdlib/our errors.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-04-11T22:06:46.999Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1147
File: internal/exec/validate_schema.go:42-57
Timestamp: 2025-04-11T22:06:46.999Z
Learning: The "ExecuteAtmosValidateSchemaCmd" function in internal/exec/validate_schema.go has been reviewed and confirmed to have acceptable cognitive complexity despite static analysis warnings. The function uses a clean structure with only three if statements for error handling and delegates complex operations to helper methods.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-08T19:56:18.660Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2024-10-28T01:51:30.811Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:329-332
Timestamp: 2024-10-28T01:51:30.811Z
Learning: In the Atmos Go code, when deleting directories or handling file paths (e.g., in `terraform_clean.go`), always resolve the absolute path using `filepath.Abs` and use the logger `u.LogWarning` for logging messages instead of using `fmt.Printf`.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-11T03:47:59.576Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-08-15T14:43:41.030Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Use table-driven tests for testing multiple scenarios in Go

Applied to files:

  • internal/exec/terraform_generate_backends_test.go
🧬 Code graph analysis (1)
internal/exec/terraform_generate_backends.go (2)
pkg/config/const.go (2)
  • BackendSectionName (71-71)
  • BackendTypeSectionName (72-72)
pkg/logger/log.go (1)
  • Warn (44-46)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Summary
🔇 Additional comments (5)
internal/exec/terraform_generate_backends.go (2)

20-68: Backend validation helpers look clean and testable.

The backendConfigValidationResult, validateBackendConfig, and checkBackendTypeAfterProcessing helpers keep backend checks side‑effect free and easy to unit test, while using the cfg constants for keys. I don’t see functional issues here; the shape handling for missing/mistyped backend and backend_type is sensible and matches the new tests.


185-195: Early validation + warning on missing backend config is a good guardrail.

Running validateBackendConfig before doing any of the heavier work and emitting a warning with guidance on auto_generate_backend_file: false gives users a clear signal while safely skipping misconfigured components. The control flow (continue on invalid, then copying BackendSection/BackendType only on valid) avoids leaking state between components.

internal/exec/terraform_generate_backends_test.go (3)

3-18: Import updates align with Atmos conventions.

The added imports (buffering, logging, error alias) are grouped stdlib → third‑party → atmos packages and keep the established aliases (errUtils, log, u), so this stays consistent with the repo’s style.


786-795: Empty backend type behavior is well‑specified via ErrBackendTypeRequired.

The new subtest around generateComponentBackendConfig with an empty backend type cleanly asserts that you get a non‑nil error, a nil result, and ErrBackendTypeRequired. That gives a precise contract for callers and lines up with the new validation flow.


913-932: checkBackendTypeAfterProcessing tests are straightforward and exhaustive enough.

You cover both generic “any non‑empty string is fine” and the empty‑string skip case, which matches the helper’s simple contract and guards against regressions if additional backend types are introduced.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 4, 2025
osterman and others added 8 commits December 4, 2025 20:35
- Add validation in generateComponentBackendConfig() to reject empty backend_type
- Add ErrBackendTypeRequired sentinel error for proper error handling
- Log warnings when skipping backend generation due to missing backend or backend_type
- Include auto_generate_backend_file setting hint in warning messages
- Add comprehensive tests to verify no backend files are generated when config is incomplete
- Tests validate both warning messages and file non-existence

This prevents the issue where an empty backend type would result in invalid Terraform config like `{"terraform": {"backend": {"": {}}}}`, which causes "Duplicate backend configuration" errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Clarify that the YAML processor sets empty backend_type strings, so tests
hit the "empty after template processing" path rather than the "not configured" path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add validateBackendConfig() pure function with 100% test coverage
- Add checkBackendTypeAfterProcessing() pure function with 100% test coverage
- Add comprehensive unit tests for all validation scenarios
- Refactor ExecuteTerraformGenerateBackends to use extracted functions

This improves testability by separating validation logic from side effects,
allowing direct unit testing of all validation paths without requiring
complex integration test setups.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Simplify the type name and remove verbose field comments.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The struct holds the backend configuration, so backendConfig is clearer.
The function extracts config from the component section, so extractBackendConfig
better describes what it does.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replace SkipReason string with Err error field in backendConfig.
Add sentinel errors: ErrBackendSectionMissing, ErrBackendTypeMissing,
ErrBackendTypeEmptyAfterRender.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
When backend_type is set to s3, gcs, azurerm, or cloud but the backend
section is empty, skip backend generation with a warning instead of
generating invalid Terraform configuration like {"terraform":{"backend":{"s3":{}}}}.

The local backend is still allowed to have empty configuration since
Terraform supports it without any required fields.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 5, 2025
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@aknysh aknysh merged commit 40c4c0f into main Dec 6, 2025
57 checks passed
@aknysh aknysh deleted the osterman/fix-empty-backend-json branch December 6, 2025 03:18
osterman added a commit that referenced this pull request Dec 6, 2025
Brings in recent changes from main including:
- Native devcontainer support (#1697)
- Version constraint validation for atmos.yaml (#1759)
- Fix for empty backend.tf.json generation (#1833)
- Document missing component metadata fields (#1840)

Resolved conflicts:
- cmd/root.go: Added both devcontainer and init/scaffold imports
- Test snapshot will be regenerated to include devcontainer command

Note: Pre-existing linting issues in init/scaffold experimental code
remain and will be addressed before merging to main.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

Labels

patch A minor, backward compatible change size/l Large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants