Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions files/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var (
ErrInvalidHelmChartCode = "meshkit-11292"
ErrInvalidDockerComposeCode = "meshkit-11293"
ErrInvalidKustomizationCode = "meshkit-11294"
ErrUncompressedTarCode = "meshkit-11305"
ErrFileTypeNotSupportedForDesignConversionCode = "meshkit-11300"
)

Expand Down Expand Up @@ -260,6 +261,22 @@ func ErrInvalidHelmChart(fileName string, err error) error {
return errors.New(ErrInvalidHelmChartCode, errors.Critical, sdescription, ldescription, probableCause, remedy)
}

// ErrUncompressedTar returns an error explaining that Helm requires
// compressed tarballs (tgz / tar.gz) and that an uncompressed .tar was provided.
func ErrUncompressedTar(fileName string, err error) error {
return errors.New(
ErrUncompressedTarCode,
errors.Critical,
[]string{fmt.Sprintf("The file '%s' appears to be an uncompressed TAR archive.", fileName)},
[]string{fmt.Sprintf("Helm expects chart archives to be compressed (e.g., .tgz or .tar.gz). Error details: %s", err.Error())},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[]string{fmt.Sprintf("Helm expects chart archives to be compressed (e.g., .tgz or .tar.gz). Error details: %s", err.Error())},
[]string{fmt.Sprintf("Expected archives to be compressed (e.g., .tgz or .tar.gz). Error details: %s", err.Error())},

[]string{"The archive was created as an uncompressed .tar, but Helm requires compressed archives."},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[]string{"The archive was created as an uncompressed .tar, but Helm requires compressed archives."},
[]string{"The archive was created as an uncompressed .tar, but archives required to be compressed."},

[]string{
"Compress the .tar file to .tgz or .tar.gz and try again.",
"Create the Helm chart archive using 'helm package' or gzip the archive before uploading.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Create the Helm chart archive using 'helm package' or gzip the archive before uploading.",
"If it is a Helm chart archive, create using 'helm package' or gzip the archive before uploading.",

},
)
}

func ErrInvalidDockerCompose(fileName string, err error) error {
sdescription := []string{
fmt.Sprintf("The file '%s' is not a valid Docker Compose file.", fileName),
Expand Down
13 changes: 10 additions & 3 deletions files/identification.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package files
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"compress/gzip"

"github.com/meshery/meshkit/encoding"
"github.com/meshery/meshkit/models/oci"
Expand Down Expand Up @@ -298,11 +300,16 @@ func ParseFileAsHelmChart(file SanitizedFile) (*chart.Chart, error) {
return nil, fmt.Errorf("Invalid file extension %s", file.FileExt)
}

// Use Helm's loader.LoadDir to load the chart
// This function automatically handles nested directories and locates Chart.yaml
// Use Helm's loader.LoadArchive to load the chart
// This function expects a gzipped tar archive for charts (tgz / tar.gz)
chart, err := loader.LoadArchive(bytes.NewReader(file.RawData))
if err != nil {
return nil, fmt.Errorf("failed to load Helm chart %v", err)
// If the file extension was an uncompressed .tar and the loader failed
// due to gzip/invalid header, provide a human friendly hint.
if file.FileExt == ".tar" && errors.Is(err, gzip.ErrHeader) {
return nil, ErrUncompressedTar(file.FileName, err)
}
return nil, ErrInvalidHelmChart(file.FileName, err)
}

// Validate the chart (optional but recommended)
Expand Down
54 changes: 54 additions & 0 deletions files/tests/sanitization_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package files_test

import (
"archive/tar"
"bytes"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -192,3 +194,55 @@ func TestSanitizeFile(t *testing.T) {
})
}
}

// Test that providing an uncompressed .tar containing a Helm chart yields the
// helpful ErrUncompressedTarProvided (which uses ErrInvalidHelmChartCode).
func TestUncompressedHelmTarError(t *testing.T) {
// Build an in-memory uncompressed tar with a Chart.yaml
var buf bytes.Buffer
tw := tar.NewWriter(&buf)
chartYAML := []byte("apiVersion: v2\nname: test-chart\nversion: 0.1.0\n")
hdr := &tar.Header{
Name: "Chart.yaml",
Mode: 0600,
Size: int64(len(chartYAML)),
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatalf("failed to write tar header: %v", err)
}
if _, err := tw.Write(chartYAML); err != nil {
t.Fatalf("failed to write chart content: %v", err)
}
if err := tw.Close(); err != nil {
t.Fatalf("failed to close tar writer: %v", err)
}

tempDir, err := os.MkdirTemp("", "temp-tests")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
}
defer os.RemoveAll(tempDir)

validExts := map[string]bool{
".json": true,
".yml": true,
".yaml": true,
".tar": true,
".tgz": true,
".gz": true,
".zip": true,
}

sanitized, err := files.SanitizeFile(buf.Bytes(), "uncompressed-helm.tar", tempDir, validExts)
if err != nil {
t.Fatalf("unexpected sanitize error: %v", err)
}

_, err = files.ParseFileAsHelmChart(sanitized)
if err == nil {
t.Fatalf("expected error when parsing uncompressed tar as helm chart, got nil")
}
if errors.GetCode(err) != files.ErrUncompressedTarCode {
t.Fatalf("expected error code %s, got %s (err: %v)", files.ErrUncompressedTarCode, errors.GetCode(err), err)
Comment on lines +245 to +246
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if errors.GetCode(err) != files.ErrUncompressedTarCode {
t.Fatalf("expected error code %s, got %s (err: %v)", files.ErrUncompressedTarCode, errors.GetCode(err), err)
assert.NotNil(t, err) // to replace previous if
assert.Equal(t, files.ErrUncompressedTarCode, errors.GetCode(err))

}
}