feat(cloudformation): add changesets, drift detection, fmt/list/source verbs [EXPERIMENTAL] - #3000
Draft
Erik Osterman (Cloud Posse) (osterman) wants to merge 10 commits into
Conversation
Contributor
|
Tip Atmos Pro
No affected stacks workflow was detected for this pull request. |
Erik Osterman (Cloud Posse) (osterman)
had a problem deploying
to
screengrabs
August 26, 2026 17:24 — with
GitHub Actions
Failure
Dependency Review✅ No vulnerabilities or license issues found.Scanned FilesNone |
Erik Osterman (Cloud Posse) (osterman)
had a problem deploying
to
screengrabs
August 26, 2026 17:28 — with
GitHub Actions
Failure
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
August 27, 2026 11:28
e43e0f4 to
845cff7
Compare
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
August 27, 2026 11:39
845cff7 to
8fad5cf
Compare
Erik Osterman (Cloud Posse) (osterman)
had a problem deploying
to
screengrabs
August 27, 2026 11:39 — with
GitHub Actions
Failure
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
August 27, 2026 11:44
8fad5cf to
dbf1a63
Compare
Erik Osterman (Cloud Posse) (osterman)
had a problem deploying
to
screengrabs
August 27, 2026 11:44 — with
GitHub Actions
Failure
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
August 27, 2026 15:43
825ba90 to
9b85623
Compare
Erik Osterman (Cloud Posse) (osterman)
had a problem deploying
to
screengrabs
August 27, 2026 15:43 — with
GitHub Actions
Failure
Erik Osterman (Cloud Posse) (osterman)
had a problem deploying
to
screengrabs
August 27, 2026 15:43 — with
GitHub Actions
Failure
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
August 27, 2026 16:00
9b85623 to
d579baf
Compare
Erik Osterman (Cloud Posse) (osterman)
had a problem deploying
to
screengrabs
August 27, 2026 16:00 — with
GitHub Actions
Failure
Erik Osterman (Cloud Posse) (osterman)
temporarily deployed
to
screengrabs
August 27, 2026 18:08 — with
GitHub Actions
Inactive
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
August 31, 2026 11:48
7ade8f0 to
a37103a
Compare
Erik Osterman (Cloud Posse) (osterman)
temporarily deployed
to
screengrabs
August 31, 2026 11:49 — with
GitHub Actions
Inactive
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
September 2, 2026 21:33
a37103a to
c3d2689
Compare
Erik Osterman (Cloud Posse) (osterman)
temporarily deployed
to
screengrabs
September 2, 2026 21:33 — with
GitHub Actions
Inactive
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
September 2, 2026 22:32
c3d2689 to
da12caf
Compare
Erik Osterman (Cloud Posse) (osterman)
temporarily deployed
to
screengrabs
September 2, 2026 22:32 — with
GitHub Actions
Inactive
…t verbs Explicit changeset control (create/execute/list/delete), complementing the implicit changeset flow apply/deploy/diff already use: - atmos aws cloudformation changeset create/execute/list/delete - atmos aws cloudformation drift detect/describe (DetectStackDrift/ DescribeStackDriftDetectionStatus/DescribeStackResourceDrifts) - atmos aws cloudformation get template/policy (GetTemplate/GetStackPolicy) Also the Terraform<->CloudFormation interop bridge: - `!aws.cloudformation.output <component> [stack] <output>` YAML function, sibling to !terraform.output (same cycle-detection/nested-auth machinery). - atmos.Component(...).outputs now resolves for aws/cloudformation targets, not just terraform. The CFN client interface grew ListChangeSets/DeleteChangeSet/GetTemplate/ GetStackPolicy/ListStacks/DetectStackDrift/DescribeStackDriftDetectionStatus/ DescribeStackResourceDrifts. runOperation and ComponentProvider.Execute were refactored from long switches to map-based dispatch (cyclomatic complexity had crossed the lint threshold with the new operations). The Outputs-fetching logic behind the YAML/template functions couldn't live in internal/exec directly (the provider-agnostic-auth depguard rule forbids AWS SDK imports there) or reuse pkg/component/aws/cloudformation's own client (it already imports internal/exec, so the reverse import would cycle) — added a small leaf package, pkg/aws/cloudformation, mirroring pkg/aws/identity's shape. Verified live against the Floci AWS emulator: changeset create/execute/list, get template, and both the YAML function and atmos.Component().outputs resolving a second component's real deployed Output value. drift detect and get policy hit genuine Floci/LocalStack-community limitations (confirmed via matching failures on raw AWS CLI calls against the same endpoint, not Atmos bugs) — DetectStackDrift is unimplemented and GetStackPolicy returns a malformed response Floci's own SDK client can't parse either. Every new/renamed YAML function tag required updates across five independent registries that must stay in sync with pkg/utils/yaml_utils.go's AtmosYamlFunc* constants: pkg/function/tag (the format-agnostic tag catalog), pkg/tags/selector.go (functions forbidden in metadata.tags/labels — this one matters: cross-component output resolution requires auth and a live API call, so it must be excluded from tag/label selector evaluation same as !terraform.output), pkg/config/schema/ratchet_test.go (atmos.yaml preprocessing classification), and cmd/list/utils.go (functions skipped during inventory upload when no AuthManager is available). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pkg/component/aws/cloudformation was at 74.6% after the Phase 2 commit added changeset_verbs.go/drift.go/get.go with no tests of their own; pkg/aws/cloudformation (the new leaf package backing the YAML/template function interop bridge) had none at all. Now 93.5% and 100% respectively, plus full coverage on the new internal/exec functions (cloudformation_output_getter.go, the !aws.cloudformation.output YAML function, and componentFunc's new CFN branch). Two small testability seams, matching each file's own existing convention: - pkg/aws/cloudformation/outputs.go had none at all — extracted a cloudFormationAPI interface + loadAWSConfig/newCloudFormationClient vars, mirroring pkg/aws/organization's identical pattern. - drift.go's poll interval/timeout became vars instead of consts so tests can shrink them, rather than requiring a real 15-minute wait to exercise the timeout branch. New fixture: tests/fixtures/scenarios/aws-cloudformation-outputs/, needed because the YAML/template function tests call through the real ExecuteDescribeComponent (no existing seam for it). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…se 2)
- atmos aws cloudformation fmt [--check]: native, dependency-free
comment-preserving YAML round-trip via yaml.v3's Node API (no cfn-format
binary exists to shell out to, and Rain's own formatter is archived along
with the rest of Rain). Both fmt and render are exempted from the
auth-manager setup every other operation requires — neither calls the
CloudFormation API.
- atmos aws cloudformation list [--status ...] [--region ...]: account-wide
ListStacks, annotated "managed"/"unmanaged" against the queried stack's
configured aws/cloudformation components by stack_name. Unlike every other
verb this isn't scoped to one component, so it bypasses
ComponentProvider.Execute entirely and calls the new
pkg/component/aws/cloudformation.ListDeployedStacks directly.
- atmos aws cloudformation source pull/list/describe/delete: wired onto the
existing generic pkg/provisioner/source/cmd builders already shared by
terraform/helmfile/packer — needed one addition, Config.CLIName, since those
three all happen to have a CLI command name identical to their internal
ComponentType string ("terraform" IS "terraform"), which "aws/cloudformation"
(type) vs. "aws cloudformation" (CLI path) breaks; CLIName defaults to
ComponentType so the other three callers are unaffected.
Verified live against the Floci AWS emulator: fmt --check/apply against the
example's template (confirmed short-form intrinsic tags like !Sub/!Ref
round-trip correctly, comments survive), list correctly marking a deployed
stack "managed" against its configured stack_name, and source describe
correctly reporting "not configured" for a component with no source: section.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pkg/component/aws/cloudformation dropped to 86.6% after the fmt/list/source commit added fmt.go/list.go with no tests; now 93.7%. cmd/aws/cloudformation went from 0% (no test file existed) to 50%, covering the pure extraction logic (cloudFormationComponentStackName, configuredCloudFormationStackNames) that list's managed/unmanaged annotation depends on — the remaining gap there is mostly RunE plumbing (real auth/config init), consistent with how the rest of this file is tested. One small extraction for testability: list.go's Managed-annotation loop is now its own pure function, annotateManagedStacks, so the managed/unmanaged boolean per stack is asserted directly rather than only through a full AWS-client round-trip. cmd/aws/cloudformation/source has no test file, matching cmd/terraform/source's own precedent — it's a config literal plus four delegated AddCommand calls with nothing to assert beyond "it builds," which the parent package's own tests already exercise. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CLI docs for changeset create/execute/list/delete, drift detect/describe, get template/policy, fmt, list, and source pull/list/describe/delete (mirroring the existing terraform/helmfile/packer source docs pattern). Also documents the Terraform<->CloudFormation interop bridge: !aws.cloudformation.output alongside the other YAML functions (including its forbidden-in-selectors restriction, same as !terraform.output), and atmos.Component(...).outputs now resolving aws/cloudformation targets. No config/schema reference changes needed — Phase 2 added CLI verbs only, no new stack-manifest or atmos.yaml fields. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…dentity componentFunc cached its result under stack+component alone, computed after resolving the nested target's AuthManager. Two calls for the same component/stack under two different resolved identities (e.g. two callers passing different --identity, or a target whose own auth section only applies on one call) could silently return the other identity's/region's cached outputs. Move the AuthManager resolution ahead of the cache lookup and fold the resolved identity/region into the cache key. Found via CodeRabbit review. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t confirmed-drift/changeset ones DetectStackDrift/DescribeStackDriftDetectionStatus/DescribeStackResourceDrifts API failures and detection timeouts were wrapped in ErrAwsCloudFormationDriftDetected, which should mean drift was actually confirmed (runDriftDetect's --fail-on-drift case, left unchanged). Likewise GetTemplate/GetStackPolicy failures were wrapped in ErrAwsCloudFormationChangeSetFailed despite having nothing to do with a changeset. Swapped both to ErrAwsCloudFormationAPICallFailed. Found via CodeRabbit review. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… strengthen tests - GetAvailableCommands() now derives its list from subCommandOperations instead of a hand-maintained literal, which was missing "destroy", "outputs", and "fmt" — those verbs were dispatchable via Execute but rejected by pkg/composition's verb-allowlist check (GetAvailableCommands is its source of truth). - pkg/aws/cloudformation's GetOutputs (the !aws.cloudformation.output interop bridge) wrapped both a DescribeStacks API failure and a genuine stack-not-found result in the same ErrAwsCloudFormationChangeSetFailed, despite neither being changeset-related. Split into ErrAwsCloudFormationAPICallFailed and a new ErrAwsCloudFormationStackNotFound. - Fixed a stale doc comment on runChangesetList (said "creation time", renders "description"). - Strengthened TestRenderDeployedStacksList_Populated: "managed" is a substring of "unmanaged", so the old assert.Contains checks would still pass even if both rows rendered as unmanaged. Now asserts full rendered lines. Found via CodeRabbit review. Several other findings from the same pass were verified against current code and are false positives (not fixed): the --affected/--all doc examples correctly omit --stack per this codebase's bulk-selection convention; `plan` is a genuinely registered alias for `diff`; `list`'s empty --stack behavior matches every other describe-stacks command's "no filter = all stacks" convention; the NextToken-nil pagination check matches every other pagination loop in this package and the AWS SDK's documented contract; and yaml_func_aws.go's discarded second return value from resolveNestedOutputAuth is the resolved auth manager, not an error — the function has no error return at all. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This branch's own docs (changeset/drift/fmt/get/list/source, 18 verbs) referenced screengrab casts that were never recorded, and cli.yaml's command manifest never listed them — the same gap fixed cumulatively on the top of the stack, but each PR in this stack is validated against its own branch tip, not the final merged result, so this layer needs its own fix. Also recorded the original 8 top-level verbs' casts (render/plan/ diff/apply/deploy/delete/validate/output) plus --help, which had never been committed at all on this branch either. atmos --chdir=demo/casts casts generate screengrabs cli --filter=cloudformation Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Erik Osterman (Cloud Posse) (osterman)
force-pushed
the
osterman/cfn-phase2-changesets-drift-outputs
branch
from
September 3, 2026 00:13
da12caf to
430dd87
Compare
Erik Osterman (Cloud Posse) (osterman)
temporarily deployed
to
screengrabs
September 3, 2026 00:14 — with
GitHub Actions
Inactive
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## osterman/cfn-phase1-core-lifecycle #3000 +/- ##
======================================================================
+ Coverage 83.55% 83.58% +0.03%
======================================================================
Files 1963 1973 +10
Lines 191390 191947 +557
======================================================================
+ Hits 159911 160448 +537
- Misses 23477 23490 +13
- Partials 8002 8009 +7
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
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.
what
aws/cloudformationcomponent type: changeset management(
changeset create/execute/list/delete), drift detection (drift detect/describe), template/policyfetch (
get template/policy), plusfmt,list, andsource(JIT vendoring) inspection verbs.why
and drift visibility that CloudFormation users expect, matching the ergonomics the archived Rain
CLI used to provide.
references
cfn-phase1-core-lifecyclein this stack.cfn-phase4-migration-graduationfor the final layer and blog post.