diff --git a/internal/chart/v3/util/save.go b/internal/chart/v3/util/save.go index 09235c1ea..3b91bcb7a 100644 --- a/internal/chart/v3/util/save.go +++ b/internal/chart/v3/util/save.go @@ -33,7 +33,11 @@ import ( "helm.sh/helm/v4/pkg/chart/common" ) -var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=") +// RFC 1952 subfield header: +// +---+---+---+---+==================================+ +// |SI1|SI2| LEN |... LEN bytes of subfield data ...| +// +---+---+---+---+==================================+ +var headerBytes = []byte("rr\x28\x00aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=") // SaveDir saves a chart as files in a directory. // diff --git a/internal/chart/v3/util/save_test.go b/internal/chart/v3/util/save_test.go index 00f2c5cf4..f0ff46077 100644 --- a/internal/chart/v3/util/save_test.go +++ b/internal/chart/v3/util/save_test.go @@ -21,6 +21,7 @@ import ( "bytes" "compress/gzip" "crypto/sha256" + "encoding/binary" "encoding/hex" "errors" "io" @@ -108,6 +109,41 @@ func TestSave(t *testing.T) { require.Error(t, err, "Expected error saving chart with invalid name") } +func TestSavedGzipExtraFieldIsValid(t *testing.T) { + tmp := t.TempDir() + c := &chart.Chart{ + Metadata: &chart.Metadata{ + APIVersion: chart.APIVersionV3, + Name: "ahab", + Version: "1.2.3", + }, + } + + where, err := Save(c, tmp) + require.NoError(t, err, "Failed to save") + + f, err := os.Open(where) + require.NoError(t, err, "Failed to open saved file") + defer f.Close() + + r, err := gzip.NewReader(f) + require.NoError(t, err, "Failed to create gzip reader") + defer r.Close() + + // RFC 1952 ยง2.3.1.1: + // Each subfield consists of SI1, SI2 (1 byte each), + // a 2-byte little-endian LEN, and LEN bytes of data. + // https://www.rfc-editor.org/rfc/rfc1952.html#page-8 + extra := r.Extra + + require.NotEmpty(t, extra) + require.GreaterOrEqual(t, len(extra), 4) + + dataLen := int(binary.LittleEndian.Uint16(extra[2:4])) + // Assume a single subfield. + require.Lenf(t, extra, 4+dataLen, "gzip extra field has malformed subfield: LEN=%d but %d data byte(s) follow the subfield header", dataLen, len(extra)-4) +} + // Creates a copy with a different schema; does not modify anything. func withSchema(chart chart.Chart, schema []byte) chart.Chart { chart.Schema = schema