Skip to content

fix(output): stop after-* hooks from corrupting backend.tf.json when backend uses !terraform.state#2358

Merged
aknysh merged 9 commits intocloudposse:mainfrom
zack-is-cool:fix/2356-after-apply-hook-backend-regeneration
Apr 23, 2026
Merged

fix(output): stop after-* hooks from corrupting backend.tf.json when backend uses !terraform.state#2358
aknysh merged 9 commits intocloudposse:mainfrom
zack-is-cool:fix/2356-after-apply-hook-backend-regeneration

Conversation

@zack-is-cool
Copy link
Copy Markdown
Contributor

@zack-is-cool zack-is-cool commented Apr 22, 2026

Summary

Fixes #2356. The after-terraform-apply store hook path regenerated
backend.tf.json / providers_override.tf.json from un-rendered
component sections when the backend referenced !terraform.state,
overwriting a correctly-rendered file with literal YAML-function strings:

-        "bucket": "atmos-tfstate-dev",
-        "dynamodb_table": "atmos-tfstate-lock-dev",
+        "bucket": "!terraform.state tfstate-backend dev s3_bucket_id",
+        "dynamodb_table": "!terraform.state tfstate-backend dev dynamodb_table_name",

The hook then failed its tofu output call with:

Error: Backend initialization required: please run "tofu init"
Reason: Backend configuration block has changed

Why

Regression introduced in v1.216.0 by #2309 (commit 3c0e748ce) +
follow-up commit c7ef142a9 ("fix: skip-init should skip yaml function
evaluation"
). c7ef142a9 added a guard disabling YAML-function
evaluation when SkipInit && authManager == nil to avoid failing on
auth-requiring functions in the post-hook context. The guard is overly
broad — it also disables evaluation of non-auth functions like
!terraform.state — so sections returned from DescribeComponent retain
literal YAML-function strings. execute() then extracts config.Backend
from those sections and writes them to disk via GenerateBackendIfNeeded.

Fix

Thread processYamlFunctions bool through execute() in
pkg/terraform/output/executor.go and guard the artifact-regeneration
block (Step 4 / Step 5) behind it. When YAML functions were not
evaluated upstream, execute() must not regenerate artifacts from the
un-rendered sections. The backend file on disk from the init/apply phase
is already correct; leaving it alone is always safe. Output reading
(tofu output) still works via the on-disk state.

Minimal, localized diff — four commits:

  1. refactor(output): inject BackendGenerator and thread processYamlFunctions through execute() — pure DI plumbing, no behavior change.
  2. fix(output): skip artifact regeneration when YAML functions were not processed — the actual guard.
  3. test(output): assert backend-generator calls match processYamlFunctions in SkipInit tests — locks in the invariant in four existing SkipInit tests.
  4. test(output): regression test for #2356 backend.tf.json corruption — byte-identical integration assertion.

Test plan

  • New unit test TestExecutor_Execute_SkipsArtifactRegen_WhenYamlFunctionsNotProcessed (demonstrably red before the guard, green after).
  • Four existing SkipInit tests strengthened with zero-call expectations on the backend-generator mock.
  • Inverse assertion in TestExecutor_GetAllOutputs_SkipInit_WithAuthManager_ProcessesYamlFunctions: GenerateBackendIfNeeded + GenerateProvidersIfNeeded called exactly once when auth is present.
  • Integration regression test TestExecutor_Regression_Issue2356_BackendFileUnchangedInSkipInitPath: writes a rendered backend.tf.json, drives GetOutputWithOptions(SkipInit=true, authManager=nil), asserts the file is byte-identical. Fails without the guard; passes with it.
  • go test ./pkg/terraform/output/... -count=1 green.
  • make lint / ./custom-gcl run --new-from-rev=origin/main clean (one dupl warning on the new test vs the existing SkipInit test is suppressed with //nolint:dupl + justification — they test contrasting invariants at the same call site; extracting shared scaffolding would obscure the red/green comparison).
  • Manual end-to-end via LocalStack + Redis repro (ignore/issues/post-apply-hook-backend-racecondition/repro.sh in the branch, referenced from after-terraform-apply hook corrupts backend.tf.json when backend uses !terraform.state #2356). Exits 0 with FIX VERIFIED on this branch; backend file byte-diff is empty after the after-apply hook.
  • CI full suite — opening this PR runs it.

Follow-up

The processYamlFunctions = false guard in GetOutputWithOptions /
fetchAndCacheOutputs is the deeper design issue — auth availability
should not gate evaluation of non-auth YAML functions. Tracked in #2357.
This PR is the minimal regression fix for v1.216.x.

Release

  • fix: conventional commit → patch release (v1.216.1).
  • No schema changes, no user-facing config changes.
  • No roadmap update (regression fix, not a feature).

Summary by CodeRabbit

  • Bug Fixes

    • Backend and provider override files are regenerated only when YAML functions are processed, preventing unnecessary rewrites.
    • Fixed a case where skip-initialization could overwrite already-rendered backend/provider files, preserving existing configurations.
  • Tests

    • Added regression tests to ensure backend/provider files remain unchanged in the skip-initialization path and to validate correct conditional regeneration behavior.

…ions through execute()

Prep for cloudposse#2356 fix. Adds WithBackendGenerator option so tests can assert
artifact-regeneration behavior, and adds a processYamlFunctions parameter
to execute() plumbed through all four internal call sites. No behavior
change — all current callers pass values equivalent to the old behavior.
…processed

Guards Step 4/Step 5 of execute() behind the new processYamlFunctions flag.
When after-* hooks read outputs with SkipInit=true && authManager==nil,
DescribeComponent is intentionally called with ProcessYamlFunctions=false,
which leaves literal '!terraform.state ...' strings in config.Backend and
config.Providers. Regenerating backend.tf.json / providers_override.tf.json
from those un-rendered sections overwrote a correctly-rendered file from
the init/apply phase with a broken one, causing subsequent tofu output to
fail with 'Backend configuration block has changed'.

Fixes cloudposse#2356.
…ns in SkipInit tests

Strengthens the four SkipInit tests to explicitly verify that
GenerateBackendIfNeeded and GenerateProvidersIfNeeded are called iff
YAML functions were processed. Locks in the cloudposse#2356 fix and the
opposite invariant (auth present -> regen still happens).
…ruption

Integration-level assertion: a pre-written backend.tf.json remains
byte-identical on disk after GetOutputWithOptions(SkipInit=true)
runs against a component whose sections contain literal YAML-function
strings. Fails without the execute() guard; passes with it.
@zack-is-cool zack-is-cool requested a review from a team as a code owner April 22, 2026 20:33
@atmos-pro
Copy link
Copy Markdown
Contributor

atmos-pro Bot commented Apr 22, 2026

Tip

Atmos Pro  

No affected stacks workflow was detected for this pull request.
If this is expected, no action is needed.
Learn More.

View pull request changes on Atmos Pro

@github-actions github-actions Bot added the size/m Medium size PR label Apr 22, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

📝 Walkthrough

Walkthrough

Executor.execute now accepts a new processYamlFunctions boolean and will only invoke backend/provider regeneration when that flag is true. Executor gained an injectable BackendGenerator and WithBackendGenerator option; call sites propagate the flag. Tests and generated mocks updated to cover the new behavior and regression.

Changes

Cohort / File(s) Summary
Core Executor Logic
pkg/terraform/output/executor.go
Added processYamlFunctions bool parameter to execute(), conditional gating around backend/provider regeneration, injected backendGenerator field, WithBackendGenerator() option, default initialization in NewExecutor, and updated mockgen directive to include BackendGenerator. Callers (GetOutput, GetOutputWithOptions, ExecuteWithSections, fetchAndCacheOutputs) updated to pass the flag; ExecuteWithSections docs tightened.
Unit Tests
pkg/terraform/output/executor_test.go
Updated tests to pass explicit processYamlFunctions. Injected MockBackendGenerator via WithBackendGenerator() and added gomock expectations asserting regeneration is skipped when false and invoked when true. Added regression tests for error propagation from backend/provider generation and for the skip branch.
Regression Test & Mocks
pkg/terraform/output/executor_regression_test.go, pkg/terraform/output/mock_executor_test.go
Added regression test TestExecutor_Regression_Issue2356_BackendFileUnchangedInSkipInitPath verifying SkipInit=true path does not overwrite existing backend/provider files when YAML functions are not processed. Generated MockBackendGenerator with GenerateBackendIfNeeded and GenerateProvidersIfNeeded methods and EXPECT recorders.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Executor
    participant BackendGenerator
    participant FS

    Caller->>Executor: GetOutputWithOptions(..., SkipInit, ProcessYamlFunctions)
    Executor->>Executor: determine processYamlFunctions
    alt processYamlFunctions == true
        Executor->>BackendGenerator: GenerateBackendIfNeeded(config, comp, stack, auth)
        BackendGenerator->>FS: write backend.tf.json / providers_override.tf.json
        BackendGenerator-->>Executor: success / error
        Executor->>BackendGenerator: GenerateProvidersIfNeeded(config, auth)
        BackendGenerator->>FS: write providers_override.tf.json
        BackendGenerator-->>Executor: success / error
    else processYamlFunctions == false
        Executor-->>Executor: skip backend/provider regeneration
    end
    Executor->>FS: terraform init/apply or read cached outputs
    Executor-->>Caller: outputs or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • osterman
  • aknysh
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary fix: preventing YAML functions from being written as unrendered literals to backend.tf.json during after-* hooks.
Linked Issues check ✅ Passed The PR directly addresses issue #2356 by threading a processYamlFunctions flag through execute() and guarding artifact regeneration to skip when YAML functions weren't processed upstream.
Out of Scope Changes check ✅ Passed All changes are scoped to the executor's backend/provider regeneration logic and its unit/integration tests; no unrelated modifications present.
Docstring Coverage ✅ Passed Docstring coverage is 92.86% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@zack-is-cool zack-is-cool marked this pull request as draft April 22, 2026 20:39
Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
pkg/terraform/output/executor_regression_test.go (1)

86-88: Assert the executor used the backend file’s workdir.

The test compares backendPath, but the runner factory ignores workdir. Capture it and assert it equals componentDir; otherwise a path-resolution change could make this test pass while checking the wrong file.

Test hardening
+	var capturedWorkdir string
 	customFactory := func(workdir, executable string) (TerraformRunner, error) {
+		capturedWorkdir = workdir
 		return mockRunner, nil
 	}
@@
 	require.NoError(t, err)
+	require.Equal(t, componentDir, capturedWorkdir,
+		"regression test must exercise the same workdir as the backend file under assertion")
 
 	// Assert the file on disk is byte-identical.

Also applies to: 133-139

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/terraform/output/executor_regression_test.go` around lines 86 - 88, The
test's customFactory closure currently ignores its workdir parameter so the test
never verifies the executor used the backend file's workdir; update the closure
used for Terraform runner factory (customFactory) to capture the incoming
workdir argument (e.g., assign to a local variable like capturedWorkdir) and add
an assertion that capturedWorkdir == componentDir (or use testify/require as
used elsewhere) to ensure the factory is called with the backend file's
directory; repeat the same change for the other factory instance referenced in
the test (the one around the 133-139 range) so both factories verify the workdir
parameter instead of ignoring it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/terraform/output/executor_regression_test.go`:
- Around line 86-88: The test's customFactory closure currently ignores its
workdir parameter so the test never verifies the executor used the backend
file's workdir; update the closure used for Terraform runner factory
(customFactory) to capture the incoming workdir argument (e.g., assign to a
local variable like capturedWorkdir) and add an assertion that capturedWorkdir
== componentDir (or use testify/require as used elsewhere) to ensure the factory
is called with the backend file's directory; repeat the same change for the
other factory instance referenced in the test (the one around the 133-139 range)
so both factories verify the workdir parameter instead of ignoring it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f18a6d16-ab46-4781-8fc2-08c1682c0c16

📥 Commits

Reviewing files that changed from the base of the PR and between c1bb921 and 1f58b6b.

📒 Files selected for processing (4)
  • pkg/terraform/output/executor.go
  • pkg/terraform/output/executor_regression_test.go
  • pkg/terraform/output/executor_test.go
  • pkg/terraform/output/mock_executor_test.go

coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 22, 2026
The custom-gcl linter flagged TestExecutor_Execute_SkipsArtifactRegen_WhenYamlFunctionsNotProcessed
as structurally duplicate of TestExecutor_Execute_SkipInit_DirectCall. The two
tests are intentionally parallel — they assert the processYamlFunctions=true vs
=false invariants at the same execute() call site — so sharing scaffolding via
a helper would obscure the red/green contrast this PR is establishing.

No behavior change.
…oviders regen

- TestExecutor_Execute_PropagatesBackendGenError: asserts GenerateBackendIfNeeded
  errors propagate unchanged out of execute() in the processYamlFunctions=true
  branch. Locks in the only newly-reachable error path introduced by the guard.
- TestExecutor_Execute_PropagatesProvidersGenError: symmetric coverage for
  GenerateProvidersIfNeeded, and also confirms execute() short-circuits on the
  first generator error (no downstream runner calls).
- TestExecutor_Regression_Issue2356_...: extended to also pre-write a rendered
  providers_override.tf.json, add a providers section with literal
  '!terraform.state ...' strings, and assert the file is byte-identical after
  the SkipInit path. Manual revert-check confirms both backend and providers
  assertions fire if the guard is removed.

Addresses review findings on error-path and providers coverage gaps.
…ator contract

Addresses review feedback on the cloudposse#2356 fix:

- Expand the Step 4/5 guard comment to explain *why* execute() regenerates
  artifacts in the first place (static remote state, cross-stack
  !terraform.output, auth-present output fetch). Prevents a future reader
  from concluding regen is redundant with apply and deleting it.
- Add log.Debug when the guard skips regeneration, so operators debugging
  hook-related issues can distinguish 'skipped by design (cloudposse#2356)' from
  'never reached this code path'.
- WithBackendGenerator godoc now states explicitly that BackendGenerator is
  an internal test seam, not a stable external extension point.
- ExecuteWithSections gains a caller contract docblock: the sections must
  have ProcessYamlFunctions-evaluated values; literal YAML-function strings
  would bypass the execute() guard (which runs with processYamlFunctions=true
  on this path) and cause the same corruption cloudposse#2356 fixed.

No behavior change — same guarded flow, same public API surface.
CodeRabbit flagged: the customFactory closure was discarding its workdir
parameter, so if upstream path resolution ever changed the byte-compare
could pass vacuously against an untouched file while the real generator
wrote elsewhere.

Capture the workdir the executor asks for and require it equals
componentDir before asserting on file contents.
@zack-is-cool
Copy link
Copy Markdown
Contributor Author

Thanks @coderabbitai — addressed in ddc1653.

The customFactory closure now captures the workdir argument and the test asserts capturedWorkdir == componentDir before the byte-compares. If upstream path resolution ever changes (e.g. a suffix added to utils.GetComponentPath), the test will fail with an explicit workdir mismatch rather than passing vacuously against an untouched file while the real generator writes elsewhere.

Note: there's only one customFactory closure in this file — the "Also applies to: 133-139" reference looks like it was pointing at the assertion block that consumes the captured value, which is now wired in.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

Tip

For best results, initiate chat on the files or code changes.

@zack-is-cool Solid. The captured-workdir assertion is exactly the right guard — if path resolution drifts, the test fails loudly instead of silently passing against a stale file. Thanks for the clarification on the single closure too.


🧠 Learnings used
Learnt from: zack-is-cool
Repo: cloudposse/atmos PR: 2328
File: internal/terraform_backend/terraform_backend_local_test.go:0-0
Timestamp: 2026-04-16T19:29:10.867Z
Learning: In cloudposse/atmos `internal/terraform_backend/terraform_backend_local_test.go` (TestReadTerraformBackendLocal_JITWorkdir "atmos_component with path traversal" subtest): the traversal payload `atmos_component: "../../../../etc/evil"` is prefixed with the stack name (e.g. `demo-`) inside `BuildPath`, producing `demo-../../../../etc/evil`. Because `filepath.Clean` treats `demo-..` as a literal segment, only 3 of the 4 `..` levels are consumed; the derived path may or may not escape `BasePath` depending on its depth. Therefore `require.NotNil` cannot be used here — `nil` is a valid return when the traversal-derived path passes the containment guard but has no state file. The correct invariant assertion is the conditional `if content != nil { assert value == expected }`, which guards "never reads from outside BasePath" without over-constraining the return value.

Learnt from: nitrocode
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2026-03-18T23:56:50.624Z
Learning: In cloudposse/atmos, when auth.TerraformPreHook fails in internal/exec/terraform_execute_helpers_exec.go (prepareComponentExecution function), execution is TERMINATED by returning the error. This is the correct behavior — the code comment reads "Pre-hook failures terminate execution — this matches the original terraform.go behavior. Authentication setup failures must not silently produce unauthenticated terraform commands." The previously stored learning (ID 11a3bc42) that said "execution continues" was stale and incorrect. The original terraform.go always returned on TerraformPreHook error.

If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@zack-is-cool zack-is-cool marked this pull request as ready for review April 22, 2026 21:54
Copy link
Copy Markdown
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.

Caution

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

⚠️ Outside diff range comments (1)
pkg/terraform/output/executor_test.go (1)

1318-1375: ⚠️ Potential issue | 🟡 Minor

The fakeAuthManager := "fake-auth-manager" string will fail the type assertion in fetchAndCacheOutputs before DescribeComponent is reached.

GetAllOutputs calls fetchAndCacheOutputs, which validates that authManager is a real auth.AuthManager (lines 204–209 of executor.go). The test will return ErrInvalidAuthManagerType early, never reaching the DescribeComponent call it's meant to exercise.

Replace the string with a mock auth.AuthManager (use NewMockAuthManager(ctrl) or equivalent) so the test exercises the actual YAML-function processing path it claims to verify.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/terraform/output/executor_test.go` around lines 1318 - 1375, The test
uses a plain string for fakeAuthManager which triggers the auth type check in
fetchAndCacheOutputs and returns ErrInvalidAuthManagerType before
DescribeComponent runs; replace fakeAuthManager := "fake-auth-manager" with a
proper mock implementing auth.AuthManager (e.g. fakeAuthManager :=
NewMockAuthManager(ctrl)) so GetAllOutputs calls into fetchAndCacheOutputs with
a valid auth.AuthManager and the DescribeComponent path
(params.ProcessYamlFunctions) is exercised as intended.
🧹 Nitpick comments (1)
pkg/terraform/output/executor_regression_test.go (1)

188-221: Good helper — the inline comments explaining why the literal !terraform.state ... strings matter (Line 197-201, 208-211) turn this from "test data" into documentation of the bug's surface area.

One minor nit: the helper is unexported and only used by the one regression test in this file. If more #2356-adjacent regression tests land later (e.g. for !terraform.output or other auth-backed functions), consider parameterizing the YAML-function name so each scenario gets its own canonical fixture without copy-paste. Not a blocker for this PR — just flagging for the follow-up tracked in #2357.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/terraform/output/executor_regression_test.go` around lines 188 - 221, The
helper regressionSectionsWithLiteralYamlFunctions should be parameterized to
accept the YAML-function identifier (e.g. yamlFunc string) instead of hardcoding
"!terraform.state" so tests can reuse it for other YAML functions; update the
function signature regressionSectionsWithLiteralYamlFunctions(yamlFunc string)
and replace the inline literals (used by GenerateBackendIfNeeded and
GenerateProvidersIfNeeded test scenarios) with formatted strings that prepend
"!" + yamlFunc (e.g. "!"+yamlFunc+" ..."), and update the single regression test
call to pass "terraform.state" (future tests can pass "terraform.output" etc.).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@pkg/terraform/output/executor_test.go`:
- Around line 1318-1375: The test uses a plain string for fakeAuthManager which
triggers the auth type check in fetchAndCacheOutputs and returns
ErrInvalidAuthManagerType before DescribeComponent runs; replace fakeAuthManager
:= "fake-auth-manager" with a proper mock implementing auth.AuthManager (e.g.
fakeAuthManager := NewMockAuthManager(ctrl)) so GetAllOutputs calls into
fetchAndCacheOutputs with a valid auth.AuthManager and the DescribeComponent
path (params.ProcessYamlFunctions) is exercised as intended.

---

Nitpick comments:
In `@pkg/terraform/output/executor_regression_test.go`:
- Around line 188-221: The helper regressionSectionsWithLiteralYamlFunctions
should be parameterized to accept the YAML-function identifier (e.g. yamlFunc
string) instead of hardcoding "!terraform.state" so tests can reuse it for other
YAML functions; update the function signature
regressionSectionsWithLiteralYamlFunctions(yamlFunc string) and replace the
inline literals (used by GenerateBackendIfNeeded and GenerateProvidersIfNeeded
test scenarios) with formatted strings that prepend "!" + yamlFunc (e.g.
"!"+yamlFunc+" ..."), and update the single regression test call to pass
"terraform.state" (future tests can pass "terraform.output" etc.).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8b4d32ab-f310-4502-bc98-cf3950830ee9

📥 Commits

Reviewing files that changed from the base of the PR and between 1f58b6b and ddc1653.

📒 Files selected for processing (3)
  • pkg/terraform/output/executor.go
  • pkg/terraform/output/executor_regression_test.go
  • pkg/terraform/output/executor_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/terraform/output/executor.go

coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 22, 2026
@aknysh aknysh added the patch A minor, backward compatible change label Apr 23, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.95%. Comparing base (c1bb921) to head (2a23561).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2358      +/-   ##
==========================================
- Coverage   77.35%   76.95%   -0.41%     
==========================================
  Files        1089     1089              
  Lines      102828   135605   +32777     
==========================================
+ Hits        79547   104354   +24807     
- Misses      18909    26880    +7971     
+ Partials     4372     4371       -1     
Flag Coverage Δ
unittests 76.95% <100.00%> (-0.41%) ⬇️

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

Files with missing lines Coverage Δ
pkg/terraform/output/executor.go 89.58% <100.00%> (+2.88%) ⬆️

... and 1032 files with indirect coverage changes

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

gofumpt moved //nolint:dupl below its intended site and left an orphan
'by design —' lowercase sentence that godot flagged. Restructure so the
nolint directive sits directly above the func and the explanatory comment
reads as a complete sentence.
Copy link
Copy Markdown
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.

🧹 Nitpick comments (2)
pkg/terraform/output/executor_test.go (2)

1326-1374: Use a typed auth manager for this regression test.

This now asserts the auth-present path, but fakeAuthManager is a string. That only proves “non-nil flips the flag” and conflicts with nearby invalid-auth tests. Prefer a real/mock auth.AuthManager so the test covers the path users can actually hit. As per coding guidelines, “Test behavior, not implementation. Never test stub functions. Avoid tautological tests.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/terraform/output/executor_test.go` around lines 1326 - 1374, The test
uses a string as fakeAuthManager which only verifies non-nil behavior; replace
it with a real typed auth.AuthManager mock (e.g., create mockAuthMgr :=
mock_auth.NewMockAuthManager(ctrl) or a concrete auth.AuthManager test double)
and pass that into exec.GetAllOutputs so the DescribeComponent expectation
asserts the actual typed manager; update the DescribeComponent DoAndReturn to
assert params.AuthManager equals mockAuthMgr and adjust any imports/setup to use
the mock auth package and controller.

1479-1484: Fix the duplicate-test rationale.

This says the duplicate tests contrast processYamlFunctions=true vs false, but this test and TestExecutor_Execute_SkipInit_DirectCall both pass false. Please update the comment to point at the auth-present/generator-called coverage, or remove the duplicate if it no longer adds a separate invariant.

Suggested wording
-// design — the two tests contrast the processYamlFunctions=true vs =false
-// invariants at the same execute() call site, so sharing scaffolding via a
-// helper would obscure the side-by-side comparison.
+// design — this test isolates the processYamlFunctions=false invariant at
+// execute(), while the auth-present tests cover the processYamlFunctions=true
+// regeneration path.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/terraform/output/executor_test.go` around lines 1479 - 1484, The
duplicate-test rationale is incorrect: both this test and
TestExecutor_Execute_SkipInit_DirectCall pass processYamlFunctions=false, so
update the comment above this test to accurately explain what the test adds
(e.g., it covers the "auth present / generator called" behavior difference
versus the other test) or if the test is redundant remove it; specifically edit
the comment that references processYamlFunctions to instead reference the
auth/generator invariant (or delete the duplicated test) and keep the
//nolint:dupl line only if you retain intentional duplication for that corrected
rationale.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/terraform/output/executor_test.go`:
- Around line 1326-1374: The test uses a string as fakeAuthManager which only
verifies non-nil behavior; replace it with a real typed auth.AuthManager mock
(e.g., create mockAuthMgr := mock_auth.NewMockAuthManager(ctrl) or a concrete
auth.AuthManager test double) and pass that into exec.GetAllOutputs so the
DescribeComponent expectation asserts the actual typed manager; update the
DescribeComponent DoAndReturn to assert params.AuthManager equals mockAuthMgr
and adjust any imports/setup to use the mock auth package and controller.
- Around line 1479-1484: The duplicate-test rationale is incorrect: both this
test and TestExecutor_Execute_SkipInit_DirectCall pass
processYamlFunctions=false, so update the comment above this test to accurately
explain what the test adds (e.g., it covers the "auth present / generator
called" behavior difference versus the other test) or if the test is redundant
remove it; specifically edit the comment that references processYamlFunctions to
instead reference the auth/generator invariant (or delete the duplicated test)
and keep the //nolint:dupl line only if you retain intentional duplication for
that corrected rationale.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5e011343-5301-49f2-bfd6-790a7e5cc115

📥 Commits

Reviewing files that changed from the base of the PR and between ddc1653 and 2a23561.

📒 Files selected for processing (1)
  • pkg/terraform/output/executor_test.go

@aknysh aknysh merged commit 0f648b1 into cloudposse:main Apr 23, 2026
56 of 57 checks passed
@atmos-pro
Copy link
Copy Markdown
Contributor

atmos-pro Bot commented Apr 23, 2026

Note

Atmos Pro  

Waiting for your GitHub Actions workflow to upload affected stacks.
Learn More.

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

Labels

patch A minor, backward compatible change size/m Medium size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

after-terraform-apply hook corrupts backend.tf.json when backend uses !terraform.state

2 participants