Update dependency cloudposse/atmos to v1.217.0#53
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
7f38c4d to
c5e394b
Compare
c5e394b to
4995934
Compare
4995934 to
b2f36f0
Compare
b2f36f0 to
0118e4c
Compare
0118e4c to
1054e04
Compare
1054e04 to
3a2767f
Compare
3a2767f to
8fd79a7
Compare
8fd79a7 to
110e70b
Compare
110e70b to
4df6347
Compare
4df6347 to
e417521
Compare
e417521 to
3dc296f
Compare
3dc296f to
03866bc
Compare
03866bc to
2edc9fc
Compare
2edc9fc to
61c52ba
Compare
61c52ba to
aac9c8a
Compare
fe59fed to
1e7ddcb
Compare
1e7ddcb to
533faba
Compare
533faba to
3382d8a
Compare
3382d8a to
01b32f7
Compare
01b32f7 to
c03a20e
Compare
c03a20e to
677f617
Compare
677f617 to
2f5aeb5
Compare
2f5aeb5 to
f924a39
Compare
f924a39 to
21f89ec
Compare
21f89ec to
61f3dc1
Compare
61f3dc1 to
1a61ee4
Compare
1a61ee4 to
8633261
Compare
8633261 to
d28c1ff
Compare
d28c1ff to
5b77c83
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
v1.166.0→v1.217.0Release Notes
cloudposse/atmos (cloudposse/atmos)
v1.217.0Compare Source
docs(roadmap): curate featured; drop internal-refactor changelog posts @osterman (#2384)
what
featured[]inwebsite/src/data/roadmap.jsat 6 curated strategic initiatives. Dropdevcontainer,workflows,instance-status-upload, andchunked-stack-uploads. Final 6:atmos-ai,cloud-auth,native-ci,pro-commit,source-provisioning,toolchain.ci-cdinitiative for the two demoted Atmos Pro items so their changelogs stay reachable from the roadmap. Recalcci-cd.progress89 → 92.qualityinitiative milestones:process-args-flags-refactor,refactoring-executeterraform-for-testability,describe-stacks-complexity-reduction. Recalcquality.progress86 → 75..claude/agents/roadmap.mdwith two new rules: (1)featured[]is manually curated, max 6, edited only when the user explicitly asks; (2) internal-only refactors with no user-visible change do not get changelog posts. Adds matching schema docs and quality-check items.why
/roadmapnext to transformative initiatives like Atmos AI and Cloud Auth. That diluted its meaning.featured[], so it was being modified on every release. Codifying "max 6, opt-in only" stops the drift at the source.git log, not the user-facing changelog.references
no-release— content/data only; no Go code, no user-visible CLI behavior change. Removing already-published changelog entries that should not have been published.Summary by CodeRabbit
Documentation
Chores
Quality
docs: document the component `provision:` block (provision.backend, provision.workdir) @osterman (#2378)
what
website/docs/stacks/components/provision.mdxthat documents the entireprovision:block as a coherent feature, with sections forprovision.backend.enabled(terraform-only),provision.workdir.enabled(all four toolchains), toolchain defaults, component-level overrides, and global defaults viasettings.provision.workdir.{enabled,ttl}inatmos.yaml.:::tipcallout towebsite/docs/stacks/components/terraform/backend.mdxclarifying thatbackend:(where state is stored) is distinct fromprovision.backend:(auto-create that location).website/docs/components/terraform/backend-provisioning.mdxto the new schema page so the conceptual deep-dive points at the schema reference.why
provision:block (withprovision.backend.enabledandprovision.workdir.enabled) is functional and used in fixtures, but had no dedicated documentation page in Stack Configuration. The only references were a CLI command page (atmos terraform workdir), a passing mention incli/configuration/components/terraform.mdx, and the backend-provisioning conceptual page — none of which document the schema directly.*.metadata,ansible,helmfile,packer,terraform/backendand noticedprovisionwas missing entirely.:::tipon the backend page resolves long-standing confusion between thebackend:block (state location) and theprovision.backend:block (whether to bootstrap that location).references
pkg/schema/schema.go:402-414(ProvisionWorkdirSettings),pkg/provisioner/workdir/types.go:57-61(WorkdirConfig),pkg/provisioner/backend_hook.go:111-125(provision.backend.enabled).tests/fixtures/scenarios/workdir/stacks/catalog/workdir-defaults.yaml.cd website && npm run build(zero broken links; new page registered as the 544th content route).Summary by CodeRabbit
New Features
list:CLI configuration for customizablecomponents,instances, andstacksoutputsettings.provisionandprovision.workdirdocs for workdir defaults/TTLDocumentation
BITBUCKET_USERNAMEChores
Unknowndocs: refresh CI page with native CI workflows; deprecate legacy GH Actions @osterman (#2373)
what
affected-stacks,atmos-terraform-plan/apply, drift detection/remediation, and the index) fromwebsite/docs/integrations/github-actions/towebsite/docs/deprecated/github-actions/, with:::warning Deprecatedbanners on each page pointing readers to/ci.website/docs/ci/ci.mdxaround the two reference reposcloudposse-examples/atmos-native-ciandcloudposse-examples/atmos-native-ci-advanced— concrete excerpts for deploy-on-PR, deploy-on-merge, preview cleanup, and anatmos describe affected --format=matrixfan-out, plus a discreet pointer to the deprecated content./integrations/github-actions/*URLs to/ci, add a collapsed "Deprecated" sub-category at the bottom of the Resources sidebar, keepsetup-atmosandcomponent-updaterin the (now smaller) GitHub Actions sidebar entry, and repoint cross-links across docs, two blog posts, and the roadmap.why
atmos terraform plan/apply/deployalready produces the artifacts the wrapper actions used to provide — the legacy actions are no longer the recommended path for new projects.references
cloudposse-examples/atmos-native-ci— basic example workflows excerpted in the new/cipagecloudposse-examples/atmos-native-ci-advanced— matrix workflow excerpted in the new/cipageSummary by CodeRabbit
New Features
Documentation
Chores
feat(list): --process-templates and --process-functions flags; fix list instances --upload auth @aknysh (#2363)
what
--process-templatesand--process-functionsCLI flags (andATMOS_PROCESS_TEMPLATES/ATMOS_PROCESS_FUNCTIONSenv vars) to everyatmos listsubcommand that processes stack manifests:list instances,list components,list metadata,list sources,list stacks. Defaults aretrue, matchingatmos describe affected/atmos describe stacks/atmos describe component.--process-templatestoggles Go templates (includingatmos.Component(...));--process-functionstoggles YAML functions (!terraform.state,!terraform.output,!store,!aws.*, …).atmos list instances --uploadhang in CI: per-component auth resolution ininternal/exec/describe_stacks_component_processor.gowas gated onprocessYamlFunctionsonly, so the template-only path (atmos.Component(...)inside Go templates) ranterraform initwith an emptyAuthContextagainst remote backends and failed withNo valid credential sources found. Guard now fires when either templates or YAML functions will run.shouldResolvePerComponentAuth(...)predicate,resolveComponentAuthManager(...)method, and an injectablecomponentAuthManagerResolverfield ondescribeStacksProcessorso the decision can be exercised without running real OIDC/STS.InstancesCommandOptions/MetadataOptionsinpkg/list/and through both the matrix-format and tree-format branches oflist_instances.go, so every output path of the same invocation honors the same flag values.ExecuteDescribeStacks) plus a dedicated auth-guard regression suite (TestShouldResolvePerComponentAuth,TestResolveComponentAuthManager6-row table,TestResolveComponentAuthManager_ResolverErrorFallsBackToParent).atmos listcommand page, added a blog post announcing the feature, and added a shipped milestone to the Discoverability & List Commands roadmap initiative.go.mod:sentry-go v0.45.1(cockroachdb/errors v1.12.0 still references the removedExtrafield),gocloud.dev v0.41.0(gomplate/v3 s3blob uses removedConfigProvider),hairyhenderson/go-fsimpl v0.3.1(transitive via the gocloud.dev pin).why
atmos list instances --uploadwas broken in CI for any repo whose component sections callatmos.Component(...)inside Go templates with a stack-level default identity — the exact shape used by the Atmos Pro release workflow. Users reported the command failing withNo valid credential sources foundwhileatmos describe affected --uploadin the same workflow succeeded.atmos.Component(...)is a Go template function, not a YAML function. The processor's per-component auth resolver assumed YAML functions were the only consumer ofinfo.AuthContextand gated itself onprocessYamlFunctions. The template path reads the sameAuthContextand shells out toterraform init+terraform output, so disabling per-component auth broke template-only invocations.atmos listflags to line up withatmos describeflags. They didn't: onlylist affected,list settings, andlist valueshad the two knobs. A user workflow actually relied on--process-functionsonlist instances(where it didn't exist), which produced anunknown flagerror and a confusing escape hatch. Adding the two flags everywhere the command processes stacks closes that gap.truefor parity. Users who runatmos listlocally withouttofu/terraformon$PATHcan opt out with--process-functions=falseorATMOS_PROCESS_FUNCTIONS=false; the auth-guard fix above ensures thetrue, truedefault works end-to-end in CI.go get -u ./...pass doesn't trip over them blindly.references
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
Chores
Document CI statuses configuration options @goruha (#2362)
what
why
Summary by CodeRabbit
🚀 Enhancements
fix(jit): honor metadata.component subpath for JIT source-provisioned components @zack-is-cool (#2371)
What
JIT-provisioned components can now point at a submodule inside a cloned upstream repo via
metadata.component, the same way non-JIT components already can. Every JIT-capable code path is covered —terraform plan/apply,terraform generate varfile,terraform shell,helmfile,packer, andansible— and the resolver now lives inpkg/component/rather than being curve-fitted to Terraform insideinternal/exec/.Before this PR,
metadata.component: modules/iam-policywas silently ignored on the JIT/workdir code path — atmos cloned the repo to.workdir/<type>/<stack>-<component>/and ran the underlying tool against that root, so generated files (backend.tf.json, varfile,.terraform/, helmfile state, packer cache, ansible inventory) all landed at the repo root instead of at.workdir/<type>/<stack>-<component>/modules/iam-policy/. The tools then either failed with confusing errors or silently ran against the wrong directory (e.g. a repo root with no.tffiles).Fixes #2364.
Why this matters
Some upstream repos organize modules under
modules/<name>/rather than at the repo root (e.g.terraform-aws-modules/terraform-aws-iam). For JIT to be useful against those repos, atmos needs to clone the whole repo into a workdir (so relative parent-path references like../../shared-vars.tfresolve) and then run the tool against a specific submodule inside it. Non-JIT components already support this viametadata.component; this PR brings JIT/non-JIT parity for that capability and applies it uniformly across every executor.What changed (revised after maintainer review)
This PR was originally scoped to Terraform with helpers in
internal/exec/. Maintainer feedback on the first review was clear: the helpers belong inpkg/, and the same fix should apply to Helmfile/Packer/Ansible — not be curve-fitted to Terraform.Both items are addressed in this revision.
New package:
pkg/component/Helpers extracted into a single component-type-parameterized package, used by all four executors:
All five executor entry points collapse to one call
internal/exec/terraform_execute_helpers.go(plan/apply/etc.)provisionComponentSource(...)(terraform-only helper)component.ProvisionAndResolveComponentPath(ctx, ..., cfg.TerraformComponentType, ...)internal/exec/terraform_generate_varfile.gotryJITProvision(...)+ privatecheckDirectoryExists(terraform-only reimpl, subpath bolted on)component.ProvisionAndResolveComponentPath(ctx, ..., cfg.TerraformComponentType, ...)internal/exec/helmfile.go(prev. lines 121-155)provSource.AutoProvisionSource+ rawWorkdirPathKeylookup (subpath ignored)component.ProvisionAndResolveComponentPath(ctx, ..., cfg.HelmfileComponentType, ...)internal/exec/packer.go(prev. lines 121-155)component.ProvisionAndResolveComponentPath(ctx, ..., cfg.PackerComponentType, ...)pkg/component/ansible/executor.go(prev. lines 380-429)component.ProvisionAndResolveComponentPath(ctx, ..., cfg.AnsibleComponentType, ...)Helmfile, Packer, Ansible, and
terraform generate varfilesilently inherited the same #2364 bug; this PR fixes them at the same time as Terraform plan/apply, with zero curve-fitting.terraform shelland the post-ProcessStacksresolvers (terraform plan-diff,terraform verify-plan) callcomponent.ApplyWorkdirSubpathToSectionandcomponent.BuildAndResolveWorkdirPathrespectively for the same reason.Adjacent behavior change: JIT runs whenever
source.uriis setBefore this PR, helmfile/packer/ansible/
terraform generate varfileonly invokedAutoProvisionSourcewhen the local fallback component dir was missing. Ansible andterraform generate varfileadditionally short-circuited the moment that dir existed, never running JIT. After the refactor, all five entry points (terraform plan/apply, terraform generate varfile, helmfile, packer, ansible) take the same path: whensource.uriis declared, the source provisioner runs unconditionally, and only the YAML'ssource.uridecides whether JIT is in play.This is safe under steady-state operation because
AutoProvisionSourcealready self-debounces via two cache layers —invocationDoneKey(no-ops a second call within the same command lifecycle) andneedsProvisioning(skips re-provisioning when the version, URI, and freshness pin all match) — both inpkg/provisioner/source/provision_hook.go. Net effect for users: every JIT-capable entry point now honorssource.urithe same way terraform plan/apply always has, and the previously preferred lazy-skip-on-stale-local-dir path is gone.Post-ProcessStacks resolvers also use the shared helper
internal/exec/terraform_plan_diff.goandinternal/exec/terraform_verify_plan.gopreviously called the terraform-privateresolveWorkdirComponentPath; both now callcomponent.BuildAndResolveWorkdirPath(atmosConfig, info, cfg.TerraformComponentType).Existence-gated subpath join (the disambiguation)
metadata.componenthas two valid uses for JIT components — a real subdirectory inside the cloned repo, or an inheritance/identity pointer to an abstract base. The fix consults the filesystem rather than guessing from the string. After clone, either the joined subdirectory exists (case 1, apply the join) or it doesn't (case 2, leave the workdir root alone). String-shape heuristics (e.g. checking for/) are unreliable; the filesystem already encodes the right answer aftergit clone.An unexported
workdirSubpathAppliedKeyconstant + privatesubpathAppliedMarkerstruct type (both inpkg/component/) guard against double-joining if the orchestrator is invoked twice against the sameinfo.ComponentSectionmap. YAML deserialization can't produce this type, so a stack manifest containing_workdir_subpath_applied: <anything>cannot bypass the join. The constant lives inpkg/component/rather thanpkg/provisioner/workdir/because read/write access is confined to this package — keeping the protocol single-sourced next to the only code that uses it.Error sentinel precision
Three sentinels carry distinct meaning across the orchestrator and its callers:
errUtils.ErrProvisionerFailed—AutoProvisionSource(the JIT hook) failed.errUtils.ErrWorkdirProvision— path resolution / stat / abs-subpath rejection failure on the workdir path.errUtils.ErrInvalidComponent— stat failure on the local component directory (the no-source fallback path).Two related fixes during review:
AutoProvisionSourcefailures withErrWorkdirProvision, which conflicted with the established pattern inpkg/provisioner/registry.go,internal/exec/terraform_shell.go, and the (now-removed) ansible executor — all of which usedErrProvisionerFailed. Bringing ansible's existing semantics back.componentDirExistshelper used to wrap every stat failure withErrWorkdirProvision, including the!HasSourcebranch where the path is a local component directory, not a workdir. It now takes a sentinel parameter so the wrap matches the actual classification.terraform_shell.gono longer re-wraps an already-wrappedErrWorkdirProvisionwithErrProvisionerFailed; the original sentinel survives in the chain soerrors.Istriage works correctly.Design notes
..inmetadata.componentis allowed. Many upstream Terraform modules reference shared files via relative parent paths (../../shared-vars.tf) and need the full repo on disk with the working directory at a subdirectory. Restricting to strict subpaths would break those layouts. Atmos's threat model assumes a trusted operator running atmos against their own stack configs —metadata.componentis YAML-author-controlled, on par with!exec,!template, and!terraform.state, all of which can read or invoke arbitrary host resources. The godoc onResolveWorkdirSubpathspells this out for future readers.Absolute
metadata.componentis rejected. An absolute value violates the documented contract (metadata.componentis a relative subpath inside the workdir).filepath.Joinwould silently coerce it into a child of the workdir root on Unix and apply drive-letter semantics on Windows — coercing it would mask author error. Rejected up-front with a wrappedErrWorkdirProvision.Same-name inheritance is a no-op. When
metadata.componentequals the component instance name (e.g. a component namedvpcwithmetadata.component: vpc), atmos already clears the field during stack processing, soinfo.BaseComponentPathis empty andfilepath.Joinis never called.Trade-off: typos fall through. A typo in
metadata.component(e.g.modules/iam-policwhen the user meantmodules/iam-policy) silently falls back to the workdir root rather than failing fast. This matches pre-PR behavior for invalid subpaths and is logged at debug level for traceability. A future enhancement could surface a warning when the join falls back, distinguishing typos from intentional inheritance-pointer use.What is not changed
The orchestrator short-circuits at
!provSource.HasSource(...), so non-source components never reach the new code. Behavior of each non-JIT shape:metadata.component<workdirRoot>/<subpath>doesn't exist on disk; the resolver returnsexists=falseand the originalcomponentPathis preserved.metadata.componentplan-diffandverify-planonly: these two commands now resolve to the provisioned workdir root (where state actually lives) instead of falling back to the local component path. Live execution paths were already correct.Other deferred scope:
atmos terraform generate planfile— this command buildscomponentPathdirectly fromatmosConfig.TerraformDirAbsolutePath + info.FinalComponentand never invokes JIT provisioning. As a result,generate planfiledoes not support JIT components today (with or without ametadata.componentsubpath) — a pre-existing limitation, not a regression introduced by this PR. Wiring up JIT provisioning there is out of scope.Tests
Unit (
pkg/component/workdir_path_test.go):TestResolveWorkdirSubpath_JoinedPathExistsTestResolveWorkdirSubpath_JoinedPathMissingFallsBackTestResolveWorkdirSubpath_EmptySubpathReturnsRootmetadata.componentshort-circuits to the rootTestResolveWorkdirSubpath_AllowsParentSegment..resolves naturally — codifies the design decisionTestResolveWorkdirSubpath_RejectsAbsolutePathErrWorkdirProvisionTestResolveWorkdirSubpath_RejectsAbsolutePathOutsideWorkdirTestResolveWorkdirSubpath_RegularFileAtCandidateErrWorkdirProvisionwhen the candidate exists but is not a directoryTestApplyWorkdirSubpathToSection_JoinsSubpathWorkdirPathKeyto the joined subpath and sets the typed sentinelTestApplyWorkdirSubpathToSection_InheritancePointerPreservesRootWorkdirPathKeystays at the workdir rootTestApplyWorkdirSubpathToSection_NoWorkdirPathKeyWorkdirPathKeyis absentTestApplyWorkdirSubpathToSection_EmptyWorkdirPathWorkdirPathKeyis the empty stringTestApplyWorkdirSubpathToSection_DoubleCallAppliesOnceTestApplyWorkdirSubpathToSection_SentinelGatesDoubleJoinTestApplyWorkdirSubpathToSection_UserYAMLCannotForgeSentinelbool,string,int,map) cannot impersonate the typed sentinelTestBuildAndResolveWorkdirPath_ExistingDir(joined-path, true, nil)when the workdir subpath existsTestBuildAndResolveWorkdirPath_AllComponentTypes.workdir/<componentType>/TestBuildAndResolveWorkdirPath_AllComponentTypesWithSubpathmetadata.componentsubpath join (issue #2364 across executors)TestBuildAndResolveWorkdirPath_InheritancePointerFallsBack(workdir-root, true, nil)when the workdir root exists but the subpath doesn'tTestBuildAndResolveWorkdirPath_NonExistentDir(candidate, false, nil)when the workdir is not provisioned yetTestBuildAndResolveWorkdirPath_RegularFileAtCandidateErrWorkdirProvisionwhen the candidate exists but is not a directoryTestBuildAndResolveWorkdirPath_StatErrorPropagatesErrWorkdirProvisionfor non-ENOENTstat failures (EACCES)TestProvisionAndResolveComponentPath_NoSourceReturnsFallbackTestProvisionAndResolveComponentPath_NoSourceMissingDirexists=falsecorrectly when fallback dir is absentIntegration (
tests/cli_source_provisioner_workdir_test.go):TestJITSource_MetadataComponentSubpathatmos terraform generate varfile null-label-exports -s dev*.terraform.tfvars.jsonlands at<workdir>/exports/, not the workdir root. Reverting the fix moves the varfile and fails this assertion.TestJITSource_MetadataComponentSubpath_TerraformShellatmos terraform shell null-label-exports -s dev --dry-runWorking directoryandComponent pathinclude themetadata.componentsubpath. Reverting the fix prints the bare workdir root and fails this assertion.Both use
github.com/cloudposse/terraform-null-label@0.25.0withmetadata.component: exportsand skip gracefully on offline runners (no GitHub access or nogitbinary) via the existing precondition helpers.References
Summary by CodeRabbit
New Features
Bug Fixes
Tests
test(describe-affected): accept all three valid Source values in TestResolveBase_PullRequest_Closed @aknysh (#2388)
what
Fix a CI-blocking test bug in `pkg/ci/providers/github/base_test.go` introduced silently by PR #2380.
`TestResolveBase_PullRequest_Closed` passes on PR runs (where `merge-base` or `HEAD~1` is reachable) but fails on post-merge runs to `main` (where only the documented `event.pull_request.base.sha` fallback is available):
why
The assertion
```go
assert.Contains(t, res.Source, "merge-base", "HEAD~1")
```
has a silent bug: testify treats the 4th positional argument to `assert.Contains` as the failure message, not an alternate value to match. So the test only ever checked for `"merge-base"`, and quietly passed on PR runs (where `merge-base` or `HEAD~1` was reachable) while failing on post-merge runs to `main` (where the GitHub Actions checkout depth and missing `origin/` fetch leave only the third documented fallback, `event.pull_request.base.sha`).
`ResolveBase()`'s closed-PR fallback chain in `pkg/ci/providers/github/base.go` documents three valid Sources:
Replace the broken `Contains`-with-msg call with an explicit OR over the three substrings. The fix matches the test's own existing comment ("merge-base and HEAD~1 may or may not work; either way we get a valid resolution") -- the bug was that the assertion didn't actually check for "either way."
No production code change -- `ResolveBase()` already implements all three fallback paths correctly.
references
fix(ci): use terraform exit code as the source of truth for CI status @osterman (#2382)
what
terraform planwith-detailed-exitcode, for change detection) in the CI summary path. Text parsing of stdout/stderr is downgraded to enrichment only — it still extracts resource counts, output values, and error message bodies, but no longer drives the binaryHasErrors/HasChangesdecisions.cmd/terraform/utils.go→pkg/hooks RunCIHooks→pkg/ci ExecuteOptions→plugin.HookContextso the plugin handler has a clean signal independent of output format.parseOutputWithError(pkg/ci/plugins/terraform/handlers.go) so that:apply/deploy:HasErrors = (exitCode != 0)plan:HasErrors = (exitCode == 1);exitCode == 2also impliesHasChangesHasErrors = (exitCode != 0)CommandError.Error()for the body if text parsing didn't find one.*plugin.OutputResultfromparseOutputWithErrorthroughwriteSummaryandbuildTemplateContext(it had been silently dropped —writeSummaryhad_ *plugin.OutputResultas its second arg, andbuildTemplateContextre-parsedctx.Outputfrom scratch).buildTemplateContextkeeps anil-fallback so legacy callers continue to work.RunCIHooksto take a*RunCIHooksOptionsstruct (per the repo's options pattern) since the parameter list grew past the linter's max-args limit.HasChangesfor plan, apply exit 0 with strayError:in output → no error, plus the original failure-summary tests for plan/apply/deploy.why
atmos terraform deploy <component> -s <stack> --upload-statusfailing at the authentication step (before terraform itself ran, exit code 1) still produced a job summary that read## No Changes Applied for eks/karpenter-node-pool in e98d-gov-use1-dsswith aNO CHANGEbadge. The check run was correctly marked failed, but the summary contradicted it.ExtractErrors's^Error:regex (it's emitted as**Error:**in markdown form), andwriteSummarysilently dropped the already-enrichedOutputResult, so the apply template fell through to the no-changes branch. Anything that fails before terraform runs — auth, OOM, signal kill, network — would have hit the same bug.apply: 0 = success / non-zero = error;plan -detailed-exitcode: 0/1/2). Using them as the authoritative signal makes the hook robust against output-format drift between Terraform and OpenTofu, and against any pre-terraform failure that produces no parseable output.errUtils.GetExitCodealready unwrapsexec.ExitError,ExecError,exitCoder, andWorkflowStepError, so the existing error chains carry it through without further plumbing.references
pkg/ci/plugins/terraform/handlers.go(parseOutputWithError,writeSummary).pkg/ci/plugins/terraform/plugin.go(buildTemplateContext).pkg/ci/internal/plugin/types.go,pkg/ci/executor.go,pkg/hooks/hooks.go,cmd/terraform/utils.go.pkg/ci/plugins/terraform/templates/{apply,plan}.mdalready had{{ if .Result.HasErrors }}branches; they just weren't being reached.Summary by CodeRabbit
Release Notes
Bug Fixes
planandapplyoperations, properly handling plan changes and command execution failures.Tests
fix(auth): preserve AWS SDK error in assume-role / web-identity / assume-root failures @aknysh (#2385)
what
WithCause(err)at the three STS error sites inpkg/auth/identities/aws/:assume_role.go— standardAssumeRolepath.assume_role.go—AssumeRoleWithWebIdentity(OIDC) path.assume_root.go—AssumeRoot(centralized root access) path.pkg/auth/identities/aws/assume_sdk_error_test.gothat point STS at a local
httptest.Serverreturning AWS-style XMLerror envelopes (via the existing
aws.resolver.urlmechanism). Eachtest asserts the sentinel is preserved (
errors.Is(err, ErrAuthenticationFailed)), the AWS error code and message arereachable in
err.Error(), and the SDK error is also reachablethrough
errors.As(err, &smithy.APIError).docs/fixes/2026-05-01-assume-role-error-swallows-aws-cause.mddocumenting the issue and fix.
why
errUtils.Build(ErrAuthenticationFailed).WithExplanation(...).WithHint(...).Err()but never threaded the underlying SDK
errinto the chain. Operatorssaw only
authentication failed: identity=<name> step=<n>: authentication failedwith no AWS context.ATMOS_LOGS_LEVEL=Debug, whether the failure wasAccessDenied,NoSuchEntity,InvalidIdentityToken,ExpiredTokenException,MalformedPolicyDocumentException, throttling, etc. Each has adifferent remediation; the hint list ("verify the role ARN", "check
the trust policy", ...) effectively enumerated every plausible cause
because the actual one had been dropped.
WithCause(err)for exactly thiscase (
errors/builder.go:104-167). It chains the cause viafmt.Errorf("%w: %w", sentinel, cause), preserves the sentinel forerrors.Ischecks, and merges any hints/safe details the causealready carried. The canonical pattern is already used at
pkg/auth/identities/aws/webflow_token.go:88-97. The three assumesites just hadn't adopted it yet.
inline:
authentication failed: identity=<name> step=<n>: authentication failed: operation error STS: AssumeRoleWithWebIdentity, https response error StatusCode: 403, RequestID: ..., api error AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity— which makes the trust-policy / token / role-ARN problems
diagnosable from the first run.
WithCause(err)lines andconfirming the new tests fail; restoring the fix turns them green
again. Full
pkg/auth/...test suite (~25 packages) passes.references
docs/fixes/2026-05-01-assume-role-error-swallows-aws-cause.md—full root-cause writeup, code paths, and rationale (added in this
PR).
errors/builder.go:104-167—WithCause/WithCausefhelpersused by the fix.
pkg/auth/identities/aws/webflow_token.go:88-97— canonicalpattern referenced as the model for these three sites.
pkg/auth/manager_chain.go:570— chain wrapper that alreadyexpected the leaf to thread the cause via the trailing
%w; thisPR makes the leaf actually do so.
Summary by CodeRabbit
Bug Fixes
Tests
Documentation
fix(describe-affected): resolve PR base via merge-base with shallow-clone self-heal @osterman (#2380)
what
Fix
atmos describe affectedreporting many more affected componentsthan the PR actually modified, specifically when the PR is out of
date with the target branch.
pkg/git/merge_base.goaddsMergeBaseWithAutoFetchthat runs atargeted
git fetch origin <target>(and optionally one--deepen=200) whenMergeBasecan't resolve. Bounded retries.pkg/ci/providers/github/base.go:resolvePRBasekeeps merge-base asthe primary strategy and drops the buggy last-resort path that
returned
refs/remotes/origin/<target>(which downstream resolvedto the current tip of the target branch, producing the
false-positives). New last-resort is
event.pull_request.base.sha,which is frozen at the last PR sync and never points to the
current tip.
ExecuteDescribeAffectedWithTargetRefCheckoutaccepts a newtargetBranchparameter and self-heals viagit fetchwhenworktree creation hits a missing target commit.
pkg/git/fetch.go(FetchRef,DeepenFetch) lifted fromPR #2285. New
TargetBranchfield onBaseResolutionandDescribeAffectedCmdArgs.why
A customer reported that
atmos describe affectedon an out-of-datePR listed components the PR did not touch. The root cause was a
fallback path documented as "handles this gracefully" in the PRD
that, in practice, silently produced wrong results when the local
repo was a shallow checkout (the
actions/checkout@v4default).Walkthrough and rationale are in
docs/fixes/2026-04-30-describe-affected-out-of-date-pr.md.The user's suggestion — using
pull_request.merge_commit_shaasthe base — would also work and is documented as a considered
alternative in the fixes doc. We chose merge-base + auto-fetch
because it preserves the existing PRD architecture, doesn't require
fetching
M's parent separately, and works naturally withactions/checkout@v4's default merge-ref checkout.supersedes #2285
PR #2285 proposed promoting
pull_request.base.shato the primarystrategy. This PR keeps merge-base as primary (gold standard) and
uses
base.shaonly as a fallback that replaces the buggyref-tip path. The fetch helpers and signature plumbing are lifted
from #2285; credit to the original work.
tests
pkg/git/merge_base_test.go: newTestMergeBaseWithAutoFetch_RecoversFromMissingRefbuilds anorigin/clone pair, deletes
origin/mainto simulate a shallowCI checkout, and asserts the recovered SHA is the fork point —
not the current main tip.
pkg/ci/providers/github/base_test.go:TestResolveBase_PullRequest_OutOfDate_FallsBackToPayloadSHAreproduces the customer scenario at unit-test level.
internal/exec/describe_affected_test.go:TestResolveBaseFromCIhardened to require
describe.SHAis populated anddescribe.Refempty — guards against any future regression thatre-introduces the ref-tip fallback.
references
Summary by CodeRabbit
fix: authbridge resolver reads auth context from manager's stackInfo, not caller's @MrZablah (#2379)
what
instead of the caller's stackInfo
why
the terraform executor to authbridge.NewResolver
stackInfo.AuthContext.AWS, never the caller's info
manager's pointer, populated by auth)
available"
references
Summary by CodeRabbit
Bug Fixes
Chores
Tests
test: increase test coverage in pkg/flags, pkg/filesystem, pkg/http, and pkg/function @[copilot-swe-agent[bot]](https://redirect.github.com/apps/copilot-swe-agent) (#2173)
- [x] Explore all affected files - [x] internal/exec/stack_processor_utils_test.go: Convert hardcoded path strings to filepath.Join (both test functions) - [x] pkg/filesystem/export_test.go: Add trailing period to inline comment on line 35 - [x] Build & test verification💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.
Summary by CodeRabbit
fix(output): stop after-* hooks from corrupting backend.tf.json when backend uses !terraform.state @zack-is-cool (#2358)
Summary
Fixes #2356. The
after-terraform-applystore hook path regeneratedbackend.tf.json/providers_override.tf.jsonfrom un-renderedcomponent sections when the backend referenced
!terraform.state,overwriting a correctly-rendered file with literal YAML-function strings:
The hook then failed its
tofu outputcall with:Why
Regression introduced in v1.216.0 by #2309 (commit
3c0e748ce) +follow-up commit
c7ef142a9("fix: skip-init should skip yaml functionevaluation").
c7ef142a9added a guard disabling YAML-functionevaluation when
SkipInit && authManager == nilto avoid failing onauth-requiring functions in the post-hook context. The guard is overly
broad — it also disables evaluation of non-auth functions like
!terraform.state— so sect