From 1cc2ad00611d036e244fd8a88cac31ab8923b367 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Fri, 11 Oct 2019 16:19:26 +0100 Subject: [PATCH] Port #5298 to Helm v3 (#6613) Signed-off-by: Martin Hickey --- pkg/chart/loader/archive.go | 42 ++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/pkg/chart/loader/archive.go b/pkg/chart/loader/archive.go index 45b9fb468..3c50fe379 100644 --- a/pkg/chart/loader/archive.go +++ b/pkg/chart/loader/archive.go @@ -20,7 +20,9 @@ import ( "archive/tar" "bytes" "compress/gzip" + "fmt" "io" + "net/http" "os" "path" "regexp" @@ -55,7 +57,45 @@ func LoadFile(name string) (*chart.Chart, error) { } defer raw.Close() - return LoadArchive(raw) + err = ensureArchive(name, raw) + if err != nil { + return nil, err + } + + c, err := LoadArchive(raw) + if err != nil { + if err == gzip.ErrHeader { + return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %s)", name, err) + } + } + return c, err +} + +// ensureArchive's job is to return an informative error if the file does not appear to be a gzipped archive. +// +// Sometimes users will provide a values.yaml for an argument where a chart is expected. One common occurrence +// of this is invoking `helm template values.yaml mychart` which would otherwise produce a confusing error +// if we didn't check for this. +func ensureArchive(name string, raw *os.File) error { + defer raw.Seek(0, 0) // reset read offset to allow archive loading to proceed. + + // Check the file format to give us a chance to provide the user with more actionable feedback. + buffer := make([]byte, 512) + _, err := raw.Read(buffer) + if err != nil && err != io.EOF { + return fmt.Errorf("file '%s' cannot be read: %s", name, err) + } + if contentType := http.DetectContentType(buffer); contentType != "application/x-gzip" { + // TODO: Is there a way to reliably test if a file content is YAML? ghodss/yaml accepts a wide + // variety of content (Makefile, .zshrc) as valid YAML without errors. + + // Wrong content type. Let's check if it's yaml and give an extra hint? + if strings.HasSuffix(name, ".yml") || strings.HasSuffix(name, ".yaml") { + return fmt.Errorf("file '%s' seems to be a YAML file, but expected a gzipped archive", name) + } + return fmt.Errorf("file '%s' does not appear to be a gzipped archive; got '%s'", name, contentType) + } + return nil } // LoadArchiveFiles reads in files out of an archive into memory. This function