Add Validation, Scaffolding, and Emulators cards to landing grid @osterman (#2974)
## what- Add three feature cards to the homepage "Batteries included" grid: Validation, Scaffolding, and Emulators.
- Each card follows the existing schema (icon, title, description, tag line, doc link) and slots next to its closest existing sibling card (Validation next to Vendoring, Scaffolding next to Toolchain, Emulators next to Workflows & Automation) so the grid still fills to full rows of 4.
- Link targets (
/validation/validating,/cli/commands/scaffold/usage,/cli/commands/emulator/usage) were verified against how other docs pages already link to these same destinations internally, not guessed.
why
- These three capabilities already ship in Atmos and have full docs, but weren't represented anywhere on the landing page, understating what the runtime includes out of the box.
- Kept to three additions (not four) so the grid still lands on a clean multiple of 4 cards per row instead of leaving a new single orphaned card in the last row.
references
- N/A
Summary by CodeRabbit
- New Features
- Added Validation, Scaffolding, and Emulators to the landing page’s battery features.
- Updated workflow messaging to highlight 35+ step types and revised emulator wording.
- Bug Fixes
- Improved retries for transient Sigstore trust-root CDN errors while excluding unrelated certificate-fetch failures.
- Documentation
- Explained how custom commands and workflows can work together as a task runner replacement.
- Clarified custom command configuration, optional usage, wrapped commands, and examples.
- Updated the custom commands link to point to the expanded documentation.
fix(container): resolve build/mount paths via base_path, add JIT source support @osterman (#2979)
## what- Container components (
components.container) now resolvebuild.context,build.dockerfile, andrun.mounts[].sourcethe same way Terraform/Helmfile/Kubernetes/Helm components resolve theirs: relative tocomponents.container.base_pathjoined with the component's own name, via a new precomputedContainerDirAbsolutePathand a"container"case in the shared component-path resolver. components.container.base_pathis promoted from an ad hoc, silently-ignored config value into a real, typedComponents.Containerfield.- Container components gain the same just-in-time
source:provisioning as Terraform/Helmfile/Kubernetes/Helm — a component declaring a source is auto-vendored into a workdir, which then anchors build/mount paths instead of the static base path. - Removed the now-redundant bespoke
container.Config/DefaultConfig()/parseConfig(), and fixed a hardcoded"components/container"literal indescribe_stacks.gothat ignored any configured override. - Regenerated the
atmos.yamlJSON schema, updated the container CLI docs and theatmos-containeragent skill, and added a changelog post + roadmap milestone.
why
build.context/build.dockerfilewere passed todocker build/podman buildcompletely unanchored, so they silently resolved against whatever directoryatmoshappened to be invoked from instead of the project — working by accident only when run from the repo root.run.mounts[].sourceanchored to the bare project root rather than the component itself, andcomponents.container.base_pathhad no effect anywhere despite being accepted as valid config.- Every other component type already has a consistent, CWD-independent path-resolution mechanism (
base_path+component:/metadata.component) plus JIT source provisioning; containers were the one component kind never wired into it.
references
- N/A
Summary by CodeRabbit
-
New Features
- Added configurable container component base paths, defaulting to
components/container. - Relative build contexts and mount sources now resolve from the component directory; Dockerfiles resolve from the build context.
- Added automatic provisioning for container components using
source:when needed.
- Added configurable container component base paths, defaulting to
-
Documentation
- Added guidance on path resolution, configuration, migration, and source provisioning.
- Updated the product roadmap to reflect the shipped functionality.
fix(ci): scope test-required aliases to their own OS's shard results @osterman (#2976)
## whattest-required (the legacy compatibility shim that aliases the sharded test matrix under the three historical required-check names) checked needs.test.result, which is a single aggregated verdict across the entire test matrix (3 OSes × 10 shards). A failure in any one shard on any one OS flipped that aggregate to failure, so all three aliases (Acceptance Tests (linux/macos/windows)) failed together even when only one OS actually had a failing shard.
This PR rewrites test-required to query the run's actual per-job results via gh api .../actions/runs/.../jobs, filtered by OS, so each alias only fails when a shard belonging to its own OS failed. It also stops gating the macos alias on terraform-registry-cache (whose matrix only has linux/windows legs and has no macos job to report on), which had the same cross-OS aggregation bug.
why
Observed on #2972: windows shard 2/10 failed after 57s, and Acceptance Tests (linux), (macos), and (windows) all failed within 3-4s as sympathetic failures with no real linux/macos test failures, forcing unnecessary re-runs/investigation of unaffected OSes.
references
- Observed on #2972
🚀 Enhancements
fix: ECR/ACR ambient-credential errors and broken --identity selector @osterman (#2977)
## whatatmos aws ecr login/atmos azure acr loginambient-credential fallback (no Atmos identity
configured) now returns a rich, actionable error when the underlying cloud SDK fails to retrieve
credentials (e.g. EC2 IMDS timeout, Azure managed identity failure), with an explanation and a
hint to runlogin --identity <name>or configurevia.identity.- Fixed bare
--identity(no value) failing withflag needs an argumentinstead of showing the
interactive identity selector, on 6 commands: custom commands (atmos.yamlcommands:),
describe,list,aws ecr login,aws eks token, andazure aks token. Each had hand-rolled
its own--identityflag registration instead of using the sharedflags.WithIdentityFlag()
builder that ~150 other commands already use, so each silently lost theNoOptDefValwiring that
makes bare--identitylegal and triggers the picker. - Exported
auth.ResolveSelectedIdentity(pkg/auth/manager_helpers.go) so the
sentinel-to-interactive-picker resolution logic lives in one place instead of being duplicated
(aws ecr login) or missing entirely (the other five commands).
why
- A user hit both issues running a downstream custom command (
atmos app build): first
--identity(bare) rejected as a usage error instead of prompting, and separately — once
ambient AWS credentials were tried as a fallback — a bare EC2 IMDS timeout with no indication
that configuring an Atmos identity was the fix. - The
--identityflag exists as a single, centrally-defined flag specifically so this class of
bug can't happen; these 6 commands were the stragglers that never got migrated onto that shared
definition, so the bug had to be independently rediscovered and patched (see the ad-hoc
NoOptDefValfix already present onaws ecr login) instead of being fixed once.
references
docs/fixes/2026-08-20-ecr-acr-ambient-credential-identity-hint.mddocs/fixes/2026-08-21-identity-flag-noOptDefVal-consolidation.md
Summary by CodeRabbit
-
New Features
- Bare
--identitynow opens interactive identity selection across supported AWS, Azure, EKS, listing, description, and custom commands. - Selected identities are consistently applied to subsequent authentication and operations.
- Bare
-
Bug Fixes
- Improved ECR and ACR authentication errors with actionable identity configuration guidance.
- Preserved underlying authentication and selection errors for easier troubleshooting.
-
Documentation
- Added guidance covering interactive identity selection and ambient credential troubleshooting.
fix: prevent concurrent-map-write panic in global Viper singleton @osterman (#2980)
## what- Routes every access to the process-wide global Viper singleton through a new mutex-guarded
pkg/config.GlobalViper()wrapper (SafeViper), instead of callingviper.GetViper()/viper.Set/viper.Get*directly — mirroring the embedded-mutex pattern already used bypkg/io/pkg/ui. - Fixes
pkg/hooks.GetHooksto forward theAtmosConfigit already received intoExecuteDescribeComponentParams, removing a redundant second, independently concurrent config load per hook invocation. - Closes a second, independently racy package-level slice (
mergedConfigFilesinpkg/config/load.go) by wrapping it in its own mutex-guarded tracker. - Adds
pkg/config/load_concurrent_test.go, a-race-driven regression test that spins up concurrentLoadConfigcalls against a real fixture and reproduces the original panic on unfixed code. - Minor cleanup:
bridgeVendorUpdaterConfignow fetchesGlobalViper()once instead of once perSetcall, and a newciFlagKeyconstant replaces 10 duplicated"ci"string literals incmd/terraform/utils.go(surfaced by golangci-lint'sadd-constantcheck once those lines were touched).
why
atmos terraform ... --max-concurrency 3(and even2) could panic withfatal error: concurrent map writesinsideviper.(*Viper).Set, reported from production usage. Root cause:pkg/config.LoadConfigbridgesprofiles.base_pathandvendor.update.*/vendor.ci.*into the process-wide global Viper singleton on every call, with zero locking (spf13/viperhas no internal synchronization), while the DAG scheduler runsLoadConfigconcurrently — once per graph node — whenever--max-concurrency > 1.GetHookswas also triggering a second, entirely redundantInitCliConfig/LoadConfigcall per node because it never forwarded theAtmosConfigit was already given, doubling the exposure to the race for no reason.- The regression test proves the fix: run against the pre-fix code under
go test -race, it reliably reproduces the exactviper.(*Viper).Setrace reported in production; against the fixed code it passes clean.
references
- Reported in Slack by two engineers hitting the same panic at
--max-concurrency 2and3.
Summary by CodeRabbit
-
Bug Fixes
- Improved configuration handling during concurrent operations, preserving environment-key casing and preventing cross-load contamination.
- Ensured hooks use the active configuration when describing components.
- Standardized CI mode and profile settings detection across commands.
- Explicit
--ci=falsenow overrides CI environment settings and automatic CI detection. - Improved reliability when reading shared configuration during shell and command execution, including masking settings.
-
Tests
- Added coverage for concurrent configuration loading, CI precedence, shared configuration access, and configuration-aware hook execution.