diff --git a/slug.go b/slug.go index 09d8fbe..53c4579 100644 --- a/slug.go +++ b/slug.go @@ -158,6 +158,12 @@ func (p *Packer) Pack(src string, w io.Writer) (*Meta, error) { ignoreRules = parseIgnoreFile(src) } + // Ensure the source path provided is absolute + src, err = filepath.Abs(src) + if err != nil { + return nil, fmt.Errorf("failed to read absolute path for source: %w", err) + } + // Walk the tree of files. err = filepath.Walk(src, p.packWalkFn(src, src, src, tarW, meta, ignoreRules)) if err != nil { @@ -264,7 +270,7 @@ func (p *Packer) packWalkFn(root, src, dst string, tarW *tar.Writer, meta *Meta, // If the target is a directory we can recurse into the target // directory by calling the packWalkFn with updated arguments. if resolved.info.IsDir() { - return filepath.Walk(resolved.absTarget, p.packWalkFn(root, resolved.target, path, tarW, meta, ignoreRules)) + return filepath.Walk(resolved.absTarget, p.packWalkFn(root, resolved.absTarget, path, tarW, meta, ignoreRules)) } // Dereference this symlink by updating the header with the target file diff --git a/slug_test.go b/slug_test.go index 44b6878..5a1eb9d 100644 --- a/slug_test.go +++ b/slug_test.go @@ -55,6 +55,43 @@ func TestPack_rootIsSymlink(t *testing.T) { } } +func TestPack_absoluteSrcRelativeSymlinks(t *testing.T) { + var path string + var err error + + // In instances we run within CI, we want to fetch + // the absolute path where our test is located + if workDir, ok := os.LookupEnv("GITHUB_WORKSPACE"); ok { + path = workDir + } else { + path, err = os.Getwd() + if err != nil { + t.Fatalf("could not determine the working dir: %v", err) + } + } + + // One last check, if this variable is empty we'll error + // since we need the absolute path for the source + if path == "" { + t.Fatal("Home directory could not be determined") + } + + path = filepath.Join(path, "testdata/archive-dir-absolute/dev") + slug := bytes.NewBuffer(nil) + _, err = Pack(path, slug, true) + if err != nil { + // We simply want to ensure paths can be resolved while + // traversing the source directory + t.Fatalf("err: %v", err) + } + + // Cannot pack without dereferencing + _, err = Pack(path, slug, false) + if !strings.HasPrefix(err.Error(), "illegal slug error:") { + t.Fatalf("expected illegal slug error, got %q", err) + } +} + func TestPackWithoutIgnoring(t *testing.T) { slug := bytes.NewBuffer(nil) @@ -1057,7 +1094,8 @@ func assertArchiveFixture(t *testing.T, slug *bytes.Buffer, got *Meta) { tarR := tar.NewReader(gzipR) var ( - symFound bool + sym1Found bool + sym2Found bool externalTargetFound bool fileList []string slugSize int64 @@ -1084,25 +1122,35 @@ func assertArchiveFixture(t *testing.T, slug *bytes.Buffer, got *Meta) { if hdr.Linkname != "../bar.txt" { t.Fatalf("expect target of '../bar.txt', got %q", hdr.Linkname) } - symFound = true + sym1Found = true } - if hdr.Name == "example.tf" { + if hdr.Name == "sub2/bar.txt" { if hdr.Typeflag != tar.TypeSymlink { - t.Fatalf("expected symlink file 'example.tf'") + t.Fatalf("expect symlink for file 'sub2/bar.txt'") + } + if hdr.Linkname != "../sub/bar.txt" { + t.Fatalf("expect target of '../sub/bar.txt', got %q", hdr.Linkname) + } + sym2Found = true + } + + if hdr.Name == "example.tf" { + if hdr.Typeflag != tar.TypeReg { + t.Fatalf("expected symlink to be dereferenced 'example.tf'") } externalTargetFound = true } } // Make sure we saw and handled a symlink - if !symFound { - t.Fatal("expected to find symlink") + if !sym1Found || !sym2Found { + t.Fatal("expected to find two symlinks") } - // Make sure we saw and handled a nested symlink + // Make sure we saw and handled a dereferenced symlink if !externalTargetFound { - t.Fatal("expected to find nested symlink") + t.Fatal("expected to find dereferenced symlink") } // Make sure the .git directory is ignored diff --git a/testdata/archive-dir-absolute/_common/extra-files/bar.sh b/testdata/archive-dir-absolute/_common/extra-files/bar.sh new file mode 100644 index 0000000..5b0e87e --- /dev/null +++ b/testdata/archive-dir-absolute/_common/extra-files/bar.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "bar" diff --git a/testdata/archive-dir-absolute/_common/extra-files/foo.sh b/testdata/archive-dir-absolute/_common/extra-files/foo.sh new file mode 100644 index 0000000..af85c95 --- /dev/null +++ b/testdata/archive-dir-absolute/_common/extra-files/foo.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "foo" diff --git a/testdata/archive-dir-absolute/_common/locals.tf b/testdata/archive-dir-absolute/_common/locals.tf new file mode 100644 index 0000000..7324c9d --- /dev/null +++ b/testdata/archive-dir-absolute/_common/locals.tf @@ -0,0 +1,3 @@ +locals { + app = "service-01" +} diff --git a/testdata/archive-dir-absolute/_common/output.tf b/testdata/archive-dir-absolute/_common/output.tf new file mode 100644 index 0000000..94e8f35 --- /dev/null +++ b/testdata/archive-dir-absolute/_common/output.tf @@ -0,0 +1,7 @@ +locals { + files = fileset("${path.module}/extra-files", "*.sh") +} + +output "scripts" { + value = local.files +} diff --git a/testdata/archive-dir-absolute/_common/versions.tf b/testdata/archive-dir-absolute/_common/versions.tf new file mode 100644 index 0000000..c509258 --- /dev/null +++ b/testdata/archive-dir-absolute/_common/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = "~> 1.2" +} diff --git a/testdata/archive-dir-absolute/dev/backend.tf b/testdata/archive-dir-absolute/dev/backend.tf new file mode 100644 index 0000000..3e1c863 --- /dev/null +++ b/testdata/archive-dir-absolute/dev/backend.tf @@ -0,0 +1,10 @@ +terraform { + remote "backend" { + hostname = "foobar.terraform.io" + organization = "hashicorp" + + workspaces { + name = "dev-service-02" + } + } +} diff --git a/testdata/archive-dir-absolute/dev/extra-files b/testdata/archive-dir-absolute/dev/extra-files new file mode 120000 index 0000000..6773dc5 --- /dev/null +++ b/testdata/archive-dir-absolute/dev/extra-files @@ -0,0 +1 @@ +../_common/extra-files \ No newline at end of file diff --git a/testdata/archive-dir-absolute/dev/locals.tf b/testdata/archive-dir-absolute/dev/locals.tf new file mode 120000 index 0000000..173668c --- /dev/null +++ b/testdata/archive-dir-absolute/dev/locals.tf @@ -0,0 +1 @@ +../_common/locals.tf \ No newline at end of file diff --git a/testdata/archive-dir-absolute/dev/output.tf b/testdata/archive-dir-absolute/dev/output.tf new file mode 120000 index 0000000..d597fae --- /dev/null +++ b/testdata/archive-dir-absolute/dev/output.tf @@ -0,0 +1 @@ +../_common/output.tf \ No newline at end of file diff --git a/testdata/archive-dir-absolute/dev/variables.tf b/testdata/archive-dir-absolute/dev/variables.tf new file mode 100644 index 0000000..ec9ce9d --- /dev/null +++ b/testdata/archive-dir-absolute/dev/variables.tf @@ -0,0 +1,4 @@ +locals { + env = "dev" + region = "us-east-2" +} diff --git a/testdata/archive-dir-absolute/dev/versions.tf b/testdata/archive-dir-absolute/dev/versions.tf new file mode 120000 index 0000000..08a39e4 --- /dev/null +++ b/testdata/archive-dir-absolute/dev/versions.tf @@ -0,0 +1 @@ +../_common/versions.tf \ No newline at end of file