github cloudposse/atmos v1.223.0-rc.7

pre-release2 hours ago
Refresh Atmos agent skills for Native CI @osterman (#2493) ## what
  • Refresh the Atmos agent skills to use current stack naming, dependency, provisioning, auth, and toolchain guidance.
  • Replace the old atmos-gitops skill with atmos-ci, centered on Native CI, containerized GitHub Actions, OIDC profiles, checks, comments, summaries, affected/all matrices, and direct Atmos commands.
  • Add an atmos-ai skill focused on AI providers, MCP configuration/export, Atmos auth in agent workflows, and toolchain-aware MCP usage.
  • Remove Spacelift promotion from the skill bundle and keep deprecated wrapper actions, name_pattern, and settings.depends_on only as migration warnings.

why

  • Agents were recommending stale Atmos syntax and legacy CI patterns.
  • Native CI, dependencies.components, name_template, source provisioning with workdirs, backend provisioning, and Atmos-managed tool dependencies are the preferred guidance.
  • Terraform/OpenTofu setup actions and legacy Cloud Posse wrapper actions should be discouraged in favor of the Atmos container and toolchain-managed dependencies.tools.

references

Summary by CodeRabbit

  • Documentation
    • Expanded and reorganized Atmos skill/reference guidance, adding first-class AI/MCP, Native CI, profiles, toolchain, containers/emulators, secrets, GitOps, AWS, and core configuration navigation.
    • Added new/updated pages for atmos-ai, Terraform/OpenTofu orchestration, atmos mcp export, atmos ai ask, atmos-profiles, migration (including Remote-State Bridge), and improved guidance for generate/overrides and validation.
  • Bug Fixes
    • Improved terminal color behavior to honor environment-based controls.
    • Enhanced tool download retry/error reporting for clearer diagnostics.
  • Tests
    • Updated fixtures and strengthened marketplace/catalog and download retry assertions.
  • Chores
    • Refreshed plugin/marketplace metadata and licensing notice; reorganized documentation via links.
docs: provider-generation default_tags + missing YAML function pages @osterman (#2704) ## what
  • Add a "Setting Default Tags" section to the Provider Generation page (components/terraform/providers.mdx), showing how to set the AWS provider's default_tags via the providers section, populated with !git.repository, !git.sha, and !git.branch.
  • Add 5 missing YAML function doc pages so they appear in the docs sidebar: !git.sha, !git.branch, !git.ref, !git.root, and !emulator.
  • Cross-link the new !git.* pages from their existing siblings (git.name, git.host, git.owner, git.repository, git.url, repo-root) and from the YAML functions index page.
  • Fix a pre-existing template bug in stacks/providers.mdx's dynamic provider example: {{ .stage }} is not a valid template variable and should be {{ .vars.stage }}.

why

  • The Provider Generation page had no example showing how to set default_tags, a common requirement for consistent resource tagging (repository, commit, branch, etc.) across an account.
  • !git.sha, !git.branch, !git.ref, !git.root, and !emulator are all implemented, working YAML functions, but had no doc page and were therefore invisible in the sidebar.
  • The {{ .stage }} bug produced a non-functional example — Atmos's template context only exposes stage/tenant/environment/namespace nested under .vars, never as bare top-level keys.

references

Summary by CodeRabbit

  • Documentation
    • Added new docs for YAML functions covering Git metadata (!git.sha, !git.ref, !git.branch, !git.root), repository paths, and emulator connection details (!emulator).
    • Expanded the YAML function index and “Related Functions” sections to improve discoverability of Git helpers.
    • Added guidance for setting AWS provider default_tags with dynamic values and a CI-friendly fallback for detached HEAD.
    • Updated the dynamic provider configuration example to use the correct current-stack variable format.
perf(lint): isolate golangci-lint cache and lock per worktree @osterman (#2701) ## what
  • Point TMPDIR and GOLANGCI_LINT_CACHE at repo-local dirs in scripts/run-custom-golangci-lint.sh so each worktree gets its own golangci-lint lock and cache (GOCACHE stays shared for warm typecheck data); opt out with ATMOS_LINT_SHARED_CACHE=1.
  • Skip rebuilding the custom-gcl binary in atmos lint custom-gcl when it is already up to date (staleness guard mirroring lint lintroller/lint gomodcheck).
  • Drop the redundant standalone lint lintroller pass from atmos lint changed (it already runs as a plugin inside custom-gcl).

why

  • golangci-lint's single-instance lock is a fixed machine-global path (os.TempDir()/golangci-lint.lock), not inside GOLANGCI_LINT_CACHE, so parallel worktree lints (e.g. rebase storms after a merge) serialized on one lock and a run orphaned by a tool timeout froze every other worktree; relocating the lock via a per-worktree TMPDIR lets them run in parallel and contains an orphan to its own worktree.
  • Rebuilding custom-gcl (clone + compile) on every lint changed was the single biggest per-run cost during a rebase storm when the binary is identical across worktrees.
  • Verified empirically: an isolated-TMPDIR lint ran at ~94% CPU in parallel with another holding the global lock, with its lock file under .golangci-tmp/.

references

  • Contributor tooling only (dev lint flow + pre-commit hook); no user-visible change to the Atmos binary — labeled no-release.

Summary by CodeRabbit

  • Bug Fixes
    • Improved linting behavior in parallel worktrees by isolating golangci-lint cache and lock files per worktree, reducing contention and unexpected failures.
    • Updated the “changed” lint flow to skip an unnecessary full-repo lint pass, making runs leaner and faster.
    • Made the custom Go-based lint helper rebuild only when the binary is missing or stale, avoiding redundant rebuilds and speeding up repeated lint runs.
[codex] Add native asciicast recording and demo embeds @osterman (#2672) ## what
  • Adds Atmos-native asciicast recording, playback, rendering, and cast/workdir step support.
  • Adds reproducible cast demo commands, deterministic fixtures, committed website casts, and an asciicast authoring skill.
  • Adds website cast playback plus README front matter/example embed support for showing casts on command and example pages.

why

  • Makes command demos reproducible, source-controlled, reviewable as plain text, and reusable across docs.
  • Lets examples opt into casts without duplicating command-page videos.
  • Provides validated demo coverage for Terraform, vendor, describe/list, and AWS emulator workflows.

references

  • None.

Summary by CodeRabbit

  • New Features
    • Added terminal recording via global --cast (supports generated .cast output and rendering to .gif/.mp4 and more formats).
    • Introduced atmos cast play and atmos cast render.
    • Added interactive cast simulation/session driving, plus script and workdir step capabilities.
    • Added website cast playback through the new CastPlayer component and an embedded cast demo gallery.
  • Bug Fixes
    • Improved forced-color behavior and cast/help capturing consistency, without impacting normal CLI argument handling.
  • Documentation
    • Updated CLI docs, examples, and skills/guides to cover cast workflows and new step patterns.

🚀 Enhancements

fix(workflows): resolve step vars in inline shell/atmos/exec steps @sgtoj (#2711) ## What

Workflow step types handled inline (shell, atmos, exec) now resolve step-variable templates — {{ .steps.*.value }}, {{ .env.* }}, {{ .flags.* }}, plus Sprig/Gomplate functions — in both the step command and the step env: values, matching how custom command steps already behave.

workflows:
  deploy:
    steps:
      - name: component
        type: format
        content: "vpc"
      - type: atmos
        command: terraform apply {{ .steps.component.value }} -auto-approve
        env:
          COMPONENT: "{{ .steps.component.value }}"

Before this change, terraform apply {{ .steps.component.value }} -auto-approve was passed through verbatim (literal {{ .steps.component.value }}); now it resolves to terraform apply vpc -auto-approve.

Why

This is a bug, not a new feature. The documented contract (PRD goal “capture step outputs for use in subsequent steps via Go templates”, and its own examples using type: atmos / type: shell command steps) is that any step can consume prior steps' outputs. Handler-routed step types (toast, markdown, container, the interactive prompts, …) and custom command steps already resolved these templates; workflow shell/atmos/exec steps were the outlier — they executed the raw command and merged env: values without running either through the step-variable engine, so the templates were emitted literally. It went unnoticed because the shipped examples only surface step values through handler-routed display steps, never a raw shell/atmos command.

How

  • ExecuteWorkflow configures the workflow step executor with the same template engine as the custom command executor (cmd/cmd_utils.go): the full Atmos renderer (Sprig/Gomplate), multi-pass rendering, and flag protection — so templating behaves identically in workflows and custom commands.
  • Inline step commands and env: values are resolved through that engine before execution.
  • New Variables.ResolveWith applies a per-call environment overlay without mutating the shared executor env, so a step's environment is visible as {{ .env.* }} without leaking across steps.
  • prepareStepEnvironment stays a pure merger (its existing tests are unchanged); env values are resolved ahead of it.

Commands and env: values without template markers are returned unchanged.

Testing

  • Unit tests: Variables.ResolveWith (overlay + non-mutation), command resolution (.steps + env overlay, non-leak, Sprig parity, invalid-template error), and env: resolution.
  • End-to-end (built binary): a workflow feeding a captured value into a shell step's command, env:, and a Sprig function all resolve correctly.
  • go build ./..., pkg/runner/step + internal/exec suites, and atmos lint changed are clean.

References

  • docs/fixes/2026-07-07-workflow-step-variable-templating.md
  • Reference implementation mirrored: cmd/cmd_utils.go (custom command step executor)

Summary by CodeRabbit

  • New Features

    • Workflow steps can reference earlier step outputs in inline shell, atmos, and exec commands and in env: values.
    • Expanded workflow documentation with “Referencing values from other steps” examples.
  • Bug Fixes

    • Fixed unresolved template expressions in certain inline workflow steps.
    • env: template resolution now uses a per-step overlay so values resolve correctly without impacting other steps.
fix: correct out-of-date atmos-manifest workflow schema (#2708) @sgtoj (#2710) ## what
  • Bring the published atmos-manifest JSON Schema (served at atmos.tools and mirrored to SchemaStore) back in sync with the workflow features shipped in 1.222.0, so editors using # yaml-language-server: $schema=… stop drawing false-positive errors on valid workflows.
  • workflow_manifest (the object under each named workflow): add the 7 missing workflow-definition fields — dependencies, working_directory, env, container, output, viewport, show (reusing the existing dependencies definition via $ref).
  • workflow_step: add the 75 missing step fields with descriptions, spanning every step-type family (options/default/interactive/tty/script, plus http, cast, container, style, log, say, env, exit, emulator, junit, require, workdir, table, control/parallel). Set additionalProperties: true and make level a plain string (see why).
  • Add three shared sub-definitions: workflow_viewport, workflow_show, workflow_container (the latter also accepts false to run on the host).
  • Add a reflection-based ratchet test (schema_workflow_coverage_test.go) that fails the build if a WorkflowStep/WorkflowDefinition field is ever authored without a matching schema property — the same "you can't forget the schema" pattern already used for top-level/component sections.
  • Add regression tests (schema_workflow_validation_test.go) reproducing the issue's exact snippets, covering one field from every step-type family, all workflow-level fields, and confirming typed fields (e.g. options, code) are still validated.

why

  • The issue named three rejected fields (dependencies, options, default), but the schema had drifted far more broadly: it modeled only 21 of ~96 authored step fields and 3 of 10 workflow-definition fields, both with additionalProperties: false. Any workflow using a newer field produced misleading "Property X is not allowed" red squiggles on config that Atmos parses and runs correctly.
  • I validated the updated schema against all 60 real workflow files in the repo. That surfaced two ways the old strict schema over-tightened against shipped examples: an ignored/unknown key, and level: values outside a log-level set. Workflow steps are a lenient, polymorphic union of ~30 step types and Atmos ignores unknown keys at runtime, so additionalProperties: true (plus fully enumerated known fields for autocomplete + type checks) matches real behavior and eliminates the whole false-positive class — present and future — mirroring how providers/templates are modeled. level is a plain string field, so it is no longer constrained by an enum.
  • The ratchet test makes this drift a build failure going forward, so the published schema can't silently fall behind the structs again.
  • Scope is intentionally the published (website/SchemaStore) schema; the embedded schemas do not model workflow steps and atmos validate stacks is unchanged.

references

  • Closes #2708
  • Follow-ups discovered while validating real workflows (out of scope here, worth separate issues):
    • examples/quick-start-advanced/stacks/workflows/{backend,validation}.yaml (and the mirrored doc) use command: true — an unquoted-YAML-boolean footgun where a string command belongs; the schema correctly flags it.
    • Dedicated schemas for custom-command files (commands:) and profile files (auth:) — the issue's "ideally" ask; purely additive (no false-positives today) and a larger separate effort.

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation for workflow manifests so commonly used workflow and step settings are now recognized correctly.
    • Fixed schema handling for interactive, command, file, container, output, and UI-related workflow options.
    • Reduced false validation/editor warnings by allowing supported workflow step fields and preserving type checks for invalid values.
  • Tests

    • Added coverage to guard against future workflow schema regressions.
fix(ci): exclude auth caches from ci.cache (defensive hardening) @osterman (#2705) ## what
  • ci.cache (the CI build cache) now excludes aws-sso, azure-device-code, aws-webflow, and auth — the subdirectories under ~/.cache/atmos where Atmos persists session credentials — unconditionally, with no opt-out, regardless of ci.cache.paths.
  • Applies in both Atmos's own cache backend (pkg/ci/cache/archive.go) and the atmos ci cache paths output used with the native actions/cache GitHub Action (rendered as !-prefixed glob exclusions, working around a known actions/toolkit glob-depth limitation).
  • Drift-guard tests in each owning auth package assert their subdir constants stay in sync with the exclusion list, so a rename can't silently reopen the gap.
  • Docs (website/docs/cli/configuration/ci/cache.mdx, docs/prd/native-ci/framework/ci-cache.md) and an internal fix note (docs/fixes/) are included.

why

  • ci.cache's default behavior (cache the entire XDG cache root when ci.cache.paths is unset) meant Atmos's own auth session material (AWS SSO tokens/refresh token/client secret, Azure device-code tokens, Atmos's webflow refresh token) sat in the same directory tree that gets archived by default.
  • This is purely defensive hardening — ci.cache was never demonstrated to be exploitable or vulnerable in CI. A repo's GitHub Actions cache is already scoped to that repo, and everything involved is short-lived, rotating session material. This change just makes it structurally impossible for these directories to end up in a cache archive, rather than relying on ci.cache.paths conventions.
  • OIDC-based auth (GitHub/GCP/Azure) was confirmed unaffected either way — those flows never write credentials to disk.

references

  • docs/prd/native-ci/framework/ci-cache.md#default-excluded-auth-paths

Summary by CodeRabbit

  • New Features
    • CI cache outputs now include default excluded paths alongside included paths.
    • GitHub, JSON, YAML, and env formats now show the exclusion list consistently.
  • Bug Fixes
    • Default auth-related cache directories are no longer archived by CI cache flows.
    • Cache exclusion handling is now applied consistently across archive creation and cache path generation.
  • Documentation
    • Updated CI cache docs to explain the default exclusions and their effect on cache behavior.
fix(website): repair broken /blog announcement link @osterman (#2702) ## What
  • Fix the broken announcement-bar link: /blog/native-ci-integration/changelog/native-ci-integration.
  • Add a createRedirects rule to plugin-client-redirects so any other stale /blog/<slug> URL (old bookmarks, indexed search results) forwards to its current /changelog/<slug> page, matching the existing bare /blog/changelog redirect.

Why

The blog plugin's routeBasePath was changed from /blog to changelog a while back (#1707), but the announcement bar (website/src/data/announcements.js) still hardcoded the old /blog/... path, so it 404'd live on atmos.tools.

Neither existing safety net catches this class of bug:

  • .github/workflows/link-check.yml (lychee) is scoped to **.md and explicitly excludes website/**.
  • Docusaurus's onBrokenLinks: 'throw' only analyzes links it discovers via rendered MDX/<Link> content — the announcement bar renders its content string through dangerouslySetInnerHTML, which is invisible to that check.

This PR fixes the one known broken instance and adds the redirect as a safety net for any other pre-#1707 /blog/* links floating around externally.

Test plan

  • cd website && npm run build succeeds.
  • Confirmed build/blog/native-ci-integration/index.html contains a meta-refresh to /changelog/native-ci-integration.
  • Confirmed 236 /blog/* redirect pages are generated (one per changelog post).
  • Live-verified https://atmos.tools/changelog/native-ci-integration returns 200 (the corrected target).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added automatic redirects for old changelog URLs to their matching blog pages, helping visitors reach updated content without broken links.
  • Bug Fixes

    • Updated an announcement link so it points to the correct changelog page.
fix: deep merge drops keys under unquoted-integer YAML map keys @osterman (#2700) ## what
  • Fixes normalizeMapReflect in pkg/merge/merge.go so a map[interface{}]interface{} (the shape yaml.v3 produces for a YAML mapping with an unquoted non-string key, e.g. 1:) is stringified into map[string]any instead of being preserved as an opaque typed map.
  • Adds pkg/merge/merge_yaml_integer_key_test.go, which reproduces the bug end-to-end via real yaml.v3 unmarshaling and unit-tests the normalization contract directly.
  • Documents the root cause and fix in docs/fixes/2026-07-07-deep-merge-yaml-integer-key.md.

why

  • Since the native deep-merge rewrite (#2201), a nested map whose parent key is an unquoted integer in YAML (e.g. eni.1:) was silently replaced instead of deep-merged whenever a stack overrides a subset of its keys, dropping catalog-only keys with no error.
  • Root cause: yaml.v3 only decodes a mapping into map[string]interface{} when every key resolves to !!str; an unquoted integer key forces map[interface{}]interface{} for that mapping node. normalizeMapReflect lumped this together with genuinely-typed non-string-key Go maps (e.g. map[int]schema.Provider) and preserved both, so deepMergeNative's map[string]any fast path saw a type mismatch and fell back to "src overrides dst" for the whole submap.
  • The previous partial regression fix (#2248) addressed list↔map type-mismatch guards but did not address this map-key normalization gap.

references

Summary by CodeRabbit

  • Bug Fixes
    • Fixed a deep-merge regression where YAML maps with unquoted integer keys could replace sub-maps instead of merging nested content.
    • Improved normalization of maps with mixed interface/non-string keys, including correct behavior when stringified keys collide.
    • Enhanced signature verification retry handling by classifying additional upstream cosign HTTP failures as retryable (with 404 non-retryable).
  • Tests
    • Expanded coverage for YAML integer-key normalization, interface-keyed normalization, and colliding stringified keys.
    • Updated CLI golden snapshots and affected-area test expectations to use quoted numeric YAML keys.
  • Documentation
    • Added incident write-ups for the YAML regression and the cosign HTTP retry issue.

Don't miss a new atmos release

NewReleases is sending notifications on new releases.