Skip to content

fix(io): migrate fmt.Fprintf/Println anti-patterns to pkg/ui, pkg/data - #2713

Merged
Andriy Knysh (aknysh) merged 19 commits into
mainfrom
osterman/pr-instructions
Jul 13, 2026
Merged

Andriy Knysh (aknysh) merged 19 commits into
mainfrom
osterman/pr-instructions

Conversation

@osterman

@osterman Erik Osterman (Cloud Posse) (osterman) commented Jul 10, 2026 •

Copy link
Copy Markdown
Member

what

  • Migrate every remaining raw fmt.Fprintf/fmt.Fprintln/fmt.Println call outside pkg/io/pkg/ui to the sanctioned ui.*/data.* API across ~40 files (AI permission prompts, devcontainer/kubeconfig debug diagnostics, CI annotations/log groups, the Cobra root command, pkg/manifest, pkg/runner/step cast recording, and more).
  • Delete the pure print-forwarding shims in pkg/utils (PrintMessage, PrintfMessageToTUI, PrintfMarkdown*) and migrate all ~50 call sites directly onto data.*/ui.*, consolidating onto the already-established ui.Markdown/ui.MarkdownMessage renderer instead of a second, bespoke one.
  • Add data.WriteUnmasked/WriteUnmaskedf, an explicit escape hatch for the one legitimate case where masking must not apply (atmos auth env / atmos env emitting real credential values for shell eval).
  • Add ui.MarkdownNoWrap/MarkdownMessageNoWrap for deterministic, snapshot-stable single-line notices (used by the telemetry disclosure).
  • Fix RootCmd's default output writer to route through the masked I/O context instead of raw os.Stdout, and extract the oversized Cobra help/usage closures into named helpers while there.
  • Correct pkg/devcontainer's ShowConfig/List output to the data channel (primary command output) instead of the UI channel, and update the affected CLI golden snapshots to match.

why

  • CLAUDE.md bans raw fmt.Fprintf/fmt.Println outside pkg/io/pkg/ui because it bypasses secret masking, TTY/color degradation, and --cast recording. Several call sites found in this audit (AI permission prompts, devcontainer/kubeconfig debug output, CI annotations, the Cobra help writer) genuinely bypassed masking entirely.
  • The pkg/utils print helpers were pure forwarding shims duplicating pkg/ui/pkg/data, adding an unnecessary second code path for callers to reason about; deleting them and routing directly through the canonical API reduces pkg/utils's surface area per this repo's ongoing effort to empty that package out.
  • atmos auth env/atmos env need one legitimate, explicit way to emit unmasked output (the whole point of those commands is exporting real credentials for eval), so a dedicated WriteUnmasked API makes that intent explicit instead of ad hoc fmt.Print calls.

references

@atmos-pro

atmos-pro Bot commented Jul 10, 2026 •

Copy link
Copy Markdown
Contributor

Tip

Atmos Pro  

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

@osterman Erik Osterman (Cloud Posse) (osterman) added the patch A minor, backward compatible change label Jul 10, 2026
@github-actions github-actions Bot added the size/l Large size PR label Jul 10, 2026
@mergify

mergify Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Important

Cloud Posse Engineering Team Review Required

This pull request modifies files that require Cloud Posse's review. Please be patient, and a core maintainer will review your changes.

To expedite this process, reach out to us on Slack in the #pr-reviews channel.

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@mergify mergify Bot added the needs-cloudposse Needs Cloud Posse assistance label Jul 10, 2026
@github-actions

github-actions Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Resource Changes Found for bucket in test

Atmos CI

create

Plan: 4 to add, 0 to change, 0 to destroy.
To reproduce this locally, run:

atmos terraform plan bucket -s test

Create

+ aws_s3_bucket.checkov_target
+ aws_s3_bucket.this
+ aws_s3_bucket.trivy_target
+ aws_s3_bucket_public_access_block.trivy_target
Terraform Plan Summary
  # aws_s3_bucket.checkov_target will be created
  + resource "aws_s3_bucket" "checkov_target" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = "atmos-native-ci-e2e-checkov-test"
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = (known after apply)
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags_all                    = (known after apply)
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)

      + cors_rule (known after apply)

      + grant (known after apply)

      + lifecycle_rule (known after apply)

      + logging (known after apply)

      + object_lock_configuration (known after apply)

      + replication_configuration (known after apply)

      + server_side_encryption_configuration (known after apply)

      + versioning (known after apply)

      + website (known after apply)
    }

  # aws_s3_bucket.this will be created
  + resource "aws_s3_bucket" "this" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = "atmos-native-ci-e2e-test"
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = (known after apply)
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags                        = {
          + "AtmosFixture" = "native-ci-e2e"
          + "Stage"        = "test"
        }
      + tags_all                    = {
          + "AtmosFixture" = "native-ci-e2e"
          + "Stage"        = "test"
        }
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)

      + cors_rule (known after apply)

      + grant (known after apply)

      + lifecycle_rule (known after apply)

      + logging (known after apply)

      + object_lock_configuration (known after apply)

      + replication_configuration (known after apply)

      + server_side_encryption_configuration (known after apply)

      + versioning (known after apply)

      + website (known after apply)
    }

  # aws_s3_bucket.trivy_target will be created
  + resource "aws_s3_bucket" "trivy_target" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = "atmos-native-ci-e2e-trivy-test"
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = (known after apply)
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags_all                    = (known after apply)
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)

      + cors_rule (known after apply)

      + grant (known after apply)

      + lifecycle_rule (known after apply)

      + logging (known after apply)

      + object_lock_configuration (known after apply)

      + replication_configuration (known after apply)

      + server_side_encryption_configuration (known after apply)

      + versioning (known after apply)

      + website (known after apply)
    }

  # aws_s3_bucket_public_access_block.trivy_target will be created
  + resource "aws_s3_bucket_public_access_block" "trivy_target" {
      + block_public_acls       = true
      + block_public_policy     = true
      + bucket                  = (known after apply)
      + id                      = (known after apply)
      + ignore_public_acls      = true
      + restrict_public_buckets = true
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + bucket_name = "atmos-native-ci-e2e-test"

@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a62591e4-d979-4179-b2c5-5689964b4b98

📥 Commits

Reviewing files that changed from the base of the PR and between 3e99bfa and 4b785c2.

📒 Files selected for processing (1)
  • cmd/version/formatters_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/version/formatters_test.go

📝 Walkthrough

Walkthrough

This PR migrates output to shared data and ui helpers, adds no-wrap Markdown and unmasked writing, refactors root help and interactive prompts, improves structured diagnostics, initializes test I/O, and updates CI, hooks, tests, and snapshots.

Changes

Output and interaction migration

Layer / File(s) Summary
Shared data and UI foundations
pkg/data/*, pkg/ui/*, pkg/utils/*, pkg/telemetry/*
Adds unmasked and no-wrap Markdown writers, updates formatter APIs, and removes legacy utility output helpers.
Command output and root help flow
cmd/*, internal/exec/*, pkg/list/*, pkg/manifest/*
Routes output through shared helpers and restructures Cobra usage, help, pager, telemetry, and update rendering.
Interactive prompts and session behavior
pkg/ai/*, errors/errors.go, cmd/ai/*
Adds TTY-aware huh prompts, prompt error sentinels, UI status output, and session cleanup coverage.
Package and provider output migration
pkg/auth/*, pkg/ci/*, pkg/devcontainer/*, pkg/env/*, pkg/runner/*, pkg/toolchain/*
Replaces direct stream writes with shared data or UI output and propagates selected write errors.
Test I/O and behavior coverage
**/*_test.go
Initializes shared test I/O and adds coverage for rendering, write failures, TTY failures, diagnostics, and command execution paths.
Diagnostics, CI, and snapshots
.github/*, .pre-commit-config.yaml, .atmos.d/*, tests/snapshots/*, tests/cli_test.go
Adds dependency retries and hook stages, updates CI build commands and timeouts, and aligns snapshot normalization and golden output.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: aknysh, maxymvlasov

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: replacing raw fmt-based output with pkg/ui and pkg/data helpers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch osterman/pr-instructions

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
pkg/ci/providers/generic/provider.go (1)

181-183: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stale comment: says "write to stderr" but now uses ui.Writef.

The comment on line 181 still reads "No summary file configured - write to stderr." but the code now routes through ui.Writef, which writes through the UI formatter channel, not directly to stderr. Update the comment to reflect the new output path.

♻️ Update stale comment
-	// No summary file configured - write to stderr.
-	// This makes the summary visible in local testing.
+	// No summary file configured - write through the UI channel.
+	// This makes the summary visible in local testing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/ci/providers/generic/provider.go` around lines 181 - 183, Update the
stale comment above the ui.Writef call in the generic provider’s summary-output
logic to describe writing through the UI formatter/channel instead of directly
to stderr.
cmd/ai/sessions.go (1)

289-291: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider ui.Writeln for human-facing session messages.

These messages (e.g., "✅ Deleted N session(s)...", "Resume the session with: ...") are human-facing UI messages, not pipeable data. Per coding guidelines, human-facing UI messages should go through ui.* functions. Using ui.Writeln would also remove the _ = error-discarding pattern since it's void.

As per coding guidelines: "Write pipeable data through data.Write/data.Writef/data.Writeln/data.WriteJSON/data.WriteYAML and human-facing UI messages through ui functions."

♻️ Suggested refactor
 func cleanSessionsCommand(cmd *cobra.Command, args []string) error {
 	// ...
 	if count == 0 {
-		_ = data.Writeln("No sessions to clean.")
+		ui.Writeln("No sessions to clean.")
 	} else {
-		_ = data.Writeln(fmt.Sprintf("✅ Deleted %d session(s) older than %s", count, olderThanStr))
+		ui.Writeln(fmt.Sprintf("✅ Deleted %d session(s) older than %s", count, olderThanStr))
 	}
 	// ...
 }

Apply the same pattern to exportSessionCommand (line 367) and importSessionCommand (lines 408-414), replacing _ = data.Writeln(...) with ui.Writeln(...).

Also applies to: 367-367, 408-414

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/ai/sessions.go` around lines 289 - 291, Replace human-facing session
status and guidance messages emitted by the affected cleanup,
exportSessionCommand, and importSessionCommand paths with ui.Writeln instead of
data.Writeln; remove the _ = error-discarding assignments. Keep data writers
only for pipeable output, including messages such as “No sessions to clean,”
deletion summaries, and resume instructions.

Source: Coding guidelines

pkg/devcontainer/lifecycle_config.go (1)

37-153: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider propagating write errors from print functions.

All print helpers silently discard data.Writef/data.Writeln errors with _ =. While this matches the prior fmt.Printf behavior (which also ignored errors), ShowConfig returns error and could propagate write failures (e.g., broken pipe) if the print functions returned error. This is a pre-existing pattern made explicit by the migration, so deferring is fine.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/devcontainer/lifecycle_config.go` around lines 37 - 153, Defer this
refactor for now; retain the existing ignored data.Writef/data.Writeln errors
across printBasicInfo, printBuildInfo, printWorkspaceInfo, printMounts,
printPorts, printEnv, printRunArgs, and printRemoteUser. If addressed later,
change each helper to return and propagate errors through ShowConfig rather than
discarding them.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/root.go`:
- Around line 2270-2313: Restore the command’s original output writer after
buffered help rendering so the --cast tee remains active. In both renderFlagHelp
and renderInteractiveHelp, save command.OutOrStdout() before
command.SetOut(&buf), then restore it after command.Help() (ideally with defer)
while preserving the buffered content for pager output.

In `@pkg/data/data_test.go`:
- Around line 441-477: TestWriteUnmasked_BypassesMasking leaks the package-level
I/O context and registered secret. Save the existing globalIOContext before
calling InitWriter(ioCtx), then restore it with defer immediately after setup,
while retaining direct ioCtx access for masker registration.

In `@pkg/ui/formatter.go`:
- Around line 290-294: In MarkdownMessageNoWrap, the MarkdownNoWrap error branch
overwrites its correctly formatted fallback with raw content. Remove the
rendered = content override and preserve the rendered value returned by
globalFormatter.MarkdownNoWrap, including its trimmed content and trailing
newline.

In `@tests/snapshots/TestCLICommands_atmos_support.stdout.golden`:
- Line 8: Fix the malformed GitHub URL in the snapshot output by locating the
source text or wrapping/no-wrap Markdown logic that produces “https://github.
com/cloudposse/atmos/issues” and preserving
“https://github.com/cloudposse/atmos/issues” without the inserted space; update
the golden snapshot only if the generated output is correct.

---

Nitpick comments:
In `@cmd/ai/sessions.go`:
- Around line 289-291: Replace human-facing session status and guidance messages
emitted by the affected cleanup, exportSessionCommand, and importSessionCommand
paths with ui.Writeln instead of data.Writeln; remove the _ = error-discarding
assignments. Keep data writers only for pipeable output, including messages such
as “No sessions to clean,” deletion summaries, and resume instructions.

In `@pkg/ci/providers/generic/provider.go`:
- Around line 181-183: Update the stale comment above the ui.Writef call in the
generic provider’s summary-output logic to describe writing through the UI
formatter/channel instead of directly to stderr.

In `@pkg/devcontainer/lifecycle_config.go`:
- Around line 37-153: Defer this refactor for now; retain the existing ignored
data.Writef/data.Writeln errors across printBasicInfo, printBuildInfo,
printWorkspaceInfo, printMounts, printPorts, printEnv, printRunArgs, and
printRemoteUser. If addressed later, change each helper to return and propagate
errors through ShowConfig rather than discarding them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f555c66b-e29d-42dd-8e7b-092079395710

📥 Commits

Reviewing files that changed from the base of the PR and between 708f70e and adbedb0.

📒 Files selected for processing (87)
  • cmd/ai/ask.go
  • cmd/ai/sessions.go
  • cmd/ai/testmain_test.go
  • cmd/auth/env.go
  • cmd/cmd_utils.go
  • cmd/cmd_utils_test.go
  • cmd/custom_command_integration_test.go
  • cmd/devcontainer/helpers.go
  • cmd/devcontainer/interfaces.go
  • cmd/devcontainer/mock_interfaces_test.go
  • cmd/devcontainer/providers.go
  • cmd/devcontainer/providers_test.go
  • cmd/devcontainer/service.go
  • cmd/devcontainer/service_test.go
  • cmd/docs.go
  • cmd/list/settings.go
  • cmd/list/values.go
  • cmd/root.go
  • cmd/support.go
  • cmd/testing_helpers_test.go
  • cmd/testing_main_test.go
  • cmd/version/formatters.go
  • cmd/version/testmain_test.go
  • internal/exec/atmos.go
  • internal/exec/docs_generate.go
  • internal/exec/pro.go
  • internal/exec/shell_utils.go
  • internal/exec/testmain_test.go
  • internal/exec/validate_schema.go
  • internal/exec/version.go
  • internal/exec/workflow_adapters.go
  • internal/exec/workflow_utils.go
  • pkg/ai/context.go
  • pkg/ai/session/manager.go
  • pkg/ai/tools/permission/checker_test.go
  • pkg/ai/tools/permission/prompter.go
  • pkg/ai/tools/permission/testmain_test.go
  • pkg/atlantis/testmain_test.go
  • pkg/auth/cloud/kube/config.go
  • pkg/auth/credentials/store.go
  • pkg/auth/identities/aws/webflow_ui.go
  • pkg/auth/providers/aws/sso.go
  • pkg/aws/aws_eks_update_kubeconfig_test.go
  • pkg/ci/providers/generic/provider.go
  • pkg/ci/providers/github/annotations.go
  • pkg/ci/providers/github/annotations_test.go
  • pkg/ci/providers/github/log_group.go
  • pkg/ci/providers/github/log_group_test.go
  • pkg/component/mock/mock.go
  • pkg/data/data.go
  • pkg/data/data_test.go
  • pkg/devcontainer/lifecycle_config.go
  • pkg/devcontainer/lifecycle_list.go
  • pkg/devcontainer/testmain_test.go
  • pkg/env/output.go
  • pkg/env/testmain_test.go
  • pkg/hooks/main_test.go
  • pkg/list/list_instances.go
  • pkg/manifest/render.go
  • pkg/manifest/testmain_test.go
  • pkg/provisioner/source/cmd/testmain_test.go
  • pkg/runner/step/cast.go
  • pkg/runner/step/cast_simulate.go
  • pkg/runner/step/testmain_test.go
  • pkg/telemetry/testmain_test.go
  • pkg/telemetry/utils.go
  • pkg/telemetry/utils_test.go
  • pkg/ui/formatter.go
  • pkg/ui/formatter_test.go
  • pkg/ui/interfaces.go
  • pkg/ui/output_test.go
  • pkg/utils/doc_utils.go
  • pkg/utils/go_getter_utils_test.go
  • pkg/utils/json_utils.go
  • pkg/utils/log_utils.go
  • pkg/utils/log_utils_test.go
  • pkg/utils/markdown_utils.go
  • pkg/utils/markdown_utils_test.go
  • pkg/utils/version_utils.go
  • pkg/utils/yaml_utils.go
  • tests/snapshots/TestCLICommands_atmos.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_atlantis_generate_repo-config.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_doesnt_warn_if_in_git_repo_with_no_atmos_config.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_list_instances.tty.golden
  • tests/snapshots/TestCLICommands_atmos_support.stdout.golden
  • tests/snapshots/TestCLICommands_atmos_warns_if_not_in_git_repo_with_no_atmos_config.stderr.golden
  • tests/snapshots/TestCLICommands_check_atmos_in_empty-dir.stderr.golden
💤 Files with no reviewable changes (11)
  • pkg/utils/markdown_utils_test.go
  • pkg/aws/aws_eks_update_kubeconfig_test.go
  • cmd/devcontainer/interfaces.go
  • cmd/devcontainer/service_test.go
  • pkg/utils/markdown_utils.go
  • cmd/devcontainer/providers.go
  • pkg/utils/log_utils_test.go
  • pkg/telemetry/utils_test.go
  • cmd/devcontainer/providers_test.go
  • cmd/devcontainer/mock_interfaces_test.go
  • pkg/utils/log_utils.go

Comment thread cmd/root.go
Comment thread pkg/data/data_test.go
Comment thread pkg/ui/formatter.go
Comment thread tests/snapshots/TestCLICommands_atmos_support.stdout.golden Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/data/data_test.go`:
- Around line 721-809: Update setupTestIO to capture the current package-level
markdown renderer before tests run and restore it during cleanup, alongside
globalIOContext. Ensure all tests using SetMarkdownRenderer, including
TestMarkdownNoWrap and its fallback/error variants, leave the original renderer
intact for subsequent tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cb1c9f2e-f9b8-43b3-9d01-ad0698bd5af4

📥 Commits

Reviewing files that changed from the base of the PR and between adbedb0 and 08de036.

📒 Files selected for processing (7)
  • cmd/help_template_test.go
  • cmd/root.go
  • cmd/support.go
  • pkg/data/data.go
  • pkg/data/data_test.go
  • pkg/ui/formatter.go
  • tests/snapshots/TestCLICommands_atmos_support.stdout.golden
✅ Files skipped from review due to trivial changes (1)
  • tests/snapshots/TestCLICommands_atmos_support.stdout.golden
🚧 Files skipped from review as they are similar to previous changes (3)
  • cmd/support.go
  • pkg/ui/formatter.go
  • cmd/root.go

Comment thread pkg/data/data_test.go
Erik Osterman (Cloud Posse) (osterman) added a commit that referenced this pull request Jul 10, 2026
… markdown renderer in data test helper

- Bump the shared macOS/Windows "Acceptance tests" step timeout from 45 to
  60 minutes. Windows has repeatedly run right up against the 45-minute cap
  and gotten force-cancelled before finishing, failing the job with no real
  test failure in the logs; still comfortably inside the job's 75-minute
  overall timeout.
- pkg/data/data_test.go: setupTestIO now also snapshots and restores
  globalMarkdownRender (not just globalIOContext), so tests calling
  SetMarkdownRenderer no longer leak a mock renderer into later tests
  (CodeRabbit review comment on PR #2713).
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 10, 2026
@codecov

codecov Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.11911% with 64 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.61%. Comparing base (86edc83) to head (4b785c2).

Files with missing lines Patch % Lines
pkg/ai/tools/permission/prompter.go 25.53% 35 Missing ⚠️
pkg/ai/context.go 13.33% 13 Missing ⚠️
pkg/toolchain/uninstall.go 61.90% 7 Missing and 1 partial ⚠️
cmd/root.go 94.44% 3 Missing and 2 partials ⚠️
pkg/ui/formatter.go 93.10% 1 Missing and 1 partial ⚠️
cmd/devcontainer/helpers.go 0.00% 1 Missing ⚠️

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

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2713      +/-   ##
==========================================
+ Coverage   81.32%   81.61%   +0.29%     
==========================================
  Files        1641     1639       -2     
  Lines      154729   154739      +10     
==========================================
+ Hits       125830   126290     +460     
+ Misses      21974    21533     -441     
+ Partials     6925     6916       -9     
Flag Coverage Δ
unittests 81.61% <84.11%> (+0.29%) ⬆️

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

Files with missing lines Coverage Δ
cmd/ai/ask.go 77.50% <100.00%> (+4.66%) ⬆️
cmd/ai/sessions.go 89.23% <100.00%> (+1.02%) ⬆️
cmd/auth/env.go 83.19% <100.00%> (+0.28%) ⬆️
cmd/auth/helpers.go 92.06% <100.00%> (+0.26%) ⬆️
cmd/cmd_utils.go 69.50% <100.00%> (+0.42%) ⬆️
cmd/devcontainer/providers.go 60.00% <ø> (-2.17%) ⬇️
cmd/devcontainer/service.go 86.11% <100.00%> (ø)
cmd/docs.go 11.11% <100.00%> (ø)
cmd/list/settings.go 74.64% <100.00%> (+35.75%) ⬆️
cmd/list/values.go 70.23% <100.00%> (+28.81%) ⬆️
... and 41 more

... and 24 files with indirect coverage changes

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

Erik Osterman (Cloud Posse) (osterman) added a commit that referenced this pull request Jul 10, 2026
Adds targeted unit tests for the largest patch-coverage gaps flagged by
Codecov on this branch (144 uncovered added lines across 19 files):

- cmd/root.go: help-rendering cluster (initCobraConfig, rootUsageFunc,
  isHelpRequested, parsePagerFlagValue, renderFlagHelp, renderInteractiveHelp,
  renderRootHelp, rootHelpFunc) via new cmd/root_help_render_test.go.
- pkg/auth/cloud/kube/config.go: debug-diff comparison helpers
  (configContentEqual, *MapsEqualDebug, mergeWouldChange), 100% covered.
- pkg/data/data.go + pkg/ui/formatter.go: WriteUnmasked/MarkdownNoWrap
  error paths and MarkdownMessageNoWrap/markdownRenderWidth branches.
- 8 small cmd/* files (auth/env, version/formatters, list/values,
  list/settings, support, ai/ask, ai/sessions, devcontainer/helpers) and
  7 small pkg/*+internal/exec files (ai/context, auth/providers/aws/sso,
  runner/step/cast_simulate, exec/atmos, exec/workflow_utils,
  ai/session/manager, auth/credentials/store).

pkg/ai/session/compactor.go gets a //go:generate mockgen directive (plus
the generated pkg/ai/session/mock_compactor.go) so Compactor can be mocked
for the manager_test.go additions - no behavior change.

A handful of lines (~11) remain uncovered where testing would require
faking a real TTY (boa/bubbletea usage rendering, isatty-gated devcontainer
prompt) or adding a DI seam with no other use, documented inline.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/ai/context_test.go`:
- Around line 16-51: Add a dedicated “closed pipe returns error” subtest
alongside the existing cases in TestPromptForConsent: replace os.Stdin with a
pipe, close the write end without writing input, invoke PromptForConsent, and
assert that an error is returned. Ensure stdin restoration and pipe
setup/cleanup match the existing test pattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0f1793a3-177c-48db-9e61-5358374a953f

📥 Commits

Reviewing files that changed from the base of the PR and between 660d10a and 26d10d4.

📒 Files selected for processing (21)
  • cmd/ai/ask_test.go
  • cmd/ai/sessions_test.go
  • cmd/auth/env_test.go
  • cmd/list/settings_test.go
  • cmd/list/values_test.go
  • cmd/root_help_render_test.go
  • cmd/support_test.go
  • cmd/version/formatters_test.go
  • internal/exec/atmos_test.go
  • internal/exec/workflow_utils_test.go
  • pkg/ai/context_test.go
  • pkg/ai/session/compactor.go
  • pkg/ai/session/manager_test.go
  • pkg/ai/session/mock_compactor.go
  • pkg/auth/cloud/kube/config_diff_test.go
  • pkg/auth/credentials/store_test.go
  • pkg/auth/providers/aws/sso_test.go
  • pkg/data/data_test.go
  • pkg/runner/step/cast_simulate_test.go
  • pkg/ui/formatter_test.go
  • pkg/ui/output_test.go
✅ Files skipped from review due to trivial changes (2)
  • pkg/ai/session/compactor.go
  • pkg/ai/session/mock_compactor.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/data/data_test.go

Comment thread pkg/ai/context_test.go Outdated
Erik Osterman (Cloud Posse) (osterman) added a commit that referenced this pull request Jul 10, 2026
Add a "closed pipe returns error" case to TestPromptForConsent for the
reader.ReadString EOF-without-delimiter branch, per CodeRabbit review on
PR #2713.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 10, 2026
…data

Audits and migrates every remaining raw fmt.Fprintf/Fprintln/Println call
outside pkg/io/pkg/ui to the sanctioned ui.*/data.* API, so all output
consistently goes through secret masking, TTY/color degradation, and
--cast recording as CLAUDE.md requires. Several call sites (AI permission
prompts, devcontainer/kubeconfig debug diagnostics, CI annotations, the
Cobra help writer) previously bypassed masking entirely.

- Add data.WriteUnmasked/WriteUnmaskedf, an explicit escape hatch for the
  one legitimate case where masking must not apply: atmos auth env / atmos
  env emitting real credential values for shell eval.
- Add ui.MarkdownNoWrap/MarkdownMessageNoWrap for deterministic,
  snapshot-stable single-line notices (used by the telemetry disclosure).
- Delete the pure print-forwarding shims in pkg/utils
  (PrintMessage/PrintfMessageToTUI/PrintfMarkdown*) and migrate all ~50
  call sites directly to data.*/ui.*, consolidating onto the
  already-established ui.Markdown/MarkdownMessage renderer instead of a
  second, bespoke one.
- Fix RootCmd's default output writer (cmd/root.go) to route through the
  masked I/O context instead of raw os.Stdout, without touching Cobra's
  help/usage template writer convention; extracted the oversized help/usage
  closures into named helpers while there.
- Correct pkg/devcontainer's ShowConfig/List output to the data channel
  (primary command output) instead of the UI channel it was mismigrated
  to initially.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…, stabilize CI markdown tests

- data.MarkdownNoWrap/MarkdownNoWrapf render markdown without word-wrap so
  long inline URLs in `atmos support` no longer get hard-broken mid-domain
  (e.g. "https://github. com/...") when they don't fit the wrap width.
- renderFlagHelp/renderInteractiveHelp restore the command's original writer
  after buffering into a pager, so it isn't left pointed at a discarded
  buffer for output written after the function returns.
- cmd/help_template_test.go strips ANSI codes before asserting on rendered
  description text, since CI=true forces color output (see
  terminal.DetectColorProfile) and Glamour wraps each word in its own style
  span, breaking plain substring checks.
… markdown renderer in data test helper

- Bump the shared macOS/Windows "Acceptance tests" step timeout from 45 to
  60 minutes. Windows has repeatedly run right up against the 45-minute cap
  and gotten force-cancelled before finishing, failing the job with no real
  test failure in the logs; still comfortably inside the job's 75-minute
  overall timeout.
- pkg/data/data_test.go: setupTestIO now also snapshots and restores
  globalMarkdownRender (not just globalIOContext), so tests calling
  SetMarkdownRenderer no longer leak a mock renderer into later tests
  (CodeRabbit review comment on PR #2713).
Adds targeted unit tests for the largest patch-coverage gaps flagged by
Codecov on this branch (144 uncovered added lines across 19 files):

- cmd/root.go: help-rendering cluster (initCobraConfig, rootUsageFunc,
  isHelpRequested, parsePagerFlagValue, renderFlagHelp, renderInteractiveHelp,
  renderRootHelp, rootHelpFunc) via new cmd/root_help_render_test.go.
- pkg/auth/cloud/kube/config.go: debug-diff comparison helpers
  (configContentEqual, *MapsEqualDebug, mergeWouldChange), 100% covered.
- pkg/data/data.go + pkg/ui/formatter.go: WriteUnmasked/MarkdownNoWrap
  error paths and MarkdownMessageNoWrap/markdownRenderWidth branches.
- 8 small cmd/* files (auth/env, version/formatters, list/values,
  list/settings, support, ai/ask, ai/sessions, devcontainer/helpers) and
  7 small pkg/*+internal/exec files (ai/context, auth/providers/aws/sso,
  runner/step/cast_simulate, exec/atmos, exec/workflow_utils,
  ai/session/manager, auth/credentials/store).

pkg/ai/session/compactor.go gets a //go:generate mockgen directive (plus
the generated pkg/ai/session/mock_compactor.go) so Compactor can be mocked
for the manager_test.go additions - no behavior change.

A handful of lines (~11) remain uncovered where testing would require
faking a real TTY (boa/bubbletea usage rendering, isatty-gated devcontainer
prompt) or adding a DI seam with no other use, documented inline.
Add a "closed pipe returns error" case to TestPromptForConsent for the
reader.ReadString EOF-without-delimiter branch, per CodeRabbit review on
PR #2713.
…er CI=true

CI=true forces color output (see terminal.DetectColorProfile), which made
Glamour wrap "test command"/" description" in separate ANSI style spans and
broke the plain assert.Contains checks - same class of failure fixed
earlier for TestRenderMarkdownDescription/TestPrintDescription.
Bubble Tea fails fast when it can't open a controlling TTY on Unix
(openInputTTY falls back to /dev/tty and errors immediately), which this
test relied on to reach ExecuteAtmosCmd's error-return path without a real
interactive session. On Windows it instead reads via syscall.ReadConsole
against the process's console handle, which blocks waiting for real input
instead of erroring - hanging the whole internal/exec test binary until the
CI job's 40-minute timeout killed it.
Every push was rerunning the full commit-time hook suite (go build, lint,
go mod tidy, etc.) a second time on an already-verified tree, adding
several minutes of redundant work to every push. Add default_stages:
[pre-commit] (plus default_install_hook_types) so hooks only fire at
commit time; three pre-commit-hooks.yaml hooks (trailing-whitespace,
end-of-file-fixer, check-added-large-files) hardcode their own stages
upstream and need an explicit override to respect this too.

CI's own lint/build jobs still re-verify everything server-side on push,
so this doesn't remove coverage for the rebase/amend/cherry-pick case
where the local tree changes without a fresh commit-time run - CI is the
backstop for that.
Same class of hang as TestExecuteAtmosCmd_TUIStartFailureIsReturned: Bubble
Tea fails fast when it can't open a controlling TTY on Unix, which this test
relied on to reach ExecuteWorkflowUI's error-return path without a real
interactive session. On Windows it instead reads via syscall.ReadConsole
against the process's console handle, which blocks waiting for real input
instead of erroring - hanging the whole internal/exec test binary until the
CI job's 40-minute timeout killed it.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 11, 2026
…om merging independent toast lines

The migration to ui.Success/Info/Warning (3faadd1) replaced hand-rolled
"\n%s ...\n\n" Writef calls with the new single-line toast API, silently
dropping the blank-line padding those calls used to emit around auth login,
docs generate, pro lock/unlock, and the version latest-check message.
Separately, tests/cli_test.go's snapshot-normalization pass was blindly
merging independent icon-prefixed toast lines (e.g. the telemetry notice and
the experimental-feature notice) onto one line since it had no way to tell a
wrapped paragraph continuation from two distinct ui.* calls; fix it at the
root by deriving the non-mergeable prefix set from pkg/ui/theme's icon
constants instead of patching one glyph at a time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@mergify

mergify Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Jul 12, 2026
# Conflicts:
#	internal/exec/workflow_adapters.go
@mergify mergify Bot removed the conflict This PR has conflicts label Jul 12, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 12, 2026
…save

The Build (windows) job's 30-minute timeout was tuned before this branch
merged in a much larger dependency tree (AI/MCP/LSP/k8s/OPA/Helm v4), so a
cold-cache Windows build now runs the job right up against that budget and
gets killed mid cache-save (observed: killed at 30m10s), which cascades into
downstream jobs (e.g. the k3s demo-helmfile gate) reporting a false failure
since their upstream build never finished. Bump to 45 minutes for real
headroom.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 12, 2026
…ble width test

TestCreateVersionTable_IndicatorColumnStaysNarrow asserted the byte offset of
"VERSION" in the rendered header line directly, but under CI=true the header
cell renders bold ("\x1b[1mVERSION"), and strings.Index counted those escape
bytes as part of the column position (expected 4, got 8) — same class of bug
already fixed elsewhere in this file's captureStderr helper (bfdccd0).
Strip ANSI from the table string before splitting into lines, consistent
with that precedent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@aknysh
Andriy Knysh (aknysh) merged commit 50947fa into main Jul 13, 2026
86 checks passed
@aknysh
Andriy Knysh (aknysh) deleted the osterman/pr-instructions branch July 13, 2026 12:04
@atmos-pro

atmos-pro Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor

Tip

Atmos Pro  

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

@mergify mergify Bot removed the needs-cloudposse Needs Cloud Posse assistance label Jul 13, 2026
@github-actions

Copy link
Copy Markdown

These changes were released in v1.223.0-rc.10.

Erik Osterman (Cloud Posse) (osterman) added a commit that referenced this pull request Aug 19, 2026
…ionale

All 7 actions/setup-go steps in .github/workflows/test.yml had cache: false,
two with a comment claiming this avoided "PR-controlled keys" poisoning the
cache across PRs or into main. That rationale doesn't hold: GitHub Actions
already isolates this. A pull_request run gets read/write access only to
its own branch's cache scope, read-only access to the default branch's
cache, and cannot restore caches from sibling PRs; only push/
workflow_dispatch/schedule/etc. can write to the default branch's cache
scope at all - pull_request and merge_group both get read-only access to
it. There's no cross-PR or PR->main poisoning path for this to guard
against.

The one real, historically-documented incident (PR #2713, 2026-07-13) was a
cold-cache Windows build blowing through its then-30-minute timeout during
the post-job cache-save step, not a poisoning attack - fixed at the time by
bumping the timeout to 45 minutes (still in place today). cache: false was
introduced separately and later (2026-08-02, commit 9343caf, a large
squashed refactor(store) PR whose own commit message never mentions
caching), with no documented rationale beyond the now-corrected comment.

Restores cache: true explicitly (not just the implicit default) on all 7
steps so there's a concrete anchor for the corrected explanatory comment,
kept once on the build job's step rather than duplicated 7x.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Michael Pursifull (arcaven) pushed a commit to arcaven/atmos that referenced this pull request Aug 19, 2026
…dup (cloudposse#2955)

* refactor(lint): replace bash lint orchestration with go-native Mage tooling

Ports the bash staleness-check/build orchestration for custom-gcl,
lintroller, and gomodcheck (in .atmos.d/lint.yaml and
scripts/run-custom-golangci-lint.sh) to Go targets in magefiles/,
invoked via `go tool mage` (Go 1.24+ tool directive). Fixes latent
POSIX-only staleness checks (find -newer) that silently never worked
on Windows, and replaces a hand-rolled cached-binary staleness check
for gomodcheck with a simpler `go run` (the pre-commit hook already
did this, unifying both call sites for the first time). The
never-build-custom-gcl-in-a-pre-commit-hook invariant (previously
fixed after a worktree corruption incident) is preserved exactly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(security): remediate CodeQL allocation-size-overflow alerts

Replace make(T, len(base)+len(overlay)) capacity hints with
max(len(base), len(overlay)) in mergeEnvSlices to avoid the summed-len
overflow pattern CodeQL flags (go/allocation-size-overflow, alerts
#5326-#5329). max() of two independently-safe lengths carries no
overflow risk, unlike their sum.

Also fixes pre-existing EditorConfig indentation (3-space list
continuations under numbered items, want multiples of 2) in
tools/lintroller/README.md that was blocking this commit's
affected-file validation hook.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(mage): address CodeRabbit findings on the Mage lint migration

Fixes 4 review threads on PR cloudposse#2955: lintrollerIsStale ignored go.mod/go.sum
changes, CustomGCL built golangci-lint in the caller's cwd instead of the
repo root, Precommit only checked binary existence (not staleness), and
mageRepoRoot's HasPrefix match could stop at tools/lintroller's own go.mod
instead of walking to the real root. Adds unit test coverage for
magefiles/ (previously invisible to `go test ./...` under the mage build
tag) and a standalone CI job + Codecov wiring so it's no longer untested.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(deps): bump moby/go-archive to v0.3.0 for path-traversal fix

Dependabot alert cloudposse#277 (GHSA-hfg8-hc9c-6c3h, high): a crafted tar
archive could write outside the extraction directory in
github.com/moby/go-archive < v0.3.0. v0.2.0 -> v0.3.0 is a semver-minor
bump, not blocked by .github/dependabot.yml's major-version-only
ignore rule. Transitively pulls moby/sys/sequential v0.7.0 and
moby/sys/user v0.4.1 via `go mod tidy`.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* perf(lint): switch import formatter from goimports to gci

goimports takes ~95-108s for a full-repo custom-gcl fmt pass; gci with
explicit import-section ordering (standard/default/cloudposse-prefix)
does the same pass in ~5-7s, a ~15-20x speedup, benchmarked directly
against this repo. gci is a stock golangci-lint v2 formatter, so no
.custom-gcl.yml plugin change is needed.

Updates the two doc references (CLAUDE.md, lint-fix/test-coverage-fix
agents) that named goimports as the enforced formatter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(docs): correct pre-existing EditorConfig indentation in agent guardrails

.claude/agents/lint-fix.md and .claude/agents/test-coverage-fix.md used a
3-space continuation indent under numbered-list items, violating this
repo's .editorconfig (markdown indent_size: 2, left-padding must be a
multiple of 2). Pre-existing on origin/main, but only surfaced once these
files were touched by the goimports->gci commit, since `atmos validate
--affected` validates whole files once they enter the affected set rather
than just changed lines. CI's "Run pre-commit hooks" job on PR cloudposse#2955 caught
this (Validate EditorConfig failed with the same 11 findings reproduced
locally). Also adds the fix-log record for the goimports->gci swap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* test(magefiles): close patch coverage gaps flagged by Codecov on PR cloudposse#2955

Codecov reported this PR's patch coverage at 80.80% (48 lines missing)
across magefiles/mage_lint_changed.go (0%), mage_lint_lintroller.go
(65.85%), mage_lint_customgcl.go (78.57%), mage_lint_golangci_run.go
(86.45%), magefile.go (85.71%), mage_lint_precommit.go (84.61%), and
mage_lint_gomodcheck.go (90.00%) — below CLAUDE.md's mandatory >85%.

Adds tests exercising real failure-propagation and build-orchestration
paths (repo-root resolution errors, staleness-check errors via ENOTDIR,
an end-to-end go-build-and-run against a trivial stand-in program, go
list parse failures, gomodcheck's success path) rather than padding
coverage. Remaining gaps are left uncovered with stated reasons:
Windows-only branches (unreachable on this CI runner), and a few
genuinely impractical-to-reproduce OS-level races/failures (fd close
errors, TOCTOU on directory walks).

Local coverage on the touched functions is now at or near 100% for
every function Codecov flagged; magefiles/acceptance.go is untouched
(not part of this branch's diff vs origin/main, correctly excluded
from Codecov's patch view).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(ci): restore Go build cache in test.yml, correct the security rationale

All 7 actions/setup-go steps in .github/workflows/test.yml had cache: false,
two with a comment claiming this avoided "PR-controlled keys" poisoning the
cache across PRs or into main. That rationale doesn't hold: GitHub Actions
already isolates this. A pull_request run gets read/write access only to
its own branch's cache scope, read-only access to the default branch's
cache, and cannot restore caches from sibling PRs; only push/
workflow_dispatch/schedule/etc. can write to the default branch's cache
scope at all - pull_request and merge_group both get read-only access to
it. There's no cross-PR or PR->main poisoning path for this to guard
against.

The one real, historically-documented incident (PR cloudposse#2713, 2026-07-13) was a
cold-cache Windows build blowing through its then-30-minute timeout during
the post-job cache-save step, not a poisoning attack - fixed at the time by
bumping the timeout to 45 minutes (still in place today). cache: false was
introduced separately and later (2026-08-02, commit 9343caf, a large
squashed refactor(store) PR whose own commit message never mentions
caching), with no documented rationale beyond the now-corrected comment.

Restores cache: true explicitly (not just the implicit default) on all 7
steps so there's a concrete anchor for the corrected explanatory comment,
kept once on the build job's step rather than duplicated 7x.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants