feat(packages): add support for uploading helm provenance files (#36695)

Adds `POST helm/api/prov` endpoint for helm repository allowing for upload of provenance files.

Tested manually to a degree but I really didn't want to mess with gpg
again so I'm not sure if helm will correctly verify the chart.
Initial draft made by gemini 3 flash but was finetuned somewhat.

Additionally there's an route that allows for upload of both files via
/api/charts - as separate files in form. If there's any interest in that
I guess it can be added but I think helm is moving to OCI anyway which
we support.

Fixes: https://github.com/go-gitea/gitea/issues/36678
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
TheFox0x7
2026-08-09 12:55:43 +00:00
committed by GitHub
co-authored by silverwind
parent 7e34eae370
commit 85558c28fc
4 changed files with 163 additions and 0 deletions
+21
View File
@@ -5,6 +5,7 @@ package helm
import (
"archive/tar"
"bytes"
"compress/gzip"
"io"
"strings"
@@ -12,6 +13,7 @@ import (
"gitea.dev/modules/util"
"gitea.dev/modules/validation"
"github.com/ProtonMail/go-crypto/openpgp/clearsign"
"github.com/hashicorp/go-version"
"go.yaml.in/yaml/v4"
)
@@ -25,6 +27,8 @@ var (
ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid")
// ErrInvalidChart indicates an invalid chart
ErrInvalidChart = util.NewInvalidArgumentErrorf("chart is invalid")
// ErrInvalidProvenance indicates an invalid provenance file
ErrInvalidProvenance = util.NewInvalidArgumentErrorf("provenance file is invalid")
)
// Metadata for a Chart file. This models the structure of a Chart.yaml file.
@@ -128,3 +132,20 @@ func ParseChartFile(r io.Reader) (*Metadata, error) {
return metadata, nil
}
// ParseProvenanceFile parses a provenance file to retrieve the metadata of a Helm chart
func ParseProvenanceFile(r io.Reader) (*Metadata, error) {
data, err := io.ReadAll(io.LimitReader(r, 1<<20))
if err != nil {
return nil, err
}
// A provenance file must be a clearsigned PGP message
block, _ := clearsign.Decode(data)
if block == nil {
return nil, ErrInvalidProvenance
}
// Use the plaintext content from the clearsigned message
return ParseChartFile(bytes.NewReader(block.Plaintext))
}