diff --git a/pkg/action/pull.go b/pkg/action/pull.go index dc1e33e3a..8619e50e4 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -19,6 +19,7 @@ package action import ( "crypto/sha256" "fmt" + "io" "os" "path/filepath" "strings" @@ -144,17 +145,25 @@ func (p *Pull) Run(chartRef string) (string, error) { // path does not go through the registry client's summary printer, so we emit // a consistent summary here. We mirror the OCI output format: // - // Pulled: : + // Pulled: : // Digest: sha256: // // For HTTP/repo pulls, the digest is the SHA-256 of the downloaded .tgz archive. // For direct OCI pulls, the registry client already prints "Pulled:" and // "Digest:" (manifest digest), so we do not print here to avoid duplicates. if p.RepoURL != "" || !registry.IsOCI(downloadSourceRef) { - fmt.Fprintf(&out, "Pulled: %s\n", downloadSourceRef) + base := trimAnySuffix(downloadSourceRef, ".tar.gz", ".tgz") + chart, ver := splitChartNameVersion(base) + + tag := chart + if ver != "" { + tag += ":" + ver + } else if p.Version != "" { + tag += ":" + p.Version + } + fmt.Fprintf(&out, "Pulled: %s\n", tag) - if f, err := os.ReadFile(saved); err == nil { - sum := sha256.Sum256(f) + if sum, err := sha256File(saved); err == nil { fmt.Fprintf(&out, "Digest: sha256:%x\n", sum) } } @@ -194,3 +203,33 @@ func (p *Pull) Run(chartRef string) (string, error) { } return out.String(), nil } + +func trimAnySuffix(s string, suffixes ...string) string { + for _, suf := range suffixes { + if strings.HasSuffix(s, suf) { + return strings.TrimSuffix(s, suf) + } + } + return s +} + +func splitChartNameVersion(s string) (name, version string) { + if i := strings.LastIndex(s, "-"); i > 0 { + return s[:i], s[i+1:] + } + return s, "" +} + +func sha256File(path string) ([]byte, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + return nil, err + } + return h.Sum(nil), nil +} diff --git a/pkg/action/pull_test.go b/pkg/action/pull_test.go index 7d06ff9dd..5c6f488e9 100644 --- a/pkg/action/pull_test.go +++ b/pkg/action/pull_test.go @@ -77,7 +77,7 @@ entries: out, err := p.Run("testchart") require.NoError(t, err, "Pull.Run() should succeed. Output:\n%s", out) - expectedURL := srv.URL + "/testchart-1.2.3.tgz" + expectedURL := srv.URL + "/testchart:1.2.3" assert.Contains(t, out, "Pulled: "+expectedURL, "expected Pulled summary in output") assert.Contains(t, out, "Digest: "+wantDigest, "expected archive digest in output") @@ -95,7 +95,7 @@ func TestPull_PrintsSummary_ForDirectHTTPURL(t *testing.T) { wantDigest := fmt.Sprintf("sha256:%x", sum) mux := http.NewServeMux() - mux.HandleFunc("/directchart-9.9.9.tgz", func(w http.ResponseWriter, _ *http.Request) { + mux.HandleFunc("/directchart-9.9.9.tar.gz", func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/gzip") _, _ = w.Write(chartBytes) }) @@ -114,17 +114,17 @@ func TestPull_PrintsSummary_ForDirectHTTPURL(t *testing.T) { p.DestDir = t.TempDir() // Direct HTTP URL (absolute URL). Version is ignored for absolute URLs. - chartURL := srv.URL + "/directchart-9.9.9.tgz" + chartURL := srv.URL + "/directchart-9.9.9.tar.gz" out, err := p.Run(chartURL) require.NoError(t, err, "Pull.Run() should succeed. Output:\n%s", out) // Output should reflect name-version.tgz from the URL. - expectedURL := srv.URL + "/directchart-9.9.9.tgz" + expectedURL := srv.URL + "/directchart:9.9.9" assert.Contains(t, out, "Pulled: "+expectedURL, "expected Pulled summary in output") assert.Contains(t, out, "Digest: "+wantDigest, "expected archive digest in output") // Ensure the chart file was saved. - _, statErr := os.Stat(filepath.Join(p.DestDir, "directchart-9.9.9.tgz")) + _, statErr := os.Stat(filepath.Join(p.DestDir, "directchart-9.9.9.tar.gz")) require.NoError(t, statErr, "expected chart archive to be saved") } diff --git a/pkg/cmd/pull_test.go b/pkg/cmd/pull_test.go index 8a7a223cd..34bf2860b 100644 --- a/pkg/cmd/pull_test.go +++ b/pkg/cmd/pull_test.go @@ -44,7 +44,7 @@ func TestPullCmd(t *testing.T) { t.Fatal(err) } - helmTestKeyOut := "Pulled: signtest:0.1.0\n" + + helmTestKeyOut := "Pulled: test/signtest\n" + "Digest: sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55\n" + "Signed by: Helm Testing (This key should only be used for testing. DO NOT TRUST.) \n" + "Using Key With Fingerprint: 5E615389B53CA37F0EE60BD3843BBF981FC18762\n" +