When a default identity is configured only in stack config (e.g., stacks/orgs/acme/_defaults),
the identity is not passed to describe component and other commands. Users are prompted to
select an identity even though one is configured as default in their stack configuration.
❯ atmos describe component <component> -s <stack>
┃ No default identity configured. Please choose an identity:
┃ > identity-1
┃ identity-2
┃ ...Even when stack config has:
# stacks/orgs/acme/_defaults.yaml
auth:
identities:
identity-1:
default: trueSetting the default in the profile config works:
# profiles/managers/atmos.yaml
auth:
identities:
identity-1:
kind: aws/assume-role
default: true
via:
identity: identity-1/permission-set
principal:
assume_role: arn:aws:iam::123456789012:role/managersThe issue manifests differently depending on the command type:
The atmos describe component command was not following the same pattern as atmos terraform * commands. While terraform commands already implemented Component Auth Merge (Approach 1), describe component was simply using global auth config directly:
Old (broken) code in cmd/describe_component.go:
// Load atmos configuration - processStacks = FALSE
atmosConfig, err := cfg.InitCliConfig(..., false)
// Create AuthManager using ONLY atmos.yaml + profile auth config
// Stack-level defaults were completely ignored!
authManager, err := CreateAuthManagerFromIdentity(identityName, &atmosConfig.Auth)The fix was to update describe component to follow the same Approach 1 pattern that terraform commands already used.
For commands like describe stacks, describe affected, and list instances that operate on multiple stacks/components, there's a genuine chicken-and-egg problem:
-
InitCliConfig(processStacks=false)only loads:- System atmos config
- User atmos config (
~/.atmos/atmos.yaml) - Project atmos config (
atmos.yaml) - Profile configs (e.g.,
profiles/managers/atmos.yaml)
-
Stack configs are NOT loaded at this point because:
- Processing stacks may require authentication (for YAML functions)
- Authentication requires knowing the identity
- Identity resolution happens before stack processing
-
These commands cannot use Approach 1 (Component Auth Merge) because they don't have a specific component+stack pair to query upfront.
Profile configs are loaded during InitCliConfig before stacks are processed:
- Profiles are part of the atmos configuration layer
- They're merged into
atmosConfig.Authimmediately - The
AuthManagersees them when checking for defaults
For describe component: The command simply wasn't merging stack-level auth config.
For multi-stack commands: Stack configs are only processed when processStacks=true, creating a timing issue that required Approach 2 (Stack Scanning) to solve.
Two approaches are used depending on whether a specific component+stack pair is available:
For commands like describe component and terraform * where both component and stack are known,
we leverage the existing stack inheritance and merge functionality:
- Call
ExecuteDescribeComponent()withProcessTemplates=false, ProcessYamlFunctions=false, AuthManager=nil - The component config output includes the merged auth section from stack inheritance
- Merge with global auth using
auth.MergeComponentAuthFromConfig() - Create auth manager with the merged config
This approach is preferred because:
- It uses the existing stack merge logic (no duplication)
- The auth section includes all inherited defaults from stack hierarchy
- Component-level auth overrides are respected
Example flow in terraform.go and describe_component.go:
// 1. Start with global auth config
mergedAuthConfig := auth.CopyGlobalAuthConfig(&atmosConfig.Auth)
// 2. Get component config (includes stack-level auth with default flag)
componentConfig, err := ExecuteDescribeComponent(&ExecuteDescribeComponentParams{
Component: component,
Stack: stack,
ProcessTemplates: false,
ProcessYamlFunctions: false, // Avoid circular dependency
AuthManager: nil, // No auth manager yet
})
// 3. Merge component auth (including stack defaults) with global auth
if err == nil {
mergedAuthConfig, err = auth.MergeComponentAuthFromConfig(...)
}
// 4. Create auth manager with fully merged config
authManager, err := CreateAuthManagerFromIdentity(identityName, mergedAuthConfig)For commands that operate on multiple stacks/components (e.g., describe stacks, describe affected),
we perform a lightweight pre-scan of stack configurations to extract auth identity defaults:
-
Stack auth scanner (
pkg/config/stack_auth_scanner.go):- Scans stack manifest files for
auth.identities.*.default: true - Uses minimal YAML parsing without template/function processing
- Returns a map of identity names to their default status
- Scans stack manifest files for
-
Merge into auth config before creating an auth manager:
- Stack defaults take precedence over atmos.yaml defaults
- Follows Atmos inheritance model (more specific config overrides global)
- Atmos config defaults (
atmos.yaml) - Stack config defaults (scanned or from component merge)
- CLI flag (
--identity) / environment variable (ATMOS_IDENTITY)
New Files:
pkg/config/stack_auth_scanner.go- Scanner for stack-level auth defaultspkg/config/stack_auth_scanner_test.go- Unit tests for scanner
Commands Using Component Auth Merge (Approach 1):
cmd/describe_component.go- Uses terraform.go pattern withExecuteDescribeComponent+MergeComponentAuthFromConfiginternal/exec/terraform.go- Original implementation of this pattern
Commands Using Stack Scanning (Approach 2):
cmd/describe_stacks.go- UsesCreateAuthManagerFromIdentityWithAtmosConfigcmd/describe_affected.go- UsesCreateAuthManagerFromIdentityWithAtmosConfigcmd/describe_dependents.go- UsesCreateAuthManagerFromIdentityWithAtmosConfigcmd/list/instances.go- UsesCreateAndAuthenticateManagerWithAtmosConfiginternal/exec/workflow_utils.go- Scans stack defaults when creating AuthManager
Updated Internal Execution:
internal/exec/terraform_nested_auth_helper.go- Resolves AuthManager for nested component references in YAML functions using Approach 1
Updated Auth Helpers:
pkg/auth/manager_helpers.go- NewCreateAndAuthenticateManagerWithAtmosConfigfunctioncmd/identity_flag.go- NewCreateAuthManagerFromIdentityWithAtmosConfigwrapper
pkg/config/stack_auth_scanner_test.go- Scanner logic testspkg/auth/manager_helpers_test.go- Integration with auth manager
- Test fixture in
tests/fixtures/scenarios/stack-auth-defaults/ - CLI test verifying stack-level defaults work without prompting
atmos describe component- Has specific component+stackatmos terraform *(all terraform subcommands) - Has specific component+stack
atmos describe stacks- Operates on multiple stacks/componentsatmos describe affected- Operates on all affected componentsatmos describe dependents- Operates on multiple stacksatmos list instances- Lists all instances across stacks
!terraform.state- Inherits AuthManager from parent command context!terraform.output- Inherits AuthManager from parent command context- For nested component references, uses Approach 1 (Component Auth Merge) via
resolveAuthManagerForNestedComponent()
- Workflow execution scans for stack-level defaults when no explicit identity is specified (uses Approach 2)