Skip to content

Commit

Permalink
fixup; restore Install
Browse files Browse the repository at this point in the history
  • Loading branch information
menehune23 committed Sep 27, 2021
1 parent 4c8d959 commit d067bbb
Show file tree
Hide file tree
Showing 2 changed files with 263 additions and 1 deletion.
7 changes: 7 additions & 0 deletions postal/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ func (s Service) Deliver(dependency Dependency, cnbPath, layerPath, platformPath
return nil
}

// Install will invoke Deliver with a hardcoded value of /platform for the platform path.
//
// Deprecated: Use Deliver instead.
func (s Service) Install(dependency Dependency, cnbPath, layerPath string) error {
return s.Deliver(dependency, cnbPath, layerPath, "/platform")
}

// GenerateBillOfMaterials will generate a list of BOMEntry values given a
// collection of Dependency values.
func (s Service) GenerateBillOfMaterials(dependencies ...Dependency) []packit.BOMEntry {
Expand Down
257 changes: 256 additions & 1 deletion postal/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ version = "this is super not semver"
},
"some-cnb-path",
layerPath,
"",
"some-platform-dir",
)
}
})
Expand Down Expand Up @@ -548,6 +548,7 @@ version = "this is super not semver"
Expect(err).NotTo(HaveOccurred())

Expect(mappingResolver.FindDependencyMappingCall.Receives.SHA256).To(Equal(dependencySHA))
Expect(mappingResolver.FindDependencyMappingCall.Receives.PlatformDir).To(Equal("some-platform-dir"))
Expect(transport.DropCall.Receives.Root).To(Equal("some-cnb-path"))
Expect(transport.DropCall.Receives.Uri).To(Equal("dependency-mapping-entry.tgz"))

Expand Down Expand Up @@ -716,6 +717,260 @@ version = "this is super not semver"
})
})

context("Install", func() {
var (
dependencySHA string
layerPath string
install func() error
)

it.Before(func() {
var err error
layerPath, err = os.MkdirTemp("", "layer")
Expect(err).NotTo(HaveOccurred())

buffer := bytes.NewBuffer(nil)
zw := gzip.NewWriter(buffer)
tw := tar.NewWriter(zw)

Expect(tw.WriteHeader(&tar.Header{Name: "./some-dir", Mode: 0755, Typeflag: tar.TypeDir})).To(Succeed())
_, err = tw.Write(nil)
Expect(err).NotTo(HaveOccurred())

nestedFile := "./some-dir/some-file"
Expect(tw.WriteHeader(&tar.Header{Name: nestedFile, Mode: 0755, Size: int64(len(nestedFile))})).To(Succeed())
_, err = tw.Write([]byte(nestedFile))
Expect(err).NotTo(HaveOccurred())

for _, file := range []string{"./first", "./second", "./third"} {
Expect(tw.WriteHeader(&tar.Header{Name: file, Mode: 0755, Size: int64(len(file))})).To(Succeed())
_, err = tw.Write([]byte(file))
Expect(err).NotTo(HaveOccurred())
}

linkName := "./symlink"
linkDest := "./first"
Expect(tw.WriteHeader(&tar.Header{Name: linkName, Mode: 0777, Size: int64(0), Typeflag: tar.TypeSymlink, Linkname: linkDest})).To(Succeed())
_, err = tw.Write([]byte{})
Expect(err).NotTo(HaveOccurred())

Expect(tw.Close()).To(Succeed())
Expect(zw.Close()).To(Succeed())

sum := sha256.Sum256(buffer.Bytes())
dependencySHA = hex.EncodeToString(sum[:])

transport.DropCall.Returns.ReadCloser = io.NopCloser(buffer)

install = func() error {
return service.Install(
postal.Dependency{
ID: "some-entry",
Stacks: []string{"some-stack"},
URI: "some-entry.tgz",
SHA256: dependencySHA,
Version: "1.2.3",
},
"some-cnb-path",
layerPath,
)
}
})

it.After(func() {
Expect(os.RemoveAll(layerPath)).To(Succeed())
})

it("downloads the dependency and unpackages it into the path", func() {
err := install()

Expect(err).NotTo(HaveOccurred())

Expect(transport.DropCall.Receives.Root).To(Equal("some-cnb-path"))
Expect(transport.DropCall.Receives.Uri).To(Equal("some-entry.tgz"))

files, err := filepath.Glob(fmt.Sprintf("%s/*", layerPath))
Expect(err).NotTo(HaveOccurred())
Expect(files).To(ConsistOf([]string{
filepath.Join(layerPath, "first"),
filepath.Join(layerPath, "second"),
filepath.Join(layerPath, "third"),
filepath.Join(layerPath, "some-dir"),
filepath.Join(layerPath, "symlink"),
}))

info, err := os.Stat(filepath.Join(layerPath, "first"))
Expect(err).NotTo(HaveOccurred())
Expect(info.Mode()).To(Equal(os.FileMode(0755)))
})

context("when there is a dependency mapping via binding", func() {
it.Before(func() {
mappingResolver.FindDependencyMappingCall.Returns.String = "dependency-mapping-entry.tgz"
})

it("looks up the dependency from the platform binding and downloads that instead", func() {
err := install()

Expect(err).NotTo(HaveOccurred())

Expect(mappingResolver.FindDependencyMappingCall.Receives.SHA256).To(Equal(dependencySHA))
Expect(mappingResolver.FindDependencyMappingCall.Receives.PlatformDir).To(Equal("/platform"))
Expect(transport.DropCall.Receives.Root).To(Equal("some-cnb-path"))
Expect(transport.DropCall.Receives.Uri).To(Equal("dependency-mapping-entry.tgz"))

files, err := filepath.Glob(fmt.Sprintf("%s/*", layerPath))
Expect(err).NotTo(HaveOccurred())
Expect(files).To(ConsistOf([]string{
filepath.Join(layerPath, "first"),
filepath.Join(layerPath, "second"),
filepath.Join(layerPath, "third"),
filepath.Join(layerPath, "some-dir"),
filepath.Join(layerPath, "symlink"),
}))

info, err := os.Stat(filepath.Join(layerPath, "first"))
Expect(err).NotTo(HaveOccurred())
Expect(info.Mode()).To(Equal(os.FileMode(0755)))
})
})

context("failure cases", func() {
context("when the transport cannot fetch a dependency", func() {
it.Before(func() {
transport.DropCall.Returns.Error = errors.New("there was an error")
})

it("returns an error", func() {
err := install()

Expect(err).To(MatchError("failed to fetch dependency: there was an error"))
})
})

context("when the file contents are empty", func() {
it.Before(func() {
// This is a FLAC header
buffer := bytes.NewBuffer([]byte("\x66\x4C\x61\x43\x00\x00\x00\x22"))
transport.DropCall.Returns.ReadCloser = io.NopCloser(buffer)

sum := sha256.Sum256(buffer.Bytes())
dependencySHA = hex.EncodeToString(sum[:])
})

it("fails to create a gzip reader", func() {
err := install()

Expect(err).To(MatchError(ContainSubstring("unsupported archive type")))
})
})

context("when the file contents are malformed", func() {
it.Before(func() {
buffer := bytes.NewBuffer(nil)
gzipWriter := gzip.NewWriter(buffer)

_, err := gzipWriter.Write([]byte("something"))
Expect(err).NotTo(HaveOccurred())

Expect(gzipWriter.Close()).To(Succeed())

transport.DropCall.Returns.ReadCloser = io.NopCloser(buffer)

sum := sha256.Sum256(buffer.Bytes())
dependencySHA = hex.EncodeToString(sum[:])
})

it("fails to create a tar reader", func() {
err := install()

Expect(err).To(MatchError(ContainSubstring("failed to read tar response")))
})
})

context("when the file checksum does not match", func() {
it("fails to create a tar reader", func() {
err := service.Install(postal.Dependency{
ID: "some-entry",
Stacks: []string{"some-stack"},
URI: "some-entry.tgz",
SHA256: "this is not a valid checksum",
Version: "1.2.3",
}, "some-cnb-path",
layerPath,
)

Expect(err).To(MatchError(ContainSubstring("checksum does not match")))
})
})

context("when it does not have permission to write into directory on container", func() {
it.Before(func() {
Expect(os.Chmod(layerPath, 0000)).To(Succeed())
})

it.After(func() {
Expect(os.Chmod(layerPath, 0755)).To(Succeed())
})

it("fails to make a dir", func() {
err := install()

Expect(err).To(MatchError(ContainSubstring("failed to create archived directory")))
})
})

context("when it does not have permission to write into directory that it decompressed", func() {
var testDir string
it.Before(func() {
testDir = filepath.Join(layerPath, "some-dir")
Expect(os.MkdirAll(testDir, os.ModePerm)).To(Succeed())
Expect(os.Chmod(testDir, 0000)).To(Succeed())
})

it.After(func() {
Expect(os.Chmod(testDir, 0755)).To(Succeed())
})

it("fails to make a file", func() {
err := install()

Expect(err).To(MatchError(ContainSubstring("failed to create archived file")))
})
})

context("when it is given a broken symlink", func() {
it.Before(func() {
buffer := bytes.NewBuffer(nil)
zw := gzip.NewWriter(buffer)
tw := tar.NewWriter(zw)

linkName := "symlink"
Expect(tw.WriteHeader(&tar.Header{Name: linkName, Mode: 0777, Size: int64(0), Typeflag: tar.TypeSymlink, Linkname: "some-file"})).To(Succeed())
_, err := tw.Write([]byte{})
Expect(err).NotTo(HaveOccurred())

Expect(tw.Close()).To(Succeed())
Expect(zw.Close()).To(Succeed())

Expect(os.WriteFile(filepath.Join(layerPath, "some-file"), nil, 0644)).To(Succeed())
Expect(os.Symlink("some-file", filepath.Join(layerPath, "symlink"))).To(Succeed())

sum := sha256.Sum256(buffer.Bytes())
dependencySHA = hex.EncodeToString(sum[:])

transport.DropCall.Returns.ReadCloser = io.NopCloser(buffer)
})

it("fails to extract the symlink", func() {
err := install()

Expect(err).To(MatchError(ContainSubstring("failed to extract symlink")))
})
})
})
})

context("GenerateBillOfMaterials", func() {

it("returns a list of BOMEntry values", func() {
Expand Down

0 comments on commit d067bbb

Please sign in to comment.