Skip to content

Commit

Permalink
fix: panic if Terraform module references path outside repository. (#…
Browse files Browse the repository at this point in the history
…2013)

## What this PR does / why we need it:

Fix a panic in the case a Terraform module has module calls with source
outside of the project root directory.

## Which issue(s) this PR fixes:
Fixes #2012 

## Special notes for your reviewer:

## Does this PR introduce a user-facing change?
```
yes, fixes a panic.
```
  • Loading branch information
i4ki authored Dec 18, 2024
2 parents 5dbde67 + b60bdd7 commit a1e3c39
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ Given a version number `MAJOR.MINOR.PATCH`, we increment the:
- The API Key configuration has precedence over all other authentication methods.
- Add support for unprefixed Bitbucket URLs in Terraform `module.source`.

### Fixed

- Fix `terramate list --changed` panic when a Terraform module references a path outside the project root.

## v0.11.4

### Added
Expand Down
9 changes: 9 additions & 0 deletions stack/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path"
"path/filepath"
"sort"
"strings"

"github.com/rs/zerolog/log"
"github.com/terramate-io/terramate/config"
Expand Down Expand Up @@ -570,6 +571,14 @@ func (m *Manager) tfModuleChanged(
}

modAbsPath := filepath.Join(basedir, mod.Source)
rootdir := m.root.Tree().RootDir()
if modAbsPath != rootdir && !strings.HasPrefix(modAbsPath, rootdir+string(filepath.Separator)) {
printer.Stderr.WarnWithDetails("skipping module call outside of the root directory", errors.E(
"module at %q references path %s (abspath %s) outside of the project root",
basedir, mod.Source, modAbsPath,
))
return false, "", nil
}
modPath := project.PrjAbsPath(m.root.HostDir(), modAbsPath)

st, err := os.Stat(modAbsPath)
Expand Down
51 changes: 51 additions & 0 deletions stack/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ func TestListChangedStacks(t *testing.T) {
changed: []string{"/stack"},
},
},
{
name: "single stack: dependent module changed has source path outside project root",
repobuilder: singleStackDependentModuleChangedWithSourceOutsideRepo,
want: listTestResult{
list: []string{"/stack"},
changed: []string{},
},
},
{
name: "multiple stack: single module changed",
repobuilder: multipleStackOneChangedModule,
Expand Down Expand Up @@ -708,6 +716,49 @@ module "module2" {
return repo
}

func singleStackDependentModuleChangedWithSourceOutsideRepo(t *testing.T) repository {
repo := singleMergeCommitRepoNoStack(t)

modules := test.Mkdir(t, repo.Dir, "modules")
module1 := test.Mkdir(t, modules, "module1")
module2 := test.Mkdir(t, modules, "module2")

repo.modules = append(repo.modules, module1, module2)

stack := test.Mkdir(t, repo.Dir, "stack")
root, err := config.LoadRoot(repo.Dir)
assert.NoError(t, err)
createStack(t, root, stack)
g := test.NewGitWrapper(t, repo.Dir, []string{})

test.WriteFile(t, stack, "main.tf", `
module "module1" {
source = "../modules/module1"
}
`)
test.WriteFile(t, module1, "main.tf", `
module "module2" {
source = "../../../../../../../module2"
}
`)

test.WriteFile(t, module2, "main.tf", `# nothing here`)

assert.NoError(t, g.Add(repo.Dir), "add files")
assert.NoError(t, g.Commit("files"), "commit files")
assert.NoError(t, g.Push("origin", "main"))

assert.NoError(t, g.Checkout("change-module", true))

test.WriteFile(t, module2, "main.tf", `
# any change
`)

assert.NoError(t, g.Add(repo.Dir), "add main.tf")
assert.NoError(t, g.Commit("commit module1/main.tf"), "commit main.tf")
return repo
}

func singleTerragruntStackWithNoChangesRepo(t *testing.T) repository {
repo := singleMergeCommitRepoNoStack(t)
test.WriteFile(t, repo.Dir, "terramate.tm.hcl", Doc(
Expand Down

0 comments on commit a1e3c39

Please sign in to comment.