Skip to content

v1.229.0-rc.1

Pre-release
Pre-release

Choose a tag to compare

@cloudposse-releaser cloudposse-releaser released this 11 Sep 01:10
· 5 commits to main since this release
ba4cd29
Add single-label lookups with optional defaults Erik Osterman (Cloud Posse) (@osterman) (#3097) ## what
  • Add !labels key [default] with missing-key errors, explicit fallbacks, and inheritance coverage.

  • Document label access and an Atmos Pro example that consumes resolved labels; update agent skills, the feature announcement, and roadmap.

  • Allow macOS Colima startup 12 minutes for provisioning and its VM restart, and give the enclosing setup step 55 minutes to cover both attempts.

why

  • Read individual labels in stack configuration with explicit missing-key behavior.
  • Prevent CI from killing Colima during its second boot: the passing sibling job used 7m37s of the former 8-minute startup cap.

references

  • CI fix validated with actionlint, Bash syntax checks, ShellCheck, timeout-budget checks, repository lint, pre-commit hooks, and local CodeRabbit review (zero findings).
  • Historical changelog audit moved to #3099; validated with local CodeRabbit review, Go build and focused tests, lint, and website build.

Summary by CodeRabbit

  • New Features

    • !labels can retrieve an individual metadata label with an optional fallback value.
    • Bare !labels continues to return the complete label map.
    • Label values resolve from component metadata after stack defaults and inheritance.
    • Label lookups can be used in workflow inputs for component- and stack-specific runner selection.
  • Documentation

    • Expanded YAML function, metadata, workflow, migration, and roadmap documentation with syntax, examples, and fallback behavior.
    • Added a blog post detailing single-label lookups.
fix(ci): stop Mergify updating bot PRs once approved Erik Osterman (Cloud Posse) (@osterman) (#3112) ## what
  • Add #approved-reviews-by=0 to the Mergify rule Keep Dependabot/Renovate PRs up to date with main, so Mergify stops running update on a bot PR once it has an approval.

why

Since main moved to GitHub's native merge queue (ruleset "Merge Queue", 2026-08-06), this rule fails on essentially every bot PR that gets enqueued — 6 of the last 12 (#3066, #3067, #3071, #3086, #3091, #3098):

Base branch update has failed
protected branch '' check failed: A pull request for this branch has been added to a merge queue. Branches that are queued for merging cannot be updated.

Mechanism:

  • Mergify's update action merges main into the PR's head branch. GitHub locks that branch while the PR sits in the native queue.

  • Mergify's built-in "skip if queued" guard is queue-position = -1, which only reflects Mergify's own queue. There is no Mergify condition for GitHub's native queue, and nothing lands on the head SHA either (no check-run or commit status is created on enqueue), so there is nothing else to condition on.

  • The rule wakes on PR webhooks, not promptly on pushes to main. On the failing PRs the branch had been behind for 50–70 min unnoticed; Mergify re-evaluated ~2 min after the approval/enqueue events, when the branch was already locked:

    PR approved enqueued update failed merged
    #3091 02:20:02Z 02:20:09Z 02:21:44Z 02:40Z
    #3098 02:22:21Z 02:22:28Z 02:24:37Z 02:43Z
    #3067 20:35:15Z 20:35:32Z 20:37:46Z 21:25Z
    #3066 20:35:30Z 20:35:35Z 20:38:05Z 21:25Z

Why approval is the right gate: the "Required Pull Request Reviews" ruleset requires 1 approval with no bypass actors, so GitHub cannot enqueue a PR without a current approval. Approval is therefore a strictly earlier signal than enqueue, with no timing dependency (an Actions workflow on pull_request: enqueued toggling a label would be racing that same ~2 min window). After approval the merge queue owns freshness by re-testing against current main.

Side benefit: the ruleset has dismiss_stale_reviews_on_push: true, so today a Mergify update landing after approval dismisses the approval and forces a re-review. That stops.

Context: this rule was added in #2752 because main then had strict: true (require branches up to date). That protection is gone with the merge queue, so the alternative of deleting the rule outright is also valid; this keeps pre-review freshness for bot PRs.

The failures were cosmetic (Mergify is not a required status check; the PRs merged via the queue), but they show up as a red check on every bot PR.

references

  • #2752 (introduced the rule)
  • Mergify update action docs: "You do not need to use this action if you use the merge queue."

Summary by CodeRabbit

  • Chores
    • Updated automated dependency pull request handling so branches are refreshed only after receiving at least one approval.
    • Added guidance explaining the approval requirement before entering the merge queue.
fix(ci): invalidate CloudFront cache on website deploys Erik Osterman (Cloud Posse) (@osterman) (#3103) ## what
  • Add a cloudfront-distribution-id / cloudfront-invalidation-paths input and invalidation step to the shared .github/actions/s3-deploy composite action.
  • Wire it into website-deploy-prod.yml (invalidates /* on the prod atmos-docs-site-spa distribution E2WVYUGW40ZPA8) and website-preview-deploy.yml (invalidates only /pr-<N>/* on the dev distribution E1U29O8X09M5UR, so one PR's deploy never busts every other open PR's preview cache).
  • Add cloudfront.amazonaws.com:443 to both workflows' Harden Runner allowlist.
  • Add a fix-log entry documenting the root cause and validation.

why

  • atmos.tools threw a browser ChunkLoadError (404 on a hashed JS bundle). Root cause: website-deploy-prod.yml runs aws s3 sync --delete but never invalidated CloudFront, and the distribution's legacy per-behavior TTL (min_ttl: 60) floors edge caching regardless of origin Cache-Control. A client hitting a stale edge-cached index.html within that window got 404s on chunks a newer deploy had already deleted.
  • This is a different bug than the 2026-09-08 concurrent-deploy race (docs/fixes/2026-09-08-website-deploy-race-serialize.md) — confirmed via GitHub Actions run history that the existing concurrency: guard is working correctly.
  • The deploy IAM roles already grant cloudfront:CreateInvalidation/cloudfront:GetInvalidation scoped to their own distribution (confirmed live via aws iam get-role-policy, not just the infra-live Terraform source) — it was simply unused, so this fix is fully contained in cloudposse/atmos with no infra-live change needed.
  • Manually ran the invalidation against prod as immediate remediation for the live incident; confirmed it reached Completed.

references

  • docs/fixes/2026-09-09-website-cloudfront-stale-chunk-invalidation.md
  • docs/fixes/2026-09-08-website-deploy-race-serialize.md (related prior incident, confirmed not the same root cause)

Summary by CodeRabbit

  • Bug Fixes

    • CloudFront caches are now invalidated after production website deployments, helping prevent users from receiving stale pages or broken asset references.
    • Preview deployments invalidate only their corresponding preview path, reducing unintended cache refreshes.
  • Documentation

    • Added documentation describing the stale-cache issue, its resolution, and validation steps.
Link changelog announcements to usage documentation Erik Osterman (Cloud Posse) (@osterman) (#3099) ## what
  • Link 259 existing changelog posts to usage documentation and correct stale links.
  • Add missing diagnostics and component-mocks references, clarify process-metrics limits, and require usage links in changelog authoring guidance.

why

  • Make announcements lead to usable instructions independently of the label lookup feature.

references

  • Split from #3097; validated with local CodeRabbit review, changed-file lint, website build, and link checks.
feat(vendor): add Azure DevOps pull-request provider Jorrit Elfferich (@jorrite) (#3048) ## What

Adds pkg/git/providers/azuredevops as a second PullRequestPublisher implementation alongside the existing GitHub provider, so atmos vendor update --pull-request can target Azure DevOps Repos.

  • New azuredevops provider, registered via init() under ci.pull_request.provider: azuredevops.
  • schema.VendorPullRequestConfig gains organization / project / repository fields, since Azure DevOps addresses a repository with three segments instead of GitHub's owner/repository pair. pkg/config's bridgeVendorUpdaterConfig now syncs these three fields into viper along with the rest of vendor.ci.pull_request.* — they were declared on the schema and read by cmd/vendor/update.go but never actually bridged, so provider: azuredevops always failed configuration validation regardless of what atmos.yaml declared (found by testing against a real Azure DevOps org).
  • PullRequestOptions gains an additive Namespace []string field to carry the extra segment (nil for GitHub; the GitHub provider now rejects a non-empty Namespace instead of silently ignoring it).
  • Authenticates via AZURE_DEVOPS_EXT_PAT (HTTP Basic, empty username).
  • Same create-or-update-active-PR reconciliation as the GitHub provider: lists active pull requests filtered by source/target branch, updates the existing one's title/description in place if found, otherwise creates a new one.
  • Labels apply the same way as GitHub's provider. Reviewers don't: Azure DevOps' reviewers API takes an identity GUID, not a plain username, so each configured reviewers entry (a display name, account name, or email) is resolved through the Identities API before being applied. A group match or an ambiguous match fails loudly instead of guessing; only individuals are supported today. Confirmed against a real Azure DevOps org, resolving both a display name and an email correctly.
  • Assignees aren't supported by Azure DevOps pull requests, so a non-empty assignees fails loudly instead of being silently dropped.
  • The default PR body's "Atmos CI" badge is now provider-supplied instead of hardcoded centrally: a new optional atmosgit.PullRequestBodyBadger interface lets a PullRequestPublisher return its own badge, since each forge's pull request markdown has its own quirks (raw HTML support, image hosting requirements, light/dark switching); a publisher that doesn't implement it gets a static text-link fallback. GitHub keeps its existing raw-HTML <picture> badge with light/dark switching. Azure DevOps uses a plain, sized markdown image (![]() with Azure DevOps' own =WIDTHxHEIGHT sizing syntax) instead of raw HTML, which doesn't render in Azure DevOps pull request descriptions at all — confirmed against a real pull request.
  • Documentation update to website/docs/cli/configuration/vendor.mdx, a changelog post, and a roadmap milestone.

Why

The PullRequestPublisher interface was explicitly designed to support more providers than GitHub, but nothing had implemented a second one yet. Teams hosting components in Azure DevOps Repos had no way to use the Component Updater's automated PR workflow at all.

References

  • Interface: pkg/git/pull_request.go
  • Existing implementation this mirrors: pkg/git/providers/github/pull_request.go
  • Follow-up filed for a separate, pre-existing bug found while testing this against a real org (not caused by this PR, reproduces on main for any git-ref-versioned vendor source): #3076

Summary by CodeRabbit

  • New Features

    • Added Azure DevOps Repos support for vendor update --pull-request.
    • Supports creating or updating pull requests, labels, reviewers, and organization/project/repository configuration.
    • Added Azure DevOps authentication through AZURE_DEVOPS_EXT_PAT.
    • Pull request bodies now support provider-specific CI badges.
  • Bug Fixes

    • Added validation for incomplete repository settings, invalid namespaces, unsupported assignees, and unresolved reviewers.
    • GitHub now rejects unsupported namespace configuration.
  • Documentation

    • Added Azure DevOps configuration guidance and release documentation.
feat(website): Atmos Pro cast download/embed components Erik Osterman (Cloud Posse) (@osterman) (#2739) ## what
  • Adds CastProDownload, a "Download ▾" split-button component offering rendered GIF/MP4/SVG/WEBM artifacts of any .cast file in a public GitHub repo, via the new Atmos Pro cast-rendering service.
  • Adds CastProEmbed, an <iframe> wrapper for the service's hosted HTML player, for embedding a cast player without hosting the source file locally.
  • Adds a shared CastProArtifact module: a pure URL builder (buildArtifactUrl/buildEmbedUrl, with unit tests) and a useCastArtifact hook that follows the render service's three response shapes — an already-rendered artifact (triggers a native download), a still-rendering one (polls on Retry-After, capped at ~60s), and a hard error (surfaces the JSON error message).
  • Adds a /cast-pro-demo page exercising both components against a real cloudposse/atmos cast path, and a test:cast-pro-artifact npm script.

why

  • Atmos Pro added a public, CORS-enabled service that renders any .cast recording in a public GitHub repo to GIF/MP4/SVG/WEBM, or to a hosted HTML player. This lets atmos.tools offer downloads/embeds of casts without needing them committed as static assets first, unlike the existing CastPlayer component.
  • This PR lands the reusable building blocks and a demo page; wiring the components into specific docs/blog pages is left for follow-up, so it's labeled no-release.

references

  • Atmos Pro cast-rendering endpoint: https://atmos-pro.com/casts/{owner}/{repo}/{ref}/{path}.cast.{gif|mp4|svg|webm}

Summary by CodeRabbit

  • New Features

    • Added Cast Pro sharing controls for copying demo and embed links.
    • Added downloads in GIF, MP4, SVG, and WEBM formats with progress polling and inline error feedback.
    • Added an embeddable Cast Pro player with responsive 16:9 display.
    • Added a Cast Pro demo page showcasing embedding and artifact downloads.
    • Added cast actions to the file browser when source information is available.
  • Tests

    • Added coverage for URL generation, validation, supported formats, and embed links.
  • Documentation

    • Added usage and response-handling documentation for Cast Pro features.
docs: flag Homebrew FIPS gap in fips-140-mode PRD Erik Osterman (Cloud Posse) (@osterman) (#3074) ## What

Documents a Homebrew-specific gap in docs/prd/fips-140-mode.md's "Where It's Wired In" table: the atmos formula in Homebrew/homebrew-core builds with a plain go build and no GOFIPS140, so brew install atmos produces a binary reporting "fips": false in atmos version --format=json, while GitHub Release binaries (built via .goreleaser.yml, which does set GOFIPS140=latest) correctly report "fips": true.

Why

atmos version --format=json showing fips: false looked like GoReleaser had regressed. Investigation confirmed GoReleaser and the local atmos build path (magefiles/build.go) both set GOFIPS140=latest correctly. The actual gap is Homebrew's from-source build, which lives entirely outside this repo. The PRD's wiring table previously claimed "every distinct Go-toolchain build invocation in the repo sets GOFIPS140" without mentioning that Homebrew isn't covered by that claim at all (it's not a build invocation in this repo), so this was an unflagged blind spot.

A fix is proposed upstream: Homebrew/homebrew-core#302847 (draft, pending Homebrew maintainer review — outside this repo's control).

References

  • docs/prd/fips-140-mode.md
  • internal/exec/version.go (isFIPSBuild() — reads crypto/fips140.Enabled() at runtime)
  • .goreleaser.yml (sets GOFIPS140=latest for release binaries)
  • Upstream fix: Homebrew/homebrew-core#302847

Summary by CodeRabbit

  • Documentation

    • Documented the Homebrew distribution path and its alignment with FIPS 140-enabled GitHub Release binaries.
    • Added troubleshooting documentation for a race condition affecting dependent-description tests.
  • Bug Fixes

    • Improved consistency for Homebrew installations by ensuring they use FIPS 140-compatible build settings.
    • Prevented intermittent test failures caused by concurrent output handling.
docs: add homebrew skill for atmos formula PR workflow Erik Osterman (Cloud Posse) (@osterman) (#3081) ## What

Adds .claude/skills/homebrew/SKILL.md, an agent skill covering the Homebrew/homebrew-core formula PR workflow for atmos: the real PR template, AI/LLM disclosure rules, the 50-character commit-subject limit, and how to run brew install --build-from-source / brew test / brew audit --strict / brew style locally via a disposable tap without a full homebrew-core clone.

Why

A prior attempt at a Homebrew formula PR (Homebrew/homebrew-core#302847) was auto-closed by BrewTestBot for looking AI-generated and skipping the real PR template. This skill exists so the next attempt (fixing that PR, per its own "do not open a new PR" instruction) follows homebrew-core's actual conventions instead of repeating the same mistake.

References

Summary by CodeRabbit

  • Bug Fixes

    • Fixed secret command behavior so component selection consistently uses the explicitly selected stack, including across repeated commands and shell completion.
    • Improved required-flag validation when retrieving secrets without a component.
  • Reliability

    • Added bounded retries for transient Terraform provider registry connection failures during initialization.
    • Improved resilience when describing affected components during intermittent network failures.
  • Documentation

    • Updated Homebrew guidance with portable, cross-platform commands.
    • Documented fixes for intermittent Windows CI network and Terraform registry failures.
fix(ci): restore-only Go caches with a real warmup writer Erik Osterman (Cloud Posse) (@osterman) (#3077) ## what
  • Replace actions/setup-go's built-in cache with a restore-only custom cache (restore-keys fallback, ImageOS-free key) in .github/actions/setup-go-cache; no CI job ever saves Go caches anymore
  • Make setup-go-cache-warmup.yml the sole cache writer: adds a Linux leg, runs the real compiles (go build ./..., mage acceptance:precompile, and a -race/CGO warm for the race job's namespace), saves under run-unique keys, and triggers on go.mod/go.sum pushes to main
  • Move the Build linux leg and the race job off extras=s3-cache so all Linux jobs share the GitHub cache backend; upgrade the race job to runner=xlarge
  • Fix kubernetes-e2e nullifying its restored cache with a GOCACHE override
  • Give native-ci's ~700MB provider-mirror cache a main-scope writer (new push-triggered warm-cache job); PR runs are now restore-only
  • Cache the custom-gcl binary (full golangci-lint rebuild every run today), the pnpm store in both website workflows, and add restore-only toolchain caches to lint, hooks-tflint, floci, floci-go, and race
  • Roll the toolchain cache key automatically on .tool-versions changes (hashFiles in atmos.yaml ci.cache.key)

why

Storage-level caching works (92 entries / ~99GB active, no eviction thrash), but the caches were functionally hollow: setup-go entries are immutable per go.sum hash, and the old warmup only ran go mod download — so whenever it saved first, the frozen entry had an empty GOCACHE and every later build compiled from scratch while logging a cache hit. Measured live on run 34179823625: 504s go build in Build(linux), a 27-minute race job, and 1-1.8GB re-saved per platform per PR after every dependency merge. The Linux split-brain (build job on RunsOn S3, shards on GitHub cache) meant the warmest cache in the run was invisible to the ten Linux acceptance shards.

Deliberately not done: relocating atmos's own cache root to the Windows work disk — the acceptance shards assert XDG-default paths, and the cache's saver and restorers must agree on the root.

Post-merge verification: dispatch setup-go-cache-warmup.yml, confirm multi-GB go-cache-* entries on refs/heads/main, then compare Build(linux) go build time (expect ~504s → well under 2 min) and race-job duration (expect ~27m → ~10-15m).

references

  • docs/fixes/2026-09-07-ci-go-cache-restore-only-warmup-writer.md (full investigation and change record)
  • docs/fixes/2026-08-19-restore-go-build-cache-in-ci.md, docs/fixes/2026-08-31-terraform-registry-cache-windows-runner-degradation.md (prior incidents this builds on)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • CI Improvements

    • Improved Go, Terraform, provider, and toolchain cache restoration for faster, more consistent checks.
    • Added main-branch cache warmups and reduced unnecessary cache writes.
    • Improved linting and test performance through reusable cached tools and increased capacity for race-enabled testing.
    • Cache invalidation now responds automatically to pinned tool version changes.
  • Website Builds

    • Added pnpm dependency caching to production and preview builds.
  • Bug Fixes

    • Acceptance checks now retry transient shard-listing failures while continuing to fail promptly on permanent errors.
  • Documentation

    • Documented the updated CI caching behavior and verification process.
feat(version): add yaml manager and json format field to Version Tracker Erik Osterman (Cloud Posse) (@osterman) (#3069) ## what
  • Adds an optional format field to the json version-tracker manager's options.set entries (pkg/version/managers/json/json.go): a Go template (Sprig string functions + Atmos template functions) rendered against the resolved manager.VersionRef, whose output replaces the verbatim value before it's written into the target JSON field.
  • Adds a new yaml file manager (pkg/version/managers/yaml/) that writes locked values into YAML files at configured field paths, reusing Atmos's own format-preserving YAML editor (pkg/yaml, the engine behind atmos config set/atmos stack set) so comments, anchors/aliases, and key order on untouched fields survive the write. It supports the same optional format field as the json manager, and the same dot-notation path syntax as atmos config set/atmos stack set (sources[0].version, metadata."weird.key"), which is distinct from the json manager's sjson/gjson dialect.
  • Extracts the format-template rendering and duplicate-path-check logic shared by both managers into pkg/version/managers/format.go and pkg/version/managers/pathutil.go, and updates the json manager to use them (no behavior change).
  • New sentinel errors for both managers (ErrVersionJSONFormatInvalid, ErrVersionYAML*) so a bad format template or an invalid options.set configuration is rejected outright instead of silently writing garbage or an empty string.
  • Unit tests for both managers, including a yaml-specific test that a fixture with comments and an anchor/alias survives an edit untouched, and a test that a bare-digit version string round-trips as a YAML string rather than silently becoming an int.
  • Docs (website/docs/cli/configuration/version/files.mdx): a format example/section for json, and a new "Updating YAML Files" section for yaml.
  • Two blog posts (json-manager-format, version-tracker-yaml-manager) and two roadmap milestones announcing both features.

why

  • The json manager always wrote a locked dependency's resolved value byte-for-byte. For a dependency sourced from github-releases/github-tags, that value is the raw git tag (e.g. v1.228.0) — wrong when the target field expects bare semver, such as a plugin manifest's version field. Reshaping happens at the write site (setEntry), not on the shared manager.VersionRef type or the lock file, since the same locked dependency may feed multiple write sites that want different shapes, and versions.lock.yaml should stay the untouched, auditable record of what was resolved against upstream.
  • Neither the existing template manager (renders a whole *.tmpl source to a sibling file) nor marker (a plain comment-annotated token rewrite) patches a single field in an existing, hand-maintained YAML document while preserving comments and anchors. The yaml manager fills that gap by reusing Atmos's already-shipped format-preserving YAML editor instead of building new YAML-parsing logic.

references

  • Found while finishing #2895, after two related json-manager Version Tracker gaps shipped in #2900 and #2966.

Summary by CodeRabbit

  • New Features

    • Added a YAML version manager that updates configured fields while preserving comments, key order, and formatting.
    • YAML and JSON entries support optional templates and custom delimiters for transforming resolved versions.
    • YAML updates support dot-notation paths, missing simple keys, and digest-pinned values.
    • Registered YAML management with track apply.
  • Bug Fixes

    • Improved error messages for invalid templates, duplicate paths, unsupported targets, and malformed configurations.
    • Failed updates now identify changes that were withheld.
  • Documentation

    • Added YAML configuration guidance, examples, roadmap details, and blog posts covering YAML management and JSON formatting.
test: parallelize blocker-free tests in the race job's slowest packages Erik Osterman (Cloud Posse) (@osterman) (#3078) ## what
  • Add t.Parallel() to every top-level test and t.Run closure in the test files that have no parallelism blockers, across the packages that dominate the CI race job's wall clock:
    • Batch 1: all of pkg/describe (46/49 tests); pkg/toolchain itself is excluded — its TestMain routes UI output into one captured buffer, so any parallel test that emits ui.* output races on it, and its heavy tests must stay serial regardless
    • Batch 2: 201 more files — internal/exec (76), pkg/runner/step (29), pkg/ai/tools/atmos (29), pkg/config (22), pkg/pro (15), pkg/toolchain/installer (10), cmd/terraform (8), pkg/terraform/ui (7), cmd/toolchain (3), pkg/toolchain/registry/aqua (2)
  • Leave three pkg/describe tests serial with explained //nolint:paralleltest directives (they invoke sibling test functions directly with their own *testing.T, so a second t.Parallel() panics)
  • Cap test-process parallelism now that intra-package parallelism is real: the race sweep passes -parallel=4 (ATMOS_TEST_RACE_PARALLEL), and every acceptance-shard test process gets -parallel / -test.parallel = half the runner's cores (ATMOS_TEST_PARALLEL) — without it the 3-vCPU hosted macOS runners oversubscribed and several shards ran 50-150% slower (e.g. shard 1: 665s → 1134s) while 4-vCPU Linux/Windows were unchanged
  • Enable the paralleltest linter scoped (via the existing path-except idiom in .golangci.yml) to exactly the converted files so they don't regress; tparallel (already on) caught seven parent tests deferring cleanup while running parallel subtests, now t.Cleanup
  • Fix a pre-existing Windows flake surfaced by the wider run: cmd/stack's fixture copy read the basic scenario's gitignored terraform.tfstate.d/…/terraform.tfstate while a shard-mate was writing it ("another process has locked a portion of the file"); the copy now skips Terraform runtime artifacts via the shared sandbox helper's predicate, exported as testhelpers.IsTerraformArtifact

why

The CI race job runs the whole ./... suite un-sharded, so its ~27-minute wall clock floors on the slowest packages — pkg/toolchain (556s), pkg/describe (327s), internal/exec (323s), cmd (247s), measured from run 34179823625. Go parallelizes across packages but runs tests within a package serially unless they call t.Parallel(). Locally pkg/describe drops from 18.1s to ~7-10s.

Method: mechanical conversion, then per-package go test -count=2 and go test -race as the arbiter — any file whose tests failed, panicked, or raced was reverted (96 files in the local pass, 13 more after CI runs exposed what local validation could not: package-cache resets (detectionCache, ClearBaseComponentConfigCache) and global-registry writes (atmosio.RegisterSecret) that the mutex makes race-clean but not order-safe, gomonkey code patching in TestGetAffectedComponents (skipped locally under -race and on darwin/arm64), and logical races on tests that swap package-level seams such as os.Stdin, executeTerraformLint, renderAndDeliver, tfoutput.SetDefaultExecutor, SetLastAuthContext, SetLastMergeContext, and one that hits pkg/terminal's unsynchronized lazy viper init). Files skipped or reverted use t.Setenv/t.Chdir (directly or via fixture helpers), mutate package globals (mock getters, SetAtmosConfig, viper, data.InitWriter/ui.InitFormatter, shared cobra command trees), share package caches, or raced under -race. All of cmd/list stays serial: its initTestIO/pkg/flags bindFlagToViper path races on package-level parsers. Those need dependency-injection refactoring before they can go parallel — that's the remaining lever on the race job's floor.

Two genuine production concurrency bugs surfaced by -race during this work (not fixed here): pkg/ui/markdown.NewRenderer races on glamour's shared style bytes when called concurrently (any parallel errors.Format), and the lazy viper.BindEnv init in pkg/ui/theme/pkg/terminal is unsynchronized (concurrent-map panic).

Validated: every converted package green under -count=2 and -race (zero data races), go vet clean, paralleltest lint clean over all scoped packages. Companion to #3077, which warms the race job's build cache and upsizes its runner.

references

  • #3077 (CI cache overhaul this pairs with)
  • docs/fixes/2026-09-01-race-detector-ci-job-timeouts.md (prior race-job timeout incident)

🤖 Generated with Claude Code

fix(ci): serialize website deploys and fix Sentry loader key Erik Osterman (Cloud Posse) (@osterman) (#3072) ## what
  • Add a concurrency group to website-deploy-prod.yml (cancel-in-progress: false) so pushes to main deploy one at a time.
  • Add a per-PR concurrency group to website-preview-deploy.yml for the same reason.
  • Pass the Sentry Loader public key instead of the full DSN to docusaurus-plugin-sentry.
  • Record the timeline in docs/fixes/2026-09-08-website-deploy-race-serialize.md.

why

atmos.tools went blank tonight. The live index.html referenced runtime~main.99cb7223.js and main.7524adc2.js, both 404.

The merge queue landed #3024 and #3058 on main three minutes apart. Each push triggered Website Deploy Prod, and the workflow had no concurrency group. Both runs execute aws s3 sync --delete against the single shared origin prefix, and Docusaurus content-hashes every bundle, so two builds never share asset names.

Time (UTC) Run Action
02:27:30 A (#3024) uploads main.7524adc2.js, runtime~main.99cb7223.js
02:27:55 A uploads index.html referencing A's bundles
02:27:58 B (#3058) --delete removes A's two bundles; uploads its own

B's sync plan was computed before A's index.html landed, so B never rewrote it. Result: A's index.html pointing at bundles B deleted, and both runs green.

cancel-in-progress stays false on purpose. Aborting a run mid-sync leaves a half-uploaded site, which is the same failure. With a group, the in-flight deploy finishes, the newest pending run queues behind it, and older pending runs are superseded.

Separately, the same console showed the Sentry loader script CORS-blocked. docusaurus-plugin-sentry v2 builds https://js.sentry-cdn.com/${DSN}.min.js, so the option must be the Loader Script public key, not the DSN. The corrected URL returns 200; the old one returned 404. This did not cause the outage.

references

  • Deploy runs that raced: 34179330617 (#3024) and 34179504121 (#3058)
  • actionlint passes on both workflows; the Sentry head tag was rendered locally through the installed plugin and produces the corrected src.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved production deployments by preventing overlapping releases from racing or overwriting one another.
    • Improved pull request preview deployments by isolating concurrent builds and skipping invalid preview runs.
    • Updated Sentry configuration to use the public loader key, improving client-side error reporting setup.
  • Documentation

    • Added an incident report documenting the deployment race, its resolution, validation, and follow-up actions.
feat(website): add Security & Trust page with live OpenSSF data Erik Osterman (Cloud Posse) (@osterman) (#3024) ## what
  • Adds a new /security page to atmos.tools showing our OpenSSF Scorecard and OpenSSF Best Practices badge results.
  • Data is fetched live at site build time via a new Docusaurus plugin (website/plugins/fetch-security-posture) — no client-side runtime dependency on the third-party APIs, and the build never fails if either API is temporarily unavailable (each dataset degrades gracefully with a "verify directly" fallback link).
  • The page leads with a prominent "verify this yourself" callout linking to the official Scorecard viewer and Best Practices project page, followed by the badge status, overall score with a build-time timestamp, and the full 18-check table.
  • Adds a "Security" link to the footer's Resources column.

why

  • Enterprises evaluating Atmos for adoption want to check our security posture, and a static badge image can go stale or feel unverifiable.
  • Pulling the live JSON from the authoritative sources (api.scorecard.dev, bestpractices.dev) and linking straight back to them lets evaluators verify the numbers themselves instead of trusting a cached badge.
  • This mirrors the existing build-time data-fetch pattern already used for GitHub stars and the latest release (website/plugins/fetch-github-stars, fetch-latest-release), so it fits the codebase's established conventions rather than introducing a new fetch mechanism.

references

  • Related: cloudposse/atmos recently earned a passing OpenSSF Best Practices badge (project #14393).
  • Upstream: comment on ossf/scorecard#3678 documenting that Scorecard can't yet detect a merge queue as a substitute for the "up-to-date branches" setting, including the Rulesets API call that exposes it. This is the gap behind the Branch-Protection finding the page annotates.

Summary by CodeRabbit

  • New Features
    • Added a Security page displaying OpenSSF Scorecard results and Best Practices status.
    • Added score gauges, risk indicators, expandable check details, verification links, repository metadata, and scan timestamps.
    • Added contextual explanations for checks whose scores may not reflect actual risk.
    • Added a fallback message when security data is unavailable.
    • Added automatic retrieval of security posture data during website builds.
    • Added a Security link to the website footer.
  • Documentation
    • Added an announcement introducing the Security & Trust page and security reporting resources.

🚀 Enhancements

fix(examples): use real Infracost CLI Erik Osterman (Cloud Posse) (@osterman) (#3093) ## what
  • Replaces the public Infracost emulator with a pinned real Infracost CLI dependency and API-key documentation.
  • Moves deterministic cost output into a dedicated cast fixture and regenerates both affected casts.
  • Fixes the custom-command hook script path from the component working directory.

why

  • Public examples must run the real integrations they demonstrate; deterministic stand-ins belong only to cast fixtures.

references

  • N/A

Summary by CodeRabbit

  • New Features

    • Added a complete NAT gateway fixture for the Infracost hook demonstration.
    • Added configuration for Terraform plans with deterministic cost reporting.
  • Documentation

    • Updated the Infracost example to use the real CLI, including version setup and API key requirements.
    • Updated custom hook instructions to use reliable component-relative script paths.
  • Bug Fixes

    • Improved cache action compatibility with older bootstrap CLI versions.
    • Prevented intermittent package repository errors during automated builds and tests.
  • Demo Updates

    • Refreshed hook recordings and aligned demo fixtures with current configurations.
fix(scaffold): write conflict markers on manual merge, fix init --update, fix --force+--update Jorrit Elfferich (@jorrite) (#3047) ## what
  • atmos scaffold generate --update (and atmos init --update, sharing the same engine) with the default --merge-strategy=manual now writes real <<<<<<</=======/>>>>>>> conflict markers plus every non-conflicting change on a real merge conflict, instead of discarding the whole merge and writing nothing.
  • atmos init --update now pins its initial --git commit to .atmos/init/metadata.yaml, the same way atmos scaffold generate already does, and reads it back as the merge base instead of defaulting to live HEAD.
  • --force combined with --update is no longer a silent no-op: an unset --merge-strategy now defaults to theirs in that combination, and an explicitly-passed ours/manual together with --force --update is now a clear validation error instead of silently doing nothing.
  • Re-running --update against a file already left with unresolved conflict markers now fails fast with a specific message instead of an opaque three-way merge failed.
  • Reworded every --force-suggesting error hint across the merge engine to describe what --force actually does now.

why

  • The manual-merge-conflict bug is the still-open half of #2912. The issue was closed as resolved by #2989, but that PR fixed a different bug reported in the same thread (silent base-ref pinning) and never touched the manual-merge-strategy code path — confirmed by reproducing the original issue's exact repro steps live on current main before this fix.
  • Field-testing that fix surfaced that atmos init --update has the exact base-ref-pinning bug #2989 fixed for atmos scaffold generate, because the fix lived only in cmd/scaffold and was never ported to cmd/init — the two commands' base-ref resolution had drifted apart. This PR extracts the shared logic into pkg/generator/gitinit.go so it can't drift apart a second time.
  • --force being silently ignored under --update made several existing error hints false, and left users with no way to push through a conflict without hand-editing the file.
  • The unresolved-markers re-run scenario is a new consequence of the conflict-marker fix (previously nothing was ever written on conflict, so it was impossible) — it's fixed in the same PR rather than shipped as a known gap.

See docs/fixes/2026-09-04-scaffold-init-update-merge-fixes.md for full context, the complete list of changed files, and how each fix was validated (unit tests plus live end-to-end verification against a built binary).

references

  • Closes #2912
  • Fix record: docs/fixes/2026-09-04-scaffold-init-update-merge-fixes.md

Summary by CodeRabbit

  • Bug Fixes
    • init --update and scaffold generate --update now use the correct target and previously pinned merge base.
    • Merge conflicts are saved with clear conflict markers instead of failing without preserving results.
    • Re-running updates on files with unresolved conflicts now provides a clear error.
    • --force --update defaults to using the template version; incompatible strategies are rejected.
    • Initial Git metadata is now preserved for future updates.
    • Error messages provide clearer guidance for resolving conflicts and overwriting files.
    • Dry-run updates no longer modify files when conflicts occur.
fix(ci): test summary/JUnit dropped OpenTofu runs and late diagnostics Erik Osterman (Cloud Posse) (@osterman) (#3082) ## Summary
  • atmos terraform test --ci discarded every run and file event from tofu test -json: OpenTofu emits one test_run/test_file event per subject carrying only status, with no progress field, and the parser only accepted events with progress: "complete". The test_summary event has the same shape in both tools, so badge counts stayed right while the results table came out empty and <component>.junit.xml reported tests="0" on a passing run.
  • Both Terraform and OpenTofu emit an assertion-failure diagnostic after the run's final event; the parser only attached diagnostics that arrived before it, so failing runs lost their message and file:line (and with them the ::error annotation and the summary's Details column) under Terraform too.
  • Fix: testEventComplete accepts a bare terminal status as final; attachLateDiagnostics reconciles diagnostics that arrive after their run. The stop-gap backfillMissingTestJSONRuns guard stays as a last resort but now warns loudly if it ever fires.
  • Also closes out a related, already-fixed emulator-endpoint report: confirmed via git merge-base --is-ancestor and a fresh Docker repro that #2942/#2960 are intact and shipped in v1.228.0; re-verification note appended to the existing fix doc.

Why

The report came from a repository whose toolchain pins tofu. This repo's own examples/terraform-tests fixture is Terraform-only (it uses variable blocks that OpenTofu rejects), so eleven local repro runs never hit it; diffing raw -json streams from both tools on a minimal module exposed the missing progress field and the diagnostic ordering.

Verification

  • New regression tests use verbatim OpenTofu 1.12.5 streams; they failed before the parser change with every run reported as run detail unavailable (pass) and no file/line.
  • End-to-end under OpenTofu (components.terraform.command: tofu, one passing + one failing run, GITHUB_ACTIONS=true … --ci): JUnit tests="2" failures="1" with real names and line="12" on the failure; summary lists both runs with tests/min.tftest.hcl:12 in Details; ::error file=…,line=12 annotation emitted.
  • Terraform path unchanged: examples/terraform-tests still yields tests="4" with all real run names.

References

  • docs/fixes/2026-09-08-ci-test-json-opentofu-runs-dropped.md
  • docs/fixes/2026-08-19-emulator-endpoint-job-container-network-join.md (re-verification note)

Summary by CodeRabbit

  • Bug Fixes

    • Fixed CI test reporting for OpenTofu, including summaries, JUnit results, and assertion diagnostics.
    • Improved handling of missing test-run records with safeguards against excessive synthesized entries.
    • Clearly indicate when test results are incomplete due to truncation.
  • Documentation

    • Added re-verification details for emulator networking and endpoint connectivity in the published release image.
  • Chores

    • Updated website package version overrides.
fix(ci): keep pinned atmos schema snapshots durable across deploys Erik Osterman (Cloud Posse) (@osterman) (#3092) ## what
  • Fix pinned atmos schema URLs (e.g. atmos.tools/schemas/atmos/atmos-manifest/1.228.0/atmos-manifest.json) 404ing shortly after every release.
  • Backfilled the pinned atmos-manifest/atmos-config snapshots for all 7 releases affected since the pinning feature shipped (v1.224.0-v1.228.0) directly in prod S3 (already live, no PR needed for that part).
  • Consolidated .github/scripts/s3-deploy-with-charset.sh and the 4 near-duplicate schema generate/publish steps in website-deploy-prod.yml into two reusable composite actions: .github/actions/s3-deploy and .github/actions/publish-atmos-schema.
  • Bumped 5 vulnerable transitive npm deps in website/ (js-yaml, svgo, joi, colord) via pnpm.overrides, closing 7 open Dependabot alerts — all within-major patch bumps.

why

  • website-deploy-prod.yml only regenerated the pinned per-release schema snapshot if: github.event_name == 'release', but every deploy (including ordinary pushes to main) ran aws s3 sync --delete against the same S3 prefix. Since a pinned snapshot from an older release was absent from that run's local build, --delete pruned it — so a pinned URL survived only until the next routine deploy. The docs' own example version (1.219.0) had already succumbed to this.
  • The fix excludes pinned schema paths from --delete and publishes each release's new snapshot via a direct, non-deleting aws s3 cp, decoupling it from the routine sync's deletion scope.
  • The composite-action refactor was requested to consolidate CI logic that had grown into 5 near-identical steps plus a loose .github/scripts/*.sh, per this repo's "CI scripts live in local actions" convention.
  • The npm bumps address a git push-triggered security-remediate pass; the current branch already had an open diff, so the fixes landed here directly.

references

  • Related to #2592 (original pinned-schema feature this PR fixes a regression in)

Summary by CodeRabbit

  • New Features

    • Added automated generation and publishing of Atmos schemas, including version-specific snapshots for production releases.
    • Added shared website deployment automation for synchronizing content to S3 while preserving required metadata.
  • Improvements

    • Standardized production and preview website deployments around reusable automation.
    • Improved consistency of schema publishing across release and non-release deployments.
fix(auth): clear Azure realm MSAL cache on logout so re-login is fresh Andriy Knysh (@aknysh) (#3087) ## what
  • atmos auth logout (including --all --force) now removes the realm-scoped Azure MSAL token cache (~/.azure/atmos/{realm}/msal_token_cache.json) in addition to the keyring entry and the Atmos device-code token it already cleared.
  • The shared Azure CLI cache (~/.azure/msal_token_cache.json) is intentionally preserved — it is co-owned with a user's own az login session.
  • Applies to the azure/device-code and azure/interactive providers (interactive embeds device-code); azure/cli and azure/oidc never create a realm MSAL cache and are unaffected.

why

  • After a role or PIM change, users found that atmos auth logout followed by atmos auth login did not pick up the new access — they kept getting 403 AuthorizationFailed (e.g. Microsoft.ContainerService/managedClusters/read), and atmos auth whoami showed the credential still expiring on the old session's clock.
  • Root cause: the device-code/interactive providers build their MSAL client from the realm cache and attempt a silent token acquisition before any interactive flow. Logout removed the Atmos device-code token (~/.cache/atmos/azure-device-code/<provider>/token.json) but never the realm MSAL cache — a different file — so the next login silently re-minted a token from the stale cached account/refresh token, which predated the PIM elevation.
  • The only workaround was to delete the realm cache by hand (rm ~/.azure/atmos/<realm>/msal_token_cache.json). This makes logout actually forget the session, so re-login is genuinely fresh.

tests / validation

  • Reproducing tests written first and confirmed failing on the unpatched code, now passing: logout removes the realm MSAL cache for both device-code and interactive providers, preserves the shared az cache, and treats a missing cache as a clean no-op. Added a direct RemoveMSALCache unit test (realm removal, missing-file no-op, empty-realm safety guard, real os.Remove failure) and a Logout error-path test.
  • Changed functions fully covered (resolveMSALCachePath 100%, NewMSALCache 100%, Logout 100%, RemoveMSALCache 90.9% — only the untestable os.UserHomeDir error return remains).
  • go test ./pkg/auth/... green; atmos fix lint (patch-scoped CI gate) reports 0 issues.

references

  • Fix doc: docs/fixes/2026-09-08-azure-logout-msal-cache-stale-session.md
  • Follows the Azure auth line: #2862 (azure/interactive), #2861 / #2890 (Azure CLI cache fixes)

Summary by CodeRabbit

  • Bug Fixes

    • Azure logout now removes realm-specific cached authentication data for device-code and interactive sign-ins.
    • Shared Azure CLI authentication remains available after logout.
    • Logout succeeds cleanly when no realm-specific cache exists and reports cache-removal failures when they occur.
  • Documentation

    • Added documentation describing Azure logout behavior, cache handling, provider differences, and validation results.
fix: preserve prompted component/stack across profile-fallback re-exec Erik Osterman (Cloud Posse) (@osterman) (#3080) ## What

Carries interactively-resolved component/stack values through a profile-fallback re-exec, so the re-exec'd child process doesn't re-prompt for values the user (or an earlier prompt) already supplied.

ReExecContext (pkg/auth/profile_fallback.go) distinguishes "resolved via prompt" from "supplied on the command line" via ComponentPrompted/StackPrompted flags on schema.ConfigAndStacksInfo — only prompted values are injected into the child's re-exec argv, since command-line-supplied values are already present in os.Args and re-adding them would duplicate a positional argument.

Why

When an invalid identity config triggers the interactive profile fallback (auth.MaybeOfferProfileFallbackForIdentity), the process re-execs itself with the newly-picked profile. Previously, if component/stack had just been resolved via an interactive prompt (not passed as CLI args), the re-exec'd child had no record of that and prompted the user again for the same values — a redundant, confusing extra step in an already-interruptive flow.

References

  • pkg/auth/profile_fallback.go (ReExecContext, maybeOfferProfileFallback, reExecWithProfile)
  • internal/exec/utils_auth.go (offerIdentityProfileFallback, resolveIdentityConfigError)
  • cmd/terraform/shared/execution.go (promptMissingComponent/promptMissingStack now set the *Prompted flags)
  • pkg/schema/schema.go (ConfigAndStacksInfo.ComponentPrompted / StackPrompted)

Summary by CodeRabbit

  • Bug Fixes

    • Preserved component and stack values selected through interactive prompts during authentication and profile fallback.
    • Prevented unnecessary repeated prompts when authentication requires a profile-based retry.
    • Ensured backend create, update, delete, describe, and list commands consistently retain prompted values throughout execution.
  • Tests

    • Added coverage for prompted-value tracking, authentication retries, profile fallback, and backend command behavior.
fix(terraform-ui): clean up terraform plan --ui output Erik Osterman (Cloud Posse) (@osterman) (#3083) ## what
  • Fixes deprecation-warning log lines from atmos terraform plan --ui that embedded a raw blank line from Terraform's multi-paragraph diagnostic detail, making the trailing address=/file=/line= metadata appear to jump to the far right of the terminal and wrap onto its own line.
  • Fixes the plan summary/dependency tree silently disappearing after a successful plan with no error or explanation.
  • Fixes broken indentation for nested arrays (2+ levels deep, e.g. CloudFront's ordered_cache_behavior) in the plan tree's JSON attribute-diff rendering.
  • Adds a # (N unchanged attributes hidden) footer to the plan tree, mirroring Terraform's own plan-output convention.
  • Hardens a previously-unbounded subprocess call in tests/cli_describe_identity_test.go with a timeout.

why

  • The deprecation-warning bug was in extractFirstSentence: it fell through to returning Terraform's entire multi-paragraph diagnostic detail (including the embedded blank line) instead of a single clean sentence, and was also picking the generic "derived from a deprecated source" lead-in over the actual, specific deprecation message. It now stops at the first paragraph break and prefers the specific, actionable final sentence.
  • The missing plan summary was a real bug, not cosmetic: the second terraform show -json <planfile> subprocess (used to build the tree/summary after a successful plan) never received the component's effective environment (TF_DATA_DIR, credentials) the way the original plan/apply subprocess does, so it could fail independently of the plan itself — and that failure was silently discarded with zero indication anything went wrong. It now inherits the same environment, and any remaining failure is logged with the real subprocess stderr instead of a bare "exit status 1".
  • The broken array indentation was a reproducible bug in the jsoniter library's MarshalIndent, confirmed against a minimal standalone repro; ConvertToJSON now marshals compact with jsoniter and re-indents with stdlib encoding/json, which isn't subject to the bug.
  • The unchanged-attributes footer closes a parity gap where the diff-only attribute list gave no sense of how much of the resource actually stayed the same, unlike Terraform's native output.
  • The test hardening turns a previously-observed subprocess hang (which took down the entire test binary via go test's global timeout) into a fast, attributable failure on just the affected subtest.

references

  • N/A

Summary by CodeRabbit

  • New Features

    • Plan summaries now show hidden unchanged attributes with correct singular and plural wording.
    • Terraform subprocesses honor the configured environment and provide clearer failure details.
    • Diagnostic messages are rendered as concise, single-line summaries without boilerplate.
  • Bug Fixes

    • Warnings are now logged when plan summaries cannot be rendered.
    • Sensitive information in Terraform errors is masked.
    • Nested JSON arrays are formatted correctly.
    • Identity description tests now fail promptly instead of hanging.
fix(secret): stop leaking the resolved --stack into viper's override layer Erik Osterman (Cloud Posse) (@osterman) (#3075) ## what
  • parseScopeStack (cmd/secret/shared.go) and parseInitScope (cmd/secret/init.go) no longer write the resolved stack into viper's override layer with viper.Set. A stack chosen at the interactive prompt is now recorded on the command's own --stack flag via a small adoptPromptedStack helper, which the component completion still sees through viper's flag binding.
  • New regression tests in cmd/secret/stack_override_test.go: the exact failing sequence (import --stack prod, then set --stack dev must load with dev), the prompted-stack propagation through the flag binding, and the empty-choice no-op.
  • Fix record: docs/fixes/2026-09-07-secret-stack-viper-override-leak.md.

why

  • [race] non-acceptance test suite failed on a main push (run 34179504147) and on #3069 (run 34181209571), each time in one of the two global-scope secret set tests with no global declaration was found in the stack. Replaying the CI shuffle seeds locally reproduces it deterministically; unshuffled runs pass.
  • Root cause: a viper override outranks every later flag parse for the life of the process. After any secret command ran with --stack prod, the next command's --stack dev resolved to prod, its stack filter matched nothing, and the lookup failed. Bisected to TestRunSecretImport_FromStoreMode → global-scope set; a probe showed the pflag reset to "" while viper.GetString("stack") stayed "prod" even after SetDefault, i.e. the override layer.
  • The override only existed to make a prompted stack visible to the component prompt's completion. Setting the flag gives the same visibility, is reset with every other flag, and removes a real in-process footgun for anything that runs more than one secret command per process.

references

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where interactively selected secret stacks could carry over to subsequent commands.
    • Secret commands now preserve required-flag errors when no stack is selected.
    • Empty interactive stack selections no longer modify command state or secrets.
    • Improved error messages when stack flag handling fails.
  • Tests

    • Added coverage for repeated commands, interactive stack selection, missing flags, and non-interactive initialization.
  • Documentation

    • Documented the secret stack selection and command-isolation fix.
fix(source): retry DNS/connect failures for JIT sources; clone JIT test fixtures locally Erik Osterman (Cloud Posse) (@osterman) (#3073) ## what
  • isRetryableGitError (pkg/downloader/get_git.go) now recognises OS-level resolver and connect failures in git's own wording — could not resolve host, no such host, could not connect to server, failed to connect to, network is unreachable, name resolution — with tests for each plus a guard that a real 403 from the remote is still not retried.
  • JIT source provisioning (pkg/provisioner/source/vendor.go) always passes a retry policy to the git getter: the source's own retry: when set, otherwise a bounded default of 3 attempts with exponential backoff (1s→8s, 20% jitter). Only transient transport failures are retried; auth failures and missing refs still fail fast, and max_attempts: 1 opts out. The terraform/helmfile/packer source docs describe the default.
  • The TestJITSource_* and TestJITSource_MetadataComponentSubpath* acceptance tests clone from a throwaway local git::file:// repository (tests/jit_source_local_repo_test.go) instead of github.com — same go-getter git path (clone, ref=, depth=1, //subpath), no network, runs on all three OSes. The rewrite happens in each test's sandboxed copy of the fixture; the checked-in fixture keeps its real-world URIs. RequireGitHubAccess is dropped from the two tests that used it.
  • Fix record: docs/fixes/2026-09-07-jit-source-network-flakes.md.

why

  • Acceptance Tests (windows, shard 2/10) on #3069 failed in TestJITSource_PackerOutput with Failed to connect to github.com:443 after 61 ms: Could not connect to server, right after the same job's checkout had hit Could not resolve host: github.com. On Windows, harden-runner's agent fronts DNS with a local proxy and installs a firewall allow-rule per resolved IP; under a test shard's process churn it occasionally drops a query or races the allow-rule. These blips recur several times a week (see the docs/fixes/ entries from 2026-08-10, 2026-09-02, 2026-09-03) and nothing in the affected PRs touches source provisioning.
  • Two gaps turned a one-second blip into a red build: the git retry predicate didn't match either message, and JIT provisioning had no retry unless a source configured one — so a user's terraform plan with a JIT source fails on the same blip on a laptop or in their CI. Retrying only transport-level failures, with a bounded budget, fixes the user-facing behaviour without masking real errors.
  • The JIT tests exist to cover the provisioning path, not GitHub reachability. A Gitea/testcontainers stand-in was rejected because GitHub's Windows and macOS runners can't run Linux containers — the fixture would skip exactly where the flake happens.

references

Summary by CodeRabbit

  • Bug Fixes

    • Git-based source downloads now automatically retry transient DNS, connection, and network failures up to three times with exponential backoff.
    • Missing references and authentication failures are not retried, except for a short retry window when credentials are brokered by Atmos.
    • Existing custom retry settings remain unchanged, including the option to disable retries.
  • Documentation

    • Documented default retry behavior across Helmfile, Packer, and Terraform source configuration.
fix(ci): never create a bulk-run status without a real component Erik Osterman (Cloud Posse) (@osterman) (#3058) ## what
  • Guard createCheckRun/updateCheckRun and harden FormatStatusContext so a CI status can never be created or referenced without a real, resolved component and stack.
  • Add new before.terraform.{plan,apply,destroy}.aggregate CI hook events, fired once the component graph is resolved and filtered, that create one real pending check-run per component up front for --affected/--all runs — mirroring the existing after-aggregate path.
  • Add the missing per-node before-CI-hook for deploy (it already had a per-node after-hook but no before counterpart), gated so it never fires if a user before-hook aborts the node.
  • Make the after-aggregate CI resolver run via defer in ExecuteTerraform so it's guaranteed to fire even if a later step errors and returns early.

why

  • atmos terraform deploy --affected --upload-status (and --all, and plan/apply/destroy) created a pending GitHub commit status named atmos/deploy/<stack>/ — with no component, because bulk selection resolves its component list after the global before-hook already fired. That status was never updated, leaving PR checks stuck on "Waiting for status to be reported" forever, even though the run succeeded.
  • A CI status is always about a specific component; the fix makes that an enforced invariant rather than an incidental convention, and gives bulk runs the same real, resolvable pending-status UX that single-component runs already have.

references

Summary by CodeRabbit

  • New Features

    • Added Terraform CI hooks that create pending checks for each resolved component before plan, apply, or destroy operations begin.
    • Added aggregate before-operation hooks for Terraform plan, apply, and destroy workflows.
    • CI checks now include resolved stack and component context.
  • Bug Fixes

    • Prevented malformed check runs and status contexts when required context is missing.
    • Ensured CI results are finalized after later Terraform processing errors.
    • Improved handling of CI hook failures without interrupting Terraform execution.
    • Platform and race-condition test safeguards can no longer be bypassed by the skip environment setting.

🤖 Automatic Updates

build(deps): bump github.com/containerd/containerd/v2 from 2.3.3 to 2.3.5 in the go_modules group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) (#3098) Bumps the go_modules group with 1 update in the / directory: [github.com/containerd/containerd/v2](https://github.com/containerd/containerd).

Updates github.com/containerd/containerd/v2 from 2.3.3 to 2.3.5

Release notes

Sourced from github.com/containerd/containerd/v2's releases.

containerd 2.3.5

Welcome to the v2.3.5 release of containerd!

The fifth patch release for containerd 2.3 contains various fixes and updates including security patches.

Security Updates

Highlights

Image Distribution

  • Apply hardening to strip sensitive authentication headers when fetching descriptor URLs (#14030)

Runtime

  • Avoid hangs and data races when streaming container standard I/O in CRI (#14094)
  • Fix missing error messages in OpenTelemetry trace attributes (#14049)
  • Fix user and group lookup failures in container rootfs containing symlinked /etc/passwd or /etc/group (#13999)
  • Fix configuration loading error when drop-in configuration files have a higher version than the root configuration (#13995)
  • Avoid containerd startup hangs when loading shims (#13983)
  • Add context to error when shim delete times out (#13921)
  • Fix Windows Server 2022 container compatibility on host builds newer than the latest LTSC (containerd/platforms#34)

Snapshotters

  • Fix unpack failure for EROFS images containing the erofs OS feature (#14062)

Please try out the release binaries and report any issues at https://github.com/containerd/containerd/issues.

Contributors

  • Phil Estes
  • Samuel Karp
  • Derek McGowan
  • Sebastiaan van Stijn
  • Akhil Mohan
  • Maksym Pavlenko
  • Wei Fu
  • Oleh Konko
  • Austin Vazquez
  • Jing Chen
  • Martín Fernández
  • Paco Xu
  • XlabAI

... (truncated)

Commits
  • 1294c24 Merge pull request #14092 from samuelkarp/prepare-release-2.3.5
  • db68d72 Prepare release notes for v2.3.5
  • be419b0 Merge commit from fork
  • 84ea25b Merge commit from fork
  • 5db0399 Merge pull request #14094 from k8s-infra-cherrypick-robot/cherry-pick-14085-t...
  • 9f6be86 Fix data races and a deadlock in the byte stream helpers
  • 9ec55f0 cri: cancel ExecSync IO drain on context cancellation
  • c535779 archive: skip redundant opaque whiteout walks
  • 3684f86 Merge pull request #14063 from k8s-infra-cherrypick-robot/cherry-pick-14057-t...
  • 7459b1f Merge pull request #14062 from k8s-infra-cherrypick-robot/cherry-pick-14012-t...
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore <dependency name> major version will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
  • @dependabot ignore <dependency name> minor version will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
  • @dependabot ignore <dependency name> will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
  • @dependabot unignore <dependency name> will remove all of the ignore conditions of the specified dependency
  • @dependabot unignore <dependency name> <ignore condition> will remove the ignore condition of the specified dependency and ignore conditions
    You can disable automated security fix PRs for this repo from the Security Alerts page.
fix(deps): update module github.com/gofrs/flock to v0.13.1 @[renovate[bot]](https://github.com/apps/renovate) (#3091) This PR contains the following updates:
Package Change Age Confidence
github.com/gofrs/flock v0.13.0v0.13.1 age confidence

Release Notes

gofrs/flock (github.com/gofrs/flock)

v0.13.1

Compare Source

What's Changed

New Contributors

Full Changelog: gofrs/flock@v0.13.0...v0.13.1


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

fix(deps): update github.com/hashicorp/terraform-config-inspect digest to 75d64de @[renovate[bot]](https://github.com/apps/renovate) (#3054) This PR contains the following updates:
Package Type Update Change
github.com/hashicorp/terraform-config-inspect require digest 2fb54c275d64de

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

fix(deps): update module github.com/gabriel-vasile/mimetype to v1.4.15 @[renovate[bot]](https://github.com/apps/renovate) (#3079) This PR contains the following updates:
Package Change Age Confidence
github.com/gabriel-vasile/mimetype v1.4.13v1.4.15 age confidence

Release Notes

gabriel-vasile/mimetype (github.com/gabriel-vasile/mimetype)

v1.4.15: fix int overflow on 32bit arch

Compare Source

What's Changed

This release fixes an integer overflow panic on 32 bit architectures and retracts the previous release.

Full Changelog: gabriel-vasile/mimetype@v.1.4.14...v1.4.15

v1.4.14: pyc, pcap, cycloned, gedcom support

Compare Source

Media type changes

  • newly added: application/x-bytecode.python, application/vnd.tcpdump.pcap, application/vnd.cyclonedx+xml, application/vnd.cyclonedx+json, text/vnd.familysearch.gedcom
  • superseded and demoted to aliases:
    image/vnd.mozilla.apng superseded by image/apng
    video/x-matroska superseded by video/matroska
    application/x-rar-compressed superseded by application/vnd.rar

Full changelog

New Contributors

Full Changelog: gabriel-vasile/mimetype@v1.4.13...v1.4.14


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

fix(deps): update module github.com/charmbracelet/x/ansi to v0.11.8 @[renovate[bot]](https://github.com/apps/renovate) (#3070) This PR contains the following updates:
Package Change Age Confidence
github.com/charmbracelet/x/ansi v0.11.7v0.11.8 age confidence

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.