Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ APACHE 2.0 LICENSED DEPENDENCIES

- cloud.google.com/go/storage
License: Apache-2.0
URL: https://github.com/googleapis/google-cloud-go/blob/storage/v1.58.0/storage/LICENSE
URL: https://github.com/googleapis/google-cloud-go/blob/storage/v1.59.2/storage/LICENSE

- cuelang.org/go
License: Apache-2.0
Expand Down Expand Up @@ -119,7 +119,7 @@ APACHE 2.0 LICENSED DEPENDENCIES

- github.com/aws/aws-sdk-go-v2/feature/s3/manager
License: Apache-2.0
URL: https://github.com/aws/aws-sdk-go-v2/blob/feature/s3/manager/v1.20.19/feature/s3/manager/LICENSE.txt
URL: https://github.com/aws/aws-sdk-go-v2/blob/feature/s3/manager/v1.22.0/feature/s3/manager/LICENSE.txt

- github.com/aws/aws-sdk-go-v2/internal/configsources
License: Apache-2.0
Expand Down Expand Up @@ -159,7 +159,7 @@ APACHE 2.0 LICENSED DEPENDENCIES

- github.com/aws/aws-sdk-go-v2/service/s3
License: Apache-2.0
URL: https://github.com/aws/aws-sdk-go-v2/blob/service/s3/v1.95.1/service/s3/LICENSE.txt
URL: https://github.com/aws/aws-sdk-go-v2/blob/service/s3/v1.96.0/service/s3/LICENSE.txt

- github.com/aws/aws-sdk-go-v2/service/secretsmanager
License: Apache-2.0
Expand Down Expand Up @@ -950,7 +950,7 @@ MIT LICENSED DEPENDENCIES

- al.essio.dev/pkg/shellescape
License: MIT
URL: https://github.com/alessio/shellescape/blob/v1.5.1/LICENSE
URL: https://github.com/alessio/shellescape/blob/v1.6.0/LICENSE

- github.com/99designs/keyring
License: MIT
Expand Down Expand Up @@ -1034,7 +1034,7 @@ MIT LICENSED DEPENDENCIES

- github.com/alecthomas/chroma/v2
License: MIT
URL: https://github.com/alecthomas/chroma/blob/v2.23.0/COPYING
URL: https://github.com/alecthomas/chroma/blob/v2.23.1/COPYING

- github.com/alecthomas/participle/v2/lexer
License: MIT
Expand Down Expand Up @@ -1078,7 +1078,7 @@ MIT LICENSED DEPENDENCIES

- github.com/bmatcuk/doublestar/v4
License: MIT
URL: https://github.com/bmatcuk/doublestar/blob/v4.9.2/LICENSE
URL: https://github.com/bmatcuk/doublestar/blob/v4.10.0/LICENSE

- github.com/catppuccin/go
License: MIT
Expand All @@ -1098,7 +1098,7 @@ MIT LICENSED DEPENDENCIES

- github.com/charmbracelet/bubbles
License: MIT
URL: https://github.com/charmbracelet/bubbles/blob/23b8fd6302d7/LICENSE
URL: https://github.com/charmbracelet/bubbles/blob/v0.21.1/LICENSE

- github.com/charmbracelet/bubbletea
License: MIT
Expand Down Expand Up @@ -1130,11 +1130,11 @@ MIT LICENSED DEPENDENCIES

- github.com/charmbracelet/x/ansi
License: MIT
URL: https://github.com/charmbracelet/x/blob/ansi/v0.11.4/ansi/LICENSE
URL: https://github.com/charmbracelet/x/blob/ansi/v0.11.5/ansi/LICENSE

- github.com/charmbracelet/x/cellbuf
License: MIT
URL: https://github.com/charmbracelet/x/blob/cellbuf/v0.0.14/cellbuf/LICENSE
URL: https://github.com/charmbracelet/x/blob/cellbuf/v0.0.15/cellbuf/LICENSE

- github.com/charmbracelet/x/exp/slice
License: MIT
Expand All @@ -1150,15 +1150,15 @@ MIT LICENSED DEPENDENCIES

- github.com/clipperhouse/displaywidth
License: MIT
URL: https://github.com/clipperhouse/displaywidth/blob/v0.7.0/LICENSE
URL: https://github.com/clipperhouse/displaywidth/blob/v0.9.0/LICENSE

- github.com/clipperhouse/stringish
License: MIT
URL: https://github.com/clipperhouse/stringish/blob/v0.1.1/LICENSE

- github.com/clipperhouse/uax29/v2
- github.com/clipperhouse/uax29/v2/graphemes
License: MIT
URL: https://github.com/clipperhouse/uax29/blob/v2.3.0/LICENSE
URL: https://github.com/clipperhouse/uax29/blob/v2.5.0/LICENSE

- github.com/cloudposse/atmos/pkg/config/homedir
License: MIT
Expand Down
249 changes: 249 additions & 0 deletions docs/fixes/2026-02-07-describe-affected-source-provision-sections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# Fix: `describe affected` now checks `source` and `provision` sections

**Date**: 2026-02-07
**Status**: ✅ FIXED

## Problem Summary

When running `atmos describe affected`, changes to the `source` and `provision` sections of a component are NOT
detected. This means:

- If `source.version` changes (e.g., upgrading from `0.25.0` to `0.26.0`), the component is NOT marked as affected
- If `provision.workdir.enabled` changes, the component is NOT marked as affected
- Any other changes to `source` or `provision` configuration are silently ignored

## Root Cause

The `describe affected` command only checks these sections for changes:

- `metadata` - checked via `isEqual`
- `vars` - checked via `isEqual`
- `env` - checked via `isEqual`
- `settings` - checked via `isEqual`
- 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`

```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
}
```

## Impact

This issue affects:

1. **Source Vendoring**: When upgrading module versions via `source.version`, the component won't be detected as
affected, potentially causing stale deployments.

2. **Workdir Configuration**: Changes to `provision.workdir.enabled` or other workdir settings won't trigger the
component to be marked as affected.

3. **CI/CD Pipelines**: Automated workflows relying on `describe affected` will miss components that need updates due
to source or provision configuration changes.

## Test Fixtures

Test fixtures have been added to reproduce this issue:

```text
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 that `source.version` and `provision.workdir` changes are detected

## Applied Fix

Added checks for `source` and `provision` sections in `processTerraformComponentsIndexed`,
`processHelmfileComponentsIndexed`, and `processPackerComponentsIndexed`.

### Implementation (Option A: Add section checks)

```go
// 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
}
}
}
```

### Alternative (Option B: Generic section comparison)

An alternative approach would be to create a list of sections and iterate over them:

```go
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...
}
}
}
```

## Implementation Status

- [x] Issue documented
- [x] Root cause identified
- [x] Test fixtures created
- [x] Tests added to reproduce the issue
- [x] Fix implemented

## Implemented Fix

Added checks for `source` and `provision` sections in all three component processing functions:
- `processTerraformComponentsIndexed`
- `processHelmfileComponentsIndexed`
- `processPackerComponentsIndexed`

### Changes Made

**File: `internal/exec/describe_affected_components.go`**

1. Added new affected reason constants:
- `affectedReasonStackSource = "stack.source"`
- `affectedReasonStackProvision = "stack.provision"`

2. Added new section name constants:
- `sectionNameSource = "source"`
- `sectionNameProvision = "provision"`

3. Added checks in all three component processing functions to detect changes in `source` and `provision` sections.

### Test Results

```text
=== 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)
```

## Analysis: Why Vendored/Workdir Files Don't Need Detection

### Question

Should `describe affected` also detect changes to the actual vendored component files in the workdir folder
(e.g., `.workdir/terraform/<stack>-<component>/`)?

### Answer: No, and here's why

#### How Component Path Detection Works

The `isComponentFolderChangedIndexed()` function checks the **static base path**:

```go
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.

#### Workdir Files Are Runtime Artifacts

When workdir or source vendoring is enabled:

1. Developer modifies `source.version` in stack YAML (e.g., `1.0.0` → `1.1.0`)
2. At `atmos terraform plan` time, the provisioner downloads version `1.1.0` to `.workdir/`
3. 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.

#### What Gets Detected

| 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) |

#### The Detection Flow

```text
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/
```

### Conclusion

The fix is complete. Detecting vendored workdir files is not needed because:

1. **Source of truth is configuration**: The `source` and `provision` sections define what gets vendored. These are now
detected.

2. **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.

3. **Changing `source.version` triggers affected**: If `source.version` changes, the component is correctly marked as
affected with reason `stack.source`. The actual vendoring happens at execution time.
Loading