github cloudposse/atmos v1.218.0

4 hours ago
feat(dev-3124): Pin Terraform provider versions via required_providers @osterman (#1841)

what

  • Create unified pkg/generator package with registry pattern for Terraform file generation
  • Implement required_providers and required_version support in stack configurations
  • Add atmos terraform generate required-providers CLI command
  • Auto-generate terraform_override.tf.json with version constraints during terraform commands
  • Update JSON schema to support new configuration fields

why

This feature allows users to pin Terraform and provider versions per component, improving reproducibility and reducing dependency-related issues. The unified generator package consolidates file generation logic for better maintainability.

references

Closes #3124

Summary by CodeRabbit

  • New Features

    • New CLI subcommand to generate a terraform_override.tf.json (required_providers and required_version); supports --stack, optional --file and dry-run.
    • Stacks/components now support required_providers and required_version with inheritance and overrides.
    • Automated generators produce provider overrides, varfiles, and required_providers files.
  • Documentation

    • JSON schema and website roadmap updated to document required_providers and required_version.

✏️ Tip: You can customize this high-level summary in your review settings.

feat(pro): GitHub merge-queue support for describe affected --upload @osterman (#2395)

what

  • Allow atmos describe affected --upload under GITHUB_EVENT_NAME=merge_group (previously gated to pull_request only).
  • Resolve the diff base for merge-queue events from event.merge_group.base_sha, populate HeadSHA from event.merge_group.head_sha, and derive the target branch from event.merge_group.base_ref — with graceful fallback to GITHUB_BASE_REF when no event payload is available.
  • Backfill the full settings.pro event schema in the configuration reference (pull_request, release, drift_detection) and add a new Merge Queue Support section documenting the optional settings.pro.merge_group.checks_requested.workflows block, the prerequisites, the resolution order, and the migration note.
  • Rename ErrUploadRequiresPullRequestEventErrUploadRequiresSupportedEvent and update the error message/hints to mention pull_request, pull_request_target, and merge_group.
  • Add tests covering the merge_group event acceptance, payload-aware base resolution paths, and the opaque round-trip of settings.pro.{pull_request,release,drift_detection,merge_group} through StripAffectedForUpload.
  • Add a feature blog post and a shipped milestone in the CI/CD initiative on the roadmap.

why

  • Atmos Pro now subscribes to GitHub check_suite.requested webhooks and creates check runs on the synthetic SHAs GitHub produces when a PR enters a merge queue (gh-readonly-queue/<base>/pr-<N>-<sha>). For the check to conclude correctly when stacks are affected, the CLI must allow --upload under merge_group and resolve the diff base against the target-branch commit the synthetic merge was built on top of.
  • Without this change, required "Atmos Pro" checks hang in Expected — Waiting for status to be reported on every queued PR until a delayed reconciler sweeps them, breaking required-checks workflows.
  • The public settings.pro per-event schema was previously undocumented on atmos.tools — customers were copying shapes from test fixtures. Backfilling the full reference (and adding merge_group alongside it) addresses both gaps in one PR.
  • settings.pro is opaque map[string]any end-to-end, so no struct changes are required for merge_group to round-trip; the new test locks that contract in to prevent a future struct-tightening from silently dropping the new block.

references

[!NOTE]
The Merge Queue Support section in pro.mdx (and the migration note in the blog post) contain an Atmos CLI ≥ X.Y.Z placeholder. Replace with the actual released version once this PR is tagged.

Summary by CodeRabbit

  • New Features

    • Support for GitHub merge-queue (merge_group) uploads; uploads now accept pull_request, pull_request_target, and merge_group events
    • settings.pro.merge_group configuration (including checks_requested.workflows) is preserved through uploads
  • Bug Fixes

    • Improved validation and clearer hints for unsupported CI event types
  • Tests

    • Added unit tests covering merge_group upload validation and schema preservation
  • Documentation

    • Added blog post, CLI docs, and roadmap entry describing merge-queue support and configuration

Review Change Stack

fix(website): render decorative card titles as div, not h2, to fix Algolia search relevance @osterman (#2400)

what

  • Swizzle @theme/DocCard so each card's title renders as <div className={styles.cardTitle}> instead of <Heading as=\"h2\">. Visual styling is preserved because the CSS module rule (font-size: 1.2rem) targets the className, not the element.
  • Change ActionCard's <h2>{title}</h2> to <div className=\"action-card__title\">{title}</div> and add explicit font tokens so the title still renders at h2 size.
  • Mirrors the same pattern PR #2393 applied to Terminal, Screengrab, and File.

why

  • Algolia DocSearch v3 indexes any article h2 as a page section (lvl2) — that's the default Docusaurus crawler template's selector. Decorative h2s emitted by these components were being indexed as if they were real headings.
  • On /cli/configuration/auth/ the DocCardList "Related Commands" section emits ten <h2 class=\"cardTitle_*\">📄️ atmos auth login</h2>-style entries. Searches like atmos auth ranked these card titles above the actual /cli/commands/auth/usage page because they contained the literal query.
  • On /cli/commands/auth/usage the ActionCard title <h2>Configure Authentication</h2> sat between the page H1 and the first real H2. That extra heading scrambled the crawler's hierarchy extractor, leaving the page with a single weak type:\"content\" record and no lvl1/lvl2 records — so it couldn't compete with the noisier configuration page.
  • Card titles are navigational labels for a link, not section headings; a <div> is semantically more honest and removes the indexing hijack without forcing an atmos-specific deviation from the DocSearch v3 defaults.

references

  • Builds on #2393 (single-H1-per-page fix for Terminal/Screengrab/File).
  • Verified by querying the live Algolia index at `https://32YOERUX83-dsn.algolia.net/1/indexes/atmos.tools/query\` before and after the build. After the next crawl, the `atmos auth` page should emit proper `lvl1`/`lvl2` records and the configuration page's card list should no longer pollute results.
  • Followup candidates (not in this PR): sweep the remaining decorative-h2 components (`KeyTakeaways`, `KeyPoints`, `NextSteps`, `Card`, `CardGroup`, `Step`, hardcoded `AISection`), and audit the 323 URLs the crawler reported as ignored in the last run.

Summary by CodeRabbit

  • New Features

    • Added a documentation card component that shows docs links or category collections with smart linking and interactive hover behavior.
  • Style

    • Improved action card title styling using a dedicated title class and refined design tokens.
    • Polished documentation card appearance with hover effects, transitions, and updated typography.

Review Change Stack

fix(website): single H1 per page for valid Algolia search hierarchy @osterman (#2393)

what

  • Stop rendering decorative <h1> in Terminal, Screengrab, and File chrome components — replaced with semantic <div className="window-title|file-title"> and matching CSS selectors.
  • Demote heading levels (h1→h2, h2→h3, …) in embedded README content rendered by EmbedExample, with an embeddedH1 class so the visual size is preserved.
  • Demote stray # Heading markdown to ## in three docs pages: describe-affected.mdx, inheritance.mdx, mindset.mdx.
image

why

  • Algolia DocSearch builds its sidebar/breadcrumbs from the page's H1 → H2 → H3 outline. Multiple H1s per page (one from the Docusaurus title, one from a Terminal window chrome, another from an embedded README) caused jumbled/duplicated search results.
  • Valid HTML5 also expects a single H1 per page; this aligns the rendered DOM with that convention without changing any visible styling.

references

Summary by CodeRabbit

  • Documentation

    • Adjusted heading levels, reordered section headings, and converted several top-level headings to second-level for clearer structure and to avoid duplicate page-level headings in embedded content.
  • Style

    • Switched component title markup from top-level headings to classed containers and added styling to preserve visual hierarchy.
    • Shifted embedded content heading levels in rendering and updated terminal/embedded title styles for consistent appearance across themes.

🚀 Enhancements

fix(ci): classify output-only plan summaries @osterman (#2407)

Summary

Fixes CI summary classification for output-only Terraform/OpenTofu plans on the stdout fallback path. These plans already had HasChanges=true, but the rendered summary could still use the no-change heading and badge because the template context only inferred output changes from parsed output values.

Root Cause

JSON plan parsing has structured output_changes, but stdout parsing only sees Changes to Outputs:. The parser set the changed-result text but did not preserve an explicit output-change signal for the template context.

Changes

  • Add TerraformOutputData.HasOutputChanges.
  • Set it from JSON plan output changes and stdout Changes to Outputs: detection.
  • Use the explicit signal when building the Terraform summary template context.
  • Add an anonymized end-to-end regression test for the after.terraform.plan summary path.
  • Document the fix under docs/fixes.

Validation

  • go test ./pkg/ci/plugins/terraform -run TestOnAfterPlan_OutputOnlyStdout_RendersOutputChangeSummary -count=1
  • go test ./pkg/ci/plugins/terraform -run 'OutputOnly|OnAfterPlan|Template' -count=1
  • go test ./pkg/ci/plugins/terraform -count=1
  • pre-commit hooks during commit, including Go build, gofumpt, tidy check, and golangci-lint

Summary by CodeRabbit

  • Bug Fixes
    • Fixed CI summary display for Terraform and OpenTofu plans containing output-only changes. Previously, plans that only modified output values incorrectly displayed "No Changes" heading and badge on CI summaries. They now correctly display "Output Changes" heading with appropriate messaging.

Review Change Stack

fix(profile,auth): list table truncation, alignment, and active-profile indicator @osterman (#2365)

what

  • Profile list table now shows every configured profile instead of just the first row, and flags the currently-active profile with a green dot resolved from --profile / ATMOS_PROFILE / profiles.default.
  • Auth list table (providers + identities) gets the same row-truncation fix, so atmos auth list --format=table no longer drops rows.
  • Profile-fallback path made viable from terraform: TerraformPreHook now offers the profile-switch fallback (matching atmos auth login/exec/shell/env/console/whoami) when the loaded config has no usable auth, and --profile is propagated to auth subcommand config init so the re-exec re-loads the picked profile's identities.
  • profiles.base_path synced to global viper in LoadConfig so the auth profile fallback can discover profiles in custom locations.
  • New exported cfg.GetActiveProfiles(*schema.AtmosConfiguration) helper centralises the resolution order used by both the renderer and any future callers.
  • Regression tests added in pkg/profile/list, pkg/auth/list, pkg/config, pkg/auth, and cmd/auth_config_test.go.

why

  • bubbles/table reserves one of the configured WithHeight() lines for the header — passing len(rows) rendered len(rows)-1 data rows. With 2 profiles, only 1 was visible. The data layer (--format=json) was always correct, so the bug was purely in the table renderer at three call sites.
  • After fixing height, the cursor row (row 0) was rendered with a blue highlight from bubbles' default Selected style. Aliasing s.Selected = s.Cell removed the highlight but re-applied Padding(0,1) to the whole joined row, shifting the cursor row 1 column right of every other row. Using an empty lipgloss.NewStyle() removes the highlight without the double-padding.
  • The active-profile dot was being mangled into in TTY output because bubbles' renderRow calls runewidth.Truncate(value, width, "…"), and runewidth counts ANSI escape bytes as visible width: a pre-styled \x1b[…m●\x1b[0m reports width ~8 and gets truncated to a single . Putting a plain in the cell and post-styling after View() returns sidesteps the bug.
  • The Terraform pre-hook surfaced a bare "no default identity" error in the exact scenarios the auth commands' fallback already handles. Wiring the same fallback in keeps the UX consistent.
  • Without syncing profiles.base_path to the global viper, the fallback could not see profiles in user-configured locations and silently returned no candidates.

references

  • Symptom: running atmos profile list in a directory with multiple profiles displayed only the first one in the table view (JSON output was unaffected).

Summary by CodeRabbit

  • New Features

    • Profile list now displays active profiles with a visual indicator (●).
    • Added support for default profiles in configuration.
    • Profile fallback suggestions when authentication configuration is incomplete.
  • Bug Fixes

    • Fixed table rendering to properly display all rows with multiple entries.
    • Eliminated duplicate help flag output during configuration loading.
    • Improved profile resolution for edge cases in flag parsing.

Review Change Stack

fix(ci): use active atmos identity for S3 planfile uploads @calxus (#2372)

what

  • Make the S3 planfile store authenticate via the active Atmos auth identity instead of always falling back to the AWS SDK default credential chain.
  • Add an IdentityAwareBackend interface to pkg/ci/artifact so the registry can inject an AuthContextResolver (mirroring the existing pkg/store pattern).
  • Refactor the S3 backend to defer client initialization when an identity is configured and resolve credentials lazily via the injected resolver.
  • Wire ci.createPlanfileStore to propagate info.Identity (the resolved --identity / ATMOS_IDENTITY value) and a resolver built from info.AuthManager.
  • Add unit tests covering registry resolver injection, S3 lazy init paths, and attachIdentity precedence.

why

  • atmos terraform plan was succeeding in CI (the Terraform subprocess inherits the prepared environment) but the subsequent S3 planfile upload failed with IMDS errors because the upload runs in the parent atmos process, which had no awareness of the active identity.
  • Common CI setups assume GitHub OIDC + IAM role assumption is enough — the parent process has no ambient AWS credentials to fall back on, so the failure surfaced as a confusing AWS-side error rather than an Atmos config issue.
  • The fix reuses the same identity resolver pattern already used by SSM / Azure Key Vault / GSM stores, so AWS-store auth wiring stays consistent across the codebase.
  • When no identity is in scope, behavior is unchanged: the default credential chain is still used, so existing setups that relied on ambient credentials are unaffected.

references

Summary by CodeRabbit

  • New Features

    • Artifact storage backends now support identity-aware authentication with lazy credential resolution and the ability to attach or override an auth identity/resolver after store creation.
  • Tests

    • Added tests validating identity propagation, deferred auth initialization, resolver invocation semantics, and correct error handling when auth resolution fails.
fix(ci): wire PR comment posting into terraform plan hook @joshAtRula (#2405)

Resolves the regression reported in #2367 where ci.comments.enabled: true had no effect: the schema field existed and ATMOS_CI_COMMENTS_ENABLED was wired, but no code path ever called the GitHub API to create or update a PR comment. The terraform plugin now posts a PR comment on after.terraform.plan whenever comments are enabled and the event is a pull request.

Interface changes:

  • Add Provider.PostComment(ctx, *PostCommentOptions) (*Comment, error) to the CI provider interface, along with CommentBehavior (create / update / upsert) and result types.
  • pkg/ci/providers/github/comments.go: upsert via HTML marker <!-- atmos:ci:{command}:{component}:{stack} --> using Issues.ListComments + EditComment / CreateComment. 403/404 errors carry hints directing users to the permissions: pull-requests: write workflow grant. Pagination-aware marker scan.
  • Generic provider returns ErrCIOperationNotSupported.

Plugin wiring:

  • pkg/ci/plugins/terraform/comments.go: new postComment() handler reuses the summary rendered by writeSummary() so ci.templates.terraform.plan overrides apply to both the job summary and the PR comment body.
  • Hooked into onAfterPlan as warn-only (apply/deploy intentionally excluded for this fix — plan-only scope).
  • Skips silently when the event is not a PR, repo context is incomplete, or the rendered summary is empty.

Schema:

  • CICommentsConfig.Enabled changed from bool to *bool so nil (unset) can default off without colliding with explicit false. This matches the sibling CIChecksConfig.Enabled and prevents upgrading installations from silently starting to post comments.
  • ATMOS_CI_COMMENTS_ENABLED env override updated for pointer-bool semantics; tests extended to cover the unset-nil path.

Errors:

  • Add ErrCICommentPostFailed, ErrCICommentListFailed, ErrCICommentUpdateFailed, ErrCICommentNotFound.
  • Incidentally convert 4 pre-existing dynamic fmt.Errorf sites in pkg/config/utils.go:GetContextPrefix to wrap a new ErrStackNamePatternPartMissing sentinel; gofumpt reformatted those lines, which pulled them into lint's new-from-rev diff. Error message text is preserved so existing tests still match.

Tests:

  • 13 httptest-backed tests for the GitHub comments API covering upsert create, upsert update (marker matches), create-always, update-returns- not-found, input validation, 403/404 hint propagation, pagination, and default behavior.
  • 8 handler tests covering enabled + PR present, skip when disabled, skip when unset (nil), skip when no PR, skip when no repo context, warn-only on API failure, and behavior-flag respect.
  • registry_provider_test and handlers_test mockProvider updated for the new interface method.

Docs:

  • docs/prd/native-ci/providers/github/pr-comments.md: status flipped from Deferred to Shipped with locked-in decisions.
  • implementation-status.md: PR Comments row now Done; v14.0 changelog entry added; totals updated to 148/151.

Closes #2367

what

  • Wires up PR comment posting for the native CI integration, which was previously schema-only (ci.comments.enabled: true did nothing).
  • Adds Provider.PostComment to the CI provider interface with create/update/upsert semantics.
  • Implements the GitHub provider's comment API (pkg/ci/providers/github/comments.go) using HTML-marker-based upsert (<!-- atmos:ci:{command}:{component}:{stack} -->) so repeat runs update the existing comment instead of stacking new ones.
  • Hooks comment posting into onAfterPlan (plan-only, as agreed) and reuses the already-rendered summary so ci.templates.terraform.plan overrides apply to both the GitHub job summary and the PR comment body.
  • Changes CICommentsConfig.Enabled from bool to *bool so unset (nil) defaults to off and upgrading installations don't silently start posting comments.
  • Returns actionable hints on 403/404 errors that point users to the missing permissions: pull-requests: write workflow grant.
  • Adds 4 new sentinel errors (ErrCICommentPostFailed, ErrCICommentListFailed, ErrCICommentUpdateFailed, ErrCICommentNotFound).
  • Incidentally: converts 4 pre-existing dynamic fmt.Errorf sites in pkg/config/utils.go:GetContextPrefix to a new ErrStackNamePatternPartMissing sentinel — error message text preserved so existing tests still match.

why

  • Customer-facing regression in v1.216.0: the docs at https://atmos.tools/cli/configuration/ci/comments promise PR comments, and the schema field + ATMOS_CI_COMMENTS_ENABLED env var suggest the feature works, but no code path ever called the GitHub API. Users configuring ci.comments.enabled: true in a pull_request workflow see the job summary render correctly but no comment on the PR.
  • The PRD (docs/prd/native-ci/providers/github/pr-comments.md) explicitly marked the design as "Deferred" and implementation-status.md tracked it as "Not Started". This PR locks in the design decisions and ships the feature.
  • *bool for Enabled matches the pattern already used by CIChecksConfig.Enabled and gives us room to default off without breaking explicit false values — preventing silent behavior change on upgrade.
  • Reusing the rendered summary for the comment body (rather than rendering a second template) keeps user template customization coherent: one override point (ci.templates.terraform.plan) controls what shows up in both surfaces.
  • 403/404 hinting mirrors the pattern already established in checks.go for the commit status API, since the permissions failure mode is identical and common.

scope

  • Plan-only, deliberately. apply and deploy do not post comments. Review happens on the PR thread for plans; apply/deploy outcomes live in the checks pane. Revisit if users ask.
  • Custom ci.comments.template override is still a follow-up — the comment currently reuses the summary template. The schema field is preserved so this can be wired later without another breaking change.

testing

  • go test -race ./pkg/ci/... ./pkg/config/... ./pkg/schema/... ./errors/... — 2308 tests pass across 19 packages.
  • 13 new httptest-backed tests for pkg/ci/providers/github/comments.go cover upsert create/update, create-always, update-returns-not-found, input validation, 403/404 hint propagation, pagination across list pages, and default-behavior fallback.
  • 8 new handler tests cover enabled + PR present (posts), disabled (skips), unset/nil (skips — upgrade safety), no PR event (skips), no repo context (skips), API failure (warn-only, handler still returns nil), and behavior flag respected.
  • pre-commit run is clean: go-fumpt, go build, go.mod tidy, golangci-lint config verify, golangci-lint, gomodcheck, CLAUDE.md size, trailing whitespace, end-of-files, yaml, large files — all pass.

references

  • closes #2367
  • PRD: docs/prd/native-ci/providers/github/pr-comments.md (status flipped Deferred → Shipped in this PR)
  • Implementation tracker: docs/prd/native-ci/framework/implementation-status.md (PR Comments row now Done; v14.0 changelog entry added)
  • Docs: cli/configuration/ci/comments (no content changes — behavior now matches the doc)
  • Precedent for marker-based upsert: tfcmt

Summary by CodeRabbit

  • New Features

    • Opt-in PR comment posting for CI plan runs on GitHub with marker-based updates; defaults to disabled.
  • Providers

    • GitHub provider: create/update/upsert comment behaviors implemented; generic provider reports comments unsupported.
  • Configuration

    • CI comments setting changed to tri-state (unset vs true/false), with env var support to explicitly set.
  • Tests

    • Extensive tests covering comment behaviors and handler wiring.
  • Documentation

    • Docs and implementation status updated to mark PR comments as shipped.

Review Change Stack

fix(auth/eks): suppress success line for no-op kubeconfig writes @mtb-xt (#2402)

what

  • WriteClusterConfig now returns (changed bool, err error) and detects no-op writes by comparing the serialized kubeconfig against the on-disk file.
  • EKSIntegration.Execute only emits ui.Success when the kubeconfig actually changed; otherwise it logs at debug.
  • The explicit atmos aws eks update-kubeconfig --integration command keeps its unconditional success message — the user asked for it explicitly there.
  • Added three tests: merge no-op, replace no-op, and merge with a changed field (to confirm changed flips back to true for real updates).

why

Auto-provisioned EKS integrations re-run on every identity resolution. In a single atmos workflow ... (or template lookup, or !terraform.output evaluation), that can mean hundreds of identity authentications back-to-back, each printing:

✓ EKS kubeconfig: platform-apse2-dev → /home/.../.config/atmos/kube/config

The repeated lines bury real output and errors (one user reported the output completely hiding a credential-chain failure under thousands of identical success lines). The on-disk file was almost always already correct after the first write, so the success line was misleading on top of being noisy.

Now you see the success line once, the first time the kubeconfig is actually written or modified, and quiet debug logs the rest of the time. This also avoids unnecessary mtime / chmod churn on the kubeconfig file.

references

  • Originating discussion: user observed 1000+ ✓ EKS kubeconfig: ... lines from a single atmos workflow plan/dev -f bedrock invocation.
  • Code touchpoints:
    • pkg/auth/cloud/kube/config.goWriteClusterConfig, new writeIfChanged/mergeIfChanged/configsEqual helpers.
    • pkg/auth/integrations/aws/eks.goEKSIntegration.Execute gate.
    • cmd/aws/eks/update_kubeconfig_sdk.go — caller update (still always prints success for the explicit command).

test plan

  • go test ./pkg/auth/cloud/kube/... ./pkg/auth/integrations/aws/... passes.
  • New tests cover merge no-op, replace no-op, and field-change → changed=true.
  • No-op call confirmed to leave the file mtime untouched.
  • Manual: run atmos workflow ... against a stack with auto-provisioned aws/eks integrations and confirm the success line appears once instead of per-component.

Summary by CodeRabbit

  • Bug Fixes

    • Kubeconfig writes now detect structurally identical content and skip unnecessary disk writes.
    • File permission drift is reconciled without rewriting unchanged content.
    • CLI success output is shown only when the kubeconfig was actually modified; no-op runs report the config is already up to date (debug).
    • Preserves third-party kubeconfig entries when managing clusters.
  • Tests

    • Added coverage for no-op merge/replace, permission-reconcile without content change, visible-field change detection, multi-cluster rewrite behavior, and preservation of third-party kubeconfig entries.

Review Change Stack

refactor: Migrate atmos auth to Command Registry with StandardParser @osterman (#1919)

What

Refactors the atmos auth command family from the legacy flat-file structure to the Command Registry pattern with unified flag handling via pkg/flags/StandardParser. As a side-effect of the refactor, this PR also resolves two long-standing flag-precedence bugs (#1973 and #2392) and adds regression tests so they cannot silently regress again.

  • Migrated 11 auth files from cmd/auth_*.go to an organised cmd/auth/ package with a CommandProvider interface.
  • Replaced direct viper.BindPFlag() / viper.BindEnv() calls with flags.NewStandardParser(...) + parser.BindToViper(...) (Forbidigo-compliant).
  • Replaced DisableFlagParsing with the SeparatedArgs pattern for pass-through commands (auth shell, auth exec).
  • Promoted auth user to a real subcommand package (cmd/auth/user/).

Why

  • Eliminates Forbidigo violations: removes direct viper.BindPFlag() / viper.BindEnv() calls.
  • Consistent flag precedence: every auth subcommand now goes through BuildConfigAndStacksInfo(cmd, v) so global flags (--base-path, --config, --config-path, --profile) are honoured uniformly.
  • Enables the plugin architecture: commands self-register via CommandProvider.
  • Better testability: helpers are isolated and mockable; coverage on cmd/auth rose from 33% → 47% in this PR.

Closes

Closes #1973--profile not applied for auth exec and auth shell

Root cause: the legacy executeAuthExecCommandCore / executeAuthShellCommandCore loaded the atmos config from cfg.InitCliConfig(newAuthConfigAndStacksInfo(cmd), false) — a helper that only read --base-path / --config / --config-path and dropped --profile on the floor. auth list / auth env / auth whoami happened to call a different helper that did read profile, hence the asymmetric bug.

Fix: both cmd/auth/exec.go and cmd/auth/shell.go now call BuildConfigAndStacksInfo(cmd, v) (a wrapper over flags.BuildConfigAndStacksInfo) which extracts all global flags including --profile into ConfigAndStacksInfo.ProfilesFromArg before cfg.InitCliConfig.

Regression tests:

  • cmd/auth/exec_test.go::TestAuthExec_ProfileFlagAppliedToConfig
  • cmd/auth/shell_test.go::TestAuthShell_ProfileFlagAppliedToConfig

Both cover single-profile, multi-profile, and no-profile cases.

Closes #2392--identity silently dropped on atmos terraform plan

Root cause: the bug as reported at v1.216.0 stemmed from --identity being parsed inconsistently between command families. Terraform commands relied solely on the legacy arg-walker parseIdentityFlag while auth/describe used a Cobra-flag-based path.

Fix: terraform commands now register --identity via the StandardParser (cmd/terraform/flags.go::registerIdentityFlags) and the legacy arg-walker still populates info.Identity for backwards compat — so both paths converge on the same value. setupTerraformAuth (in internal/exec/terraform_execute_helpers.go) passes info.Identity verbatim to the auth manager creator; pkg/auth.resolveIdentityName returns it as-is when non-empty, so the explicit flag value can never be overridden by a profile-default identity.

Regression tests:

  • internal/exec/cli_utils_test.go::TestProcessCommandLineArgs_TerraformIdentityFlag_Issue2392 — replays the exact arg shape from the bug report (terraform plan account-map -s core-gbl-root --identity core-root/admin) and asserts info.Identity == "core-root/admin".
  • internal/exec/terraform_execute_helpers_auth_test.go::TestSetupTerraformAuth_IdentityFlagPropagatesToAuthCreator — builds a merged auth config with both a default: true identity and a non-default identity and asserts setupTerraformAuth passes the explicit --identity value verbatim.
  • internal/exec/terraform_execute_helpers_auth_test.go::TestSetupTerraformAuth_EmptyIdentity_AllowsAutoDetection — inverse guard: empty info.Identity must still allow auto-detect.

Testing

  • go build ./..., go vet ./..., make lint — all clean.
  • go test -short ./cmd/... ./internal/... ./pkg/... — all pass.
  • Coverage on the refactored package: cmd/auth 33.0% → 47.6%, cmd/auth/user 35.6% → 51.0%.
  • 39 new test functions added across the auth package, including five explicit regression tests for #1973 and #2392.

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive auth command group with subcommands: login, logout, whoami, list, env, exec, shell, console, validate, and user configure.
  • Improvements

    • Enhanced identity flag handling (equals/space forms, interactive select, disable/omit modes) and improved argument preprocessing/completions.
    • Better auth UX: cached credentials, safer environment output formats (bash/json/dotenv/GitHub), console/session options (destination, duration, issuer, print-only/no-open), and launch/run commands with authenticated environments.
  • Documentation

    • Updated CLI docs and usage tips for identity placement, examples, and auth command usage.
fix(pro): friendlier 4xx error rendering and propagate hints to users @osterman (#2386)

what

  • Surface the Atmos Pro server's user-facing 4xx fields (errorMessage, errorTag, data.validationErrors[]) directly to the CLI user instead of opaque HTTP 500: API response error: API request failed with status N noise.
  • Render data.validationErrors[] as a bullet list under the headline (with dedupe of trailing server-side concatenations like "failed: A; B").
  • Add a 400 hint linking to settings.pro.* docs and a drift-detection-specific hint (selected by errorTag == DriftDetectionValidationError or substring match on the message).
  • Drop the redundant HTTP <code>: prefix in APIError.Error() for 4xx so output reads UploadInstances: <server message> instead of UploadInstances: HTTP 400: API response error: <server message>.
  • Preserve trace_id on all statuses (including 4xx) so support can correlate user-reported issues.
  • Tolerate both errorMessage (current) and legacy error field on responses; new EffectiveErrorMessage() prefers the former.
  • Replace errors.Join(sentinel, cause) with a small wrapErr helper using the existing errUtils.Build(...).WithCause(...) pattern. Stdlib errors.Join and fmt.Errorf("%w: %w", ...) both produce multi-errors that hide cockroach hint annotations from GetAllHints, which is why the existing 401/403/404/5xx hints never actually rendered to users.
  • Retry behavior unchanged: 4xx remains non-retryable, 401 still refreshes the OIDC token, 5xx still backs off.

why

  • Real user pain: running atmos list instances --upload against a misconfigured stack produced UploadInstances: HTTP 500: API response error: API request failed with status 500 (trace_id: ...) four times in a row. The server actually returned a clean validation message describing the missing drift-detection workflows, but the CLI couldn't surface it (DTO field-name mismatch + lost hints).
  • The atmos-pro server now correctly returns 4xx (not 500) with structured errorMessage and data.validationErrors[] for user-error conditions; this PR is the CLI side of that contract.
  • Hints attached via errUtils.Build(...).WithHint(...) were silently dropped at the outermost wrap layer because errors.Join doesn't expose its children to cockroachErrors.GetAllHints. Users never saw the lightbulb hints the 401/403/404/5xx code paths were already emitting; this PR makes them visible.

Summary by CodeRabbit

  • New Features

    • Richer API error parsing that surfaces structured messages, validation bullets, and drift-detection guidance.
    • Unified error-wrapping semantics that preserve original error hints and improve retry exhaustion reporting.
  • Bug Fixes

    • Cleaner 4xx error text (removed redundant HTTP prefix) while preserving trace IDs.
    • 400 responses are not retried and now surface clearer, deduplicated validation bullets.
    • More consistent error handling and ensured response bodies are closed on error.
  • Tests

    • Expanded tests covering error rendering, drift-detection cases, retry behavior, and response-body/redirect edge cases.

Associated Pull Requests

Deployment Status

To view the Atmos Pro deployment status of this release, see #2410.

Don't miss a new atmos release

NewReleases is sending notifications on new releases.