feat(dev-3124): Pin Terraform provider versions via required_providers @osterman (#1841)
what
- Create unified
pkg/generatorpackage with registry pattern for Terraform file generation - Implement
required_providersandrequired_versionsupport in stack configurations - Add
atmos terraform generate required-providersCLI command - Auto-generate
terraform_override.tf.jsonwith 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 --uploadunderGITHUB_EVENT_NAME=merge_group(previously gated topull_requestonly). - Resolve the diff base for merge-queue events from
event.merge_group.base_sha, populateHeadSHAfromevent.merge_group.head_sha, and derive the target branch fromevent.merge_group.base_ref— with graceful fallback toGITHUB_BASE_REFwhen no event payload is available. - Backfill the full
settings.proevent schema in the configuration reference (pull_request,release,drift_detection) and add a new Merge Queue Support section documenting the optionalsettings.pro.merge_group.checks_requested.workflowsblock, the prerequisites, the resolution order, and the migration note. - Rename
ErrUploadRequiresPullRequestEvent→ErrUploadRequiresSupportedEventand update the error message/hints to mentionpull_request,pull_request_target, andmerge_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}throughStripAffectedForUpload. - 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.requestedwebhooks 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--uploadundermerge_groupand 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.proper-event schema was previously undocumented on atmos.tools — customers were copying shapes from test fixtures. Backfilling the full reference (and addingmerge_groupalongside it) addresses both gaps in one PR. settings.prois opaquemap[string]anyend-to-end, so no struct changes are required formerge_groupto round-trip; the new test locks that contract in to prevent a future struct-tightening from silently dropping the new block.
references
- GitHub merge queue documentation: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue
- Configuration reference:
/cli/configuration/settings/pro#merge-queue-support - Companion Atmos Pro server-side change subscribes to
check_suite.requestedforgh-readonly-queue/...head branches.
[!NOTE]
The Merge Queue Support section inpro.mdx(and the migration note in the blog post) contain anAtmos CLI ≥ X.Y.Zplaceholder. 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
fix(website): render decorative card titles as div, not h2, to fix Algolia search relevance @osterman (#2400)
what
- Swizzle
@theme/DocCardso 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, andFile.
why
- Algolia DocSearch v3 indexes any
article h2as 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/theDocCardList"Related Commands" section emits ten<h2 class=\"cardTitle_*\">📄️ atmos auth login</h2>-style entries. Searches likeatmos authranked these card titles above the actual/cli/commands/auth/usagepage because they contained the literal query. - On
/cli/commands/auth/usagetheActionCardtitle<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 weaktype:\"content\"record and nolvl1/lvl2records — 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.
fix(website): single H1 per page for valid Algolia search hierarchy @osterman (#2393)
what
- Stop rendering decorative
<h1>inTerminal,Screengrab, andFilechrome 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 anembeddedH1class so the visual size is preserved. - Demote stray
# Headingmarkdown to##in three docs pages:describe-affected.mdx,inheritance.mdx,mindset.mdx.
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
- Algolia DocSearch indexing rules: https://docsearch.algolia.com/docs/record-extractor
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.plansummary path. - Document the fix under
docs/fixes.
Validation
go test ./pkg/ci/plugins/terraform -run TestOnAfterPlan_OutputOnlyStdout_RendersOutputChangeSummary -count=1go test ./pkg/ci/plugins/terraform -run 'OutputOnly|OnAfterPlan|Template' -count=1go 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.
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=tableno longer drops rows. - Profile-fallback path made viable from
terraform:TerraformPreHooknow offers the profile-switch fallback (matchingatmos auth login/exec/shell/env/console/whoami) when the loaded config has no usable auth, and--profileis propagated to auth subcommand config init so the re-exec re-loads the picked profile's identities. profiles.base_pathsynced to global viper inLoadConfigso 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, andcmd/auth_config_test.go.
why
bubbles/tablereserves one of the configuredWithHeight()lines for the header — passinglen(rows)renderedlen(rows)-1data 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
Selectedstyle. Aliasings.Selected = s.Cellremoved the highlight but re-appliedPadding(0,1)to the whole joined row, shifting the cursor row 1 column right of every other row. Using an emptylipgloss.NewStyle()removes the highlight without the double-padding. - The active-profile dot was being mangled into
…in TTY output because bubbles'renderRowcallsrunewidth.Truncate(value, width, "…"), andrunewidthcounts ANSI escape bytes as visible width: a pre-styled\x1b[…m●\x1b[0mreports width ~8 and gets truncated to a single…. Putting a plain●in the cell and post-styling afterView()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_pathto the global viper, the fallback could not see profiles in user-configured locations and silently returned no candidates.
references
- Symptom: running
atmos profile listin 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.
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
IdentityAwareBackendinterface topkg/ci/artifactso the registry can inject anAuthContextResolver(mirroring the existingpkg/storepattern). - Refactor the S3 backend to defer client initialization when an identity is configured and resolve credentials lazily via the injected resolver.
- Wire
ci.createPlanfileStoreto propagateinfo.Identity(the resolved--identity/ATMOS_IDENTITYvalue) and a resolver built frominfo.AuthManager. - Add unit tests covering registry resolver injection, S3 lazy init paths, and
attachIdentityprecedence.
why
atmos terraform planwas 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
- closes #2369
- Mirrors the identity-aware store pattern in
pkg/store/aws_ssm_param_store.goandpkg/store/authbridge/resolver.go.
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 withCommentBehavior(create / update / upsert) and result types. pkg/ci/providers/github/comments.go: upsert via HTML marker<!-- atmos:ci:{command}:{component}:{stack} -->usingIssues.ListComments+EditComment/CreateComment. 403/404 errors carry hints directing users to thepermissions: pull-requests: writeworkflow grant. Pagination-aware marker scan.- Generic provider returns
ErrCIOperationNotSupported.
Plugin wiring:
pkg/ci/plugins/terraform/comments.go: newpostComment()handler reuses the summary rendered bywriteSummary()soci.templates.terraform.planoverrides apply to both the job summary and the PR comment body.- Hooked into
onAfterPlanas 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.Enabledchanged fromboolto*boolso nil (unset) can default off without colliding with explicitfalse. This matches the siblingCIChecksConfig.Enabledand prevents upgrading installations from silently starting to post comments.ATMOS_CI_COMMENTS_ENABLEDenv 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.Errorfsites inpkg/config/utils.go:GetContextPrefixto wrap a newErrStackNamePatternPartMissingsentinel; 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_testandhandlers_testmockProviderupdated 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: truedid nothing). - Adds
Provider.PostCommentto 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 soci.templates.terraform.planoverrides apply to both the GitHub job summary and the PR comment body. - Changes
CICommentsConfig.Enabledfromboolto*boolso 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: writeworkflow grant. - Adds 4 new sentinel errors (
ErrCICommentPostFailed,ErrCICommentListFailed,ErrCICommentUpdateFailed,ErrCICommentNotFound). - Incidentally: converts 4 pre-existing dynamic
fmt.Errorfsites inpkg/config/utils.go:GetContextPrefixto a newErrStackNamePatternPartMissingsentinel — 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_ENABLEDenv var suggest the feature works, but no code path ever called the GitHub API. Users configuringci.comments.enabled: truein apull_requestworkflow 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.mdtracked it as "Not Started". This PR locks in the design decisions and ships the feature. *boolforEnabledmatches the pattern already used byCIChecksConfig.Enabledand gives us room to default off without breaking explicitfalsevalues — 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.gofor the commit status API, since the permissions failure mode is identical and common.
scope
- Plan-only, deliberately.
applyanddeploydo 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.templateoverride 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.gocover 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 runis 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.
fix(auth/eks): suppress success line for no-op kubeconfig writes @mtb-xt (#2402)
what
WriteClusterConfignow returns(changed bool, err error)and detects no-op writes by comparing the serialized kubeconfig against the on-disk file.EKSIntegration.Executeonly emitsui.Successwhen the kubeconfig actually changed; otherwise it logs at debug.- The explicit
atmos aws eks update-kubeconfig --integrationcommand 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
changedflips 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 singleatmos workflow plan/dev -f bedrockinvocation. - Code touchpoints:
pkg/auth/cloud/kube/config.go—WriteClusterConfig, newwriteIfChanged/mergeIfChanged/configsEqualhelpers.pkg/auth/integrations/aws/eks.go—EKSIntegration.Executegate.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-provisionedaws/eksintegrations 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.
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_*.goto an organisedcmd/auth/package with aCommandProviderinterface. - Replaced direct
viper.BindPFlag()/viper.BindEnv()calls withflags.NewStandardParser(...)+parser.BindToViper(...)(Forbidigo-compliant). - Replaced
DisableFlagParsingwith theSeparatedArgspattern for pass-through commands (auth shell,auth exec). - Promoted
auth userto 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/authrose 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_ProfileFlagAppliedToConfigcmd/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 assertsinfo.Identity == "core-root/admin".internal/exec/terraform_execute_helpers_auth_test.go::TestSetupTerraformAuth_IdentityFlagPropagatesToAuthCreator— builds a merged auth config with both adefault: trueidentity and a non-default identity and assertssetupTerraformAuthpasses the explicit--identityvalue verbatim.internal/exec/terraform_execute_helpers_auth_test.go::TestSetupTerraformAuth_EmptyIdentity_AllowsAutoDetection— inverse guard: emptyinfo.Identitymust 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/auth33.0% → 47.6%,cmd/auth/user35.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 opaqueHTTP 500: API response error: API request failed with status Nnoise. - 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 byerrorTag == DriftDetectionValidationErroror substring match on the message). - Drop the redundant
HTTP <code>:prefix inAPIError.Error()for 4xx so output readsUploadInstances: <server message>instead ofUploadInstances: HTTP 400: API response error: <server message>. - Preserve
trace_idon all statuses (including 4xx) so support can correlate user-reported issues. - Tolerate both
errorMessage(current) and legacyerrorfield on responses; newEffectiveErrorMessage()prefers the former. - Replace
errors.Join(sentinel, cause)with a smallwrapErrhelper using the existingerrUtils.Build(...).WithCause(...)pattern. Stdliberrors.Joinandfmt.Errorf("%w: %w", ...)both produce multi-errors that hide cockroach hint annotations fromGetAllHints, 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 --uploadagainst a misconfigured stack producedUploadInstances: 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
errorMessageanddata.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 becauseerrors.Joindoesn't expose its children tocockroachErrors.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.