Skip to content

feat: Add automatic backend provisioning#1808

Merged
aknysh merged 71 commits intomainfrom
osterman/auto-backend-provision
Dec 13, 2025
Merged

feat: Add automatic backend provisioning#1808
aknysh merged 71 commits intomainfrom
osterman/auto-backend-provision

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 noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • New "terraform backend" CLI with create/list/describe/update/delete and automatic backend provisioning (secure-by-default S3, cross-account support) plus a pre-Terraform-init hook to run provisioners.
  • Documentation

    • Multiple PRDs, website guides, and a blog post covering provisioning architecture, configs, examples, CLI usage, and migration guidance.
  • Bug Fixes

    • Help output printing now safely handles empty descriptions.
  • Tests

    • Extensive tests for provisioning flows, S3 create/delete, CLI commands, registry/hook execution, and deletion workflows.

✏️ 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 <noreply@anthropic.com>
@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 an in-process backend provisioning system and CLI for Terraform state backends, registers and executes provisioner hooks before Terraform init, implements S3 create/delete provisioners (AWS interactions, assume-role support), provides CLI DI/helpers and tests, and wires a new atmos terraform backend command with Atmos config propagation.

Changes

Cohort / File(s) Summary
Backend provisioning core
pkg/provisioner/backend/backend.go, pkg/provisioner/backend/s3.go, pkg/provisioner/backend/s3_delete.go, pkg/provisioner/backend/*_test.go
Registry for backend create/delete functions; ProvisionBackend orchestration; S3 implementation (create: ensure bucket, versioning, encryption, public access, tags; delete: list/delete objects & versions, delete bucket) with AWS client abstractions, auth/assume-role support, and extensive unit tests/mocks.
Provisioner framework & registry
pkg/provisioner/provisioner.go, pkg/provisioner/registry.go, pkg/provisioner/*_test.go
New provisioner model, ProvisionWithParams/DeleteBackend flows, HookEvent type and constants, Register/Get/Execute provisioners, execution semantics (fail-fast, perf tracking), timeouts and tests for concurrency, context and auth propagation.
Terraform execution hooks
internal/exec/terraform.go, pkg/hooks/event.go
Adds BeforeTerraformInit hook constant and invokes provisioner.ExecuteProvisioners(before.terraform.init) with 5-minute timeouts at multiple pre-init code paths.
CLI backend commands
cmd/terraform/backend/backend.go, cmd/terraform/backend/backend_*.go, cmd/terraform_commands.go, cmd/root.go
Adds atmos terraform backend command and subcommands (create, list, describe, update, delete); exposes SetAtmosConfig to propagate Atmos config into backend CLI; registers backend command with terraform parent.
CLI helpers & DI
cmd/terraform/backend/backend_helpers.go, cmd/terraform/backend/mock_backend_helpers_test.go, cmd/terraform/backend/backend_test_helpers.go
Introduces ConfigInitializer and Provisioner interfaces, default adapters, SetConfigInitializer/SetProvisioner/ResetDependencies, CommonOptions/ParseCommonFlags, InitConfigAndAuth, CreateDescribeComponentFunc, ExecuteProvisionCommand, and related tests/mocks.
CLI command tests & snapshots
cmd/terraform/backend/*_test.go, cmd/terraform/backend/backend_commands_test.go, tests/snapshots/*terraform*.golden
Extensive CLI tests for structure, flags, RunE flows; gomock-generated mocks; updated help/CLI snapshots to include the new backend subcommand.
Errors
errors/errors.go
Adds and reorganizes backend-provisioning sentinel errors (validation, AWS ops, deletion/force/state checks, access denied, etc.).
TUI/help formatting & tests
internal/tui/templates/help_printer.go, internal/tui/templates/help_printer_test.go
Guarded help-line printing to avoid out-of-bounds when descriptions are empty; tests and updated snapshots.
Docs / PRDs / Website
docs/prd/*, website/docs/**, website/blog/*.mdx, website/docusaurus.config.js
New PRDs and user docs describing automatic backend provisioning, updated tutorials (use_lockfile), redirects, blog post, and many documentation reorganizations.
Misc / tooling & small edits
.golangci.yml, pkg/config/load_flags_test.go, demo/screengrabs/demo-stacks.txt, CLAUDE.md
Linter exclusion for backend provisioner package, minor test comment tweaks, updated demo screengrabs, and doc-style guidance updates.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant CLI as "atmos CLI"
    participant BackendCmd as "backend subcommand"
    participant Config as "InitConfigAndAuth"
    participant Prov as "Provisioner (ProvisionWithParams)"
    participant BackendPkg as "pkg/provisioner/backend"
    participant Registry as "Provisioner Registry"
    participant S3 as "S3 Provisioner"
    participant AWS

    User->>CLI: atmos terraform backend create <component>
    CLI->>BackendCmd: dispatch create command
    BackendCmd->>Config: Parse flags → InitConfigAndAuth(component, stack, identity)
    Config-->>BackendCmd: return atmosConfig + authContext + componentConfig
    BackendCmd->>Prov: call ProvisionWithParams(...)
    Prov->>BackendPkg: ProvisionBackend(ctx, atmosConfig, componentConfig, authContext)
    BackendPkg->>Registry: GetBackendCreate(backend_type)
    Registry->>S3: invoke CreateS3Backend(ctx,...)
    S3->>AWS: load creds / assume role (if configured)
    AWS-->>S3: creds
    S3->>AWS: HeadBucket
    alt bucket missing
        S3->>AWS: CreateBucket
    end
    S3->>AWS: PutBucketVersioning / PutBucketEncryption / PutPublicAccessBlock / PutBucketTagging
    AWS-->>S3: ops success
    S3-->>BackendPkg: success
    BackendPkg-->>Prov: success
    Prov-->>BackendCmd: success
    BackendCmd-->>User: success message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Points to focus review on:

  • pkg/provisioner/backend/s3.go and pkg/provisioner/backend/s3_delete.go: AWS SDK usage, assume-role logic, region-specific CreateBucket behavior, pagination and batched deletes, and error wrapping/retry considerations.
  • pkg/provisioner/registry.go and pkg/provisioner/provisioner.go: concurrency correctness, registration semantics, ExecuteProvisioners fail-fast behavior, timeout usage and context propagation.
  • cmd/terraform/backend/backend_helpers.go and cmd/terraform/backend/*: InitConfigAndAuth, DI boundaries, flag/Viper binding, ExecuteProvisionCommand flow, and test/mock wiring.
  • internal/exec/terraform.go and pkg/hooks/event.go: placement and semantics of BeforeTerraformInit hook calls across pre-init paths and error handling.
  • errors/errors.go: ensure sentinel errors align with callers and are used consistently across provisioner modules and tests.

Possibly related PRs

Suggested reviewers

  • osterman

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.45% 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 clearly and concisely describes the main feature being added: automatic backend provisioning. It directly reflects the core functionality implemented across the changeset.
✨ 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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Add provision command to help output snapshots.

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

Co-Authored-By: Claude <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Nov 21, 2025

Codecov Report

❌ Patch coverage is 75.57355% with 181 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.31%. Comparing base (2f28bdc) to head (3e43c02).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
cmd/terraform/backend/backend_helpers.go 29.46% 74 Missing and 5 partials ⚠️
pkg/provisioner/backend/s3_delete.go 68.94% 49 Missing and 1 partial ⚠️
pkg/provisioner/backend/s3.go 82.94% 29 Missing ⚠️
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 ⚠️
internal/exec/terraform.go 60.00% 2 Missing and 2 partials ⚠️
internal/tui/templates/help_printer.go 40.00% 1 Missing and 2 partials ⚠️
cmd/terraform/backend/backend_delete.go 93.54% 1 Missing and 1 partial ⚠️
cmd/terraform/backend/backend_describe.go 91.30% 1 Missing and 1 partial ⚠️
cmd/terraform/backend/backend_list.go 90.90% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1808      +/-   ##
==========================================
+ Coverage   73.27%   73.31%   +0.04%     
==========================================
  Files         551      563      +12     
  Lines       53458    54195     +737     
==========================================
+ Hits        39170    39735     +565     
- Misses      11442    11607     +165     
- Partials     2846     2853       +7     
Flag Coverage Δ
unittests 73.31% <75.57%> (+0.04%) ⬆️

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

Files with missing lines Coverage Δ
cmd/root.go 63.98% <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/provisioner.go 100.00% <100.00%> (ø)
pkg/provisioner/registry.go 100.00% <100.00%> (ø)
cmd/terraform/backend/backend_delete.go 93.54% <93.54%> (ø)
cmd/terraform/backend/backend_describe.go 91.30% <91.30%> (ø)
cmd/terraform/backend/backend_list.go 90.90% <90.90%> (ø)
... 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 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 23, 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: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
website/docs/components/terraform/backends.mdx (1)

1-200: Test website build with documentation changes.

Per coding guidelines, all documentation changes in website/**/*.mdx must be tested locally. Run cd website && npm run build to verify no broken links, missing images, or component rendering issues.

♻️ Duplicate comments (5)
cmd/terraform/backend/backend_helpers_test.go (1)

15-91: Global Viper mutation in tests remains brittle; DI would isolate better.

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

369-612: Fix markdownlint blockers (tabs + “emphasis as heading”) to prevent docs CI failures.

Also applies to: 867-969, 1429-1433

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

51-190: Fix markdownlint issues (tabs/missing fence languages/MD036 headings) to keep docs lint green.

Also applies to: 339-352, 918-932, 1058-1065

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

45-87: Fix markdownlint blockers (tabs + fence languages + MD036 headings).

Also applies to: 359-372, 417-437, 996-1058, 1247-1261


182-206: PRD auth failure semantics conflict with repo behavior (TerraformPreHook is non-fatal).

Based on learnings, the PRD examples should reflect that auth.TerraformPreHook(...) errors are logged but do not abort Terraform execution.

Also applies to: 1113-1138

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

492-506: Doc snippet: don’t treat all HeadBucket errors as “bucket doesn’t exist”.

checkS3BucketExists returning (false, nil) on any error conflates 404 with 403 (AccessDenied), which can lead readers to think provisioning should proceed when it should fail fast. Recommend documenting/illustrating “404 → false; AccessDenied/other → error”.

pkg/provisioner/provisioner.go (2)

36-79: ProvisionWithParams has proper validation but perf.Track could use params.AtmosConfig.

The nil checks (lines 41-47) address past review concerns. However, line 39 passes nil to perf.Track when params.AtmosConfig is available after validation.

 func ProvisionWithParams(params *ProvisionParams) error {
-	defer perf.Track(nil, "provision.ProvisionWithParams")()
-
 	if params == nil {
 		return fmt.Errorf("%w: provision params", errUtils.ErrNilParam)
 	}
+	defer perf.Track(params.AtmosConfig, "provision.ProvisionWithParams")()

Move the defer after the nil check to use params.AtmosConfig.


142-177: DeleteBackendWithParams has proper structure but perf.Track could be improved.

Similar to ProvisionWithParams, line 144 passes nil to perf.Track when params.AtmosConfig could be available after validation.

 func DeleteBackendWithParams(params *DeleteBackendParams) error {
-	defer perf.Track(nil, "provision.DeleteBackend")()
-
 	if err := validateDeleteParams(params); err != nil {
 		return err
 	}
+	defer perf.Track(params.AtmosConfig, "provision.DeleteBackend")()

Move defer after validation to use params.AtmosConfig.

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: 4

♻️ Duplicate comments (5)
pkg/provisioner/backend/backend_test.go (1)

438-503: Minor: gcsCALLED naming typo makes the test harder to scan.

The variable gcsCALLED (mixed case) at line 446 is a typo—rename it to gcsCalled for consistency with s3Called at line 445.

Apply this diff:

-    gcsCALLED := false
+    gcsCalled := false

     mockGCSProvisioner := func(ctx context.Context, atmosConfig *schema.AtmosConfiguration, backendConfig map[string]any, authContext *schema.AuthContext) error {
-        gcsCALLED = true
+        gcsCalled = true
         return nil
     }
@@ -477,11 +477,11 @@
     err := ProvisionBackend(ctx, atmosConfig, componentConfigS3, nil)
     require.NoError(t, err)
     assert.True(t, s3Called, "S3 provisioner should have been called")
-    assert.False(t, gcsCALLED, "GCS provisioner should not have been called")
+    assert.False(t, gcsCalled, "GCS provisioner should not have been called")

     // Reset flags.
     s3Called = false
-    gcsCALLED = false
+    gcsCalled = false
@@ -498,7 +498,7 @@
     err = ProvisionBackend(ctx, atmosConfig, componentConfigGCS, nil)
     require.NoError(t, err)
     assert.False(t, s3Called, "S3 provisioner should not have been called")
-    assert.True(t, gcsCALLED, "GCS provisioner should have been called")
+    assert.True(t, gcsCalled, "GCS provisioner should have been called")
pkg/provisioner/provisioner.go (1)

36-79: Fix perf.Track to use params.AtmosConfig instead of nil.

Line 39 passes nil to perf.Track(), but params.AtmosConfig is available. All other provisioner functions correctly track with atmosConfig when available—use the same pattern here.

Apply this diff:

 func ProvisionWithParams(params *ProvisionParams) error {
-    defer perf.Track(nil, "provisioner.ProvisionWithParams")()
+    defer perf.Track(params.AtmosConfig, "provisioner.ProvisionWithParams")()

Optional: Consider context propagation.

Line 63 creates a fresh context.Background() timeout instead of propagating the caller's context. For proper cancellation support (e.g., Ctrl-C), the context should flow from the CLI handler through to backend provisioning. This would require adding Ctx context.Context to ProvisionParams and threading it through the call chain.

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

369-606: Fix markdownlint violations to avoid doc build failures.

Static hints show MD010/MD036 still present (hard tabs + emphasis used as headings). Please convert tabs → spaces and promote bold “Step X” lines to real headings.

Also applies to: 879-904, 922-982, 1441-1445

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

51-190: Fix markdownlint issues (tabs, fenced block languages, emphasis-as-heading).

Static hints still report MD010 across multiple fenced blocks; please normalize tabs → spaces in code fences (if MD010 is enforced there) and avoid bold-only “headings”.

Also applies to: 339-355, 909-935, 1038-1066

website/docs/components/terraform/backends.mdx (1)

194-200: Fix “Backend Configuration” related link inconsistency.

The “Related” list links “Backend Configuration” to /stacks/backend, but earlier you direct readers to /stacks/components/terraform/backend as the configuration reference. Align the label/link so users don’t bounce to the wrong page.

🧹 Nitpick comments (6)
pkg/provisioner/backend/backend_test.go (1)

23-43: Inconsistent registry reset helper usage.

Line 25 uses resetBackendRegistry() while other tests (lines 67, 82, 91, etc.) use ResetRegistryForTesting(). Both appear to do the same thing—clearing the backend provisioner registry. For consistency and maintainability, use the same helper throughout.

Suggestion:

Replace resetBackendRegistry() with ResetRegistryForTesting() in all tests, or clarify if there's a semantic difference between the two.

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

115-124: Consider removing unicode glyphs from CLI output for portability.

Strings like / can render poorly in some terminals and CI logs; optional to keep, but worth considering a plain-text fallback.


126-162: listAllObjects: consider explicitly setting MaxKeys and tightening state-file detection.

Minor: you set MaxKeys elsewhere but not here; also you only count .tfstate in Versions (not delete markers), which is probably fine but worth confirming as intended.


164-178: Harden collectObjectIdentifiers against nil keys.

If AWS ever returns entries with Key == nil, DeleteObjects will fail. Skipping nil keys defensively avoids turning one bad entry into a full stop.


202-222: Potential TOCTOU: bucket can refill between listing and deletion.

If new objects are written while deleting, DeleteBucket can fail. Optional: retry list+delete once when delete-bucket fails with “not empty”, or surface a specific “bucket changed during delete” hint.


224-233: Consider classifying “bucket not empty” separately.

If DeleteBucket fails due to BucketNotEmpty, mapping to a dedicated sentinel (e.g., ErrBucketNotEmpty) can improve UX and remediation guidance.

aknysh and others added 3 commits December 12, 2025 18:44
- Fix encryption/Bucket Key claim in s3-backend-provisioner.md:
  SSE-S3 (AES-256) doesn't use Bucket Key (only applies to SSE-KMS)
- Fix godot violations in DeleteS3Backend doc comment:
  Convert bullet points to flowing prose ending with periods

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

Co-Authored-By: Claude <noreply@anthropic.com>
Convert all user-facing errors to use ErrorBuilder pattern per repo
guidelines for consistent hints, context, and error handling:

- errForceRequired: --force flag requirement error
- createS3ClientForDeletion: AWS config loading error
- validateBucketExistsForDeletion: bucket not found error
- listAllObjects: list objects permission error
- deleteBatch: delete objects error with partial failure handling
- deleteAllObjects: list versions for deletion error
- deleteBucket: bucket deletion error

Extracted helper functions to keep DeleteS3Backend under 60 lines:
- errForceRequired()
- createS3ClientForDeletion()
- validateBucketExistsForDeletion()
- deleteS3BucketAndContents()

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

Co-Authored-By: Claude <noreply@anthropic.com>
Add helper functions to safely extract AtmosConfig from params structs,
allowing perf.Track to use the actual AtmosConfig instead of nil while
still satisfying the lintroller requirement that perf.Track must be at
the start of the function (before nil checks).

- getAtmosConfigFromProvisionParams: safely extracts from ProvisionParams
- getAtmosConfigFromDeleteParams: safely extracts from DeleteBackendParams

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

Co-Authored-By: Claude <noreply@anthropic.com>
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: 2

♻️ Duplicate comments (2)
docs/prd/s3-backend-provisioner.md (2)

880-880: Convert emphasis-used-as-headings to proper markdown headings (MD036).

Lines marked with "Step X:" or similar emphasis should be converted to ## or ### headings to pass markdownlint and improve document structure.

Example fix (line 880):

-**Step 1: Enable global feature flag (optional)**
+### Step 1: Enable global feature flag (optional)

Apply similar fixes to lines: 890, 907, 923, 946, 952, 967, 977, and 1442.

Also applies to: 890-890, 907-907, 923-923, 946-946, 952-952, 967-967, 977-977, 1442-1442


113-135: Clarify deletion semantics—the wording contradicts itself.

Line 115 states "--force flag is always required", but line 122 introduces a "Non-Empty Bucket Handling" section implying the flag's behavior differs. Reword to unambiguously convey the CLI contract:

-### Non-Empty Bucket Handling
-
-The `--force` flag is always required. When provided, the command:
+### Safety Mechanisms

-**Without `--force` flag:**
-- Command exits with error: "the --force flag is required for deletion"
-- No bucket inspection or deletion occurs
+If `--force` is not provided, deletion is rejected. When `--force` is provided, the command:
🧹 Nitpick comments (3)
pkg/provisioner/provisioner.go (3)

16-33: Good error handling and safe config extraction.

The sentinel error and helper functions are well-structured. The helpers ensure perf.Track receives a valid AtmosConfig even when params are nil, addressing previous feedback.

Optional: The two helper functions are nearly identical. If this pattern repeats elsewhere, consider a generic helper or interface-based approach to reduce duplication.


52-95: Well-structured provisioning orchestration.

The function properly validates inputs, uses ErrorBuilder for user-facing errors, tracks performance, and propagates AuthContext for cross-account provisioning. All major concerns from past reviews have been addressed.

Optional: For CLI cancellation support (e.g., Ctrl-C), consider adding a Ctx context.Context field to ProvisionParams and propagating it instead of creating context.Background(). This would flow cancellation signals from the CLI through to backend operations. Not critical for this PR but noted for future enhancement.


118-193: Solid deletion flow with proper validation.

The deletion functions mirror the provisioning pattern: parameter struct, thorough validation via validateDeleteParams, ErrorBuilder with helpful hints, and proper nil-checking. All prior concerns about missing validations have been resolved.

Same optional note as ProvisionWithParams: adding a Ctx field to DeleteBackendParams would enable cancellation propagation from the CLI, but this is not critical.

📜 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 e64b79e and 9423186.

📒 Files selected for processing (3)
  • docs/prd/s3-backend-provisioner.md (1 hunks)
  • pkg/provisioner/backend/s3_delete.go (1 hunks)
  • pkg/provisioner/provisioner.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

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

**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
All code must pass golangci-lint checks
Follow Go's error handling idioms: use meaningful error messages, wrap errors with context using fmt.Errorf("context: %w", err), and consider using custom error types for domain-specific errors
Follow standard Go coding style: use gofmt and goimports to format code, prefer short descriptive variable names, use kebab-case for command-line flags, and snake_case for environment variables
Document all exported functions, types, and methods following Go's documentation conventions
Document complex logic with inline comments in Go code
Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging

**/*.go: All comments must end with periods (enforced by godot linter)
NEVER delete existing comments without a very strong reason. Comments document why/how/what/where. Preserve helpful comments, update to match code, refactor for clarity, add context when modifying.
Organize imports in three groups separated by blank lines, sorted alphabetically: 1) Go stdlib, 2) 3rd-party (NOT cloudposse/atmos), 3) Atmos packages. Maintain aliases: cfg, log, u, errUtils
Add defer perf.Track(atmosConfig, "pkg.FuncName")() with a blank line to all public functions. Use nil if no atmosConfig parameter is available.
Define interfaces for all major functionality. Use dependency injection for testability. Generate mocks with go.uber.org/mock/mockgen. Avoid integration tests by mocking external dependencies.
Use //go:generate directives with go.uber.org/mock/mockgen for mock generation. Never creat...

Files:

  • pkg/provisioner/backend/s3_delete.go
  • pkg/provisioner/provisioner.go
pkg/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

pkg/**/*.go: For complex domains with multiple operations, use Service-Oriented Architecture with one Service struct per domain, provider interfaces for classes of problems, default implementations, mock implementations, and dependency injection for testability.
Follow multi-provider registry pattern: 1) Define interface in dedicated package, 2) Implement per provider, 3) Register implementations, 4) Generate mocks.

Files:

  • pkg/provisioner/backend/s3_delete.go
  • pkg/provisioner/provisioner.go
docs/prd/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

PRDs (Product Requirements Documents) must be in docs/prd/ using kebab-case filenames: command-registry-pattern.md, error-handling-strategy.md, testing-strategy.md

Files:

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

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2024-10-27T04:54:32.397Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:314-319
Timestamp: 2024-10-27T04:54:32.397Z
Learning: When deleting empty folders in the `deleteFolders` function, handling errors from `os.Remove` are not required, as failures do not affect the process.

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : All comments must end with periods (enforced by `godot` linter)

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : NEVER delete existing comments without a very strong reason. Comments document why/how/what/where. Preserve helpful comments, update to match code, refactor for clarity, add context when modifying.

Applied to files:

  • pkg/provisioner/backend/s3_delete.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 : Document complex logic with inline comments in Go code

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2025-02-03T06:00:11.419Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 959
File: cmd/describe_config.go:20-20
Timestamp: 2025-02-03T06:00:11.419Z
Learning: Commands should use `PrintErrorMarkdownAndExit` with empty title and suggestion (`"", err, ""`) for general error handling. Specific titles like "Invalid Usage" or "File Not Found" should only be used for validation or specific error scenarios.

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
  • pkg/provisioner/provisioner.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : ALL user-facing errors MUST use ErrorBuilder with sentinel errors from `errors/errors.go`. ALWAYS use `errors.Is()` for checking, NEVER string comparison. ALWAYS use `assert.ErrorIs()` in tests, NEVER `assert.Contains(err.Error(), ...)`

Applied to files:

  • pkg/provisioner/backend/s3_delete.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 : Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2025-09-10T22:38:42.212Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1475
File: pkg/auth/identities/aws/user.go:141-145
Timestamp: 2025-09-10T22:38:42.212Z
Learning: The user confirmed that the errors package has an error string wrapping format, contradicting the previous learning about ErrWrappingFormat being invalid. The current usage of fmt.Errorf(errUtils.ErrWrappingFormat, errUtils.ErrAuthAwsFileManagerFailed, err) appears to be the correct pattern.

Applied to files:

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

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2025-02-03T06:00:11.419Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 959
File: cmd/describe_config.go:20-20
Timestamp: 2025-02-03T06:00:11.419Z
Learning: The `describe config` command should use `PrintErrorMarkdownAndExit` with empty title and suggestion for consistency with other commands.

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2024-10-12T18:38:28.458Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 715
File: pkg/logger/logger.go:21-32
Timestamp: 2024-10-12T18:38:28.458Z
Learning: In Go code, avoid prefixing struct names with 'I' (e.g., `IError`) as it can be confusing, suggesting an interface. Use descriptive names for structs to improve code clarity.

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
📚 Learning: 2025-04-04T02:03:23.676Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1185
File: internal/exec/yaml_func_store.go:26-26
Timestamp: 2025-04-04T02:03:23.676Z
Learning: The Atmos codebase currently uses `log.Fatal` for error handling in multiple places. The maintainers are aware this isn't an ideal pattern (should only be used in main() or init() functions) and plan to address it comprehensively in a separate PR. CodeRabbit should not flag these issues or push for immediate changes until that refactoring is complete.

Applied to files:

  • pkg/provisioner/backend/s3_delete.go
  • pkg/provisioner/provisioner.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
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:

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

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : ALWAYS ask for user approval before adding nolint comments. Prefer refactoring over nolint. Exception for bubbletea models: `//nolint:gocritic // bubbletea models must be passed by value`. Exception for intentional subprocess calls: `//nolint:gosec // intentional subprocess call`. NEVER add nolint for gocognit, cyclomatic complexity, magic numbers, or nestif.

Applied to files:

  • pkg/provisioner/provisioner.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 meaningful feedback to users and include progress indicators for long-running operations in CLI commands

Applied to files:

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

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-04-04T02:03:21.906Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1185
File: internal/exec/yaml_func_store.go:71-72
Timestamp: 2025-04-04T02:03:21.906Z
Learning: The codebase currently uses `log.Fatal` for error handling in library functions, which terminates the program. There is a plan to refactor this approach in a separate PR to improve API design by returning error messages instead of terminating execution.

Applied to files:

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*_test.go : Test behavior, not implementation. Never test stub functions. Avoid tautological tests. Make code testable using DI. No coverage theater. Remove always-skipped tests. Table-driven tests need real scenarios. Use `assert.ErrorIs(err, ErrSentinel)` for our/stdlib errors.

Applied to files:

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

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

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

  • pkg/provisioner/provisioner.go
📚 Learning: 2024-11-13T21:37:07.852Z
Learnt from: Cerebrovinny
Repo: cloudposse/atmos PR: 764
File: internal/exec/describe_stacks.go:289-295
Timestamp: 2024-11-13T21:37:07.852Z
Learning: In the `internal/exec/describe_stacks.go` file of the `atmos` project written in Go, avoid extracting the stack name handling logic into a helper function within the `ExecuteDescribeStacks` method, even if the logic appears duplicated.

Applied to files:

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-08-16T23:33:07.477Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1405
File: internal/exec/describe_dependents_test.go:651-652
Timestamp: 2025-08-16T23:33:07.477Z
Learning: In the cloudposse/atmos Go codebase, ExecuteDescribeDependents expects a pointer to AtmosConfiguration (*schema.AtmosConfiguration), so when calling it with a value returned by cfg.InitCliConfig (which returns schema.AtmosConfiguration), the address-of operator (&) is necessary: ExecuteDescribeDependents(&atmosConfig, ...).

Applied to files:

  • pkg/provisioner/provisioner.go
📚 Learning: 2024-10-30T13:25:45.965Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:405-412
Timestamp: 2024-10-30T13:25:45.965Z
Learning: In `internal/exec/terraform_clean.go`, when appending `stackFolders` to `folders` in the `handleCleanSubCommand` function, it's unnecessary to check if `stackFolders` is nil before appending, because in Go, appending a nil slice is safe and does not cause a panic.

Applied to files:

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

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-11-30T04:16:24.155Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1821
File: pkg/merge/deferred.go:34-48
Timestamp: 2025-11-30T04:16:24.155Z
Learning: In the cloudposse/atmos repository, the `defer perf.Track()` guideline applies to functions that perform meaningful work (I/O, computation, external calls), but explicitly excludes trivial accessors/mutators (e.g., simple getters, setters with single integer increments, string joins, or map appends) where the tracking overhead would exceed the actual method cost and provide no actionable performance data. Hot-path methods called in tight loops should especially avoid perf.Track() if they perform only trivial operations.

Applied to files:

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : Add `defer perf.Track(atmosConfig, "pkg.FuncName")()` with a blank line to all public functions. Use `nil` if no atmosConfig parameter is available.

Applied to files:

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

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-10-13T18:13:54.020Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1622
File: pkg/perf/perf.go:140-184
Timestamp: 2025-10-13T18:13:54.020Z
Learning: In pkg/perf/perf.go, the `trackWithSimpleStack` function intentionally skips ownership checks at call stack depth > 1 to avoid expensive `getGoroutineID()` calls on every nested function. This is a performance optimization for the common single-goroutine execution case (most Atmos commands), accepting the rare edge case of potential metric corruption if multi-goroutine execution occurs at depth > 1. The ~19× performance improvement justifies this trade-off.

Applied to files:

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-11-30T04:16:01.899Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1821
File: pkg/merge/deferred.go:50-59
Timestamp: 2025-11-30T04:16:01.899Z
Learning: In the cloudposse/atmos repository, performance tracking with `defer perf.Track()` should NOT be added to trivial O(1) getter methods that only return field references or check map lengths (e.g., `GetDeferredValues()`, `HasDeferredValues()`). The guideline to add perf tracking to "all public functions" applies to functions that do meaningful work (I/O, computation, external calls), not to trivial accessors where the tracking overhead would exceed the operation time and pollute performance reports.

Applied to files:

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : Use `context.Context` for cancellation signals, deadlines/timeouts, and request-scoped values. Context should be the first parameter in functions that accept it. DO NOT use context for configuration, dependencies, or avoiding proper function parameters.

Applied to files:

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-09-29T02:20:11.636Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/validate_component.go:117-118
Timestamp: 2025-09-29T02:20:11.636Z
Learning: The ValidateComponent function in internal/exec/validate_component.go had its componentSection parameter type refined from `any` to `map[string]any` without adding new parameters. This is a type safety improvement, not a signature change requiring call site updates.

Applied to files:

  • pkg/provisioner/provisioner.go
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to website/docs/cli/commands/**/*.mdx : All CLI commands/flags need Docusaurus docs in `website/docs/cli/commands/`. Use `<dl>` for args/flags. Build: `cd website && npm run build`

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 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:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to website/docs/cli/commands/**/*.mdx : Use `<dl>` for arguments/flags in documentation. Follow Docusaurus conventions: frontmatter, purpose note, screengrab, usage/examples/arguments/flags sections.

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to website/blog/**/*.mdx : Follow PR template (what/why/references). PRs labeled `minor`/`major` MUST include blog post: `website/blog/YYYY-MM-DD-feature-name.mdx`. Use `.mdx` with YAML front matter, `<!--truncate-->` after intro. MUST use tags from `website/blog/tags.yml` only. MUST use existing author from `website/blog/authors.yml` or add new entry.

Applied to files:

  • docs/prd/s3-backend-provisioner.md
🧬 Code graph analysis (1)
pkg/provisioner/backend/s3_delete.go (1)
pkg/provisioner/backend/s3.go (1)
  • S3ClientAPI (28-38)
🪛 LanguageTool
docs/prd/s3-backend-provisioner.md

[typographical] ~134-~134: Consider using a typographic opening quote here.
Context: ...ce` flag:** - Command exits with error: "the --force flag is required for deletio...

(EN_QUOTES)


[typographical] ~1384-~1384: To join two clauses or introduce examples, consider using an em dash.
Context: ...ioner System](./provisioner-system.md)** - Generic provisioner infrastructure - **[...

(DASH_RULE)


[typographical] ~1385-~1385: To join two clauses or introduce examples, consider using an em dash.
Context: ...Provisioner](./backend-provisioner.md)** - Backend provisioner interface --- ## A...

(DASH_RULE)

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

376-376: Hard tabs
Column: 1

(MD010, no-hard-tabs)


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)


396-396: Hard tabs
Column: 1

(MD010, no-hard-tabs)


397-397: Hard tabs
Column: 1

(MD010, no-hard-tabs)


398-398: Hard tabs
Column: 1

(MD010, no-hard-tabs)


400-400: Hard tabs
Column: 1

(MD010, no-hard-tabs)


402-402: Hard tabs
Column: 1

(MD010, no-hard-tabs)


403-403: Hard tabs
Column: 1

(MD010, no-hard-tabs)


404-404: Hard tabs
Column: 1

(MD010, no-hard-tabs)


405-405: Hard tabs
Column: 1

(MD010, no-hard-tabs)


406-406: Hard tabs
Column: 1

(MD010, no-hard-tabs)


408-408: Hard tabs
Column: 1

(MD010, no-hard-tabs)


409-409: Hard tabs
Column: 1

(MD010, no-hard-tabs)


410-410: Hard tabs
Column: 1

(MD010, no-hard-tabs)


411-411: Hard tabs
Column: 1

(MD010, no-hard-tabs)


413-413: Hard tabs
Column: 1

(MD010, no-hard-tabs)


414-414: Hard tabs
Column: 1

(MD010, no-hard-tabs)


415-415: Hard tabs
Column: 1

(MD010, no-hard-tabs)


416-416: Hard tabs
Column: 1

(MD010, no-hard-tabs)


418-418: Hard tabs
Column: 1

(MD010, no-hard-tabs)


419-419: Hard tabs
Column: 1

(MD010, no-hard-tabs)


420-420: Hard tabs
Column: 1

(MD010, no-hard-tabs)


421-421: Hard tabs
Column: 1

(MD010, no-hard-tabs)


422-422: Hard tabs
Column: 1

(MD010, no-hard-tabs)


424-424: Hard tabs
Column: 1

(MD010, no-hard-tabs)


425-425: Hard tabs
Column: 1

(MD010, no-hard-tabs)


426-426: Hard tabs
Column: 1

(MD010, no-hard-tabs)


427-427: Hard tabs
Column: 1

(MD010, no-hard-tabs)


428-428: Hard tabs
Column: 1

(MD010, no-hard-tabs)


429-429: Hard tabs
Column: 1

(MD010, no-hard-tabs)


431-431: Hard tabs
Column: 1

(MD010, no-hard-tabs)


432-432: Hard tabs
Column: 1

(MD010, no-hard-tabs)


433-433: Hard tabs
Column: 1

(MD010, no-hard-tabs)


434-434: Hard tabs
Column: 1

(MD010, no-hard-tabs)


436-436: Hard tabs
Column: 1

(MD010, no-hard-tabs)


437-437: Hard tabs
Column: 1

(MD010, no-hard-tabs)


438-438: Hard tabs
Column: 1

(MD010, no-hard-tabs)


439-439: Hard tabs
Column: 1

(MD010, no-hard-tabs)


440-440: Hard tabs
Column: 1

(MD010, no-hard-tabs)


442-442: Hard tabs
Column: 1

(MD010, no-hard-tabs)


443-443: Hard tabs
Column: 1

(MD010, no-hard-tabs)


448-448: Hard tabs
Column: 1

(MD010, no-hard-tabs)


449-449: Hard tabs
Column: 1

(MD010, no-hard-tabs)


450-450: Hard tabs
Column: 1

(MD010, no-hard-tabs)


452-452: Hard tabs
Column: 1

(MD010, no-hard-tabs)


454-454: Hard tabs
Column: 1

(MD010, no-hard-tabs)


455-455: 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)


461-461: Hard tabs
Column: 1

(MD010, no-hard-tabs)


462-462: Hard tabs
Column: 1

(MD010, no-hard-tabs)


463-463: Hard tabs
Column: 1

(MD010, no-hard-tabs)


464-464: Hard tabs
Column: 1

(MD010, no-hard-tabs)


466-466: Hard tabs
Column: 1

(MD010, no-hard-tabs)


467-467: 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)


471-471: Hard tabs
Column: 1

(MD010, no-hard-tabs)


472-472: Hard tabs
Column: 1

(MD010, no-hard-tabs)


473-473: Hard tabs
Column: 1

(MD010, no-hard-tabs)


475-475: 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)


478-478: Hard tabs
Column: 1

(MD010, no-hard-tabs)


479-479: Hard tabs
Column: 1

(MD010, no-hard-tabs)


480-480: 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)


485-485: 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)


490-490: Hard tabs
Column: 1

(MD010, no-hard-tabs)


499-499: Hard tabs
Column: 1

(MD010, no-hard-tabs)


501-501: 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)


505-505: Hard tabs
Column: 1

(MD010, no-hard-tabs)


506-506: Hard tabs
Column: 1

(MD010, no-hard-tabs)


507-507: Hard tabs
Column: 1

(MD010, no-hard-tabs)


508-508: Hard tabs
Column: 1

(MD010, no-hard-tabs)


509-509: Hard tabs
Column: 1

(MD010, no-hard-tabs)


510-510: Hard tabs
Column: 1

(MD010, no-hard-tabs)


511-511: Hard tabs
Column: 1

(MD010, no-hard-tabs)


512-512: Hard tabs
Column: 1

(MD010, no-hard-tabs)


513-513: Hard tabs
Column: 1

(MD010, no-hard-tabs)


514-514: Hard tabs
Column: 1

(MD010, no-hard-tabs)


515-515: Hard tabs
Column: 1

(MD010, no-hard-tabs)


516-516: Hard tabs
Column: 1

(MD010, no-hard-tabs)


518-518: Hard tabs
Column: 1

(MD010, no-hard-tabs)


523-523: Hard tabs
Column: 1

(MD010, no-hard-tabs)


524-524: Hard tabs
Column: 1

(MD010, no-hard-tabs)


525-525: Hard tabs
Column: 1

(MD010, no-hard-tabs)


527-527: 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)


532-532: Hard tabs
Column: 1

(MD010, no-hard-tabs)


534-534: Hard tabs
Column: 1

(MD010, no-hard-tabs)


535-535: Hard tabs
Column: 1

(MD010, no-hard-tabs)


536-536: Hard tabs
Column: 1

(MD010, no-hard-tabs)


537-537: Hard tabs
Column: 1

(MD010, no-hard-tabs)


538-538: Hard tabs
Column: 1

(MD010, no-hard-tabs)


539-539: 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)


545-545: Hard tabs
Column: 1

(MD010, no-hard-tabs)


546-546: Hard tabs
Column: 1

(MD010, no-hard-tabs)


548-548: Hard tabs
Column: 1

(MD010, no-hard-tabs)


549-549: Hard tabs
Column: 1

(MD010, no-hard-tabs)


550-550: Hard tabs
Column: 1

(MD010, no-hard-tabs)


551-551: Hard tabs
Column: 1

(MD010, no-hard-tabs)


552-552: Hard tabs
Column: 1

(MD010, no-hard-tabs)


553-553: Hard tabs
Column: 1

(MD010, no-hard-tabs)


554-554: Hard tabs
Column: 1

(MD010, no-hard-tabs)


555-555: Hard tabs
Column: 1

(MD010, no-hard-tabs)


556-556: Hard tabs
Column: 1

(MD010, no-hard-tabs)


557-557: Hard tabs
Column: 1

(MD010, no-hard-tabs)


559-559: Hard tabs
Column: 1

(MD010, no-hard-tabs)


560-560: Hard tabs
Column: 1

(MD010, no-hard-tabs)


561-561: Hard tabs
Column: 1

(MD010, no-hard-tabs)


562-562: Hard tabs
Column: 1

(MD010, no-hard-tabs)


563-563: Hard tabs
Column: 1

(MD010, no-hard-tabs)


564-564: Hard tabs
Column: 1

(MD010, no-hard-tabs)


565-565: Hard tabs
Column: 1

(MD010, no-hard-tabs)


566-566: Hard tabs
Column: 1

(MD010, no-hard-tabs)


567-567: Hard tabs
Column: 1

(MD010, no-hard-tabs)


568-568: Hard tabs
Column: 1

(MD010, no-hard-tabs)


569-569: Hard tabs
Column: 1

(MD010, no-hard-tabs)


570-570: Hard tabs
Column: 1

(MD010, no-hard-tabs)


571-571: Hard tabs
Column: 1

(MD010, no-hard-tabs)


572-572: Hard tabs
Column: 1

(MD010, no-hard-tabs)


573-573: Hard tabs
Column: 1

(MD010, no-hard-tabs)


574-574: Hard tabs
Column: 1

(MD010, no-hard-tabs)


575-575: 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)


584-584: 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)


591-591: Hard tabs
Column: 1

(MD010, no-hard-tabs)


592-592: Hard tabs
Column: 1

(MD010, no-hard-tabs)


593-593: Hard tabs
Column: 1

(MD010, no-hard-tabs)


594-594: Hard tabs
Column: 1

(MD010, no-hard-tabs)


595-595: Hard tabs
Column: 1

(MD010, no-hard-tabs)


596-596: Hard tabs
Column: 1

(MD010, no-hard-tabs)


597-597: Hard tabs
Column: 1

(MD010, no-hard-tabs)


598-598: Hard tabs
Column: 1

(MD010, no-hard-tabs)


599-599: Hard tabs
Column: 1

(MD010, no-hard-tabs)


600-600: Hard tabs
Column: 1

(MD010, no-hard-tabs)


601-601: Hard tabs
Column: 1

(MD010, no-hard-tabs)


602-602: Hard tabs
Column: 1

(MD010, no-hard-tabs)


603-603: Hard tabs
Column: 1

(MD010, no-hard-tabs)


604-604: Hard tabs
Column: 1

(MD010, no-hard-tabs)


606-606: Hard tabs
Column: 1

(MD010, no-hard-tabs)


611-611: Hard tabs
Column: 1

(MD010, no-hard-tabs)


612-612: Hard tabs
Column: 1

(MD010, no-hard-tabs)


613-613: Hard tabs
Column: 1

(MD010, no-hard-tabs)


614-614: Hard tabs
Column: 1

(MD010, no-hard-tabs)


615-615: Hard tabs
Column: 1

(MD010, no-hard-tabs)


616-616: 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)


623-623: Hard tabs
Column: 1

(MD010, no-hard-tabs)


637-637: Hard tabs
Column: 1

(MD010, no-hard-tabs)


641-641: Hard tabs
Column: 1

(MD010, no-hard-tabs)


645-645: Hard tabs
Column: 1

(MD010, no-hard-tabs)


649-649: Hard tabs
Column: 1

(MD010, no-hard-tabs)


653-653: Hard tabs
Column: 1

(MD010, no-hard-tabs)


654-654: Hard tabs
Column: 1

(MD010, no-hard-tabs)


658-658: Hard tabs
Column: 1

(MD010, no-hard-tabs)


659-659: Hard tabs
Column: 1

(MD010, no-hard-tabs)


660-660: Hard tabs
Column: 1

(MD010, no-hard-tabs)


661-661: Hard tabs
Column: 1

(MD010, no-hard-tabs)


662-662: Hard tabs
Column: 1

(MD010, no-hard-tabs)


666-666: Hard tabs
Column: 1

(MD010, no-hard-tabs)


667-667: Hard tabs
Column: 1

(MD010, no-hard-tabs)


671-671: Hard tabs
Column: 1

(MD010, no-hard-tabs)


672-672: Hard tabs
Column: 1

(MD010, no-hard-tabs)


673-673: 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)


691-691: Hard tabs
Column: 1

(MD010, no-hard-tabs)


692-692: Hard tabs
Column: 1

(MD010, no-hard-tabs)


693-693: Hard tabs
Column: 1

(MD010, no-hard-tabs)


694-694: Hard tabs
Column: 1

(MD010, no-hard-tabs)


695-695: Hard tabs
Column: 1

(MD010, no-hard-tabs)


696-696: Hard tabs
Column: 1

(MD010, no-hard-tabs)


700-700: Hard tabs
Column: 1

(MD010, no-hard-tabs)


701-701: Hard tabs
Column: 1

(MD010, no-hard-tabs)


703-703: Hard tabs
Column: 1

(MD010, no-hard-tabs)


704-704: 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)


712-712: 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)


880-880: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


890-890: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


907-907: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


923-923: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


946-946: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


952-952: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


967-967: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


977-977: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1442-1442: 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 (macos)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Summary
🔇 Additional comments (9)
docs/prd/s3-backend-provisioner.md (1)

74-85: Encryption note correctly clarifies SSE-S3 vs Bucket Key—LGTM.

The clarification at line 83 explicitly states Bucket Key applies only to SSE-KMS, resolving prior ambiguity. This is accurate and helpful.

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

1-16: LGTM! Clean package structure and properly organized imports.

Imports follow the three-group convention (stdlib, 3rd-party, atmos) with correct aliasing.


18-64: Excellent resolution of previous review feedback.

The function now:

  • Enforces the force flag at the start (lines 38-40), addressing the "unused parameter" concern
  • Uses a clean orchestration pattern with well-factored helpers
  • Includes comprehensive documentation with proper godot compliance

The safety mechanisms (validation, warnings, batch deletion) are well-structured.


66-189: Excellent ErrorBuilder usage throughout.

All helper functions properly use ErrorBuilder with sentinel errors from errors/errors.go, providing clear explanations, context, and actionable hints. This addresses the previous feedback about consistent error handling patterns.

The listAllObjects function correctly handles pagination and counts state files for informative warnings.


207-238: Critical partial failure handling implemented correctly.

Lines 224-236 properly handle the case where DeleteObjects returns HTTP 200 but includes per-key errors in resp.Errors. This prevents infinite loops on undeletable objects and provides clear diagnostic information.

The error includes bucket, key, version, code, and message context—exactly what's needed for troubleshooting.


240-281: Clean batch deletion and bucket removal.

The deleteAllObjects function correctly paginates through large buckets (up to 1000 keys per batch per AWS limits) and delegates to deleteBatch for consistent error handling.

The deleteBucket function provides clear error context and hints when the final deletion fails.

pkg/provisioner/provisioner.go (3)

3-14: Imports organized correctly.

Package declaration and import structure follow the guidelines. All necessary packages are imported with proper aliases.


35-50: Excellent use of DI and parameter structs.

ExecuteDescribeComponentFunc provides clean dependency injection to avoid circular dependencies. The ProvisionParams struct eliminates the need for long parameter lists and revive suppressions, directly addressing prior feedback.


97-116: Correct not-implemented handling.

Both functions now return proper errors via ErrorBuilder instead of nil, ensuring the CLI exits with non-zero status. This directly addresses prior feedback about false-success exit codes.

aknysh and others added 2 commits December 12, 2025 19:20
Convert all hard tabs to 2 spaces in Go code examples to pass
markdownlint MD010 rule and prevent docs build failures.

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

Co-Authored-By: Claude <noreply@anthropic.com>
The checkS3BucketExists function uses errors.As() but the import
block was missing the errors package.

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

Co-Authored-By: Claude <noreply@anthropic.com>
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

♻️ Duplicate comments (4)
docs/prd/s3-backend-provisioner.md (4)

370-390: Fix hard tabs in Go code block (MD010 blocker).

This issue was previously flagged but remains unresolved. The Go code block contains hard tab characters that violate markdownlint MD010 and will cause docs build failures. Replace all hard tabs with spaces (2 spaces per tab to match project style).

Run this to fix:

#!/bin/bash
sed -i 's/\t/  /g' docs/prd/s3-backend-provisioner.md

Then verify with:

markdownlint docs/prd/s3-backend-provisioner.md

499-520: Add missing errors import to Go example.

Line 510 calls errors.As() but the import block (lines 375–389) does not include the errors standard library package. This is a code example correctness issue.

 import (
   "context"
+  "errors"
   "fmt"
   "sync"
   "time"

113-135: Resolve contradictory deletion semantics.

The section states --force is "always required" but then describes a "default behavior (no --force)" mode. Reword to avoid ambiguity: if --force is always required, there is no default non-forced path. Either update the heading from "Non-Empty Bucket Handling" to clarify behavior when --force is supplied, or revise the opening statement if deletion without --force is actually possible.

Suggested fix: remove lines 133–135 and reword:

-**Without `--force` flag:**
-- Command exits with error: "the --force flag is required for deletion"
-- No bucket inspection or deletion occurs

Then add at the end of line 124 context: "When the --force flag is provided:" and remove the "Without --force" subsection.


881-881: Convert bold "Step X" lines to markdown headings (MD036).

Lines using bold text (e.g., **Step 1: ...**) should be markdown headings (### Step 1: ...) to comply with markdownlint MD036 and improve semantic structure. This affects the Migration Guide and other sections.

Examples:

  • Line 881: **Step 1: Enable global feature flag (optional)**### Step 1: Enable global feature flag (optional)
  • Line 891: **Step 2: Enable per-component**### Step 2: Enable per-component
  • Line 908: **Step 3: Generate backend**### Step 3: Generate backend
  • Line 924: **Step 1: Provision production backend via Terraform module**### Step 1: Provision production backend via Terraform module
  • Line 947: **Step 2: Apply backend infrastructure**### Step 2: Apply backend infrastructure
  • Line 953: **Step 3: Update component to use production backend**### Step 3: Update component to use production backend
  • Line 968: **Step 4: Migrate state**### Step 4: Migrate state
  • Line 978: **Step 5: (Optional) Delete old auto-provisioned bucket**### Step 5: (Optional) Delete old auto-provisioned bucket
  • Line 1443: **End of PRD**### End of PRD

Also applies to: 891-891, 908-908, 924-924, 947-947, 953-953, 968-968, 978-978

📜 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 9423186 and 3e43c02.

📒 Files selected for processing (1)
  • docs/prd/s3-backend-provisioner.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
docs/prd/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

PRDs (Product Requirements Documents) must be in docs/prd/ using kebab-case filenames: command-registry-pattern.md, error-handling-strategy.md, testing-strategy.md

Files:

  • docs/prd/s3-backend-provisioner.md
🧠 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.
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-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to website/docs/cli/commands/**/*.mdx : All CLI commands/flags need Docusaurus docs in `website/docs/cli/commands/`. Use `<dl>` for args/flags. Build: `cd website && npm run build`

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 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:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to website/docs/cli/commands/**/*.mdx : Use `<dl>` for arguments/flags in documentation. Follow Docusaurus conventions: frontmatter, purpose note, screengrab, usage/examples/arguments/flags sections.

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to website/blog/**/*.mdx : Follow PR template (what/why/references). PRs labeled `minor`/`major` MUST include blog post: `website/blog/YYYY-MM-DD-feature-name.mdx`. Use `.mdx` with YAML front matter, `<!--truncate-->` after intro. MUST use tags from `website/blog/tags.yml` only. MUST use existing author from `website/blog/authors.yml` or add new entry.

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 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:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : ALWAYS ask for user approval before adding nolint comments. Prefer refactoring over nolint. Exception for bubbletea models: `//nolint:gocritic // bubbletea models must be passed by value`. Exception for intentional subprocess calls: `//nolint:gosec // intentional subprocess call`. NEVER add nolint for gocognit, cyclomatic complexity, magic numbers, or nestif.

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 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 : Follow standard Go coding style: use `gofmt` and `goimports` to format code, prefer short descriptive variable names, use kebab-case for command-line flags, and snake_case for environment variables

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 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 : Follow Go's error handling idioms: use meaningful error messages, wrap errors with context using `fmt.Errorf("context: %w", err)`, and consider using custom error types for domain-specific errors

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 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:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to internal/**/*.go : For legacy patterns (internal/non-user-facing only): use `errors.Join` for multiple errors, `fmt.Errorf("%w", err)` for chains (sequential call stack), or `fmt.Errorf` with multiple `%w` like `errors.Join` (Go 1.20+).

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 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 : Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : ALL user-facing errors MUST use ErrorBuilder with sentinel errors from `errors/errors.go`. ALWAYS use `errors.Is()` for checking, NEVER string comparison. ALWAYS use `assert.ErrorIs()` in tests, NEVER `assert.Contains(err.Error(), ...)`

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 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:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-04-04T02:03:23.676Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1185
File: internal/exec/yaml_func_store.go:26-26
Timestamp: 2025-04-04T02:03:23.676Z
Learning: The Atmos codebase currently uses `log.Fatal` for error handling in multiple places. The maintainers are aware this isn't an ideal pattern (should only be used in main() or init() functions) and plan to address it comprehensively in a separate PR. CodeRabbit should not flag these issues or push for immediate changes until that refactoring is complete.

Applied to files:

  • docs/prd/s3-backend-provisioner.md
📚 Learning: 2025-12-10T23:12:15.805Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-10T23:12:15.805Z
Learning: Applies to **/*.go : Organize imports in three groups separated by blank lines, sorted alphabetically: 1) Go stdlib, 2) 3rd-party (NOT cloudposse/atmos), 3) Atmos packages. Maintain aliases: `cfg`, `log`, `u`, `errUtils`

Applied to files:

  • docs/prd/s3-backend-provisioner.md
🪛 LanguageTool
docs/prd/s3-backend-provisioner.md

[typographical] ~134-~134: Consider using a typographic opening quote here.
Context: ...ce` flag:** - Command exits with error: "the --force flag is required for deletio...

(EN_QUOTES)


[typographical] ~1385-~1385: To join two clauses or introduce examples, consider using an em dash.
Context: ...ioner System](./provisioner-system.md)** - Generic provisioner infrastructure - **[...

(DASH_RULE)


[typographical] ~1386-~1386: To join two clauses or introduce examples, consider using an em dash.
Context: ...Provisioner](./backend-provisioner.md)** - Backend provisioner interface --- ## A...

(DASH_RULE)

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

881-881: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


891-891: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


908-908: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


924-924: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


947-947: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


953-953: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


968-968: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


978-978: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1443-1443: 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). (4)
  • GitHub Check: Acceptance Tests (linux)
  • GitHub Check: Acceptance Tests (macos)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Summary

@aknysh aknysh merged commit c152e0b into main Dec 13, 2025
59 checks passed
@aknysh aknysh deleted the osterman/auto-backend-provision branch December 13, 2025 00:51
@mergify mergify bot removed the needs-cloudposse Needs Cloud Posse assistance label Dec 13, 2025
@github-actions
Copy link

Warning

Changelog Entry Required

This PR is labeled minor or major but doesn't include a changelog entry.

Action needed: Add a new blog post in website/blog/ to announce this change.

Example filename: website/blog/2025-12-13-feature-name.mdx

Alternatively: If this change doesn't require a changelog entry, remove the minor or major label.

@github-actions
Copy link

These changes were released in v1.202.0-rc.1.

@github-actions
Copy link

These changes were released in v1.203.0-test.1.

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 size/xl Extra large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants