github cloudposse/atmos v1.221.1

5 hours ago
feat(ci): migrate demo-localstack to Floci (rename to demo-floci) @osterman (#2599)

what

  • Replace the LocalStack image with Floci (floci/floci:1.5.23, pinned) for the AWS-emulator demo
  • Rename the example examples/demo-localstackexamples/demo-floci, and the CI job [localstack] demo-localstack[floci] demo-floci
  • Rename all emulator-facing names inside the example: mixin (stacks/mixins/floci.yaml), YAML anchor (&floci_url), auth identity (floci-superuser), custom commands (atmos floci up|down|restart|reset|status), compose service/container
  • Decouple the vendor-globs test from this demo: it vendors **/demo-localstack/* from origin/main at test time, so a rename would break it in this PR (main has no demo-floci yet) and on every unmerged branch afterward. It now targets examples/demo-helmfile (identical root file set), keeping it green before and after merge
  • Drop LocalStack-specific service-container config Floci doesn't need (SERVICES, DEBUG, docker.sock mount, 4510-4559 port range — this demo only touches STS/IAM/S3)
  • Update devcontainer bootstrap, examples index, and website file-browser plugin references

why

LocalStack EOL'd Community Edition: the OSS repo was archived in March 2026, the unified image now requires an account + auth token, and hosted infrastructure is being dismantled — the localhost.localstack.cloud DNS breakage fixed in #2598 was collateral from that wind-down. Staying on the unpatched 2023-era localstack:1.4.0 image means depending on a dead project whose vendor is actively turning things off.

Floci is the community's drop-in replacement (MIT, no auth token, same 4566 edge port and credential pattern) and is already used by the Terraform DAG scheduler integration tests (tests/terraform_floci_dag_test.go).

merge checklist (branch protection)

[localstack] demo-localstack is a required status check on main. Merge order:

  1. Merge #2598 first (under the current rule)
  2. Update the required check on main: [localstack] demo-localstack[floci] demo-floci
  3. Merge this PR
  4. Other branches pick everything up by merging main (which they already need for the #2598 DNS fix)

verification

  • CI: the Floci-backed demo job passed in 1m50s (vs LocalStack's ~3m; Floci's native binary boots in ~26ms vs ~15s)
  • Local: full atmos test (validate + plan/apply/destroy × 3 stacks) passed against floci/floci:1.5.23 under podman
  • vendor-globs CLI test executed for real against remote main (not skipped) with the new demo-helmfile glob — passed

references

Summary by CodeRabbit

  • New Features

    • Added demo-floci example and Atmos CLI commands to manage the Floci emulator (start/stop/restart/reset/status).
  • Documentation

    • Updated example READMEs and compose guidance with Floci setup, port/credentials, and Terraform tips.
  • CI

    • CI workflows switched demo coverage from LocalStack to Floci.
  • Tests

    • Added offline test for demo-floci and updated demo-related test expectations.
  • Chores

    • Updated local demo startup script, demo manifests, and website tags to use Floci.
feat(testing): add pact consumer contracts for Atmos Pro API @goruha (#2588)

what

  • Add pact consumer contract tests for all 8 Atmos Pro API endpoints in pkg/pro/
  • Add github.com/pact-foundation/pact-go/v2 as a dev dependency
  • Generate pacts/atmos-AtmosPro.json — the consumer contract file checked into version control
  • Add a "Pact Contract Testing" section to the README with setup and usage instructions
  • Add Spec Kit workflow artifacts (.specify/, specs/) and related Claude skills

why

  • Consumer contract tests run the real AtmosProAPIClient against a pact mock server, so any change to request/response shapes in pkg/pro/ is caught locally before it reaches the live Atmos Pro API
  • Tests are isolated behind //go:build pact and never run in the standard go test ./... suite, keeping the default CI pipeline unaffected
  • Checking pacts/atmos-AtmosPro.json into version control makes API surface drift visible in PR diffs

references

  • Pact Go documentation
  • Covered endpoints: UploadAffectedStacks, LockStack, UnlockStack, ExchangeOIDCToken, GetGitHubOIDCToken, UploadInstances, UploadInstanceStatus, CreateCommit
fix(ci): use localhost endpoints in LocalStack demo to avoid DNS hangs @osterman (#2598)

what

  • Switch the demo-localstack example's AWS provider endpoints from https://localhost.localstack.cloud:4566 to http://localhost:4566
  • Enable s3_use_path_style: true so S3 operations don't depend on wildcard *.localhost.localstack.cloud DNS/TLS
  • Add skip_requesting_account_id: true so provider configure doesn't block on identity lookups
  • Update the example README to document the settings and the expected "AWS account ID not found for provider" warning

why

The [localstack] demo-localstack CI job started hanging until the 20-minute timeout across all branches beginning 2026-06-10 ~02:18 UTC, with no corresponding code change (identical commits both passed and failed; the LocalStack image is pinned at 1.4.0 with the same build hash in green and red runs).

Root cause: localhost.localstack.cloud is a public DNS record hosted by LocalStack that resolves to 127.0.0.1. After LocalStack EOL'd Community Edition (repo archived March 2026), their DNS zone was restructured on 2026-06-08 18:53 UTC (SOA serial; the record is now a freshly delegated Route53 subzone). GitHub's Azure runners began intermittently failing to resolve the name ~31h later as resolver caches expired. The Terraform AWS provider treats DNS failure as retryable and backs off past the job timeout — hanging silently before its first API call.

Evidence:

  • Every failed run hangs at the identical point: after terraform workspace new dev-demo, before the provider's first API call. The LocalStack container log shows exactly one completed request (sts.GetSessionToken => 200 — issued by atmos auth, which uses http://localhost:4566 and always succeeds). The provider's first call via localhost.localstack.cloud never arrives.
  • A/B proof: on osterman/fix-post-merge-sha, a run with the old endpoints timed out at 13:43 UTC; the identical change in this PR passed at 13:53 UTC (run 27281214186).

Extending the timeout would not help — the provider's retry backoff exceeds any reasonable limit when DNS is failing.

references

  • Failing runs (examples): 27248701025, 27283701712, 27282384395, 27300390150 — all cancelled at the 20-min [localstack] job timeout
  • Green run with this exact change: 27281214186
  • LocalStack Community EOL: https://blog.localstack.cloud/the-road-ahead-for-localstack/ (the DNS zone change itself is unannounced)

Summary by CodeRabbit

  • Documentation
    • Updated LocalStack example documentation and configuration for improved CI compatibility, clarifying expected Terraform behavior and configuration settings.

🚀 Enhancements

fix(exec): preserve empty lists as empty (not null) in YAML function processing @AleksandrMatveev (#2603)

what

  • Fix empty-list stack variables (e.g. attributes: []) being written as null in the generated *.terraform.tfvars.json.
  • The []any branch of processNodesWithContext now seeds its accumulator with make([]any, 0, len(v)) instead of a nil slice, so empty lists stay empty (non-nil).
  • Add a regression test (TestProcessNodesPreservesEmptyLists) covering top-level, nested, and !unset-emptied lists, asserting they remain non-nil and serialize to JSON [] rather than null.

why

  • An empty list collapsed to a nil slice during YAML-function processing. A nil slice renders as [] in YAML (so atmos describe looked correct) but marshals to null in JSON, so the generated tfvars contained "attributes": null.
  • Terraform/OpenTofu then fails on that value in functions that reject null where a list is expected:
    Error: Invalid function argument
      while calling concat(seqs...)
      Invalid value for "seqs" parameter: argument must not be null.
    
  • This is a regression introduced when the !unset YAML function was added: the slice branch was changed from index-assignment into a pre-sized slice to append onto a nil slice, to support dropping items. Bisected to commit 28678366. The fix keeps the !unset skip semantics while restoring non-nil empty-list behavior.

Minimal repro — stack var empty_list: []:

before after
empty_list in generated tfvars null []
non-empty lists preserved preserved

references

  • Regression introduced by the !unset YAML function feature (commit 28678366)

Summary by CodeRabbit

  • Bug Fixes

    • Empty lists are now preserved and serialized as JSON arrays ([]) rather than null across top-level, nested, and unset-cleared lists.
  • Tests

    • Added a regression test to verify empty-list preservation and updated CLI snapshot expectations to use empty arrays instead of null.
Fix optional toolchain signature 404 handling @osterman (#2601)

what

  • Treat missing toolchain signature and attestation evidence as skipped under signatures: when_available instead of failing installs.
  • Pre-download remote SLSA and Minisign sidecars so missing files follow the same optional policy as other signature evidence.
  • Add regression coverage for the tflint GitHub attestation 404 case, required-mode failures, missing SLSA/Minisign/Cosign evidence, and invalid signature failures.

why

  • Keeps package verification non-breaking by default while still failing when available evidence does not validate.
  • Fixes installs like terraform-linters/tflint, where gh attestation verify can return HTTP 404 because no attestation exists even though checksum verification can pass.
  • Preserves strict behavior for signatures: required.

references

  • Reported from a terraform-linters/tflint install on Atmos 1.220.0 where gh attestation verify returned HTTP 404 for missing attestations.

Summary by CodeRabbit

  • New Features

    • Fetch remote signature sidecars automatically with temporary storage and cleanup.
    • Treat certain transient attestation service stream errors as retryable.
  • Bug Fixes

    • Better handling of missing or unavailable signature/provenance/attestation evidence — mark as skipped when optional, fail when required.
    • More consistent enforcement across verification paths.
  • Tests

    • Added tests covering skip vs. required behaviors and retry classification.
fix(ansible): forward `-- ` passthrough to ansible-playbook @mtb-xt (#2594)

what

  • Fix atmos ansible playbook <component> -s <stack> -- <ansible-args> failing with a misleading Unknown command \`` error.
  • playbookCmd now uses a separator-aware argument validator instead of cobra.ExactArgs(1): it requires exactly one positional component, counting only the arguments before a -- separator.
  • Adds regression tests for the -- passthrough path.

why

  • cobra.ExactArgs(1) counts every positional argument, including the ansible-playbook passthrough tokens captured after --. Any invocation using -- (e.g. -- --check, -- --tags web, -- --limit host) therefore tripped argument validation with 2+ "positional" args, and the root UsageFunc rendered that failure as an Unknown command error naming the component.
  • This made it impossible to forward native ansible-playbook flags, even though the command help documents [options] and points at the ansible-playbook CLI docs, and the executor (buildCommandArgs) already appends info.AdditionalArgsAndFlags to the command.
  • cobra.ArgsLenAtDash() returns -1 when no -- is present, so the validator still checks the full slice for the common case and keeps the original "exactly one component" contract.

Before

$ atmos ansible playbook myapp -s prod -- --check
Error: Unknown command `myapp` for `atmos ansible playbook`

After

$ atmos ansible playbook myapp -s prod --dry-run -- --check
ansible-playbook --extra-vars @/.../prod-myapp.ansible.vars.yaml -i inventory/hosts.yml --check playbook.yml

references

Summary by CodeRabbit

  • New Features

    • Forward additional args after -- verbatim to the underlying playbook command; positional validation ignores these passthrough args.
  • Bug Fixes

    • Require exactly one component before -- and return clear validation errors when missing or duplicated.
  • Tests

    • Added comprehensive tests for separator-aware parsing, validation, and passthrough behavior, including prompt-aware validation scenarios.

Don't miss a new atmos release

NewReleases is sending notifications on new releases.