feat: add `atmos pro commit` for server-side commits via GitHub App @osterman (#2298)
what
- Add new
atmos pro commitCLI command that sends changed files to Atmos Pro, which creates commits server-side using its GitHub App installation — ensuring commits trigger CI workflows (unlikeGITHUB_TOKENcommits) - Flexible staging control:
--add "*.tf"for patterns,--all/-Afor everything, or commit whatever is already staged - Built-in infinite loop prevention: automatically detects when running as
atmos-pro[bot]and exits early - Client-side validation: path safety (
.github/rejection, traversal prevention), file size limits (2 MiB), max 200 changed files - Reuses existing OIDC authentication flow from
pkg/pro/api_client.go - Introduces new
atmos-problog tag and retroactively tags 3 existing Atmos Pro changelog entries - Full CLI docs, blog post announcement, and roadmap entry
why
- Commits made with
GITHUB_TOKENin GitHub Actions don't trigger subsequent workflow runs — this is a deliberate GitHub limitation that blocks autofix patterns (e.g.,terraform fmt+ commit) - Teams previously needed third-party services like autofix.ci to work around this
- Atmos Pro's GitHub App can create commits that trigger CI, and this command provides the CLI interface for that capability
- The workflow never receives a write token — Atmos Pro controls exactly what gets committed
references
- Replaces autofix.ci for autocommit workflows
- Uses existing OIDC auth from
pkg/pro/api_client.go(NewAtmosProAPIClientFromEnv) - API endpoint:
POST /api/v1/git/commit
Summary by CodeRabbit
-
New Features
- Added
atmos pro commitfor server-side GitHub commits with staging flags (--message,--comment,--add,--all), loop prevention, branch checks, file-size and changed-files safety limits, and stdout commit SHA.
- Added
-
Documentation
- New CLI docs, blog post, roadmap entry, and tags with usage, GitHub Actions examples, flags, and safety guidance.
-
Usability
- Improved input validation and clearer user-facing errors for commit and API failures.
-
Tests
- Added unit and integration tests for commit flow, API client, DTO JSON, and validations.
-
Chores
- CI workflow updated to run formatting fixes and invoke
pro commit.
- CI workflow updated to run formatting fixes and invoke
feat: Add terraform.workspace.prefix_separator setting for hierarchical state paths @aknysh (#2313)
what
- Adds a new
terraform.workspace.prefix_separatorsetting inatmos.yamlthat controls how/in component names is handled when Atmos auto-generates backend key prefixes - Default value
"-"preserves backward compatibility (e.g.services/consul→services-consul) - Setting
prefix_separator: "/"preserves directory hierarchy (e.g.services/consulstaysservices/consul) - Applies to all three supported backends: S3 (
workspace_key_prefix), GCS (prefix), and Azure (keycomponent) - Explicitly configured backend keys are never modified — the separator only affects auto-generated values
why
- Teams with large component libraries (hundreds of components) organize them in directory hierarchies like
services/consul,platform/eks,data/rds - With the default
-separator, the state bucket becomes a flat listing of hundreds of dash-separated prefixes — making it difficult to navigate - Previously, the only workaround was setting
workspace_key_prefixexplicitly via Go templates in every component, bypassing the cleanermetadata.namemechanism - With
prefix_separator: "/", the state bucket mirrors the component directory structure, giving users the same hierarchy in both their source tree and their state storage - The default
"-"ensures no existing configurations are affected — users opt in explicitly
Configuration
# atmos.yaml
terraform:
workspace:
prefix_separator: "/" # Preserve directory hierarchy in state pathsBefore / After
| Component | Default ("-")
| With prefix_separator: "/"
|
|---|---|---|
services/consul
| services-consul/workspace/terraform.tfstate
| services/consul/workspace/terraform.tfstate
|
platform/eks
| platform-eks/workspace/terraform.tfstate
| platform/eks/workspace/terraform.tfstate
|
Implementation
WorkspaceConfigstruct withPrefixSeparatorfield added to the Terraform schemagetWorkspacePrefixSeparatorhelper reads the configured separator (defaults to"-")applyPrefixSeparatorhelper transforms component names — preserves/when separator is"/", replaces otherwise- All three backend setter functions (
setS3BackendDefaults,setGCSBackendDefaults,setAzureBackendKey) updated to use the configured separator - All changed functions at 100% test coverage
Tests
- 20+ new unit tests covering all backends, both separators,
metadata.namewith slashes,baseComponentName, explicit config passthrough, and end-to-end flow throughprocessTerraformBackend - All pre-existing backend tests continue to pass (backward compatibility verified)
Documentation
- PRD:
docs/prd/terraform-workspace-key-prefix-slash-preservation.md - Blog post:
website/blog/2026-04-11-workspace-prefix-separator.mdx - Roadmap entry added to the
dxinitiative
references
- PRD:
docs/prd/terraform-workspace-key-prefix-slash-preservation.md— full analysis, alternatives considered, migration guide - Blog post:
website/blog/2026-04-11-workspace-prefix-separator.mdx - Affected code:
internal/exec/stack_processor_backend.go— the three setter functions that auto-generate backend key prefixes
Summary by CodeRabbit
-
New Features
- New configurable components.terraform.workspace.prefix_separator in atmos.yaml (default "-") to control Terraform backend key prefix formatting.
-
Documentation
- Added PRD, website doc, and blog post describing the setting and migration guidance; updated roadmap entry.
-
Tests
- Added unit/integration tests and updated CLI snapshots covering separator and backend-key behavior.
-
Chores
- Bumped Google Cloud client versions and updated NOTICE license references; added link-check exclusion.
feat: add ATMOS_CI_COMMENTS_ENABLED env var to override ci.comments.enabled @[copilot-swe-agent[bot]](https://github.com/apps/copilot-swe-agent) (#2300)
`ci.comments.enabled` could only be controlled via `atmos.yaml`, making it impossible to disable PR/MR comments in specific workflows without maintaining separate config profiles.Changes
pkg/config/utils.go: ParseATMOS_CI_COMMENTS_ENABLEDinprocessEnvVars(), overridingatmosConfig.CI.Comments.Enabledwhen set. Follows the same pattern asATMOS_VERSION_CHECK_ENABLED. Invalid values emit a warning and leave the config unchanged.pkg/config/utils_test.go: Tests coveringtrue/false/1/0values, unset behavior (YAML value preserved), and invalid input (config unchanged in both directions).website/docs/cli/configuration/ci/comments.mdx: Document the new env var in the config reference and a dedicated Environment Variables section.website/docs/cli/configuration/ci/index.mdx: AddATMOS_CI_COMMENTS_ENABLEDto the CI environment variables table.
Usage
# atmos.yaml — default enabled for most workflows
ci:
comments:
enabled: true# GitHub Actions — disable comments in a specific workflow
- name: Plan (no comments)
env:
ATMOS_CI_COMMENTS_ENABLED: "false"
run: atmos terraform plan ...The env var takes precedence over the YAML value when set; when unset, the YAML value is used unchanged.
fix: Add ATMOS_CI_GITHUB_TOKEN for separate CI token override @osterman (#2304)
what
- Added
ATMOS_CI_GITHUB_TOKENenvironment variable with highest priority in CI token resolution (ATMOS_CI_GITHUB_TOKEN>GITHUB_TOKEN>GH_TOKEN) - Added actionable error hints when GitHub Status API returns 404 or 403, explaining token permission requirements and suggesting
ATMOS_CI_GITHUB_TOKEN - Switched
createCheckRun/updateCheckRunerror wrapping fromfmt.Errorfto the error builder pattern to preserve hint metadata through the error chain
why
- Users running Atmos in GitHub Actions with a GitHub App token (e.g., for Terraform managing GitHub repos) get 404 errors on commit status updates because the App token lacks
statuses: writepermission - The workflow's default
GITHUB_TOKENhas the right permission via thepermissions:block, but there was no way to use a separate token for CI operations vs Terraform - The raw 404 error gave no guidance on what went wrong or how to fix it — users with
statuses: writein their workflow were confused why it wasn't working
references
- Follows existing
ATMOS_CI_*naming convention (ATMOS_CI_OUTPUT,ATMOS_CI_SUMMARY,ATMOS_CI_SHA, etc.)
Summary by CodeRabbit
-
New Features
- Added support for a dedicated CI GitHub token (ATMOS_CI_GITHUB_TOKEN) with highest precedence over GITHUB_TOKEN and GH_TOKEN.
-
Bug Fixes
- Improved GitHub API error reporting to include actionable hints for permission/authentication failures (notably 403/404).
-
Documentation
- Published blog post and updated roadmap describing the new CI token and guidance.
-
Tests
- Expanded coverage to validate token precedence and error-hint behavior.
docs: Fix component-level auth identity selection syntax @osterman (#2301)
what
- Fixed incorrect
auth.identity: <name>syntax in the auth documentation to use the actual supportedauth.identities.<name>.default: truesyntax - Updated both the "Component-Level Configuration" and "Component-Level Identity Selection" examples in
website/docs/stacks/auth.mdx
why
- A user reported that component-level identity selection was not working. The root cause was that the documentation showed a non-existent
auth.identityshorthand syntax. - The
ComponentAuthConfigstruct inpkg/schema/schema_auth.goonly supportsidentities(a map), andhasDefaultIdentity()ininternal/exec/terraform_nested_auth_helper.goonly checks for identities withdefault: true. - Users following the docs were writing config that was silently ignored, causing components to run under the default identity instead of the intended one.
references
- Reported by a user in Slack who was trying to use component-level identity selection per https://atmos.tools/stacks/auth#component-level-identity-selection
- Working example syntax confirmed via cloudposse-examples/atmos-native-ci
Summary by CodeRabbit
- Documentation
- Updated authentication configuration documentation for component-level settings. The
authblock structure has been revised to use anidentitiesmap instead of a singleidentityfield. This enables multiple identity configurations per component, with the ability to designate one identity as the default usingdefault: true.
- Updated authentication configuration documentation for component-level settings. The
feat: Add OAuth2 PKCE browser-based auth for AWS user/root identities @Benbentwo (#2148)
what
- Implement OAuth2 PKCE browser-based authentication as a third-tier fallback for
aws/useridentity - Add interactive browser flow with local callback server and bubbletea spinner
- Add non-interactive mode that displays authorization URL and prompts for manual code entry
- Cache refresh tokens to XDG cache directory for 12-hour session reuse
- Automatically refresh temporary credentials every 15 minutes via refresh token grant
why
AWS recently introduced browser-based OAuth2 authentication for IAM users and root accounts, eliminating the need for static access keys. This implementation provides the same convenient web-based flow that SSO users already enjoy, as a fallback when YAML credentials and keychain credentials are unavailable. Refresh token support enables long-lived 12-hour sessions without requiring browser reopening.
references
- Closes ATMOS-162
- Related: AWS blog post on simplified developer access https://aws.amazon.com/blogs/security/simplified-developer-access-to-aws-with-aws-login/
- PRD:
docs/prd/aws-browser-auth.md
Summary by CodeRabbit
-
New Features
- Browser-based AWS sign-in fallback (OAuth2 PKCE) enabled by default: automatic browser open with spinner, plain-URL/manual stdin fallback, refresh-token caching (12h), periodic credential refresh, and persisted AWS config/credentials.
-
Bug Fixes
- Clearer user-facing error paths and improved debug logging during webflow and credential resolution failures.
-
Tests
- Extensive test coverage for PKCE, callback/server behavior, token exchange/refresh, caching, UI flows, and error scenarios.
-
Documentation
- Blog post, docs, and roadmap updated; new config option to disable the browser fallback.
feat: Add GitHub Actions format to atmos auth env @osterman (#1984)
what
- Added
--format=githuboption toatmos auth envcommand - Added
--outputflag for explicit file output (appends mode) - Automatically detects
$GITHUB_ENVenvironment variable when using github format - Supports single-line values as
KEY=valueand multiline values with heredoc syntax
why
This eliminates the need for complex shell pipelines like atmos auth env ... | grep "^export " | sed 's/^export //' >> $GITHUB_ENV. Users can now directly output to GitHub Actions $GITHUB_ENV file with proper formatting and multiline value handling.
references
Closes issue related to GitHub Actions integration workflow simplification.
Summary by CodeRabbit
-
New Features
- GitHub Actions format for
atmos auth env: Export credentials directly to $GITHUB_ENV with--format=github - New
--output-fileflag to redirect output to a file - Automatic $GITHUB_ENV detection when using GitHub format without explicit output file specification
- GitHub Actions format for
-
Documentation
- Updated CLI help and documentation to reflect new format and flag options
- Added blog post about GitHub Actions format integration
Add environment specification for Homebrew bump action @goruha (#2289)
what
- Add environment specification for Homebrew bump action
why
- Reduce secrets visibility
Summary by CodeRabbit
- Chores
- Updated release infrastructure configuration for deployment automation.
feat: AWS Security & Compliance — finding-to-code mapping with AI remediation @aknysh (#2282)
what
- Add
atmos aws security analyze— fetch security findings from AWS Security Hub, map them to Atmos components and stacks via resource tags, and generate structured remediation reports - Add
atmos aws compliance report— generate compliance posture reports against industry frameworks (CIS AWS, PCI-DSS, SOC2, HIPAA, NIST) with pass/fail scoring - Add finding-to-code mapping pipeline with 7 strategies:
finding-tag(exact),tag-api(exact),context-tags(high),account-map(low),ecr-repo(low),naming-convention(low),resource-type(low) - Add optional AI-powered remediation via
--aiflag — multi-turn tool analysis reads component source and stack config, generates root cause analysis, specific code changes, stack YAML changes, deploy commands, risk assessment - Add AI finding deduplication (same title+component+stack analyzed once) and retry with exponential backoff for transient API errors
- Add 4 output formats: Markdown (terminal), JSON (CI/CD), YAML, CSV
- Add Atmos Auth integration via
identityconfig field for targeting Security Hub delegated admin accounts - Add
--stack,--component,--severity,--source,--framework,--format,--file,--max-findings,--no-group,--region,--identityflags - Add AI tools:
atmos_list_findings,atmos_describe_finding,atmos_analyze_finding,atmos_compliance_report - Add example:
examples/aws-security-compliance/ - Add Docusaurus docs for all commands and configuration
- Add blog post with production testing results
why
Reviewing AWS security findings today requires navigating multiple AWS console pages, cross-referencing resources with Terraform code, and manually figuring out which configuration caused the issue. This is slow, error-prone, and requires deep AWS + Terraform expertise.
Atmos owns the component-to-stack relationship, so it can trace a security finding on an AWS resource all the way back to the exact Terraform code and stack configuration that created it — and generate a targeted fix.
The key differentiator vs AWS MCP security servers: MCP servers return raw findings but have no concept of Atmos stacks, components, or Terraform source code. Our implementation maps findings to IaC and generates specific remediation with deploy commands.
See It in Action
Tested against a multi-account AWS organization (11 accounts, Security Hub delegated admin, 500 findings, 97.2% mapped to Atmos components).
1. Security findings mapped to components
$ atmos aws security analyze --stack plat-use2-dev --component rds/example
ℹ Fetching security findings...
ℹ Mapping 500 findings to Atmos components...
ℹ Filtered to 4 findings matching stack="plat-use2-dev" component="rds/example"
# Security Report: plat-use2-dev / rds/example
Findings: 4 (1 CRITICAL, 3 HIGH)
## CRITICAL Findings (1)
### 1. Security groups should not allow unrestricted access to ports with high risk
| Field | Value |
|----------------|--------------------------------------------------------------|
| **Severity** | CRITICAL |
| **Source** | security-hub (aws-foundational-security-best-practices/1.0) |
| **Resource** | arn:aws:ec2:us-east-2:***:security-group/sg-*** |
| **Component** | rds/example |
| **Stack** | plat-use2-dev |
| **Confidence** | exact |
| **Mapped By** | finding-tag |
Resource Tags:
• atmos_stack = plat-use2-dev
• atmos_component = rds/example
• terraform_component = rds
• Name = acme-plat-use2-dev-example-postgres-db
• Namespace = acme, Tenant = plat, Environment = use2, Stage = dev
## Summary
| Severity | Count | Mapped | Unmapped |
|-----------|-------|--------|----------|
| CRITICAL | 1 | 1 | 0 |
| HIGH | 3 | 3 | 0 |
| **Total** | **4** | **4** | **0** |
2. AI-powered remediation (--ai)
$ atmos aws security analyze --stack plat-use2-dev --component rds/example --ai
ℹ Analyzing findings with AI...
✓ AI analysis complete — Security Analysis: rds/example in plat-use2-dev
## Findings Breakdown
### EC2.18: Unrestricted Ingress on Unauthorized Port (HIGH)
Port 5432 (PostgreSQL) is open to 0.0.0.0/0. The likely cause is
allowed_cidr_blocks being set to an overly permissive value.
### EC2.13: Unrestricted Ingress on Port 22/SSH (HIGH)
⚠️ Port 22 has no business being on an RDS security group. This strongly
suggests an out-of-band manual change in the AWS Console — drift from IaC.
## Root Cause (Common Thread)
Both findings stem from var.allowed_cidr_blocks being set too permissively,
compounded by possible out-of-band drift.
## Priority Actions
1. Remove the port-22 inbound rule manually (out-of-band drift)
2. Update catalog/rds/example.yaml:
allowed_cidr_blocks: []
publicly_accessible: false
use_private_subnets: true
3. Add Terraform validation guards:
validation {
condition = !contains(var.allowed_cidr_blocks, "0.0.0.0/0")
error_message = "allowed_cidr_blocks must not contain 0.0.0.0/0."
}
4. Plan and apply:
atmos terraform plan rds/example -s plat-use2-dev
atmos terraform apply rds/example -s plat-use2-dev
## Risk Assessment
| Finding | Risk | Note |
|----------------------|--------|--------------------------------------------|
| EC2.18 (port 5432) | Medium | Removing rule breaks direct DB connections |
| EC2.13 (port 22/SSH) | Low | No RDS traffic should depend on SSH |
3. Compliance report
$ atmos aws compliance report
# Compliance Report: CIS AWS Foundations Benchmark
## Score: 35/42 Controls Passing (83%)
### Failing Controls
| Control | Title | Severity |
|--------------|-----------------------------------------------------------------------|----------|
| Config.1 | AWS Config should be enabled with service-linked role | CRITICAL |
| EC2.14 | Security groups should not allow ingress from 0.0.0.0/0 to port 3389 | HIGH |
| EC2.13 | Security groups should not allow ingress from 0.0.0.0/0 to port 22 | HIGH |
| S3.1 | S3 buckets should have block public access settings enabled | MEDIUM |
| EC2.6 | VPC flow logging should be enabled in all VPCs | MEDIUM |
| IAM.17 | Ensure IAM password policy expires passwords within 90 days | LOW |
| CloudTrail.7 | Ensure S3 access logging on CloudTrail S3 bucket | LOW |
4. Compliance report with AI (--ai)
$ atmos aws compliance report --ai
✓ AI analysis complete — CIS Foundations Benchmark
## Overall Status: 🟡 83% Compliant (35/42 controls passing)
## 🚨 Priority Issues (Fix First)
### CRITICAL
| Control | Issue | Action |
|----------|----------------------------------------|------------------------------------|
| Config.1 | AWS Config not enabled or missing role | Enable in all regions, attach role |
### HIGH
| Control | Issue | Action |
|---------|------------------------------------|-----------------------------------------|
| EC2.14 | RDP (port 3389) open to 0.0.0.0/0 | Restrict to known IP ranges or VPN |
| EC2.13 | SSH (port 22) open to 0.0.0.0/0 | Use SSM Session Manager instead of SSH |
## 🟠 Medium: S3.1 (Block Public Access), EC2.6 (VPC Flow Logs)
## 🟢 Low: IAM.17 (Password policy), CloudTrail.7 (S3 access logging)
## Next Steps
1. Lock down security groups for ports 22/3389
2. Enable AWS Config — also detects future drift
3. Run `atmos terraform apply` on security-groups, vpc, config components
4. Re-run this report to verify score improves
New CLI Commands
atmos aws security analyze
Fetches findings from Security Hub, maps them to Atmos components via resource tags (7 mapping strategies with confidence levels), and renders reports in 4 formats. Post-mapping --stack and --component filters narrow results after mapping. With --ai, the AI reads component source code and stack config via multi-turn tools to generate specific remediation.
atmos aws compliance report
Queries Security Hub enabled standards, counts total controls via ListSecurityControlDefinitions, and computes pass/fail scores. Supports --framework filter for CIS AWS, PCI-DSS, SOC2, HIPAA, NIST. With --ai, generates prioritized remediation for each failing control.
Configuration
aws:
security:
enabled: true
identity: "security-readonly" # Atmos Auth → Security Hub account
region: "us-east-2" # Aggregation region
max_findings: 500
tag_mapping:
stack_tag: "atmos:stack"
component_tag: "atmos:component"Example
See examples/aws-security-compliance/ for a complete configuration with auth, tag mapping, AI provider, and all commands.
references
- PRD:
docs/prd/atmos-aws-security-compliance.md - Blog:
website/blog/2026-04-03-aws-security-compliance.mdx - Example:
examples/aws-security-compliance/ - Docs:
website/docs/cli/commands/aws/security/,website/docs/cli/commands/aws/compliance/ - Config:
website/docs/cli/configuration/aws/security.mdx
Summary by CodeRabbit
Release Notes
-
New Features
- AWS Security Hub integration with automatic mapping of findings to Atmos components and stacks
- Compliance reporting with support for CIS-AWS, PCI-DSS, SOC2, HIPAA, and NIST frameworks
- AI-powered remediation analysis using
--aiflag for structured guidance - Multiple output formats (Markdown, JSON, YAML, CSV) for security and compliance reports
- Configuration schema for AWS security settings, tag mapping, and frameworks
-
Documentation
- Added comprehensive guides for
atmos aws security analyzeandatmos aws compliance reportcommands - Added AWS configuration documentation for security settings and tag-based component mapping
- Added blog post and examples demonstrating end-to-end AWS security workflows
- Added comprehensive guides for
🚀 Enhancements
fix: Custom command sharing name with experimental built-in no longer triggers warning @aknysh (#2319)
what
- Fixed experimental command detection to only match top-level built-in commands, not custom commands that share the same name
- Added
isTopLevelCommand()helper to verify a command is a direct child of the root command - Updated
findExperimentalParent()to require both a registry match and top-level position
why
- A user-defined custom command
atmos utils aiwas incorrectly triggering the experimental warning for the built-inatmos aicommand - The detection logic in
findExperimentalParent()walked the command tree and checkedIsCommandExperimental(c.Name()), which matches on bare name only — so any nested command node namedaimatched the registered built-inaiprovider - The fix ensures registry-based experimental detection only fires when the command is a direct child of root (parent's parent is nil), distinguishing
atmos aifromatmos utils ai
references
- Closes #2315
Summary by CodeRabbit
- Bug Fixes
- Improved experimental command detection so only top-level experimental commands are treated as experimental. This prevents custom or nested commands with the same name from being misclassified, ensuring experimental labels and related behavior appear only for the intended root-level commands.
fix: Return upload errors instead of silently swallowing them @osterman (#2316)
what
describe affected --uploadandlist instances --uploadnow return errors instead of silently swallowing them when the Atmos Pro API client cannot be created or the upload failsdescribe affected --uploadreturns actionable hints guiding users to setATMOS_PRO_TOKENorATMOS_PRO_WORKSPACE_ID- All Atmos Pro API requests now include a
User-Agentheader (atmos/<version> (<os>; <arch>)) instead of the Go defaultGo-http-client/1.1
why
- Upload failures (misconfigured credentials, wrong workspace ID, server-side access denied) were invisible — the CLI logged a warning but returned success, making it impossible to diagnose issues like "workspace does not have access to repository"
- The missing
User-Agentheader made it difficult to identify Atmos CLI traffic in server logs
references
- Server-side error observed:
Workspace does not have access to repositorywas logged server-side but never surfaced to the CLI user
Summary by CodeRabbit
-
Bug Fixes
- Upload failures now propagate and halt commands instead of being silently skipped.
- Pro API client creation now returns descriptive errors with authentication/workspace hints.
-
New Features
- Pro API requests include User-Agent headers with version and system info.
-
Documentation
- Added "Atmos Pro" doc with setup, OIDC guidance, CLI usage, env vars, and troubleshooting; added to CLI sidebar and navbar.
-
Tests
- Added/updated tests to enforce explicit API client/auth failure handling.
fix: CI job summary shows NO_CHANGE badge for output-only Terraform changes @osterman (#2306)
what
- When Terraform plan detects only output changes (exit code 2), the CI job summary now correctly distinguishes this from "no changes" and "resource changes"
- Added a new blue
OUTPUT_CHANGEbadge for output-only plans/applies, distinct from the grayNO_CHANGEbadge and the resource-levelCREATE/CHANGE/REPLACE/DESTROYbadges - Template headings now differentiate: "Resource Changes Found" vs "Output Changes Found" vs "No Changes"
- Plan detail summary shows "Output values will change. No infrastructure changes." for output-only changes
why
- Terraform exits with code 2 when there are changes, including output-only changes (no infrastructure modifications). The existing
HasChanges()method only checked resource counts, so output-only changes were incorrectly reported as "NO_CHANGE" in CI job summaries. This was misleading because Terraform considers these real changes that need to be applied. - Making the distinction between resource changes and output-only changes explicit helps CI users understand at a glance whether infrastructure will be modified or just state outputs will be updated.
references
- Terraform plan exit codes: 0 = no changes, 1 = error, 2 = changes detected (includes output-only changes)
Summary by CodeRabbit
-
New Features
- Detect and report Terraform output-only changes with distinct "Output Changes Found" / "Output Changes Applied" messaging.
-
Improvements
- Separate resource vs output-only summaries, badges, and details for clearer plan/apply results.
- Revised workspace handling to prefer selection before creation and improved handling of missing state files on Windows.
- Added utilities to clear Terraform caches to reduce stale-state issues.
-
Tests
- Added/expanded tests for output-only detection, summaries, workspace behaviors, and cache isolation.
-
Documentation
- Updated templates and fixtures to reflect new messaging.
fix: Replace symlink strategy with plain directory for SAML browser storage @aknysh (#2312)
what
- Fixes SAML browser storage state failing to save on Windows — the directory at
~/.aws/saml2aws/was missing because the previous symlink-based strategy requires privileges most Windows users don't have - Replaces the symlink-based storage directory strategy with plain directory creation on all platforms — no special privileges required
- Handles legacy symlink migration: detects and removes stale symlinks from previous Atmos versions, preserving any existing
storageState.jsonfrom the symlink target - Removes ~70 lines of dead symlink code (symlink creation, staging, restore, validation)
- Adds comprehensive cross-platform tests for the new directory-based storage strategy and legacy migration
- Adds fix doc with full end-to-end auth flow analysis explaining the two independent storage systems (AWS credentials vs Playwright browser session state)
why
- Root cause: the previous symlink strategy created
~/.aws/saml2awsas a symlink to an XDG cache directory. On Windows,os.Symlinkrequires Developer Mode or admin privileges — without these, the symlink creation failed silently and the directory was simply absent. The upstream saml2aws library then failed to writestorageState.jsonbecause the parent directory did not exist ("The system cannot find the path specified") - Impact is browser session reuse only:
storageState.jsoncontains Playwright browser session data (cookies for re-authentication). It is NOT part of the AWS credential pipeline — credentials are stored separately in INI files under~/.config/atmos/aws/{provider}/credentialsusingfilepath.Join(correct on all platforms). Without the fix, users must re-authenticate in the browser every time instead of reusing a saved session - The fix creates a plain directory at the path saml2aws expects using
os.MkdirAllwithfilepath.Join— works on all platforms, no special privileges required. Legacy symlinks from previous versions are detected and migrated (preserving existing session state) - Upstream bug: saml2aws also constructs the storage path using
fmt.Sprintfwith hardcoded forward slashes instead offilepath.Join, producing mixed separators on Windows. Go'sospackage normalizes these internally, so once the directory exists the path resolves correctly
references
- Fix doc:
docs/fixes/2026-04-10-auth-windows-path-issues.md(full root-cause analysis, auth flow trace, impact assessment) - Upstream bug:
github.com/versent/saml2aws/v2/pkg/provider/browser/browser.go:118— usesfmt.Sprintfwith hardcoded forward slashes instead offilepath.Join - Related:
saml-driver-installbranch / PR #1747 — the branch where the symlink strategy was originally implemented - Related:
docs/prd/saml-browser-driver-integration.md— SAML browser driver integration PRD
Summary by CodeRabbit
-
Bug Fixes
- Fixed Windows failures saving browser session state during SAML authentication by ensuring a real, platform-correct storage directory and automatic migration of existing setups.
- Improved cross-platform robustness and preserved existing session state where present.
-
Documentation
- Added a detailed guide describing the issue, root cause, and migration strategy.
-
Tests
- Added cross-platform tests verifying idempotent directory creation, state preservation, and migration behavior.
fix: Enable automatic Playwright browser driver download for SAML authentication @osterman (#1747)
what
Fixes SAML authentication failing with "please install the driver (v1.47.2) and browsers first" error when download_browser_driver: true is configured.
why
Root cause: The DownloadBrowser flag was set on saml2aws IDPAccount config but NOT on LoginDetails, which is what saml2aws actually checks when deciding whether to download drivers.
Additionally, the code was using incorrect Playwright cache directory paths (ms-playwright-go instead of ms-playwright), causing driver detection to fail.
Changes
Code Changes
- Set
LoginDetails.DownloadBrowserincreateLoginDetails()to matchshouldDownloadBrowser()logic - Corrected Playwright cache directory paths from
ms-playwright-gotoms-playwright(actual playwright-go location) - Enhanced driver detection to verify actual browser binaries exist (not just empty version directories)
Testing
- Added comprehensive integration test that downloads real Chromium drivers (~140 MB) and validates installation
- Unit tests verify
LoginDetails.DownloadBrowseris set correctly across all scenarios - Driver detection tests verify empty directories don't register as valid installations
Documentation
- Removed broken manual installation command (
go run playwright install) - Added warning about manual installation requiring advanced knowledge of playwright-go internals
- Clarified cache directory locations and why PATH is not required
- Emphasized
download_browser_driver: trueas the recommended approach
references
- Fixes the issue where SAML authentication with
download_browser_driver: truestill fails - Related to playwright-go embedded library behavior vs standalone playwright CLI tool
- Playwright cache locations: https://playwright.dev/docs/browsers#managing-browser-binaries
Summary by CodeRabbit
-
New Features
- Opt-in automatic Playwright browser driver downloads for AWS SAML auth (download_browser_driver); new browser_type and browser_executable_path config options; improved cross-platform driver detection, XDG-compliant storage with symlink handling; Logrus routed into Atmos logging; new sentinel error for invalid browser executables.
-
Documentation
- Expanded guides for auto-download workflow, custom browser config, platform cache paths, examples, and heavy integration test instructions.
-
Tests
- Added unit and integration tests covering driver detection, download/install flow, storage/symlink behavior, and logging adapter; CI gate to enable integrations.
fix: Ensure terraform plan-diff processes yaml and skips init properly @jhoward-rula (#2305)
what
- Fixes a bug where
atmos terraform plan-diffwould not properly process templates, functions, or respect the--skip-initflag. - Issue #2258
why
- Issue #2258
references
- closes #2258
Summary by CodeRabbit
- New Features
- The
plan-diffcommand now accepts additional configuration options for controlling Terraform template processing, function execution, and initialization behavior during plan operations.
- The
fix: Atmos Auth stack-level default identity resolution @aknysh (#2303)
what
- Fixes three related bugs in Atmos Auth identity resolution without breaking any existing auth functionality.
- Issue #2293: Teaches the stack auth scanner to follow
import:chains recursively, soauth.identities.<name>.default: truedeclared in an imported_defaults.yamlis visible to every command — including multi-stack commands likedescribe stacks/describe affected/list affected. - Discussion https://github.com/orgs/cloudposse/discussions/122%7C#122: Splits the
pkg/authentry points into a NO-SCAN variant (for commands with a stack-scoped merged auth config) and a SCAN variant (for multi-stack commands). The split makes the cross-stack default-identity leak structurally impossible for terraform/helmfile/describe-component flows. - Issue 3 (component-level default override): When a component declares its own
auth.identities.<name>.default: trueand the globalatmos.yamlalso has a different default, the component-level default now wins cleanly instead of producing "multiple default identities" prompts. - Keeps every previous auth fix intact, including the Approach 1 / Approach 2 design, the
allAgreeconflict-detection, the describe-affected AuthManager threading, and the MCP scoped-auth env-override flow. - Adds two scenario fixtures (using mock AWS identities for CI), three CLI regression test cases, and extensive unit tests covering every new code path.
why
- Issue #2293 — imported defaults invisible: when
auth.identities.<name>.default: truewas declared in an imported_defaults.yaml(especially one listed understacks.excluded_paths, which is the common reference-architecture layout), the pre-scanner never saw it. Users hit "No default identity configured" on commands that should have auto-authenticated. The exec-layer merge path already handled this correctly for terraform/helmfile/describe-component, but multi-stack commands (describe stacks,describe affected,list affected, workflows,aws security/compliance, MCP scoped auth) all failed. - Discussion https://github.com/orgs/cloudposse/discussions/122%7C#122 — single stack default leaks globally: when a single stack manifest declared
default: true, that identity silently propagated to every other stack across all tenants. Runningatmos terraform plan eks -s plat-stagingwould pick up thedata-stagingdefault declared in an unrelated stack file. Reported to reproduce against Atmos 1.210, 1.211, and 1.213. - Issue 3 — component-level default doesn't override global: when a component in a stack config declares a different identity as
default: truethan the globalatmos.yamldefault, both defaults survived the exec-layer deep merge inMergeComponentAuthConfig. Users were prompted to choose between multiple defaults (interactive) or got errors (CI). This broke the expected Atmos inheritance semantics where more-specific config overrides more-general. - No regressions allowed: an earlier draft removed the pre-scanner entirely. That fixed Issues 1 and 2 for
terraform *but regresseddescribe stacks,describe affected,list affected,list instances,aws security,aws compliance, and workflow execution — all of which were documented indocs/fixes/stack-level-default-auth-identity.mdas intentionally using the pre-scanner (Approach 2). This PR preserves that Approach 2 code path while fixing all three bugs, so no existing user-visible functionality is removed.
references
- closes #2293
- design doc:
docs/fixes/2026-04-08-atmos-auth-identity-resolution-fixes.md(full caller audit, rejected alternatives, coverage matrix) - related:
docs/fixes/stack-level-default-auth-identity.md(Approach 1 / Approach 2 design this PR preserves and extends) - related:
docs/fixes/2026-02-12-auth-realm-isolation-issues.md(Issue #2072allAgreeconflict-detection preserved unchanged) - related:
docs/fixes/2026-03-25-describe-affected-auth-identity-not-used.md(AuthManager threading through describe/list-affected preserved unchanged) - related:
docs/fixes/2026-04-06-mcp-server-env-not-applied-to-auth-setup.md(MCP scoped-auth flow now routes through the scan variant)
Summary by CodeRabbit
- Bug Fixes
- Identity resolution now discovers defaults from imported stack files, prevents defaults leaking across stacks/commands, and ensures component-level defaults override global defaults.
- Refactor
- Split auth manager flow into SCAN vs NO-SCAN paths and switched relevant commands to the SCAN variant for multi-stack/no-target contexts.
- Documentation
- Added a detailed guide describing the identity-resolution fixes and routing.
- Tests
- Added extensive unit, integration and CLI regression tests plus fixtures covering import-following, isolation, conflicts, and non-leakage.
fix: MCP server env block not applied to auth setup; consolidate env primitives in pkg/env and pkg/auth @aknysh (#2291)
what
- Bug fix: External MCP servers configured with both
identity:and anenv:block containingATMOS_*variables (e.g.ATMOS_PROFILE,ATMOS_CLI_CONFIG_PATH,ATMOS_BASE_PATH) failed auth setup withidentity not found. The parent's auth manager was built once fromos.Environ()and never saw the server'senv:block. - Architectural cleanup driven by review feedback:
- New foundational primitive
env.SetWithRestoreinpkg/env(atmos already has a dedicated env package; four other local save/set/restore variants exist and should consolidate to this in a follow-up). - New high-level primitive
auth.CreateAndAuthenticateManagerWithEnvOverridesinpkg/auththat delegates env mutation topkg/envand composescfg.InitCliConfig+auth.CreateAndAuthenticateManagerWithAtmosConfig. - Thin MCP-specific adapter
mcpclient.ScopedAuthProvider(~85 lines) that implements a newPerServerAuthProviderinterface soWithAuthManagerdispatches per-server. - Canonical Atmos env-var namespace constants (
AtmosEnvVarNamespace,AtmosEnvVarPrefix) added topkg/config/const.gowith build-time invariant tests. Migrated five hardcoded\"ATMOS\"/\"ATMOS_\"literals scattered acrosscmd/root.go,cmd/auth_validate.go,pkg/auth, andpkg/ai/agent/codexclito use them.
- New foundational primitive
- Result for users: any external MCP server can now define
ATMOS_PROFILE(or any otherATMOS_*variable) in itsenv:block and have it influence identity resolution — including configurations that runatmos mcp startitself as an external MCP server (the original report).
why
- The auth manager was being constructed once at command startup using the parent's
os.Environ(). Serverenv:blocks were only applied to the spawned subprocess viacmd.Env, so the parent's identity lookup ran against the default profile and never sawATMOS_PROFILE: managers(or any other override). The user's only workaround was exporting the variable in the shell before running atmos. - The bug surfaces most visibly when a user configures
atmos mcp startitself as an external MCP server (the original report), but it affects any external MCP server with bothidentity:andenv: ATMOS_*: .... - The fix lives entirely on the client side. The Atmos MCP server (
cmd/mcp/server) was already correct: when spawned as a subprocess it inherits the merged env (os.Environ()+env:block) andcfg.InitCliConfigreadsATMOS_*from there. - Why the architectural cleanup: review feedback flagged that (a) putting per-command auth factories in
cmd/is a slippery slope, (b)pkg/authshouldn't re-implement env mutation whenpkg/envalready exists, and (c) defining what counts as an Atmos env variable inside any specific subsystem is the wrong layering. Each round of feedback pushed the primitives down to where they belong, and the result is significantly less code with cleaner layering.
layering after this PR
```
pkg/config ← AtmosEnvVarNamespace / AtmosEnvVarPrefix (single source of truth)
pkg/env ← SetWithRestore (foundational env primitive, no policy)
↑
pkg/auth ← CreateAndAuthenticateManagerWithEnvOverrides (composes pkg/env + cfg.InitCliConfig + auth)
↑
pkg/mcp/client ← ScopedAuthProvider (thin MCP adapter, ~85 lines)
↑
cmd/mcp/client, ← one-line consumers, zero auth-factory code
cmd/ai
```
test coverage
100% on every new function:
- `pkg/env/restore.go` → `SetWithRestore` (incl. setenv-error branch via injectable hook)
- `pkg/auth/manager_env_overrides.go` → `CreateAndAuthenticateManagerWithEnvOverrides` (incl. env-hook error branch via injectable hook), `filterAtmosOverrides` (table-driven)
- `pkg/mcp/client/scoped_auth.go` → `NewScopedAuthProvider`, `ForServer`, `PrepareShellEnvironment`
- `pkg/mcp/client/session.go` → `WithAuthManager` (incl. per-server dispatch branch)
- `cmd/mcp/client/start_options.go` → `buildAuthOption`, `mcpServersNeedAuth`
- `cmd/ai/init.go` → `resolveAuthProvider`
- `pkg/config/const_test.go` → invariant tests for the canonical constants
references
- closes #2283
- See `docs/fixes/2026-04-06-mcp-server-env-not-applied-to-auth-setup.md` for full root-cause analysis, the fixed flow diagram, the test plan, and a follow-up consolidation note for the four pre-existing local save/restore env helpers (`internal/exec.setEnvVarsWithRestore`, `pkg/auth/cloud/gcp.PreserveEnvironment/RestoreEnvironment`, `pkg/telemetry.PreserveCIEnvVars/RestoreCIEnvVars`, `pkg/auth/identities/aws.setupAWSEnv`) that should migrate to `env.SetWithRestore` in a separate PR.
- Related: `docs/fixes/2026-03-25-describe-affected-auth-identity-not-used.md` (another auth-context propagation fix in a different code path).
- Related PRD: `docs/prd/atmos-mcp-integrations.md` (overall MCP client architecture).
Summary by CodeRabbit
-
New Features
- Per-server authentication scoping for MCP so each server can use its own ATMOS env during auth.
- Canonical ATMOS env namespace/prefix and safer env-override handling during auth setup.
-
Bug Fixes
- MCP server ATMOS env values are now applied during authentication setup.
- Clearer error mapping when per-server auth is unavailable.
-
Documentation
- Added doc describing the auth env propagation fix and behavior.
-
Tests
- Extensive unit tests for per-server auth, env overrides/restoration, and related flows.
fix: suppress JSON output for describe affected --upload @osterman (#2284)
what
- When
--uploadis used withatmos describe affected, the full affected stacks JSON is no longer dumped to the console by default - Pass
--verboseto see the JSON output, or--fileto write it to a file - The upload success message now includes a count of affected components (e.g. "Uploaded 12 affected component(s) to Atmos Pro")
why
- The affected stacks JSON payload can be very large and overwhelms the console when the primary intent is just to upload
- Users who need the output can opt in with
--verboseor--file - The summary count provides useful feedback without the noise
Summary by CodeRabbit
-
Bug Fixes
- Suppressed the large "Affected components and stacks" console output during uploads unless verbose mode or file output is requested.
- Improved the upload success message to include the number of affected components uploaded.
-
Tests
- Added unit tests covering upload/output behavior and CI event handling to validate verbose, file-output, and upload scenarios.
fix: provenance and syntax highlighting respect --no-color and pipe detection @osterman (#2281)
what
- Provenance output (
describe component --provenance) now strips ANSI color codes when stdout is piped or redirected, and respects--no-color - Syntax highlighting via
HighlightCodeWithConfigalso properly degrades when stdout is piped - Provenance output now routes through
data.Write()instead offmt.Print()for proper I/O channel handling
why
- Provenance rendering used
lipgloss.NewStyle()unconditionally without checking stdout TTY status, so ANSI escape codes leaked into piped/redirected output HighlightCodeWithConfigcheckedIsTTYSupportForStdout() || IsTTYSupportForStderr()— since stderr remains a TTY when piping stdout, this always returned true and defeated pipe detectionfmt.Print()bypassed the data channel I/O layer, skipping secret masking
references
- Follows the same stdout-only TTY check pattern used by list commands (
pkg/list/list_values.go) - Mirrors
HighlightCodeWithConfig's precedence:NoColorwins, thenForceColor, then stdout TTY detection
Summary by CodeRabbit
-
Improvements
- More precise color handling for provenance and code highlighting: honors NoColor/ForceColor and now detects stdout TTY only for consistent styling.
- Provenance rendering disables styling when color is off.
- Provenance stdout output now flows through the shared output path for more consistent display.
-
Bug Fixes
- Normalized spacing and newline placement around provenance legends and stack headers.
-
Tests
- Updated/added tests and golden snapshots to reflect whitespace, legend formatting, and color/no-color behaviors.
Associated Pull Requests
Deployment Status
To view the Atmos Pro deployment status of this release, see #2320.