github cloudposse/atmos v1.215.0

6 hours ago
feat: add `atmos pro commit` for server-side commits via GitHub App @osterman (#2298)

what

  • Add new atmos pro commit CLI command that sends changed files to Atmos Pro, which creates commits server-side using its GitHub App installation — ensuring commits trigger CI workflows (unlike GITHUB_TOKEN commits)
  • Flexible staging control: --add "*.tf" for patterns, --all/-A for 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-pro blog tag and retroactively tags 3 existing Atmos Pro changelog entries
  • Full CLI docs, blog post announcement, and roadmap entry

why

  • Commits made with GITHUB_TOKEN in 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 commit for 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.
  • 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.
feat: Add terraform.workspace.prefix_separator setting for hierarchical state paths @aknysh (#2313)

what

  • Adds a new terraform.workspace.prefix_separator setting in atmos.yaml that controls how / in component names is handled when Atmos auto-generates backend key prefixes
  • Default value "-" preserves backward compatibility (e.g. services/consulservices-consul)
  • Setting prefix_separator: "/" preserves directory hierarchy (e.g. services/consul stays services/consul)
  • Applies to all three supported backends: S3 (workspace_key_prefix), GCS (prefix), and Azure (key component)
  • 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_prefix explicitly via Go templates in every component, bypassing the cleaner metadata.name mechanism
  • 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 paths

Before / 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

  • WorkspaceConfig struct with PrefixSeparator field added to the Terraform schema
  • getWorkspacePrefixSeparator helper reads the configured separator (defaults to "-")
  • applyPrefixSeparator helper 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.name with slashes, baseComponentName, explicit config passthrough, and end-to-end flow through processTerraformBackend
  • 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 dx initiative

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: Parse ATMOS_CI_COMMENTS_ENABLED in processEnvVars(), overriding atmosConfig.CI.Comments.Enabled when set. Follows the same pattern as ATMOS_VERSION_CHECK_ENABLED. Invalid values emit a warning and leave the config unchanged.
  • pkg/config/utils_test.go: Tests covering true/false/1/0 values, 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: Add ATMOS_CI_COMMENTS_ENABLED to 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_TOKEN environment 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/updateCheckRun error wrapping from fmt.Errorf to 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: write permission
  • The workflow's default GITHUB_TOKEN has the right permission via the permissions: 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: write in 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 supported auth.identities.<name>.default: true syntax
  • 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.identity shorthand syntax.
  • The ComponentAuthConfig struct in pkg/schema/schema_auth.go only supports identities (a map), and hasDefaultIdentity() in internal/exec/terraform_nested_auth_helper.go only checks for identities with default: 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

Summary by CodeRabbit

  • Documentation
    • Updated authentication configuration documentation for component-level settings. The auth block structure has been revised to use an identities map instead of a single identity field. This enables multiple identity configurations per component, with the ability to designate one identity as the default using default: true.
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/user identity
  • 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

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=github option to atmos auth env command
  • Added --output flag for explicit file output (appends mode)
  • Automatically detects $GITHUB_ENV environment variable when using github format
  • Supports single-line values as KEY=value and 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-file flag to redirect output to a file
    • Automatic $GITHUB_ENV detection when using GitHub format without explicit output file specification
  • 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 --ai flag — 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 identity config field for targeting Security Hub delegated admin accounts
  • Add --stack, --component, --severity, --source, --framework, --format, --file, --max-findings, --no-group, --region, --identity flags
  • 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 --ai flag 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 analyze and atmos aws compliance report commands
    • Added AWS configuration documentation for security settings and tag-based component mapping
    • Added blog post and examples demonstrating end-to-end AWS security workflows

🚀 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 ai was incorrectly triggering the experimental warning for the built-in atmos ai command
  • The detection logic in findExperimentalParent() walked the command tree and checked IsCommandExperimental(c.Name()), which matches on bare name only — so any nested command node named ai matched the registered built-in ai provider
  • 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 ai from atmos utils ai

references

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 --upload and list instances --upload now return errors instead of silently swallowing them when the Atmos Pro API client cannot be created or the upload fails
  • describe affected --upload returns actionable hints guiding users to set ATMOS_PRO_TOKEN or ATMOS_PRO_WORKSPACE_ID
  • All Atmos Pro API requests now include a User-Agent header (atmos/<version> (<os>; <arch>)) instead of the Go default Go-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-Agent header made it difficult to identify Atmos CLI traffic in server logs

references

  • Server-side error observed: Workspace does not have access to repository was 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_CHANGE badge for output-only plans/applies, distinct from the gray NO_CHANGE badge and the resource-level CREATE/CHANGE/REPLACE/DESTROY badges
  • 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.json from 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/saml2aws as a symlink to an XDG cache directory. On Windows, os.Symlink requires 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 write storageState.json because the parent directory did not exist ("The system cannot find the path specified")
  • Impact is browser session reuse only: storageState.json contains 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}/credentials using filepath.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.MkdirAll with filepath.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.Sprintf with hardcoded forward slashes instead of filepath.Join, producing mixed separators on Windows. Go's os package 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 — uses fmt.Sprintf with hardcoded forward slashes instead of filepath.Join
  • Related: saml-driver-install branch / 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.DownloadBrowser in createLoginDetails() to match shouldDownloadBrowser() logic
  • Corrected Playwright cache directory paths from ms-playwright-go to ms-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.DownloadBrowser is 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: true as the recommended approach

references

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-diff would not properly process templates, functions, or respect the --skip-init flag.
  • Issue #2258

why

references

Summary by CodeRabbit

  • New Features
    • The plan-diff command now accepts additional configuration options for controlling Terraform template processing, function execution, and initialization behavior during plan operations.
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, so auth.identities.<name>.default: true declared in an imported _defaults.yaml is visible to every command — including multi-stack commands like describe stacks / describe affected / list affected.
  • Discussion https://github.com/orgs/cloudposse/discussions/122%7C#122: Splits the pkg/auth entry 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: true and the global atmos.yaml also 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 allAgree conflict-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: true was declared in an imported _defaults.yaml (especially one listed under stacks.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. Running atmos terraform plan eks -s plat-staging would pick up the data-staging default 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: true than the global atmos.yaml default, both defaults survived the exec-layer deep merge in MergeComponentAuthConfig. 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 regressed describe stacks, describe affected, list affected, list instances, aws security, aws compliance, and workflow execution — all of which were documented in docs/fixes/stack-level-default-auth-identity.md as 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 #2072 allAgree conflict-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 an env: block containing ATMOS_* variables (e.g. ATMOS_PROFILE, ATMOS_CLI_CONFIG_PATH, ATMOS_BASE_PATH) failed auth setup with identity not found. The parent's auth manager was built once from os.Environ() and never saw the server's env: block.
  • Architectural cleanup driven by review feedback:
    • New foundational primitive env.SetWithRestore in pkg/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.CreateAndAuthenticateManagerWithEnvOverrides in pkg/auth that delegates env mutation to pkg/env and composes cfg.InitCliConfig + auth.CreateAndAuthenticateManagerWithAtmosConfig.
    • Thin MCP-specific adapter mcpclient.ScopedAuthProvider (~85 lines) that implements a new PerServerAuthProvider interface so WithAuthManager dispatches per-server.
    • Canonical Atmos env-var namespace constants (AtmosEnvVarNamespace, AtmosEnvVarPrefix) added to pkg/config/const.go with build-time invariant tests. Migrated five hardcoded \"ATMOS\" / \"ATMOS_\" literals scattered across cmd/root.go, cmd/auth_validate.go, pkg/auth, and pkg/ai/agent/codexcli to use them.
  • Result for users: any external MCP server can now define ATMOS_PROFILE (or any other ATMOS_* variable) in its env: block and have it influence identity resolution — including configurations that run atmos mcp start itself 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(). Server env: blocks were only applied to the spawned subprocess via cmd.Env, so the parent's identity lookup ran against the default profile and never saw ATMOS_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 start itself as an external MCP server (the original report), but it affects any external MCP server with both identity: and env: 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) and cfg.InitCliConfig reads ATMOS_* from there.
  • Why the architectural cleanup: review feedback flagged that (a) putting per-command auth factories in cmd/ is a slippery slope, (b) pkg/auth shouldn't re-implement env mutation when pkg/env already 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 --upload is used with atmos describe affected, the full affected stacks JSON is no longer dumped to the console by default
  • Pass --verbose to see the JSON output, or --file to 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 --verbose or --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 HighlightCodeWithConfig also properly degrades when stdout is piped
  • Provenance output now routes through data.Write() instead of fmt.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
  • HighlightCodeWithConfig checked IsTTYSupportForStdout() || IsTTYSupportForStderr() — since stderr remains a TTY when piping stdout, this always returned true and defeated pipe detection
  • fmt.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: NoColor wins, then ForceColor, 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.

Don't miss a new atmos release

NewReleases is sending notifications on new releases.