fix(ci): publish Docker images for prereleases Erik Osterman (Cloud Posse) (@osterman) (#2792)
what
- Publish the existing multi-architecture Atmos Docker image for both stable and prerelease GitHub releases.
- Keep Docker image publishing disabled for manual workflow dispatches.
why
- Native CI users consume Atmos through Docker images and need prerelease tags to test upcoming releases.
- Homebrew remains stable-release-only.
references
- N/A
Summary by CodeRabbit
- Chores
- Updated release automation so the Docker build job runs for release events.
🚀 Enhancements
fix(hooks): resolve component path from metadata.component target Erik Osterman (Cloud Posse) (@osterman) (#2802)
what
- Hooks (
infracost,trivy,checkov,kics,tflint,kind: command,kind: git,kind: step/kind: steps) now resolve$ATMOS_COMPONENT_PATH— and the hook subprocess's own working directory — from the component's resolvedmetadata.componenttarget or provisioned workdir, instead of the stack-facing component/alias name. - Path resolution for all hook kinds is consolidated behind one exported
hooks.ComponentPath(), extended to cover every provisionable component type (terraform/helmfile/packer/ansible/kubernetes/helm). kind: githooks with norepository:now use the resolved component directory (not the repo root) as their Git workdir, socommit.pathsare component-relative like other hook kinds.kind: step/kind: stepshooks defaultworking_directoryto the resolved component path when not explicitly set — excepttype: atmossteps, which re-invoke the atmos binary itself and must keep inheriting the ambient working directory so the nested run resolves the project'satmos.yaml/stacks, not the target component's own directory.- A component with a JIT
source:and hooks configured now has its source provisioned before those hooks fire (before.terraform.*is a "run before Terraform" event, not a "run before provisioning" event) — exceptbefore.terraform.init, which is the source provisioner's own lifecycle event and must keep running first. This only triggers for components that actually have hooks; every terraform subcommand already provisions its own component independently inRunE, so gating onhooks.HasHooks()avoids a second, racing provisioning attempt for components with no hooks at all. - When the resolved component directory doesn't exist on disk (component never provisioned, or an early failure before Terraform ever reaches it), the hook subprocess now falls back to the ambient process working directory instead of refusing to start — needed for
when: alwaysafter-hooks that must still fire and report the failure. - A failed JIT provisioning attempt no longer leaves its target directory behind (surfaced by review: a test promised this but didn't assert it, and asserting it failed).
vendorToTargetcreated the target directory before downloading, so a failed download left an empty component directory — enough for path resolution to treat the component as existing — and a partial copy failure would leave a non-empty one thatneedsProvisioningtreats as fully provisioned, silently skipping re-provisioning on the next run. The provisioner now removes the directory only when this attempt created it; a pre-existing directory is left untouched (covered by positive/negative unit tests inpkg/provisioner/source). - Multi-component invocations (
--all/--affected/--components/--query/--tags/--labels) no longer fail with "component is required": the metadata-resolution step is skipped for the global before/after hook (no single component is resolved yet at that point) and is best-effort everywhere else, so an intentionally invalid stack/component test scenario is rejected by Terraform's own validation with its normal message, not by hook-context preparation with a different one. - Added a fix-log record (
docs/fixes/2026-07-24-hook-component-path-metadata-component.md) and updated thecustom-hooks,git-ops, andhooks-step-typesPRDs to document all of the above. - Fixed a pre-existing Windows-only test bug (
TestComponentPathFor_Fallbacks) surfaced by this change: a hand-rolledfilepath.Separator-prefixed "absolute" path isn't actually absolute per Go'sfilepath.IsAbson Windows, sou.GetComponentPath'sAbs()call legitimately expanded it with the current drive letter, breaking the test's literal expectation. Rooted the fixture paths in a genuinet.TempDir()instead. - Fixed pre-existing 3-space (odd) markdown indentation in
docs/prd/git-ops.mdthat failededitorconfig-checker'sindent_size=2rule once this PR made the file "affected" by CI's affected-file validation. - Remediated 2 open Dependabot alerts flagged on this branch:
github.com/google/cel-gov0.26.0 → v0.29.0 (GHSA-gcjh-h69q-9w9g), and the website's transitivepostcsspin bumped from^8.5.10to^8.5.18(resolves to 8.5.23, GHSA-r28c-9q8g-f849).NOTICEandwebsite/pnpm-lock.yamlregenerated accordingly.
why
- For a component using the shared-module / "abstract component" pattern (
metadata.component: nat-gatewayon a component named e.g.nat-gateway-alias), hooks pointed at a directory that doesn't exist on disk (.../nat-gateway-aliasinstead of.../nat-gateway). Forkind: infracostthis failed silently — it just logged "Could not autodetect any projects" and reported$0.00, looking like a normal (if boring) result instead of a broken cost-estimation run.atmos describe componentalready resolvedmetadata.componentcorrectly; hooks just weren't sharing that resolution. - Making that resolution (and JIT provisioning) happen ahead of hook execution surfaced several ordering assumptions across the rest of the hook/lifecycle system that weren't true before — multi-component bulk runs,
type: atmossteps,before.terraform.init's own provisioner event, andwhen: alwaysfallback hooks on early failures — each of which needed its own narrow fix to keep working the way it did before this PR, without losing the original fix. - The security fixes close a high-severity path-traversal issue in
postcss(arbitrary.mapfile disclosure) and a medium-severity private-field-exposure issue incel-go, both flagged by Dependabot on this branch; folding them in here keeps this PR mergeable without a separate open vulnerability.
references
- Closes #2799
- Supersedes #2805 (closed) — a narrower fix for the same
metadata.componentpath resolution, fully subsumed by this PR - Related prior fixes in the JIT/
source.uricode path: #2364 / #2371, #2134 / #2137, #2309 (Bug 2), #2684 — this PR covers the plain/localmetadata.componentbranch they didn't reach
Summary by CodeRabbit
- Bug Fixes
- Terraform lifecycle hooks now resolve component metadata consistently (including alias-based selections) and carry the resolved component context into hook execution.
- Hook subprocesses, Git current-repository actions, and step hooks run from the resolved component directory;
ATMOS_COMPONENT_PATHnow matches that resolved location. - Components with configured
source:are provisioned (best-effort) before applicablebefore.terraform.*hooks; provisioning failures are non-blocking. - Step hooks default
working_directoryto the component directory while preserving explicit values and ambient behavior for Atmos steps.
- Documentation
- Updated hook-path, working-directory, and Terraform timing rules; clarified Git and env var behavior.
- Tests
- Expanded coverage for metadata resolution, JIT
source:provisioning, and working-directory defaults.
- Expanded coverage for metadata resolution, JIT
fix(install): self-elevate install.sh via sudo on Linux Erik Osterman (Cloud Posse) (@osterman) (#2806)
what
- Added a
maybe_sudohelper inwebsite/static/install.shand routed every root-requiring command in the apt/yum/apk (install_via_cloudsmith) path through it, so the script self-elevates viasudowhen not already root, and fails with a clear actionable message (pointing at the rootless binary install) if nosudois available. - Added a CI smoke-test step in
.github/workflows/install-sh-smoke.ymlthat exercises thepackageinstall method onubuntu-latest, to catch regressions of this class of bug going forward. - Fixed
website/docs/quick-start/install-atmos.mdx: a stray Unicode box-drawing character (│) had silently replaced the literal pipe (|) in the Debian/Ubuntu, RedHat/CentOS, and Alpine manual install snippets, breaking them if copy-pasted; also addedsudoto the Debian/Ubuntu tab's commands to match the RedHat tab's existing convention.
why
- A user reported that
curl -fsSL https://atmos.tools/install.sh | bash— the install command shown on the homepage — fails on a plain (non-root) Ubuntu 24.04 shell withPermission deniedwriting to/usr/share/keyrings/and/etc/apt/sources.list.d/, since the apt/yum/apk install path never elevated privileges. - This affects the primary documented install path for most Linux users, not an edge case; it went unnoticed because the CI smoke test only ever exercised the root-free binary-download method.
- The fix is scoped so it only affects the apt/yum/apk code path — Homebrew and Nix installs (e.g. on macOS) are untouched, since
maybe_sudois never invoked from those functions.
references
- Reported by a user running the homepage install command on Ubuntu 24.04.4 LTS.
Summary by CodeRabbit
- Bug Fixes
- Improved non-root installs by using
sudowhen available, with clearer guidance when neither root norsudoexists. - Made post-install verification more reliable by resolving the
atmosexecutable viacommand -v(and normalizing its path).
- Improved non-root installs by using
- Documentation
- Fixed Cloudsmith command piping syntax and refined install examples for DEB/RPM/APK (including
sudousage and version selection).
- Fixed Cloudsmith command piping syntax and refined install examples for DEB/RPM/APK (including
- Tests
- Updated the
install.sh smokeworkflow to run an additional package-mode install and verifyatmosis present inPATHonubuntu-latest.
- Updated the
fix: restore auth for evaluated list commands Erik Osterman (Cloud Posse) (@osterman) (#2801)
what
- Restore default identity scanning whenever list/describe stack processing evaluates Go templates or YAML functions; preserve
--identity=false. - Apply the policy to all list describe-stacks callers and verify
atmos.Component()forwards an inherited context to an auth-less nested target. - Keep graceful degradation limited to unprovisioned state/output; credential, IMDS, and template failures remain fatal.
why
- v1.222.0-rc.14 made list inventory authentication opt-in while templates still ran by default, leaving nested Terraform output resolution without an AuthContext and falling back to IMDS.
- The scoped per-component cache remains unchanged, so automatic auth does not restore the prior unscoped per-component authentication behavior.
references
Summary by CodeRabbit
- Bug Fixes
- Fixed authentication initialization for
describe stacksandlistso credentials are prepared only when template processing / YAML-function evaluation is enabled, or when identity is explicitly selected (while respecting the disabled identity sentinel). - Updated auth-skip guard to require both processing flags to be disabled, even when identity is set via environment.
- Restored correct parent
AuthContextinheritance for nested template/YAML evaluations. - Tightened warn/silent behavior so backend/credential/network failures are fatal (with recovery limited to unprovisioned Terraform state/output).
- Fixed authentication initialization for
- Tests
- Added/expanded coverage for auth policy, auth inheritance, and warn-mode error classification.
- Documentation
- Documented the nested auth inheritance and warn-mode behavior changes.
feat(auth): improve AWS user webflow and console access Erik Osterman (Cloud Posse) (@osterman) (#2786)
What
- Enable AWS federation console URLs for authenticated
aws/useridentities. - Add
atmos auth login --webflowto force a fresh browser OAuth2/PKCE sign-in for a directaws/useridentity without reading, deleting, or overwriting configured IAM access keys. - Preserve temporary AWS session credentials in the existing session-file cache, while enforcing
webflow_enabled: falseand clear validation errors for provider mode or non-aws/useridentities. - Improve AWS browser-auth UX: remove the misleading credential-configuration info message, display short authorization URLs in the dialog, and place long URLs below it.
- Emit experimental-command notices once per command execution.
- Stabilize acceptance-test setup and snapshots, including dependency retries/timeouts and Packer setup retries.
Why
IAM-user identities can obtain temporary STS credentials through Atmos browser authentication, but they could not open the AWS console and could not explicitly choose browser authentication when saved IAM credentials existed. This change makes both flows available while keeping long-lived credentials intact.
Validation
- Added focused command, AWS user, browser-dialog, and experimental-notice regression coverage.
- Added coverage for forced-webflow error, validation, and persistence branches; Codecov reports all modified coverable lines are covered.
- Ran affected Go package suites, focused acceptance snapshots,
actionlint, and repository pre-commit checks.
References
- N/A
Summary by CodeRabbit
-
New Features
- Added
--webflowto force a fresh browser login for AWS IAM user identities. - AWS IAM users can now access the AWS console using temporary session credentials.
- Improved browser authentication dialogs for long authorization URLs.
- Added
-
Bug Fixes
- Experimental command notices are now shown only once per execution.
- Added clearer validation and errors for unsupported webflow identity types.
-
Documentation
- Updated authentication, console access, and webflow usage guidance.
fix(secrets): store SSM scalar secrets without JSON quotes Erik Osterman (Cloud Posse) (@osterman) (#2797)
what
- Write string values to
secret: trueAWS SSM stores without JSON quoting. - Preserve JSON encoding for structured secrets and regular SSM stores, with regression coverage.
- Document absolute SSM parameter prefixes.
why
- AWS-native consumers need the raw
SecureStringvalue rather than a JSON-wrapped scalar.
references
- Closes #2795
Summary by CodeRabbit
-
Bug Fixes
- Improved AWS SSM secret handling to preserve raw string values (including number-like, boolean, and
nulltext) without unwanted formatting or type changes. - Added/strengthened round-trip behavior for structured secret values (maps and lists), plus correct handling of empty secret strings.
- Updated retrieval behavior to decode stored values consistently (including for
GetKey).
- Improved AWS SSM secret handling to preserve raw string values (including number-like, boolean, and
-
Documentation
- Clarified AWS SSM
prefixmust start with/. - Documented
secret: trueread/write behavior and related decoding ambiguity.
- Clarified AWS SSM
-
Tests
- Expanded SSM secret set/get/get-key coverage for both raw and legacy formats.
- Updated Terraform-compatible tooling test isolation to cover both
terraformandtofu.
fix(terraform): propagate provider cache to output lookups Erik Osterman (Cloud Posse) (@osterman) (#2791)
Summary
- apply Atmos's provider plugin-cache policy to internal
!terraform.outputandatmos.Component()Terraform runs - serialize internal
terraform initcalls that share a provider cache - preserve explicit cache overrides and add regression coverage
Root cause
The normal Terraform command pipeline synthesized TF_PLUGIN_CACHE_DIR, but the internal output executor created a separate subprocess environment without that automatic cache configuration. Each lookup therefore initialized providers in its component workdir unless CI injected the cache manually.
Validation
go test ./...- focused provider-cache and output-executor tests
scripts/run-custom-golangci-lint.sh- pre-commit hooks (
go-fumpt, Go build, custom lint)
Summary by CodeRabbit
- New Features
- Automatic Terraform provider plugin caching now derives and reuses a shared cache directory for Terraform subprocesses.
- Internal Terraform output lookups reuse the same caching policy.
- Bug Fixes
- Cache precedence is now component override → process environment → global config, with safer invalid-path fallback.
- Shared provider initialization is serialized, and init failures now propagate during output lookups.
- Tests
- Added coverage for cache resolution, environment wiring, init-lock serialization, and cross-platform behavior.
- Documentation
- Added fix notes for provider-cache reuse, Windows plugin-cache test issues, and a repo-copy race.
- Chores
- Updated dependency versions and website build overrides.
fix(ci): serialize verifier lifecycle and color errors Erik Osterman (Cloud Posse) (@osterman) (#2794)
what
- Keep each bootstrap verifier's install, trust repair, and execution inside its version lock.
- Render structured error output with ANSI color in CI while preserving
NO_COLORbehavior.
why
- Parallel tool installs could reinstall
cosignwhile another worker was executing it, causing LinuxETXTBSYfailures. - The structured error formatter omitted the standard
CIsignal even though the rest of Atmos recognizes CI as ANSI-capable.
references
Summary by CodeRabbit
- Bug Fixes
- CI now correctly enables ANSI color rendering unless disabled via
NO_COLOR. - Verifier bootstrap now preserves the per-version install lock through trust repair and verifier execution, reducing binary replacement race conditions.
- Added a bounded timeout for verifier subprocesses when no deadline is provided to prevent indefinite lock holding.
- CI now correctly enables ANSI color rendering unless disabled via
- Documentation
- Added a dated fixes note describing the verifier install-lock and CI color behavior.
- Tests
- Hardened CI/ANSI-dependent assertions by stripping ANSI escape codes where needed.
Add deprecation validation warnings Erik Osterman (Cloud Posse) (@osterman) (#2793)
what
- Keep supported legacy Atmos configuration valid while emitting schema-driven deprecation warnings in CLI validation and the LSP.
- Restore legacy Terraform dependency compatibility and add a customer regression scenario.
why
- Prevent 1.224 schema validation from blocking existing customer configuration while providing actionable migrations.
references
- N/A
Summary by CodeRabbit
- New Features
- Added deprecated-field warnings (with replacement guidance and file/line/column locations) to config validation, stack validation, schema validation, and language-server diagnostics.
- Updated schemas to mark legacy and dependency-related fields as deprecated, including
depends_onreplacement guidance. - Restored backward-compatible
depends_onhandling for legacy manifest layouts.
- Bug Fixes
- Schema validation now succeeds when there are no schema errors, even if warnings are present.
- Deprecation scanning is best-effort: failures no longer abort validation.
- Tests
- Added fixtures and unit/CLI tests covering deprecated-field compatibility and dependency fallback behavior.
- Documentation
- Documented deprecation warnings behavior across CLI and LSP.
fix(yaml): decode JSON after whitespace-trimmed function tags Erik Osterman (Cloud Posse) (@osterman) (#2780)
what
- Accept
[and{as valid boundaries after YAML function tags. - Add end-to-end coverage for whitespace-trimmed
!templatelist and map output. - Add a durable fix record under
docs/fixes.
why
- Go-template whitespace trimming can render
!template[...]or!template{...}, which strict tag matching left as literal strings.
references
- Closes #2778
Summary by CodeRabbit
- Bug Fixes
- Fixed YAML
!templateparsing so whitespace-trimmed templates that render JSON arrays/objects decode correctly. - Improved
!templateboundary handling around whitespace, JSON delimiters, end-of-input, and zero-argument tags, preventing accidental literal-string output.
- Fixed YAML
- Documentation
- Added a fix record documenting the corrected parsing behavior and edge cases.
- Tests
- Extended fixtures and added unit/integration assertions for trimmed list/map outputs and near-miss tag names.