Skip to content

Conversation

@osterman
Copy link
Member

@osterman osterman commented Nov 20, 2025

Summary

  • Implement automatic Terraform backend provisioning system to eliminate manual bootstrapping
  • Add self-registering provisioner architecture with hook-based integration
  • Provide S3 backend implementation with opinionated security defaults (versioning, AES-256 encryption, public access blocking)
  • Support cross-account provisioning via AuthManager integration
  • Enable CLI command for manual provisioning: atmos provision backend

Details

  • Provisioner System: Extensible self-registering architecture that allows provisioners to declare when they should run via hook events
  • S3 Backend: Hardcoded secure defaults (no configuration options), perfect for dev/test workflows
  • Hook Integration: Automatic provisioning before terraform init when enabled
  • Production Migration: Clear path to move from automatic provisioning to Terraform-managed via import blocks
  • Documentation: 3 PRDs, CLI reference, configuration guide, and blog announcement

Test Plan

  • Verify provisioner system loads and registers correctly
  • Test S3 backend provisioning creates bucket with all security defaults
  • Verify idempotent operations (running provision multiple times is safe)
  • Test CLI command: atmos provision backend <component> --stack <stack>
  • Verify automatic provisioning runs before terraform init
  • Test error handling and exit codes
  • Validate documentation builds successfully

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]

Summary by CodeRabbit

  • New Features
    • Automatic backend provisioning that runs before Terraform init; new CLI "backend" subcommands (create/list/describe/update/delete); secure-by-default S3 provisioning with cross-account role support and deletion/import workflows.
  • Documentation
    • Multiple PRDs, CLI docs, blog post, and guides covering provisioning design, configuration examples, migration and security notes.
  • Bug Fixes
    • Help-printing guard to avoid empty-description errors; improved provisioning error messages.
  • Tests
    • Extensive test coverage for provisioning flows, registry/hooks, CLI commands, and S3 operations.

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

Implement automatic Terraform backend provisioning system to eliminate manual
bootstrapping steps. Includes extensible provisioner architecture, S3 backend
implementation with hardcoded security defaults (versioning, AES-256 encryption,
public access blocking), cross-account support via role assumption, and CLI
commands for dev/test workflows.

Features:
- Self-registering provisioner system via hooks
- S3 backend provisioner with opinionated security defaults
- Automatic provisioning before terraform init
- Manual provisioning via `atmos provision backend` command
- Cross-account support with AuthManager integration
- Idempotent operations (safe to run multiple times)
- Production migration path with Terraform import blocks

Documentation:
- 3 PRDs: provisioner-system, backend-provisioner, s3-backend-provisioner
- CLI reference: website/docs/cli/commands/provision/backend.mdx
- Configuration guide: backends.mdx with automatic provisioning section
- Blog post: Announcing automatic backend provisioning

🤖 Generated with Claude Code

Co-Authored-By: Claude <[email protected]>
@osterman osterman requested a review from a team as a code owner November 20, 2025 06:29
@github-actions github-actions bot added the size/xl Extra large size PR label Nov 20, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 20, 2025

📝 Walkthrough

Walkthrough

Adds a provisioner framework and CLI for automatic Terraform backend provisioning (S3 create/delete), registers and runs provisioners before Terraform init, wires a new terraform backend command group (create/list/describe/update/delete), propagates Atmos config to the backend CLI, and adds extensive tests and documentation.

Changes

Cohort / File(s) Summary
Provisioner core & registry
pkg/provisioner/registry.go, pkg/provisioner/registry_test.go, pkg/hooks/event.go
Adds provisioner registry, HookEvent type and BeforeTerraformInit constant, registration/getters, ExecuteProvisioners and tests.
Provisioner orchestration
pkg/provisioner/provisioner.go, pkg/provisioner/provisioner_test.go
Implements high-level Provision/Delete/List/Describe flows, parameter structs, timeouts, DescribeComponent wiring, and tests.
Backend provisioning API
pkg/provisioner/backend/backend.go, pkg/provisioner/backend/backend_test.go
Adds backend create/delete func registries, Register/Get helpers, and ProvisionBackend orchestration with validation and errors.
S3 backend impl & deletion
pkg/provisioner/backend/s3.go, pkg/provisioner/backend/s3_delete.go, pkg/provisioner/backend/s3_test.go
Implements S3 create/delete workflows (bucket existence, create, versioning/encryption/public-access/tags, object/version deletion, role assumption), S3 client interface, helpers, and tests/mocks.
CLI backend commands & helpers
cmd/terraform/backend/backend.go, cmd/terraform/backend/backend_create.go, cmd/terraform/backend/backend_delete.go, cmd/terraform/backend/backend_describe.go, cmd/terraform/backend/backend_list.go, cmd/terraform/backend/backend_update.go, cmd/terraform/backend/backend_helpers.go
Adds atmos terraform backend command group, CRUD subcommands, shared flag parsing, InitConfigAndAuth, dependency injection for tests, and SetAtmosConfig/GetBackendCommand.
CLI wiring & root integration
cmd/root.go, cmd/terraform_commands.go, cmd/terraform/backend/backend.go
Propagates Atmos config to backend CLI via SetAtmosConfig(...) and attaches backend subcommand to terraform command.
CLI tests, mocks & helpers
cmd/terraform/backend/*_test.go, cmd/terraform/backend/backend_commands_test.go, cmd/terraform/backend/mock_backend_helpers_test.go, cmd/terraform/backend/backend_test_helpers.go
Adds extensive unit tests, gomock-generated mocks, and test helpers for backend CLI commands.
Terraform exec hooks
internal/exec/terraform.go
Runs provisioners for before.terraform.init with a 5-minute timeout across init paths; aborts on provisioner errors.
Errors & sentinels
errors/errors.go
Adds many backend/provisioning sentinel errors (bucket/region required, create/delete not implemented, AWS op failures, access denied, force required, etc.).
TUI help & snapshots
internal/tui/templates/help_printer.go, internal/tui/templates/help_printer_test.go, tests/snapshots/*
Guards help-flag printing for empty descriptions; updates help snapshots to include new backend subcommand and adds tests.
Tests & misc
pkg/config/load_flags_test.go
Removes OS-args dependency in tests (use Viper/env).
Docs & website
docs/prd/*, website/docs/*, website/blog/2025-11-20-automatic-backend-provisioning.mdx, website/docusaurus.config.js
Adds PRDs, docs, blog post, conceptual pages for backend provisioning/remote state, examples, and redirects.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI (atmos terraform backend create)
    participant Helpers as backend_helpers
    participant Provisioner as provisioner
    participant BackendMgr as backend registry
    participant S3Prov as S3 provisioner
    participant AWS as AWS S3

    CLI->>Helpers: ExecuteProvisionCommand(component, flags)
    Helpers->>Helpers: ParseCommonFlags -> InitConfigAndAuth
    Helpers->>Provisioner: Provision(atmosConfig, "backend", component, stack, describeFunc, authContext)
    Provisioner->>Provisioner: DescribeComponent -> componentConfig
    Provisioner->>BackendMgr: ProvisionBackend(ctx, atmosConfig, componentConfig, authContext)
    BackendMgr->>BackendMgr: extract backend_type & backend config
    BackendMgr->>BackendMgr: GetBackendCreate("s3")
    BackendMgr->>S3Prov: CreateS3Backend(ctx, atmosConfig, backendConfig, authContext)
    S3Prov->>S3Prov: extractS3Config, loadAWSConfigWithAuth
    S3Prov->>AWS: HeadBucket (exists?)
    alt Bucket exists
        S3Prov->>S3Prov: apply defaults (versioning/encryption/blocks/tags) with warnings
    else Bucket missing
        S3Prov->>AWS: CreateBucket
        S3Prov->>AWS: PutBucketVersioning, PutBucketEncryption, PutPublicAccessBlock, PutBucketTagging
    end
    S3Prov-->>BackendMgr: result (success/error)
    BackendMgr-->>Provisioner: result
    Provisioner-->>Helpers: result
    Helpers-->>CLI: UI output / exit
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas to focus review on:

  • pkg/provisioner/backend/s3.go, s3_delete.go — AWS API semantics, batching, pagination, and error wrapping.
  • pkg/provisioner/registry.go and internal/exec/terraform.go — concurrency, context/timeout handling, and fail-fast behavior.
  • cmd/terraform/backend/backend_helpers.go — InitConfigAndAuth, auth merging/precedence, and dependency injection points.
  • errors/errors.go — sentinel consistency and usage across callers.
  • New tests & generated mocks — Viper/global state isolation and test flakiness risks.

Possibly related PRs

Suggested reviewers

  • aknysh

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.78% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature: automatic backend provisioning for Terraform. It's concise, specific, and directly reflects the primary objective of the PR.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch osterman/auto-backend-provision

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • AES-256: Entity not found: Issue - Could not find referenced Issue.

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.

@mergify
Copy link

mergify bot commented Nov 20, 2025

Warning

This PR exceeds the recommended limit of 1,000 lines.

Large PRs are difficult to review and may be rejected due to their size.

Please verify that this PR does not address multiple issues.
Consider refactoring it into smaller, more focused PRs to facilitate a smoother review process.

@github-actions
Copy link

github-actions bot commented Nov 20, 2025

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

Update all PRDs and documentation to clarify that provision blocks can be
specified at multiple levels in the stack hierarchy (top-level terraform,
environment-level, component-level) and leverage Atmos's deep-merge system.

Changes:
- Add "Configuration Hierarchy" sections to all 3 PRDs showing inheritance patterns
- Update CLI docs with hierarchy examples (global defaults, environment overrides, catalog inheritance)
- Enhance core concepts backends.mdx with hierarchy section showing typical dev/prod patterns
- Add "Configuration Flexibility" section to blog post demonstrating multi-level configuration
- Fix broken documentation links (/core-concepts/backends/migration-to-production doesn't exist)

Benefits:
- Users can now set defaults at org/env level instead of repeating per component
- Clear guidance on dev (auto-provision) vs prod (pre-provisioned) patterns
- Inheritance via metadata.inherits now documented
- Component-level overrides explained

🤖 Generated with Claude Code

Co-Authored-By: Claude <[email protected]>
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: 3

🧹 Nitpick comments (9)
docs/prd/s3-backend-provisioner.md (1)

413-426: Be explicit about HeadBucket error handling semantics

checkS3BucketExists currently treats any error from HeadBucket as “bucket does not exist” and returns (false, nil):

if err != nil {
	// Bucket doesn't exist or access denied (treat as doesn't exist)
	return false, nil
}

That’s fine for the happy path (we’ll immediately try CreateBucket and get a clearer error), but it also masks transient/network issues as “non-existent”. If you later add retry/backoff or richer error reporting, this is a spot worth revisiting to distinguish “definitely not found” from “couldn’t check”. For now the behavior is acceptable but should stay intentional.

docs/prd/backend-provisioner.md (1)

340-352: Optional: clean up markdownlint issues in PRD

The PRD looks solid conceptually. Static analysis is flagging a bunch of markdown nits (hard tabs in code fences, some fences without a language like around the configuration filtering and error examples). If you run markdownlint as part of docs CI, these will likely show up:

  • MD010 (no-hard-tabs) on many Go/YAML blocks
  • MD040 (fenced-code-language) on a few unlabeled fences

Not urgent, but worth a quick pass (or a markdownlint ignore) before merging if your pipeline enforces these.

Also applies to: 616-655

docs/prd/provisioner-system.md (1)

525-545: Optional: address markdownlint warnings

This PRD is thorough and lines up with the implementation. The only issues flagged by tooling are markdown hygiene:

  • Hard tabs in many Go/YAML blocks (MD010)
  • A few code fences without a language (MD040)
  • One “emphasis as heading” case (MD036) near the exit-code table

If markdownlint is wired into CI, consider normalizing indentation to spaces and adding explicit languages (e.g., go, yaml) where missing, or updating the lint config for PRDs.

Also applies to: 1013-1045

internal/exec/terraform.go (1)

24-30: Wire provisioners to pre-init hook using shared event constant

The new calls to:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
err = provisioner.ExecuteProvisioners(ctx, provisioner.HookEvent(beforeTerraformInitEvent), &atmosConfig, info.ComponentSection, info.AuthContext)

nicely ensure all registered provisioners run before any terraform init, both in the general path and the explicit init subcommand. The 5‑minute timeout is a reasonable bound for backend provisioning.

One tweak to reduce drift risk: you already defined BeforeTerraformInit in pkg/hooks/event.go. Instead of a local string:

const (
	beforeTerraformInitEvent = "before.terraform.init"
)

you could reuse the shared constant and avoid duplicate literals, e.g.:

-import (
-    // ...
-    "github.com/cloudposse/atmos/pkg/provisioner"
-    // ...
-)
+import (
+    // ...
+    "github.com/cloudposse/atmos/pkg/hooks"
+    "github.com/cloudposse/atmos/pkg/provisioner"
+    // ...
+)
-
-const (
-    beforeTerraformInitEvent = "before.terraform.init"
-)
+// Use shared hook event name for pre-init provisioners.
+
...
-err = provisioner.ExecuteProvisioners(ctx, provisioner.HookEvent(beforeTerraformInitEvent), &atmosConfig, info.ComponentSection, info.AuthContext)
+err = provisioner.ExecuteProvisioners(ctx, provisioner.HookEvent(hooks.BeforeTerraformInit), &atmosConfig, info.ComponentSection, info.AuthContext)

Same change can be applied in the case "init" branch. This keeps the hook event name single-sourced and less error-prone if you ever rename it.

Also applies to: 420-429, 522-531

pkg/provisioner/backend/s3.go (1)

186-272: Be careful when applying defaults to pre-existing buckets

Right now applyS3BucketDefaults always:

  • Forces encryption to SSE-S3 AES-256.
  • Replaces the entire tag set with just Name and ManagedBy=Atmos.

On a bucket that already exists (e.g., pre-provisioned or shared), this will silently:

  • Downgrade or change a KMS-based encryption policy.
  • Wipe any existing tags unrelated to Atmos.

For a dev/test-only provisioner this may be acceptable, but it’s a sharp edge if someone points it at a shared or production-style bucket.

Consider one of:

  • Detecting whether the bucket was just created vs. pre-existing and only enforcing hard defaults on new buckets.
  • Merging tags instead of replacing them wholesale, and skipping encryption changes if a non-AES256 policy is already configured.
  • At minimum, making this overwrite behavior very explicit in docs and error messages.
website/docs/core-concepts/components/terraform/backends.mdx (1)

643-657: Clarify YAML context for backend / provision snippets

The examples under “Configuration” and “Supported Backend Types → S3” show backend: and provision: as top-level keys, but earlier in this doc the S3 backend examples are always nested under the component path (components.terraform.<component>.backend).

To avoid confusion, it would help to mirror that full context here, e.g.:

components:
  terraform:
    vpc:
      backend:
        bucket: acme-terraform-state-dev
        key: vpc/terraform.tfstate
        region: us-east-1
        backend_type: s3

      provision:
        backend:
          enabled: true

Same idea for the cross-account example. That keeps the docs aligned with how ProvisionBackend and the stack manifests actually structure component config.

Also applies to: 753-781

pkg/provision/provision.go (1)

25-61: Consider plumbing AuthContext into Provision for manual CLI usage

The implementation is straightforward and correct for backend provisioning, but Provision always calls:

err = backend.ProvisionBackend(ctx, atmosConfig, componentConfig, nil)

so manual atmos provision backend ... runs can’t benefit from Atmos-managed auth (e.g., --identity / AuthManager) and instead rely solely on the default AWS credential chain.

If you want the manual provision command to behave like the Terraform path (which passes an AuthContext), consider:

  • Extending ExecuteDescribeComponentFunc to also surface an *schema.AuthContext, or
  • Adding an explicit authContext *schema.AuthContext parameter to Provision and wiring it from the caller.

That would make cross-account and SSO-based provisioning consistent across both automatic and manual flows.

cmd/provision/provision.go (1)

50-98: Verify config/init and consider passing AuthContext into provisioning

A couple of small points in RunE:

  • You correctly use StandardParser + Viper for --stack (with ATMOS_STACK env support) and validate the flag; that’s consistent with the existing flag patterns.
  • You call cfg.InitCliConfig with processStacks=false, then separately call ExecuteDescribeComponent, which will do its own stack processing. That’s probably fine, but it does mean config init work is split between two places—worth a quick sanity check against existing commands that use ExecuteDescribeComponent to ensure behavior is consistent.
  • As in pkg/provision.Provision, you don’t currently plumb any AuthContext from the identity/CLI layer into backend provisioning, so atmos provision backend always falls back to the default AWS SDK credential chain.

If you want manual provisioning to honor --identity and the AuthManager flow, you’ll likely need to:

  • Grab the active AuthContext (from the same place internal/exec/terraform does), and
  • Pass it down into provision.Provision / backend.ProvisionBackend.

Not urgent for a first cut, but it will make the manual command match the automatic Terraform-init provisioning behavior.

pkg/provisioner/backend/backend.go (1)

13-21: Consider defining hook event constants.

The hook event "before.terraform.init" is hardcoded as a string literal. If hook events are used across multiple provisioners, defining them as constants (e.g., const HookBeforeTerraformInit HookEvent = "before.terraform.init") would prevent typos and improve discoverability.

For example, in a separate constants file or in pkg/provisioner/provisioner.go:

const (
    HookBeforeTerraformInit HookEvent = "before.terraform.init"
    HookAfterTerraformInit  HookEvent = "after.terraform.init"
    // ... other hooks
)

Then use it here:

-		HookEvent: "before.terraform.init",
+		HookEvent: HookBeforeTerraformInit,
📜 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 10886fe and e972b3e.

📒 Files selected for processing (15)
  • cmd/provision/provision.go (1 hunks)
  • cmd/root.go (1 hunks)
  • docs/prd/backend-provisioner.md (1 hunks)
  • docs/prd/provisioner-system.md (1 hunks)
  • docs/prd/s3-backend-provisioner.md (1 hunks)
  • internal/exec/terraform.go (4 hunks)
  • pkg/hooks/event.go (1 hunks)
  • pkg/provision/provision.go (1 hunks)
  • pkg/provisioner/backend/backend.go (1 hunks)
  • pkg/provisioner/backend/s3.go (1 hunks)
  • pkg/provisioner/errors.go (1 hunks)
  • pkg/provisioner/provisioner.go (1 hunks)
  • website/blog/2025-11-20-automatic-backend-provisioning.mdx (1 hunks)
  • website/docs/cli/commands/provision/backend.mdx (1 hunks)
  • website/docs/core-concepts/components/terraform/backends.mdx (1 hunks)
🧰 Additional context used
🧠 Learnings (30)
📓 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-13T16:39:20.007Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.

Applied to files:

  • website/docs/cli/commands/provision/backend.mdx
📚 Learning: 2025-01-19T15:49:15.593Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 955
File: tests/snapshots/TestCLICommands_atmos_validate_editorconfig_--help.stdout.golden:0-0
Timestamp: 2025-01-19T15:49:15.593Z
Learning: In future commits, the help text for Atmos CLI commands should be limited to only show component and stack parameters for commands that actually use them. This applies to the example usage section in command help text.

Applied to files:

  • website/docs/cli/commands/provision/backend.mdx
📚 Learning: 2024-12-03T05:29:07.718Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: internal/exec/terraform_utils.go:145-146
Timestamp: 2024-12-03T05:29:07.718Z
Learning: In the Atmos project, a 5-minute timeout in the `execTerraformOutput` function is acceptable for retrieving `terraform output` for a component in a stack.

Applied to files:

  • website/docs/cli/commands/provision/backend.mdx
📚 Learning: 2025-09-10T21:17:55.273Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/http_client_test.go:3-10
Timestamp: 2025-09-10T21:17:55.273Z
Learning: In the cloudposse/atmos repository, imports should never be changed as per samtholiya's coding guidelines.

Applied to files:

  • cmd/root.go
📚 Learning: 2025-07-05T20:59:02.914Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1363
File: internal/exec/template_utils.go:18-18
Timestamp: 2025-07-05T20:59:02.914Z
Learning: In the Atmos project, gomplate v4 is imported with a blank import (`_ "github.com/hairyhenderson/gomplate/v4"`) alongside v3 imports to resolve AWS SDK version conflicts. V3 uses older AWS SDK versions that conflict with newer AWS modules used by Atmos. A full migration to v4 requires extensive refactoring due to API changes and should be handled in a separate PR.

Applied to files:

  • cmd/root.go
  • internal/exec/terraform.go
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.

Applied to files:

  • cmd/root.go
  • cmd/provision/provision.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.

Applied to files:

  • cmd/root.go
  • cmd/provision/provision.go
  • internal/exec/terraform.go
📚 Learning: 2025-10-07T00:25:16.333Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1498
File: website/src/components/Screengrabs/atmos-terraform-metadata--help.html:25-55
Timestamp: 2025-10-07T00:25:16.333Z
Learning: In Atmos CLI, subcommands inherit flags from their parent commands via Cobra's command inheritance. For example, `atmos terraform metadata --help` shows `--affected` and related flags inherited from the parent `terraform` command (defined in cmd/terraform.go), even though the metadata subcommand doesn't explicitly define these flags. This is expected Cobra behavior and auto-generated help screengrabs accurately reflect this inheritance.

Applied to files:

  • cmd/root.go
  • cmd/provision/provision.go
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.

Applied to files:

  • cmd/root.go
  • cmd/provision/provision.go
📚 Learning: 2025-09-27T20:50:20.564Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1533
File: pkg/config/load.go:585-637
Timestamp: 2025-09-27T20:50:20.564Z
Learning: In the cloudposse/atmos repository, command merging prioritizes precedence over display ordering. Help commands are displayed lexicographically regardless of internal array order, so the mergeCommandArrays function focuses on ensuring the correct precedence chain (top-level file wins) rather than maintaining specific display order.

Applied to files:

  • cmd/root.go
📚 Learning: 2025-01-30T19:30:59.120Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 959
File: cmd/workflow.go:74-74
Timestamp: 2025-01-30T19:30:59.120Z
Learning: Error handling for `cmd.Usage()` is not required in the Atmos CLI codebase, as confirmed by the maintainer.

Applied to files:

  • cmd/root.go
📚 Learning: 2024-10-20T13:12:46.499Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 736
File: pkg/config/const.go:6-6
Timestamp: 2024-10-20T13:12:46.499Z
Learning: In `cmd/cmd_utils.go`, it's acceptable to have hardcoded references to `atmos.yaml` in logs, and it's not necessary to update them to use the `CliConfigFileName` constant.

Applied to files:

  • cmd/root.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:

  • cmd/root.go
  • internal/exec/terraform.go
📚 Learning: 2025-11-09T19:06:58.470Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1752
File: pkg/profile/list/formatter_table.go:27-29
Timestamp: 2025-11-09T19:06:58.470Z
Learning: In the cloudposse/atmos repository, performance tracking with `defer perf.Track()` is enforced on all functions via linting, including high-frequency utility functions, formatters, and renderers. This is a repository-wide policy to maintain consistency and avoid making case-by-case judgment calls about which functions should have profiling.

Applied to files:

  • cmd/root.go
  • internal/exec/terraform.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:

  • cmd/provision/provision.go
  • internal/exec/terraform.go
📚 Learning: 2025-11-10T03:03:31.505Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-11-10T03:03:31.505Z
Learning: In the Atmos codebase, commands using the `StandardParser` flag pattern (from pkg/flags) do NOT need explicit `viper.BindPFlag()` calls in their code. The StandardParser encapsulates flag binding internally: flags are registered via `parser.RegisterFlags(cmd)` in init(), and bound via `parser.BindFlagsToViper(cmd, v)` in RunE, which internally calls viper.BindPFlag for each flag. This pattern is used throughout Atmos (e.g., cmd/toolchain/get.go, cmd/toolchain/info.go, cmd/toolchain/install.go, cmd/toolchain/path.go). Do not flag missing viper.BindPFlag calls when StandardParser is used.

Applied to files:

  • cmd/provision/provision.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:

  • cmd/provision/provision.go
📚 Learning: 2025-01-25T03:51:57.689Z
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.

Applied to files:

  • website/blog/2025-11-20-automatic-backend-provisioning.mdx
📚 Learning: 2025-10-03T18:02:08.535Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1475
File: internal/exec/terraform.go:269-272
Timestamp: 2025-10-03T18:02:08.535Z
Learning: In internal/exec/terraform.go, when auth.TerraformPreHook fails, the error is logged but execution continues. This is a deliberate design choice to allow Terraform commands to proceed even if authentication setup fails, rather than failing fast.

Applied to files:

  • internal/exec/terraform.go
  • docs/prd/provisioner-system.md
  • docs/prd/backend-provisioner.md
📚 Learning: 2024-11-02T15:35:09.958Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 759
File: internal/exec/terraform.go:366-368
Timestamp: 2024-11-02T15:35:09.958Z
Learning: In `internal/exec/terraform.go`, the workspace cleaning code under both the general execution path and within the `case "init":` block is intentionally duplicated because the code execution paths are different. The `.terraform/environment` file should be deleted before executing `terraform init` in both scenarios to ensure a clean state.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2024-12-03T03:52:02.524Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: internal/exec/terraform_utils.go:144-145
Timestamp: 2024-12-03T03:52:02.524Z
Learning: Avoid adding context timeouts to Terraform commands in `execTerraformOutput` because their execution time can vary from seconds to hours, and making it configurable would require redesigning the command interface.

Applied to files:

  • internal/exec/terraform.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.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.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.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.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.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1405
File: internal/exec/describe_dependents_test.go:455-456
Timestamp: 2025-08-16T23:32:40.412Z
Learning: In the cloudposse/atmos Go codebase, `InitCliConfig` returns a `schema.AtmosConfiguration` value (not a pointer), while `ExecuteDescribeDependents` expects a `*schema.AtmosConfiguration` pointer parameter. Therefore, when passing the result of `InitCliConfig` to `ExecuteDescribeDependents`, use `&atmosConfig` to pass the address of the value.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2024-10-21T17:51:53.976Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform.go:114-118
Timestamp: 2024-10-21T17:51:53.976Z
Learning: When `atmos terraform clean --everything` is used without specifying a component and without the `--force` flag, prompt the user for confirmation before deleting all components. Use the `--force` flag to skip the confirmation prompt.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-04-26T15:54:10.506Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 1195
File: internal/exec/terraform_clean.go:99-99
Timestamp: 2025-04-26T15:54:10.506Z
Learning: The error variable `ErrRelPath` is defined in `internal/exec/terraform_clean_util.go` and is used across files in the `exec` package, including in `terraform_clean.go`. This is part of an approach to standardize error handling in the codebase.

Applied to files:

  • pkg/provisioner/errors.go
🧬 Code graph analysis (7)
pkg/hooks/event.go (1)
pkg/provisioner/provisioner.go (1)
  • HookEvent (14-14)
pkg/provisioner/backend/s3.go (6)
pkg/provisioner/backend/backend.go (1)
  • RegisterBackendProvisioner (38-45)
pkg/schema/schema.go (3)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
  • AWSAuthContext (582-597)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/provisioner/errors.go (10)
  • ErrLoadAWSConfig (13-13)
  • ErrApplyBucketDefaults (16-16)
  • ErrBucketRequired (7-7)
  • ErrRegionRequired (8-8)
  • ErrCheckBucketExist (14-14)
  • ErrCreateBucket (15-15)
  • ErrEnableVersioning (17-17)
  • ErrEnableEncryption (18-18)
  • ErrBlockPublicAccess (19-19)
  • ErrApplyTags (20-20)
pkg/ui/formatter.go (1)
  • Success (169-175)
internal/aws_utils/aws_utils.go (1)
  • LoadAWSConfigWithAuth (53-119)
cmd/provision/provision.go (9)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • ConfigAndStacksInfo (620-714)
pkg/flags/standard_parser.go (2)
  • StandardParser (18-22)
  • NewStandardParser (34-40)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/flags/global_registry.go (1)
  • ParseGlobalFlags (33-74)
errors/errors.go (2)
  • ErrRequiredFlagNotProvided (188-188)
  • ErrFailedToInitConfig (386-386)
pkg/config/config.go (1)
  • InitCliConfig (25-64)
internal/exec/describe_component.go (1)
  • ExecuteDescribeComponentParams (202-209)
pkg/provision/provision.go (1)
  • Provision (27-62)
pkg/flags/options.go (2)
  • WithStringFlag (37-48)
  • WithEnvVars (221-244)
pkg/provisioner/provisioner.go (3)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
pkg/hooks/event.go (1)
  • HookEvent (3-3)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/provisioner/backend/backend.go (4)
pkg/provisioner/provisioner.go (3)
  • RegisterProvisioner (46-53)
  • Provisioner (27-36)
  • HookEvent (14-14)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/provisioner/errors.go (3)
  • ErrBackendNotFound (9-9)
  • ErrBackendTypeRequired (10-10)
  • ErrNoProvisionerFound (11-11)
internal/exec/terraform.go (2)
pkg/provisioner/provisioner.go (2)
  • ExecuteProvisioners (75-96)
  • HookEvent (14-14)
pkg/schema/schema.go (1)
  • AuthContext (568-578)
pkg/provision/provision.go (4)
pkg/schema/schema.go (1)
  • AtmosConfiguration (53-94)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/provisioner/backend/backend.go (1)
  • ProvisionBackend (60-103)
pkg/ui/formatter.go (1)
  • Success (169-175)
🪛 LanguageTool
website/blog/2025-11-20-automatic-backend-provisioning.mdx

[style] ~25-~25: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ... provisions backends automatically when needed. Just enable it in your stack configura...

(EN_REPEATEDWORDS_NEED)


[style] ~106-~106: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...ment and testing workflows**, where you need backends quickly without manual setup. ...

(EN_REPEATEDWORDS_NEED)

website/docs/core-concepts/components/terraform/backends.mdx

[typographical] ~846-~846: In American English, use a period after an abbreviation.
Context: ...min" } ``` ### Development vs Production Development Workflow - ...

(MISSING_PERIOD_AFTER_ABBREVIATION)


[typographical] ~876-~876: Consider using a typographic opening quote here.
Context: ..."acme-terraform-state-prod" } resource "aws_s3_bucket" "terraform_state" { buc...

(EN_QUOTES)


[typographical] ~876-~876: Consider using a typographic close quote here.
Context: ...m-state-prod" } resource "aws_s3_bucket" "terraform_state" { bucket = "acme-te...

(EN_QUOTES)


[typographical] ~876-~876: Consider using a typographic opening quote here.
Context: ...state-prod" } resource "aws_s3_bucket" "terraform_state" { bucket = "acme-terr...

(EN_QUOTES)


[typographical] ~876-~876: Consider using a typographic close quote here.
Context: ...esource "aws_s3_bucket" "terraform_state" { bucket = "acme-terraform-state-prod...

(EN_QUOTES)


[typographical] ~881-~881: Consider using a typographic opening quote here.
Context: ...d production-specific features resource "aws_s3_bucket_lifecycle_configuration" "...

(EN_QUOTES)


[typographical] ~881-~881: Consider using a typographic close quote here.
Context: ...e "aws_s3_bucket_lifecycle_configuration" "terraform_state" { bucket = aws_s3_b...

(EN_QUOTES)


[typographical] ~881-~881: Consider using a typographic opening quote here.
Context: ..."aws_s3_bucket_lifecycle_configuration" "terraform_state" { bucket = aws_s3_buc...

(EN_QUOTES)


[typographical] ~881-~881: Consider using a typographic close quote here.
Context: ...ifecycle_configuration" "terraform_state" { bucket = aws_s3_bucket.terraform_st...

(EN_QUOTES)


[typographical] ~894-~894: Consider using a typographic opening quote here.
Context: ...current_days = 90 } } } resource "aws_s3_bucket_replication_configuration"...

(EN_QUOTES)


[typographical] ~894-~894: Consider using a typographic close quote here.
Context: ..."aws_s3_bucket_replication_configuration" "terraform_state" { bucket = aws_s3_b...

(EN_QUOTES)


[typographical] ~894-~894: Consider using a typographic opening quote here.
Context: ...ws_s3_bucket_replication_configuration" "terraform_state" { bucket = aws_s3_buc...

(EN_QUOTES)


[typographical] ~894-~894: Consider using a typographic close quote here.
Context: ...lication_configuration" "terraform_state" { bucket = aws_s3_bucket.terraform_st...

(EN_QUOTES)

docs/prd/provisioner-system.md

[style] ~14-~14: Since ownership is already implied, this phrasing may be redundant.
Context: ...Key Principle:** Each provisioner knows its own requirements and timing - the system pr...

(PRP_OWN)


[typographical] ~33-~33: Consider using a typographic opening quote here.
Context: ...Discoverability*: Hook system queries "what runs at this event?" ### First Imp...

(EN_QUOTES)


[typographical] ~33-~33: Consider using a typographic close quote here.
Context: ...system queries "what runs at this event?" ### First Implementation **Backend Pr...

(EN_QUOTES)


[style] ~411-~411: Since ownership is already implied, this phrasing may be redundant.
Context: ...ypothetical) - Each provisioner defines its own role assumption pattern --- ## Packag...

(PRP_OWN)


[grammar] ~752-~752: Please add a punctuation mark at the end of paragraph.
Context: ...igration** - How to migrate from manual provisioning --- ## Success Metrics ### Adoption ...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~954-~954: In American English, use a period after an abbreviation.
Context: ...omp --stack dev done ``` ### Automatic vs Manual Provisioning **Automatic (via h...

(MISSING_PERIOD_AFTER_ABBREVIATION)

🪛 markdownlint-cli2 (0.18.1)
docs/prd/provisioner-system.md

51-51: Hard tabs
Column: 1

(MD010, no-hard-tabs)


52-52: Hard tabs
Column: 1

(MD010, no-hard-tabs)


57-57: Hard tabs
Column: 1

(MD010, no-hard-tabs)


58-58: Hard tabs
Column: 1

(MD010, no-hard-tabs)


59-59: Hard tabs
Column: 1

(MD010, no-hard-tabs)


64-64: Hard tabs
Column: 1

(MD010, no-hard-tabs)


65-65: Hard tabs
Column: 1

(MD010, no-hard-tabs)


66-66: Hard tabs
Column: 1

(MD010, no-hard-tabs)


74-74: Hard tabs
Column: 1

(MD010, no-hard-tabs)


75-75: Hard tabs
Column: 1

(MD010, no-hard-tabs)


76-76: Hard tabs
Column: 1

(MD010, no-hard-tabs)


77-77: Hard tabs
Column: 1

(MD010, no-hard-tabs)


82-82: Hard tabs
Column: 1

(MD010, no-hard-tabs)


83-83: Hard tabs
Column: 1

(MD010, no-hard-tabs)


84-84: Hard tabs
Column: 1

(MD010, no-hard-tabs)


85-85: Hard tabs
Column: 1

(MD010, no-hard-tabs)


97-97: Hard tabs
Column: 1

(MD010, no-hard-tabs)


98-98: Hard tabs
Column: 1

(MD010, no-hard-tabs)


102-102: Hard tabs
Column: 1

(MD010, no-hard-tabs)


103-103: Hard tabs
Column: 1

(MD010, no-hard-tabs)


104-104: Hard tabs
Column: 1

(MD010, no-hard-tabs)


105-105: Hard tabs
Column: 1

(MD010, no-hard-tabs)


106-106: Hard tabs
Column: 1

(MD010, no-hard-tabs)


107-107: Hard tabs
Column: 1

(MD010, no-hard-tabs)


111-111: Hard tabs
Column: 1

(MD010, no-hard-tabs)


112-112: Hard tabs
Column: 1

(MD010, no-hard-tabs)


113-113: Hard tabs
Column: 1

(MD010, no-hard-tabs)


115-115: Hard tabs
Column: 1

(MD010, no-hard-tabs)


116-116: Hard tabs
Column: 1

(MD010, no-hard-tabs)


117-117: Hard tabs
Column: 1

(MD010, no-hard-tabs)


118-118: Hard tabs
Column: 1

(MD010, no-hard-tabs)


120-120: Hard tabs
Column: 1

(MD010, no-hard-tabs)


121-121: Hard tabs
Column: 1

(MD010, no-hard-tabs)


136-136: Hard tabs
Column: 1

(MD010, no-hard-tabs)


137-137: Hard tabs
Column: 1

(MD010, no-hard-tabs)


138-138: Hard tabs
Column: 1

(MD010, no-hard-tabs)


140-140: Hard tabs
Column: 1

(MD010, no-hard-tabs)


142-142: Hard tabs
Column: 1

(MD010, no-hard-tabs)


143-143: Hard tabs
Column: 1

(MD010, no-hard-tabs)


144-144: Hard tabs
Column: 1

(MD010, no-hard-tabs)


145-145: Hard tabs
Column: 1

(MD010, no-hard-tabs)


147-147: Hard tabs
Column: 1

(MD010, no-hard-tabs)


148-148: Hard tabs
Column: 1

(MD010, no-hard-tabs)


149-149: Hard tabs
Column: 1

(MD010, no-hard-tabs)


150-150: Hard tabs
Column: 1

(MD010, no-hard-tabs)


151-151: Hard tabs
Column: 1

(MD010, no-hard-tabs)


152-152: Hard tabs
Column: 1

(MD010, no-hard-tabs)


153-153: Hard tabs
Column: 1

(MD010, no-hard-tabs)


154-154: Hard tabs
Column: 1

(MD010, no-hard-tabs)


155-155: Hard tabs
Column: 1

(MD010, no-hard-tabs)


157-157: Hard tabs
Column: 1

(MD010, no-hard-tabs)


162-162: Hard tabs
Column: 1

(MD010, no-hard-tabs)


163-163: Hard tabs
Column: 1

(MD010, no-hard-tabs)


164-164: Hard tabs
Column: 1

(MD010, no-hard-tabs)


165-165: Hard tabs
Column: 1

(MD010, no-hard-tabs)


167-167: Hard tabs
Column: 1

(MD010, no-hard-tabs)


168-168: Hard tabs
Column: 1

(MD010, no-hard-tabs)


169-169: Hard tabs
Column: 1

(MD010, no-hard-tabs)


170-170: Hard tabs
Column: 1

(MD010, no-hard-tabs)


172-172: Hard tabs
Column: 1

(MD010, no-hard-tabs)


173-173: Hard tabs
Column: 1

(MD010, no-hard-tabs)


183-183: Hard tabs
Column: 1

(MD010, no-hard-tabs)


184-184: Hard tabs
Column: 1

(MD010, no-hard-tabs)


185-185: Hard tabs
Column: 1

(MD010, no-hard-tabs)


186-186: Hard tabs
Column: 1

(MD010, no-hard-tabs)


188-188: Hard tabs
Column: 1

(MD010, no-hard-tabs)


189-189: Hard tabs
Column: 1

(MD010, no-hard-tabs)


190-190: Hard tabs
Column: 1

(MD010, no-hard-tabs)


191-191: Hard tabs
Column: 1

(MD010, no-hard-tabs)


192-192: Hard tabs
Column: 1

(MD010, no-hard-tabs)


193-193: Hard tabs
Column: 1

(MD010, no-hard-tabs)


194-194: Hard tabs
Column: 1

(MD010, no-hard-tabs)


195-195: Hard tabs
Column: 1

(MD010, no-hard-tabs)


197-197: Hard tabs
Column: 1

(MD010, no-hard-tabs)


198-198: Hard tabs
Column: 1

(MD010, no-hard-tabs)


199-199: Hard tabs
Column: 1

(MD010, no-hard-tabs)


200-200: Hard tabs
Column: 1

(MD010, no-hard-tabs)


202-202: Hard tabs
Column: 1

(MD010, no-hard-tabs)


203-203: Hard tabs
Column: 1

(MD010, no-hard-tabs)


359-359: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


377-377: Hard tabs
Column: 1

(MD010, no-hard-tabs)


378-378: Hard tabs
Column: 1

(MD010, no-hard-tabs)


379-379: Hard tabs
Column: 1

(MD010, no-hard-tabs)


381-381: Hard tabs
Column: 1

(MD010, no-hard-tabs)


382-382: Hard tabs
Column: 1

(MD010, no-hard-tabs)


383-383: Hard tabs
Column: 1

(MD010, no-hard-tabs)


385-385: Hard tabs
Column: 1

(MD010, no-hard-tabs)


386-386: Hard tabs
Column: 1

(MD010, no-hard-tabs)


387-387: Hard tabs
Column: 1

(MD010, no-hard-tabs)


388-388: Hard tabs
Column: 1

(MD010, no-hard-tabs)


389-389: Hard tabs
Column: 1

(MD010, no-hard-tabs)


390-390: Hard tabs
Column: 1

(MD010, no-hard-tabs)


391-391: Hard tabs
Column: 1

(MD010, no-hard-tabs)


392-392: Hard tabs
Column: 1

(MD010, no-hard-tabs)


394-394: Hard tabs
Column: 1

(MD010, no-hard-tabs)


395-395: Hard tabs
Column: 1

(MD010, no-hard-tabs)


396-396: Hard tabs
Column: 1

(MD010, no-hard-tabs)


417-417: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


449-449: Hard tabs
Column: 1

(MD010, no-hard-tabs)


450-450: Hard tabs
Column: 1

(MD010, no-hard-tabs)


451-451: Hard tabs
Column: 1

(MD010, no-hard-tabs)


455-455: Hard tabs
Column: 1

(MD010, no-hard-tabs)


456-456: Hard tabs
Column: 1

(MD010, no-hard-tabs)


457-457: Hard tabs
Column: 1

(MD010, no-hard-tabs)


458-458: Hard tabs
Column: 1

(MD010, no-hard-tabs)


459-459: Hard tabs
Column: 1

(MD010, no-hard-tabs)


460-460: Hard tabs
Column: 1

(MD010, no-hard-tabs)


464-464: Hard tabs
Column: 1

(MD010, no-hard-tabs)


465-465: Hard tabs
Column: 1

(MD010, no-hard-tabs)


466-466: Hard tabs
Column: 1

(MD010, no-hard-tabs)


468-468: Hard tabs
Column: 1

(MD010, no-hard-tabs)


469-469: Hard tabs
Column: 1

(MD010, no-hard-tabs)


470-470: Hard tabs
Column: 1

(MD010, no-hard-tabs)


471-471: Hard tabs
Column: 1

(MD010, no-hard-tabs)


473-473: Hard tabs
Column: 1

(MD010, no-hard-tabs)


474-474: Hard tabs
Column: 1

(MD010, no-hard-tabs)


476-476: Hard tabs
Column: 1

(MD010, no-hard-tabs)


477-477: Hard tabs
Column: 1

(MD010, no-hard-tabs)


481-481: Hard tabs
Column: 1

(MD010, no-hard-tabs)


482-482: Hard tabs
Column: 1

(MD010, no-hard-tabs)


483-483: Hard tabs
Column: 1

(MD010, no-hard-tabs)


484-484: Hard tabs
Column: 1

(MD010, no-hard-tabs)


486-486: Hard tabs
Column: 1

(MD010, no-hard-tabs)


487-487: Hard tabs
Column: 1

(MD010, no-hard-tabs)


488-488: Hard tabs
Column: 1

(MD010, no-hard-tabs)


489-489: Hard tabs
Column: 1

(MD010, no-hard-tabs)


491-491: Hard tabs
Column: 1

(MD010, no-hard-tabs)


492-492: Hard tabs
Column: 1

(MD010, no-hard-tabs)


502-502: Hard tabs
Column: 1

(MD010, no-hard-tabs)


503-503: Hard tabs
Column: 1

(MD010, no-hard-tabs)


528-528: Hard tabs
Column: 1

(MD010, no-hard-tabs)


529-529: Hard tabs
Column: 1

(MD010, no-hard-tabs)


530-530: Hard tabs
Column: 1

(MD010, no-hard-tabs)


531-531: Hard tabs
Column: 1

(MD010, no-hard-tabs)


539-539: Hard tabs
Column: 1

(MD010, no-hard-tabs)


540-540: Hard tabs
Column: 1

(MD010, no-hard-tabs)


541-541: Hard tabs
Column: 1

(MD010, no-hard-tabs)


542-542: Hard tabs
Column: 1

(MD010, no-hard-tabs)


543-543: Hard tabs
Column: 1

(MD010, no-hard-tabs)


575-575: Hard tabs
Column: 1

(MD010, no-hard-tabs)


576-576: Hard tabs
Column: 1

(MD010, no-hard-tabs)


577-577: Hard tabs
Column: 1

(MD010, no-hard-tabs)


578-578: Hard tabs
Column: 1

(MD010, no-hard-tabs)


579-579: Hard tabs
Column: 1

(MD010, no-hard-tabs)


580-580: Hard tabs
Column: 1

(MD010, no-hard-tabs)


581-581: Hard tabs
Column: 1

(MD010, no-hard-tabs)


582-582: Hard tabs
Column: 1

(MD010, no-hard-tabs)


583-583: Hard tabs
Column: 1

(MD010, no-hard-tabs)


585-585: Hard tabs
Column: 1

(MD010, no-hard-tabs)


586-586: Hard tabs
Column: 1

(MD010, no-hard-tabs)


587-587: Hard tabs
Column: 1

(MD010, no-hard-tabs)


588-588: Hard tabs
Column: 1

(MD010, no-hard-tabs)


589-589: Hard tabs
Column: 1

(MD010, no-hard-tabs)


590-590: Hard tabs
Column: 1

(MD010, no-hard-tabs)


592-592: Hard tabs
Column: 1

(MD010, no-hard-tabs)


617-617: Hard tabs
Column: 1

(MD010, no-hard-tabs)


618-618: Hard tabs
Column: 1

(MD010, no-hard-tabs)


619-619: Hard tabs
Column: 1

(MD010, no-hard-tabs)


620-620: Hard tabs
Column: 1

(MD010, no-hard-tabs)


621-621: Hard tabs
Column: 1

(MD010, no-hard-tabs)


663-663: Hard tabs
Column: 1

(MD010, no-hard-tabs)


664-664: Hard tabs
Column: 1

(MD010, no-hard-tabs)


665-665: Hard tabs
Column: 1

(MD010, no-hard-tabs)


667-667: Hard tabs
Column: 1

(MD010, no-hard-tabs)


668-668: Hard tabs
Column: 1

(MD010, no-hard-tabs)


669-669: Hard tabs
Column: 1

(MD010, no-hard-tabs)


683-683: Hard tabs
Column: 1

(MD010, no-hard-tabs)


684-684: Hard tabs
Column: 1

(MD010, no-hard-tabs)


685-685: Hard tabs
Column: 1

(MD010, no-hard-tabs)


686-686: Hard tabs
Column: 1

(MD010, no-hard-tabs)


688-688: Hard tabs
Column: 1

(MD010, no-hard-tabs)


689-689: Hard tabs
Column: 1

(MD010, no-hard-tabs)


690-690: Hard tabs
Column: 1

(MD010, no-hard-tabs)


691-691: Hard tabs
Column: 1

(MD010, no-hard-tabs)


693-693: Hard tabs
Column: 1

(MD010, no-hard-tabs)


706-706: Hard tabs
Column: 1

(MD010, no-hard-tabs)


707-707: Hard tabs
Column: 1

(MD010, no-hard-tabs)


708-708: Hard tabs
Column: 1

(MD010, no-hard-tabs)


713-713: Hard tabs
Column: 1

(MD010, no-hard-tabs)


714-714: Hard tabs
Column: 1

(MD010, no-hard-tabs)


715-715: Hard tabs
Column: 1

(MD010, no-hard-tabs)


716-716: Hard tabs
Column: 1

(MD010, no-hard-tabs)


717-717: Hard tabs
Column: 1

(MD010, no-hard-tabs)


718-718: Hard tabs
Column: 1

(MD010, no-hard-tabs)


804-804: Hard tabs
Column: 1

(MD010, no-hard-tabs)


805-805: Hard tabs
Column: 1

(MD010, no-hard-tabs)


811-811: Hard tabs
Column: 1

(MD010, no-hard-tabs)


815-815: Hard tabs
Column: 1

(MD010, no-hard-tabs)


819-819: Hard tabs
Column: 1

(MD010, no-hard-tabs)


820-820: Hard tabs
Column: 1

(MD010, no-hard-tabs)


821-821: Hard tabs
Column: 1

(MD010, no-hard-tabs)


838-838: Hard tabs
Column: 1

(MD010, no-hard-tabs)


839-839: Hard tabs
Column: 1

(MD010, no-hard-tabs)


840-840: Hard tabs
Column: 1

(MD010, no-hard-tabs)


841-841: Hard tabs
Column: 1

(MD010, no-hard-tabs)


842-842: Hard tabs
Column: 1

(MD010, no-hard-tabs)


844-844: Hard tabs
Column: 1

(MD010, no-hard-tabs)


845-845: Hard tabs
Column: 1

(MD010, no-hard-tabs)


849-849: Hard tabs
Column: 1

(MD010, no-hard-tabs)


850-850: Hard tabs
Column: 1

(MD010, no-hard-tabs)


852-852: Hard tabs
Column: 1

(MD010, no-hard-tabs)


853-853: Hard tabs
Column: 1

(MD010, no-hard-tabs)


867-867: Hard tabs
Column: 1

(MD010, no-hard-tabs)


869-869: Hard tabs
Column: 1

(MD010, no-hard-tabs)


870-870: Hard tabs
Column: 1

(MD010, no-hard-tabs)


871-871: Hard tabs
Column: 1

(MD010, no-hard-tabs)


876-876: Hard tabs
Column: 1

(MD010, no-hard-tabs)


877-877: Hard tabs
Column: 1

(MD010, no-hard-tabs)


878-878: Hard tabs
Column: 1

(MD010, no-hard-tabs)


879-879: Hard tabs
Column: 1

(MD010, no-hard-tabs)


880-880: Hard tabs
Column: 1

(MD010, no-hard-tabs)


882-882: Hard tabs
Column: 1

(MD010, no-hard-tabs)


883-883: Hard tabs
Column: 1

(MD010, no-hard-tabs)


884-884: Hard tabs
Column: 1

(MD010, no-hard-tabs)


885-885: Hard tabs
Column: 1

(MD010, no-hard-tabs)


887-887: Hard tabs
Column: 1

(MD010, no-hard-tabs)


888-888: Hard tabs
Column: 1

(MD010, no-hard-tabs)


889-889: Hard tabs
Column: 1

(MD010, no-hard-tabs)


891-891: Hard tabs
Column: 1

(MD010, no-hard-tabs)


892-892: Hard tabs
Column: 1

(MD010, no-hard-tabs)


893-893: Hard tabs
Column: 1

(MD010, no-hard-tabs)


894-894: Hard tabs
Column: 1

(MD010, no-hard-tabs)


895-895: Hard tabs
Column: 1

(MD010, no-hard-tabs)


896-896: Hard tabs
Column: 1

(MD010, no-hard-tabs)


898-898: Hard tabs
Column: 1

(MD010, no-hard-tabs)


899-899: Hard tabs
Column: 1

(MD010, no-hard-tabs)


900-900: Hard tabs
Column: 1

(MD010, no-hard-tabs)


902-902: Hard tabs
Column: 1

(MD010, no-hard-tabs)


903-903: Hard tabs
Column: 1

(MD010, no-hard-tabs)


904-904: Hard tabs
Column: 1

(MD010, no-hard-tabs)


906-906: Hard tabs
Column: 1

(MD010, no-hard-tabs)


907-907: Hard tabs
Column: 1

(MD010, no-hard-tabs)


908-908: Hard tabs
Column: 1

(MD010, no-hard-tabs)


909-909: Hard tabs
Column: 1

(MD010, no-hard-tabs)


910-910: Hard tabs
Column: 1

(MD010, no-hard-tabs)


911-911: Hard tabs
Column: 1

(MD010, no-hard-tabs)


912-912: Hard tabs
Column: 1

(MD010, no-hard-tabs)


913-913: Hard tabs
Column: 1

(MD010, no-hard-tabs)


915-915: Hard tabs
Column: 1

(MD010, no-hard-tabs)


916-916: Hard tabs
Column: 1

(MD010, no-hard-tabs)


996-996: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1017-1017: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1018-1018: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1019-1019: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1021-1021: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1023-1023: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1024-1024: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1025-1025: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1027-1027: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1028-1028: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1029-1029: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1030-1030: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1031-1031: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1032-1032: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1033-1033: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1034-1034: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1035-1035: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1036-1036: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1037-1037: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1039-1039: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1040-1040: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1041-1041: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1043-1043: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1052-1052: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1053-1053: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1060-1060: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1061-1061: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1062-1062: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1063-1063: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1064-1064: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1065-1065: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1072-1072: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1073-1073: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1074-1074: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1075-1075: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1076-1076: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1077-1077: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1078-1078: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1098-1098: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1099-1099: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1100-1100: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1101-1101: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1103-1103: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1104-1104: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1105-1105: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1106-1106: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1107-1107: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1108-1108: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1109-1109: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1110-1110: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1111-1111: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1112-1112: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1114-1114: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1115-1115: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1116-1116: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1117-1117: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1119-1119: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1120-1120: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1138-1138: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1168-1168: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1169-1169: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1170-1170: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1174-1174: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1175-1175: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1176-1176: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1177-1177: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1178-1178: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1182-1182: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1183-1183: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1184-1184: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1186-1186: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1187-1187: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1188-1188: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1189-1189: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1190-1190: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1192-1192: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1193-1193: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1194-1194: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1195-1195: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1197-1197: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1198-1198: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1199-1199: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1200-1200: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1202-1202: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1203-1203: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1205-1205: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1206-1206: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1207-1207: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1208-1208: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1209-1209: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1211-1211: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1212-1212: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1213-1213: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1214-1214: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1216-1216: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1217-1217: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1218-1218: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1219-1219: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1220-1220: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1222-1222: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1223-1223: Hard tabs
Column: 1

(MD010, no-hard-tabs)


1247-1247: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

⏰ 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). (3)
  • GitHub Check: Acceptance Tests (linux)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Summary
🔇 Additional comments (11)
pkg/hooks/event.go (1)

5-11: New BeforeTerraformInit hook constant looks good

Defining BeforeTerraformInit here keeps the event name centralized and consistent with other hook events. It lines up with the provisioner design that runs before terraform init.

cmd/root.go (1)

44-53: Provision command registration via blank import is consistent

Importing cmd/provision for side effects matches the existing pattern for built-in commands (about, list, profile, theme, version). This is the right minimal change to surface atmos provision without further plumbing.

website/docs/cli/commands/provision/backend.mdx (1)

210-216: Review comment is incorrect—documentation already matches implementation

The doc lists tags as Name and ManagedBy=Atmos, which directly matches the implementation in pkg/provisioner/backend/s3.go (lines 261–266). The code applies exactly those two tags:

  • Key: "Name" → bucket name
  • Key: "ManagedBy""Atmos"

The review claims the implementation has CreatedAt and Purpose tags, but these don't exist in the S3 provisioner code. Additionally, the reference to lines 499-507 is invalid (the file has 419 lines).

No changes needed.

Likely an incorrect or invalid review comment.

pkg/provisioner/backend/s3.go (1)

48-85: Provision flow and error wrapping look solid

Config extraction, AWS config loading (with optional assume role), and the overall provision flow are clean and consistent with the existing error-sentinel pattern (ErrLoadAWSConfig, ErrApplyBucketDefaults, etc.). Idempotent re-runs on the same bucket look correctly supported.

pkg/provisioner/provisioner.go (1)

38-96: Provisioner registry and execution model look good

The registry is concurrency-safe, GetProvisionersForEvent returns a defensive copy, and ExecuteProvisioners’s fail-fast behavior with a typed error ("provisioner %s failed: %w") is a nice, predictable contract for callers. This is a solid foundation for hook-based provisioning.

pkg/provisioner/backend/backend.go (5)

23-29: Clean function signature.

The BackendProvisionerFunc type is well-defined with clear parameters and a straightforward error return. Good choice passing backendConfig as map[string]any for flexibility across different backend types.


31-35: Thread-safe registry implementation looks good.

Using sync.RWMutex is appropriate here since the registry will be read-heavy (many lookups, few registrations). The initialization and documentation are clear.


37-45: Proper locking and registration.

The function correctly uses write lock for map mutation and properly defers the unlock. The perf tracking is consistent with the codebase pattern.


47-56: Correct read lock usage.

The function appropriately uses RLock for read-only access and returns nil for missing provisioners, which the caller handles gracefully.


58-103: Well-structured orchestration with proper error handling.

The function correctly:

  • Returns early when provisioning is disabled (avoiding unnecessary work)
  • Uses safe type assertions with ok checks
  • Wraps errors with %w for proper error chain support
  • Delegates to the appropriate backend provisioner

The nested map traversal pattern is safe and handles all edge cases appropriately.

pkg/provisioner/errors.go (1)

5-21: Well-defined sentinel errors.

The error variables follow Go best practices:

  • Standard errors.New() pattern for sentinel errors (compatible with errors.Is())
  • Consistent Err prefix naming convention
  • Clear, specific error messages

These errors align well with the backend provisioning operations described in the PR.

This commit addresses all major CodeRabbit review comments:

## Critical Fixes

- **Add AuthContext support**: Provision commands now support `--identity` flag
  for Atmos-managed authentication (SSO). Credentials are written to files
  and picked up by AWS SDK credential chain.

- **Improve S3 error handling**: Enhanced error messages with actionable hints
  using Atmos error builder pattern. Distinguish between 403 (permissions),
  404 (not found), and network errors with specific guidance.

- **Add S3 defaults warnings**: Warn users when modifying pre-existing buckets
  that settings (encryption, tags) will be overwritten with opinionated defaults.

- **Fix CLI help text**: Changed from `provision <type>` to `provision backend`
  to only advertise supported provisioner types. Updated descriptions.

- **Fix YAML examples**: Corrected `backend_type` placement in blog post and
  CLI docs - must be at component level, not nested in backend block.

## Code Quality Improvements

- **Use consistent hook constants**: Added local constants with documentation
  linking to canonical definitions in pkg/hooks/event.go (avoiding import cycles).

- **Add new error type**: `ErrS3BucketAccessDenied` for permission-denied scenarios.

- **Refactor Provision function**: Added ProvisionParams struct and ProvisionWithParams
  to comply with argument-limit linting rule while maintaining backward compatibility.

## Files Changed

- cmd/provision/provision.go: Add identity flag and auth integration
- pkg/provision/provision.go: Thread authManager, add params struct
- pkg/provisioner/backend/s3.go: Enhanced error handling and warnings
- pkg/provisioner/backend/backend.go: Document hook event constant
- internal/exec/terraform.go: Add hook constant documentation
- errors/errors.go: Add ErrS3BucketAccessDenied
- website/blog/2025-11-20-automatic-backend-provisioning.mdx: Fix YAML examples
- website/docs/cli/commands/provision/backend.mdx: Fix YAML examples

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

Co-Authored-By: Claude <[email protected]>
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: 1

🧹 Nitpick comments (2)
pkg/provisioner/backend/s3.go (1)

127-147: Consider preserving ErrS3BucketAccessDenied when wrapping errors in ensureBucket

The concern is valid. bucketExists intentionally classifies errors—returning ErrS3BucketAccessDenied with rich hints at lines 184–189 and 200–207—but ensureBucket re-wraps all errors with ErrCheckBucketExist at line 132, losing that semantic distinction.

Although no current callers check for the sentinel, the error classification at the lower layer represents intentional design. Preserving it via a conditional check:

 func ensureBucket(ctx context.Context, client *s3.Client, bucket, region string) (bool, error) {
     exists, err := bucketExists(ctx, client, bucket)
     if err != nil {
+        // Preserve access-denied classification for callers.
+        if errors.Is(err, errUtils.ErrS3BucketAccessDenied) {
+            return false, err
+        }
         return false, fmt.Errorf(errFormat, provisioner.ErrCheckBucketExist, err)
     }

…keeps error type info available for future handling. Note: createBucket (line 142) doesn't return specialized errors, so that wrapping remains appropriate.

cmd/provision/provision.go (1)

58-60: Redundant argument validation.

The manual len(args) != 2 check is redundant since Args: cobra.ExactArgs(2) on line 52 already enforces this. Cobra will prevent RunE from executing if the argument count is incorrect.

Apply this diff to remove the redundant check:

 	RunE: func(cmd *cobra.Command, args []string) error {
 		defer perf.Track(atmosConfigPtr, "provision.RunE")()
 
-		if len(args) != 2 {
-			return errUtils.ErrInvalidArguments
-		}
-
 		provisionerType := args[0]
 		component := args[1]
📜 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 e972b3e and ead68a1.

📒 Files selected for processing (8)
  • cmd/provision/provision.go (1 hunks)
  • errors/errors.go (1 hunks)
  • internal/exec/terraform.go (4 hunks)
  • pkg/provision/provision.go (1 hunks)
  • pkg/provisioner/backend/backend.go (1 hunks)
  • pkg/provisioner/backend/s3.go (1 hunks)
  • website/blog/2025-11-20-automatic-backend-provisioning.mdx (1 hunks)
  • website/docs/cli/commands/provision/backend.mdx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/exec/terraform.go
  • pkg/provisioner/backend/backend.go
🧰 Additional context used
🧠 Learnings (16)
📓 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.
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.

Applied to files:

  • website/docs/cli/commands/provision/backend.mdx
📚 Learning: 2025-01-19T15:49:15.593Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 955
File: tests/snapshots/TestCLICommands_atmos_validate_editorconfig_--help.stdout.golden:0-0
Timestamp: 2025-01-19T15:49:15.593Z
Learning: In future commits, the help text for Atmos CLI commands should be limited to only show component and stack parameters for commands that actually use them. This applies to the example usage section in command help text.

Applied to files:

  • website/docs/cli/commands/provision/backend.mdx
  • cmd/provision/provision.go
📚 Learning: 2024-12-03T05:29:07.718Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: internal/exec/terraform_utils.go:145-146
Timestamp: 2024-12-03T05:29:07.718Z
Learning: In the Atmos project, a 5-minute timeout in the `execTerraformOutput` function is acceptable for retrieving `terraform output` for a component in a stack.

Applied to files:

  • website/docs/cli/commands/provision/backend.mdx
📚 Learning: 2025-01-25T03:51:57.689Z
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.

Applied to files:

  • website/blog/2025-11-20-automatic-backend-provisioning.mdx
📚 Learning: 2025-10-27T01:54:35.665Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1714
File: website/blog/2025-10-26-zero-config-terminal-output.md:6-6
Timestamp: 2025-10-27T01:54:35.665Z
Learning: In the Atmos blog (website/blog/), blog post authors in frontmatter should always be set to the actual committer or PR opener (e.g., "osterman"), not generic organization names like "cloudposse" or "atmos". Authors must exist in website/blog/authors.yml.

Applied to files:

  • website/blog/2025-11-20-automatic-backend-provisioning.mdx
📚 Learning: 2025-03-18T12:26:25.329Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 1149
File: tests/snapshots/TestCLICommands_atmos_vendor_pull_ssh.stderr.golden:7-7
Timestamp: 2025-03-18T12:26:25.329Z
Learning: In the Atmos project, typos or inconsistencies in test snapshot files (such as "terrafrom" instead of "terraform") may be intentional as they capture the exact output of commands and should not be flagged as issues requiring correction.

Applied to files:

  • website/blog/2025-11-20-automatic-backend-provisioning.mdx
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.

Applied to files:

  • cmd/provision/provision.go
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.

Applied to files:

  • cmd/provision/provision.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:

  • cmd/provision/provision.go
📚 Learning: 2025-10-07T00:25:16.333Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1498
File: website/src/components/Screengrabs/atmos-terraform-metadata--help.html:25-55
Timestamp: 2025-10-07T00:25:16.333Z
Learning: In Atmos CLI, subcommands inherit flags from their parent commands via Cobra's command inheritance. For example, `atmos terraform metadata --help` shows `--affected` and related flags inherited from the parent `terraform` command (defined in cmd/terraform.go), even though the metadata subcommand doesn't explicitly define these flags. This is expected Cobra behavior and auto-generated help screengrabs accurately reflect this inheritance.

Applied to files:

  • cmd/provision/provision.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:

  • cmd/provision/provision.go
📚 Learning: 2025-11-10T03:03:31.505Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-11-10T03:03:31.505Z
Learning: In the Atmos codebase, commands using the `StandardParser` flag pattern (from pkg/flags) do NOT need explicit `viper.BindPFlag()` calls in their code. The StandardParser encapsulates flag binding internally: flags are registered via `parser.RegisterFlags(cmd)` in init(), and bound via `parser.BindFlagsToViper(cmd, v)` in RunE, which internally calls viper.BindPFlag for each flag. This pattern is used throughout Atmos (e.g., cmd/toolchain/get.go, cmd/toolchain/info.go, cmd/toolchain/install.go, cmd/toolchain/path.go). Do not flag missing viper.BindPFlag calls when StandardParser is used.

Applied to files:

  • cmd/provision/provision.go
📚 Learning: 2025-09-05T14:57:37.360Z
Learnt from: RoseSecurity
Repo: cloudposse/atmos PR: 1448
File: cmd/ansible.go:26-28
Timestamp: 2025-09-05T14:57:37.360Z
Learning: The Atmos codebase uses a consistent pattern for commands that delegate to external tools: `PersistentFlags().Bool("", false, doubleDashHint)` where doubleDashHint provides help text about using double dashes to separate Atmos options from native command arguments. This pattern is used across terraform, packer, helmfile, atlantis, aws, and ansible commands.

Applied to files:

  • cmd/provision/provision.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.

Applied to files:

  • cmd/provision/provision.go
📚 Learning: 2025-01-07T20:38:09.618Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 896
File: cmd/editor_config.go:37-40
Timestamp: 2025-01-07T20:38:09.618Z
Learning: Error handling suggestion for `cmd.Help()` in `cmd/editor_config.go` was deferred as the code is planned for future modifications.

Applied to files:

  • cmd/provision/provision.go
🧬 Code graph analysis (3)
pkg/provisioner/backend/s3.go (7)
pkg/provisioner/backend/backend.go (1)
  • RegisterBackendProvisioner (45-52)
pkg/schema/schema.go (2)
  • AuthContext (568-578)
  • AWSAuthContext (582-597)
errors/builder.go (1)
  • Build (21-23)
pkg/provisioner/errors.go (10)
  • ErrLoadAWSConfig (13-13)
  • ErrApplyBucketDefaults (16-16)
  • ErrBucketRequired (7-7)
  • ErrRegionRequired (8-8)
  • ErrCheckBucketExist (14-14)
  • ErrCreateBucket (15-15)
  • ErrEnableVersioning (17-17)
  • ErrEnableEncryption (18-18)
  • ErrBlockPublicAccess (19-19)
  • ErrApplyTags (20-20)
pkg/ui/formatter.go (2)
  • Success (169-175)
  • Warning (213-219)
internal/aws_utils/aws_utils.go (1)
  • LoadAWSConfigWithAuth (53-119)
errors/errors.go (1)
  • ErrS3BucketAccessDenied (91-91)
cmd/provision/provision.go (8)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • ConfigAndStacksInfo (620-714)
pkg/flags/standard_parser.go (2)
  • StandardParser (18-22)
  • NewStandardParser (34-40)
errors/errors.go (3)
  • ErrInvalidArguments (191-191)
  • ErrRequiredFlagNotProvided (189-189)
  • ErrFailedToInitConfig (387-387)
pkg/config/config.go (1)
  • InitCliConfig (25-64)
pkg/auth/manager_helpers.go (1)
  • CreateAndAuthenticateManager (180-222)
internal/exec/describe_component.go (1)
  • ExecuteDescribeComponentParams (202-209)
pkg/provision/provision.go (1)
  • Provision (41-58)
pkg/flags/options.go (2)
  • WithStringFlag (37-48)
  • WithEnvVars (221-244)
pkg/provision/provision.go (4)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/provisioner/backend/backend.go (1)
  • ProvisionBackend (67-110)
pkg/ui/formatter.go (1)
  • Success (169-175)
🪛 LanguageTool
website/blog/2025-11-20-automatic-backend-provisioning.mdx

[style] ~25-~25: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ... provisions backends automatically when needed. Just enable it in your stack configura...

(EN_REPEATEDWORDS_NEED)


[style] ~107-~107: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...ment and testing workflows**, where you need backends quickly without manual setup. ...

(EN_REPEATEDWORDS_NEED)

⏰ 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). (3)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Acceptance Tests (linux)
  • GitHub Check: Summary
🔇 Additional comments (11)
errors/errors.go (1)

91-91: New S3 access-denied sentinel looks consistent

ErrS3BucketAccessDenied matches existing naming and usage patterns and is ready to wire into S3-related flows.

website/blog/2025-11-20-automatic-backend-provisioning.mdx (1)

25-41: Blog examples now match the actual backend schema

The YAML snippets correctly keep backend_type: s3 at the component level (sibling of backend and provision), and the cross-account/“Getting Started” examples align with the S3 provisioner’s config shape. Frontmatter author also matches the PR opener.

Looks good as a user-facing overview of the new flow.

Also applies to: 139-152, 191-206

pkg/provisioner/backend/s3.go (1)

26-27: Review comment is incorrect—multiple %w verbs are valid and explicitly supported

Go 1.20+ supports multiple %w verbs in fmt.Errorf, which return errors implementing Unwrap() []error. The codebase's .golangci.yml confirms this: "supports multiple %w verbs per fmt.Errorf call (requires Go 1.20+)". The current format "%w: %w" is correct and will not panic. Changing it to "%w: %v" would actually lose error chain semantics needed for errors.Is/As.

The code is correct as written and requires no changes.

Likely an incorrect or invalid review comment.

website/docs/cli/commands/provision/backend.mdx (1)

80-86: Verify Issue #1 accuracy; Issue #2 appears potentially incorrect

Issue #1 is solid: the docs list backend types (s3, gcs, azurerm) but only the S3 provisioner is registered in code—no GCS or Azure implementations exist.

Issue #2 needs clarification: the backend provisioner code directly accesses componentConfig["provision"], componentConfig["backend"], and componentConfig["backend_type"] as top-level keys. This suggests root-level provision: in stack config is actually what the code expects, contradicting the review's claim that it should be nested under terraform:.

Before updating the docs, confirm with the team:

  • Whether stack config uses root-level provision: or terraform: provision: (or if both merge down to top-level during processing)
  • Which pattern the existing docs should show as canonical

Fix confirmed: Update line 83 to reflect S3-only support (mark GCS/Azure as planned or remove them).

cmd/provision/provision.go (7)

1-19: Clean package structure.

Imports are well-organized and all appear necessary for the command implementation.


21-26: LGTM.

Package-level variables follow the Atmos command pattern for config and flag parser management.


28-39: Well-structured options and config setup.

The ProvisionOptions struct cleanly embeds global flags, and SetAtmosConfig provides the integration point for config injection from root.go.


41-51: Help text correctly scoped to supported provisioners.

The command documentation now only advertises the backend provisioner type, which matches the implementation. This addresses previous feedback about advertising unsupported types.


82-114: Solid integration with Atmos internals.

The config loading, auth manager setup, and provision orchestration follow established Atmos patterns. The describeComponent callback appropriately disables template and function processing for the provisioning workflow.


149-171: Clean CommandProvider implementation.

The provider correctly implements the interface with appropriate return values. Grouping under "Core Stack Commands" makes sense for this infrastructure provisioning command.


117-147: The dual binding pattern is correct and standard across Atmos.

The concern about BindToViper in init() being redundant is incorrect. Verification shows that all StandardParser commands consistently use this dual-binding approach:

  • BindToViper() in init() for early environment variable support
  • BindFlagsToViper() in RunE() for flag and precedence handling at execution time

This pattern is used identically in cmd/list/components.go, cmd/list/stacks.go, and other commands.

One minor observation: Line 118's explicit DisableFlagParsing = false sets the default value and isn't necessary (other commands omit it). This is harmless but optional to remove.

Add unit tests for the automatic backend provisioning feature:

- pkg/provision/provision_test.go: Tests for nil parameter validation
  (CodeRabbit critical fix), provisioner type validation, and backend
  provisioning success/failure scenarios

- pkg/provisioner/provisioner_test.go: Tests for provisioner registry,
  concurrent registration, fail-fast behavior, and context cancellation

- pkg/provisioner/backend/backend_test.go: Tests for backend provisioner
  registry, enable/disable scenarios, missing configuration handling,
  and multi-backend support

- pkg/provisioner/backend/s3_test.go: Tests for S3 config extraction,
  bucket name validation, and region handling

- cmd/provision/provision_test.go: Tests for CommandProvider interface,
  flag parsing, environment variable support, and help text

Test coverage:
- pkg/provision: 95.5%
- pkg/provisioner: 100%
- pkg/provisioner/backend: 34.7% (AWS SDK operations require integration tests)
- cmd/provision: 36.1% (RunE requires full config initialization)

Also adds nil parameter validation to ProvisionWithParams using static
errors (ErrNilParam) to prevent panics when called with nil params.
This addresses the CodeRabbit review feedback.

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

Co-Authored-By: Claude <[email protected]>
coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 21, 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)
pkg/provisioner/backend/backend_test.go (1)

340-341: Inconsistent variable naming.

The variable gcsCALLED uses uppercase, while similar variables elsewhere use camelCase (e.g., s3Called on line 340, provisioner1Called, provisioner2Called in other tests).

Apply this diff for consistency:

-	gcsCALLED := false
+	gcsCalled := false

And update the references on lines 349, 373, 377, 395:

-		gcsCALLED = true
+		gcsCalled = true
-	assert.False(t, gcsCALLED, "GCS provisioner should not have been called")
+	assert.False(t, gcsCalled, "GCS provisioner should not have been called")
-	gcsCALLED = false
+	gcsCalled = false
-	assert.True(t, gcsCALLED, "GCS provisioner should have been called")
+	assert.True(t, gcsCalled, "GCS provisioner should have been called")
📜 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 ead68a1 and 70f808f.

📒 Files selected for processing (6)
  • cmd/provision/provision_test.go (1 hunks)
  • pkg/provision/provision.go (1 hunks)
  • pkg/provision/provision_test.go (1 hunks)
  • pkg/provisioner/backend/backend_test.go (1 hunks)
  • pkg/provisioner/backend/s3_test.go (1 hunks)
  • pkg/provisioner/provisioner_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (12)
📓 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.
📚 Learning: 2025-11-10T23:23:39.771Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/registry/aqua/aqua_test.go:417-442
Timestamp: 2025-11-10T23:23:39.771Z
Learning: In Atmos toolchain AquaRegistry, tests should not hit real GitHub. Use the options pattern via WithGitHubBaseURL to inject an httptest server URL and make GetLatestVersion/GetAvailableVersions deterministic.

Applied to files:

  • pkg/provisioner/backend/s3_test.go
  • pkg/provisioner/provisioner_test.go
  • pkg/provisioner/backend/backend_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:

  • pkg/provisioner/backend/s3_test.go
  • pkg/provisioner/backend/backend_test.go
  • cmd/provision/provision_test.go
📚 Learning: 2025-11-11T03:47:45.878Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.

Applied to files:

  • pkg/provisioner/backend/backend_test.go
  • cmd/provision/provision_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:

  • pkg/provision/provision.go
📚 Learning: 2024-12-02T21:26:32.337Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.

Applied to files:

  • pkg/provision/provision.go
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.

Applied to files:

  • cmd/provision/provision_test.go
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.

Applied to files:

  • cmd/provision/provision_test.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:

  • cmd/provision/provision_test.go
📚 Learning: 2025-01-09T22:37:01.004Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 914
File: cmd/terraform_commands.go:260-265
Timestamp: 2025-01-09T22:37:01.004Z
Learning: In the terraform commands implementation (cmd/terraform_commands.go), the direct use of `os.Args[2:]` for argument handling is intentionally preserved to avoid extensive refactoring. While it could be improved to use cobra's argument parsing, such changes should be handled in a dedicated PR to maintain focus and minimize risk.

Applied to files:

  • cmd/provision/provision_test.go
📚 Learning: 2025-11-10T03:03:31.505Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-11-10T03:03:31.505Z
Learning: In the Atmos codebase, commands using the `StandardParser` flag pattern (from pkg/flags) do NOT need explicit `viper.BindPFlag()` calls in their code. The StandardParser encapsulates flag binding internally: flags are registered via `parser.RegisterFlags(cmd)` in init(), and bound via `parser.BindFlagsToViper(cmd, v)` in RunE, which internally calls viper.BindPFlag for each flag. This pattern is used throughout Atmos (e.g., cmd/toolchain/get.go, cmd/toolchain/info.go, cmd/toolchain/install.go, cmd/toolchain/path.go). Do not flag missing viper.BindPFlag calls when StandardParser is used.

Applied to files:

  • cmd/provision/provision_test.go
📚 Learning: 2025-01-30T19:30:59.120Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 959
File: cmd/workflow.go:74-74
Timestamp: 2025-01-30T19:30:59.120Z
Learning: Error handling for `cmd.Usage()` is not required in the Atmos CLI codebase, as confirmed by the maintainer.

Applied to files:

  • cmd/provision/provision_test.go
🧬 Code graph analysis (6)
pkg/provisioner/backend/s3_test.go (2)
pkg/provisioner/errors.go (1)
  • ErrBucketRequired (7-7)
pkg/provisioner/backend/backend.go (1)
  • GetBackendProvisioner (56-63)
pkg/provisioner/provisioner_test.go (2)
pkg/provisioner/provisioner.go (4)
  • Provisioner (27-36)
  • RegisterProvisioner (46-53)
  • GetProvisionersForEvent (56-71)
  • ExecuteProvisioners (75-96)
pkg/schema/schema.go (3)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
  • AWSAuthContext (582-597)
pkg/provisioner/backend/backend_test.go (3)
pkg/provisioner/backend/backend.go (4)
  • BackendProvisionerFunc (31-36)
  • RegisterBackendProvisioner (45-52)
  • GetBackendProvisioner (56-63)
  • ProvisionBackend (67-110)
pkg/schema/schema.go (3)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
  • AWSAuthContext (582-597)
pkg/provisioner/errors.go (3)
  • ErrBackendNotFound (9-9)
  • ErrBackendTypeRequired (10-10)
  • ErrNoProvisionerFound (11-11)
pkg/provision/provision.go (5)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
errors/errors.go (1)
  • ErrNilParam (499-499)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/provisioner/backend/backend.go (1)
  • ProvisionBackend (67-110)
pkg/ui/formatter.go (1)
  • Success (169-175)
pkg/provision/provision_test.go (4)
pkg/provision/provision.go (4)
  • ProvisionWithParams (65-119)
  • ProvisionParams (28-35)
  • ErrUnsupportedProvisionerType (18-18)
  • Provision (42-59)
errors/errors.go (1)
  • ErrNilParam (499-499)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
pkg/provisioner/backend/backend.go (1)
  • RegisterBackendProvisioner (45-52)
cmd/provision/provision_test.go (3)
cmd/provision/provision.go (2)
  • ProvisionCommandProvider (150-150)
  • ProvisionOptions (29-33)
pkg/schema/schema.go (1)
  • AtmosConfiguration (53-94)
errors/errors.go (1)
  • ErrRequiredFlagNotProvided (189-189)
⏰ 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 (7)
pkg/provisioner/provisioner_test.go (1)

1-417: Comprehensive test coverage for provisioner registry.

This test suite provides excellent coverage of the provisioner registry system, including registration, retrieval, execution, concurrency, and error handling. The use of resetRegistry() ensures proper test isolation, and edge cases like context cancellation and event-scoped isolation are well-tested.

pkg/provisioner/backend/s3_test.go (1)

1-291: Well-focused S3 backend config tests.

The test suite appropriately focuses on config parsing and validation logic without hitting real AWS services. The table-driven approach for TestExtractS3Config provides comprehensive coverage of edge cases, and the note at the end clearly explains the testing strategy.

pkg/provisioner/backend/backend_test.go (1)

1-515: Comprehensive backend provisioning tests.

The test suite provides thorough coverage of the backend provisioning flow, including edge cases for missing configuration, disabled provisioning, auth context propagation, and concurrent operations. The use of resetBackendRegistry() ensures proper test isolation.

pkg/provision/provision_test.go (1)

1-331: Thorough provision orchestration tests.

This test suite effectively validates the provision orchestration logic, including parameter validation, error propagation, and successful provisioning flows. The use of mock provisioners and callbacks allows testing without external dependencies.

cmd/provision/provision_test.go (1)

1-369: Comprehensive CLI command tests.

This test suite provides excellent coverage of the provision command structure, including metadata, flags, argument validation, environment variable handling, and precedence rules. The tests properly use t.Setenv for environment variable setup as per project conventions.

Based on learnings

pkg/provision/provision.go (2)

65-76: Proper nil parameter validation.

The nil checks for params and params.DescribeComponent before calling perf.Track and using the callbacks prevent potential panics and provide clear error messages. This addresses the defensive programming concerns from previous reviews.


95-110: Clear TODO for future authContext integration.

The TODO comment clearly explains the current approach (relying on AWS SDK credential chain) and the future direction (populating schema.AuthContext for in-process SDK calls). This is good documentation for future maintainers.

- Add S3ClientAPI interface for all S3 operations
- Refactor internal functions to accept interface for testability
- Add comprehensive mock-based tests for S3 operations
- Increase backend coverage from 34.7% to 77.1%

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

Co-Authored-By: Claude <[email protected]>
Add provision command to help output snapshots.

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

Co-Authored-By: Claude <[email protected]>
@codecov
Copy link

codecov bot commented Nov 21, 2025

Codecov Report

❌ Patch coverage is 72.71242% with 167 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.04%. Comparing base (6e39488) to head (a61b9bb).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
cmd/terraform/backend/backend_helpers.go 31.39% 56 Missing and 3 partials ⚠️
pkg/provisioner/backend/s3.go 70.58% 48 Missing and 2 partials ⚠️
pkg/provisioner/backend/s3_delete.go 76.63% 23 Missing and 2 partials ⚠️
cmd/terraform/backend/backend_create.go 58.33% 4 Missing and 1 partial ⚠️
cmd/terraform/backend/backend_update.go 58.33% 4 Missing and 1 partial ⚠️
cmd/terraform/backend/backend_delete.go 84.61% 2 Missing and 2 partials ⚠️
cmd/terraform/backend/backend_describe.go 84.00% 2 Missing and 2 partials ⚠️
cmd/terraform/backend/backend_list.go 83.33% 2 Missing and 2 partials ⚠️
internal/exec/terraform.go 60.00% 2 Missing and 2 partials ⚠️
pkg/provisioner/provisioner.go 93.10% 2 Missing and 2 partials ⚠️
... and 1 more

❌ Your patch check has failed because the patch coverage (72.71%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1808      +/-   ##
==========================================
+ Coverage   71.98%   72.04%   +0.05%     
==========================================
  Files         471      483      +12     
  Lines       45222    45830     +608     
==========================================
+ Hits        32555    33016     +461     
- Misses      10071    10203     +132     
- Partials     2596     2611      +15     
Flag Coverage Δ
unittests 72.04% <72.71%> (+0.05%) ⬆️

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

Files with missing lines Coverage Δ
cmd/root.go 66.82% <100.00%> (+0.05%) ⬆️
cmd/terraform/backend/backend.go 100.00% <100.00%> (ø)
cmd/terraform_commands.go 93.13% <100.00%> (+0.06%) ⬆️
errors/errors.go 100.00% <ø> (ø)
pkg/provisioner/backend/backend.go 100.00% <100.00%> (ø)
pkg/provisioner/registry.go 100.00% <100.00%> (ø)
internal/tui/templates/help_printer.go 84.21% <40.00%> (+16.21%) ⬆️
cmd/terraform/backend/backend_delete.go 84.61% <84.61%> (ø)
cmd/terraform/backend/backend_describe.go 84.00% <84.00%> (ø)
cmd/terraform/backend/backend_list.go 83.33% <83.33%> (ø)
... and 7 more

... and 3 files with indirect coverage changes

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

@osterman osterman added the minor New features that do not break anything label Nov 22, 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: 1

🧹 Nitpick comments (2)
pkg/provisioner/backend/s3.go (2)

53-64: Align ProvisionS3Backend doc comment with actual configuration requirements.

The comment says “No configuration options beyond enabled: true”, but extractS3Config requires bucket and region and supports optional assume_role.role_arn. That’s a bit misleading for callers.

Might be clearer to say something like “No knobs for the security defaults; only bucket/region/assume_role are configurable” so expectations match the code.

Also applies to: 111-137


80-90: Propagate the underlying AWS config error for better diagnostics.

On loadAWSConfigWithAuth failure you return a nicely annotated ErrLoadAWSConfig, but the original err from the AWS SDK is dropped. That can make debugging auth/region issues harder.

Consider including the cause as context, e.g.:

-	if err != nil {
-		return errUtils.Build(provisioner.ErrLoadAWSConfig).
+	if err != nil {
+		return errUtils.Build(provisioner.ErrLoadAWSConfig).
 			WithHint("Check AWS credentials are configured correctly").
 			WithHintf("Verify AWS region '%s' is valid", config.region).
 			WithHint("If using --identity flag, ensure the identity is authenticated").
 			WithContext("region", config.region).
 			WithContext("bucket", config.bucket).
+			WithContext("cause", err.Error()).
 			Err()
 	}

Keeps the same UX while preserving the root cause for logs and troubleshooting.

Also applies to: 161-174

📜 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 70f808f and 79b874e.

📒 Files selected for processing (5)
  • cmd/root.go (1 hunks)
  • pkg/provisioner/backend/s3.go (1 hunks)
  • pkg/provisioner/backend/s3_test.go (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_--help.stdout.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • cmd/root.go
  • pkg/provisioner/backend/s3_test.go
🧰 Additional context used
🧠 Learnings (12)
📓 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.
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_--help.stdout.golden
📚 Learning: 2025-03-18T12:26:25.329Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 1149
File: tests/snapshots/TestCLICommands_atmos_vendor_pull_ssh.stderr.golden:7-7
Timestamp: 2025-03-18T12:26:25.329Z
Learning: In the Atmos project, typos or inconsistencies in test snapshot files (such as "terrafrom" instead of "terraform") may be intentional as they capture the exact output of commands and should not be flagged as issues requiring correction.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_--help.stdout.golden
📚 Learning: 2025-02-14T23:12:38.030Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 1061
File: tests/snapshots/TestCLICommands_atmos_vendor_pull_ssh.stderr.golden:8-8
Timestamp: 2025-02-14T23:12:38.030Z
Learning: Test snapshots in the Atmos project, particularly for dry run scenarios, may be updated during the development process, and temporary inconsistencies in their content should not be flagged as issues.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
📚 Learning: 2025-09-27T20:50:20.564Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1533
File: pkg/config/load.go:585-637
Timestamp: 2025-09-27T20:50:20.564Z
Learning: In the cloudposse/atmos repository, command merging prioritizes precedence over display ordering. Help commands are displayed lexicographically regardless of internal array order, so the mergeCommandArrays function focuses on ensuring the correct precedence chain (top-level file wins) rather than maintaining specific display order.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_--help.stdout.golden
📚 Learning: 2025-09-10T21:17:55.273Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/http_client_test.go:3-10
Timestamp: 2025-09-10T21:17:55.273Z
Learning: In the cloudposse/atmos repository, imports should never be changed as per samtholiya's coding guidelines.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
📚 Learning: 2025-01-19T15:49:15.593Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 955
File: tests/snapshots/TestCLICommands_atmos_validate_editorconfig_--help.stdout.golden:0-0
Timestamp: 2025-01-19T15:49:15.593Z
Learning: In future commits, the help text for Atmos CLI commands should be limited to only show component and stack parameters for commands that actually use them. This applies to the example usage section in command help text.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_--help.stdout.golden
📚 Learning: 2025-10-07T00:25:16.333Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1498
File: website/src/components/Screengrabs/atmos-terraform-metadata--help.html:25-55
Timestamp: 2025-10-07T00:25:16.333Z
Learning: In Atmos CLI, subcommands inherit flags from their parent commands via Cobra's command inheritance. For example, `atmos terraform metadata --help` shows `--affected` and related flags inherited from the parent `terraform` command (defined in cmd/terraform.go), even though the metadata subcommand doesn't explicitly define these flags. This is expected Cobra behavior and auto-generated help screengrabs accurately reflect this inheritance.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_--help.stdout.golden
📚 Learning: 2025-01-30T19:30:59.120Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 959
File: cmd/workflow.go:74-74
Timestamp: 2025-01-30T19:30:59.120Z
Learning: Error handling for `cmd.Usage()` is not required in the Atmos CLI codebase, as confirmed by the maintainer.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
📚 Learning: 2024-11-25T17:17:15.703Z
Learnt from: RoseSecurity
Repo: cloudposse/atmos PR: 797
File: pkg/list/atmos.yaml:213-214
Timestamp: 2024-11-25T17:17:15.703Z
Learning: The file `pkg/list/atmos.yaml` is primarily intended for testing purposes.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_--help.stdout.golden
📚 Learning: 2025-09-05T14:57:37.360Z
Learnt from: RoseSecurity
Repo: cloudposse/atmos PR: 1448
File: cmd/ansible.go:26-28
Timestamp: 2025-09-05T14:57:37.360Z
Learning: The Atmos codebase uses a consistent pattern for commands that delegate to external tools: `PersistentFlags().Bool("", false, doubleDashHint)` where doubleDashHint provides help text about using double dashes to separate Atmos options from native command arguments. This pattern is used across terraform, packer, helmfile, atlantis, aws, and ansible commands.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_--help.stdout.golden
🧬 Code graph analysis (1)
pkg/provisioner/backend/s3.go (8)
pkg/provisioner/backend/backend.go (1)
  • RegisterBackendProvisioner (45-52)
pkg/schema/schema.go (3)
  • AtmosConfiguration (53-94)
  • AuthContext (568-578)
  • AWSAuthContext (582-597)
pkg/perf/perf.go (1)
  • Track (121-138)
errors/builder.go (1)
  • Build (21-23)
pkg/provisioner/errors.go (10)
  • ErrLoadAWSConfig (13-13)
  • ErrApplyBucketDefaults (16-16)
  • ErrBucketRequired (7-7)
  • ErrRegionRequired (8-8)
  • ErrCheckBucketExist (14-14)
  • ErrCreateBucket (15-15)
  • ErrEnableVersioning (17-17)
  • ErrEnableEncryption (18-18)
  • ErrBlockPublicAccess (19-19)
  • ErrApplyTags (20-20)
pkg/ui/formatter.go (2)
  • Success (169-175)
  • Warning (213-219)
internal/aws_utils/aws_utils.go (1)
  • LoadAWSConfigWithAuth (53-119)
errors/errors.go (1)
  • ErrS3BucketAccessDenied (91-91)
⏰ 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 (4)
tests/snapshots/TestCLICommands_atmos_non-existent.stderr.golden (1)

21-21: Snapshot correctly updated for new subcommand.

The addition of "provision" to the error output is properly positioned alphabetically and follows the established formatting pattern.

tests/snapshots/TestCLICommands_atmos_--help.stdout.golden (1)

26-26: Help output accurately reflects new command.

The provision subcommand is properly documented in the help text with a clear, concise description that matches the PR objectives.

pkg/provisioner/backend/s3.go (2)

238-253: CreateBucket flow looks solid for region handling.

Good call on omitting CreateBucketConfiguration for us-east-1 and using a region-specific LocationConstraint elsewhere. That matches S3’s quirky create semantics and keeps the helper narrow and testable.


26-27: The original review comment is incorrect.

Go 1.20+ supports multiple %w verbs in fmt.Errorf, which returns an error implementing Unwrap() []error — there is no runtime panic. Your retrieved learnings further confirm this: Atmos uses Go 1.24.8 and explicitly configures errorlint with errorf-multi: true to validate this exact pattern. The learnings also show this format ("%w: %w") is already established throughout the codebase in the errors package and used correctly.

The code at line 26–27 is valid and follows Atmos' own conventions. No changes needed.

Likely an incorrect or invalid review comment.

osterman and others added 2 commits November 22, 2025 19:07
BucketKeyEnabled only applies to SSE-KMS encryption, not AES-256.
Remove the field from the ServerSideEncryptionConfiguration when
using AES-256 to avoid invalid configuration.

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

Co-Authored-By: Claude <[email protected]>
coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 23, 2025
Document that backend commands now support component-level auth configuration
with default identities, making them consistent with regular terraform commands.

Changes:
- Updated --identity flag description to clarify it overrides component default
- Added new "Authentication" section explaining component-level identity
- Included YAML example showing how to configure component auth
- Documented identity flag override behavior
- Added link to auth documentation for complete details

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

Co-Authored-By: Claude <[email protected]>
coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 26, 2025
Updated snapshot to include 'backend [command]' in terraform help output
after adding component-level auth support to backend commands.
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: 1

🧹 Nitpick comments (20)
cmd/terraform/backend/backend_test_helpers.go (1)

21-68: Solid test helper reducing duplication.

The helper validates command structure, required flags, and argument constraints in one place. The copy of requiredFlags slice in the loop prevents false positives from shared state.

One consideration: the helper assumes all commands require exactly one argument (lines 52-67). If a future backend command needs different argument validation (e.g., list with zero args), you may need to parameterize this behavior.

 type commandTestParams struct {
 	cmd           *cobra.Command
 	parser        *flags.StandardParser
 	expectedUse   string
 	expectedShort string
 	requiredFlags []string
+	expectedArgs  int // 0 = skip args test, 1 = ExactArgs(1), etc.
 }
pkg/provisioner/registry.go (2)

89-93: Consider checking context cancellation in the loop.

For long-running provisioner chains, respecting context cancellation provides better responsiveness to user interrupts.

 for _, p := range provisioners {
+	if err := ctx.Err(); err != nil {
+		return fmt.Errorf("provisioning cancelled: %w", err)
+	}
 	if err := p.Func(ctx, atmosConfig, componentConfig, authContext); err != nil {
 		return fmt.Errorf("provisioner %s failed: %w", p.Type, err)
 	}
 }

90-91: Consider using static errors for provisioner failures.

Per coding guidelines, errors should be wrapped using static errors defined in errors/errors.go. This enables callers to use errors.Is() for specific error handling.

Define in errors/errors.go:

var ErrProvisionerFailed = errors.New("provisioner failed")

Then wrap:

-return fmt.Errorf("provisioner %s failed: %w", p.Type, err)
+return fmt.Errorf("provisioner %s: %w", p.Type, errors.Join(ErrProvisionerFailed, err))
website/blog/2025-11-20-automatic-backend-provisioning.mdx (1)

141-149: CLI example has redundant duplicate command.

Lines 143 and 146 show identical commands. Consider differentiating them or removing the duplicate.

 # Provision backend explicitly
 atmos terraform backend create vpc --stack dev

-# Automatic in CI/CD
-atmos terraform backend create vpc --stack dev
+# Provision multiple backends in CI/CD
 atmos terraform backend create eks --stack dev
 atmos terraform apply vpc --stack dev  # Only runs if provisioning succeeded
docs/prd/s3-backend-provisioner.md (2)

360-365: Add language specifier to code block.

Static analysis flagged missing language for the package structure block.

-```
+```text
 pkg/provisioner/backend/
   ├── s3.go              # S3 backend provisioner
   ├── s3_test.go         # Unit tests
   ├── s3_integration_test.go  # Integration tests

---

`1189-1189`: **Duplicate heading detected.**

"Error Handling" appears twice (lines 798 and 1189). Consider renaming one for clarity, e.g., "Error Categories and Recovery".

</blockquote></details>
<details>
<summary>cmd/terraform/backend/backend_describe.go (1)</summary><blockquote>

`54-71`: **Init function correctly sets up parser and flags.**

The StandardParser pattern handles viper binding internally. Panic on init error is acceptable for fatal startup conditions.

Minor note: Line 55 `DisableFlagParsing = false` is the default value and could be removed.

</blockquote></details>
<details>
<summary>pkg/provisioner/registry_test.go (1)</summary><blockquote>

`211-250`: **Fail-fast test has a potential ordering assumption.**

The comment at lines 248-249 acknowledges order isn't guaranteed, yet the test relies on `provisioner1` being called first. If the implementation changes ordering, this could become flaky.

Consider asserting only that the error contains expected content without assuming which provisioner failed first.

</blockquote></details>
<details>
<summary>pkg/provisioner/backend/s3_delete.go (1)</summary><blockquote>

`130-134`: **Minor: range variable could be used directly.**

```diff
 for i := range output.Versions {
-	if output.Versions[i].Key != nil && strings.HasSuffix(*output.Versions[i].Key, ".tfstate") {
+for _, v := range output.Versions {
+	if v.Key != nil && strings.HasSuffix(*v.Key, ".tfstate") {
 		stateFiles++
 	}
 }
cmd/terraform/backend/backend_list.go (1)

23-32: Redundant flag binding.

BindFlagsToViper is called here at line 25, but ParseCommonFlags (line 29) also calls BindFlagsToViper internally (see backend_helpers.go:31). Remove the explicit call here.

 	RunE: func(cmd *cobra.Command, args []string) error {
 		defer perf.Track(atmosConfigPtr, "backend.list.RunE")()
 
-		// Parse flags.
-		v := viper.GetViper()
-		if err := listParser.BindFlagsToViper(cmd, v); err != nil {
-			return err
-		}
-
 		opts, err := ParseCommonFlags(cmd, listParser)
 		if err != nil {
 			return err
 		}
+
+		v := viper.GetViper()
 		format := v.GetString("format")
cmd/terraform/backend/backend_delete.go (1)

28-32: Same redundant flag binding as list command.

Remove explicit BindFlagsToViper call since ParseCommonFlags handles this internally.

 	RunE: func(cmd *cobra.Command, args []string) error {
 		defer perf.Track(atmosConfigPtr, "backend.delete.RunE")()
 
 		component := args[0]
 
-		// Parse flags.
-		v := viper.GetViper()
-		if err := deleteParser.BindFlagsToViper(cmd, v); err != nil {
-			return err
-		}
-
 		opts, err := ParseCommonFlags(cmd, deleteParser)
 		if err != nil {
 			return err
 		}
 
+		v := viper.GetViper()
 		force := v.GetBool("force")
cmd/terraform/backend/backend_helpers.go (3)

41-43: Error message could specify the missing flag.

Consider wrapping with context to identify which flag is missing.

 	if opts.Stack == "" {
-		return nil, errUtils.ErrRequiredFlagNotProvided
+		return nil, fmt.Errorf("%w: --stack", errUtils.ErrRequiredFlagNotProvided)
 	}

82-85: Inconsistent error handling.

Other errors in this function are wrapped with context, but this one is returned directly. Consider wrapping for consistency.

 	authManager, err := auth.CreateAndAuthenticateManager(identity, mergedAuthConfig, cfg.IdentityFlagSelectValue)
 	if err != nil {
-		return nil, nil, err
+		return nil, nil, fmt.Errorf("failed to create auth manager: %w", err)
 	}

132-144: Minor duplication with CreateDescribeComponentFunc.

This inline function duplicates what CreateDescribeComponentFunc(nil) would return. Consider reusing:

 	// Create describe component callback.
-	// Note: We don't need to pass authContext to the describe function for backend provisioning
-	// since we already loaded the component config in InitConfigAndAuth.
-	describeFunc := func(component, stack string) (map[string]any, error) {
-		return e.ExecuteDescribeComponent(&e.ExecuteDescribeComponentParams{
-			Component:            component,
-			Stack:                stack,
-			ProcessTemplates:     false,
-			ProcessYamlFunctions: false,
-			Skip:                 nil,
-			AuthManager:          nil, // Auth already handled
-		})
-	}
+	describeFunc := CreateDescribeComponentFunc(nil) // Auth already handled in InitConfigAndAuth
pkg/provisioner/provisioner.go (4)

16-17: Error should be in errors/errors.go.

Per coding guidelines, static errors should be defined centrally. Move ErrUnsupportedProvisionerType to errors/errors.go for consistency with ErrBackendNotFound, ErrBackendTypeRequired, etc.


91-97: Redundant variable assignment.

Line 95 just renames params.AuthContext to authContext. Use params.AuthContext directly at line 97.

-	// Pass AuthContext from params directly to backend provisioner.
-	// This enables in-process SDK calls with Atmos-managed credentials.
-	// The AuthContext was populated by the command layer through InitConfigAndAuth,
-	// which merges component-level auth with global auth and respects default identity settings.
-	authContext := params.AuthContext
-
-	err = backend.ProvisionBackend(ctx, params.AtmosConfig, componentConfig, authContext)
+	// Pass AuthContext from params directly to backend provisioner.
+	// This enables in-process SDK calls with Atmos-managed credentials.
+	// The AuthContext was populated by the command layer through InitConfigAndAuth,
+	// which merges component-level auth with global auth and respects default identity settings.
+	err = backend.ProvisionBackend(ctx, params.AtmosConfig, componentConfig, params.AuthContext)

106-122: Stub implementations return success.

These stubs return nil despite not being implemented. Consider returning an error or tracking these as TODOs.

Want me to open an issue to track implementing ListBackends and DescribeBackend?


159-163: Hardcoded "supported: s3" will become stale.

When GCS or azurerm backends are added, this error message won't update. Consider omitting the hint or deriving supported types from the registry.

 	deleteFunc := backend.GetBackendDelete(backendType)
 	if deleteFunc == nil {
-		return fmt.Errorf("%w: %s (supported: s3)", errUtils.ErrDeleteNotImplemented, backendType)
+		return fmt.Errorf("%w: %s", errUtils.ErrDeleteNotImplemented, backendType)
 	}
pkg/provisioner/backend/s3.go (2)

3-25: Reuse shared ErrWrapFormat instead of hardcoding errFormat.

You’re duplicating the standard error-wrap format string locally as const errFormat = "%w: %w", even though errUtils.ErrWrapFormat already exists for this purpose. It’s cleaner and keeps behavior consistent to alias or call through to the shared constant.

You can simplify to something like:

-import (
-    "context"
-    "errors"
-    "fmt"
-    "net/http"
-    "time"
-
-    //nolint:depguard
-    "github.com/aws/aws-sdk-go-v2/aws"
-    //nolint:depguard
-    "github.com/aws/aws-sdk-go-v2/service/s3"
-    //nolint:depguard
-    "github.com/aws/aws-sdk-go-v2/service/s3/types"
-    "github.com/aws/smithy-go"
-
-    errUtils "github.com/cloudposse/atmos/errors"
-    "github.com/cloudposse/atmos/internal/aws_utils"
-    "github.com/cloudposse/atmos/pkg/perf"
-    "github.com/cloudposse/atmos/pkg/schema"
-    "github.com/cloudposse/atmos/pkg/ui"
-)
-
-const errFormat = "%w: %w"
+import (
+    "context"
+    "errors"
+    "fmt"
+    "net/http"
+    "time"
+
+    //nolint:depguard
+    "github.com/aws/aws-sdk-go-v2/aws"
+    //nolint:depguard
+    "github.com/aws/aws-sdk-go-v2/service/s3"
+    //nolint:depguard
+    "github.com/aws/aws-sdk-go-v2/service/s3/types"
+    "github.com/aws/smithy-go"
+
+    errUtils "github.com/cloudposse/atmos/errors"
+    "github.com/cloudposse/atmos/internal/aws_utils"
+    "github.com/cloudposse/atmos/pkg/perf"
+    "github.com/cloudposse/atmos/pkg/schema"
+    "github.com/cloudposse/atmos/pkg/ui"
+)
+
+const errFormat = errUtils.ErrWrapFormat

That way all wrapping uses the same central format and you avoid another magic string.


68-113: Preserve underlying AWS config error details in CreateS3Backend.

The high-level wrapping with ErrLoadAWSConfig and helpful hints is great, but the original error from loadAWSConfigWithAuth is currently discarded, so any AWS SDK–specific reason (bad profile, region, etc.) is lost.

You can keep your existing hints and also surface the root cause for debugging by adding it as context:

 awsConfig, err := loadAWSConfigWithAuth(ctx, config.region, config.roleArn, authContext)
 if err != nil {
-    return errUtils.Build(errUtils.ErrLoadAWSConfig).
+    return errUtils.Build(errUtils.ErrLoadAWSConfig).
         WithHint("Check AWS credentials are configured correctly").
         WithHintf("Verify AWS region '%s' is valid", config.region).
         WithHint("If using --identity flag, ensure the identity is authenticated").
         WithContext("region", config.region).
-        WithContext("bucket", config.bucket).
+        WithContext("bucket", config.bucket).
+        WithContext("cause", err.Error()).
         Err()
 }

That keeps the new sentinel while still giving operators the exact SDK failure message when they need to debug.

Add guard at the beginning of DeleteS3Backend to require the --force flag
before performing any destructive operations. This prevents accidental
deletion of S3 backends and their contents.

The force parameter was declared but never checked, allowing deletion
without explicit confirmation. Now returns ErrForceRequired with a clear
message when force=false.

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

Co-Authored-By: Claude <[email protected]>
- Refactor DeleteS3Backend to reduce function length from 63 to 60 lines
- Extract deleteBackendContents and showDeletionWarning helper functions
- Remove //nolint:funlen directive to allow natural linter validation
- Add comprehensive test coverage for deletion helper functions
- Add tests for force flag validation, missing parameters, and error handling
- Improve test coverage from 67.0% to 73.4%
- Regenerate CLI snapshots for backend command integration

Changes:
- pkg/provisioner/backend/s3_delete.go:
  - Extract deleteBackendContents() to handle warning display and deletion
  - Extract showDeletionWarning() to format deletion warning messages
  - Reduce DeleteS3Backend() from 63 to 60 lines without nolint

- pkg/provisioner/backend/s3_test.go:
  - Add TestDeleteBackendContents_EmptyBucket test
  - Add TestDeleteBackendContents_Success table-driven test (regular objects and state files)
  - Add TestDeleteBackendContents_DeleteError test
  - Add TestShowDeletionWarning_* tests (with and without state files)
  - Add TestDeleteS3Backend_ForceRequired test
  - Add TestDeleteS3Backend_MissingBucket test
  - Add TestDeleteS3Backend_MissingRegion test
  - Add TestListAllObjects_* tests (empty bucket, with objects, pagination)
  - Add TestDeleteAllObjects_Success test
  - Add TestDeleteBucket_Success and TestDeleteBucket_Failure tests

- tests/snapshots/*:
  - Regenerate golden snapshots to include new backend command

Note: Coverage limited to 73.4% due to AWS SDK integration code requiring
live credentials. All testable helper functions have 85-100% coverage.

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

Co-Authored-By: Claude <[email protected]>
coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 27, 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)
pkg/provisioner/backend/s3_test.go (2)

256-267: Consider removing this tautological test.

This test verifies Go's basic struct assignment works. It doesn't test business logic or behavior. Per guidelines, avoid tautological tests.

-func TestS3Config_FieldValues(t *testing.T) {
-	// Test s3Config structure holds correct values.
-	config := &s3Config{
-		bucket:  "test-bucket",
-		region:  "us-west-2",
-		roleArn: "arn:aws:iam::123456789012:role/TestRole",
-	}
-
-	assert.Equal(t, "test-bucket", config.bucket)
-	assert.Equal(t, "us-west-2", config.region)
-	assert.Equal(t, "arn:aws:iam::123456789012:role/TestRole", config.roleArn)
-}

358-361: Testing implementation details.

This asserts the internal errFormat constant value. Tests should verify behavior, not implementation. If the format changes intentionally, this test fails for the wrong reason. Optional to remove.

pkg/provisioner/backend/s3_delete.go (1)

205-217: Consider handling partial delete failures.

With Quiet: aws.Bool(true), the DeleteObjects response doesn't return deleted objects, but it can still include Errors for partial failures. Currently these are not checked.

 		if len(objectsToDelete) > 0 {
-			_, err := client.DeleteObjects(ctx, &s3.DeleteObjectsInput{
+			result, err := client.DeleteObjects(ctx, &s3.DeleteObjectsInput{
 				Bucket: aws.String(bucket),
 				Delete: &types.Delete{
 					Objects: objectsToDelete,
 					Quiet:   aws.Bool(true), // Don't return deleted objects in response.
 				},
 			})
 			if err != nil {
 				return fmt.Errorf(errFormat, errUtils.ErrDeleteObjects, err)
 			}
+			// Check for partial failures.
+			if len(result.Errors) > 0 {
+				return fmt.Errorf("%w: %d object(s) failed to delete", errUtils.ErrDeleteObjects, len(result.Errors))
+			}
 		}
📜 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 607a918 and e48531e.

📒 Files selected for processing (6)
  • pkg/provisioner/backend/s3_delete.go (1 hunks)
  • pkg/provisioner/backend/s3_test.go (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_terraform.stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_terraform_--help.stdout.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_terraform_--help_alias_subcommand_check.stdout.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_terraform_non-existent.stderr.golden (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/snapshots/TestCLICommands_atmos_terraform_--help.stdout.golden
  • tests/snapshots/TestCLICommands_atmos_terraform.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_terraform_--help_alias_subcommand_check.stdout.golden
  • tests/snapshots/TestCLICommands_atmos_terraform_non-existent.stderr.golden
🧰 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:

  • pkg/provisioner/backend/s3_test.go
  • pkg/provisioner/backend/s3_delete.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:

  • pkg/provisioner/backend/s3_test.go
🧠 Learnings (11)
📓 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-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:

  • pkg/provisioner/backend/s3_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:

  • pkg/provisioner/backend/s3_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 **/*.go : Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations

Applied to files:

  • pkg/provisioner/backend/s3_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: Use interface-driven design with dependency injection for testability. Generate mocks with go.uber.org/mock/mockgen using //go:generate directives.

Applied to files:

  • pkg/provisioner/backend/s3_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:

  • pkg/provisioner/backend/s3_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:

  • pkg/provisioner/backend/s3_test.go
📚 Learning: 2024-12-02T21:26:32.337Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.

Applied to files:

  • pkg/provisioner/backend/s3_delete.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:

  • pkg/provisioner/backend/s3_delete.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:

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
🧬 Code graph analysis (2)
pkg/provisioner/backend/s3_test.go (2)
errors/errors.go (11)
  • ErrBucketRequired (568-568)
  • ErrRegionRequired (569-569)
  • ErrCheckBucketExist (576-576)
  • ErrCreateBucket (577-577)
  • ErrEnableVersioning (579-579)
  • ErrEnableEncryption (580-580)
  • ErrBlockPublicAccess (581-581)
  • ErrApplyTags (582-582)
  • ErrForceRequired (583-583)
  • ErrDeleteBucket (587-587)
  • ErrDeleteObjects (586-586)
pkg/provisioner/backend/s3.go (1)
  • S3ClientAPI (31-41)
pkg/provisioner/backend/s3_delete.go (5)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • AuthContext (569-579)
pkg/perf/perf.go (1)
  • Track (121-138)
errors/errors.go (6)
  • ErrForceRequired (583-583)
  • ErrLoadAWSConfig (575-575)
  • ErrBackendNotFound (570-570)
  • ErrListObjects (588-588)
  • ErrDeleteObjects (586-586)
  • ErrDeleteBucket (587-587)
pkg/ui/formatter.go (2)
  • Success (233-239)
  • Warning (277-283)
pkg/provisioner/backend/s3.go (1)
  • S3ClientAPI (31-41)
⏰ 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 (11)
pkg/provisioner/backend/s3_test.go (6)

21-32: Manual mock is acceptable here, but consider mockgen for consistency.

The mock satisfies S3ClientAPI and works well. Guidelines prefer go.uber.org/mock/mockgen, but manual mocks with function fields are pragmatic for complex AWS interfaces. The //nolint:dupl is understood.


97-248: Solid table-driven tests for config extraction.

Covers valid configs, missing/empty fields, type mismatches, and assume_role edge cases. Good use of assert.ErrorIs for sentinel error verification.


365-525: Comprehensive bucket operation tests.

Good coverage of bucketExists, createBucket, and ensureBucket functions. Notable: us-east-1 LocationConstraint special case (line 450) and proper error sentinel verification throughout.


662-793: Good tests for security defaults application.

Tests verify all four security operations are called and proper error propagation. The alreadyExisted=true path (line 720) confirms operations still run for existing buckets.


841-878: Force flag enforcement tests look good.

Tests verify ErrForceRequired is returned when force=false, and config validation still runs when force=true. This aligns with the fix from the previous review.


900-956: Pagination and state file counting tests are thorough.

State file detection (.tfstate suffix) is verified. Pagination test (lines 924-956) correctly validates multiple API calls with marker handling.

pkg/provisioner/backend/s3_delete.go (5)

41-53: Force flag validation is now in place.

The fix from the previous review is implemented. The function properly returns ErrForceRequired when force=false.


54-100: Main deletion flow is well-structured.

Config extraction → AWS config → existence check → list objects → delete contents → delete bucket. Good separation of concerns. The _ = ui.Info(...) pattern is consistent with the codebase.


133-169: Pagination and counting logic is correct.

Handles versions, delete markers, and .tfstate detection. The aws.ToBool(output.IsTruncated) is the right approach for nil-safe boolean handling.


122-131: Clear warning messaging.

Highlights object count and specifically calls out Terraform state files. Good UX for a destructive operation.


231-240: Simple and correct bucket deletion wrapper.

Proper error wrapping with ErrDeleteBucket sentinel.

Improve test coverage for the backend command package from 14-37% to 75%.

Changes:
- Add mockgen directive and interfaces for ConfigInitializer and Provisioner
- Rename Provisioner.Provision to CreateBackend for consistency
- Refactor commands to use dependency injection for testability
- Add comprehensive unit tests with mocks for all command paths
- Add helper functions for test setup and Viper configuration
- Add command structure tests for create/update commands

Coverage improvements:
- ExecuteProvisionCommand: 90.9%
- ParseCommonFlags: 85.7%
- SetConfigInitializer/SetProvisioner/ResetDependencies: 100%
- GetBackendCommand: 100%

The remaining uncovered code is production wrapper functions that delegate
to external packages - these are intentionally not unit tested.

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

Co-Authored-By: Claude <[email protected]>
Reorganize confusing backend documentation from 2 overlapping pages into 3
logically separated pages:

1. Terraform Backends (backends.mdx) - Configure where state is stored
2. Terraform Remote State (remote-state.mdx) - Read other components' state
3. Automatic Backend Provisioning (backend-provisioning.mdx) - Auto-create backends

Changes:
- Create backend-provisioning.mdx with extracted auto-provisioning content
- Create remote-state.mdx (renamed from state-backend.mdx)
- Trim backends.mdx by removing provisioning section (~300 lines)
- Add cross-reference tip boxes linking all 3 pages
- Update internal links in advanced.mdx and terraform-backend.mdx
- Add redirect from /state-backend to /remote-state
- Remove unnecessary Git credential step from codeql.yml workflow

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

Co-Authored-By: Claude <[email protected]>
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: 1

🧹 Nitpick comments (1)
cmd/terraform/backend/backend_helpers.go (1)

164-176: Optional: add perf tracking for this exported helper.

CreateDescribeComponentFunc is exported and potentially used in hot paths, but it doesn’t currently have defer perf.Track(nil, "cmd.terraform.backend.CreateDescribeComponentFunc")() like other public functions per guidelines.

Not a blocker, but if you want consistent perf telemetry on exported helpers, you could add:

func CreateDescribeComponentFunc(authManager auth.AuthManager) func(string, string) (map[string]any, error) {
+   defer perf.Track(nil, "cmd.terraform.backend.CreateDescribeComponentFunc")()
+
    return func(component, stack string) (map[string]any, error) {
        return e.ExecuteDescribeComponent(&e.ExecuteDescribeComponentParams{
            // ...
        })
    }
}
📜 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 e48531e and 0d40d27.

📒 Files selected for processing (15)
  • cmd/terraform/backend/backend_commands_test.go (1 hunks)
  • cmd/terraform/backend/backend_create_test.go (1 hunks)
  • cmd/terraform/backend/backend_delete.go (1 hunks)
  • cmd/terraform/backend/backend_describe.go (1 hunks)
  • cmd/terraform/backend/backend_helpers.go (1 hunks)
  • cmd/terraform/backend/backend_list.go (1 hunks)
  • cmd/terraform/backend/backend_test.go (1 hunks)
  • cmd/terraform/backend/backend_update_test.go (1 hunks)
  • cmd/terraform/backend/mock_backend_helpers_test.go (1 hunks)
  • website/docs/cli/commands/terraform/terraform-backend.mdx (1 hunks)
  • website/docs/core-concepts/components/terraform/backend-provisioning.mdx (1 hunks)
  • website/docs/core-concepts/components/terraform/backends.mdx (2 hunks)
  • website/docs/core-concepts/components/terraform/remote-state.mdx (2 hunks)
  • website/docs/quick-start/advanced/advanced.mdx (1 hunks)
  • website/docusaurus.config.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • cmd/terraform/backend/backend_describe.go
  • cmd/terraform/backend/backend_list.go
  • website/docs/core-concepts/components/terraform/backends.mdx
  • cmd/terraform/backend/backend_delete.go
🧰 Additional context used
📓 Path-based instructions (6)
website/**

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

website/**: Update website documentation in the website/ directory when adding new features, ensure consistency between CLI help text and website documentation, and follow the website's documentation structure and style
Keep website code in the website/ directory, follow the existing website architecture and style, and test website changes locally before committing
Keep CLI documentation and website documentation in sync and document new features on the website with examples and use cases

Files:

  • website/docs/core-concepts/components/terraform/remote-state.mdx
  • website/docs/quick-start/advanced/advanced.mdx
  • website/docs/cli/commands/terraform/terraform-backend.mdx
  • website/docusaurus.config.js
  • website/docs/core-concepts/components/terraform/backend-provisioning.mdx
**/*.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:

  • cmd/terraform/backend/backend_update_test.go
  • cmd/terraform/backend/backend_test.go
  • cmd/terraform/backend/backend_create_test.go
  • cmd/terraform/backend/mock_backend_helpers_test.go
  • cmd/terraform/backend/backend_commands_test.go
  • cmd/terraform/backend/backend_helpers.go
cmd/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

cmd/**/*.go: Use unified flag parsing infrastructure in pkg/flags/. Commands MUST use flags.NewStandardParser() for command-specific flags. NEVER call viper.BindEnv() or viper.BindPFlag() directly outside pkg/flags/ (Forbidigo enforces this).
Telemetry is auto-enabled via RootCmd.ExecuteC(). Non-standard paths use telemetry.CaptureCmd(). Never capture user data.

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands, implementing each command in a separate file under cmd/ directory
Provide comprehensive help text for all commands and flags, include examples in command help, and follow Go's documentation conventions in Cobra command definitions
Provide meaningful feedback to users and include progress indicators for long-running operations in CLI commands

Files:

  • cmd/terraform/backend/backend_update_test.go
  • cmd/terraform/backend/backend_test.go
  • cmd/terraform/backend/backend_create_test.go
  • cmd/terraform/backend/mock_backend_helpers_test.go
  • cmd/terraform/backend/backend_commands_test.go
  • cmd/terraform/backend/backend_helpers.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:

  • cmd/terraform/backend/backend_update_test.go
  • cmd/terraform/backend/backend_test.go
  • cmd/terraform/backend/backend_create_test.go
  • cmd/terraform/backend/mock_backend_helpers_test.go
  • cmd/terraform/backend/backend_commands_test.go
cmd/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS use cmd.NewTestKit(t) for cmd package tests to auto-clean RootCmd state (flags, args). Required for any test touching RootCmd.

Files:

  • cmd/terraform/backend/backend_update_test.go
  • cmd/terraform/backend/backend_test.go
  • cmd/terraform/backend/backend_create_test.go
  • cmd/terraform/backend/mock_backend_helpers_test.go
  • cmd/terraform/backend/backend_commands_test.go
website/docs/cli/commands/**/*.mdx

📄 CodeRabbit inference engine (CLAUDE.md)

website/docs/cli/commands/**/*.mdx: All commands and flags need Docusaurus documentation in website/docs/cli/commands/. Use

for arguments/flags. Build website after changes: cd website && npm run build.
Use Docusaurus conventions with frontmatter, purpose note, screengrab, usage/examples/arguments/flags sections for CLI command documentation.

Files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
🧠 Learnings (43)
📓 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.
Learnt from: mcalhoun
Repo: cloudposse/atmos PR: 963
File: website/docs/core-concepts/projects/configuration/stores.mdx:286-286
Timestamp: 2025-04-25T20:54:19.701Z
Learning: For the AWS SSM Parameter Store implementation in Atmos, support for `read_role_arn` and `write_role_arn` options is essential to enable cross-account access, allowing users to run operations like `terraform plan` in multiple accounts while accessing values across keystores. Azure Key Vault would need similar capabilities for cross-tenant/subscription authentication.
📚 Learning: 2024-12-17T07:10:26.295Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 863
File: internal/exec/stack_utils.go:201-223
Timestamp: 2024-12-17T07:10:26.295Z
Learning: Unit tests for remote state backend functionality are located in the `examples/tests` directory.

Applied to files:

  • website/docs/core-concepts/components/terraform/remote-state.mdx
📚 Learning: 2025-04-25T20:54:19.701Z
Learnt from: mcalhoun
Repo: cloudposse/atmos PR: 963
File: website/docs/core-concepts/projects/configuration/stores.mdx:286-286
Timestamp: 2025-04-25T20:54:19.701Z
Learning: For the AWS SSM Parameter Store implementation in Atmos, support for `read_role_arn` and `write_role_arn` options is essential to enable cross-account access, allowing users to run operations like `terraform plan` in multiple accounts while accessing values across keystores. Azure Key Vault would need similar capabilities for cross-tenant/subscription authentication.

Applied to files:

  • website/docs/core-concepts/components/terraform/remote-state.mdx
  • website/docs/core-concepts/components/terraform/backend-provisioning.mdx
📚 Learning: 2024-12-01T00:33:20.298Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml:28-32
Timestamp: 2024-12-01T00:33:20.298Z
Learning: In `examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml`, `!exec atmos terraform output` is used in examples to demonstrate its usage, even though `!terraform.output` is the recommended approach according to the documentation.

Applied to files:

  • website/docs/quick-start/advanced/advanced.mdx
📚 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:

  • cmd/terraform/backend/backend_update_test.go
  • cmd/terraform/backend/backend_test.go
  • cmd/terraform/backend/backend_create_test.go
  • cmd/terraform/backend/backend_commands_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 cmd/**/*.go : Use Cobra's recommended command structure with a root command and subcommands, implementing each command in a separate file under `cmd/` directory

Applied to files:

  • cmd/terraform/backend/backend_update_test.go
  • cmd/terraform/backend/backend_create_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 cmd/**/*_test.go : ALWAYS use cmd.NewTestKit(t) for cmd package tests to auto-clean RootCmd state (flags, args). Required for any test touching RootCmd.

Applied to files:

  • cmd/terraform/backend/backend_update_test.go
  • cmd/terraform/backend/backend_create_test.go
  • cmd/terraform/backend/backend_commands_test.go
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.

Applied to files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
📚 Learning: 2024-12-03T04:01:16.446Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:0-0
Timestamp: 2024-12-03T04:01:16.446Z
Learning: In the `terraform.output.mdx` documentation file (`website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx`), the cache invalidation and cache scope behavior for the `!terraform.output` function are already described.

Applied to files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
📚 Learning: 2025-01-19T15:49:15.593Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 955
File: tests/snapshots/TestCLICommands_atmos_validate_editorconfig_--help.stdout.golden:0-0
Timestamp: 2025-01-19T15:49:15.593Z
Learning: In future commits, the help text for Atmos CLI commands should be limited to only show component and stack parameters for commands that actually use them. This applies to the example usage section in command help text.

Applied to files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
📚 Learning: 2025-10-07T00:25:16.333Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1498
File: website/src/components/Screengrabs/atmos-terraform-metadata--help.html:25-55
Timestamp: 2025-10-07T00:25:16.333Z
Learning: In Atmos CLI, subcommands inherit flags from their parent commands via Cobra's command inheritance. For example, `atmos terraform metadata --help` shows `--affected` and related flags inherited from the parent `terraform` command (defined in cmd/terraform.go), even though the metadata subcommand doesn't explicitly define these flags. This is expected Cobra behavior and auto-generated help screengrabs accurately reflect this inheritance.

Applied to files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
📚 Learning: 2024-12-03T05:29:07.718Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: internal/exec/terraform_utils.go:145-146
Timestamp: 2024-12-03T05:29:07.718Z
Learning: In the Atmos project, a 5-minute timeout in the `execTerraformOutput` function is acceptable for retrieving `terraform output` for a component in a stack.

Applied to files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
📚 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:

  • cmd/terraform/backend/backend_test.go
  • cmd/terraform/backend/backend_commands_test.go
📚 Learning: 2025-11-11T03:47:45.878Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.

Applied to files:

  • cmd/terraform/backend/backend_test.go
  • cmd/terraform/backend/backend_commands_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: The atmos codebase has a custom extension to *testing.T that provides a Chdir method, allowing test functions to call t.Chdir() to change working directories during tests. This is used consistently across test files in the codebase.

Applied to files:

  • cmd/terraform/backend/backend_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 **/*.go : Add defer perf.Track(atmosConfig, "pkg.FuncName")() + blank line to all public functions. Use nil if no atmosConfig parameter.

Applied to files:

  • cmd/terraform/backend/backend_test.go
📚 Learning: 2025-11-10T23:23:39.771Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/registry/aqua/aqua_test.go:417-442
Timestamp: 2025-11-10T23:23:39.771Z
Learning: In Atmos toolchain AquaRegistry, tests should not hit real GitHub. Use the options pattern via WithGitHubBaseURL to inject an httptest server URL and make GetLatestVersion/GetAvailableVersions deterministic.

Applied to files:

  • cmd/terraform/backend/backend_test.go
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.

Applied to files:

  • cmd/terraform/backend/backend_test.go
  • cmd/terraform/backend/backend_helpers.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:

  • cmd/terraform/backend/backend_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:

  • cmd/terraform/backend/backend_test.go
📚 Learning: 2025-03-18T12:26:25.329Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 1149
File: tests/snapshots/TestCLICommands_atmos_vendor_pull_ssh.stderr.golden:7-7
Timestamp: 2025-03-18T12:26:25.329Z
Learning: In the Atmos project, typos or inconsistencies in test snapshot files (such as "terrafrom" instead of "terraform") may be intentional as they capture the exact output of commands and should not be flagged as issues requiring correction.

Applied to files:

  • cmd/terraform/backend/backend_test.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.

Applied to files:

  • cmd/terraform/backend/backend_test.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1405
File: internal/exec/describe_dependents_test.go:455-456
Timestamp: 2025-08-16T23:32:40.412Z
Learning: In the cloudposse/atmos Go codebase, `InitCliConfig` returns a `schema.AtmosConfiguration` value (not a pointer), while `ExecuteDescribeDependents` expects a `*schema.AtmosConfiguration` pointer parameter. Therefore, when passing the result of `InitCliConfig` to `ExecuteDescribeDependents`, use `&atmosConfig` to pass the address of the value.

Applied to files:

  • cmd/terraform/backend/backend_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: When adding new CLI commands: 1) Create cmd/[command]/ with CommandProvider interface, 2) Add blank import to cmd/root.go, 3) Implement in internal/exec/mycommand.go, 4) Add tests in cmd/mycommand/mycommand_test.go, 5) Create Docusaurus docs, 6) Build website.

Applied to files:

  • cmd/terraform/backend/backend_create_test.go
  • cmd/terraform/backend/backend_commands_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:

  • cmd/terraform/backend/backend_create_test.go
  • cmd/terraform/backend/backend_commands_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:

  • cmd/terraform/backend/mock_backend_helpers_test.go
  • cmd/terraform/backend/backend_commands_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: Use interface-driven design with dependency injection for testability. Generate mocks with go.uber.org/mock/mockgen using //go:generate directives.

Applied to files:

  • cmd/terraform/backend/mock_backend_helpers_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 **/*.go : Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations

Applied to files:

  • cmd/terraform/backend/mock_backend_helpers_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 **/*.go : Use go.uber.org/mock/mockgen with //go:generate directives for mock generation. Never create manual mocks.

Applied to files:

  • cmd/terraform/backend/mock_backend_helpers_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: Follow multi-provider registry pattern: 1) Define interface in dedicated package, 2) Implement per provider, 3) Register implementations, 4) Generate mocks. See pkg/store/ for reference (AWS SSM, Azure Key Vault, Google Secret Manager).

Applied to files:

  • cmd/terraform/backend/mock_backend_helpers_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 cmd/**/*.go : Provide comprehensive help text for all commands and flags, include examples in command help, and follow Go's documentation conventions in Cobra command definitions

Applied to files:

  • cmd/terraform/backend/backend_commands_test.go
📚 Learning: 2025-01-09T22:37:01.004Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 914
File: cmd/terraform_commands.go:260-265
Timestamp: 2025-01-09T22:37:01.004Z
Learning: In the terraform commands implementation (cmd/terraform_commands.go), the direct use of `os.Args[2:]` for argument handling is intentionally preserved to avoid extensive refactoring. While it could be improved to use cobra's argument parsing, such changes should be handled in a dedicated PR to maintain focus and minimize risk.

Applied to files:

  • cmd/terraform/backend/backend_commands_test.go
  • cmd/terraform/backend/backend_helpers.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 **/*.go : Small focused files (<600 lines). One cmd/impl per file. Co-locate tests. Never use //revive:disable:file-length-limit.

Applied to files:

  • cmd/terraform/backend/backend_commands_test.go
  • cmd/terraform/backend/backend_helpers.go
📚 Learning: 2025-02-18T13:18:53.146Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1068
File: cmd/vendor_pull.go:31-31
Timestamp: 2025-02-18T13:18:53.146Z
Learning: Error checking is not required for cobra.Command.RegisterFlagCompletionFunc calls as these are static configurations done at init time.

Applied to files:

  • cmd/terraform/backend/backend_commands_test.go
📚 Learning: 2025-11-10T03:03:31.505Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-11-10T03:03:31.505Z
Learning: In the Atmos codebase, commands using the `StandardParser` flag pattern (from pkg/flags) do NOT need explicit `viper.BindPFlag()` calls in their code. The StandardParser encapsulates flag binding internally: flags are registered via `parser.RegisterFlags(cmd)` in init(), and bound via `parser.BindFlagsToViper(cmd, v)` in RunE, which internally calls viper.BindPFlag for each flag. This pattern is used throughout Atmos (e.g., cmd/toolchain/get.go, cmd/toolchain/info.go, cmd/toolchain/install.go, cmd/toolchain/path.go). Do not flag missing viper.BindPFlag calls when StandardParser is used.

Applied to files:

  • cmd/terraform/backend/backend_commands_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:

  • cmd/terraform/backend/backend_commands_test.go
📚 Learning: 2025-06-07T19:28:21.289Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1266
File: cmd/describe_affected.go:0-0
Timestamp: 2025-06-07T19:28:21.289Z
Learning: In the Atmos codebase, using panic for unsupported flag types in flag processing functions like setDescribeAffectedFlagValueInCliArgs is the expected behavior rather than returning errors. This pattern is preferred for developer errors when unsupported types are added to the flagsKeyValue map.

Applied to files:

  • cmd/terraform/backend/backend_commands_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:

  • cmd/terraform/backend/backend_commands_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 cmd/**/*.go : Use unified flag parsing infrastructure in pkg/flags/. Commands MUST use flags.NewStandardParser() for command-specific flags. NEVER call viper.BindEnv() or viper.BindPFlag() directly outside pkg/flags/ (Forbidigo enforces this).

Applied to files:

  • cmd/terraform/backend/backend_commands_test.go
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.

Applied to files:

  • cmd/terraform/backend/backend_helpers.go
📚 Learning: 2025-06-23T02:14:30.937Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1327
File: cmd/terraform.go:111-117
Timestamp: 2025-06-23T02:14:30.937Z
Learning: In cmd/terraform.go, flags for the DescribeAffected function are added dynamically at runtime when info.Affected is true. This is intentional to avoid exposing internal flags like "file", "format", "verbose", "include-spacelift-admin-stacks", "include-settings", and "upload" in the terraform command interface, while still providing them for the shared DescribeAffected function used by both `atmos describe affected` and `atmos terraform apply --affected`.

Applied to files:

  • cmd/terraform/backend/backend_helpers.go
📚 Learning: 2024-12-07T16:19:01.683Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 825
File: internal/exec/terraform.go:30-30
Timestamp: 2024-12-07T16:19:01.683Z
Learning: In `internal/exec/terraform.go`, skipping stack validation when help flags are present is not necessary.

Applied to files:

  • cmd/terraform/backend/backend_helpers.go
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.

Applied to files:

  • cmd/terraform/backend/backend_helpers.go
🧬 Code graph analysis (2)
cmd/terraform/backend/backend_test.go (2)
pkg/schema/schema.go (1)
  • AtmosConfiguration (53-94)
cmd/terraform/backend/backend.go (1)
  • GetBackendCommand (35-37)
cmd/terraform/backend/mock_backend_helpers_test.go (3)
cmd/terraform/backend/backend_helpers.go (1)
  • InitConfigAndAuth (117-162)
pkg/schema/schema.go (2)
  • AtmosConfiguration (53-94)
  • AuthContext (569-579)
pkg/provisioner/provisioner.go (3)
  • DeleteBackend (129-172)
  • DescribeBackend (116-122)
  • ListBackends (107-113)
🪛 LanguageTool
website/docs/cli/commands/terraform/terraform-backend.mdx

[style] ~136-~136: Since ownership is already implied, this phrasing may be redundant.
Context: ...-Level Identity Components can specify their own authentication identity with a default:...

(PRP_OWN)

website/docs/core-concepts/components/terraform/backend-provisioning.mdx

[typographical] ~235-~235: Consider using a typographic opening quote here.
Context: ...lves a classic chicken-and-egg problem: "How do I manage my state backend with Te...

(EN_QUOTES)


[typographical] ~235-~235: Consider using a typographic close quote here.
Context: ...ckend to exist before Terraform can run?" Traditional Workaround: 1. Use loc...

(EN_QUOTES)


[typographical] ~276-~276: Consider using a typographic opening quote here.
Context: ..."acme-terraform-state-prod" } resource "aws_s3_bucket" "terraform_state" { buc...

(EN_QUOTES)


[typographical] ~276-~276: Consider using a typographic close quote here.
Context: ...m-state-prod" } resource "aws_s3_bucket" "terraform_state" { bucket = "acme-te...

(EN_QUOTES)


[typographical] ~276-~276: Consider using a typographic opening quote here.
Context: ...state-prod" } resource "aws_s3_bucket" "terraform_state" { bucket = "acme-terr...

(EN_QUOTES)


[typographical] ~276-~276: Consider using a typographic close quote here.
Context: ...esource "aws_s3_bucket" "terraform_state" { bucket = "acme-terraform-state-prod...

(EN_QUOTES)


[typographical] ~281-~281: Consider using a typographic opening quote here.
Context: ...prod" } # Add lifecycle rules resource "aws_s3_bucket_lifecycle_configuration" "...

(EN_QUOTES)


[typographical] ~281-~281: Consider using a typographic close quote here.
Context: ...e "aws_s3_bucket_lifecycle_configuration" "terraform_state" { bucket = aws_s3_b...

(EN_QUOTES)


[typographical] ~281-~281: Consider using a typographic opening quote here.
Context: ..."aws_s3_bucket_lifecycle_configuration" "terraform_state" { bucket = aws_s3_buc...

(EN_QUOTES)


[typographical] ~281-~281: Consider using a typographic close quote here.
Context: ...ifecycle_configuration" "terraform_state" { bucket = aws_s3_bucket.terraform_st...

(EN_QUOTES)


[typographical] ~295-~295: Consider using a typographic opening quote here.
Context: ...lication for disaster recovery resource "aws_s3_bucket_replication_configuration"...

(EN_QUOTES)


[typographical] ~295-~295: Consider using a typographic close quote here.
Context: ..."aws_s3_bucket_replication_configuration" "terraform_state" { bucket = aws_s3_b...

(EN_QUOTES)


[typographical] ~295-~295: Consider using a typographic opening quote here.
Context: ...ws_s3_bucket_replication_configuration" "terraform_state" { bucket = aws_s3_buc...

(EN_QUOTES)


[typographical] ~295-~295: Consider using a typographic close quote here.
Context: ...lication_configuration" "terraform_state" { bucket = aws_s3_bucket.terraform_st...

(EN_QUOTES)

⏰ 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 (windows)
  • GitHub Check: Acceptance Tests (linux)
  • GitHub Check: Summary
🔇 Additional comments (22)
website/docs/quick-start/advanced/advanced.mdx (1)

25-26: LGTM! Link update aligns with documentation reorganization.

The updated link correctly points to the renamed remote-state documentation, matching the redirect configured in docusaurus.config.js.

website/docusaurus.config.js (1)

55-59: Good backward compatibility maintenance.

The redirect ensures old state-backend URLs continue working after the documentation reorganization. The inline comment helpfully explains the reason for the redirect.

website/docs/core-concepts/components/terraform/backend-provisioning.mdx (1)

1-349: Excellent comprehensive documentation.

This new page thoroughly covers automatic backend provisioning with:

  • Clear configuration examples at multiple hierarchy levels
  • Practical IAM permissions guidance
  • Well-explained bootstrap problem solution
  • Detailed migration path to Terraform-managed backends
  • Strong cross-references to related documentation

The structure follows Docusaurus conventions with proper frontmatter, Terminal components, and logical section flow. Code examples are syntactically correct.

website/docs/cli/commands/terraform/terraform-backend.mdx (1)

1-544: Thorough CLI reference documentation.

This comprehensive CLI reference correctly follows the Docusaurus conventions specified in coding guidelines:

  • Uses <dl> elements for arguments and flags (lines 23-38, 109-128)
  • Includes frontmatter with purpose note (lines 1-13)
  • Provides usage examples and practical scenarios
  • Documents error handling with exit codes table
  • Cross-references related commands and concepts

The intentional content overlap with backend-provisioning.mdx (IAM permissions, migration guide) is appropriate since this serves as CLI reference while the other provides conceptual guidance.

As per coding guidelines, verify CLI help text stays in sync with this documentation when running atmos terraform backend --help.

website/docs/core-concepts/components/terraform/remote-state.mdx (3)

2-6: Improved focus and clarity.

The updated title and description better emphasize this page's specific purpose: configuring remote state access for reading other components' outputs. This aligns well with the documentation reorganization.


16-20: Strong cross-referencing.

The new Related Documentation tip block helps readers navigate between backend storage configuration, automatic provisioning, and remote state usage—a logical flow that makes the documentation ecosystem more discoverable.


92-97: Good addition of references section.

Consolidating related documentation links at the end provides a helpful jumping-off point for readers who want to explore related concepts after understanding remote state configuration.

cmd/terraform/backend/backend_create_test.go (1)

7-15: Solid structure test.

Clean and minimal. The helper-based approach keeps tests DRY across the backend commands.

cmd/terraform/backend/backend_update_test.go (1)

7-15: Consistent with sibling command tests.

Follows the established pattern. Good.

cmd/terraform/backend/backend_test.go (2)

11-25: Clean config wiring test.

Save/restore pattern with defer ensures test isolation. Straightforward assertions.


27-51: Thorough command structure verification.

Validates parent command and subcommand registration. The map-based Use field check is a practical approach.

cmd/terraform/backend/backend_commands_test.go (8)

18-38: Well-designed test helper.

Clean setup with proper cleanup registration. The t.Helper() call ensures stack traces point to the actual test.


40-64: Good viper state isolation.

Capturing and restoring viper state prevents test pollution. Solid pattern for tests that modify global config.


66-184: Comprehensive table-driven provision tests.

Covers the key scenarios: success, missing required flag, config init failure, provision failure, and auth context propagation. Good use of gomock expectations.


186-300: Delete command well covered.

Tests both force=true and force=false paths along with error scenarios. Matches the pattern of other command tests.


302-416: Describe command tests look solid.

Format variations (yaml/json) and error paths covered.


418-532: List command tests complete the set.

Consistent pattern with describe tests. Good coverage.


534-596: DI helper tests validate the wiring.

Type assertions in TestResetDependencies confirm defaults are restored correctly. Simple but necessary.


598-619: Flag parsing validation.

TestParseCommonFlags_Success confirms the parser extracts expected values. Could add a negative case, but acceptable for initial coverage.

cmd/terraform/backend/mock_backend_helpers_test.go (1)

1-17: Generated mock file correctly uses //go:generate directive.

Verification confirms the //go:generate directive is properly in place at line 3 of backend_helpers.go:

//go:generate go run go.uber.org/mock/[email protected] -source=backend_helpers.go -destination=mock_backend_helpers_test.go -package=backend

The mock file is correctly generated using go.uber.org/mock/mockgen as required by coding guidelines. No issues found.

cmd/terraform/backend/backend_helpers.go (2)

23-84: Nice dependency injection + mocking setup.

Interfaces (ConfigInitializer, Provisioner), default implementations, and the Set*/ResetDependencies hooks give you clean seams for testing and keep cmd wiring thin. The mockgen directive is aligned with the repo’s “no manual mocks” guidance. No changes needed here.


93-111: I'll verify the review comment by examining the actual code and error handling patterns in the backend helpers file and the error sentinels available.
<function_calls>

find . -type f -name "backend_helpers.go" | head -5

</function_calls>
<function_calls>

wc -l cmd/terraform/backend/backend_helpers.go

</function_calls>
<function_calls>

cat -n cmd/terraform/backend/backend_helpers.go | head -170

</function_calls>
<function_calls>

find . -type f -name "errors.go" -path "/errors/" | head -5

</function_calls>
<function_calls>

wc -l pkg/errors/errors.go

</function_calls>
<function_calls>

cat -n pkg/errors/errors.go

</function_calls>

Comment on lines +178 to +213
// ExecuteProvisionCommand is the shared RunE implementation for create and update commands.
// Both operations are idempotent - they provision or update the backend to match the desired state.
func ExecuteProvisionCommand(cmd *cobra.Command, args []string, parser *flags.StandardParser, perfLabel string) error {
defer perf.Track(atmosConfigPtr, perfLabel)()

component := args[0]

// Parse common flags.
opts, err := ParseCommonFlags(cmd, parser)
if err != nil {
return err
}

// Initialize config and auth using injected dependency.
atmosConfig, authContext, err := configInit.InitConfigAndAuth(component, opts.Stack, opts.Identity)
if err != nil {
return err
}

// Create describe component callback.
// Note: We don't need to pass authContext to the describe function for backend provisioning
// since we already loaded the component config in InitConfigAndAuth.
describeFunc := func(component, stack string) (map[string]any, error) {
return e.ExecuteDescribeComponent(&e.ExecuteDescribeComponentParams{
Component: component,
Stack: stack,
ProcessTemplates: false,
ProcessYamlFunctions: false,
Skip: nil,
AuthManager: nil, // Auth already handled
})
}

// Execute provision command using injected provisioner.
return prov.CreateBackend(atmosConfig, component, opts.Stack, describeFunc, authContext)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find files that use ExecuteProvisionCommand
rg -r "ExecuteProvisionCommand" cmd/terraform/backend/ -n -B 5 -A 2

Repository: cloudposse/atmos

Length of output: 42


🏁 Script executed:

# Read the specific file to check the comment and understand the context
cat -n cmd/terraform/backend/backend_helpers.go | sed -n '178,213p'

Repository: cloudposse/atmos

Length of output: 1715


🏁 Script executed:

# Also search for the command definition that might use this function
find cmd/terraform/backend -name "*.go" -type f | head -20

Repository: cloudposse/atmos

Length of output: 786


🏁 Script executed:

# Check backend_create.go for command definition and how ExecuteProvisionCommand is called
rg -n "ExecuteProvisionCommand\|Args:" cmd/terraform/backend/backend_create.go -B 5 -A 2

Repository: cloudposse/atmos

Length of output: 42


🏁 Script executed:

# Check backend_update.go for command definition and how ExecuteProvisionCommand is called
rg -n "ExecuteProvisionCommand\|Args:" cmd/terraform/backend/backend_update.go -B 5 -A 2

Repository: cloudposse/atmos

Length of output: 42


🏁 Script executed:

# Let's see the full command definition in backend_create.go
head -100 cmd/terraform/backend/backend_create.go | tail -70

Repository: cloudposse/atmos

Length of output: 979


🏁 Script executed:

# Check backend_update.go for command definition
head -100 cmd/terraform/backend/backend_update.go

Repository: cloudposse/atmos

Length of output: 1040


Comment period needs fixing; args access is already guarded by Cobra.

The args safety concern doesn't apply here—both createCmd and updateCmd enforce Args: cobra.ExactArgs(1), so args[0] (line 183) is guaranteed to be safe.

However, the comment on lines 198–199 is missing a period at the end:

  // Create describe component callback.
- // Note: We don't need to pass authContext to the describe function for backend provisioning
+ // Note: We don't need to pass authContext to the describe function for backend provisioning.
  // since we already loaded the component config in InitConfigAndAuth.

This will trigger the godot linter. Add a period to line 198 to resolve.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// ExecuteProvisionCommand is the shared RunE implementation for create and update commands.
// Both operations are idempotent - they provision or update the backend to match the desired state.
func ExecuteProvisionCommand(cmd *cobra.Command, args []string, parser *flags.StandardParser, perfLabel string) error {
defer perf.Track(atmosConfigPtr, perfLabel)()
component := args[0]
// Parse common flags.
opts, err := ParseCommonFlags(cmd, parser)
if err != nil {
return err
}
// Initialize config and auth using injected dependency.
atmosConfig, authContext, err := configInit.InitConfigAndAuth(component, opts.Stack, opts.Identity)
if err != nil {
return err
}
// Create describe component callback.
// Note: We don't need to pass authContext to the describe function for backend provisioning
// since we already loaded the component config in InitConfigAndAuth.
describeFunc := func(component, stack string) (map[string]any, error) {
return e.ExecuteDescribeComponent(&e.ExecuteDescribeComponentParams{
Component: component,
Stack: stack,
ProcessTemplates: false,
ProcessYamlFunctions: false,
Skip: nil,
AuthManager: nil, // Auth already handled
})
}
// Execute provision command using injected provisioner.
return prov.CreateBackend(atmosConfig, component, opts.Stack, describeFunc, authContext)
}
// ExecuteProvisionCommand is the shared RunE implementation for create and update commands.
// Both operations are idempotent - they provision or update the backend to match the desired state.
func ExecuteProvisionCommand(cmd *cobra.Command, args []string, parser *flags.StandardParser, perfLabel string) error {
defer perf.Track(atmosConfigPtr, perfLabel)()
component := args[0]
// Parse common flags.
opts, err := ParseCommonFlags(cmd, parser)
if err != nil {
return err
}
// Initialize config and auth using injected dependency.
atmosConfig, authContext, err := configInit.InitConfigAndAuth(component, opts.Stack, opts.Identity)
if err != nil {
return err
}
// Create describe component callback.
// Note: We don't need to pass authContext to the describe function for backend provisioning.
// since we already loaded the component config in InitConfigAndAuth.
describeFunc := func(component, stack string) (map[string]any, error) {
return e.ExecuteDescribeComponent(&e.ExecuteDescribeComponentParams{
Component: component,
Stack: stack,
ProcessTemplates: false,
ProcessYamlFunctions: false,
Skip: nil,
AuthManager: nil, // Auth already handled
})
}
// Execute provision command using injected provisioner.
return prov.CreateBackend(atmosConfig, component, opts.Stack, describeFunc, authContext)
}
🤖 Prompt for AI Agents
In cmd/terraform/backend/backend_helpers.go around lines 178-213, update the
inline comment on lines 198-199 by adding a period at the end of the sentence
(i.e., make "Auth already handled" into "Auth already handled.") to satisfy the
godot linter; leave the surrounding code and other comments unchanged.

Move the separate Terraform and OpenTofu backend lists into tabbed
interface for better organization and cleaner presentation.

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

Co-Authored-By: Claude <[email protected]>
…s value

- Replace DynamoDB locking with `use_lockfile: true` (Terraform 1.10+/OpenTofu 1.8+)
- Rewrite intro to "Why Use Atmos for Backend Configuration?" - focuses on value
  proposition rather than outdated Terraform limitations
- Add explanation that backend.s3 section is serialized verbatim to JSON
- Remove CloudPosse-specific _defaults.yaml convention note
- Update remote-state.mdx and configure-terraform-backend.mdx for consistency

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

Co-Authored-By: Claude <[email protected]>
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)
website/docs/core-concepts/components/terraform/backends.mdx (1)

430-431: Minor wording refinement opportunity.

Line 431 says "Each account needs to have a separate S3 bucket and IAM role with different permissions" but doesn't mention use_lockfile like the examples below do. Consider adding use_lockfile: true to the explanatory text to emphasize it as part of the modern pattern.

📜 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 0d40d27 and a3a2b95.

📒 Files selected for processing (3)
  • website/docs/core-concepts/components/terraform/backends.mdx (16 hunks)
  • website/docs/core-concepts/components/terraform/remote-state.mdx (4 hunks)
  • website/docs/quick-start/advanced/configure-terraform-backend.mdx (10 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
website/**

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

website/**: Update website documentation in the website/ directory when adding new features, ensure consistency between CLI help text and website documentation, and follow the website's documentation structure and style
Keep website code in the website/ directory, follow the existing website architecture and style, and test website changes locally before committing
Keep CLI documentation and website documentation in sync and document new features on the website with examples and use cases

Files:

  • website/docs/quick-start/advanced/configure-terraform-backend.mdx
  • website/docs/core-concepts/components/terraform/backends.mdx
  • website/docs/core-concepts/components/terraform/remote-state.mdx
🧠 Learnings (7)
📓 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-04-25T20:54:19.701Z
Learnt from: mcalhoun
Repo: cloudposse/atmos PR: 963
File: website/docs/core-concepts/projects/configuration/stores.mdx:286-286
Timestamp: 2025-04-25T20:54:19.701Z
Learning: For the AWS SSM Parameter Store implementation in Atmos, support for `read_role_arn` and `write_role_arn` options is essential to enable cross-account access, allowing users to run operations like `terraform plan` in multiple accounts while accessing values across keystores. Azure Key Vault would need similar capabilities for cross-tenant/subscription authentication.

Applied to files:

  • website/docs/quick-start/advanced/configure-terraform-backend.mdx
  • website/docs/core-concepts/components/terraform/backends.mdx
  • website/docs/core-concepts/components/terraform/remote-state.mdx
📚 Learning: 2025-01-25T03:51:57.689Z
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.

Applied to files:

  • website/docs/core-concepts/components/terraform/backends.mdx
📚 Learning: 2025-03-18T12:26:25.329Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 1149
File: tests/snapshots/TestCLICommands_atmos_vendor_pull_ssh.stderr.golden:7-7
Timestamp: 2025-03-18T12:26:25.329Z
Learning: In the Atmos project, typos or inconsistencies in test snapshot files (such as "terrafrom" instead of "terraform") may be intentional as they capture the exact output of commands and should not be flagged as issues requiring correction.

Applied to files:

  • website/docs/core-concepts/components/terraform/backends.mdx
📚 Learning: 2024-12-01T00:33:20.298Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml:28-32
Timestamp: 2024-12-01T00:33:20.298Z
Learning: In `examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml`, `!exec atmos terraform output` is used in examples to demonstrate its usage, even though `!terraform.output` is the recommended approach according to the documentation.

Applied to files:

  • website/docs/core-concepts/components/terraform/backends.mdx
📚 Learning: 2025-10-07T00:25:16.333Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1498
File: website/src/components/Screengrabs/atmos-terraform-metadata--help.html:25-55
Timestamp: 2025-10-07T00:25:16.333Z
Learning: In Atmos CLI, subcommands inherit flags from their parent commands via Cobra's command inheritance. For example, `atmos terraform metadata --help` shows `--affected` and related flags inherited from the parent `terraform` command (defined in cmd/terraform.go), even though the metadata subcommand doesn't explicitly define these flags. This is expected Cobra behavior and auto-generated help screengrabs accurately reflect this inheritance.

Applied to files:

  • website/docs/core-concepts/components/terraform/backends.mdx
📚 Learning: 2024-12-17T07:10:26.295Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 863
File: internal/exec/stack_utils.go:201-223
Timestamp: 2024-12-17T07:10:26.295Z
Learning: Unit tests for remote state backend functionality are located in the `examples/tests` directory.

Applied to files:

  • website/docs/core-concepts/components/terraform/remote-state.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 (linux)
  • GitHub Check: Acceptance Tests (macos)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Summary
🔇 Additional comments (9)
website/docs/quick-start/advanced/configure-terraform-backend.mdx (2)

92-95: Clear native S3 locking guidance.

The new callout effectively directs users to modern locking while providing a legacy path. Placement after the backend example is intuitive.


101-104: Good cross-reference to backend provisioning.

The tip clearly positions automatic provisioning as the recommended path and links to new documentation. Consider verifying the link target /core-concepts/components/terraform/backend-provisioning exists in the PR.

website/docs/core-concepts/components/terraform/remote-state.mdx (2)

16-20: Well-organized Related Documentation section.

Three linked docs provide clear navigation to related concepts. Good use of tip component to encourage cross-linking.


33-90: Clear override pattern documentation.

The example effectively demonstrates read-only role assumption for remote state access. The note (lines 89-90) clarifying when each role is used is particularly helpful for understanding the design.

website/docs/core-concepts/components/terraform/backends.mdx (5)

59-79: Strong value proposition section.

"Why Use Atmos for Backend Configuration?" clearly explains benefits (DRY, no backend.tf in modules, Terraform+OpenTofu support, automatic provisioning). The subsections logically separate concerns. This helps users understand the motivation for the feature.


106-225: Excellent Tab-based structure for backend approaches.

Marking "Atmos-Managed" as default and providing "Manual HCL" as an alternative is the right UX. The warning (lines 218-222) about inheritance and multiple instance limitations for manual approach is important context.


112-123: Terminal component usage.

Using <Terminal> for configuration blocks is consistent with the quick-start file. This is good for visual consistency across website docs.


145-147: Clarifying backend attribute compatibility.

The note that any valid S3 backend attribute works (pass-through model) is important documentation. Users know they're not limited to a predefined schema.


651-654: Updated References section is complete.

All four references are present and relevant (Remote State, Backend Provisioning, official Terraform/OpenTofu docs, and design patterns). Good parallel structure to remote-state.mdx References.

Update all acme-* bucket examples to use Cloud Posse's null label
convention: {namespace}-{environment}-{stage}-{name}

Changes:
- acme-terraform-state-dev → acme-ue1-dev-tfstate
- acme-terraform-state-prod → acme-ue1-prod-tfstate
- acme-terraform-state → acme-gbl-root-tfstate
- Add cross-account support note to backends.mdx
- Add "Reuse Root Modules" bullet point

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

Co-Authored-By: Claude <[email protected]>
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: 1

📜 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 a3a2b95 and a61b9bb.

📒 Files selected for processing (5)
  • website/docs/cli/commands/terraform/terraform-backend.mdx (1 hunks)
  • website/docs/core-concepts/components/terraform/backend-provisioning.mdx (1 hunks)
  • website/docs/core-concepts/components/terraform/backends.mdx (16 hunks)
  • website/docs/core-concepts/components/terraform/remote-state.mdx (4 hunks)
  • website/docs/design-patterns/defaults-pattern.mdx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/docs/core-concepts/components/terraform/remote-state.mdx
🧰 Additional context used
📓 Path-based instructions (2)
website/**

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

website/**: Update website documentation in the website/ directory when adding new features, ensure consistency between CLI help text and website documentation, and follow the website's documentation structure and style
Keep website code in the website/ directory, follow the existing website architecture and style, and test website changes locally before committing
Keep CLI documentation and website documentation in sync and document new features on the website with examples and use cases

Files:

  • website/docs/core-concepts/components/terraform/backend-provisioning.mdx
  • website/docs/core-concepts/components/terraform/backends.mdx
  • website/docs/design-patterns/defaults-pattern.mdx
  • website/docs/cli/commands/terraform/terraform-backend.mdx
website/docs/cli/commands/**/*.mdx

📄 CodeRabbit inference engine (CLAUDE.md)

website/docs/cli/commands/**/*.mdx: All commands and flags need Docusaurus documentation in website/docs/cli/commands/. Use

for arguments/flags. Build website after changes: cd website && npm run build.
Use Docusaurus conventions with frontmatter, purpose note, screengrab, usage/examples/arguments/flags sections for CLI command documentation.

Files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
🧠 Learnings (7)
📓 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-04-25T20:54:19.701Z
Learnt from: mcalhoun
Repo: cloudposse/atmos PR: 963
File: website/docs/core-concepts/projects/configuration/stores.mdx:286-286
Timestamp: 2025-04-25T20:54:19.701Z
Learning: For the AWS SSM Parameter Store implementation in Atmos, support for `read_role_arn` and `write_role_arn` options is essential to enable cross-account access, allowing users to run operations like `terraform plan` in multiple accounts while accessing values across keystores. Azure Key Vault would need similar capabilities for cross-tenant/subscription authentication.

Applied to files:

  • website/docs/core-concepts/components/terraform/backend-provisioning.mdx
  • website/docs/core-concepts/components/terraform/backends.mdx
📚 Learning: 2024-12-01T00:33:20.298Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml:28-32
Timestamp: 2024-12-01T00:33:20.298Z
Learning: In `examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml`, `!exec atmos terraform output` is used in examples to demonstrate its usage, even though `!terraform.output` is the recommended approach according to the documentation.

Applied to files:

  • website/docs/core-concepts/components/terraform/backends.mdx
📚 Learning: 2025-10-07T00:25:16.333Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1498
File: website/src/components/Screengrabs/atmos-terraform-metadata--help.html:25-55
Timestamp: 2025-10-07T00:25:16.333Z
Learning: In Atmos CLI, subcommands inherit flags from their parent commands via Cobra's command inheritance. For example, `atmos terraform metadata --help` shows `--affected` and related flags inherited from the parent `terraform` command (defined in cmd/terraform.go), even though the metadata subcommand doesn't explicitly define these flags. This is expected Cobra behavior and auto-generated help screengrabs accurately reflect this inheritance.

Applied to files:

  • website/docs/core-concepts/components/terraform/backends.mdx
  • website/docs/cli/commands/terraform/terraform-backend.mdx
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.

Applied to files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
📚 Learning: 2024-12-03T04:01:16.446Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:0-0
Timestamp: 2024-12-03T04:01:16.446Z
Learning: In the `terraform.output.mdx` documentation file (`website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx`), the cache invalidation and cache scope behavior for the `!terraform.output` function are already described.

Applied to files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
📚 Learning: 2024-12-03T05:29:07.718Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: internal/exec/terraform_utils.go:145-146
Timestamp: 2024-12-03T05:29:07.718Z
Learning: In the Atmos project, a 5-minute timeout in the `execTerraformOutput` function is acceptable for retrieving `terraform output` for a component in a stack.

Applied to files:

  • website/docs/cli/commands/terraform/terraform-backend.mdx
🪛 LanguageTool
website/docs/core-concepts/components/terraform/backend-provisioning.mdx

[typographical] ~235-~235: Consider using a typographic opening quote here.
Context: ...lves a classic chicken-and-egg problem: "How do I manage my state backend with Te...

(EN_QUOTES)


[typographical] ~235-~235: Consider using a typographic close quote here.
Context: ...ckend to exist before Terraform can run?" Traditional Workaround: 1. Use loc...

(EN_QUOTES)


[typographical] ~276-~276: Consider using a typographic opening quote here.
Context: ...d = "acme-ue1-prod-tfstate" } resource "aws_s3_bucket" "terraform_state" { buc...

(EN_QUOTES)


[typographical] ~276-~276: Consider using a typographic close quote here.
Context: ...prod-tfstate" } resource "aws_s3_bucket" "terraform_state" { bucket = "acme-ue...

(EN_QUOTES)


[typographical] ~276-~276: Consider using a typographic opening quote here.
Context: ...od-tfstate" } resource "aws_s3_bucket" "terraform_state" { bucket = "acme-ue1-...

(EN_QUOTES)


[typographical] ~276-~276: Consider using a typographic close quote here.
Context: ...esource "aws_s3_bucket" "terraform_state" { bucket = "acme-ue1-prod-tfstate" } ...

(EN_QUOTES)


[typographical] ~281-~281: Consider using a typographic opening quote here.
Context: ...tate" } # Add lifecycle rules resource "aws_s3_bucket_lifecycle_configuration" "...

(EN_QUOTES)


[typographical] ~281-~281: Consider using a typographic close quote here.
Context: ...e "aws_s3_bucket_lifecycle_configuration" "terraform_state" { bucket = aws_s3_b...

(EN_QUOTES)


[typographical] ~281-~281: Consider using a typographic opening quote here.
Context: ..."aws_s3_bucket_lifecycle_configuration" "terraform_state" { bucket = aws_s3_buc...

(EN_QUOTES)


[typographical] ~281-~281: Consider using a typographic close quote here.
Context: ...ifecycle_configuration" "terraform_state" { bucket = aws_s3_bucket.terraform_st...

(EN_QUOTES)


[typographical] ~295-~295: Consider using a typographic opening quote here.
Context: ...lication for disaster recovery resource "aws_s3_bucket_replication_configuration"...

(EN_QUOTES)


[typographical] ~295-~295: Consider using a typographic close quote here.
Context: ..."aws_s3_bucket_replication_configuration" "terraform_state" { bucket = aws_s3_b...

(EN_QUOTES)


[typographical] ~295-~295: Consider using a typographic opening quote here.
Context: ...ws_s3_bucket_replication_configuration" "terraform_state" { bucket = aws_s3_buc...

(EN_QUOTES)


[typographical] ~295-~295: Consider using a typographic close quote here.
Context: ...lication_configuration" "terraform_state" { bucket = aws_s3_bucket.terraform_st...

(EN_QUOTES)

website/docs/cli/commands/terraform/terraform-backend.mdx

[style] ~136-~136: Since ownership is already implied, this phrasing may be redundant.
Context: ...-Level Identity Components can specify their own authentication identity with a default:...

(PRP_OWN)

⏰ 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
🔇 Additional comments (8)
website/docs/design-patterns/defaults-pattern.mdx (1)

204-214: Consistent backend configuration updates.

The example aligns well with the broader shift to native S3 locking (use_lockfile: true) and away from DynamoDB-based state locking. The bucket naming convention is clear.

website/docs/cli/commands/terraform/terraform-backend.mdx (1)

1-13: Comprehensive CLI documentation with strong structure.

Excellent use of Docusaurus conventions: frontmatter, purpose note, <dl> tags for args/flags, terminal code blocks, and cross-references. The documentation covers manual provisioning, automatic flows, authentication, and migration paths clearly.

website/docs/core-concepts/components/terraform/backend-provisioning.mdx (1)

1-349: Well-structured core concepts guide with practical guidance.

Clear hierarchy from configuration through IAM permissions and migration patterns. Terminal component usage is consistent, examples are concrete, and the deep-merge behavior is well-explained. The idempotent operations section with realistic output is helpful for users understanding the tool's behavior.

website/docs/core-concepts/components/terraform/backends.mdx (5)

1-57: Clean structural reorganization with Tabs component.

The split between Terraform and OpenTofu backends using Tabs provides good clarity without duplication. Added cross-reference to Backend Provisioning docs is well-placed. Related Documentation tip at the top improves navigation.


59-81: Excellent value proposition for Atmos-managed backends.

Clear distinction between DRY configuration benefits and provisioning capabilities. The comparison of reusing modules across environments is concrete. Cross-reference to Backend Provisioning docs for details is appropriate.


108-227: Well-structured Tabs approach with clear guidance for both paths.

The Atmos-Managed tab provides actionable step-by-step guidance, and the generated output example shows the result clearly. The Manual HCL tab appropriately warns about limitations. All examples now correctly use use_lockfile: true instead of DynamoDB locking.


430-651: Comprehensive examples of deep-merge and multi-instance configurations.

The Backend Inheritance section cleanly demonstrates configuration split across organizational hierarchy levels with the merged result. Multiple Component Instances section clearly explains why auto-generated backends are essential. All examples consistently updated to use use_lockfile: true.


653-660: Updated References section appropriately links to new content.

New cross-references to Remote State and Backend Provisioning docs are well-placed for user navigation.

description: Manage Terraform state backend infrastructure
---

import Screengrab from '@site/src/components/Screengrab'
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the full content of the file under review
cat -n website/docs/cli/commands/terraform/terraform-backend.mdx

Repository: cloudposse/atmos

Length of output: 17689


🏁 Script executed:

#!/bin/bash
# Check other similar CLI command documentation files to see how Screengrab is used
fd -t f 'terraform.*\.mdx$' website/docs/cli/commands/ | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && head -20 {}'

Repository: cloudposse/atmos

Length of output: 3303


Remove the unused Screengrab import.

The Screengrab component is imported on line 9 but is not used anywhere in the document. Unlike other CLI command documentation files (e.g., terraform-apply.mdx, terraform-clean.mdx), which both import and use <Screengrab> to display CLI help output, this file contains only the import statement without any corresponding component usage.

-import Screengrab from '@site/src/components/Screengrab'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import Screengrab from '@site/src/components/Screengrab'
🤖 Prompt for AI Agents
In website/docs/cli/commands/terraform/terraform-backend.mdx around line 9, the
Screengrab component is imported but never used; remove the unused import
statement (import Screengrab from '@site/src/components/Screengrab') so the file
matches other CLI docs and avoids an unnecessary unused import.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor New features that do not break anything needs-cloudposse Needs Cloud Posse assistance size/xl Extra large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants