Date: 2026-02-07 Status: ✅ FIXED
When running atmos describe affected, changes to the source and provision sections of a component are NOT
detected. This means:
- If
source.versionchanges (e.g., upgrading from0.25.0to0.26.0), the component is NOT marked as affected - If
provision.workdir.enabledchanges, the component is NOT marked as affected - Any other changes to
sourceorprovisionconfiguration are silently ignored
The describe affected command only checks these sections for changes:
metadata- checked viaisEqualvars- checked viaisEqualenv- checked viaisEqualsettings- checked viaisEqual- Component folder files - checked via
isComponentFolderChangedIndexed
The source and provision sections are NOT included in the comparison.
Code location: internal/exec/describe_affected_components.go
func processTerraformComponentsIndexed(...) ([]schema.Affected, error) {
// ...
// Check metadata section (OK)
if !isEqual(remoteStacks, ..., metadataSection, sectionNameMetadata) { ... }
// Check component folder changes (OK)
changed, err := isComponentFolderChangedIndexed(component, ...)
// Check vars section (OK)
if !isEqual(remoteStacks, ..., varSection, sectionNameVars) { ... }
// Check env section (OK)
if !isEqual(remoteStacks, ..., envSection, sectionNameEnv) { ... }
// Check settings section (OK)
if !isEqual(remoteStacks, ..., settingsSection, cfg.SettingsSectionName) { ... }
// MISSING: source section check
// MISSING: provision section check
}This issue affects:
-
Source Vendoring: When upgrading module versions via
source.version, the component won't be detected as affected, potentially causing stale deployments. -
Workdir Configuration: Changes to
provision.workdir.enabledor other workdir settings won't trigger the component to be marked as affected. -
CI/CD Pipelines: Automated workflows relying on
describe affectedwill miss components that need updates due to source or provision configuration changes.
Test fixtures have been added to reproduce this issue:
tests/fixtures/scenarios/atmos-describe-affected-source-vendoring/
├── atmos.yaml
├── components/terraform/mock/
│ └── main.tf
├── stacks/deploy/
│ └── staging.yaml # HEAD state (source.version = "1.0.0")
└── stacks-with-source-version-change/deploy/
└── staging.yaml # BASE state (source.version = "1.1.0")
Tests:
TestDescribeAffectedSourceVersionChange- Tests thatsource.versionandprovision.workdirchanges are detected
Added checks for source and provision sections in processTerraformComponentsIndexed,
processHelmfileComponentsIndexed, and processPackerComponentsIndexed.
// In processTerraformComponentsIndexed:
// Check source section for changes (NEW)
if sourceSection, ok := componentSection["source"].(map[string]any); ok {
if !isEqual(remoteStacks, stackName, cfg.TerraformComponentType, componentName, sourceSection, "source") {
err := addAffectedComponent(&affected, atmosConfig, componentName, stackName, cfg.TerraformComponentType,
&componentSection, "stack.source", includeSpaceliftAdminStacks, currentStacks, includeSettings)
if err != nil {
return nil, err
}
}
}
// Check provision section for changes (NEW)
if provisionSection, ok := componentSection["provision"].(map[string]any); ok {
if !isEqual(remoteStacks, stackName, cfg.TerraformComponentType, componentName, provisionSection, "provision") {
err := addAffectedComponent(&affected, atmosConfig, componentName, stackName, cfg.TerraformComponentType,
&componentSection, "stack.provision", includeSpaceliftAdminStacks, currentStacks, includeSettings)
if err != nil {
return nil, err
}
}
}An alternative approach would be to create a list of sections and iterate over them:
sectionsToCheck := []struct {
name string
reasonFmt string
}{
{"metadata", affectedReasonStackMetadata},
{"vars", affectedReasonStackVars},
{"env", affectedReasonStackEnv},
{"settings", affectedReasonStackSettings},
{"source", "stack.source"}, // NEW
{"provision", "stack.provision"}, // NEW
}
for _, section := range sectionsToCheck {
if sectionData, ok := componentSection[section.name].(map[string]any); ok {
if !isEqual(remoteStacks, stackName, componentType, componentName, sectionData, section.name) {
// Add affected...
}
}
}- Issue documented
- Root cause identified
- Test fixtures created
- Tests added to reproduce the issue
- Fix implemented
Added checks for source and provision sections in all three component processing functions:
processTerraformComponentsIndexedprocessHelmfileComponentsIndexedprocessPackerComponentsIndexed
File: internal/exec/describe_affected_components.go
-
Added new affected reason constants:
affectedReasonStackSource = "stack.source"affectedReasonStackProvision = "stack.provision"
-
Added new section name constants:
sectionNameSource = "source"sectionNameProvision = "provision"
-
Added checks in all three component processing functions to detect changes in
sourceandprovisionsections.
=== RUN TestDescribeAffectedSourceVersionChange
describe_affected_test.go:1388: Found 3 affected components
describe_affected_test.go:1390: - vpc-source in ue1-staging (affected by: stack.source)
describe_affected_test.go:1390: - vpc-source-workdir in ue1-staging (affected by: stack.source)
describe_affected_test.go:1390: - component-workdir-only in ue1-staging (affected by: stack.provision)
--- PASS: TestDescribeAffectedSourceVersionChange (6.84s)
Should describe affected also detect changes to the actual vendored component files in the workdir folder
(e.g., .workdir/terraform/<stack>-<component>/)?
The isComponentFolderChangedIndexed() function checks the static base path:
componentPath = filepath.Join(atmosConfig.BasePath, atmosConfig.Components.Terraform.BasePath, component)
// e.g., components/terraform/vpc/This is intentional because the base component folder is the source of truth that's committed to git.
When workdir or source vendoring is enabled:
- Developer modifies
source.versionin stack YAML (e.g.,1.0.0→1.1.0) - At
atmos terraform plantime, the provisioner downloads version1.1.0to.workdir/ - The workdir folder is typically in
.gitignore- it's not committed to git
The workdir path (.workdir/terraform/<stack>-<component>/) contains generated files, not source-controlled files.
| Change Type | Should Detect? | Status |
|---|---|---|
Base component folder files (.tf files) |
✅ Yes | Already works via isComponentFolderChangedIndexed |
source.version config change |
✅ Yes | Fixed in this commit |
source.uri config change |
✅ Yes | Fixed in this commit |
provision.workdir config change |
✅ Yes | Fixed in this commit |
Vendored files in .workdir/ |
❌ No | Not needed (runtime artifact, not in git) |
Developer changes source.version: 1.0.0 → 1.1.0
↓
Commits stack YAML change to git
↓
describe affected detects "stack.source" change ← This is what we fixed
↓
Component marked as affected
↓
At terraform plan time, provisioner vendors new version to .workdir/
The fix is complete. Detecting vendored workdir files is not needed because:
-
Source of truth is configuration: The
sourceandprovisionsections define what gets vendored. These are now detected. -
Workdir is ephemeral: Files in
.workdir/are generated at runtime based on config. They're not in git, so there's no git diff to detect. -
Changing
source.versiontriggers affected: Ifsource.versionchanges, the component is correctly marked as affected with reasonstack.source. The actual vendoring happens at execution time.