Skip to content

Suggest profiles when no auth config; clean up legacy keyring entries#2154

Merged
aknysh merged 10 commits intomainfrom
osterman/auth-suggest-profile
Mar 16, 2026
Merged

Suggest profiles when no auth config; clean up legacy keyring entries#2154
aknysh merged 10 commits intomainfrom
osterman/auth-suggest-profile

Conversation

@osterman
Copy link
Copy Markdown
Member

@osterman osterman commented Mar 8, 2026

what

  • Fix: Propagate auth realm through CopyGlobalAuthConfig and buildGlobalAuthSection so that ExecuteTerraform (both single-component and --all paths) uses the correct realm for credential storage. This is the root cause fix for Auth realm not considered when using --all option #2187.
    • CopyGlobalAuthConfig in pkg/auth/config_helpers.go was missing Realm and RealmSource fields — when --all iterates components, each call to CopyGlobalAuthConfig produced an auth config with an empty realm
    • buildGlobalAuthSection in internal/exec/utils_auth.go was not including realm in the auth map — the deep-merge path lost the realm value
  • When running atmos auth list with no providers/identities configured, Atmos now checks if profiles exist and suggests using the --profile flag to load auth configuration from profile-specific atmos.yaml files
  • After successfully caching credentials under the current realm, legacy (pre-realm) keyring entries are automatically cleaned up to prevent realm mismatch warnings
  • Uses the error builder pattern with ErrAuthNotConfigured sentinel error for rich, helpful error messages
  • Improved error message when identity kind is empty (not configured in active profile)

why

When running atmos terraform plan -s <stack> --all, credentials were stored without the auth realm in the path, causing realm mismatch warnings. Single-component runs (atmos terraform plan <component> -s <stack>) worked correctly because they used a different code path that preserved the realm. The two-line root cause fix ensures realm propagation through both paths.

Users working with profile-based configurations (like infra-live) need better guidance when auth config is not in the base atmos.yaml. Suggesting available profiles reduces friction and helps users discover the correct workflow.

The keyring cleanup prevents accumulated migration warnings when users upgrade to realm-aware credential management and transition between different credential storage locations.

testing

  • Unit tests verify Realm/RealmSource are copied in CopyGlobalAuthConfig (including deep-copy mutation safety)
  • Unit tests verify realm is included/excluded in buildGlobalAuthSection based on whether it's set
  • Integration tests verify realm propagation through getMergedAuthConfigWithFetcher (the --all code path)
  • Tests confirm no-realm configurations continue to work correctly (backward compatibility)
  • Tests for profile suggestion, legacy credential cleanup, and empty identity kind error messages
  • Updated golden snapshots reflecting realm now appearing in describe component output

references

Summary by CodeRabbit

  • New Features

    • Auth list now suggests available profiles and shows a --profile usage hint when no auth providers or identities are configured.
  • Improvements

    • Automatic cleanup of legacy credential files and keyring entries after successful authentication to prevent realm-mismatch warnings.
    • Auth configuration now preserves and exposes a realm value where applicable; CLI describe output snapshots updated.
  • Bug Fixes

    • Clearer, actionable error when an identity is missing its kind, including guidance to list/select profiles.
  • Tests

    • Expanded tests for profile suggestions, realm propagation, merging, and legacy cleanup edge cases.

@osterman osterman requested a review from a team as a code owner March 8, 2026 17:21
@github-actions github-actions bot added the size/m Medium size PR label Mar 8, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 8, 2026

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Threads AtmosConfiguration through the auth-list flow to suggest profiles when no auth is configured, adds realm propagation into global auth copies, and implements cleanup of legacy pre-realm keyring entries and credential files after authentication or credential storage.

Changes

Cohort / File(s) Summary
Auth list CLI
cmd/auth_list.go, cmd/auth_list_test.go
loadAuthManagerForList now returns (*schema.AtmosConfiguration); added suggestProfilesForAuth(atmosConfig) and call sites to surface profile hints when no auth providers/identities exist. Tests added for profile suggestions and empty-profile behavior.
Legacy credential cleanup (auth manager)
pkg/auth/realm_mismatch.go, pkg/auth/realm_mismatch_test.go, pkg/auth/manager_whoami.go, pkg/auth/manager.go
New methods deleteLegacyKeyringEntry and deleteLegacyCredentialFiles added and invoked after successful auth or credential storage to remove pre-realm keyring entries and AWS creds/config files. Extensive tests cover empty realm, nil store, file/lock cleanup and error paths.
Auth config realm propagation & helpers
pkg/auth/config_helpers.go, internal/exec/utils_auth.go, internal/exec/utils_auth_test.go, pkg/auth/config_helpers_test.go
Copy/merge helpers now include Realm and RealmSource propagation into global/auth merges; tests extended to verify realm survives merges and round trips.
Factory & identity validation
pkg/auth/factory/factory.go, pkg/auth/factory/factory_test.go, pkg/auth/manager_test.go
Identity factory now returns explicit error when config.Kind is empty. initializeIdentities adds validation to return structured errors pointing to profiles when identity kind is missing; tests added to assert error contents.
Snapshots / CLI output
tests/snapshots/...
Multiple golden snapshots updated to include populated auth.realm values where previously auth was empty.
Misc tests & small changes
cmd/auth_list_test.go, internal/exec/utils_auth_test.go, pkg/auth/config_helpers_test.go, pkg/auth/manager_test.go
Added/updated tests, imports, and test helpers to exercise new flows and error hints. Some tests appear duplicated in the diff and may need deduplication.

Sequence Diagram(s)

sequenceDiagram
participant CLI as CLI (auth list)
participant Cmd as Cobra Command
participant Atmos as AtmosConfig
participant Profile as ProfileManager
participant User as Terminal

CLI->>Cmd: invoke auth list
Cmd->>Atmos: loadAuthManagerForList(cmd)
Atmos-->>CLI: (authManager, atmosConfig)
CLI->>Profile: suggestProfilesForAuth(atmosConfig)
Profile-->>CLI: profiles[]
alt profiles found
CLI->>User: return ErrAuthNotConfigured with hints (profile names, --profile)
else no profiles
CLI->>User: continue without suggestion
end
Loading
sequenceDiagram
participant Auth as AuthManager
participant Chain as AuthChain/Steps
participant Keyring as CredentialStore
participant FS as Filesystem
participant Logger as Logger

Auth->>Chain: Authenticate()
Chain-->>Auth: credentials (session or non-session)
alt non-session credentials stored
Auth->>Keyring: store credentials
Auth->>Auth: deleteLegacyKeyringEntry(alias)
Auth->>FS: deleteLegacyCredentialFiles()
Logger-->>Auth: log deletions or non-existence
end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main changes: suggesting profiles when auth is missing and cleaning up legacy keyring entries.
Linked Issues check ✅ Passed The PR addresses the core issue #2187 by propagating realm through auth config [internal/exec/utils_auth.go], cleaning legacy entries after auth [pkg/auth/manager_whoami.go, pkg/auth/manager.go], and improving error messaging. Realm propagation in buildGlobalAuthSection fixes the --all path.
Out of Scope Changes check ✅ Passed All changes stay focused on auth realm handling, legacy cleanup, profile suggestions, and related test coverage. No unrelated modifications detected outside the stated scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch osterman/auth-suggest-profile
📝 Coding Plan
  • Generate coding plan for human review comments

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
Copy Markdown
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: 3

🧹 Nitpick comments (1)
pkg/auth/realm_mismatch_test.go (1)

295-349: These cleanup cases want one table-driven test.

The three new tests only vary by realm/store setup and expected outcome. Folding them into a single table will make future realm cases much cheaper to add and keep this file aligned with the repo’s test style.

As per coding guidelines, "**/*_test.go: Use table-driven tests for testing multiple scenarios in Go."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/auth/realm_mismatch_test.go` around lines 295 - 349, Combine the three
tests into one table-driven test that iterates scenarios for different
realm/store setups and expected outcomes: create a slice of test cases with
fields like name, store data (using realmAwareTestStore), realm
(realm.RealmInfo), and expectedError bool; loop over cases with t.Run and inside
call m := &manager{credentialStore: tc.store, realm: tc.realm} followed by
m.deleteLegacyKeyringEntry("my-identity") and assertions that check Retrieve
results based on tc.expectedError; keep the existing test logic (checks for
deletion/no-op/nil store not panicking) and reuse identifiers from the diff such
as deleteLegacyKeyringEntry, realmAwareTestStore, manager, and realm.RealmInfo
so the refactor is purely structural and preserves behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/auth_list.go`:
- Around line 403-417: The helper loadAuthManagerForList currently calls
cfg.InitCliConfig with an empty schema.ConfigAndStacksInfo, ignoring global
selection flags; change the function signature to accept the cobra command (cmd)
and use flags.ParseGlobalFlags(cmd, v) to populate a ConfigAndStacksInfo
instance, then pass that populated struct into cfg.InitCliConfig so --profile,
--config, --base-path, etc. are respected; keep existing error wrapping and the
subsequent createAuthManager(&atmosConfig.Auth, atmosConfig.CliConfigPath) usage
unchanged and add a regression test for the --profile case.

In `@pkg/auth/realm_mismatch_test.go`:
- Around line 361-406: Remove the hand-rolled realmAwareTestStore and instead
use a generated mock for the CredentialStore interface (or extend the existing
generated test double); add or update a //go:generate mockgen directive to
produce a mock for the CredentialStore, then modify the tests to configure the
mock's Store, Retrieve, Delete, List, IsExpired and Type method
expectations/returns (using types.ICredentials where needed) to simulate
per-realm behavior rather than keeping realmAwareTestStore with methods Store,
Retrieve, Delete, List, IsExpired, Type in the test file.

In `@pkg/auth/realm_mismatch.go`:
- Around line 130-133: The current Delete error handling in the
m.credentialStore.Delete(alias, "") call treats all errors as "No legacy keyring
entry to delete"; change it to detect the store's not-found condition and only
log the "no legacy keyring entry" message for that case, while logging a
distinct, detailed error (including the error value) for any other failures so
real keyring/backend errors are visible; update the branch around
m.credentialStore.Delete(...) to check for the store-specific not-found sentinel
(or call like errors.Is(err, store.ErrNotFound) / err ==
credentialstore.ErrNotFound) and call log.Debug(...) for not-found but
log.Error(...) (with alias and err) for other errors.

---

Nitpick comments:
In `@pkg/auth/realm_mismatch_test.go`:
- Around line 295-349: Combine the three tests into one table-driven test that
iterates scenarios for different realm/store setups and expected outcomes:
create a slice of test cases with fields like name, store data (using
realmAwareTestStore), realm (realm.RealmInfo), and expectedError bool; loop over
cases with t.Run and inside call m := &manager{credentialStore: tc.store, realm:
tc.realm} followed by m.deleteLegacyKeyringEntry("my-identity") and assertions
that check Retrieve results based on tc.expectedError; keep the existing test
logic (checks for deletion/no-op/nil store not panicking) and reuse identifiers
from the diff such as deleteLegacyKeyringEntry, realmAwareTestStore, manager,
and realm.RealmInfo so the refactor is purely structural and preserves behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 385c631a-2975-4ea2-963a-085a8d162bcd

📥 Commits

Reviewing files that changed from the base of the PR and between f0ab0c7 and 559121d.

📒 Files selected for processing (6)
  • cmd/auth_list.go
  • cmd/auth_list_test.go
  • pkg/auth/manager_chain.go
  • pkg/auth/manager_whoami.go
  • pkg/auth/realm_mismatch.go
  • pkg/auth/realm_mismatch_test.go

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 8, 2026

Codecov Report

❌ Patch coverage is 91.57895% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.43%. Comparing base (9b7152a) to head (6599e73).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/auth/realm_mismatch.go 82.85% 3 Missing and 3 partials ⚠️
cmd/auth_list.go 93.75% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2154      +/-   ##
==========================================
+ Coverage   77.40%   77.43%   +0.02%     
==========================================
  Files         962      962              
  Lines       91318    91406      +88     
==========================================
+ Hits        70686    70779      +93     
+ Misses      16551    16543       -8     
- Partials     4081     4084       +3     
Flag Coverage Δ
unittests 77.43% <91.57%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/exec/utils_auth.go 96.34% <100.00%> (+0.13%) ⬆️
pkg/auth/config_helpers.go 90.47% <100.00%> (+0.31%) ⬆️
pkg/auth/factory/factory.go 92.94% <100.00%> (+0.17%) ⬆️
pkg/auth/manager.go 81.96% <100.00%> (+0.95%) ⬆️
pkg/auth/manager_whoami.go 100.00% <100.00%> (ø)
cmd/auth_list.go 78.60% <93.75%> (+4.69%) ⬆️
pkg/auth/realm_mismatch.go 93.81% <82.85%> (-6.19%) ⬇️

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@osterman osterman added the patch A minor, backward compatible change label Mar 8, 2026
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/auth/manager.go`:
- Around line 234-240: The docstring for deleteLegacyKeyringEntry in
realm_mismatch.go is inaccurate about when it runs; update the comment to
reflect that deleteLegacyKeyringEntry (and deleteLegacyCredentialFiles) are
invoked early in Authenticate (before authenticateChain and buildWhoamiInfo) and
therefore remove legacy entries unconditionally rather than only "after
credentials have been successfully stored under the current realm." Edit the
docstring to state the actual contract: these functions perform proactive
cleanup at the start of the Authenticate flow and may remove legacy credentials
even if subsequent authentication fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0a0bf080-b163-45a2-8680-75a03a829a1c

📥 Commits

Reviewing files that changed from the base of the PR and between 559121d and 7dccf89.

📒 Files selected for processing (3)
  • pkg/auth/manager.go
  • pkg/auth/realm_mismatch.go
  • pkg/auth/realm_mismatch_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/auth/realm_mismatch.go

Copy link
Copy Markdown
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: 3

♻️ Duplicate comments (1)
cmd/auth_list.go (1)

402-417: ⚠️ Potential issue | 🟠 Major

This helper still drops --profile.

schema.ConfigAndStacksInfo is still assembled by hand and only forwards three selection flags. atmos auth list --profile <name> will keep loading the base config here and can incorrectly trigger the new suggestion path. Please use the shared global-flag parser instead of copying a subset.

Based on learnings, "cfg.InitCliConfig must receive a schema.ConfigAndStacksInfo populated via flags.ParseGlobalFlags(cmd, v) because LoadConfig reads config selection fields directly from that struct; passing an empty struct makes --base-path, --config, --config-path, and --profile silently ignored."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/auth_list.go` around lines 402 - 417, loadAuthManagerForList builds
schema.ConfigAndStacksInfo manually and omits the --profile (and other global)
flags, causing cfg.InitCliConfig to receive an incomplete struct; replace the
manual assembly with the shared global-flag parser by calling
flags.ParseGlobalFlags(cmd, &configAndStacksInfo) (or the equivalent used
project-wide) so schema.ConfigAndStacksInfo is fully populated (including
profile, base-path, config, config-path) before calling cfg.InitCliConfig in
loadAuthManagerForList.
🧹 Nitpick comments (1)
pkg/auth/realm_mismatch_test.go (1)

334-355: Please cover the lock-file and directory cleanup paths too.

deleteLegacyCredentialFiles now removes credentials.lock, config.lock, and then prunes empty directories, but this test only asserts the two main files. A couple more assertions here would close the remaining coverage gap around the new behavior.

As per coding guidelines, "Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/auth/realm_mismatch_test.go` around lines 334 - 355, The test
TestDeleteLegacyCredentialFiles_CleansUpNoRealmFiles only checks deletion of
credentials and config; enhance it to also create credentials.lock and
config.lock in providerDir before calling m.deleteLegacyCredentialFiles() and
assert those lock files are removed (os.IsNotExist), and finally assert that the
providerDir (or the empty ancestor directories like atmos/aws/my-provider) have
been pruned by checking that filepath.Join(parent, "atmos", "aws",
"my-provider") (or its parents) does not exist after cleanup; reference the
manager.deleteLegacyCredentialFiles function and the files named
"credentials.lock" and "config.lock" when adding these assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/auth_list.go`:
- Around line 155-161: The suggestion gating is using the filtered results
(filteredProviders/filteredIdentities) after applyFilters, which can be empty
even when auth is configured; change the condition so
suggestProfilesForAuth(atmosConfig) is invoked based on the unfiltered auth
config (e.g., check atmosConfig.Auth.Providers and atmosConfig.Auth.Identities
or the original providers/identities variables) instead of
filteredProviders/filteredIdentities, ensuring profiles are suggested when any
providers or identities exist in the config.

In `@pkg/auth/realm_mismatch.go`:
- Around line 123-177: The helpers deleteLegacyKeyringEntry and
deleteLegacyCredentialFiles are being invoked before authenticateChain, which
prematurely purges legacy credentials even if authentication or writing the new
realm-scoped credentials fails; move the calls so they run only after a
successful authentication and after the code that writes the new realm-scoped
credentials completes (i.e., remove any pre-auth calls to
deleteLegacyKeyringEntry and deleteLegacyCredentialFiles and invoke them in the
post-success path immediately after authenticateChain returns successfully and
after the new credential write routine finishes).

---

Duplicate comments:
In `@cmd/auth_list.go`:
- Around line 402-417: loadAuthManagerForList builds schema.ConfigAndStacksInfo
manually and omits the --profile (and other global) flags, causing
cfg.InitCliConfig to receive an incomplete struct; replace the manual assembly
with the shared global-flag parser by calling flags.ParseGlobalFlags(cmd,
&configAndStacksInfo) (or the equivalent used project-wide) so
schema.ConfigAndStacksInfo is fully populated (including profile, base-path,
config, config-path) before calling cfg.InitCliConfig in loadAuthManagerForList.

---

Nitpick comments:
In `@pkg/auth/realm_mismatch_test.go`:
- Around line 334-355: The test
TestDeleteLegacyCredentialFiles_CleansUpNoRealmFiles only checks deletion of
credentials and config; enhance it to also create credentials.lock and
config.lock in providerDir before calling m.deleteLegacyCredentialFiles() and
assert those lock files are removed (os.IsNotExist), and finally assert that the
providerDir (or the empty ancestor directories like atmos/aws/my-provider) have
been pruned by checking that filepath.Join(parent, "atmos", "aws",
"my-provider") (or its parents) does not exist after cleanup; reference the
manager.deleteLegacyCredentialFiles function and the files named
"credentials.lock" and "config.lock" when adding these assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e1ab234d-99b1-49f6-b293-5963add9c070

📥 Commits

Reviewing files that changed from the base of the PR and between 7dccf89 and ce9cf90.

📒 Files selected for processing (3)
  • cmd/auth_list.go
  • pkg/auth/realm_mismatch.go
  • pkg/auth/realm_mismatch_test.go

Copy link
Copy Markdown
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.

♻️ Duplicate comments (4)
pkg/auth/manager.go (1)

279-285: ⚠️ Potential issue | 🟠 Major

Keep the target identity out of this cleanup loop for keyring-backed creds.

Line 283 still iterates over identityName, but in pkg/auth/manager_whoami.go, Lines 43-51, buildWhoamiInfo only removes that legacy alias after Store(identityName, creds, m.realm.Value) succeeds. For non-session credentials, this can still delete the fallback entry before the new realm-scoped write lands.

Suggested fix
 m.deleteLegacyCredentialFiles()
 for _, step := range chain {
+	if step == identityName && !isSessionToken(finalCreds) {
+		continue
+	}
 	m.deleteLegacyKeyringEntry(step)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/auth/manager.go` around lines 279 - 285, The cleanup loop is removing the
target identity's legacy keyring entry prematurely; change the loop that calls
m.deleteLegacyKeyringEntry(step) so it skips the current identityName (the
target identity used in buildWhoamiInfo/Store) — i.e., if step == identityName
then continue — ensuring the target's legacy alias is not deleted before
Store(identityName, creds, m.realm.Value) completes; keep
m.deleteLegacyCredentialFiles() as-is.
cmd/auth_list.go (1)

403-418: ⚠️ Potential issue | 🟠 Major

loadAuthManagerForList still drops --profile.

Line 407 hand-copies only base-path, config, and config-path into ConfigAndStacksInfo; ProfilesFromArg never gets populated. atmos auth list --profile <name> can still load the base config and then suggest the same profile the user already selected. Please use the standard global flag parser here instead of open-coding a subset.

Based on learnings, cfg.InitCliConfig must receive a schema.ConfigAndStacksInfo populated via flags.ParseGlobalFlags(cmd, v) because LoadConfig reads config selection fields directly from that struct; passing an empty or partial struct makes --base-path, --config, --config-path, and --profile silently ignored.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/auth_list.go` around lines 403 - 418, loadAuthManagerForList currently
hand-copies a subset of flags into a schema.ConfigAndStacksInfo and therefore
drops --profile; replace the manual flag handling with the standard parser by
calling flags.ParseGlobalFlags(cmd, &configAndStacksInfo) (or the equivalent
global flag parsing helper) to populate schema.ConfigAndStacksInfo before
calling cfg.InitCliConfig so ProfilesFromArg (and other global flags) are
respected; update references to configAndStacksInfo, loadAuthManagerForList,
cfg.InitCliConfig, and flags.ParseGlobalFlags accordingly.
pkg/auth/realm_mismatch.go (2)

131-133: ⚠️ Potential issue | 🟡 Minor

Surface real keyring cleanup failures.

Right now every delete miss/backend failure lands in the same debug path. Please keep the expected “already gone” case at debug, but promote unexpected keyring/backend errors so migration cleanup failures stay visible.

Based on learnings, "Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/auth/realm_mismatch.go` around lines 131 - 133, The delete call in
m.credentialStore.Delete (pkg/auth/realm_mismatch.go) currently logs all
failures at debug; change it to distinguish the expected "already gone" case
from real backend errors: detect the not-found condition using the credential
store's sentinel error (e.g., keyring.ErrNotFound or a provided
IsNotFound/IsNotExist helper) or by matching the well-known error text, and keep
that case at Debug with alias context; for any other error log at Error (or
Warn) level with full error details and alias so migration cleanup failures are
visible and actionable.

145-177: ⚠️ Potential issue | 🟠 Major

Don’t purge every legacy provider tree after one login.

This helper removes legacy files for all aws/<provider>/... directories, even though a successful auth only refreshes one root provider chain. That means logging into one provider can erase fallback files for unrelated providers that have not been re-cached under the current realm yet. Please scope this to the provider that just wrote fresh state, or move it behind a provider-owned cleanup hook.

Based on learnings, "The auth manager in pkg/auth/manager.go should remain cloud-agnostic and not contain AWS-specific logic or references to specific cloud providers. Keep the manager generic and extensible."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/auth/realm_mismatch.go` around lines 145 - 177, The
deleteLegacyCredentialFiles method on manager currently deletes every provider
subtree under awsDirNameForMismatch, which can purge unrelated providers after a
single login; change it to only target the specific provider that just refreshed
state by accepting (or using) a provider identifier instead of iterating all
entries — e.g., update deleteLegacyCredentialFiles to take a providerName (or
make it a method on the provider/credential owner) and only remove files under
filepath.Join(awsDirNameForMismatch, providerName), or alternatively remove this
AWS-specific logic from manager and call a provider-owned cleanup hook from the
provider implementation; also remove direct AWS-specific symbols from the
generic auth manager so it remains cloud-agnostic (use an injected provider
cleanup interface rather than awsDirNameForMismatch inside manager).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@cmd/auth_list.go`:
- Around line 403-418: loadAuthManagerForList currently hand-copies a subset of
flags into a schema.ConfigAndStacksInfo and therefore drops --profile; replace
the manual flag handling with the standard parser by calling
flags.ParseGlobalFlags(cmd, &configAndStacksInfo) (or the equivalent global flag
parsing helper) to populate schema.ConfigAndStacksInfo before calling
cfg.InitCliConfig so ProfilesFromArg (and other global flags) are respected;
update references to configAndStacksInfo, loadAuthManagerForList,
cfg.InitCliConfig, and flags.ParseGlobalFlags accordingly.

In `@pkg/auth/manager.go`:
- Around line 279-285: The cleanup loop is removing the target identity's legacy
keyring entry prematurely; change the loop that calls
m.deleteLegacyKeyringEntry(step) so it skips the current identityName (the
target identity used in buildWhoamiInfo/Store) — i.e., if step == identityName
then continue — ensuring the target's legacy alias is not deleted before
Store(identityName, creds, m.realm.Value) completes; keep
m.deleteLegacyCredentialFiles() as-is.

In `@pkg/auth/realm_mismatch.go`:
- Around line 131-133: The delete call in m.credentialStore.Delete
(pkg/auth/realm_mismatch.go) currently logs all failures at debug; change it to
distinguish the expected "already gone" case from real backend errors: detect
the not-found condition using the credential store's sentinel error (e.g.,
keyring.ErrNotFound or a provided IsNotFound/IsNotExist helper) or by matching
the well-known error text, and keep that case at Debug with alias context; for
any other error log at Error (or Warn) level with full error details and alias
so migration cleanup failures are visible and actionable.
- Around line 145-177: The deleteLegacyCredentialFiles method on manager
currently deletes every provider subtree under awsDirNameForMismatch, which can
purge unrelated providers after a single login; change it to only target the
specific provider that just refreshed state by accepting (or using) a provider
identifier instead of iterating all entries — e.g., update
deleteLegacyCredentialFiles to take a providerName (or make it a method on the
provider/credential owner) and only remove files under
filepath.Join(awsDirNameForMismatch, providerName), or alternatively remove this
AWS-specific logic from manager and call a provider-owned cleanup hook from the
provider implementation; also remove direct AWS-specific symbols from the
generic auth manager so it remains cloud-agnostic (use an injected provider
cleanup interface rather than awsDirNameForMismatch inside manager).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2adf2568-2fed-434e-8ac9-8ba5fc819748

📥 Commits

Reviewing files that changed from the base of the PR and between ce9cf90 and 87b6d04.

📒 Files selected for processing (4)
  • cmd/auth_list.go
  • pkg/auth/manager.go
  • pkg/auth/realm_mismatch.go
  • pkg/auth/realm_mismatch_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/auth/realm_mismatch_test.go

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 10, 2026
coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 10, 2026
@osterman osterman force-pushed the osterman/auth-suggest-profile branch from 7a7c49d to 27ecd00 Compare March 11, 2026 00:19
osterman and others added 6 commits March 12, 2026 10:21
…g entries

- Add profile discovery hint to `atmos auth list` when no providers/identities configured
- Use error builder pattern with ErrAuthNotConfigured sentinel for rich error messages
- Suggest using --profile flag to load auth from profiles (e.g. profiles/developers/)
- Clean up legacy (pre-realm) keyring entries after successful credential caching
- Prevent realm mismatch warnings by removing outdated keyring entries
- Add comprehensive tests for profile suggestion logic and edge cases

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
After switching to realm-scoped credentials (auth.realm), old credentials
stored without a realm triggered a persistent warning on every command.
The cleanup now runs in Authenticate() so it executes even when cached
credentials allow the provider auth step to be skipped. Removes both
legacy keyring entries and file-based credentials at the no-realm path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pass global flags (--base-path, --config, --config-path) through
  loadAuthManagerForList so config selection flags are respected
- Fix misleading error log in deleteLegacyKeyringEntry to report actual
  keyring failures instead of "no legacy entry"
- Replace hand-rolled realmAwareTestStore with generated MockCredentialStore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…h.go

Update deleteLegacyKeyringEntry and deleteLegacyCredentialFiles docstrings
to accurately reflect that they run early in the Authenticate flow before
authenticateChain, removing legacy entries unconditionally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use unfiltered providers/identities for profile suggestion gate to avoid
  false positives when filters narrow results to empty
- Move legacy credential cleanup to post-success path so fallback
  credentials remain if authentication fails
- Add TODO for refactoring AWS-specific cleanup into provider-owned hook
- Add tests for uncovered paths to improve patch coverage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store implementations already handle not-found internally (returning nil),
so any error reaching deleteLegacyKeyringEntry is a real backend failure
that deserves Warn-level visibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@osterman osterman force-pushed the osterman/auth-suggest-profile branch from 27ecd00 to c9b919b Compare March 12, 2026 15:21
…profile

Replace the confusing "unsupported identity kind: " error (with dangling colon)
with context-aware messages that explain the actual problem and suggest next steps.
With a profile active: "Identity is not configured in the `marketplace` profile."
Without a profile: "Identity is not configured. Did you forget to specify a profile?"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aknysh and others added 2 commits March 16, 2026 11:34
…lAuthSection (#2187)

When running `atmos terraform plan -s <stack> --all`, the realm was lost because
CopyGlobalAuthConfig omitted Realm/RealmSource fields and buildGlobalAuthSection
omitted realm from the auth map. This caused credentials to be stored under the
wrong path, triggering realm mismatch warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aknysh
Copy link
Copy Markdown
Member

aknysh commented Mar 16, 2026

@coderabbitai full review please.
Also check if this PR fixes the issues reported in #2187

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 16, 2026

🧩 Analysis chain

Let me fetch the issue details directly.


🏁 Script executed:

#!/bin/bash
gh issue view 2187 --repo cloudposse/atmos

Length of output: 1290


@aknysh: On it! Triggering a full review now.

Regarding issue #2187 — here's my assessment:

Issue #2187 reports that atmos terraform plan -s <stack> --all stores credentials in the legacy path (.config/atmos/aws/) instead of the realm-namespaced path (.config/atmos/<realm>/), triggering a realm mismatch warning on subsequent runs.

Does PR #2154 fix it?

  • Partially / indirectly. The PR adds deleteLegacyCredentialFiles() and deleteLegacyKeyringEntry(step) calls in manager.go that run after successful authentication. This means after a user performs atmos auth login, the legacy entries under aws/ will be cleaned up, which prevents the mismatch warning on future runs.
  • Root cause is not addressed. The core issue — that --all stores credentials without the realm prefix in the first place — does not appear to be fixed in this PR. The cleanup is reactive (happens post-auth), not preventative (fixing the storage path during --all execution).
  • A follow-up issue or PR would be needed to ensure the --all code path uses the realm-aware credential storage path consistently.

🧠 Learnings used
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.

Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:37.766Z
Learning: cloudposse/atmos: For PRD docs (docs/prd/*.md), markdownlint issues like MD040/MD010/MD034 can be handled in a separate documentation cleanup commit and should not block the current PR.

Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.

Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/http_client_test.go:3-10
Timestamp: 2025-09-10T21:17:55.273Z
Learning: In the cloudposse/atmos repository, imports should never be changed as per samtholiya's coding guidelines.

Learnt from: osterman
Repo: cloudposse/atmos PR: 768
File: internal/exec/vendor_utils.go:496-513
Timestamp: 2024-11-22T12:38:33.132Z
Learning: In the Atmos project, continue to flag path traversal issues in code reviews but acknowledge when they are expected and acceptable in specific cases.

Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.

Learnt from: osterman
Repo: cloudposse/atmos PR: 1714
File: NOTICE:0-0
Timestamp: 2025-11-01T20:24:29.557Z
Learning: In the cloudposse/atmos repository, the NOTICE file is programmatically generated and should not be manually edited. Issues with dependency license URLs in NOTICE will be resolved when upstream package metadata is corrected.

Learnt from: aknysh
Repo: cloudposse/atmos PR: 1185
File: internal/exec/yaml_func_store.go:26-26
Timestamp: 2025-04-04T02:03:23.676Z
Learning: The Atmos codebase currently uses `log.Fatal` for error handling in multiple places. The maintainers are aware this isn't an ideal pattern (should only be used in main() or init() functions) and plan to address it comprehensively in a separate PR. CodeRabbit should not flag these issues or push for immediate changes until that refactoring is complete.

Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: errors/errors.go:184-203
Timestamp: 2025-12-13T06:10:13.688Z
Learning: cloudposse/atmos: For toolchain work, duplicate/unused error sentinels in errors/errors.go should be cleaned up in a separate refactor PR and not block feature PRs; canonical toolchain sentinels live under toolchain/registry with re-exports in toolchain/errors.go.

Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: agent-skills/AGENTS.md:0-0
Timestamp: 2026-03-03T16:29:20.024Z
Learning: Applies to agent-skills/**/atmos.yaml : Configure authentication providers (SSO, SAML, OIDC, GCP) and identities (AWS, Azure, GCP) in atmos.yaml with keyring storage support
✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
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: 3

♻️ Duplicate comments (1)
cmd/auth_list.go (1)

407-418: ⚠️ Potential issue | 🟠 Major

loadAuthManagerForList still ignores --profile and other global selectors.

The manual flag copy only captures base-path/config/config-path. It still drops profile selection fields, so atmos auth list --profile <name> can load base config and incorrectly trigger profile suggestions.

🐛 Proposed fix
 import (
 	_ "embed"
 	"encoding/json"
 	"fmt"
 	"sort"
 	"strings"

 	"github.com/spf13/cobra"
 	"gopkg.in/yaml.v3"

 	errUtils "github.com/cloudposse/atmos/errors"
 	authList "github.com/cloudposse/atmos/pkg/auth/list"
 	authTypes "github.com/cloudposse/atmos/pkg/auth/types"
 	cfg "github.com/cloudposse/atmos/pkg/config"
+	"github.com/cloudposse/atmos/pkg/flags"
 	log "github.com/cloudposse/atmos/pkg/logger"
 	"github.com/cloudposse/atmos/pkg/perf"
 	"github.com/cloudposse/atmos/pkg/profile"
 	"github.com/cloudposse/atmos/pkg/schema"
 )
@@
 func loadAuthManagerForList(cmd *cobra.Command) (authTypes.AuthManager, *schema.AtmosConfiguration, error) {
 	defer perf.Track(nil, "cmd.loadAuthManagerForList")()

-	configAndStacksInfo := schema.ConfigAndStacksInfo{}
-	if bp, _ := cmd.Flags().GetString("base-path"); bp != "" {
-		configAndStacksInfo.AtmosBasePath = bp
-	}
-	if cfgFiles, _ := cmd.Flags().GetStringSlice("config"); len(cfgFiles) > 0 {
-		configAndStacksInfo.AtmosConfigFilesFromArg = cfgFiles
-	}
-	if cfgDirs, _ := cmd.Flags().GetStringSlice("config-path"); len(cfgDirs) > 0 {
-		configAndStacksInfo.AtmosConfigDirsFromArg = cfgDirs
-	}
+	configAndStacksInfo, err := flags.ParseGlobalFlags(cmd, v)
+	if err != nil {
+		return nil, nil, fmt.Errorf("%w: failed to parse global flags: %w", errUtils.ErrInvalidFlag, err)
+	}

 	atmosConfig, err := cfg.InitCliConfig(configAndStacksInfo, false)

Based on learnings, cfg.InitCliConfig must be fed by flags.ParseGlobalFlags(cmd, v) because config selection fields (including ProfilesFromArg) are read from schema.ConfigAndStacksInfo, not directly from Viper.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/auth_list.go` around lines 407 - 418, The loadAuthManagerForList flow
builds schema.ConfigAndStacksInfo manually and misses global selectors like
--profile, causing cfg.InitCliConfig to use incomplete selection data; update
the code path that constructs configAndStacksInfo in loadAuthManagerForList to
call flags.ParseGlobalFlags(cmd, v) (or otherwise invoke the same parsing
routine) so that schema.ConfigAndStacksInfo (including ProfilesFromArg and other
selector fields) is populated before calling cfg.InitCliConfig; reference the
functions loadAuthManagerForList, cfg.InitCliConfig, flags.ParseGlobalFlags and
the struct schema.ConfigAndStacksInfo when making this change.
🧹 Nitpick comments (1)
pkg/auth/manager_test.go (1)

2155-2236: Consider consolidating the new identity-initialization cases into one table-driven test.

These four tests validate the same behavior shape with different inputs; a table-driven version will reduce duplication and keep future scenario additions cheaper.

As per coding guidelines Use table-driven tests for testing multiple scenarios in Go.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/auth/manager_test.go` around lines 2155 - 2236, Consolidate the four
TestInitializeIdentities_* cases into a single table-driven test: create a slice
of test cases with fields (name, cfgIdentities, stackInfo, wantErr bool,
wantErrType errUtils.ErrInvalidIdentityConfig?, wantDetails []string), then loop
with t.Run(tc.name, func(t *testing.T){ build a manager with tc.cfgIdentities
and tc.stackInfo, call m.initializeIdentities(), assert error presence/type via
assert.Error/assert.NoError and assert.ErrorIs, and when expecting errors check
cockroachErrors.GetAllDetails(err) contains each string in tc.wantDetails });
reference the existing test names
(TestInitializeIdentities_EmptyKindWithProfile,
TestInitializeIdentities_EmptyKindWithoutProfile,
TestInitializeIdentities_EmptyKindNilStackInfo,
TestInitializeIdentities_ValidKindSucceeds) and the manager.initializeIdentities
method to locate where to consolidate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/auth_list_test.go`:
- Around line 437-510: Add a regression test that passes --profile to the auth
list command and verifies that specifying a profile prevents
ErrAuthNotConfigured by loading the profile's auth config: create a test (e.g.,
TestExecuteAuthListCommand_WithProfileLoadsAuth) that sets up a temp dir with a
profile containing atmos.yaml auth data, call flags.ParseGlobalFlags(cmd, v) so
cfg.InitCliConfig receives a populated schema.ConfigAndStacksInfo, then run
createTestAuthListCmd(); set cmd.RunE = executeAuthListCommand and execute
cmd.Execute(), asserting no ErrAuthNotConfigured and that auth output reflects
the profile. Ensure the test references executeAuthListCommand,
createTestAuthListCmd, cfg.InitCliConfig, flags.ParseGlobalFlags,
schema.ConfigAndStacksInfo, and errUtils.ErrAuthNotConfigured so reviewers can
locate the relevant code.

In `@pkg/auth/factory/factory_test.go`:
- Around line 280-282: The test currently calls err.Error() inside the branch
that checks tt.errorMsg and can panic if err is nil; update the assertion to
first ensure err is non-nil before calling Error() (for example use
assert.Error(t, err) or check err != nil) and then call assert.Contains(t,
err.Error(), tt.errorMsg); adjust the block around tt.errorMsg, err and
assert.Contains in factory_test.go so the test fails cleanly instead of
panicking.

In `@pkg/auth/realm_mismatch.go`:
- Around line 157-177: The cleanup code silently ignores ReadDir and os.Remove
errors (see providerDirs, awsDir, providerDir, and the os.Remove calls), so
update it to log unexpected failures: when the initial ReadDir error is non-nil,
log the error with context (awsDir) instead of just returning; for each
os.Remove call for files and for providerDir/awsDir, check the returned error
and if it's non-nil and not os.IsNotExist(err) log a warning/error including the
path and err; keep successful-delete Debug logs as-is. Ensure you reference
provider.Name(), filepath.Join(...) results, and include clear context in each
log entry to aid debugging.

---

Duplicate comments:
In `@cmd/auth_list.go`:
- Around line 407-418: The loadAuthManagerForList flow builds
schema.ConfigAndStacksInfo manually and misses global selectors like --profile,
causing cfg.InitCliConfig to use incomplete selection data; update the code path
that constructs configAndStacksInfo in loadAuthManagerForList to call
flags.ParseGlobalFlags(cmd, v) (or otherwise invoke the same parsing routine) so
that schema.ConfigAndStacksInfo (including ProfilesFromArg and other selector
fields) is populated before calling cfg.InitCliConfig; reference the functions
loadAuthManagerForList, cfg.InitCliConfig, flags.ParseGlobalFlags and the struct
schema.ConfigAndStacksInfo when making this change.

---

Nitpick comments:
In `@pkg/auth/manager_test.go`:
- Around line 2155-2236: Consolidate the four TestInitializeIdentities_* cases
into a single table-driven test: create a slice of test cases with fields (name,
cfgIdentities, stackInfo, wantErr bool, wantErrType
errUtils.ErrInvalidIdentityConfig?, wantDetails []string), then loop with
t.Run(tc.name, func(t *testing.T){ build a manager with tc.cfgIdentities and
tc.stackInfo, call m.initializeIdentities(), assert error presence/type via
assert.Error/assert.NoError and assert.ErrorIs, and when expecting errors check
cockroachErrors.GetAllDetails(err) contains each string in tc.wantDetails });
reference the existing test names
(TestInitializeIdentities_EmptyKindWithProfile,
TestInitializeIdentities_EmptyKindWithoutProfile,
TestInitializeIdentities_EmptyKindNilStackInfo,
TestInitializeIdentities_ValidKindSucceeds) and the manager.initializeIdentities
method to locate where to consolidate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8ae9b85e-e39e-459d-b267-e04c56dcce7b

📥 Commits

Reviewing files that changed from the base of the PR and between 9b7152a and 30876e6.

📒 Files selected for processing (24)
  • cmd/auth_list.go
  • cmd/auth_list_test.go
  • internal/exec/utils_auth.go
  • internal/exec/utils_auth_test.go
  • pkg/auth/config_helpers.go
  • pkg/auth/config_helpers_test.go
  • pkg/auth/factory/factory.go
  • pkg/auth/factory/factory_test.go
  • pkg/auth/manager.go
  • pkg/auth/manager_test.go
  • pkg/auth/manager_whoami.go
  • pkg/auth/realm_mismatch.go
  • pkg/auth/realm_mismatch_test.go
  • tests/snapshots/TestCLICommands_atmos_describe_component_mock_-s_dev_(stack-names_example).stdout.golden
  • tests/snapshots/TestCLICommands_atmos_describe_component_mock_-s_production_(stack-names_example).stdout.golden
  • tests/snapshots/TestCLICommands_atmos_describe_component_vpc_-s_dev_(native-terraform_example).stdout.golden
  • tests/snapshots/TestCLICommands_atmos_describe_component_vpc_-s_my-legacy-prod-stack.stdout.golden
  • tests/snapshots/TestCLICommands_atmos_describe_component_vpc_-s_no-name-prod.stdout.golden
  • tests/snapshots/TestCLICommands_atmos_describe_component_vpc_-s_production_(native-terraform_example).stdout.golden
  • tests/snapshots/TestCLICommands_describe_component_from_nested_dir_discovers_atmos.yaml_in_parent.stdout.golden
  • tests/snapshots/TestCLICommands_describe_component_with_component_name_(backward_compatibility).stdout.golden
  • tests/snapshots/TestCLICommands_describe_component_with_current_directory_(.).stdout.golden
  • tests/snapshots/TestCLICommands_describe_component_with_relative_path.stdout.golden
  • tests/snapshots/TestCLICommands_describe_component_with_stack_flag.stdout.golden

- Use flags.ParseGlobalFlags in loadAuthManagerForList so --profile and
  other global selectors are respected instead of hand-rolled flag extraction
- Add --profile regression test confirming profile auth config suppresses
  ErrAuthNotConfigured
- Only include realm in buildGlobalAuthSection when explicitly configured
  (env/config), excluding auto-computed config-path hashes that are
  machine-specific and break CI snapshots
- Guard err.Error() in factory_test.go to prevent panic on nil error
- Log unexpected file cleanup failures in deleteLegacyCredentialFiles
  instead of silently ignoring them
- Consolidate identity initialization tests into table-driven format
- Restore golden snapshots to exclude path-dependent realm hashes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aknysh
Copy link
Copy Markdown
Member

aknysh commented Mar 16, 2026

@coderabbitai please check if this PR fixes the issues reported in #2187

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 16, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch issue `#2187` details
gh issue view 2187 --repo cloudposse/atmos --json title,body,comments

# Look at the utils_auth.go changes
cat internal/exec/utils_auth.go

# Look at config_helpers.go 
cat pkg/auth/config_helpers.go

# Look at manager.go auth authenticate function
cat pkg/auth/manager.go

Length of output: 48800


@aknysh: I need to correct my earlier analysis — this PR does fully fix issue #2187.

Here's the precise breakdown:

Root Cause (Fixed ✅)

The issue was in pkg/auth/config_helpers.goCopyGlobalAuthConfig was not copying the Realm and RealmSource fields. This PR adds exactly that:

// Before this PR: Realm and RealmSource were silently dropped
config := &schema.AuthConfig{
    Realm:       globalAuth.Realm,       // ← NEW
    RealmSource: globalAuth.RealmSource, // ← NEW
    Logs:        globalAuth.Logs,
    ...
}

getMergedAuthConfigWithFetcher (called by both single-component and --all paths) uses CopyGlobalAuthConfig to seed the merged auth config. Without Realm being copied, NewAuthManager received an empty config.Realm, so realm.GetRealm("", cliConfigPath) fell back to the legacy credential path (aws/). With the fix, the correct realm is propagated and credentials land under .config/atmos/<realm>/ consistently.

Migration Cleanup (Bonus ✅)

pkg/auth/manager.go now runs deleteLegacyCredentialFiles() and deleteLegacyKeyringEntry(step) after every successful authentication, cleaning up any stale pre-realm entries under aws/ to prevent future mismatch warnings for users upgrading from older Atmos versions.

Summary

Concern Status
--all stores creds without realm prefix Fixed via CopyGlobalAuthConfig propagating Realm/RealmSource
Existing legacy creds cause mismatch warnings Fixed via post-auth cleanup
Profile suggestion when no auth configured Added as UX improvement

My previous comment that "root cause is not addressed" was incorrect — I apologize for the confusion. Issue #2187 is fully addressed.


🧠 Learnings used
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.

Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:37.766Z
Learning: cloudposse/atmos: For PRD docs (docs/prd/*.md), markdownlint issues like MD040/MD010/MD034 can be handled in a separate documentation cleanup commit and should not block the current PR.

Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.

Learnt from: osterman
Repo: cloudposse/atmos PR: 768
File: internal/exec/vendor_utils.go:496-513
Timestamp: 2024-11-22T12:38:33.132Z
Learning: In the Atmos project, continue to flag path traversal issues in code reviews but acknowledge when they are expected and acceptable in specific cases.

Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: errors/errors.go:184-203
Timestamp: 2025-12-13T06:10:13.688Z
Learning: cloudposse/atmos: For toolchain work, duplicate/unused error sentinels in errors/errors.go should be cleaned up in a separate refactor PR and not block feature PRs; canonical toolchain sentinels live under toolchain/registry with re-exports in toolchain/errors.go.

Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.

Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/http_client_test.go:3-10
Timestamp: 2025-09-10T21:17:55.273Z
Learning: In the cloudposse/atmos repository, imports should never be changed as per samtholiya's coding guidelines.

Learnt from: osterman
Repo: cloudposse/atmos PR: 1714
File: NOTICE:0-0
Timestamp: 2025-11-01T20:24:29.557Z
Learning: In the cloudposse/atmos repository, the NOTICE file is programmatically generated and should not be manually edited. Issues with dependency license URLs in NOTICE will be resolved when upstream package metadata is corrected.

@aknysh aknysh merged commit c9f5f50 into main Mar 16, 2026
56 checks passed
@aknysh aknysh deleted the osterman/auth-suggest-profile branch March 16, 2026 18:33
@github-actions
Copy link
Copy Markdown

These changes were released in v1.210.0-test.28.

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

Labels

patch A minor, backward compatible change size/m Medium size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auth realm not considered when using --all option

2 participants