github cloudposse/atmos v1.221.0-rc.2

pre-release8 hours ago
Add ECR Public authentication: `aws/ecr-public` integration and `atmos aws ecr login --public` @osterman (#2231) ## what

Add ECR Public authentication to Atmos for authenticated access to public.ecr.aws, solving Docker rate limiting on public ECR images. Two entry points:

  • atmos aws ecr login --public — direct, zero-config login using ambient AWS credentials (the AWS SDK default chain: env, shared config/profile, SSO, IMDS/IRSA/ECS), or --public --identity <name> to use a specific identity. Ideal for CI.
  • aws/ecr-public integration kind — for automatic login on atmos auth login and identity linking.

Key changes:

  • Command (cmd/aws/ecr/login.go): new --public flag on atmos aws ecr login; ambient-credential and identity-based ECR Public login paths; mutually exclusive with a positional integration argument and --registry.
  • Cloud layer (pkg/auth/cloud/aws/ecr_public.go): GetPublicAuthorizationToken() calls ecrpublic:GetAuthorizationToken, always in us-east-1.
  • Integration layer (pkg/auth/integrations/aws/ecr_public.go): ECRPublicIntegration factory registering the aws/ecr-public kind, with region validation at config time. Implements the full Integration interface including Cleanup() (docker logout) and Environment() (DOCKER_CONFIG).
  • Region validation: rejects unsupported regions (only us-east-1 and us-west-2 have service endpoints; auth is us-east-1 only).
  • Tests: cloud-layer and integration-layer unit tests (token retrieval, region validation, cleanup, error handling) with a generated mock ECR Public client; command tests for the --public flag and mode validation.
  • Documentation: atmos aws ecr login command reference (added --public flag), ECR authentication tutorial, and a PRD (docs/prd/ecr-public-authentication.md).
  • Blog post + roadmap: announcement and a shipped milestone linking to the changelog.

Note: this branch has been merged up to main. Following #2144 (atmos auth ecr-loginatmos aws ecr login), ECR login lives under the aws namespace, and the integration was adapted to main's evolved Integration interface (exported BuildAWSConfigFromCreds, new Cleanup/Environment methods).

why

Docker pulls from public.ecr.aws hit rate limits when unauthenticated. This blocks CI workflows, especially those using cloudposse/github-action-docker-build-push which pulls BuildKit/binfmt images on every run. Authenticated pulls have significantly higher (or no) rate limits.

Because public.ecr.aws is global, any valid AWS credentials unlock authenticated pulls — so --public with ambient credentials "just works" in CI with zero configuration. ECR Public otherwise differs from private ECR: it uses the ecrpublic SDK service, a bearer token instead of SigV4, a hardcoded us-east-1 auth region, and a fixed public.ecr.aws registry URL. It requires ecr-public:GetAuthorizationToken and sts:GetServiceBearerToken IAM permissions.

references

  • ECR Public Authentication Tutorial — configuration examples, multi-environment setup.
  • atmos aws ecr login Command Reference — command usage, --public flag, integration configuration.
  • ECR Public Blog Post — announcement and use cases.
  • PRD: docs/prd/ecr-public-authentication.md.
  • AWS Docs: ECR Public APIs.

Summary by CodeRabbit

  • New Features

    • ECR Public authentication (aws/ecr-public) with atmos aws ecr login --public, identity-driven auto-provisioning, and enforced us-east-1 auth.
  • Documentation

    • Tutorials, blog post, and roadmap updated with ECR Public examples, permissions, CI guidance, and troubleshooting.
  • Bug Fixes

    • Improved identity selection UX (confirmation message) and safer CLI behavior for non‑TTY identity selection.
  • Tests

    • Extensive unit and integration tests covering ECR Public flows and CLI routing.
  • Chores

    • NOTICE/dependencies updated and minor .gitignore tweak.
feat(auth): Atmos Pro STS — JIT GitHub token broker for CI @osterman (#2546) ## what
  • Add a new auth provider kind: atmos/pro that authenticates the Atmos CLI to Atmos Pro by federating the GitHub Actions runner's OIDC token into an Atmos Pro session JWT (v1 is OIDC-only).
  • Add a new auth integration kind: github/sts — a just-in-time GitHub token broker for CI. On login it mints short-lived, scoped GitHub App installation tokens via POST /api/v1/sts, materializes them as per-owner GIT_CONFIG_* URL rewrites (env or file mode), and revokes them at command-end (via atmos auth exec in CI) and on atmos auth logout.
  • Add a passthrough kind: atmos/pro identity, a keyring-registered ProCredentials type, realm scoping for integration state, and via.provider binding for integrations (in addition to via.identity).
  • Add ATMOS_PRO_GITHUB_TOKEN, preferred by Atmos-native git operations (vendoring, source: provisioning, go-getter) ahead of ATMOS_GITHUB_TOKEN/GITHUB_TOKEN.
  • Add the PRD (docs/prd/atmos-pro-sts.md), a changelog blog post, a shipped roadmap milestone, and configuration docs; full unit-test coverage for the provider, identity, integration, keyring round-trip, via.provider matching, revoke gating, and token precedence.

why

  • Fetching private Terraform modules, Atmos source: components, and vendored artifacts in CI today requires a long-lived, over-privileged GitHub credential (PAT, machine user, or deploy key) sitting in a CI secret — a standing breach risk that can't be scoped per-run.
  • Atmos Pro STS replaces that with least-privilege, deny-by-default, short-lived tokens minted at the start of a run and revoked at the end — with zero .tf changes (the injected GIT_CONFIG_* rewrites are honored by both go-getter and Terraform's native git), and multi-org support because tokens are minted per (installation, permission-set).
  • Built into Atmos CLI core (CI-native, OIDC-aware) rather than as a GitHub Action, modeled on the existing aws/ecr/aws/eks integrations; the workflow only needs permissions: id-token: write.

references

  • PRD: docs/prd/atmos-pro-sts.md (includes deferred Future Work: moving Pro connection config under auth, unifying pkg/pro onto auth-issued sessions, and broadening command-end revoke beyond atmos auth exec)
  • Changelog: website/blog/2026-05-29-atmos-pro-github-sts.mdx

Summary by CodeRabbit

  • New Features

    • Atmos Pro GitHub token broker: new atmos/pro provider + github/sts integration for just-in-time GitHub tokens (env or git-config modes) with realm-scoped state and optional token export.
    • ATMOS_PRO_GITHUB_TOKEN added as preferred GitHub token source.
    • CI-gated automatic token revocation on command exit/logout.
    • Ambient credential broker registry to auto-provision env vars for remote reads.
  • Documentation

    • PRD, docs, and blog post for Atmos Pro STS and usage guidance.
docs: re-date custom commands step types blog post to 2026-05-30 @osterman (#2550) ## what
  • Re-dated the "25+ Interactive Step Types" blog post from 2026-01-03 to 2026-05-30.
  • Renamed the file prefix (git mv, history preserved) and added a matching date: 2026-05-30 frontmatter field.

why

  • Aligns the post's publish date with its actual release timing so it surfaces correctly in the changelog feed.
  • Adds the explicit date: field to match the repo convention (e.g. 2026-05-28-git-yaml-functions.mdx).
  • The slug is unchanged, so the published URL stays the same.

references

  • N/A — docs-only date adjustment, no user-facing code change.

Summary by CodeRabbit

  • Documentation
    • Published comprehensive guide to custom commands and workflow step types, featuring 25+ interactive step types with usage examples, including input collection, output formatting, and variable passing conventions for enhanced automation capabilities.

Review Change Stack

fix(website): use consistent brand-blue announcement bar @osterman (#2551) ## what
  • Removed the per-announcement backgroundColor/textColor overrides from website/src/data/announcements.js so every announcement bar entry inherits the brand-blue (#3578e5) / white-text defaults from the --announcement-bar-* CSS variables.
  • Documented the convention in the file header so future announcements don't reintroduce per-entry colors.

why

  • The announcement bar cycled through a rainbow of saturated Tailwind-600 colors (emerald green, violet, cyan, amber, red, indigo, teal...) that looked like "crayola" against the site's dark, near-black theme.
  • A single restrained, on-brand color reads as sophisticated and consistent with the rest of the dark site, and matches the bar's original styling.

references

  • N/A (website cosmetic change)

Summary by CodeRabbit

  • Refactor
    • Standardized announcement bar styling configuration to use shared CSS variables instead of per-announcement color settings, improving consistency across announcements.

Review Change Stack

feat: Implement workflow step types with registry pattern (DEV-263, DEV-2969) @osterman (#1899) ## what
  • Add 20+ step types across 4 categories (Interactive, Output, UI, Command) with extensible registry pattern
  • Support Go template variable passing between steps (e.g., {{ .steps.step1.value }})
  • Implement per-step output modes: viewport (pager), raw (passthrough), log (grouped), none (silent)
  • Interactive handlers with TTY detection and clear error messages in CI environments

why

Addresses DEV-263 (add input type to workflows) and DEV-2969 (add viewport support). Enables users to build complex multi-step workflows with user interaction, conditional execution, and flexible result display.

references

Summary by CodeRabbit

Release Notes

  • New Features

    • Added 25+ interactive step types for workflows and custom commands (input, confirm, choose, filter, file, write, markdown, spin, table, style, and more).
    • Support for configurable output modes (viewport, raw, log, none) and step-level display options.
    • Workflow progress rendering and status indicators.
  • Documentation

    • Comprehensive guides for interactive workflows and custom commands with step type reference.
    • New examples demonstrating interactive deployments, credentials collection, and multi-step flows.
  • Bug Fixes

    • Improved error messaging for workflow step validation and execution failures.

Review Change Stack

Add process and I/O execution foundation @shirkevich (#2464) ## Summary

This is PR 1 for the DAG concurrent execution rollout. It introduces the reusable process and stream-isolation foundation without enabling scheduler behavior or changing Terraform bulk routing.

Changes:

  • Add pkg/process with Runner, TaskSpec, Streams, Result, default os/exec runner, context-aware execution, cancellation reporting, and exit-code preservation.
  • Extend pkg/io with prefixed per-node stream composition for terminal, file, and capture sinks.
  • Refactor internal/exec.ExecuteShellCommand() into a backward-compatible wrapper over pkg/process while preserving CI stdout/stderr capture options.
  • Replace the runTerraformShow() global os.Stdout swap with injected stdout capture.

Scope

No scheduler, CLI routing consolidation, concurrency flags, or Terraform adapter behavior is enabled in this PR.

Stacking

This PR is the bottom of the DAG rollout stack and targets main.

Supersedes the earlier fork-headed draft #2459 now that the stack branches exist in cloudposse/atmos.

Validation

rtk env GOCACHE=/private/tmp/atmos-gocache GOMODCACHE=/private/tmp/atmos-gomodcache go test ./pkg/process ./pkg/io ./internal/exec ./cmd/terraform

Next PR

PR 2 branches from codex/dag-process-io-foundation and adds the generic pkg/scheduler core with ready-queue scheduling, bounded workers, deterministic aggregate results, and isolated unit tests only.

Summary by CodeRabbit

Release Notes

  • New Features

    • Configurable subprocess execution with optional contexts and injectable streams
    • Composable, scope-scoped output writers with per-line prefixing and masking
  • Bug Fixes

    • More accurate subprocess exit/error reporting and improved stream-redirection behavior
  • Tests

    • Expanded unit tests for subprocess execution, stream injection/capture, and output utilities
  • Documentation

    • Updated concurrent execution docs to reflect stream-based output handling

Review Change Stack

🚀 Enhancements

fix(auth): honor keyring.type config and send DPoP proof on AWS webflow @osterman (#2545) ## what
  • Honor auth.keyring.type from atmos.yaml across all auth-manager entrypoints by threading authConfig into credentials.NewCredentialStoreWithConfig(...) (was silently dropped via the no-arg NewCredentialStore()), and inject the manager's config-aware store into AWS user identities via a new optional SetCredentialStore interface.
  • Add an RFC 9449 DPoP proof (EC P-256 / ES256, stdlib-only) to the AWS browser webflow token requests; generate the key per session, persist it in the refresh-token cache, and reuse it on refresh (a cache without a key falls back to the browser flow).
  • Add AuthManager.CredentialStoreType() for observability/testability, mark the no-arg NewCredentialStore() constructor Deprecated, and add unit tests for both fixes (keyring backend selection, DPoP proof structure/signature, key round-trip, header presence).

why

  • #2544: with auth.keyring.type: memory set, Atmos still selected the default system keyring and hung indefinitely on hosts where the keyring service is present but unusable (e.g. a locked gnome-keyring-daemon). The config value was read and then thrown away before backend selection — only ATMOS_KEYRING_TYPE worked. Now the configured backend is honored everywhere an auth manager is built.
  • #2542: AWS sign-in's /v1/token endpoint now rejects requests without a DPoP proof (HTTP 400 INVALID_REQUEST), so browser-based authentication for aws/user identities failed at the code-exchange step. Sending the proof restores the flow; because the public-client refresh token is bound to the DPoP key, the key is persisted and reused on refresh.

references

Summary by CodeRabbit

  • New Features

    • Added RFC 9449 DPoP support for AWS OAuth token exchanges to strengthen token binding.
    • Auth now respects configured keyring backend across authentication flows.
  • Bug Fixes

    • Fixed AWS token parsing to match real-world snake_case responses.
  • Improvements

    • Auth manager exposes credential store backend type for easier diagnostics.
fix(yaml-functions): honor init.pass_vars when resolving !terraform.output (#1412) @thejrose1984 (#2548) ## what

When components.terraform.init.pass_vars: true is set, forward the component's vars to the internal terraform init that runs while resolving !terraform.output, via TF_VAR_* environment variables.

  • ComponentConfig gains PassVars + Vars, populated in ExtractComponentConfig.
  • SetupEnvironment injects TF_VAR_* for each var when PassVars is true (strings verbatim, other types JSON-encoded).
  • Regression tests cover the enabled path (string/number/bool/list), the disabled default, and env-section precedence.

why

Closes #1412.

The main terraform path honors pass_vars by passing -var-file to init (terraform_execute_helpers.go), so modules with init-time variable dependencies (e.g. a module version/source bound to var.aks_version) can initialize. But the init that runs while resolving !terraform.output goes through pkg/terraform/output, which uses the terraform-exec library and never honored pass_vars:

  • runInit only set Upgrade(false) + optional Reconfigure(true).
  • ComponentConfig had no PassVars/vars plumbing.
  • terraform-exec's initConfig has no var-file field — it structurally cannot pass -var-file to init.

So atmos tofu init/plan -s <stack> failed with Unable to compute static value / module.aks.version depends on var.aks_version which is not available whenever an init-time var came from a component resolved via !terraform.output.

Why TF_VAR_* rather than a var-file

terraform-exec can't attach a var-file to init, and an auto-loaded *.auto.tfvars.json on disk would risk cross-stack contamination when components are resolved concurrently. TF_VAR_* is process/runner-scoped, reaches init transparently through the existing SetEnv call, and Terraform/OpenTofu accept these values for the matching variable types (JSON encodings of lists/maps are valid HCL2). Gated behind pass_vars (default false), so it's a no-op unless opted in; an explicit TF_VAR_* in the component env section still wins.

references

test plan

go test ./pkg/terraform/output/...

New tests:

  • TestDefaultEnvironmentSetup_PassVars — vars exported as TF_VAR_* with correct encoding.
  • TestDefaultEnvironmentSetup_PassVarsDisabled — no TF_VAR_* when pass_vars is off.
  • TestDefaultEnvironmentSetup_PassVarsEnvSectionWins — explicit env-section TF_VAR_* wins.

Validation note: verified at the unit level (init env now carries the component vars when pass_vars is set; previously the init invocation was unchanged whether pass_vars was on or off). I don't have terraform/tofu in this environment to re-run the reporter's full tofu init/plan end-to-end, so a maintainer check against a real init-time-dependent module would be worthwhile before release.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added an option to forward component variables as TF_VAR_* environment entries during Terraform/OpenTofu init; existing TF_VAR_* values are preserved and non-string values are JSON-encoded.
  • Tests

    • Added tests for enabled/disabled forwarding, JSON encoding of non-strings, precedence of explicit env values, and end-to-end propagation to the runner env.
  • Documentation

    • Docs updated to note init.pass_vars also applies to implicit init runs and how forwarded vars are presented as TF_VAR_*.
test(yaml-functions): regression test for mixed state/output circular dependency (#2005) @thejrose1984 (#2547) ## what
  • Add a regression test and fixture for a cross-component circular dependency that mixes !terraform.state and !terraform.output (component-a → !terraform.state component-b; component-b → !terraform.output component-a).
  • New fixture: tests/fixtures/scenarios/yaml-functions-circular-deps-mixed.
  • New test: TestYAMLFunctionsCrossComponentCycleMixed.

why

This is the exact scenario from #2005. It was the same root cause as #2457 and was fixed by #2533 (making ProcessCustomYamlTags reuse the goroutine-local ResolutionContext so the Visited map survives nested walks). That fix covers both state↔state and the mixed state↔output path, but only the state↔state case had a regression test — so #2005 could silently regress while the existing test stayed green.

Verified the mixed cycle hangs (infinite recursion / goroutine stack overflow) on the commit before #2533, and returns a clean ErrCircularDependency on current main.

references

test plan

go test ./tests -run TestYAMLFunctionsCrossComponentCycle -v

Both TestYAMLFunctionsCrossComponentCycle (state↔state) and TestYAMLFunctionsCrossComponentCycleMixed (state↔output) pass. The mixed test asserts ErrCircularDependency is returned and that the MaxResolutionDepth safety net is not what fired (which would indicate the primary cycle detector regressed).

🤖 Generated with Claude Code

fix: defer custom-command/built-in collision warning to invocation time @thejrose1984 (#2549) ## what

Scope is intentionally narrow: change only when the existing collision warning fires — defer it from command-registration time to the moment the conflicting command is actually invoked.

  • No change to collision behavior: the built-in still wins and custom steps are still ignored.
  • No override:/invoke: work — that opt-in design is tracked separately in the custom-command-builtin-override PRD.
  • Implemented by wrapping the conflicting built-in command's PreRunE in processCustomCommands (preserving any existing PreRunE/PreRun and honoring Cobra's precedence of PreRunE over PreRun).
  • Adds a regression test asserting the warning is absent at registration and present (exactly once) on invocation.

why

Today the warning (introduced in #2191) is emitted from processCustomCommands, which runs during root init on every Atmos invocation. So a single colliding custom command makes every command — atmos list stacks, atmos terraform ..., etc. — print a warning about, say, a plan collision it never touched. The result is worse than noisy:

  • It's misleading — the warning points at a command the user didn't run.
  • It breaks scripting/CI that reads stderr, since every command (except version) emits it.

Deferring the warning to invocation makes it accurate and actionable: it appears exactly once, only when you run the command the warning is actually about, and stderr stays clean for every other command. Same information, delivered at the moment it's relevant instead of on every unrelated call.

Behavior

Invocation Before After
atmos list stacks (with a colliding custom plan) ⚠ warning printed no warning
atmos <colliding command> ⚠ warning printed (and also for every other command) ⚠ warning printed once, here only

references

  • Refs #2102
  • Related: #2191 (introduced the collision guard / warning)

test

go test ./cmd/ -run 'TestCustomCommand_.*Collision|TestCustomCommand_StepsConflictWarning|TestCustomCommand_NamespaceMerge|TestCustomCommand_DeepNesting'

Verified the new test fails against the previous (emit-at-registration) behavior and passes with the fix.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Collision warnings for custom commands that overlap built-in leaf commands are now deferred until the conflicting command is invoked, reducing startup noise and preserving existing pre-run error behavior.
  • Tests

    • Added regression tests to verify deferred warnings are emitted exactly once on invocation and that existing pre-run behavior and error propagation remain intact; tests skip on Windows where stderr capture is unreliable.
fix(flags): register --settings-list-merge-strategy as a global flag (#2398) @thejrose1984 (#2540) ## what
  • Register --settings-list-merge-strategy as a global persistent flag on RootCmd, with env binding to ATMOS_SETTINGS_LIST_MERGE_STRATEGY.
  • Add a Cobra-direct fallback in ProcessCommandLineArgs so the value reaches ConfigAndStacksInfo even when Cobra strips the flag from RunE's args.
  • In setSettingsConfig, scan os.Args (mirroring setLogConfig's parseFlags() pattern) so command paths that call InitCliConfig directly with a zero-value ConfigAndStacksInfo (e.g. describe config) still honor the flag.
  • Unit test the registration, inheritance, defaults, CLI value, and env-var path.

why

The flag is advertised in two places:

And Atmos's internal arg/flag layer already expects it:

  • pkg/config/const.go:147SettingsListMergeStrategyFlag = \"--settings-list-merge-strategy\"
  • internal/exec/cli_utils.go:72 — listed in commonFlags
  • internal/exec/cli_utils.go:495 — string-flag handler that writes info.SettingsListMergeStrategy
  • pkg/config/utils.go:726 — applies it onto atmosConfig.Settings.ListMergeStrategy

But it was never registered with Cobra at the global level. Subcommands that don't whitelist unknown flags (e.g. terraform plan, which has no FParseErrWhitelist) rejected the flag before the legacy commonFlags post-processing ever ran:

$ atmos --settings-list-merge-strategy=append terraform plan vpc -s test
Error: unknown flag --settings-list-merge-strategy for command atmos terraform plan

references

test plan

Unit tests added in pkg/flags/global_registry_test.go:

  • flag is registered on RootCmd as persistent
  • defaults to empty string
  • CLI flag value flows through Viper
  • ATMOS_SETTINGS_LIST_MERGE_STRATEGY env var flows through Viper
  • subcommand inherits the persistent flag

End-to-end verification on a minimal project (atmos.yaml has settings.list_merge_strategy: replace):

Invocation list_merge_strategy
atmos describe config replace (baseline from atmos.yaml)
atmos --settings-list-merge-strategy=append describe config append
atmos describe config --settings-list-merge-strategy=merge merge
ATMOS_SETTINGS_LIST_MERGE_STRATEGY=append atmos describe config append

atmos --help now lists --settings-list-merge-strategy.

Full test suites pass for the touched packages:

ok  github.com/cloudposse/atmos/pkg/flags
ok  github.com/cloudposse/atmos/pkg/flags/global
ok  github.com/cloudposse/atmos/pkg/config
ok  github.com/cloudposse/atmos/internal/exec

Summary by CodeRabbit

  • New Features
    • Added --settings-list-merge-strategy CLI flag (replace, append, merge) and ATMOS_SETTINGS_LIST_MERGE_STRATEGY env var to override list-merge behavior for an invocation
  • Documentation
    • Documented the new flag and environment variable with usage and defaults
  • Tests
    • Updated CLI help snapshots to include the new flag and refreshed help text formatting across commands

Review Change Stack

Don't miss a new atmos release

NewReleases is sending notifications on new releases.