Skip to content

Fix: Provenance file chart.yaml doesn't match the source#31916

Open
gabrnavarro wants to merge 1 commit intohelm:mainfrom
gabrnavarro:bot/task-63-issue-31866
Open

Fix: Provenance file chart.yaml doesn't match the source#31916
gabrnavarro wants to merge 1 commit intohelm:mainfrom
gabrnavarro:bot/task-63-issue-31866

Conversation

@gabrnavarro
Copy link

What changed

When signing a chart that contains list fields in Chart.yaml (e.g., keywords or sources), the provenance file now correctly serializes those lists using YAML flow style (e.g., keywords: [foo, bar]) instead of YAML block style (e.g., - foo).

A new exported MarshalMetadata function was added to pkg/provenance that handles this serialization. pkg/action/package.go was updated to use this function.

A regression test and test fixture were added to ensure the fix is covered.

Why

PGP clear-text signatures (RFC 4880) require "dash escaping": any line beginning with - must be prefixed with - in the signed body. YAML block-style list items start with - , so when chart metadata containing lists (like keywords or sources) was embedded in a provenance file, the PGP encoder would transform - foo into - - foo.

While Helm's verification code correctly un-escapes these when parsing the block.Plaintext, the raw provenance file stored on disk contained corrupted YAML. Users who tried to read or copy the Chart.yaml section from the .prov file would find double-nested arrays that couldn't be parsed as valid YAML.

Fixes #31866

Testing

  • Added TestMessageBlockKeywordsAndSources regression test that verifies:
    • Metadata bytes use flow-style arrays (no leading - entries)
    • A chart with keywords: [foo, bar] serializes without double-nesting
    • The full message block round-trips correctly through signing/verification
  • Added testdata/hashtest-keywords-1.2.3.tgz test fixture containing a chart with keywords and sources fields
  • All existing provenance and action package tests continue to pass

Copilot AI review requested due to automatic review settings March 9, 2026 16:48
@pull-request-size pull-request-size bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Mar 9, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes Helm provenance (.prov) generation so chart metadata containing YAML list fields (e.g., keywords, sources) is serialized in flow style, preventing PGP cleartext “dash escaping” from corrupting the embedded Chart.yaml content.

Changes:

  • Add provenance.MarshalMetadata to emit YAML with flow-style sequences.
  • Use provenance.MarshalMetadata during helm package --sign provenance generation.
  • Add a regression test and new chart fixture containing keywords/sources.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/provenance/sign.go Introduces MarshalMetadata and sequence flow-style rewriting via yaml.v3 nodes.
pkg/action/package.go Switches chart metadata marshaling for signing to provenance.MarshalMetadata.
pkg/provenance/sign_test.go Adds a regression test and updates helper to use MarshalMetadata.
pkg/provenance/testdata/hashtest-keywords/Chart.yaml New fixture chart metadata containing list fields.
pkg/provenance/testdata/hashtest-keywords.sha256 Checksum for the new keywords test fixture.
pkg/provenance/testdata/hashtest-keywords-1.2.3.tgz Packaged chart fixture with list fields.
go.mod Promotes gopkg.in/yaml.v3 to a direct dependency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +133 to +137
// Verify the metadata YAML does not contain double-nested arrays
metadataStr := string(metadataBytes)
if strings.Contains(metadataStr, "- - ") {
t.Errorf("metadata contains double-nested array entries (- - ), indicating keywords/sources are incorrectly wrapped:\n%s", metadataStr)
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

In this regression test, the "- - " check is applied to metadataBytes before the data goes through clearsign.Encode (where dash-escaping happens). That means it would not have caught the original bug, which only appears in the on-disk .prov content. Consider asserting on the raw sig string returned by ClearSign (or a saved .prov) to ensure it does not contain "\n- - " for list items, and optionally verify that clearsign.Decode(sig).Plaintext still round-trips.

Copilot uses AI. Check for mistakes.
Comment on lines +144 to +150
// Verify the metadata can be round-tripped: unmarshal back into Metadata and check fields
chart, err := loader.LoadFile(testChartfileWithKeywords)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, []string{"foo", "bar"}, chart.Metadata.Keywords, "keywords should be a flat string slice")
assert.Equal(t, []string{"https://example.com", "https://example.org"}, chart.Metadata.Sources, "sources should be a flat string slice")
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

The comment says the metadata is "round-tripped" by unmarshalling metadataBytes, but the test is actually re-loading the chart archive via loader.LoadFile and never parses metadataBytes. Either unmarshal metadataBytes back into a chart.Metadata (or a struct that contains Keywords/Sources) or adjust the comment/test to reflect what is being validated.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provenance file chart.yaml doesn't match the source

2 participants