diff --git a/pkg/plugin/installer/http_installer.go b/pkg/plugin/installer/http_installer.go index bac495a40..ea4ac7bcd 100644 --- a/pkg/plugin/installer/http_installer.go +++ b/pkg/plugin/installer/http_installer.go @@ -187,7 +187,7 @@ func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { return err } case tar.TypeReg: - outFile, err := os.Create(path) + outFile, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)) if err != nil { return err } diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go index a8fa06d79..89884f107 100644 --- a/pkg/plugin/installer/http_installer_test.go +++ b/pkg/plugin/installer/http_installer_test.go @@ -16,9 +16,14 @@ limitations under the License. package installer // import "helm.sh/helm/v3/pkg/plugin/installer" import ( + "archive/tar" "bytes" + "compress/gzip" "encoding/base64" + "io/ioutil" "os" + "path/filepath" + "syscall" "testing" "github.com/pkg/errors" @@ -177,3 +182,87 @@ func TestHTTPInstallerUpdate(t *testing.T) { t.Error("update method not implemented for http installer") } } + +func TestExtract(t *testing.T) { + source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz" + + tempDir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempDir) + + // Set the umask to default open permissions so we can actually test + oldmask := syscall.Umask(0000) + defer func() { + syscall.Umask(oldmask) + }() + + // Write a tarball to a buffer for us to extract + var tarbuf bytes.Buffer + tw := tar.NewWriter(&tarbuf) + var files = []struct { + Name, Body string + Mode int64 + }{ + {"plugin.yaml", "plugin metadata", 0600}, + {"README.md", "some text", 0777}, + } + for _, file := range files { + hdr := &tar.Header{ + Name: file.Name, + Typeflag: tar.TypeReg, + Mode: file.Mode, + Size: int64(len(file.Body)), + } + if err := tw.WriteHeader(hdr); err != nil { + t.Fatal(err) + } + if _, err := tw.Write([]byte(file.Body)); err != nil { + t.Fatal(err) + } + } + if err := tw.Close(); err != nil { + t.Fatal(err) + } + + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + if _, err := gz.Write(tarbuf.Bytes()); err != nil { + t.Fatal(err) + } + gz.Close() + // END tarball creation + + extr, err := NewExtractor(source) + if err != nil { + t.Fatal(err) + } + + if err = extr.Extract(&buf, tempDir); err != nil { + t.Errorf("Did not expect error but got error: %v", err) + } + + pluginYAMLFullPath := filepath.Join(tempDir, "plugin.yaml") + if info, err := os.Stat(pluginYAMLFullPath); err != nil { + if os.IsNotExist(err) { + t.Errorf("Expected %s to exist but doesn't", pluginYAMLFullPath) + } else { + t.Error(err) + } + } else if info.Mode().Perm() != 0600 { + t.Errorf("Expected %s to have 0600 mode it but has %o", pluginYAMLFullPath, info.Mode().Perm()) + } + + readmeFullPath := filepath.Join(tempDir, "README.md") + if info, err := os.Stat(readmeFullPath); err != nil { + if os.IsNotExist(err) { + t.Errorf("Expected %s to exist but doesn't", readmeFullPath) + } else { + t.Error(err) + } + } else if info.Mode().Perm() != 0777 { + t.Errorf("Expected %s to have 0777 mode it but has %o", readmeFullPath, info.Mode().Perm()) + } + +}