Terraform CLI and Provider Versions
All Terraform versions covered by the CI test suite (0.12.31, 0.13.7, 0.14.11, 0.15.1).
Terraform Configuration
data "archive_file" "foo" {
type = "zip"
source_dir = "${path.module}/foo"
output_path = "${path.module}/foo/bar.zip"
}
Expected Behavior
The output archive bar.zip's contents should exactly replicate the files contained in /foo prior to Terraform execution.
For example, if the /foo directory structure looks like:
then the expected output archive contents should look like:
Specifically, if the /foo source directory does not contain an empty file named bar.zip prior to Terraform execution, then the output archive bar.zip's contents should also not contain an empty file named bar.zip.
Also, ideally, if the /foo source directory does contain a file named bar.zip prior to Terraform execution, then the output archive bar.zip's contents should also contain a file named bar.zip with the same file contents.
Actual Behavior
The output archive bar.zip's contents includes an extra (empty) file named bar.zip.
For example, if the /foo directory structure looks like:
then the actual output archive contents looks like:
Steps to Reproduce
This can be replicated with an extra unit test in internal/provider/zip_archiver_test.go:
func TestZipArchiver_Dir_OutputSameDir(t *testing.T) {
zipfilepath := "./test-fixtures/test-dir/archive-dir.zip"
archiver := NewZipArchiver(zipfilepath)
defer os.Remove(zipfilepath)
if err := archiver.ArchiveDir("./test-fixtures/test-dir", []string{""}); err != nil {
t.Fatalf("unexpected error: %s", err)
}
ensureContents(t, zipfilepath, map[string][]byte{
"file1.txt": []byte("This is file 1"),
"file2.txt": []byte("This is file 2"),
"file3.txt": []byte("This is file 3"),
})
}
which produces the following test output:
$ go test -v -cover ./internal/provider/
...
=== RUN TestZipArchiver_FileModified
--- PASS: TestZipArchiver_FileModified (0.00s)
=== RUN TestZipArchiver_Dir
--- PASS: TestZipArchiver_Dir (0.00s)
=== RUN TestZipArchiver_Dir_OutputSameDir
zip_archiver_test.go:121: mismatched file count, got 4, want 3
zip_archiver_test.go:121: additional file in zip: archive-dir.zip
=== RUN TestZipArchiver_Dir_Exclude
--- PASS: TestZipArchiver_Dir_Exclude (0.00s)
=== RUN TestZipArchiver_Dir_Exclude_With_Directory
--- PASS: TestZipArchiver_Dir_Exclude_With_Directory (0.00s)
How much impact is this issue causing?
Medium
Logs
No response
Additional Information
The reason this bug occurs is because in the ArchiveDir() implementation (see internal/provider/zip_archiver.go), a.open() is called before filepath.Walk().
a.open() calls os.Create(a.filepath) and therefore creates the empty file in the source directory. filepath.Walk() then proceeds to iterate through the source directory including this new empty file.
Potential solutions
-
Replace os.Create(a.filepath) with os.CreateTemp("", "*.zip") to initially build the archive file in a temporary location. Once built, call os.Rename() (or io.Copy() plus os.Remove()) to move the archive file to the target path.
-
Dynamically append the output path a.filepath to the excludes list, so that it will exclude itself. (However, this solution won't handle the scenario when there is a legitimate source file at path a.filepath that needs to be included.)
Code of Conduct
Terraform CLI and Provider Versions
All Terraform versions covered by the CI test suite (
0.12.31,0.13.7,0.14.11,0.15.1).Terraform Configuration
Expected Behavior
The output archive
bar.zip's contents should exactly replicate the files contained in/fooprior to Terraform execution.For example, if the
/foodirectory structure looks like:then the expected output archive contents should look like:
Specifically, if the
/foosource directory does not contain an empty file namedbar.zipprior to Terraform execution, then the output archivebar.zip's contents should also not contain an empty file namedbar.zip.Also, ideally, if the
/foosource directory does contain a file namedbar.zipprior to Terraform execution, then the output archivebar.zip's contents should also contain a file namedbar.zipwith the same file contents.Actual Behavior
The output archive
bar.zip's contents includes an extra (empty) file namedbar.zip.For example, if the
/foodirectory structure looks like:then the actual output archive contents looks like:
Steps to Reproduce
This can be replicated with an extra unit test in
internal/provider/zip_archiver_test.go:which produces the following test output:
How much impact is this issue causing?
Medium
Logs
No response
Additional Information
The reason this bug occurs is because in the
ArchiveDir()implementation (seeinternal/provider/zip_archiver.go),a.open()is called beforefilepath.Walk().a.open()callsos.Create(a.filepath)and therefore creates the empty file in the source directory.filepath.Walk()then proceeds to iterate through the source directory including this new empty file.Potential solutions
Replace
os.Create(a.filepath)withos.CreateTemp("", "*.zip")to initially build the archive file in a temporary location. Once built, callos.Rename()(orio.Copy()plusos.Remove()) to move the archive file to the target path.Dynamically append the output path
a.filepathto the excludes list, so that it will exclude itself. (However, this solution won't handle the scenario when there is a legitimate source file at patha.filepaththat needs to be included.)Code of Conduct