fix: escape non-ASCII OCI annotation values

Signed-off-by: kkh <kkhdevs@gmail.com>
pull/31701/head
kkh 5 days ago
parent 8fcb7d1f63
commit 9dd3f87e02

@ -18,8 +18,11 @@ package registry // import "helm.sh/helm/v4/pkg/registry"
import (
"bytes"
"strconv"
"strings"
"time"
"unicode/utf16"
"unicode/utf8"
chart "helm.sh/helm/v4/pkg/chart/v2"
"helm.sh/helm/v4/pkg/chart/v2/loader"
@ -59,7 +62,7 @@ annotations:
}
// Add chart annotation
ociAnnotations[chartAnnotationKey] = chartAnnotationValue
ociAnnotations[chartAnnotationKey] = escapeNonASCII(chartAnnotationValue)
}
return ociAnnotations
@ -117,8 +120,44 @@ func addToMap(inputMap map[string]string, newKey string, newValue string) map[st
// Add item to map if its
if len(strings.TrimSpace(newValue)) > 0 {
inputMap[newKey] = newValue
inputMap[newKey] = escapeNonASCII(newValue)
}
return inputMap
}
func escapeNonASCII(value string) string {
if value == "" {
return value
}
var escaped strings.Builder
escaped.Grow(len(value))
for _, r := range value {
if r < utf8.RuneSelf {
escaped.WriteRune(r)
continue
}
if r <= 0xFFFF {
writeEscapedRune(&escaped, r)
continue
}
high, low := utf16.EncodeRune(r)
writeEscapedRune(&escaped, high)
writeEscapedRune(&escaped, low)
}
return escaped.String()
}
func writeEscapedRune(builder *strings.Builder, r rune) {
builder.WriteString("\\u")
hex := strconv.FormatInt(int64(r), 16)
for i := len(hex); i < 4; i++ {
builder.WriteByte('0')
}
builder.WriteString(hex)
}

@ -63,6 +63,20 @@ func TestGenerateOCIChartAnnotations(t *testing.T) {
"org.opencontainers.image.url": "https://helm.sh",
},
},
{
"Chart values with non-ASCII",
&chart.Metadata{
Name: "oci",
Version: "0.0.1",
Description: "OCI Helm Chart for Kr\u00f6pke",
},
map[string]string{
"org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
"org.opencontainers.image.description": "OCI Helm Chart for Kr\\u00f6pke",
},
},
{
"Maintainer without email",
&chart.Metadata{
@ -198,6 +212,22 @@ func TestGenerateOCIAnnotations(t *testing.T) {
"anotherkey": "anothervalue",
},
},
{
"Custom annotations with non-ASCII values",
&chart.Metadata{
Name: "oci",
Version: "0.0.1",
Annotations: map[string]string{
"extrakey": "Kr\u00f6pke",
},
},
map[string]string{
"org.opencontainers.image.title": "oci",
"org.opencontainers.image.version": "0.0.1",
"org.opencontainers.image.created": nowString,
"extrakey": "Kr\\u00f6pke",
},
},
{
"Verify Chart Name and Version cannot be overridden from annotations",
&chart.Metadata{
@ -231,6 +261,36 @@ func TestGenerateOCIAnnotations(t *testing.T) {
}
}
func TestEscapeNonASCII(t *testing.T) {
tests := []struct {
name string
input string
expect string
}{
{
name: "ASCII only",
input: "alpha-._:@/+ 123",
expect: "alpha-._:@/+ 123",
},
{
name: "Latin-1 characters",
input: "Kr\u00f6pke",
expect: "Kr\\u00f6pke",
},
{
name: "Emoji",
input: "chart \U0001f600",
expect: "chart \\ud83d\\ude00",
},
}
for _, tt := range tests {
if got := escapeNonASCII(tt.input); got != tt.expect {
t.Errorf("%s: expected %q, got %q", tt.name, tt.expect, got)
}
}
}
func TestGenerateOCICreatedAnnotations(t *testing.T) {
nowTime := time.Now()

Loading…
Cancel
Save