Skip to content

fix: Improve AWS credential isolation and auth error propagation#1712

Merged
aknysh merged 56 commits intomainfrom
osterman/fix-aws-profile-identity-selection
Oct 28, 2025
Merged

fix: Improve AWS credential isolation and auth error propagation#1712
aknysh merged 56 commits intomainfrom
osterman/fix-aws-profile-identity-selection

Conversation

@osterman
Copy link
Member

@osterman osterman commented Oct 24, 2025

Summary

This PR addresses multiple authentication issues when using Atmos in containerized environments with mounted credential files:

  1. Auth Pre-Hook Error Propagation - Terraform execution now properly aborts when authentication fails (e.g., Ctrl+C during SSO)
  2. AWS Credential Loading Strategy - New LoadAtmosManagedAWSConfig() function provides proper isolation while preserving Atmos-managed profile selection
  3. Noop Keyring Validation - Container auth now properly isolated from external environment variables
  4. Whoami with Noop Keyring - atmos auth whoami now works in containerized environments
  5. Test Coverage - Added test to verify auth errors properly abort execution

Changes

1. Auth Pre-Hook Error Propagation (internal/exec/terraform.go:236)

  • Problem: Errors from auth pre-hook were logged but not returned, causing terraform execution to continue even when authentication failed (e.g., user presses Ctrl+C during SSO)
  • Fix: Added return err after logging auth pre-hook errors
  • Impact: Terraform commands now properly abort on auth failures

2. AWS Credential Loading Strategy (pkg/auth/cloud/aws/env.go)

  • Problem: SDK's default config loading allowed IMDS access and was affected by external AWS_PROFILE, causing conflicts in containers
  • Solution: Created LoadAtmosManagedAWSConfig() function that:
    • Clears credential env vars (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN)
    • Preserves profile/path vars (AWS_PROFILE, AWS_SHARED_CREDENTIALS_FILE, AWS_CONFIG_FILE)
    • Allows SDK to load from Atmos-managed credential files
  • Impact: Proper isolation while still using Atmos-managed profiles

3. Noop Keyring Credential Validation (pkg/auth/credentials/keyring_noop.go)

  • Problem: Used unrestricted config.LoadDefaultConfig() which allowed IMDS access and was affected by external AWS_PROFILE
  • Fix: Changed to use LoadAtmosManagedAWSConfig()
  • Impact: Container auth now properly isolated from external env vars

4. Whoami with Noop Keyring (pkg/auth/manager.go)

  • Problem: Whoami() expected credentials from keyring, but noop keyring returns ErrCredentialsNotFound by design
  • Fix: Added check for ErrCredentialsNotFound and fallback to buildWhoamiInfoFromEnvironment()
  • Impact: atmos auth whoami now works in containerized environments

5. Test Coverage (internal/exec/terraform_test.go)

  • Added TestExecuteTerraform_AuthPreHookErrorPropagation to verify auth errors properly abort execution
  • Test validates that terraform doesn't continue on auth failure
  • Updated test fixture to include required name_pattern configuration

Technical Details

The key insight is that Atmos sets AWS_PROFILE=identity-name (in pkg/auth/cloud/aws/setup.go:59) but the previous isolation approach cleared ALL AWS env vars including AWS_PROFILE. This caused the SDK to look for a non-existent [default] section.

The new LoadAtmosManagedAWSConfig preserves AWS_PROFILE while still preventing external credential conflicts.

Test Plan

  • go build . - Build succeeds
  • go test ./internal/exec -run TestExecuteTerraform - All terraform tests pass
  • TestExecuteTerraform_AuthPreHookErrorPropagation - New test passes
  • Verified test fails when fix is removed (terraform continues execution)
  • Verified test passes when fix is restored (terraform aborts on auth error)

References

Fixes authentication issues in containerized environments with mounted credentials.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added --login and cached-credentials-first flows across auth commands; whoami now shows validation and expiry.
    • Atmos-managed credentials moved to XDG-compliant locations; improved shell enter/exit messages.
    • Geodesic helper script for building/testing in containerized environments.
  • Bug Fixes

    • Terraform pre-hook errors now abort execution.
    • Improved propagation of user-abort during authentication.
  • Documentation

    • XDG migration guides and Geodesic/CLI docs updated.
  • Tests

    • Broad expansion of auth, AWS credential, auth-context and output-propagation tests.

@osterman osterman requested a review from a team as a code owner October 24, 2025 01:49
@github-actions github-actions bot added the size/m Medium size PR label Oct 24, 2025
@github-actions
Copy link

github-actions bot commented Oct 24, 2025

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 24, 2025

📝 Walkthrough

Walkthrough

Thread authContext through Terraform output/template/hook paths; introduce XDG-based AWS credential storage and env preparation; extend auth interfaces with cached credential and environment APIs; simplify noop keyring; add credential-loading helpers, mocks and tests; Make ExecuteTerraform return early on TerraformPreHook errors.

Changes

Cohort / File(s) Summary
Terraform output & authContext
internal/exec/terraform_output_getter.go, internal/exec/terraform_output_utils.go, internal/exec/yaml_func_terraform_output.go, internal/exec/yaml_func_terraform_output_authcontext_test.go, internal/exec/mock_terraform_output_getter.go, internal/exec/template_funcs_component.go
Add TerraformOutputGetter interface and package outputGetter; add authContext *schema.AuthContext parameter to GetTerraformOutput/execTerraformOutput and thread through YAML/template code; add gomock and tests asserting authContext propagation.
ExecuteTerraform behavior
internal/exec/terraform.go, internal/exec/terraform_test.go
On TerraformPreHook error, log and immediately return the error (early exit). Add test verifying auth pre-hook error propagation.
YAML/template & hooks plumbing
internal/exec/yaml_func_utils.go, internal/exec/yaml_func_terraform_output.go, pkg/hooks/store_cmd.go, pkg/hooks/*_test.go
Pass stackInfo into tag processing, extract/derive authContext, and update hook/getter signatures and test mocks to accept authContext.
Auth interfaces & validation model
pkg/auth/types/interfaces.go, pkg/auth/types/aws_credentials.go, pkg/auth/types/github_oidc_credentials.go, pkg/auth/providers/mock/credentials.go
Introduce ValidationInfo; change ICredentials.Validate(ctx) to return (*ValidationInfo, error); add credential-store type constants and new interface methods (PrepareEnvironment, CredentialsExist, LoadCredentials, GetCachedCredentials, GetEnvironmentVariables, Type).
Auth manager, whoami, caching & logout
pkg/auth/manager.go, pkg/auth/manager_whoami.go, pkg/auth/manager_logout.go, pkg/auth/manager_caching_test.go, pkg/auth/manager_test.go
Add GetCachedCredentials and GetEnvironmentVariables; implement cached-first lookup with keyring/identity-storage fallback, buildWhoamiInfo helpers, and logout/provider/all flows with tests.
AWS identity implementations & credential loader
pkg/auth/identities/aws/*.go, pkg/auth/identities/aws/credentials_loader.go, pkg/auth/identities/aws/*_test.go
Add CredentialsExist, LoadCredentials, PrepareEnvironment to AWS identities; implement environment-driven credential loading, metadata-based expiration parsing, and extensive tests.
Credential stores
pkg/auth/credentials/keyring_noop.go, pkg/auth/credentials/keyring_file.go, pkg/auth/credentials/keyring_memory.go, pkg/auth/credentials/keyring_system.go, pkg/auth/credentials/*_test.go
Simplify noop keyring (remove caching/validation), expose Type() on stores, and update tests to reflect no-op behavior and Type() method.
AWS files & XDG support
pkg/auth/cloud/aws/files.go, pkg/auth/cloud/aws/env.go, pkg/auth/cloud/aws/files_test.go, pkg/xdg/xdg.go, pkg/xdg/xdg_test.go
Default Atmos AWS paths moved to XDG (~/.config/atmos/...), add LoadINIFile, LoadAtmosManagedAWSConfig, PrepareEnvironment, legacy-path warnings, and macOS init override for CLI-style XDG paths; add tests.
CLI commands & UX changes
cmd/auth_env.go, cmd/auth_whoami.go, cmd/auth_shell.go, cmd/auth_exec.go, cmd/auth_console.go, cmd/auth_logout.go, cmd/*_test.go
Add --login flag to auth env; prefer GetCachedCredentials before full Authenticate across commands; whoami shows validation state; logout supports identity flag; update tests and snapshots.
Mocks, tests & test infra
pkg/auth/types/mock_interfaces.go, pkg/auth/providers/mock/*, cmd/auth_console_test.go, pkg/auth/hooks_test.go, internal/exec/mock_terraform_output_getter.go, many *_test.go, tests/*
Regenerate/extend gomock mocks and test stubs for new methods and Validate signature; add tests for auth caching, env prep, credential loading; update many golden snapshots and test isolation helpers (XDG).
HTTP, errors & misc
pkg/http/client.go, errors/errors.go, errors/error_funcs.go, internal/aws_utils/aws_utils.go, internal/exec/shell_utils.go, Makefile, scripts/test-geodesic-prebuilt.sh
Improve HTTP error messages and truncation; add ErrAwsMissingEnvVars, ErrUserAborted; add plain-error fallback printing; add AWS-load debug logs; add shell enter/exit messages; add generate-mocks make target and new Geodesic test script.
Docs & website
website/docs/cli/commands/auth/*, docs/prd/xdg-base-directory-specification.md, website/blog/*, README.md
Update docs and blog posts to document XDG migration, macOS CLI conventions, Geodesic developer tooling, and migration guidance.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI Command
    participant Manager as Auth Manager
    participant Cache as Keyring/File Cache
    participant Identity as Identity Storage
    participant AWS as AWS SDK
    participant TF as Terraform Output

    CLI->>Manager: GetCachedCredentials(identity)
    Manager->>Cache: Retrieve(identity)
    alt cache hit valid
        Cache-->>Manager: creds
        Manager-->>CLI: WhoamiInfo (cached)
    else cache miss or expired
        Manager->>Identity: CredentialsExist()
        alt exists
            Identity-->>Manager: true
            Identity->>AWS: LoadCredentials(ctx)
            AWS-->>Identity: ICredentials (with Expiration)
            Manager->>Cache: Store(identity, creds)
            Manager-->>CLI: WhoamiInfo (from storage)
        else no creds
            Manager-->>CLI: ErrNoCredentialsFound
        end
    end

    CLI->>TF: Request !terraform.output (includes stackInfo)
    TF->>Manager: build authContext from stackInfo
    TF->>TF: execTerraformOutput(..., authContext)
    TF->>AWS: LoadAtmosManagedAWSConfig(ctx) via authContext
    AWS-->>TF: AWS env & credentials
    TF->>TF: Run terraform and return output
Loading
sequenceDiagram
    participant Init as pkg/xdg init
    participant XDG as adrg/xdg

    Init->>Init: detect runtime.GOOS
    alt darwin
        Init->>XDG: set ConfigHome = ~/.config
        Init->>XDG: set DataHome = ~/.local/share
        Init->>XDG: set CacheHome = ~/.cache
    else
        XDG-->>XDG: keep defaults
    end
    Note over Init,XDG: ensures CLI-style XDG paths on macOS
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Areas needing extra attention:

  • Interface/signature changes for credentials validation and updating all implementations and mocks (pkg/auth/types/*, providers, mocks).
  • GetCachedCredentials logic, expiry semantics, and keyring vs identity storage fallback (pkg/auth/manager.go, pkg/auth/manager_caching_test.go).
  • authContext propagation into Terraform/YAML/template/hook paths and generated mock correctness (internal/exec/*, pkg/hooks/*).
  • XDG path migration, macOS override, legacy-path warnings and tests (pkg/auth/cloud/aws/files.go, pkg/xdg/*, many tests and snapshots).
  • Large snapshot/golden updates — verify expected output changes and test isolation helpers.

Possibly related PRs

Suggested labels

patch

Suggested reviewers

  • osterman

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 49.72% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "fix: Improve AWS credential isolation and auth error propagation" clearly and concisely describes the two primary changes in the changeset. The title directly relates to the main modifications: the addition of auth pre-hook error propagation in terraform execution (ensuring errors abort rather than continue), and the introduction of AWS credential isolation mechanisms through LoadAtmosManagedAWSConfig and related environment handling improvements. The title uses specific, descriptive terminology and follows conventional commit conventions, making it clear to teammates reviewing commit history that this PR addresses credential handling and authentication error handling issues.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch osterman/fix-aws-profile-identity-selection

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3b77cdf and d0ff63c.

📒 Files selected for processing (1)
  • internal/exec/shell_utils.go (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • internal/exec/shell_utils.go
**/!(*_test).go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Document all exported functions, types, and methods with Go doc comments

Files:

  • internal/exec/shell_utils.go
🧬 Code graph analysis (1)
internal/exec/shell_utils.go (2)
pkg/logger/log.go (1)
  • Trace (14-16)
pkg/ui/theme/colors.go (3)
  • ColorGreen (11-11)
  • ColorCyan (12-12)
  • ColorGray (10-10)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Build (windows)
  • GitHub Check: Build (linux)
  • GitHub Check: autofix
  • GitHub Check: website-deploy-preview
  • GitHub Check: Lint (golangci)
  • GitHub Check: Analyze (go)
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: Summary
🔇 Additional comments (4)
internal/exec/shell_utils.go (4)

15-15: LGTM on import additions.

The lipgloss and theme imports are properly organized and used by the new message functions.

Also applies to: 22-22


525-525: Good call on downgrading to Trace level.

Environment variable logging at Debug level could be noisy when many vars are set. Trace is more appropriate for this detailed output.

Also applies to: 552-552


558-576: Clean implementation with good UX.

The styled message clearly indicates shell entry and provides helpful exit instructions. Writing to stderr keeps it separate from command output.


578-589: LGTM on exit message styling.

The muted gray styling for the exit message provides a good visual distinction from the entry message.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 35e2af6 and 75a252f.

📒 Files selected for processing (8)
  • internal/exec/terraform.go (1 hunks)
  • internal/exec/terraform_test.go (2 hunks)
  • pkg/auth/cloud/aws/env.go (2 hunks)
  • pkg/auth/credentials/keyring_noop.go (2 hunks)
  • pkg/auth/identities/aws/user.go (1 hunks)
  • pkg/auth/manager.go (3 hunks)
  • pkg/auth/types/aws_credentials.go (1 hunks)
  • tests/fixtures/scenarios/atmos-auth-invalid/atmos.yaml (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Generate mocks with go.uber.org/mock/mockgen using //go:generate directives; never write manual mocks
Use functional options pattern instead of functions with many parameters
Use context.Context only for cancellation, deadlines, and narrowly-scoped request values; never for config or dependencies; context should be the first parameter
All comments must end with periods (godot linter)
Organize imports in three groups with blank lines (stdlib, third-party, then Atmos packages) and sort alphabetically; keep aliases: cfg, log, u, errUtils
Error handling: wrap with static errors from errors/errors.go, combine with errors.Join, add context with fmt.Errorf("%w: msg", err), check with errors.Is; never compare strings or create dynamic error types
Use //go:generate go run go.uber.org/mock/mockgen@latest -source= -destination=test.go for mocks
Keep files small and focused (<600 lines), one command/impl per file; co-locate tests; never use //revive:disable:file-length-limit
Bind environment variables with viper.BindEnv and use ATMOS
prefix
UI (prompts/status) must write to stderr; data outputs to stdout; logging only for system events, not UI
Ensure cross-platform compatibility: prefer SDKs over binaries and use filepath.Join() instead of hardcoded separators

Files:

  • internal/exec/terraform.go
  • pkg/auth/identities/aws/user.go
  • pkg/auth/types/aws_credentials.go
  • pkg/auth/cloud/aws/env.go
  • pkg/auth/manager.go
  • pkg/auth/credentials/keyring_noop.go
  • internal/exec/terraform_test.go
**/!(*_test).go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Document all exported functions, types, and methods with Go doc comments

Files:

  • internal/exec/terraform.go
  • pkg/auth/identities/aws/user.go
  • pkg/auth/types/aws_credentials.go
  • pkg/auth/cloud/aws/env.go
  • pkg/auth/manager.go
  • pkg/auth/credentials/keyring_noop.go
{internal,pkg}/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

{internal,pkg}/**/*.go: Use interface-driven design: define interfaces, inject dependencies for testability, and prefer DI over concrete coupling
Add defer perf.Track(atmosConfig, "pkg.FuncName")() + a blank line at the start of all public functions (use nil if no atmosConfig)

Files:

  • internal/exec/terraform.go
  • pkg/auth/identities/aws/user.go
  • pkg/auth/types/aws_credentials.go
  • pkg/auth/cloud/aws/env.go
  • pkg/auth/manager.go
  • pkg/auth/credentials/keyring_noop.go
  • internal/exec/terraform_test.go
internal/exec/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Implement command business logic in internal/exec/ (not in cmd/)

Files:

  • internal/exec/terraform.go
  • internal/exec/terraform_test.go
pkg/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Place business logic in pkg rather than in cmd

Files:

  • pkg/auth/identities/aws/user.go
  • pkg/auth/types/aws_credentials.go
  • pkg/auth/cloud/aws/env.go
  • pkg/auth/manager.go
  • pkg/auth/credentials/keyring_noop.go
pkg/**

📄 CodeRabbit inference engine (CLAUDE.md)

Create purpose-built, focused packages under pkg/ instead of adding to utils; co-locate tests with clear responsibilities

Files:

  • pkg/auth/identities/aws/user.go
  • pkg/auth/types/aws_credentials.go
  • pkg/auth/cloud/aws/env.go
  • pkg/auth/manager.go
  • pkg/auth/credentials/keyring_noop.go
{**/*_test.go,tests/**}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer unit tests with mocks over integration; table-driven tests; keep integration tests under tests/; target >80% coverage

Files:

  • tests/fixtures/scenarios/atmos-auth-invalid/atmos.yaml
  • internal/exec/terraform_test.go
**/*_test.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios

**/*_test.go: Test behavior, not implementation; avoid tautological tests; use DI to make behavior testable
Tests must exercise production code paths; do not duplicate logic in tests
Use t.Skipf("reason") with clear context when skipping tests

Files:

  • internal/exec/terraform_test.go
🧠 Learnings (2)
📚 Learning: 2025-10-03T18:02:08.535Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: internal/exec/terraform.go:269-272
Timestamp: 2025-10-03T18:02:08.535Z
Learning: In internal/exec/terraform.go, when auth.TerraformPreHook fails, the error is logged but execution continues. This is a deliberate design choice to allow Terraform commands to proceed even if authentication setup fails, rather than failing fast.

Applied to files:

  • internal/exec/terraform.go
  • internal/exec/terraform_test.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
PR: cloudposse/atmos#1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.

Applied to files:

  • pkg/auth/manager.go
🧬 Code graph analysis (4)
pkg/auth/cloud/aws/env.go (1)
errors/errors.go (1)
  • ErrLoadAwsConfig (74-74)
pkg/auth/manager.go (5)
pkg/auth/credentials/keyring_file.go (1)
  • ErrCredentialsNotFound (36-36)
pkg/logger/log.go (1)
  • Debug (24-26)
errors/errors.go (1)
  • ErrNoCredentialsFound (386-386)
pkg/auth/types/whoami.go (1)
  • WhoamiInfo (6-22)
pkg/auth/types/interfaces.go (2)
  • Provider (13-42)
  • Identity (45-69)
pkg/auth/credentials/keyring_noop.go (2)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/auth/cloud/aws/env.go (1)
  • LoadAtmosManagedAWSConfig (142-176)
internal/exec/terraform_test.go (3)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/schema/schema.go (1)
  • ConfigAndStacksInfo (488-567)
internal/exec/terraform.go (1)
  • ExecuteTerraform (33-623)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Build (windows)
  • GitHub Check: Build (linux)
  • GitHub Check: autofix
  • GitHub Check: Lint (golangci)
  • GitHub Check: Analyze (go)
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: Summary
🔇 Additional comments (12)
tests/fixtures/scenarios/atmos-auth-invalid/atmos.yaml (1)

26-26: LGTM!

The name_pattern addition properly extends the test fixture to support the new auth error propagation test scenario.

pkg/auth/identities/aws/user.go (1)

181-182: Good documentation improvement.

The comment clarifies the credential loading approach, which is helpful given the new LoadAtmosManagedAWSConfig function introduced elsewhere in this PR.

pkg/auth/cloud/aws/env.go (1)

96-98: Excellent documentation enhancement.

The updated comments clearly distinguish between LoadIsolatedAWSConfig for initial authentication and LoadAtmosManagedAWSConfig for working with Atmos-managed credential files. This helps developers choose the appropriate function.

pkg/auth/types/aws_credentials.go (1)

61-63: Good explanatory comments.

The notes about circular dependency avoidance and validation approach help clarify the design decisions in this validation method.

pkg/auth/credentials/keyring_noop.go (2)

11-11: Import update aligns with the new config loading strategy.

The addition of the awsCloud package import enables use of LoadAtmosManagedAWSConfig for credential validation, which is the intended behavior change in this PR.


137-147: Config loading update properly implements the noop keyring isolation strategy.

The switch to LoadAtmosManagedAWSConfig correctly enables validation of credentials from Atmos-managed files while preventing interference from external AWS environment variables. The updated comments accurately describe this behavior.

pkg/auth/manager.go (3)

14-14: Import addition enables noop keyring detection.

The credentials package import is necessary to check for ErrCredentialsNotFound in the updated Whoami logic.


180-188: Noop keyring support properly implemented.

The updated logic correctly distinguishes between the noop keyring scenario (credentials validated but not stored) and genuinely missing credentials. The use of errors.Is for error checking and the fallback to buildWhoamiInfoFromEnvironment aligns with the PR's goal of supporting containerized environments with externally-managed credentials.


754-779: Environment-based WhoamiInfo construction correctly handles noop keyring scenario.

The function properly constructs a WhoamiInfo when credentials are managed externally. The implementation is clean, and the comments clearly explain the limitations (no credentials/expiration from keyring). Since this is a private function, the absence of godoc and perf tracking is acceptable per the coding guidelines.

internal/exec/terraform.go (1)

236-236: Auth pre-hook error propagation properly implemented.

This change correctly ensures that Terraform execution aborts when authentication fails, rather than continuing with potentially invalid credentials. This is a deliberate fix to the previous behavior where errors were only logged, addressing scenarios like user cancellation during SSO authentication.

The change aligns with the new test coverage in terraform_test.go (TestExecuteTerraform_AuthPreHookErrorPropagation).

internal/exec/terraform_test.go (2)

12-12: Import additions support the new test.

The require and perf imports are appropriately added for the new test function's assertions and performance tracking.

Also applies to: 16-16


791-859: Auth pre-hook error propagation test properly implemented.

The test effectively verifies that auth pre-hook errors abort Terraform execution. Good practices include performance tracking, cleanup with defer, stderr suppression for cleaner test output, and appropriate use of require for setup and assert for verification.

The error message check (lines 854-858) uses a broad set of keywords which reduces brittleness. Consider using assert.ErrorContains if a specific substring is always expected, though the current approach is acceptable.

This commit addresses multiple authentication issues when using Atmos
in containerized environments with mounted credential files:

## Changes

### 1. Auth Pre-Hook Error Propagation (terraform.go:236)
- **Problem**: Errors from auth pre-hook were logged but not returned,
  causing terraform execution to continue even when authentication failed
  (e.g., user presses Ctrl+C during SSO)
- **Fix**: Added `return err` after logging auth pre-hook errors
- **Impact**: Terraform commands now properly abort on auth failures

### 2. AWS Credential Loading Strategy (pkg/auth/cloud/aws/env.go)
- **Problem**: SDK's default config loading allowed IMDS access and was
  affected by external AWS_PROFILE, causing conflicts in containers
- **Solution**: Created `LoadAtmosManagedAWSConfig()` function that:
  - Clears credential env vars (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN)
  - Preserves profile/path vars (AWS_PROFILE, AWS_SHARED_CREDENTIALS_FILE, AWS_CONFIG_FILE)
  - Allows SDK to load from Atmos-managed credential files
- **Impact**: Proper isolation while still using Atmos-managed profiles

### 3. Noop Keyring Credential Validation (pkg/auth/credentials/keyring_noop.go)
- **Problem**: Used unrestricted `config.LoadDefaultConfig()` which allowed
  IMDS access and was affected by external AWS_PROFILE
- **Fix**: Changed to use `LoadAtmosManagedAWSConfig()`
- **Impact**: Container auth now properly isolated from external env vars

### 4. Whoami with Noop Keyring (pkg/auth/manager.go)
- **Problem**: `Whoami()` expected credentials from keyring, but noop keyring
  returns `ErrCredentialsNotFound` by design
- **Fix**: Added check for `ErrCredentialsNotFound` and fallback to
  `buildWhoamiInfoFromEnvironment()`
- **Impact**: `atmos auth whoami` now works in containerized environments

### 5. Test Coverage (internal/exec/terraform_test.go)
- Added `TestExecuteTerraform_AuthPreHookErrorPropagation` to verify auth
  errors properly abort execution
- Test validates that terraform doesn't continue on auth failure
- Updated test fixture to include required `name_pattern` configuration

## Technical Details

The key insight is that Atmos sets `AWS_PROFILE=identity-name` but the
previous isolation approach cleared ALL AWS env vars including AWS_PROFILE.
This caused the SDK to look for a non-existent `[default]` section.

The new `LoadAtmosManagedAWSConfig` preserves AWS_PROFILE while still
preventing external credential conflicts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@osterman osterman force-pushed the osterman/fix-aws-profile-identity-selection branch from 75a252f to 1c1e414 Compare October 24, 2025 14:51
…ta to AWS credentials files

- Added ValidationInfo struct to capture validation results (ARN, account, expiration) from cloud provider APIs
- Updated ICredentials.Validate() to return ValidationInfo instead of just expiration time
- Enhanced whoami command to validate credentials and display principal (ARN) and account information
- Fixed buildWhoamiInfo to preserve credentials in memory for validation (they're excluded from JSON/YAML via tags)
- Added x_atmos_expiration metadata key to AWS credentials files for expiration tracking
- Implemented LoadCredentials() for all AWS identity types to support noop keyring credential loading
- Added comprehensive tests for metadata reading/writing and credential loading
- Fixed whoami output formatting (removed extra newline)

This enables whoami to show green checkmark when credentials are valid and display full authentication status including ARN, account, region, and expiration time.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@osterman osterman requested a review from a team as a code owner October 25, 2025 00:22
@github-actions github-actions bot added size/xl Extra large size PR and removed size/m Medium size PR labels Oct 25, 2025
@mergify
Copy link

mergify bot commented Oct 25, 2025

Warning

This PR exceeds the recommended limit of 1,000 lines.

Large PRs are difficult to review and may be rejected due to their size.

Please verify that this PR does not address multiple issues.
Consider refactoring it into smaller, more focused PRs to facilitate a smoother review process.

The test script was consolidated into test-geodesic-prebuilt.sh which is already committed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
website/docs/cli/commands/auth/logout.mdx (1)

198-202: Update documentation: macOS paths use ~/.config, not ~/Library/Application Support.

The implementation in pkg/xdg/xdg.go overrides adrg/xdg defaults and applies CLI tool conventions across all platforms including macOS—setting xdg.ConfigHome to ~/.config (lines 18-24). This contradicts the documented paths.

Update these three sections in website/docs/cli/commands/auth/logout.mdx:

  • Line 198–202: Change macOS path from ~/Library/Application Support/atmos/aws/ to ~/.config/atmos/aws/
  • Line 316–327: Troubleshooting example should use ~/.config/atmos/ instead of ~/Library/Application\ Support/atmos/
  • Line 401–402: Precedence/default section should reflect ~/.config/atmos/aws/ for macOS
pkg/auth/types/aws_credentials.go (1)

43-47: Fix double “%w” in fmt.Errorf (compile error).

fmt.Errorf allows only one %w. Use %v for the inner error (or errors.Join when appropriate).

Apply this diff:

@@
- return nil, fmt.Errorf("%w: failed parsing AWS credential expiration: %w", errUtils.ErrInvalidAuthConfig, err)
+ return nil, fmt.Errorf("%w: failed parsing AWS credential expiration: %v", errUtils.ErrInvalidAuthConfig, err)
@@
- return nil, fmt.Errorf("%w: failed to validate AWS credentials: %w", errUtils.ErrAuthenticationFailed, err)
+ return nil, fmt.Errorf("%w: failed to validate AWS credentials: %v", errUtils.ErrAuthenticationFailed, err)

As per coding guidelines.

Also applies to: 79-80

website/docs/cli/commands/auth/usage.mdx (1)

49-57: Add terminal punctuation (doc lint).

End the “Key Configuration Details” lead‑in with a period to satisfy MD/godot styles.

-**Key Configuration Details:**
+**Key Configuration Details:**
+
+.
pkg/auth/manager.go (1)

1-1074: Fix double %w patterns in error wrapping—each fmt.Errorf call supports only one %w placeholder.

The scan confirmed 21 instances in pkg/auth/manager.go where fmt.Errorf incorrectly uses two %w placeholders (lines 140, 149, 170, 204, 214, 228, 292, 327, 340, 539, 611, 654, 854, 872, 887, 905, 998, 1005, 1016, 1042, 1069). This causes compile-time errors.

Use fmt.Errorf("context: %w", err) for wrapping a single error, or errors.Join(err1, err2) when combining multiple independent errors (per coding guidelines in CLAUDE.md).

🧹 Nitpick comments (36)
internal/exec/yaml_func_terraform_output_test.go (1)

3-14: Fix import grouping (stdlib | third‑party | Atmos).

Move testify into third‑party group and keep Atmos imports together. Keeps golangci-lint happy.

 import (
   "os"
   "path/filepath"
   "testing"
 
-  log "github.com/cloudposse/atmos/pkg/logger"
-  "github.com/stretchr/testify/assert"
-
-  cfg "github.com/cloudposse/atmos/pkg/config"
-  "github.com/cloudposse/atmos/pkg/schema"
-  u "github.com/cloudposse/atmos/pkg/utils"
+  "github.com/stretchr/testify/assert"
+
+  cfg "github.com/cloudposse/atmos/pkg/config"
+  log "github.com/cloudposse/atmos/pkg/logger"
+  "github.com/cloudposse/atmos/pkg/schema"
+  u "github.com/cloudposse/atmos/pkg/utils"
 )
internal/exec/template_funcs_component.go (1)

3-13: Tidy import groups.

Keep groups ordered and separated: stdlib, third‑party, then Atmos. Move logger with other Atmos imports.

 import (
   "fmt"
   "sync"
 
-  log "github.com/cloudposse/atmos/pkg/logger"
   "github.com/samber/lo"
 
   cfg "github.com/cloudposse/atmos/pkg/config"
+  log "github.com/cloudposse/atmos/pkg/logger"
   "github.com/cloudposse/atmos/pkg/schema"
   u "github.com/cloudposse/atmos/pkg/utils"
 )
internal/exec/terraform_output_getter.go (1)

42-43: Avoid test races when swapping the global getter.

Provide a setter that returns a restore func and guard the variable with a lock. This prevents flakiness in parallel tests.

 package exec
 
-// Global variable that can be overridden in tests.
-var outputGetter TerraformOutputGetter = &defaultOutputGetter{}
+// Global variable that can be overridden in tests.
+// Use SetTerraformOutputGetter to change it safely.
+var outputGetter TerraformOutputGetter = &defaultOutputGetter{}
+
+// Protects outputGetter in concurrent scenarios (e.g., parallel tests).
+var outputGetterMu sync.RWMutex
+
+// SetTerraformOutputGetter swaps the global getter and returns a restore function.
+func SetTerraformOutputGetter(g TerraformOutputGetter) func() {
+  outputGetterMu.Lock()
+  old := outputGetter
+  outputGetter = g
+  outputGetterMu.Unlock()
+  return func() {
+    outputGetterMu.Lock()
+    outputGetter = old
+    outputGetterMu.Unlock()
+  }
+}

And add the stdlib import:

-import (
-  "github.com/cloudposse/atmos/pkg/perf"
-  "github.com/cloudposse/atmos/pkg/schema"
-)
+import (
+  "sync"
+
+  "github.com/cloudposse/atmos/pkg/perf"
+  "github.com/cloudposse/atmos/pkg/schema"
+)
internal/exec/yaml_func_terraform_output_authcontext_test.go (3)

12-25: Fix godot: comment lines should end with periods.

Several comment lines end with “:” instead of “.”, which will trip the godot linter per guidelines. Please add trailing periods.


32-36: Prefer t.Cleanup for global restoration.

Use t.Cleanup to restore outputGetter; it ties cleanup to the test lifecycle and avoids surprises if subtests fail early.

- originalGetter := outputGetter
- outputGetter = mockOutputGetter
- defer func() { outputGetter = originalGetter }()
+ originalGetter := outputGetter
+ outputGetter = mockOutputGetter
+ t.Cleanup(func() { outputGetter = originalGetter })

Also applies to: 95-98, 176-179, 222-225


128-212: Add error-path coverage for GetOutput failures.

Current tests hit happy paths and exists=false. Please add a case where outputGetter returns an error and assert that ProcessCustomYamlTags propagates it.

+func TestAuthContextPropagatesGetOutputError(t *testing.T) {
+  ctrl := gomock.NewController(t)
+  defer ctrl.Finish()
+  mockOutputGetter := NewMockTerraformOutputGetter(ctrl)
+  original := outputGetter
+  outputGetter = mockOutputGetter
+  t.Cleanup(func() { outputGetter = original })
+
+  atmosConfig := &schema.AtmosConfiguration{BasePath: t.TempDir()}
+  stackInfo := &schema.ConfigAndStacksInfo{
+    AuthContext: &schema.AuthContext{AWS: &schema.AWSAuthContext{Profile: "p"}},
+    Stack:       "s",
+  }
+  mockErr := fmt.Errorf("boom")
+  mockOutputGetter.EXPECT().
+    GetOutput(atmosConfig, "s", "c", "o", false, gomock.Any()).
+    Return(nil, false, mockErr)
+
+  input := schema.AtmosSectionMapType{"value": "!terraform.output c s o"}
+  _, err := ProcessCustomYamlTags(atmosConfig, input, "s", nil, stackInfo)
+  assert.Error(t, err)
+  assert.Contains(t, err.Error(), "boom")
+}
internal/exec/terraform_output_utils.go (2)

380-381: Style: add blank line after perf.Track for public functions.

Matches the project pattern (see ProcessCustomYamlTags).

 func GetTerraformOutput(
@@
 ) (any, bool, error) {
-    defer perf.Track(atmosConfig, "exec.GetTerraformOutput")()
+    defer perf.Track(atmosConfig, "exec.GetTerraformOutput")()
+

358-372: Doc polish: end bullets with periods.

Godot linter requires sentence-ending periods; please add them to the parameter/returns bullets.

pkg/auth/cloud/aws/env.go (1)

147-189: Consider reducing debug logging verbosity.

The function includes extensive debug logging that logs file paths, environment variables, and file existence checks. While helpful during development, this level of logging in production code can be noisy. Consider:

  1. Removing or gating the "=== UPDATED CODE ===" marker (line 147)
  2. Consolidating the debug statements or moving them behind a higher verbosity level
website/blog/2025-10-24-macos-xdg-cli-conventions.md (3)

142-150: Clarify snippet: define homeDir for completeness.

Add a line to show how homeDir is obtained so readers can copy-paste.

 func init() {
     if runtime.GOOS == "darwin" {
+        homeDir, _ := os.UserHomeDir()
         xdg.ConfigHome = filepath.Join(homeDir, ".config")
         xdg.DataHome = filepath.Join(homeDir, ".local", "share")
         xdg.CacheHome = filepath.Join(homeDir, ".cache")
     }
 }

61-64: Tighten phrasing (“prior to” → “before”).

Small readability tweak.

-If you're upgrading from versions **prior to v1.195.0**, you're not affected because:
+If you're upgrading from versions **before v1.195.0**, you're not affected because:

158-159: Add terminal punctuation to list items.

One bullet lacks a trailing period; keep list consistent.

-- [Auth Usage Guide](/cli/commands/auth/usage) - Updated with correct macOS paths
+- [Auth Usage Guide](/cli/commands/auth/usage) - Updated with correct macOS paths.
pkg/auth/identities/aws/assume_role_test.go (2)

576-622: Harden existence check against ambient env.

Seed AWS_* credential env vars with sentinel values to ensure CredentialsExist is purely file-based.

 		t.Run(tt.name, func(t *testing.T) {
+			// Ensure ambient credential env vars don't influence existence checks.
+			t.Setenv("AWS_ACCESS_KEY_ID", "ENV_SHOULD_BE_IGNORED")
+			t.Setenv("AWS_SECRET_ACCESS_KEY", "ENV_SHOULD_BE_IGNORED")
+			t.Setenv("AWS_SESSION_TOKEN", "ENV_SHOULD_BE_IGNORED")

Optionally add a case where the profile section is missing in the credentials file to assert false.


624-698: Verify LoadCredentials ignores in-process AWS_ env.*

This PR introduces LoadAtmosManagedAWSConfig() which clears credential env vars. Assert we load from files even if AWS_* are set.

 			if tt.setupFiles {
 				t.Setenv("ATMOS_XDG_CONFIG_HOME", tmpDir)
+				// Set ambient env that must be ignored by the loader.
+				t.Setenv("AWS_ACCESS_KEY_ID", "ENV_VALUE_SHOULD_NOT_LEAK")
+				t.Setenv("AWS_SECRET_ACCESS_KEY", "ENV_VALUE_SHOULD_NOT_LEAK")
+				t.Setenv("AWS_SESSION_TOKEN", "ENV_VALUE_SHOULD_NOT_LEAK")

This makes the test validate the isolation behavior end-to-end.

pkg/auth/identities/aws/permission_set_test.go (2)

229-275: Make existence checks resilient to ambient AWS_ env.*

Mirror the isolation pattern to avoid false positives.

 		t.Run(tt.name, func(t *testing.T) {
+			// Guard against ambient env credentials affecting existence checks.
+			t.Setenv("AWS_ACCESS_KEY_ID", "ENV_SHOULD_BE_IGNORED")
+			t.Setenv("AWS_SECRET_ACCESS_KEY", "ENV_SHOULD_BE_IGNORED")
+			t.Setenv("AWS_SESSION_TOKEN", "ENV_SHOULD_BE_IGNORED")

277-352: Assert LoadCredentials ignores AWS_ env and prefers files.*

Strengthen the test to validate the new managed config loader’s isolation.

 			if tt.setupFiles {
 				t.Setenv("ATMOS_XDG_CONFIG_HOME", tmpDir)
+				// Seed ambient env to ensure loader ignores in-process credentials.
+				t.Setenv("AWS_ACCESS_KEY_ID", "ENV_VALUE_SHOULD_NOT_LEAK")
+				t.Setenv("AWS_SECRET_ACCESS_KEY", "ENV_VALUE_SHOULD_NOT_LEAK")
+				t.Setenv("AWS_SESSION_TOKEN", "ENV_VALUE_SHOULD_NOT_LEAK")
cmd/auth_env.go (2)

62-82: Normalize envVars to avoid JSON null and keep outputs predictable.

If GetEnvironmentVariables returns nil, json mode prints null. Guard once before the switch.

-		} else {
+		} else {
 			// Get environment variables WITHOUT authentication/validation
 			// This allows users to see what environment variables would be set
 			// even if they don't have valid credentials yet
 			envVars, err = authManager.GetEnvironmentVariables(identityName)
 			if err != nil {
 				return fmt.Errorf("failed to get environment variables: %w", err)
 			}
 		}
 
+		// Ensure stable empty output shape across formats.
+		if envVars == nil {
+			envVars = map[string]string{}
+		}

35-37: Bind --login to Viper and env for consistency.

Follow CLI guidelines so users can control via ATMOS_AUTH_ENV_LOGIN.

 authEnvCmd.Flags().Bool("login", false, "Trigger authentication if credentials are missing or expired (default: false)")
 
+// Bind login flag and env (flags > env).
+if err := viper.BindPFlag("auth_env_login", authEnvCmd.Flags().Lookup("login")); err != nil {
+	log.Trace("Failed to bind auth_env_login flag", "error", err)
+}
+viper.MustBindEnv("auth_env_login", "ATMOS_AUTH_ENV_LOGIN")

Optionally, read it via viper in RunE to allow env-driven defaults:

-		login, _ := cmd.Flags().GetBool("login")
+		login := viper.GetBool("auth_env_login")

As per coding guidelines.

Also applies to: 136-139

pkg/auth/cloud/aws/files_test.go (3)

378-417: Avoid homedir cache pitfalls; set HOME before resolving.

Prevent stale home detection when checking legacy paths.

-	// Override home directory for this test.
-	originalDir, _ := homedir.Dir()
-	defer func() {
-		// Restore original home directory (not possible with homedir package, but test isolation ensures cleanup).
-		_ = originalDir
-	}()
-	t.Setenv("HOME", tempHome)
+	// Override home directory for this test and disable homedir cache.
+	t.Setenv("HOME", tempHome)
+	homedir.DisableCache = true
+	defer func() { homedir.DisableCache = false }()

This ensures any homedir lookups inside NewAWSFileManager see the test HOME.


458-461: Make absolute path test cross‑platform.

Avoid hardcoded “/tmp”.

-			basePath:         "/tmp/custom-aws-creds",
-			expectedBasePath: "/tmp/custom-aws-creds",
+			basePath:         filepath.Join(os.TempDir(), "custom-aws-creds"),
+			expectedBasePath: filepath.Join(os.TempDir(), "custom-aws-creds"),

552-576: Don’t rely on env var ordering; assert by key.

GetEnvironmentVariables order isn’t guaranteed. Map by key before asserting.

-	envVars := fm.GetEnvironmentVariables(providerName, identityName)
-
-	// Verify environment variables point to custom base path.
-	expectedCredsPath := filepath.Join(customBasePath, providerName, "credentials")
-	expectedConfigPath := filepath.Join(customBasePath, providerName, "config")
-
-	assert.Equal(t, expectedCredsPath, envVars[0].Value, "AWS_SHARED_CREDENTIALS_FILE should use custom base_path")
-	assert.Equal(t, expectedConfigPath, envVars[1].Value, "AWS_CONFIG_FILE should use custom base_path")
-	assert.Equal(t, identityName, envVars[2].Value, "AWS_PROFILE should be identity name")
+	envVars := fm.GetEnvironmentVariables(providerName, identityName)
+	env := map[string]string{}
+	for _, kv := range envVars {
+		env[kv.Key] = kv.Value
+	}
+
+	// Verify environment variables point to custom base path.
+	expectedCredsPath := filepath.Join(customBasePath, providerName, "credentials")
+	expectedConfigPath := filepath.Join(customBasePath, providerName, "config")
+
+	assert.Equal(t, expectedCredsPath, env["AWS_SHARED_CREDENTIALS_FILE"])
+	assert.Equal(t, expectedConfigPath, env["AWS_CONFIG_FILE"])
+	assert.Equal(t, identityName, env["AWS_PROFILE"])
pkg/auth/providers/mock/identity.go (1)

106-119: Optional: make mock expiration deterministic to avoid flakiness.

Returning time.Now().Add(1h) can cause snapshot/test drift. Consider a fixed timestamp like in Authenticate for stability.

pkg/auth/cloud/aws/files.go (4)

27-39: Centralize error sentinels and preserve causes.

These package-local errors diverge from “static errors from errors/errors.go”. Recommend moving/using shared sentinels (e.g., ErrAwsFilesCreateCredentials, etc.) and wrap causes: fmt.Errorf("%w: %v", Err..., err) or errors.Join where independent. Current pattern returns only the sentinel after printing, losing the original error for callers/tests.


169-178: Preserve original error on write failures.

Return a wrapped error so callers can inspect root cause instead of just the sentinel. Same for SetConfigFilePermissions below.

- if err := cfg.SaveTo(credentialsPath); err != nil {
-   errUtils.CheckErrorAndPrint(ErrWriteCredentialsFile, identityName, "failed to write credentials file")
-   return ErrWriteCredentialsFile
- }
+ if err := cfg.SaveTo(credentialsPath); err != nil {
+   errUtils.CheckErrorAndPrint(ErrWriteCredentialsFile, identityName, "failed to write credentials file")
+   return fmt.Errorf("%w: %v", ErrWriteCredentialsFile, err)
+ }

268-275: Path display: prefer filepath.Rel for cross‑platform correctness.

strings.HasPrefix can mis-detect on case-insensitive filesystems or similar prefixes. Use filepath.Rel to decide if baseDir is under home, then join "~".

- func (m *AWSFileManager) GetDisplayPath() string {
-   homeDir, err := homedir.Dir()
-   if err == nil && homeDir != "" && strings.HasPrefix(m.baseDir, homeDir) {
-     return strings.Replace(m.baseDir, homeDir, "~", 1)
-   }
-   return m.baseDir
- }
+ func (m *AWSFileManager) GetDisplayPath() string {
+   homeDir, err := homedir.Dir()
+   if err == nil && homeDir != "" {
+     if rel, rerr := filepath.Rel(homeDir, m.baseDir); rerr == nil && !strings.HasPrefix(rel, "..") {
+       return filepath.Join("~", rel)
+     }
+   }
+   return m.baseDir
+ }

46-56: Doc comments: end sentences with periods (godot).

A few lines in the NewAWSFileManager doc block end without periods (e.g., headings/ bullets). Tweak to satisfy the linter.

Also applies to: 67-78, 85-109

pkg/auth/types/aws_credentials.go (1)

64-71: Guard missing region for STS (optional).

If c.Region is empty, STS will error. Either validate and return a clear error or default to a safe region.

Example:

 cfg := aws.Config{
-  Region: c.Region,
+  Region: c.Region,
   Credentials: credentials.NewStaticCredentialsProvider(
@@
 }
+if cfg.Region == "" {
+  return nil, fmt.Errorf("%w: missing AWS region for credential validation", errUtils.ErrInvalidAuthConfig)
+}

Based on coding guidelines.

Also applies to: 74-80

cmd/auth_whoami.go (1)

51-59: Use cmd.Context() instead of context.Background().

Propagate CLI cancellations/timeouts.

- ctx := context.Background()
+ ctx := cmd.Context()

As per coding guidelines.

Also applies to: 64-66

pkg/auth/manager.go (2)

206-210: Pass context into buildWhoamiInfoFromEnvironment.

Avoid context.Background(); thread the caller’s ctx for consistency.

- return m.buildWhoamiInfoFromEnvironment(identityName), nil
+ return m.buildWhoamiInfoFromEnvironment(ctx, identityName), nil
@@
-func (m *manager) buildWhoamiInfoFromEnvironment(identityName string) *types.WhoamiInfo {
+func (m *manager) buildWhoamiInfoFromEnvironment(ctx context.Context, identityName string) *types.WhoamiInfo {
@@
- ctx := context.Background()
- creds, err := identity.LoadCredentials(ctx)
+ creds, err := identity.LoadCredentials(ctx)

Based on learnings.

Also applies to: 776-825


395-404: Modernize default files display path.

Legacy fallback points to ~/.aws/atmos. Suggest XDG‑compliant default to match docs.

- return "~/.aws/atmos"
+ return "~/.config/atmos"

As per coding guidelines.

pkg/auth/identities/aws/credentials_loader.go (1)

20-67: Avoid process-wide env mutation; load with SDK options.

Temporarily setting AWS_* env vars is global and racy. Use aws-sdk-go-v2 LoadOptions to target files/profile and avoid IMDS.

-func loadAWSCredentialsFromEnvironment(ctx context.Context, env map[string]string) (*types.AWSCredentials, error) {
+func loadAWSCredentialsFromEnvironment(ctx context.Context, env map[string]string) (*types.AWSCredentials, error) {
   credsFile, hasCredsFile := env["AWS_SHARED_CREDENTIALS_FILE"]
   configFile, hasConfigFile := env["AWS_CONFIG_FILE"]
   profile, hasProfile := env["AWS_PROFILE"]
   region := env["AWS_REGION"] // Optional.
   if !hasCredsFile || !hasConfigFile || !hasProfile {
-    return nil, fmt.Errorf("missing required AWS environment variables (AWS_SHARED_CREDENTIALS_FILE, AWS_CONFIG_FILE, AWS_PROFILE)")
+    return nil, fmt.Errorf("%w: missing required AWS environment variables (AWS_SHARED_CREDENTIALS_FILE, AWS_CONFIG_FILE, AWS_PROFILE)", errUtils.ErrInvalidAuthConfig)
   }
-  // Temporarily set environment variables...
-  // (removed)
-  // Load AWS config using SDK (which will read from the files via env vars).
-  cfg, err := awsConfig.LoadDefaultConfig(ctx)
+  // Load AWS config explicitly from provided files/profile; avoids touching process env and IMDS.
+  cfg, err := awsConfig.LoadDefaultConfig(
+    ctx,
+    awsConfig.WithSharedConfigProfile(profile),
+    awsConfig.WithSharedCredentialsFiles([]string{credsFile}),
+    awsConfig.WithSharedConfigFiles([]string{configFile}),
+  )
   if err != nil {
-    return nil, fmt.Errorf("failed to load AWS config from files: %w", err)
+    return nil, fmt.Errorf("%w: failed to load AWS config from files: %v", errUtils.ErrInvalidAuthConfig, err)
   }
   awsCreds, err := cfg.Credentials.Retrieve(ctx)
   if err != nil {
-    return nil, fmt.Errorf("failed to retrieve AWS credentials from files: %w", err)
+    return nil, fmt.Errorf("%w: failed to retrieve AWS credentials from files: %v", errUtils.ErrAuthenticationFailed, err)
   }

As per coding guidelines.

Also applies to: 68-76, 88-101, 116-156

pkg/auth/types/interfaces.go (1)

79-89: Clarify LoadCredentials not-supported contract.

Returning (nil, nil) when unsupported can be ambiguous at call sites. Consider mirroring Validate’s pattern by returning a sentinel (e.g., ErrNotImplemented) to keep behavior consistent and easier to check with errors.Is.

pkg/auth/manager_test.go (4)

232-236: Populate ValidationInfo for stronger assertions.

Set Principal/Account to non-empty values so downstream paths are exercised.

-func (c *testCreds) Validate(ctx context.Context) (*types.ValidationInfo, error) {
-	return &types.ValidationInfo{Expiration: c.exp}, nil
-}
+func (c *testCreds) Validate(ctx context.Context) (*types.ValidationInfo, error) {
+	return &types.ValidationInfo{
+		Principal:  "arn:aws:iam::123456789012:user/test",
+		Account:    "123456789012",
+		Expiration: c.exp,
+	}, nil
+}

482-485: Add a negative-path whoami test.

CredentialsExist always true; consider a case where it’s false (or LoadCredentials returns creds) to cover the fallback branches.


556-561: Mirror negative-path coverage for permission-set stub.

Same as above: one test where CredentialsExist=false or LoadCredentials returns non-nil to assert manager fallback.


804-807: Unify stub defaults.

To reduce repetition across stubs, consider a small embedded base struct providing default Logout/CredentialsExist/LoadCredentials. Optional.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1c1e414 and 130e7e2.

📒 Files selected for processing (50)
  • README.md (1 hunks)
  • cmd/auth_console_test.go (2 hunks)
  • cmd/auth_env.go (3 hunks)
  • cmd/auth_whoami.go (3 hunks)
  • docs/prd/xdg-base-directory-specification.md (5 hunks)
  • internal/aws_utils/aws_utils.go (2 hunks)
  • internal/exec/mock_terraform_output_getter.go (1 hunks)
  • internal/exec/template_funcs_component.go (1 hunks)
  • internal/exec/terraform_output_getter.go (1 hunks)
  • internal/exec/terraform_output_utils.go (5 hunks)
  • internal/exec/yaml_func_terraform_output.go (3 hunks)
  • internal/exec/yaml_func_terraform_output_authcontext_test.go (1 hunks)
  • internal/exec/yaml_func_terraform_output_test.go (2 hunks)
  • internal/exec/yaml_func_utils.go (1 hunks)
  • pkg/auth/cloud/aws/env.go (3 hunks)
  • pkg/auth/cloud/aws/files.go (6 hunks)
  • pkg/auth/cloud/aws/files_test.go (1 hunks)
  • pkg/auth/cloud/aws/setup_test.go (7 hunks)
  • pkg/auth/credentials/keyring_file_test.go (1 hunks)
  • pkg/auth/credentials/keyring_noop.go (2 hunks)
  • pkg/auth/credentials/store_test.go (2 hunks)
  • pkg/auth/hooks_test.go (1 hunks)
  • pkg/auth/identities/aws/assume_role.go (2 hunks)
  • pkg/auth/identities/aws/assume_role_test.go (2 hunks)
  • pkg/auth/identities/aws/credentials_loader.go (1 hunks)
  • pkg/auth/identities/aws/credentials_loader_test.go (1 hunks)
  • pkg/auth/identities/aws/permission_set.go (2 hunks)
  • pkg/auth/identities/aws/permission_set_test.go (3 hunks)
  • pkg/auth/identities/aws/user.go (4 hunks)
  • pkg/auth/identities/aws/user_test.go (6 hunks)
  • pkg/auth/manager.go (5 hunks)
  • pkg/auth/manager_test.go (4 hunks)
  • pkg/auth/providers/aws/saml_test.go (2 hunks)
  • pkg/auth/providers/aws/sso_test.go (1 hunks)
  • pkg/auth/providers/mock/credentials.go (1 hunks)
  • pkg/auth/providers/mock/identity.go (1 hunks)
  • pkg/auth/providers/mock/identity_test.go (1 hunks)
  • pkg/auth/types/aws_credentials.go (2 hunks)
  • pkg/auth/types/github_oidc_credentials.go (1 hunks)
  • pkg/auth/types/interfaces.go (3 hunks)
  • pkg/auth/types/mock_interfaces.go (5 hunks)
  • pkg/xdg/xdg.go (1 hunks)
  • pkg/xdg/xdg_test.go (2 hunks)
  • scripts/test-geodesic-prebuilt.sh (1 hunks)
  • website/blog/2025-10-21-auth-context-implementation.md (2 hunks)
  • website/blog/2025-10-24-macos-xdg-cli-conventions.md (1 hunks)
  • website/docs/cli/commands/auth/auth-shell.mdx (1 hunks)
  • website/docs/cli/commands/auth/logout.mdx (9 hunks)
  • website/docs/cli/commands/auth/tutorials/configuring-geodesic.mdx (6 hunks)
  • website/docs/cli/commands/auth/usage.mdx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
pkg/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Place business logic in pkg rather than in cmd

Files:

  • pkg/auth/identities/aws/permission_set.go
  • pkg/auth/credentials/keyring_noop.go
  • pkg/xdg/xdg.go
  • pkg/auth/providers/mock/identity_test.go
  • pkg/auth/identities/aws/assume_role_test.go
  • pkg/auth/providers/aws/sso_test.go
  • pkg/auth/providers/mock/credentials.go
  • pkg/xdg/xdg_test.go
  • pkg/auth/identities/aws/user_test.go
  • pkg/auth/identities/aws/credentials_loader_test.go
  • pkg/auth/cloud/aws/env.go
  • pkg/auth/credentials/store_test.go
  • pkg/auth/providers/mock/identity.go
  • pkg/auth/identities/aws/permission_set_test.go
  • pkg/auth/types/github_oidc_credentials.go
  • pkg/auth/manager.go
  • pkg/auth/cloud/aws/files.go
  • pkg/auth/providers/aws/saml_test.go
  • pkg/auth/identities/aws/credentials_loader.go
  • pkg/auth/cloud/aws/setup_test.go
  • pkg/auth/identities/aws/user.go
  • pkg/auth/types/aws_credentials.go
  • pkg/auth/hooks_test.go
  • pkg/auth/credentials/keyring_file_test.go
  • pkg/auth/identities/aws/assume_role.go
  • pkg/auth/cloud/aws/files_test.go
  • pkg/auth/types/mock_interfaces.go
  • pkg/auth/types/interfaces.go
  • pkg/auth/manager_test.go
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • pkg/auth/identities/aws/permission_set.go
  • pkg/auth/credentials/keyring_noop.go
  • pkg/xdg/xdg.go
  • internal/exec/yaml_func_terraform_output_test.go
  • pkg/auth/providers/mock/identity_test.go
  • pkg/auth/identities/aws/assume_role_test.go
  • pkg/auth/providers/aws/sso_test.go
  • pkg/auth/providers/mock/credentials.go
  • pkg/xdg/xdg_test.go
  • pkg/auth/identities/aws/user_test.go
  • internal/exec/terraform_output_utils.go
  • internal/aws_utils/aws_utils.go
  • pkg/auth/identities/aws/credentials_loader_test.go
  • internal/exec/yaml_func_utils.go
  • pkg/auth/cloud/aws/env.go
  • pkg/auth/credentials/store_test.go
  • cmd/auth_console_test.go
  • cmd/auth_whoami.go
  • pkg/auth/providers/mock/identity.go
  • pkg/auth/identities/aws/permission_set_test.go
  • pkg/auth/types/github_oidc_credentials.go
  • internal/exec/mock_terraform_output_getter.go
  • internal/exec/template_funcs_component.go
  • pkg/auth/manager.go
  • pkg/auth/cloud/aws/files.go
  • internal/exec/yaml_func_terraform_output_authcontext_test.go
  • pkg/auth/providers/aws/saml_test.go
  • pkg/auth/identities/aws/credentials_loader.go
  • pkg/auth/cloud/aws/setup_test.go
  • pkg/auth/identities/aws/user.go
  • pkg/auth/types/aws_credentials.go
  • cmd/auth_env.go
  • pkg/auth/hooks_test.go
  • internal/exec/terraform_output_getter.go
  • pkg/auth/credentials/keyring_file_test.go
  • pkg/auth/identities/aws/assume_role.go
  • internal/exec/yaml_func_terraform_output.go
  • pkg/auth/cloud/aws/files_test.go
  • pkg/auth/types/mock_interfaces.go
  • pkg/auth/types/interfaces.go
  • pkg/auth/manager_test.go
**/!(*_test).go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Document all exported functions, types, and methods with Go doc comments

Files:

  • pkg/auth/identities/aws/permission_set.go
  • pkg/auth/credentials/keyring_noop.go
  • pkg/xdg/xdg.go
  • pkg/auth/providers/mock/credentials.go
  • internal/exec/terraform_output_utils.go
  • internal/aws_utils/aws_utils.go
  • internal/exec/yaml_func_utils.go
  • pkg/auth/cloud/aws/env.go
  • cmd/auth_whoami.go
  • pkg/auth/providers/mock/identity.go
  • pkg/auth/types/github_oidc_credentials.go
  • internal/exec/mock_terraform_output_getter.go
  • internal/exec/template_funcs_component.go
  • pkg/auth/manager.go
  • pkg/auth/cloud/aws/files.go
  • pkg/auth/identities/aws/credentials_loader.go
  • pkg/auth/identities/aws/user.go
  • pkg/auth/types/aws_credentials.go
  • cmd/auth_env.go
  • internal/exec/terraform_output_getter.go
  • pkg/auth/identities/aws/assume_role.go
  • internal/exec/yaml_func_terraform_output.go
  • pkg/auth/types/mock_interfaces.go
  • pkg/auth/types/interfaces.go
website/**

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

website/**: Update website documentation in website/ when adding features
Ensure consistency between CLI help text and website documentation
Follow the website's documentation structure and style
Keep website code in website/ and follow its architecture/style; test changes locally
Keep CLI and website documentation in sync; document new features with examples and use cases

Files:

  • website/docs/cli/commands/auth/auth-shell.mdx
  • website/docs/cli/commands/auth/logout.mdx
  • website/docs/cli/commands/auth/usage.mdx
  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
  • website/blog/2025-10-21-auth-context-implementation.md
  • website/docs/cli/commands/auth/tutorials/configuring-geodesic.mdx
**/*_test.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + DI; table-driven tests for coverage; target >80% coverage.
Tests must exercise production code paths; avoid duplicating implementation logic in tests.
Use t.Skipf("reason") with clear context when skipping tests; CLI tests may auto-build temp binaries.

Files:

  • internal/exec/yaml_func_terraform_output_test.go
  • pkg/auth/providers/mock/identity_test.go
  • pkg/auth/identities/aws/assume_role_test.go
  • pkg/auth/providers/aws/sso_test.go
  • pkg/xdg/xdg_test.go
  • pkg/auth/identities/aws/user_test.go
  • pkg/auth/identities/aws/credentials_loader_test.go
  • pkg/auth/credentials/store_test.go
  • cmd/auth_console_test.go
  • pkg/auth/identities/aws/permission_set_test.go
  • internal/exec/yaml_func_terraform_output_authcontext_test.go
  • pkg/auth/providers/aws/saml_test.go
  • pkg/auth/cloud/aws/setup_test.go
  • pkg/auth/hooks_test.go
  • pkg/auth/credentials/keyring_file_test.go
  • pkg/auth/cloud/aws/files_test.go
  • pkg/auth/manager_test.go
cmd/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate

cmd/**/*.go: New CLI commands must use the command registry pattern via CommandProvider and register through the command registry (see cmd/internal/registry.go).
Commands should embed *_usage.md via //go:embed and render with utils.PrintfMarkdown().
UI (prompts/status) must write to stderr; data outputs to stdout; logging only for system events (never for UI).
For non-standard execution paths, capture telemetry with telemetry.CaptureCmd(); normal paths are auto-enabled via RootCmd.ExecuteC(). Never capture user data.

Files:

  • cmd/auth_console_test.go
  • cmd/auth_whoami.go
  • cmd/auth_env.go
cmd/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use cmd.NewTestKit(t) for any tests that touch RootCmd to auto-clean RootCmd state.

Files:

  • cmd/auth_console_test.go
{cmd,pkg/ui}/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use theme colors from pkg/ui/theme/colors.go for UI elements.

Files:

  • cmd/auth_console_test.go
  • cmd/auth_whoami.go
  • cmd/auth_env.go
README.md

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Update README.md when adding new commands and features

Files:

  • README.md
website/blog/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-*.md

📄 CodeRabbit inference engine (CLAUDE.md)

PRs labeled minor or major must include a blog post with filename date prefix and feature name; include and proper tags.

Files:

  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
  • website/blog/2025-10-21-auth-context-implementation.md
docs/prd/[a-z0-9-]*.md

📄 CodeRabbit inference engine (CLAUDE.md)

All PRDs must be placed under docs/prd/ with kebab-case filenames.

Files:

  • docs/prd/xdg-base-directory-specification.md
🧠 Learnings (17)
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: XDG Base Directory Specification compliance implementation for atmos toolchain is complete: created toolchain/xdg_cache.go with GetXDGCacheDir() and GetXDGTempCacheDir() functions, updated toolchain/installer.go and cmd/toolchain_clean.go to use these XDG helpers, and changed all cache paths from hardcoded ~/.cache/tools-cache to XDG-compliant ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback).

Applied to files:

  • pkg/xdg/xdg.go
  • pkg/xdg/xdg_test.go
  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
  • docs/prd/xdg-base-directory-specification.md
  • website/blog/2025-10-21-auth-context-implementation.md
  • pkg/auth/cloud/aws/setup_test.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain XDG compliance implementation is complete with GetXDGCacheDir() and GetXDGTempCacheDir() functions in toolchain/xdg_cache.go, updated installer.go and toolchain_clean.go to use these helpers, and changed cache paths from ~/.cache/tools-cache to ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain when XDG_CACHE_HOME is not set).

Applied to files:

  • pkg/xdg/xdg.go
  • pkg/xdg/xdg_test.go
  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
  • docs/prd/xdg-base-directory-specification.md
  • website/blog/2025-10-21-auth-context-implementation.md
  • pkg/auth/cloud/aws/setup_test.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.

Applied to files:

  • pkg/xdg/xdg.go
  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
  • docs/prd/xdg-base-directory-specification.md
  • website/blog/2025-10-21-auth-context-implementation.md
  • pkg/auth/cloud/aws/setup_test.go
  • website/docs/cli/commands/auth/tutorials/configuring-geodesic.mdx
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: Final XDG Base Directory Specification implementation for atmos toolchain is complete and verified: toolchain/xdg_cache.go provides GetXDGCacheDir() and GetXDGTempCacheDir() functions, all hardcoded ~/.cache/tools-cache paths have been replaced with XDG-compliant paths using ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback), and tests have been updated to expect the new path structure.

Applied to files:

  • pkg/xdg/xdg.go
  • pkg/xdg/xdg_test.go
  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
  • docs/prd/xdg-base-directory-specification.md
  • website/blog/2025-10-21-auth-context-implementation.md
  • pkg/auth/cloud/aws/setup_test.go
📚 Learning: 2024-12-13T15:33:34.159Z
Learnt from: Listener430
PR: cloudposse/atmos#844
File: pkg/config/cache.go:17-31
Timestamp: 2024-12-13T15:33:34.159Z
Learning: In `pkg/config/cache.go`, when `XDG_CACHE_HOME` is not set, falling back to `.` (current directory) is acceptable and aligns with the requirement to primarily use `XDG_CACHE_HOME` for the cache directory.

Applied to files:

  • pkg/xdg/xdg.go
  • docs/prd/xdg-base-directory-specification.md
📚 Learning: 2025-09-10T17:34:52.568Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: pkg/auth/providers/github/oidc.go:96-100
Timestamp: 2025-09-10T17:34:52.568Z
Learning: The ATMOS_ environment variable binding guideline applies to Atmos configuration variables, not external service-required environment variables like GitHub Actions OIDC variables (GITHUB_ACTIONS, ACTIONS_ID_TOKEN_*) which must use their standard names.

Applied to files:

  • website/docs/cli/commands/auth/auth-shell.mdx
📚 Learning: 2024-12-17T07:08:41.288Z
Learnt from: aknysh
PR: cloudposse/atmos#863
File: internal/exec/yaml_func_terraform_output.go:34-38
Timestamp: 2024-12-17T07:08:41.288Z
Learning: In the `processTagTerraformOutput` function within `internal/exec/yaml_func_terraform_output.go`, parameters are separated by spaces and do not contain spaces. Therefore, using `strings.Fields()` for parsing is acceptable, and there's no need to handle parameters with spaces.

Applied to files:

  • internal/exec/yaml_func_terraform_output_test.go
  • internal/exec/yaml_func_utils.go
📚 Learning: 2024-11-30T22:07:08.610Z
Learnt from: aknysh
PR: cloudposse/atmos#810
File: internal/exec/yaml_func_terraform_output.go:35-40
Timestamp: 2024-11-30T22:07:08.610Z
Learning: In the Go function `processTagTerraformOutput` in `internal/exec/yaml_func_terraform_output.go`, parameters cannot contain spaces. The code splits the input by spaces, and if the parameters contain spaces, `len(parts) != 3` will fail and show an error to the user.

Applied to files:

  • internal/exec/yaml_func_terraform_output_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
PR: cloudposse/atmos#1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: The atmos codebase has a custom extension to *testing.T that provides a Chdir method, allowing test functions to call t.Chdir() to change working directories during tests. This is used consistently across test files in the codebase.

Applied to files:

  • pkg/xdg/xdg_test.go
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
PR: cloudposse/atmos#1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.

Applied to files:

  • website/docs/cli/commands/auth/usage.mdx
📚 Learning: 2025-10-24T14:51:19.340Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.340Z
Learning: Applies to **/*.go : Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.

Applied to files:

  • pkg/auth/cloud/aws/env.go
📚 Learning: 2025-09-09T02:14:36.708Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1452
File: internal/auth/types/whoami.go:14-15
Timestamp: 2025-09-09T02:14:36.708Z
Learning: The WhoamiInfo struct in internal/auth/types/whoami.go requires the Credentials field to be JSON-serializable for keystore unmarshaling operations, despite security concerns about credential exposure.

Applied to files:

  • cmd/auth_whoami.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain should follow XDG Base Directory Specification like the rest of atmos core, using XDG_CACHE_HOME environment variable when available and falling back to ~/.cache when not set, instead of hardcoding ~/.cache/tools-cache paths.

Applied to files:

  • docs/prd/xdg-base-directory-specification.md
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
PR: cloudposse/atmos#844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.

Applied to files:

  • docs/prd/xdg-base-directory-specification.md
📚 Learning: 2024-11-12T03:16:02.910Z
Learnt from: aknysh
PR: cloudposse/atmos#775
File: internal/exec/template_funcs_component.go:157-159
Timestamp: 2024-11-12T03:16:02.910Z
Learning: In the Go code for `componentFunc` in `internal/exec/template_funcs_component.go`, the function `cleanTerraformWorkspace` does not return errors, and it's acceptable if the file does not exist. Therefore, error handling for `cleanTerraformWorkspace` is not needed.

Applied to files:

  • internal/exec/template_funcs_component.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
PR: cloudposse/atmos#1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.

Applied to files:

  • pkg/auth/manager.go
📚 Learning: 2025-08-15T14:43:41.030Z
Learnt from: aknysh
PR: cloudposse/atmos#1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.

Applied to files:

  • pkg/auth/cloud/aws/setup_test.go
🧬 Code graph analysis (30)
pkg/auth/identities/aws/permission_set.go (3)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/auth/cloud/aws/files.go (1)
  • NewAWSFileManager (56-83)
pkg/auth/types/interfaces.go (1)
  • ICredentials (187-198)
pkg/auth/credentials/keyring_noop.go (3)
pkg/auth/types/interfaces.go (1)
  • ICredentials (187-198)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/logger/log.go (1)
  • Debug (24-26)
pkg/auth/providers/mock/identity_test.go (4)
pkg/auth/providers/mock/identity.go (2)
  • Identity (14-17)
  • NewIdentity (20-27)
pkg/auth/types/interfaces.go (1)
  • Identity (54-89)
pkg/schema/schema_auth.go (1)
  • Identity (45-53)
pkg/auth/providers/mock/credentials.go (1)
  • Credentials (11-17)
pkg/auth/identities/aws/assume_role_test.go (4)
pkg/auth/identities/aws/assume_role.go (1)
  • NewAssumeRoleIdentity (111-126)
pkg/auth/types/interfaces.go (2)
  • Identity (54-89)
  • Provider (13-42)
pkg/schema/schema_auth.go (3)
  • Identity (45-53)
  • IdentityVia (56-59)
  • Provider (18-32)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
pkg/auth/providers/mock/credentials.go (1)
pkg/auth/types/interfaces.go (1)
  • ValidationInfo (201-216)
pkg/xdg/xdg_test.go (1)
pkg/xdg/xdg.go (1)
  • GetXDGConfigDir (46-48)
pkg/auth/identities/aws/user_test.go (3)
pkg/auth/types/interfaces.go (2)
  • ICredentials (187-198)
  • Identity (54-89)
pkg/auth/identities/aws/user.go (1)
  • NewUserIdentity (39-51)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
internal/exec/terraform_output_utils.go (3)
pkg/schema/schema.go (1)
  • AuthContext (498-506)
pkg/logger/log.go (1)
  • Debug (24-26)
pkg/config/const.go (1)
  • EnvSectionName (61-61)
internal/aws_utils/aws_utils.go (2)
pkg/logger/log.go (1)
  • Debug (24-26)
errors/errors.go (1)
  • ErrLoadAwsConfig (74-74)
pkg/auth/cloud/aws/env.go (2)
pkg/logger/log.go (2)
  • Debug (24-26)
  • Errorf (59-61)
errors/errors.go (1)
  • ErrLoadAwsConfig (74-74)
pkg/auth/credentials/store_test.go (1)
pkg/auth/types/interfaces.go (1)
  • ValidationInfo (201-216)
cmd/auth_whoami.go (5)
errors/error_funcs.go (1)
  • CheckErrorPrintAndExit (58-81)
pkg/auth/types/whoami.go (1)
  • WhoamiInfo (6-22)
pkg/auth/providers/mock/credentials.go (1)
  • Credentials (11-17)
pkg/logger/log.go (1)
  • Debug (24-26)
pkg/auth/types/interfaces.go (2)
  • Identity (54-89)
  • ValidationInfo (201-216)
pkg/auth/providers/mock/identity.go (3)
pkg/auth/types/interfaces.go (2)
  • Identity (54-89)
  • ICredentials (187-198)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/auth/providers/mock/credentials.go (1)
  • Credentials (11-17)
pkg/auth/identities/aws/permission_set_test.go (4)
pkg/auth/identities/aws/permission_set.go (1)
  • NewPermissionSetIdentity (36-45)
pkg/auth/types/interfaces.go (2)
  • Identity (54-89)
  • Provider (13-42)
pkg/schema/schema_auth.go (3)
  • Identity (45-53)
  • IdentityVia (56-59)
  • Provider (18-32)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
pkg/auth/types/github_oidc_credentials.go (1)
pkg/auth/types/interfaces.go (1)
  • ValidationInfo (201-216)
internal/exec/mock_terraform_output_getter.go (1)
pkg/schema/schema.go (2)
  • AtmosConfiguration (27-65)
  • AuthContext (498-506)
pkg/auth/manager.go (6)
pkg/logger/log.go (1)
  • Debug (24-26)
pkg/auth/credentials/keyring_file.go (1)
  • ErrCredentialsNotFound (36-36)
errors/errors.go (3)
  • ErrNoCredentialsFound (386-386)
  • ErrIdentityNotFound (393-393)
  • ErrInvalidAuthConfig (370-370)
pkg/auth/types/whoami.go (1)
  • WhoamiInfo (6-22)
pkg/auth/types/interfaces.go (2)
  • Provider (13-42)
  • Identity (54-89)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/auth/cloud/aws/files.go (4)
pkg/xdg/xdg.go (1)
  • GetXDGConfigDir (46-48)
pkg/logger/log.go (3)
  • Errorf (59-61)
  • Warn (44-46)
  • Debug (24-26)
pkg/config/homedir/homedir.go (1)
  • Dir (36-63)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
internal/exec/yaml_func_terraform_output_authcontext_test.go (3)
internal/exec/mock_terraform_output_getter.go (1)
  • NewMockTerraformOutputGetter (32-36)
pkg/schema/schema.go (5)
  • AuthContext (498-506)
  • AWSAuthContext (510-525)
  • ConfigAndStacksInfo (527-610)
  • AtmosConfiguration (27-65)
  • AtmosSectionMapType (14-14)
internal/exec/yaml_func_utils.go (1)
  • ProcessCustomYamlTags (13-30)
pkg/auth/identities/aws/credentials_loader.go (2)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
pkg/logger/log.go (2)
  • Errorf (59-61)
  • Debug (24-26)
pkg/auth/cloud/aws/setup_test.go (3)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
pkg/auth/cloud/aws/setup.go (1)
  • SetupFiles (17-45)
pkg/schema/schema.go (2)
  • AuthContext (498-506)
  • AWSAuthContext (510-525)
pkg/auth/identities/aws/user.go (3)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/auth/cloud/aws/files.go (1)
  • NewAWSFileManager (56-83)
pkg/auth/types/interfaces.go (1)
  • ICredentials (187-198)
pkg/auth/types/aws_credentials.go (2)
pkg/auth/types/interfaces.go (1)
  • ValidationInfo (201-216)
errors/errors.go (1)
  • ErrAuthenticationFailed (375-375)
internal/exec/terraform_output_getter.go (3)
pkg/schema/schema.go (2)
  • AtmosConfiguration (27-65)
  • AuthContext (498-506)
pkg/perf/perf.go (1)
  • Track (121-138)
internal/exec/terraform_output_utils.go (1)
  • GetTerraformOutput (372-448)
pkg/auth/credentials/keyring_file_test.go (1)
pkg/auth/types/interfaces.go (1)
  • ValidationInfo (201-216)
pkg/auth/identities/aws/assume_role.go (3)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/auth/cloud/aws/files.go (1)
  • NewAWSFileManager (56-83)
pkg/auth/types/interfaces.go (1)
  • ICredentials (187-198)
internal/exec/yaml_func_terraform_output.go (1)
pkg/schema/schema.go (3)
  • AtmosConfiguration (27-65)
  • ConfigAndStacksInfo (527-610)
  • AuthContext (498-506)
pkg/auth/cloud/aws/files_test.go (3)
pkg/config/homedir/homedir.go (1)
  • Dir (36-63)
pkg/auth/cloud/aws/files.go (1)
  • NewAWSFileManager (56-83)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
pkg/auth/types/mock_interfaces.go (1)
pkg/auth/types/interfaces.go (2)
  • ICredentials (187-198)
  • ConsoleURLOptions (230-247)
pkg/auth/manager_test.go (2)
pkg/auth/types/whoami.go (1)
  • WhoamiInfo (6-22)
pkg/auth/types/interfaces.go (2)
  • ValidationInfo (201-216)
  • ICredentials (187-198)
🪛 LanguageTool
website/blog/2025-10-24-macos-xdg-cli-conventions.md

[style] ~52-52: This phrase is redundant (‘OS’ stands for ‘operating system’). Use simply “macOS”.
Context: ...,
/Library/Caches` - Provides better macOS system integration - Standard for applications...

(ACRONYM_TAUTOLOGY)


[style] ~61-~61: ‘prior to’ might be wordy. Consider a shorter alternative.
Context: ...ed If you're upgrading from versions prior to v1.195.0, you're not affected because...

(EN_WORDINESS_PREMIUM_PRIOR_TO)


[style] ~81-~81: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...eps credentials in the old location but affects all Atmos XDG paths (config, cache,...

(EN_REPEATEDWORDS_AFFECT)


[grammar] ~158-~158: Please add a punctuation mark at the end of paragraph.
Context: ...uth/usage) - Updated with correct macOS paths ## Migration Support If you encounter...

(PUNCTUATION_PARAGRAPH_END)

docs/prd/xdg-base-directory-specification.md

[typographical] ~39-~39: Consider using a typographic opening quote here.
Context: ...| | Testing with hermetic isolation |t.Setenv("XDG_DATA_HOME")|/tmp/test-xyz/data/a...

(EN_QUOTES)


[typographical] ~51-~51: In American English, use a period after an abbreviation.
Context: ... creation for visibility ### CLI Tools vs GUI Applications The XDG Base Director...

(MISSING_PERIOD_AFTER_ABBREVIATION)


[style] ~63-~63: This phrase is redundant (‘OS’ stands for ‘operating system’). Use simply “macOS”.
Context: ...- This provides better integration with macOS system features - Used by native macOS applica...

(ACRONYM_TAUTOLOGY)


[grammar] ~69-~69: Please add a punctuation mark at the end of paragraph.
Context: ...aths for users working across Linux and macOS ## Technical Specification ### Archit...

(PUNCTUATION_PARAGRAPH_END)


[style] ~550-~550: Consider using a different verb to strengthen your wording.
Context: ... compatibility. Rationale: Research showed that CLI tools (gh, git, packer, stripe...

(SHOW_INDICATE)


[style] ~564-~564: ‘prior to’ might be wordy. Consider a shorter alternative.
Context: ... not be affected** because: 1. Versions prior to v1.195.0 used ~/.aws/atmos/ (legacy p...

(EN_WORDINESS_PREMIUM_PRIOR_TO)

website/blog/2025-10-21-auth-context-implementation.md

[grammar] ~22-~22: Please add a punctuation mark at the end of paragraph.
Context: ...tion** for consistency with other Atmos data ## Why This Matters **The core proble...

(PUNCTUATION_PARAGRAPH_END)

website/docs/cli/commands/auth/tutorials/configuring-geodesic.mdx

[grammar] ~52-~52: Please add a punctuation mark at the end of paragraph.
Context: ... this - ❌ AWS_PROFILE - Atmos manages this Key Configuration Details: - **`A...

(PUNCTUATION_PARAGRAPH_END)

🪛 markdownlint-cli2 (0.18.1)
docs/prd/xdg-base-directory-specification.md

69-69: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build (windows)
  • GitHub Check: Analyze (go)
  • GitHub Check: Summary

osterman and others added 2 commits October 24, 2025 21:15
… custom key

Changed from using x_atmos_expiration key to using section comments for storing
expiration metadata in AWS credentials files. This approach is cleaner and more
standards-compliant:

- Updated WriteCredentials to set section.Comment with expiration
- Updated readExpirationFromMetadata to use ini.LoadSources with IgnoreInlineComment: false
- Added proper comment prefix handling (; and #)
- Updated all tests to use comment format
- Added ErrAwsMissingEnvVars static error

Format: ; atmos: expiration=2025-10-24T23:42:49Z

The ini library properly preserves comments when loading/saving, making this a
more robust solution than relying on undocumented x_ prefix behavior.

Also fixed hooks package to match new GetTerraformOutput signature with authContext parameter.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Removed references to /docs/prd/xdg-base-directory-specification which doesn't
exist in published docs. PRD files are internal development documentation not
published to the website.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (7)
pkg/hooks/store_cmd.go (1)

15-28: Document the authContext parameter.

The doc comment should describe the new authContext parameter to maintain complete documentation of the function type's contract.

Consider adding to the doc comment:

 // TerraformOutputGetter retrieves terraform outputs.
 // This enables dependency injection for testing.
+// Parameters:
+//   - authContext: Optional authentication context for credential-aware operations (may be nil)
 // Returns:
 //   - value: The output value (may be nil if the output exists but has a null value)
 //   - exists: Whether the output key exists in the terraform outputs
 //   - error: Any error that occurred during retrieval (SDK errors, network issues, etc.)
website/blog/2025-10-24-macos-xdg-cli-conventions.md (4)

128-136: Specify language for code block.

The configuration example lacks a language identifier for syntax highlighting. Change ```bash to enable proper rendering.

-\`\`\`
+\`\`\`bash
 ~/.config/

142-150: Specify language for Go code block.

This code block shows Go syntax but lacks a language identifier. Add go to the fence.

-\`\`\`
+\`\`\`go
 func init() {

156-157: Add missing documentation link verification and punctuation.

Line 157 lacks ending punctuation. Also, verify that the referenced documentation pages exist and are updated consistently with this breaking change (per coding guidelines about keeping website code in sync).

-[Configuring Geodesic with Atmos Auth](/docs/cli/commands/auth/tutorials/configuring-geodesic) - Simplified configuration (no setup needed!)
-[Auth Usage Guide](/docs/cli/commands/auth/usage) - Updated with correct macOS paths
+[Configuring Geodesic with Atmos Auth](/docs/cli/commands/auth/tutorials/configuring-geodesic) - Simplified configuration (no setup needed!).
+[Auth Usage Guide](/docs/cli/commands/auth/usage) - Updated with correct macOS paths.

171-176: Wrap bare URLs in markdown link syntax.

Lines 173–175 contain bare URLs. Wrap them in markdown link format for consistency and better rendering.

-## References
-
-- XDG Base Directory Specification: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
-- Stack Overflow Discussion: https://stackoverflow.com/questions/3373948/equivalents-of-xdg-config-home-and-xdg-data-home-on-mac-os-x
-- Geodesic: https://github.com/cloudposse/geodesic
+## References
+
+- [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
+- [Stack Overflow Discussion](https://stackoverflow.com/questions/3373948/equivalents-of-xdg-config-home-and-xdg-data-home-on-mac-os-x)
+- [Geodesic](https://github.com/cloudposse/geodesic)
pkg/auth/identities/aws/credentials_loader_test.go (2)

13-100: Nice table-driven test with good edge case coverage.

The test structure is clean and covers the important scenarios. A couple of minor suggestions:

  1. Lines 24, 37, 49, 62, 75 ignore errors from NewSection with _, while line 116 (in the round-trip test) properly checks them. For consistency, you might want to check these in the setup functions too—though NewSection rarely fails with simple names, checking keeps things uniform.

  2. Consider adding a doc comment to explain what the test covers (coding guidelines encourage doc comments on test functions).


107-143: Solid end-to-end test.

The round-trip flow is well-structured—writes metadata, reads it back, validates the timestamp format. Good to see proper error handling throughout and the 0o600 permissions for the credentials file.

One optional thought: you might consider adding a test case for when the expiration is in the past, to verify how expired credentials are handled. But that may be beyond the scope here.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 130e7e2 and 5fd720f.

📒 Files selected for processing (8)
  • errors/errors.go (1 hunks)
  • pkg/auth/cloud/aws/files.go (6 hunks)
  • pkg/auth/identities/aws/credentials_loader.go (1 hunks)
  • pkg/auth/identities/aws/credentials_loader_test.go (1 hunks)
  • pkg/hooks/store_cmd.go (2 hunks)
  • pkg/hooks/store_cmd_nil_handling_test.go (9 hunks)
  • pkg/hooks/store_cmd_test.go (1 hunks)
  • website/blog/2025-10-24-macos-xdg-cli-conventions.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/auth/cloud/aws/files.go
  • pkg/auth/identities/aws/credentials_loader.go
🧰 Additional context used
📓 Path-based instructions (6)
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • errors/errors.go
  • pkg/hooks/store_cmd.go
  • pkg/hooks/store_cmd_nil_handling_test.go
  • pkg/auth/identities/aws/credentials_loader_test.go
  • pkg/hooks/store_cmd_test.go
**/!(*_test).go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Document all exported functions, types, and methods with Go doc comments

Files:

  • errors/errors.go
  • pkg/hooks/store_cmd.go
pkg/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Place business logic in pkg rather than in cmd

Files:

  • pkg/hooks/store_cmd.go
  • pkg/hooks/store_cmd_nil_handling_test.go
  • pkg/auth/identities/aws/credentials_loader_test.go
  • pkg/hooks/store_cmd_test.go
website/**

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

website/**: Update website documentation in website/ when adding features
Ensure consistency between CLI help text and website documentation
Follow the website's documentation structure and style
Keep website code in website/ and follow its architecture/style; test changes locally
Keep CLI and website documentation in sync; document new features with examples and use cases

Files:

  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
website/blog/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-*.md

📄 CodeRabbit inference engine (CLAUDE.md)

PRs labeled minor or major must include a blog post with filename date prefix and feature name; include and proper tags.

Files:

  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
**/*_test.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + DI; table-driven tests for coverage; target >80% coverage.
Tests must exercise production code paths; avoid duplicating implementation logic in tests.
Use t.Skipf("reason") with clear context when skipping tests; CLI tests may auto-build temp binaries.

Files:

  • pkg/hooks/store_cmd_nil_handling_test.go
  • pkg/auth/identities/aws/credentials_loader_test.go
  • pkg/hooks/store_cmd_test.go
🧠 Learnings (2)
📓 Common learnings
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: internal/exec/terraform.go:269-272
Timestamp: 2025-10-03T18:02:08.535Z
Learning: In internal/exec/terraform.go, when auth.TerraformPreHook fails, the error is logged but execution continues. This is a deliberate design choice to allow Terraform commands to proceed even if authentication setup fails, rather than failing fast.
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.

Applied to files:

  • website/blog/2025-10-24-macos-xdg-cli-conventions.md
🧬 Code graph analysis (3)
pkg/hooks/store_cmd.go (1)
pkg/schema/schema.go (1)
  • AuthContext (498-506)
pkg/hooks/store_cmd_nil_handling_test.go (1)
pkg/schema/schema.go (2)
  • AtmosConfiguration (27-65)
  • AuthContext (498-506)
pkg/hooks/store_cmd_test.go (1)
pkg/schema/schema.go (2)
  • AtmosConfiguration (27-65)
  • AuthContext (498-506)
🪛 LanguageTool
website/blog/2025-10-24-macos-xdg-cli-conventions.md

[style] ~52-52: This phrase is redundant (‘OS’ stands for ‘operating system’). Use simply “macOS”.
Context: ...,
/Library/Caches` - Provides better macOS system integration - Standard for applications...

(ACRONYM_TAUTOLOGY)


[style] ~61-~61: ‘prior to’ might be wordy. Consider a shorter alternative.
Context: ...ed If you're upgrading from versions prior to v1.195.0, you're not affected because...

(EN_WORDINESS_PREMIUM_PRIOR_TO)


[style] ~81-~81: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...eps credentials in the old location but affects all Atmos XDG paths (config, cache,...

(EN_REPEATEDWORDS_AFFECT)


[grammar] ~157-~157: Please add a punctuation mark at the end of paragraph.
Context: ...uth/usage) - Updated with correct macOS paths ## Migration Support If you encounter...

(PUNCTUATION_PARAGRAPH_END)

🪛 markdownlint-cli2 (0.18.1)
website/blog/2025-10-24-macos-xdg-cli-conventions.md

69-69: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


75-75: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


83-83: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


128-128: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


173-173: Bare URL used

(MD034, no-bare-urls)


174-174: Bare URL used

(MD034, no-bare-urls)


175-175: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: autofix
  • GitHub Check: Build (windows)
  • GitHub Check: Build (linux)
  • GitHub Check: Build (macos)
  • GitHub Check: website-deploy-preview
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: Analyze (go)
  • GitHub Check: Summary
🔇 Additional comments (8)
errors/errors.go (1)

382-382: LGTM!

The new error sentinel follows the established naming convention and is appropriately placed with other AWS authentication errors.

pkg/hooks/store_cmd.go (1)

75-82: Clean integration of authContext parameter.

The nil authContext is correctly passed through, maintaining existing behavior while enabling future credential-aware operations.

pkg/hooks/store_cmd_test.go (1)

130-137: Test correctly adapted to new signature.

The mock signature update maintains test coverage while supporting the extended contract.

pkg/hooks/store_cmd_nil_handling_test.go (2)

66-77: Signature update maintains nil handling test coverage.

The authContext parameter addition doesn't affect the test's validation of nil/missing output scenarios.


149-421: Comprehensive test updates align with new signature.

All mock getter functions correctly updated to include authContext parameter. Test coverage for rate limits, intermittent failures, and error handling remains intact.

website/blog/2025-10-24-macos-xdg-cli-conventions.md (1)

1-179: Blog post structure and content alignment look solid.

The post clearly documents the breaking change and aligns well with the PR's XDG path improvements. Migration guidance is practical with three concrete options. The Geodesic integration specifics (lines 102–111) directly support the containerized auth isolation goals from PR #1712.

Verify that the documentation pages referenced at line 156–157 have been updated in this PR to reflect the macOS path changes. If they weren't, either update them or remove/defer the reference in this blog post (per coding guidelines about keeping website docs in sync).

pkg/auth/identities/aws/credentials_loader_test.go (2)

1-11: Imports look solid.

Clean organization—stdlib, then third-party, alphabetically sorted. Has everything needed for the tests.


102-105: Good check for the missing file case.

Simple and effective—verifies graceful handling when the credentials file doesn't exist.

osterman and others added 2 commits October 24, 2025 21:21
- Add performance tracking to LoadAtmosManagedAWSConfig
- Fix os.UserHomeDir() error handling in aws_utils and env.go to avoid misleading paths
- Clear AWS credential env vars when authContext is provided to prevent conflicts
- Set AWS_SDK_LOAD_CONFIG=1 and AWS_EC2_METADATA_DISABLED=true for better isolation
- Add AWS_DEFAULT_REGION alongside AWS_REGION for compatibility

These changes improve credential isolation and ensure Atmos-managed credentials
are not overridden by ambient environment variables or instance metadata.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updated documentation to show macOS uses ~/.config/atmos/ instead of
~/Library/Application Support/atmos/. This aligns with the XDG Base Directory
changes where macOS now follows CLI tool conventions (same as Linux) rather
than GUI application conventions.

Fixes blog post and auth-shell.mdx documentation.

🤖 Generated with [Claude Code](https://claude.com/claude.code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
pkg/auth/cloud/aws/env.go (3)

3-14: Fix build: import perf (and keep imports grouped/sorted).

Build fails with undefined: perf. Add perf import in the Atmos group and keep groups sorted.

Apply:

 import (
 	"context"
+	"errors"
 	"fmt"
 	"os"
 	"path/filepath"
 
 	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/config"
 
 	errUtils "github.com/cloudposse/atmos/errors"
 	log "github.com/cloudposse/atmos/pkg/logger"
+	"github.com/cloudposse/atmos/pkg/perf"
 )

104-109: Shared-config not actually disabled. Use empty file lists instead of empty profile.

config.WithSharedConfigProfile("") does not prevent loading ~/.aws/{config,credentials}. Use empty file lists to truly isolate.

Apply:

-	// Prepend config.WithSharedConfigProfile("") to disable loading from shared config files.
-	// This prevents the SDK from loading user's ~/.aws/config and ~/.aws/credentials files.
-	isolatedOptFns := make([]func(*config.LoadOptions) error, 0, len(optFns)+1)
-	isolatedOptFns = append(isolatedOptFns, config.WithSharedConfigProfile(""))
+	// Disable reading any shared config/credentials files for full isolation.
+	isolatedOptFns := make([]func(*config.LoadOptions) error, 0, len(optFns)+2)
+	isolatedOptFns = append(isolatedOptFns,
+		config.WithSharedConfigFiles([]string{}),
+		config.WithSharedCredentialsFiles([]string{}),
+	)
 	isolatedOptFns = append(isolatedOptFns, optFns...)

115-121: Invalid use of multiple %w in fmt.Errorf; wrap correctly and keep sentinel.

Multiple %w in a single fmt.Errorf triggers vet/lint and loses proper chaining. Wrap the cause once and join with the sentinel.

Apply:

-	if isolateErr != nil {
-		return aws.Config{}, fmt.Errorf("%w: %w", errUtils.ErrLoadAwsConfig, isolateErr)
-	}
+	if isolateErr != nil {
+		return aws.Config{}, errors.Join(
+			errUtils.ErrLoadAwsConfig,
+			fmt.Errorf("load isolated AWS config: %w", isolateErr),
+		)
+	}
 
-	if err != nil {
-		return aws.Config{}, fmt.Errorf("%w: %w", errUtils.ErrLoadAwsConfig, err)
-	}
+	// (no second error check needed; isolateErr already captures loader error)
-	if err != nil {
-		log.Debug("Failed to load AWS SDK config", "error", err)
-		return aws.Config{}, fmt.Errorf("%w: %w", errUtils.ErrLoadAwsConfig, err)
-	}
+	if err != nil {
+		log.Debug("Failed to load AWS SDK config", "error", err)
+		return aws.Config{}, errors.Join(
+			errUtils.ErrLoadAwsConfig,
+			fmt.Errorf("load AWS SDK config: %w", err),
+		)
+	}

Also applies to: 229-232

🧹 Nitpick comments (3)
pkg/auth/cloud/aws/env.go (3)

119-121: Remove redundant error check.

err is the same error returned from the closure into isolateErr; the second check is dead code after the previous return.

Apply:

-	if err != nil {
-		return aws.Config{}, fmt.Errorf("%w: %w", errUtils.ErrLoadAwsConfig, err)
-	}
+	// Redundant check removed.

149-151: Drop noisy debug marker.

The "=== UPDATED CODE" log is a leftover and adds noise.

Apply:

-	log.Debug("=== UPDATED CODE: LoadAtmosManagedAWSConfig called ===")

16-39: Godot: end comments with periods.

Several comment lines lack trailing periods; golangci-lint godot will flag them. Quick audit/fix across these blocks.

Would you like me to push a patch normalizing punctuation across the file?

Also applies to: 88-100, 126-143

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5fd720f and 477924d.

📒 Files selected for processing (5)
  • internal/aws_utils/aws_utils.go (2 hunks)
  • internal/exec/terraform_output_utils.go (5 hunks)
  • pkg/auth/cloud/aws/env.go (3 hunks)
  • website/blog/2025-10-21-auth-context-implementation.md (2 hunks)
  • website/docs/cli/commands/auth/auth-shell.mdx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/docs/cli/commands/auth/auth-shell.mdx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • internal/aws_utils/aws_utils.go
  • pkg/auth/cloud/aws/env.go
  • internal/exec/terraform_output_utils.go
**/!(*_test).go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Document all exported functions, types, and methods with Go doc comments

Files:

  • internal/aws_utils/aws_utils.go
  • pkg/auth/cloud/aws/env.go
  • internal/exec/terraform_output_utils.go
pkg/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Place business logic in pkg rather than in cmd

Files:

  • pkg/auth/cloud/aws/env.go
website/**

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

website/**: Update website documentation in website/ when adding features
Ensure consistency between CLI help text and website documentation
Follow the website's documentation structure and style
Keep website code in website/ and follow its architecture/style; test changes locally
Keep CLI and website documentation in sync; document new features with examples and use cases

Files:

  • website/blog/2025-10-21-auth-context-implementation.md
website/blog/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-*.md

📄 CodeRabbit inference engine (CLAUDE.md)

PRs labeled minor or major must include a blog post with filename date prefix and feature name; include and proper tags.

Files:

  • website/blog/2025-10-21-auth-context-implementation.md
🧠 Learnings (6)
📓 Common learnings
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: internal/exec/terraform.go:269-272
Timestamp: 2025-10-03T18:02:08.535Z
Learning: In internal/exec/terraform.go, when auth.TerraformPreHook fails, the error is logged but execution continues. This is a deliberate design choice to allow Terraform commands to proceed even if authentication setup fails, rather than failing fast.
📚 Learning: 2025-10-24T14:51:19.340Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.340Z
Learning: Applies to **/*.go : Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.

Applied to files:

  • pkg/auth/cloud/aws/env.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.

Applied to files:

  • website/blog/2025-10-21-auth-context-implementation.md
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: XDG Base Directory Specification compliance implementation for atmos toolchain is complete: created toolchain/xdg_cache.go with GetXDGCacheDir() and GetXDGTempCacheDir() functions, updated toolchain/installer.go and cmd/toolchain_clean.go to use these XDG helpers, and changed all cache paths from hardcoded ~/.cache/tools-cache to XDG-compliant ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback).

Applied to files:

  • website/blog/2025-10-21-auth-context-implementation.md
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: Final XDG Base Directory Specification implementation for atmos toolchain is complete and verified: toolchain/xdg_cache.go provides GetXDGCacheDir() and GetXDGTempCacheDir() functions, all hardcoded ~/.cache/tools-cache paths have been replaced with XDG-compliant paths using ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback), and tests have been updated to expect the new path structure.

Applied to files:

  • website/blog/2025-10-21-auth-context-implementation.md
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
PR: cloudposse/atmos#1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain XDG compliance implementation is complete with GetXDGCacheDir() and GetXDGTempCacheDir() functions in toolchain/xdg_cache.go, updated installer.go and toolchain_clean.go to use these helpers, and changed cache paths from ~/.cache/tools-cache to ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain when XDG_CACHE_HOME is not set).

Applied to files:

  • website/blog/2025-10-21-auth-context-implementation.md
🧬 Code graph analysis (3)
internal/aws_utils/aws_utils.go (2)
pkg/logger/log.go (1)
  • Debug (24-26)
errors/errors.go (1)
  • ErrLoadAwsConfig (74-74)
pkg/auth/cloud/aws/env.go (4)
pkg/schema/schema.go (1)
  • Context (409-424)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/logger/log.go (2)
  • Debug (24-26)
  • Errorf (59-61)
errors/errors.go (1)
  • ErrLoadAwsConfig (74-74)
internal/exec/terraform_output_utils.go (3)
pkg/schema/schema.go (1)
  • AuthContext (498-506)
pkg/logger/log.go (1)
  • Debug (24-26)
pkg/config/const.go (1)
  • EnvSectionName (61-61)
🪛 GitHub Check: Build (macos)
pkg/auth/cloud/aws/env.go

[failure] 144-144:
undefined: perf

🪛 LanguageTool
website/blog/2025-10-21-auth-context-implementation.md

[grammar] ~22-~22: Please add a punctuation mark at the end of paragraph.
Context: ...tion** for consistency with other Atmos data ## Why This Matters **The core proble...

(PUNCTUATION_PARAGRAPH_END)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Build (windows)
  • GitHub Check: Build (linux)
  • GitHub Check: Analyze (go)
  • GitHub Check: website-deploy-preview
  • GitHub Check: autofix
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: Summary
🔇 Additional comments (8)
internal/aws_utils/aws_utils.go (3)

88-91: Good fix – error handling improved.

The error from os.UserHomeDir() is now properly captured and logged, addressing the previous review concern. Skipping the default path checks when the home directory can't be determined is the right approach.


92-120: Solid debugging instrumentation.

The detailed logging of default paths, profile, and environment variables will help diagnose credential resolution issues. Using filepath.Join ensures cross-platform compatibility, and the file existence checks add useful context without changing behavior.


125-136: Debug logging additions look good.

The lifecycle logging around region handling and config loading will make it easier to trace SDK initialization issues. All debug-level, so no production noise.

internal/exec/terraform_output_utils.go (5)

63-69: LGTM: authContext parameter added correctly.

The signature update cleanly threads authentication context through the execution path.


189-206: Solid isolation setup.

The Atmos-managed credential paths, SDK config forcing, region handling, and IMDS disabling are all properly configured to prevent external auth interference.


208-221: LGTM: improved logging clarity.

The "Adding" terminology and count logging make the env var merge behavior clearer.


223-232: Good guard and logging.

The len check avoids an unnecessary SetEnv call when the map is empty, and the final count log helps with debugging.


376-396: LGTM: authContext properly threaded through.

The signature update, documentation, and propagation to execTerraformOutput are all correct. Performance tracking is appropriately included for the public function.

Also applies to: 448-448

osterman and others added 4 commits October 24, 2025 22:01
Error message improvements:
- Add ErrUserAborted for clean user abort handling
- Change error formatting from backticked quotes to backticks only
- Add provider and credential store type to "no credentials found" errors

CredentialStore.Type() implementation:
- Add Type() method to CredentialStore interface
- Implement Type() in all credential store implementations
- Regenerate MockCredentialStore with Type() method

Lint fixes:
- Add constants for repeated string literals (logKeyProvider, logKeyIdentity, logKeyProfile, errFormatWrapTwo)
- Remove non-essential debug logging using os.Getenv (forbidigo violations)
- Reduce cyclomatic complexity in loadAWSCredentialsFromEnvironment by extracting helper functions
- Fix function-result-limit by using awsEnvVars struct instead of multiple return values
- Fix hugeParam by passing aws.Credentials by pointer
- Reduce nestif complexity in validateCredentials using early return pattern
- Split manager.go to reduce file length:
  - Extract logout functions to manager_logout.go
  - Extract whoami functions to manager_whoami.go
- Split printWhoamiHuman into smaller functions

Note: manager_logout.go has pre-existing complexity issues (gocognit, nestif, cyclomatic)
that were moved from manager.go. These will be addressed in a separate commit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add CredentialStoreType* constants to avoid magic strings:
- CredentialStoreTypeSystemKeyring = "system-keyring"
- CredentialStoreTypeNoop = "noop"
- CredentialStoreTypeMemory = "memory"
- CredentialStoreTypeFile = "file"

Update all Type() method implementations to use these constants.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive tests for the helper functions extracted during
cyclomatic complexity refactoring:

- TestExtractAWSEnvVars: Tests environment variable extraction and
  validation with all combinations of present/missing required vars

- TestSetupAWSEnv: Tests environment variable setup/cleanup with:
  * New environment vars (none existing)
  * Restoring original environment vars
  * Optional region parameter handling

- TestPopulateExpiration: Tests credential expiration logic with:
  * SDK-provided expiration timestamps
  * Non-session credentials (no expiration)
  * Session tokens with zero/missing SDK expiration

These tests verify behavior in isolation, making it easier to catch
regressions and understand expected behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
When credentials are not found in the keyring, whoami should fallback
to loading from identity-managed storage (AWS credential files, etc.).

Previously, this only worked for noop keyring. Now it works for all
keyring types, including system-keyring.

This handles the common case where:
1. User authenticates via AWS CLI or other tools
2. Credentials are stored in ~/.aws/credentials
3. Atmos hasn't cached them in the keyring yet
4. User runs 'atmos auth whoami' to check credential status

The fix moves the LoadCredentials fallback to apply to all keyring types
when ErrCredentialsNotFound is returned, not just noop keyring.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
pkg/auth/cloud/aws/env.go (2)

54-86: Add perf tracking to exported helper.

WithIsolatedAWSEnv is public; add perf tracking per guidelines.

As per coding guidelines.

-func WithIsolatedAWSEnv(fn func() error) error {
+func WithIsolatedAWSEnv(fn func() error) error {
+	defer perf.Track(nil, "pkg/auth/cloud/aws.WithIsolatedAWSEnv")()

100-124: I need to verify the AWS SDK isolation approach before finalizing:

Add perf.Track and strengthen AWS config isolation.

  1. Add defer perf.Track(nil, "pkg/auth/cloud/aws.LoadIsolatedAWSConfig")() to the start of the function per coding guidelines.
  2. Strengthen isolation by explicitly disabling shared config and credentials file reads (not just the profile):
 func LoadIsolatedAWSConfig(ctx context.Context, optFns ...func(*config.LoadOptions) error) (aws.Config, error) {
+	defer perf.Track(nil, "pkg/auth/cloud/aws.LoadIsolatedAWSConfig")()
+
-	// Prepend config.WithSharedConfigProfile("") to disable loading from shared config files.
-	// This prevents the SDK from loading user's ~/.aws/config and ~/.aws/credentials files.
-	isolatedOptFns := make([]func(*config.LoadOptions) error, 0, len(optFns)+1)
-	isolatedOptFns = append(isolatedOptFns, config.WithSharedConfigProfile(""))
+	// Explicitly disable shared config/credentials files to prevent ~/.aws fallback loads.
+	isolatedOptFns := make([]func(*config.LoadOptions) error, 0, len(optFns)+3)
+	isolatedOptFns = append(isolatedOptFns,
+		config.WithSharedConfigFiles([]string{}),
+		config.WithSharedCredentialsFiles([]string{}),
+		config.WithSharedConfigProfile(""),
+	)
 	isolatedOptFns = append(isolatedOptFns, optFns...)

Setting the shared config profile to an empty string only results in the profile value being ignored. Setting shared credentials files to an empty slice results in those files being ignored. This three-option approach closes potential fallback paths.

pkg/auth/cloud/aws/files.go (3)

61-88: Add perf tracking to constructor.

NewAWSFileManager is exported; add perf tracking.

As per coding guidelines.

 func NewAWSFileManager(basePath string) (*AWSFileManager, error) {
+	defer perf.Track(nil, "aws.files.NewAWSFileManager")()

117-191: Add perf tracking to exported write methods.

WriteCredentials is exported; add perf tracking.

As per coding guidelines.

 func (m *AWSFileManager) WriteCredentials(providerName, identityName string, creds *types.AWSCredentials) error {
+	defer perf.Track(nil, "aws.files.WriteCredentials")()

194-265: Add perf tracking to WriteConfig.

WriteConfig is exported; add perf tracking.

As per coding guidelines.

 func (m *AWSFileManager) WriteConfig(providerName, identityName, region, outputFormat string) error {
+	defer perf.Track(nil, "aws.files.WriteConfig")()
♻️ Duplicate comments (1)
pkg/auth/types/mock_interfaces.go (1)

837-850: Validate mock signature correctly updated.

The previous review comment flagged that this mock returned (*time.Time, error) instead of (*ValidationInfo, error). This has been corrected - the mock now properly returns (*ValidationInfo, error).

🧹 Nitpick comments (9)
pkg/auth/cloud/aws/env.go (1)

157-181: Process-wide env mutation is racy; prefer file/options over unset/restore.

Unsetting env vars then restoring is not concurrency-safe. Prefer passing explicit shared config/credentials file options and profile via LoadOptions so no env changes are needed.

Would you like a version that accepts explicit files/profile and avoids os.Unsetenv/os.Setenv?

pkg/auth/manager.go (1)

413-419: Default files display path—align with new XDG location.

Fallback to "~/.aws/atmos" is legacy. Consider delegating to provider (if available) or computing the XDG display path to reflect new defaults.

Do you want a small helper to fetch the XDG display path here?

pkg/auth/credentials/keyring_system.go (1)

143-146: Consider adding performance tracking for consistency.

While this is a simple accessor, other methods in this file include defer perf.Track(...). Consider adding it here for consistency:

 // Type returns the type of this credential store.
 func (s *systemKeyringStore) Type() string {
+	defer perf.Track(nil, "credentials.systemKeyringStore.Type")()
+
 	return types.CredentialStoreTypeSystemKeyring
 }

As per coding guidelines: "Add defer perf.Track at the start of all public functions."

pkg/auth/credentials/keyring_memory.go (1)

137-140: Consider adding performance tracking for consistency.

Similar to the system keyring, consider adding performance tracking:

 // Type returns the type of this credential store.
 func (s *memoryKeyringStore) Type() string {
+	defer perf.Track(nil, "credentials.memoryKeyringStore.Type")()
+
 	return types.CredentialStoreTypeMemory
 }
pkg/auth/credentials/keyring_file.go (1)

319-322: Consider adding performance tracking for consistency.

For consistency with other methods in this file:

 // Type returns the type of this credential store.
 func (s *fileKeyringStore) Type() string {
+	defer perf.Track(nil, "credentials.fileKeyringStore.Type")()
+
 	return types.CredentialStoreTypeFile
 }
pkg/auth/manager_whoami.go (2)

11-44: Add performance tracking.

The buildWhoamiInfo function should include performance tracking per coding guidelines:

 // buildWhoamiInfo creates a WhoamiInfo struct from identity and credentials.
 func (m *manager) buildWhoamiInfo(identityName string, creds types.ICredentials) *types.WhoamiInfo {
+	defer perf.Track(nil, "auth.manager.buildWhoamiInfo")()
+
 	providerName := m.getProviderForIdentity(identityName)

46-95: Add performance tracking.

The buildWhoamiInfoFromEnvironment function should include performance tracking:

 func (m *manager) buildWhoamiInfoFromEnvironment(identityName string) *types.WhoamiInfo {
+	defer perf.Track(nil, "auth.manager.buildWhoamiInfoFromEnvironment")()
+
 	providerName := m.getProviderForIdentity(identityName)
pkg/auth/identities/aws/credentials_loader.go (1)

24-59: Add performance tracking.

Per coding guidelines, add performance tracking to this function:

 func loadAWSCredentialsFromEnvironment(ctx context.Context, env map[string]string) (*types.AWSCredentials, error) {
+	defer perf.Track(nil, "aws.loadAWSCredentialsFromEnvironment")()
+
 	// Extract and validate AWS environment variables.

Even unexported functions should include performance tracking for observability.

pkg/auth/identities/aws/credentials_loader_test.go (1)

240-380: Consider simplifying environment management.

The test manually saves/unsets environment variables (lines 319-336) before using t.Setenv (line 340), then registers a manual cleanup (lines 343-351). Since t.Setenv already handles cleanup, you could simplify by either:

  • Using only t.Setenv for all env operations (it saves/restores automatically), or
  • Using only manual save/restore without t.Setenv

The current approach works but mixes two cleanup strategies, making it harder to follow.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 477924d and 1830d4e.

📒 Files selected for processing (18)
  • cmd/auth_whoami.go (4 hunks)
  • errors/errors.go (1 hunks)
  • internal/aws_utils/aws_utils.go (1 hunks)
  • pkg/auth/cloud/aws/env.go (3 hunks)
  • pkg/auth/cloud/aws/files.go (6 hunks)
  • pkg/auth/credentials/keyring_file.go (1 hunks)
  • pkg/auth/credentials/keyring_memory.go (1 hunks)
  • pkg/auth/credentials/keyring_noop.go (3 hunks)
  • pkg/auth/credentials/keyring_system.go (1 hunks)
  • pkg/auth/identities/aws/credentials_loader.go (1 hunks)
  • pkg/auth/identities/aws/credentials_loader_test.go (1 hunks)
  • pkg/auth/manager.go (7 hunks)
  • pkg/auth/manager_logout.go (1 hunks)
  • pkg/auth/manager_test.go (5 hunks)
  • pkg/auth/manager_whoami.go (1 hunks)
  • pkg/auth/types/interfaces.go (5 hunks)
  • pkg/auth/types/mock_interfaces.go (6 hunks)
  • pkg/auth/types/whoami_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/aws_utils/aws_utils.go
  • pkg/auth/manager_test.go
🧰 Additional context used
📓 Path-based instructions (6)
pkg/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Place business logic in pkg rather than in cmd

Files:

  • pkg/auth/credentials/keyring_system.go
  • pkg/auth/credentials/keyring_file.go
  • pkg/auth/manager_logout.go
  • pkg/auth/types/interfaces.go
  • pkg/auth/manager_whoami.go
  • pkg/auth/identities/aws/credentials_loader_test.go
  • pkg/auth/identities/aws/credentials_loader.go
  • pkg/auth/credentials/keyring_memory.go
  • pkg/auth/types/whoami_test.go
  • pkg/auth/manager.go
  • pkg/auth/cloud/aws/files.go
  • pkg/auth/types/mock_interfaces.go
  • pkg/auth/credentials/keyring_noop.go
  • pkg/auth/cloud/aws/env.go
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • pkg/auth/credentials/keyring_system.go
  • pkg/auth/credentials/keyring_file.go
  • pkg/auth/manager_logout.go
  • pkg/auth/types/interfaces.go
  • cmd/auth_whoami.go
  • pkg/auth/manager_whoami.go
  • pkg/auth/identities/aws/credentials_loader_test.go
  • pkg/auth/identities/aws/credentials_loader.go
  • pkg/auth/credentials/keyring_memory.go
  • pkg/auth/types/whoami_test.go
  • pkg/auth/manager.go
  • errors/errors.go
  • pkg/auth/cloud/aws/files.go
  • pkg/auth/types/mock_interfaces.go
  • pkg/auth/credentials/keyring_noop.go
  • pkg/auth/cloud/aws/env.go
**/!(*_test).go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Document all exported functions, types, and methods with Go doc comments

Files:

  • pkg/auth/credentials/keyring_system.go
  • pkg/auth/credentials/keyring_file.go
  • pkg/auth/manager_logout.go
  • pkg/auth/types/interfaces.go
  • cmd/auth_whoami.go
  • pkg/auth/manager_whoami.go
  • pkg/auth/identities/aws/credentials_loader.go
  • pkg/auth/credentials/keyring_memory.go
  • pkg/auth/manager.go
  • errors/errors.go
  • pkg/auth/cloud/aws/files.go
  • pkg/auth/types/mock_interfaces.go
  • pkg/auth/credentials/keyring_noop.go
  • pkg/auth/cloud/aws/env.go
cmd/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate

cmd/**/*.go: New CLI commands must use the command registry pattern via CommandProvider and register through the command registry (see cmd/internal/registry.go).
Commands should embed *_usage.md via //go:embed and render with utils.PrintfMarkdown().
UI (prompts/status) must write to stderr; data outputs to stdout; logging only for system events (never for UI).
For non-standard execution paths, capture telemetry with telemetry.CaptureCmd(); normal paths are auto-enabled via RootCmd.ExecuteC(). Never capture user data.

Files:

  • cmd/auth_whoami.go
{cmd,pkg/ui}/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use theme colors from pkg/ui/theme/colors.go for UI elements.

Files:

  • cmd/auth_whoami.go
**/*_test.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + DI; table-driven tests for coverage; target >80% coverage.
Tests must exercise production code paths; avoid duplicating implementation logic in tests.
Use t.Skipf("reason") with clear context when skipping tests; CLI tests may auto-build temp binaries.

Files:

  • pkg/auth/identities/aws/credentials_loader_test.go
  • pkg/auth/types/whoami_test.go
🧠 Learnings (8)
📓 Common learnings
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: internal/exec/terraform.go:269-272
Timestamp: 2025-10-03T18:02:08.535Z
Learning: In internal/exec/terraform.go, when auth.TerraformPreHook fails, the error is logged but execution continues. This is a deliberate design choice to allow Terraform commands to proceed even if authentication setup fails, rather than failing fast.
📚 Learning: 2025-09-09T02:14:36.708Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1452
File: internal/auth/types/whoami.go:14-15
Timestamp: 2025-09-09T02:14:36.708Z
Learning: The WhoamiInfo struct in internal/auth/types/whoami.go requires the Credentials field to be JSON-serializable for keystore unmarshaling operations, despite security concerns about credential exposure.

Applied to files:

  • cmd/auth_whoami.go
📚 Learning: 2025-10-22T14:55:44.014Z
Learnt from: osterman
PR: cloudposse/atmos#1695
File: pkg/auth/manager.go:169-171
Timestamp: 2025-10-22T14:55:44.014Z
Learning: Go 1.20+ supports multiple %w verbs in fmt.Errorf, which returns an error implementing Unwrap() []error. This is valid and does not panic. Atmos uses Go 1.24.8 and configures errorlint with errorf-multi: true to validate this pattern.

Applied to files:

  • pkg/auth/manager.go
📚 Learning: 2025-09-10T22:38:42.212Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: pkg/auth/identities/aws/user.go:141-145
Timestamp: 2025-09-10T22:38:42.212Z
Learning: The user confirmed that the errors package has an error string wrapping format, contradicting the previous learning about ErrWrappingFormat being invalid. The current usage of fmt.Errorf(errUtils.ErrWrappingFormat, errUtils.ErrAuthAwsFileManagerFailed, err) appears to be the correct pattern.

Applied to files:

  • pkg/auth/manager.go
📚 Learning: 2025-09-10T22:38:42.212Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: pkg/auth/identities/aws/user.go:141-145
Timestamp: 2025-09-10T22:38:42.212Z
Learning: ErrWrappingFormat is correctly defined as "%w: %w" in the errors package and is used throughout the codebase to wrap two error types together. The usage fmt.Errorf(errUtils.ErrWrappingFormat, errUtils.ErrAuthAwsFileManagerFailed, err) is the correct pattern when both arguments are error types.

Applied to files:

  • pkg/auth/manager.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
PR: cloudposse/atmos#1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.

Applied to files:

  • pkg/auth/manager.go
📚 Learning: 2025-10-24T14:51:19.340Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.340Z
Learning: Applies to **/*.go : Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.

Applied to files:

  • pkg/auth/cloud/aws/env.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
PR: cloudposse/atmos#1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.

Applied to files:

  • pkg/auth/cloud/aws/env.go
🧬 Code graph analysis (13)
pkg/auth/credentials/keyring_system.go (1)
pkg/auth/types/interfaces.go (1)
  • CredentialStoreTypeSystemKeyring (14-14)
pkg/auth/credentials/keyring_file.go (1)
pkg/auth/types/interfaces.go (1)
  • CredentialStoreTypeFile (17-17)
pkg/auth/manager_logout.go (4)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/logger/log.go (3)
  • Errorf (59-61)
  • Debug (24-26)
  • Info (34-36)
errors/errors.go (8)
  • ErrIdentityNotInConfig (428-428)
  • ErrKeyringDeletion (425-425)
  • ErrLogoutNotSupported (423-423)
  • ErrProviderLogout (426-426)
  • ErrIdentityLogout (427-427)
  • ErrPartialLogout (422-422)
  • ErrLogoutFailed (421-421)
  • ErrProviderNotInConfig (429-429)
pkg/auth/types/interfaces.go (2)
  • Provider (21-50)
  • Identity (62-97)
cmd/auth_whoami.go (4)
pkg/auth/types/whoami.go (1)
  • WhoamiInfo (6-22)
pkg/logger/log.go (1)
  • Debug (24-26)
pkg/auth/types/interfaces.go (2)
  • Identity (62-97)
  • ValidationInfo (212-227)
pkg/ui/theme/colors.go (1)
  • ColorRed (16-16)
pkg/auth/manager_whoami.go (3)
pkg/auth/types/interfaces.go (3)
  • ICredentials (198-209)
  • Provider (21-50)
  • Identity (62-97)
pkg/auth/types/whoami.go (1)
  • WhoamiInfo (6-22)
pkg/logger/log.go (1)
  • Debug (24-26)
pkg/auth/identities/aws/credentials_loader_test.go (2)
errors/errors.go (1)
  • ErrAwsMissingEnvVars (382-382)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
pkg/auth/identities/aws/credentials_loader.go (3)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
pkg/logger/log.go (1)
  • Debug (24-26)
errors/errors.go (1)
  • ErrAwsMissingEnvVars (382-382)
pkg/auth/credentials/keyring_memory.go (1)
pkg/auth/types/interfaces.go (1)
  • CredentialStoreTypeMemory (16-16)
pkg/auth/manager.go (4)
pkg/logger/log.go (2)
  • Errorf (59-61)
  • Debug (24-26)
errors/errors.go (6)
  • ErrIdentityNotFound (395-395)
  • ErrNoCredentialsFound (388-388)
  • ErrExpiredCredentials (389-389)
  • ErrMultipleDefaultIdentities (399-399)
  • ErrUserAborted (384-384)
  • ErrInvalidAuthConfig (370-370)
pkg/auth/credentials/keyring_file.go (1)
  • ErrCredentialsNotFound (36-36)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/auth/cloud/aws/files.go (4)
pkg/xdg/xdg.go (1)
  • GetXDGConfigDir (46-48)
pkg/logger/log.go (3)
  • Errorf (59-61)
  • Warn (44-46)
  • Debug (24-26)
pkg/config/homedir/homedir.go (1)
  • Dir (36-63)
pkg/auth/types/aws_credentials.go (1)
  • AWSCredentials (16-23)
pkg/auth/types/mock_interfaces.go (1)
pkg/auth/types/interfaces.go (3)
  • ICredentials (198-209)
  • ValidationInfo (212-227)
  • ConsoleURLOptions (241-258)
pkg/auth/credentials/keyring_noop.go (3)
pkg/auth/types/interfaces.go (2)
  • ICredentials (198-209)
  • CredentialStoreTypeNoop (15-15)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/logger/log.go (1)
  • Debug (24-26)
pkg/auth/cloud/aws/env.go (3)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/logger/log.go (2)
  • Debug (24-26)
  • Errorf (59-61)
errors/errors.go (1)
  • ErrLoadAwsConfig (74-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Build (linux)
  • GitHub Check: Build (macos)
  • GitHub Check: Build (windows)
  • GitHub Check: autofix
  • GitHub Check: Analyze (go)
  • GitHub Check: Lint (golangci)
  • GitHub Check: website-deploy-preview
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: Summary
🔇 Additional comments (41)
pkg/auth/types/whoami_test.go (1)

21-21: Stub now satisfies interface surface.

Adding Type() keeps the stub aligned with CredentialStore. Looks good.

errors/errors.go (1)

382-385: Useful new error sentinels.

ErrAwsMissingEnvVars and ErrUserAborted align with flows added in auth. No issues.

pkg/auth/cloud/aws/files.go (2)

120-126: Good structured logging on credential writes.

Pre-write debug fields are helpful. No change needed.


197-204: Good config write logging.

Clear visibility into region/output. LGTM.

pkg/auth/types/interfaces.go (6)

12-18: Credential store type constants—nice taxonomy.

Clear, self-explanatory constants. LGTM.


155-160: AuthManager.GetEnvironmentVariables—useful for atmos env.

API shape looks right.


179-181: CredentialStore.Type—good for diagnostics.

This unblocks better error messages (used in Whoami). LGTM.


211-227: ValidationInfo shape looks solid.

Fields cover principal/account/expiration across clouds. LGTM.


205-209: No issues found—mocks and signatures are consistent.

All stale signatures are gone, mocks have been properly regenerated with the correct Validate(ctx context.Context) (*ValidationInfo, error) signature, and ValidationInfo is correctly imported and used throughout call sites.


88-97: All Identity implementations and mocks updated—verification complete.

Confirmed all Identity implementations (assumeRoleIdentity, userIdentity, permissionSetIdentity, mock.Identity, MockIdentity) now have both CredentialsExist and LoadCredentials methods. Generated mocks also include both methods with proper EXPECT recorders.

pkg/auth/manager.go (3)

197-221: Whoami noop-keyring fallback—exactly what containers need.

Handling ErrCredentialsNotFound by building from environment is the right behavior. Nice touch including credential_store type in errors.


301-306: Map TUI aborts to ErrUserAborted.

Clean UX; keeps CLI semantics predictable.


756-775: New manager.GetEnvironmentVariables—API and perf tracking look good.

Straightforward pass-through with identity existence check. LGTM.

pkg/auth/manager_logout.go (6)

14-15: Add performance tracking with nil atmosConfig.

The defer statement calls perf.Track with nil, which aligns with the coding guidelines for manager methods. However, ensure this is intentional.


110-150: LGTM on provider resolution logic.

The cycle detection and safe fallback handling are well-implemented. The function correctly traverses the identity chain to find the root provider.


152-214: LogoutProvider implementation looks solid.

The use of context values to skip nested provider logout during per-identity cleanup is a clean approach. Error aggregation maintains best-effort semantics.


216-239: LogoutAll implementation is clean.

Straightforward iteration over all identities with proper error aggregation.


40-40: No issues found—constant is defined at package scope.

The search confirms errFormatWrapTwo is defined in pkg/auth/manager.go at line 31 as a package-scoped constant. Since manager_logout.go is in the same package, it has full access to this constant. The code is correct.


48-48: No action needed—skipProviderLogoutKey is properly defined.

The verification confirms that skipProviderLogoutKey is defined at the package level in pkg/auth/manager.go:39 as a constant of type contextKey. The code at line 48 correctly references this package-level definition.

Likely an incorrect or invalid review comment.

pkg/auth/types/mock_interfaces.go (1)

198-211: New mock methods properly generated.

The additions for CredentialsExist, LoadCredentials, GetEnvironmentVariables, Type, and ConsoleAccessProvider follow correct gomock patterns and align with the interface updates described in the PR objectives.

Also applies to: 257-270, 382-395, 678-690, 852-904

pkg/auth/identities/aws/credentials_loader.go (5)

69-86: Environment variable validation looks good.

Clean validation with descriptive error message listing all required variables.


88-118: Environment setup and cleanup pattern is solid.

The save/restore pattern with cleanup function ensures environment variables are properly reset after credential loading.


120-146: SDK credential loading implementation is correct.

Proper use of AWS SDK with good error messages and context handling.


148-163: Expiration population logic handles both SDK and metadata sources.

Good fallback strategy when SDK doesn't provide expiration but session token exists.


165-227: Metadata parsing logic is robust.

The function safely handles missing or malformed metadata, returning empty string as fallback. RFC3339 validation ensures only valid timestamps are used.

cmd/auth_whoami.go (7)

55-68: Credential validation integration looks clean.

The validation flow is well-integrated, with results properly passed to the output functions.


72-105: Validation logic handles multiple credential types gracefully.

The type assertion pattern with fallback to expiration check provides good coverage. Populating whoami with validation info maintains data consistency.


107-121: Population helper is straightforward and safe.

Proper nil checks ensure no panics when validation info is incomplete.


165-179: Human output correctly uses stderr and theme colors.

The status indicator with colored checkmark/X provides immediate visual feedback. Using os.Stderr for UI output aligns with coding guidelines.


181-209: Table row builder is clean and conditional.

The function properly handles optional fields and delegates expiration formatting.


211-225: Expiration formatting provides clear urgency signals.

The threshold-based color coding (red for expiring soon, gray otherwise) gives users immediate visual feedback about credential freshness.


227-245: Table styling is consistent with UI theme.

The use of theme colors and clean borders creates professional output aligned with the rest of the CLI.

pkg/auth/identities/aws/credentials_loader_test.go (5)

18-105: Solid test coverage for metadata parsing.

Table-driven approach covers the key scenarios well: valid expiration, missing metadata, invalid format, wrong prefix, and profile-not-found cases.


107-110: LGTM.

Verifies graceful degradation when the credentials file doesn't exist.


112-148: Good end-to-end validation.

The round-trip test ensures metadata write and read operations work correctly, and the RFC3339 parsing confirms the timestamp format is valid.


150-238: Comprehensive environment variable validation.

All required/optional combinations are tested, and error checking properly uses ErrorIs to verify the specific error type.


382-453: Expiration logic well tested.

Covers SDK-provided expiration, non-session credentials (no expiration), and fallback behavior when metadata is unavailable.

pkg/auth/credentials/keyring_noop.go (4)

9-18: Clear documentation of noop store semantics.

The comments effectively explain that this store is for containerized environments where credentials are externally managed, and that it doesn't store or validate credentials.


20-45: Retrieve semantics are well-explained.

The extensive comments (lines 30-43) clearly document why validation isn't performed and why ErrCredentialsNotFound is returned, making the design intent obvious.


47-67: Consistent no-op implementations.

All methods properly signal that credentials aren't managed by this store, with appropriate return values for each contract.


68-85: Type() method properly documented.

The godoc comment follows the standard format, and the implementation correctly returns the noop store type constant.

osterman and others added 3 commits October 24, 2025 22:17
Enable `findFirstValidCachedCredentials` to find credentials stored in
AWS files (not just keyring) when validating the authentication chain.

This fixes the issue where:
1. User authenticates with a provider (e.g., core-identity/managers-team-access)
2. Provider credentials are stored in AWS credential files
3. Derived identities that depend on that provider fail to authenticate
   because the chain validation only checked the keyring

The fix adds a fallback to load credentials from identity storage (AWS
files, etc.) when the keyring returns `ErrCredentialsNotFound`, mirroring
the same pattern used in the Whoami command.

This enables chained authentication scenarios where provider credentials
exist in standard AWS credential files created by AWS CLI, SSO, or other
external tools, without requiring those credentials to be cached in the
system keyring first.

Refactored nested if/else blocks to use early returns for better
readability and to satisfy golangci-lint revive rules.

Note: Pre-existing lint violations in manager_logout.go (gocognit,
nestif, cyclomatic) are unrelated to this change and will be addressed
separately.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit addresses multiple issues with credential validation in the
authentication chain:

1. **System keyring ErrCredentialsNotFound detection**: Updated
   systemKeyringStore.Retrieve() to return ErrCredentialsNotFound when
   the underlying keyring returns keyring.ErrNotFound. This ensures
   consistent error handling across all credential store implementations
   and enables proper fallback logic.

2. **Credential validation based on actual expiration**: Fixed
   isCredentialValid() to check expiration from the credentials object
   itself, rather than querying the keyring. This allows validation of
   credentials loaded from any source (keyring, AWS files, etc.) based
   on their actual expiration time.

3. **Credential reloading for expired/invalid cached credentials**: Added
   logic to findFirstValidCachedCredentials() to attempt reloading from
   identity storage when cached credentials are expired or missing
   expiration metadata. This handles cases where:
   - Keyring has stale credentials without expiration info
   - AWS credential files have fresher credentials with valid expiration
   - External tools have updated credentials that aren't yet in keyring

4. **Enhanced Whoami fallback logic**: Updated Whoami() to:
   - First try loading from identity storage when keyring lookup fails
   - Fall back to chain authentication if direct loading fails
   - This enables whoami to work even when target identity credentials
     aren't directly available but can be derived through the chain

These changes improve the robustness of credential resolution, especially
in scenarios where credentials exist in AWS files but not in the system
keyring, or where keyring credentials are stale compared to file-based
credentials.

Note: Pre-existing lint violations in manager_logout.go (gocognit,
nestif, cyclomatic) are unrelated to these changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The `atmos auth logout` command was accepting the `--identity` flag inherited
from the parent `auth` command, but silently ignoring it and falling through
to interactive mode. This caused confusing UX where users would type:

  atmos auth logout --identity plat-dev/admin

And instead of logging out that specific identity, they would see an
interactive prompt asking what to logout, potentially logging out all
identities if they selected the wrong option.

**Changes:**
1. Added validation to detect when `--identity` flag is used with logout
2. Display clear error message explaining the correct usage:
   - Use positional argument: `atmos auth logout <identity-name>`
   - Not the flag: `atmos auth logout --identity <identity-name>`
3. Added test to ensure this validation stays in place
4. Added `logKeyChainIndex` constant to fix linter warning

**Root Cause:**
The `--identity` flag is a PersistentFlag on the parent `auth` command,
making it available to all subcommands (whoami, login, exec, etc.). However,
`logout` was designed to use positional arguments for identity names, not
the `--identity` flag. The flag was silently accepted but unused, causing
the confusing interactive prompt behavior.

**Related Issues:**
This also clarifies the distinction between identity logout (removes one
identity's credentials) vs provider logout (removes provider + all derived
identities).

Note: Pre-existing lint violations in manager_logout.go (gocognit, nestif,
cyclomatic) are unrelated to this change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
cmd/auth_logout_test.go (1)

341-345: Remove redundant cleanup - TestKit handles state restoration.

NewTestKit(t) already registers cleanup via t.Cleanup() to restore RootCmd state. The manual tk.Cleanup() call and flag reset are unnecessary and redundant.

Apply this diff:

 	tk := NewTestKit(t)
-	defer tk.Cleanup(func() {
-		// Reset the flag after test.
-		authLogoutCmd.Flags().Set("identity", "")
-	})
cmd/auth_logout.go (1)

63-74: Consider moving flag validation earlier for efficiency.

The validation logic is solid and provides clear user guidance. However, since it doesn't depend on atmosConfig or authManager, consider moving it earlier (after line 61) to fail fast before expensive config loading.

Optional refactor to move validation earlier:

 	// Get flags.
 	providerFlag, _ := cmd.Flags().GetString("provider")
 	dryRun, _ := cmd.Flags().GetBool("dry-run")
+
+	// Check if the inherited --identity flag was used (common mistake).
+	identityFlag, _ := cmd.Flags().GetString("identity")
+	if identityFlag != "" {
+		u.PrintfMarkdownToTUI("**Error:** The `--identity` flag is not supported by `atmos auth logout`.\n\n")
+		u.PrintfMarkdownToTUI("**Usage:**\n")
+		u.PrintfMessageToTUI("  Logout specific identity:  atmos auth logout <identity-name>\n")
+		u.PrintfMessageToTUI("  Logout specific provider:  atmos auth logout --provider <provider-name>\n")
+		u.PrintfMessageToTUI("  Logout all:                atmos auth logout\n\n")
+		u.PrintfMarkdownToTUI("**Example:**\n")
+		u.PrintfMessageToTUI("  atmos auth logout plat-dev/admin\n\n")
+		return fmt.Errorf("%w: use positional argument instead of --identity flag", errUtils.ErrInvalidFlag)
+	}
 
-	// Check if the inherited --identity flag was used (common mistake).
-	identityFlag, _ := cmd.Flags().GetString("identity")
-	if identityFlag != "" {
-		u.PrintfMarkdownToTUI("**Error:** The `--identity` flag is not supported by `atmos auth logout`.\n\n")
-		u.PrintfMarkdownToTUI("**Usage:**\n")
-		u.PrintfMessageToTUI("  Logout specific identity:  atmos auth logout <identity-name>\n")
-		u.PrintfMessageToTUI("  Logout specific provider:  atmos auth logout --provider <provider-name>\n")
-		u.PrintfMessageToTUI("  Logout all:                atmos auth logout\n\n")
-		u.PrintfMarkdownToTUI("**Example:**\n")
-		u.PrintfMessageToTUI("  atmos auth logout plat-dev/admin\n\n")
-		return fmt.Errorf("%w: use positional argument instead of --identity flag", errUtils.ErrInvalidFlag)
-	}
-
 	ctx := context.Background()

However, current placement is acceptable if you prefer to validate after config initialization.

pkg/auth/manager.go (2)

32-32: Remove unused constant.

The errFormatWrapTwo constant is defined but never used in this file. Dead code should be removed to keep the codebase clean.

Apply this diff:

-	errFormatWrapTwo         = "%w for %q: %w"

506-579: Good enhancement for external credential file support.

The dual-source credential loading (keyring + identity storage) correctly handles credentials created outside Atmos. The validity checking and reload logic are sound.

Optional: Consider extracting the credential retrieval/validation logic into helper methods to reduce the length of this function. The current implementation works well but could be more maintainable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1830d4e and a69ae29.

📒 Files selected for processing (4)
  • cmd/auth_logout.go (1 hunks)
  • cmd/auth_logout_test.go (1 hunks)
  • pkg/auth/credentials/keyring_system.go (2 hunks)
  • pkg/auth/manager.go (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/auth/credentials/keyring_system.go
🧰 Additional context used
📓 Path-based instructions (7)
cmd/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate

cmd/**/*.go: New CLI commands must use the command registry pattern via CommandProvider and register through the command registry (see cmd/internal/registry.go).
Commands should embed *_usage.md via //go:embed and render with utils.PrintfMarkdown().
UI (prompts/status) must write to stderr; data outputs to stdout; logging only for system events (never for UI).
For non-standard execution paths, capture telemetry with telemetry.CaptureCmd(); normal paths are auto-enabled via RootCmd.ExecuteC(). Never capture user data.

Files:

  • cmd/auth_logout.go
  • cmd/auth_logout_test.go
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • cmd/auth_logout.go
  • cmd/auth_logout_test.go
  • pkg/auth/manager.go
**/!(*_test).go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Document all exported functions, types, and methods with Go doc comments

Files:

  • cmd/auth_logout.go
  • pkg/auth/manager.go
{cmd,pkg/ui}/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use theme colors from pkg/ui/theme/colors.go for UI elements.

Files:

  • cmd/auth_logout.go
  • cmd/auth_logout_test.go
**/*_test.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + DI; table-driven tests for coverage; target >80% coverage.
Tests must exercise production code paths; avoid duplicating implementation logic in tests.
Use t.Skipf("reason") with clear context when skipping tests; CLI tests may auto-build temp binaries.

Files:

  • cmd/auth_logout_test.go
cmd/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use cmd.NewTestKit(t) for any tests that touch RootCmd to auto-clean RootCmd state.

Files:

  • cmd/auth_logout_test.go
pkg/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Place business logic in pkg rather than in cmd

Files:

  • pkg/auth/manager.go
🧠 Learnings (5)
📓 Common learnings
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: internal/exec/terraform.go:269-272
Timestamp: 2025-10-03T18:02:08.535Z
Learning: In internal/exec/terraform.go, when auth.TerraformPreHook fails, the error is logged but execution continues. This is a deliberate design choice to allow Terraform commands to proceed even if authentication setup fails, rather than failing fast.
📚 Learning: 2025-10-22T14:55:44.014Z
Learnt from: osterman
PR: cloudposse/atmos#1695
File: pkg/auth/manager.go:169-171
Timestamp: 2025-10-22T14:55:44.014Z
Learning: Go 1.20+ supports multiple %w verbs in fmt.Errorf, which returns an error implementing Unwrap() []error. This is valid and does not panic. Atmos uses Go 1.24.8 and configures errorlint with errorf-multi: true to validate this pattern.

Applied to files:

  • pkg/auth/manager.go
📚 Learning: 2025-09-10T22:38:42.212Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: pkg/auth/identities/aws/user.go:141-145
Timestamp: 2025-09-10T22:38:42.212Z
Learning: The user confirmed that the errors package has an error string wrapping format, contradicting the previous learning about ErrWrappingFormat being invalid. The current usage of fmt.Errorf(errUtils.ErrWrappingFormat, errUtils.ErrAuthAwsFileManagerFailed, err) appears to be the correct pattern.

Applied to files:

  • pkg/auth/manager.go
📚 Learning: 2025-09-10T22:38:42.212Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: pkg/auth/identities/aws/user.go:141-145
Timestamp: 2025-09-10T22:38:42.212Z
Learning: ErrWrappingFormat is correctly defined as "%w: %w" in the errors package and is used throughout the codebase to wrap two error types together. The usage fmt.Errorf(errUtils.ErrWrappingFormat, errUtils.ErrAuthAwsFileManagerFailed, err) is the correct pattern when both arguments are error types.

Applied to files:

  • pkg/auth/manager.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
PR: cloudposse/atmos#1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.

Applied to files:

  • pkg/auth/manager.go
🧬 Code graph analysis (3)
cmd/auth_logout.go (3)
pkg/utils/markdown_utils.go (1)
  • PrintfMarkdownToTUI (89-93)
pkg/utils/log_utils.go (1)
  • PrintfMessageToTUI (33-35)
errors/errors.go (1)
  • ErrInvalidFlag (108-108)
cmd/auth_logout_test.go (2)
cmd/testkit_test.go (1)
  • NewTestKit (55-65)
errors/errors.go (1)
  • ErrInvalidFlag (108-108)
pkg/auth/manager.go (5)
pkg/logger/log.go (2)
  • Errorf (59-61)
  • Debug (24-26)
errors/errors.go (6)
  • ErrIdentityNotFound (395-395)
  • ErrNoCredentialsFound (388-388)
  • ErrExpiredCredentials (389-389)
  • ErrMultipleDefaultIdentities (399-399)
  • ErrUserAborted (384-384)
  • ErrInvalidAuthConfig (370-370)
pkg/auth/credentials/keyring_file.go (1)
  • ErrCredentialsNotFound (36-36)
pkg/auth/types/interfaces.go (1)
  • ICredentials (198-209)
pkg/perf/perf.go (1)
  • Track (121-138)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Build (windows)
  • GitHub Check: Build (macos)
  • GitHub Check: prepare
  • GitHub Check: validate-codeowners
  • GitHub Check: website-deploy-preview
  • GitHub Check: PR Size Labeler
  • GitHub Check: Check for changelog entry
  • GitHub Check: PR Semver Labels
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Summary
🔇 Additional comments (4)
cmd/auth_logout_test.go (1)

348-356: Solid test coverage for flag validation.

The test correctly verifies that --identity flag usage triggers validation with appropriate error type and message. Clean assertions with ErrorIs and Contains.

cmd/auth_logout.go (1)

63-74: Clean validation with helpful user guidance.

The implementation correctly prevents --identity flag usage and provides clear examples directing users to the right approach. Error handling follows guidelines with proper wrapping and static error types.

pkg/auth/manager.go (2)

198-245: Solid fallback strategy for containerized environments.

The three-tier fallback (keyring → identity storage → chain auth) handles the noop keyring case well and aligns with the PR objectives. The extensive debug logging will help troubleshoot credential loading issues.


834-853: Clean implementation of environment variable retrieval.

The method follows coding guidelines with proper performance tracking and error wrapping. The delegation to identity.Environment() is appropriate.

…h commands

The `auth shell`, `auth exec`, `auth console`, and `auth env` commands were
calling `Authenticate()` directly, which forces a full authentication flow
(including SSO device prompts) even when valid cached credentials already exist.

This caused poor UX where users would run `auth whoami` and see valid
credentials, then run `auth shell` and be prompted to login again despite
having 1+ hours remaining on their session.

**Changes:**
1. Updated all auth commands to call `Whoami()` first
2. Only fallback to `Authenticate()` if `Whoami()` fails (no cached creds)
3. Added debug logging to show when fallback authentication is triggered
4. Added missing log import to `auth_exec.go`

**Behavior:**
- `auth login` - Still forces fresh authentication (correct behavior)
- `auth whoami` - Already used `Whoami()` (no change needed)
- `auth shell` - Now checks cache first ✓
- `auth exec` - Now checks cache first ✓
- `auth console` - Now checks cache first ✓
- `auth env --login` - Now checks cache first ✓

**Benefits:**
- Eliminates unnecessary SSO prompts when credentials are valid
- Provides seamless experience across auth commands
- Reduces authentication latency (cached lookup vs full flow)
- Consistent behavior: all commands respect cached credentials

**Testing:**
Verified that `auth shell` with valid cached credentials (38 min remaining)
successfully uses the cache without triggering authentication flow.

Note: Pre-existing lint violations in manager_logout.go (gocognit, nestif,
cyclomatic) are unrelated to this change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@aknysh aknysh merged commit 1eda3a2 into main Oct 28, 2025
54 checks passed
@aknysh aknysh deleted the osterman/fix-aws-profile-identity-selection branch October 28, 2025 02:51
@mergify mergify bot removed the needs-cloudposse Needs Cloud Posse assistance label Oct 28, 2025
@github-actions
Copy link

These changes were released in v1.196.0-test.3.

@github-actions
Copy link

These changes were released in v1.196.0-rc.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor New features that do not break anything size/xl Extra large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants