Repository: meshery/meshkit

Issue:
[Helm] Improve import error message for unsupported uncompressed Helm .tar
### Current Behavior

```
Attempted to identify as 'helm-chart': failed to load Helm chart gzip: invalid header
```

### Desired Behavior
Same details, but with a human-friendly, initial message regarding unsupported, uncompressed .tar files that need to be tgz. or tar.gz (compressed), which is all that Helm supports.

---
### Contributor [Guides](https://docs.meshery.io/project/contributing) and [Handbook](https://meshery.io/community#handbook)
- 🛠 [Meshery Build & Release Strategy](https://docs.meshery.io/project/contributing/build-and-release)
- 📚 [Instructions for contributing to documentation](https://github.com/meshery/meshery/blob/master/CONTRIBUTING.md#documentation-contribution-flow)
   - Meshery documentation [site](https://docs.meshery.io/) and [source](https://github.com/meshery/meshery/tree/master/docs)
- 🎨 Wireframes and designs for Meshery UI in [Figma](https://www.figma.com/file/SMP3zxOjZztdOLtgN4dS2W/Meshery-UI)
- 🙋🏾🙋🏼 Questions: [Discussion Forum](http://discuss.meshery.io) and [Community Slack](https://slack.meshery.io)


Discussion:
@bashSunny101: Hi
Kindly assign this to me, I'm ready to work on it 
 
@leecalcote: Alrighty. @bashSunny101: Hi @leecalcote,
I have made some changes to fix the mentioned issue, Kindly review it and let me know if any further changes are to be made.
Also this contribution is part of hacktoberfest, so if possible kindly add labels to it, would be a great help :)
Thanks !@leecalcote: Labels aren’t needed. The repo already has the topic. @bashSunny101: @Darshan174 hi ,
Can you please review this PR@stale: This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@leecalcote: @bashSunny101, come to the next Meshery meeting and demo to work.

Solution patch:
diff --git a/files/error.go b/files/error.go
index 0b4b55e..86fa0fc 100644
--- a/files/error.go
+++ b/files/error.go
@@ -38,6 +38,7 @@ var (
 	ErrInvalidHelmChartCode                        = "meshkit-11292"
 	ErrInvalidDockerComposeCode                    = "meshkit-11293"
 	ErrInvalidKustomizationCode                    = "meshkit-11294"
+	ErrUncompressedTarCode                         = "meshkit-11305"
 	ErrFileTypeNotSupportedForDesignConversionCode = "meshkit-11300"
 )
 
@@ -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("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 archives required to be compressed."},
+		[]string{
+			"Compress the .tar file to .tgz or .tar.gz and try again.",
+			"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),
diff --git a/files/identification.go b/files/identification.go
index de30d5c..fc96652 100644
--- a/files/identification.go
+++ b/files/identification.go
@@ -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"
@@ -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)



Test patch:
diff --git a/files/tests/sanitization_test.go b/files/tests/sanitization_test.go
index a92a178..d5c0cff 100644
--- a/files/tests/sanitization_test.go
+++ b/files/tests/sanitization_test.go
@@ -1,12 +1,15 @@
 package files_test
 
 import (
+	"archive/tar"
+	"bytes"
 	"os"
 	"path/filepath"
 	"testing"
 
 	"github.com/meshery/meshkit/errors"
 	"github.com/meshery/meshkit/files"
+	"github.com/stretchr/testify/assert"
 	coreV1 "github.com/meshery/schemas/models/v1alpha1/core"
 )
 
@@ -192,3 +195,51 @@ func TestSanitizeFile(t *testing.T) {
 		})
 	}
 }
+
+// Test that providing an uncompressed .tar containing a Helm chart yields the
+// helpful ErrUncompressedTar (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)
+	assert.NotNil(t, err)
+	assert.Equal(t, files.ErrUncompressedTarCode, errors.GetCode(err))
+}