diff --git a/pkg/cosign/chart.go b/pkg/cosign/chart.go index e16d551..958ed55 100644 --- a/pkg/cosign/chart.go +++ b/pkg/cosign/chart.go @@ -17,7 +17,6 @@ import ( "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" "helm.sh/helm/v3/pkg/chart/loader" - "helm.sh/helm/v3/pkg/repo" _ "github.com/sigstore/sigstore/pkg/signature/kms/aws" _ "github.com/sigstore/sigstore/pkg/signature/kms/azure" @@ -148,20 +147,10 @@ func (so SignChartOption) Run() error { } for _, d := range chartRef.Metadata.Dependencies { - if d.Repository != "" { + if !(d.Repository == "" || strings.HasPrefix(d.Repository, "file://")) { v := d.Version if strings.Contains(v, "*") || strings.Contains(v, "x") { - chart := helm.Chart{ - Name: d.Name, - Repo: repo.Entry{ - Name: c.Repo.Name + "/" + d.Name, - URL: d.Repository, - }, - Version: d.Version, - ValuesFilePath: c.ValuesFilePath, - Parent: &c, - PlainHTTP: c.PlainHTTP, - } + chart := helm.DependencyToChart(d, c) // Resolve Globs to latest patch v, err = chart.ResolveVersion() diff --git a/pkg/helm/chart.go b/pkg/helm/chart.go index 4a812e2..857ddad 100644 --- a/pkg/helm/chart.go +++ b/pkg/helm/chart.go @@ -55,6 +55,21 @@ type Chart struct { DepsCount int } +func DependencyToChart(d *chart.Dependency, p Chart) Chart { + return Chart{ + Name: d.Name, + Repo: repo.Entry{ + Name: p.Repo.Name + "/" + d.Name, + URL: d.Repository, + }, + Version: d.Version, + Parent: &p, + ValuesFilePath: p.ValuesFilePath, + DepsCount: 0, + PlainHTTP: p.PlainHTTP, + } +} + // AddChartRepositoryToHelmRepositoryFile adds repository to Helm repository.yml to enable querying/pull func (c Chart) AddToHelmRepositoryFile() (bool, error) { config := cli.New() @@ -583,42 +598,35 @@ func (c Chart) PushAndModify(registry string, insecure bool, plainHTTP bool) (st } defer os.Remove(path) - dname, err := os.MkdirTemp("", "sampledir") + dir, err := os.MkdirTemp("", "sampledir") if err != nil { return "", err } - // fmt.Println("Temp dir name:", dname) - defer os.RemoveAll(dname) + defer os.RemoveAll(dir) - err = chartutil.ExpandFile(dname, path) + err = chartutil.ExpandFile(dir, path) if err != nil { return "", err } // modify chart contents here before pushing - chartRef, err := loader.Load(dname + "/" + c.Name) + chartRef, err := loader.Load(dir + "/" + c.Name) if err != nil { return "", err } // Dependencies (Chart.yaml) for _, d := range chartRef.Metadata.Dependencies { - if d.Repository != "" { + switch { + case strings.HasPrefix(d.Repository, "file://"): + slog.Debug("Leaving embedded chart as is", slog.String("Chart", d.Name)) + case d.Repository != "": // Change dependency ref to registry being imported to d.Repository = registry - if strings.Contains(d.Version, "*") { - chart := Chart{ - Name: d.Name, - Repo: repo.Entry{ - Name: c.Repo.Name + "/" + d.Name, - URL: d.Repository, - }, - Version: d.Version, - ValuesFilePath: c.ValuesFilePath, - Parent: &c, - } + if strings.Contains(d.Version, "*") || strings.Contains(d.Version, "x") { + chart := DependencyToChart(d, c) // OCI dependencies can not use globs in version // Resolve Globs to latest patch @@ -631,7 +639,7 @@ func (c Chart) PushAndModify(registry string, insecure bool, plainHTTP bool) (st } - err = chartutil.SaveChartfile(dname+"/"+c.Name+"/Chart.yaml", chartRef.Metadata) + err = chartutil.SaveChartfile(dir+"/"+c.Name+"/Chart.yaml", chartRef.Metadata) if err != nil { return "", err } @@ -640,14 +648,14 @@ func (c Chart) PushAndModify(registry string, insecure bool, plainHTTP bool) (st // https://github.com/helm/helm/blob/main/cmd/helm/dependency_update.go var buf bytes.Buffer ma := getManager(&buf, true, true) - ma.ChartPath = dname + "/" + c.Name + ma.ChartPath = dir + "/" + c.Name err = ma.Update() if err != nil { - return "", err + slog.Debug("Error occurred trying to update Helm Chart on filesystem, skipping update of chart dependencies", slog.String("error", err.Error())) } // Reload Helm Chart from filesystem - chartRef, err = loader.Load(dname + "/" + c.Name) + chartRef, err = loader.Load(dir + "/" + c.Name) if err != nil { return "", err } @@ -802,8 +810,8 @@ func (c Chart) Locate() (string, error) { } return fmt.Sprintf("%s/%s-%s.tgz", helmCacheHome, c.Name, c.Version), nil - default: + default: u, err := url.Parse(c.Repo.URL) if err != nil { return "", err diff --git a/pkg/helm/chartImportOption.go b/pkg/helm/chartImportOption.go index daea0c6..86dfbc5 100644 --- a/pkg/helm/chartImportOption.go +++ b/pkg/helm/chartImportOption.go @@ -11,7 +11,6 @@ import ( "github.com/ChristofferNissen/helmper/pkg/registry" "github.com/k0kubun/go-ansi" "github.com/schollz/progressbar/v3" - "helm.sh/helm/v3/pkg/repo" ) type ChartImportOption struct { @@ -53,25 +52,14 @@ func (opt ChartImportOption) Run(ctx context.Context, setters ...Option) error { // continue // } - // Only import enabled charts - if d.Repository == "" { + // only import remote charts + if d.Repository == "" || strings.HasPrefix(d.Repository, "file://") { // Embedded in parent chart slog.Debug("Skipping embedded chart", slog.String("chart", d.Name), slog.String("parent", c.Name)) continue } - chart := Chart{ - Name: d.Name, - Repo: repo.Entry{ - Name: c.Repo.Name + "/" + d.Name, - URL: d.Repository, - }, - Version: d.Version, - ValuesFilePath: c.ValuesFilePath, - Parent: &c, - DepsCount: 0, - PlainHTTP: c.PlainHTTP, - } + chart := DependencyToChart(d, c) // Resolve Globs to latest patch if strings.Contains(chart.Version, "*") { diff --git a/pkg/helm/chartOption.go b/pkg/helm/chartOption.go index 6b15474..ba9acc0 100644 --- a/pkg/helm/chartOption.go +++ b/pkg/helm/chartOption.go @@ -18,7 +18,6 @@ import ( "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/cli" - "helm.sh/helm/v3/pkg/repo" ) type ChartData map[Chart]map[*registry.Image][]string @@ -105,19 +104,23 @@ func determineTag(ctx context.Context, img *registry.Image, plainHTTP bool) bool } func determineSubChartPath(d *chart.Dependency, subChart *Chart, c *Chart, path string, args *Options) (string, error) { - if d.Repository == "" { - p := path - - // Check if path is archive e.g. contains '.tgz' - if strings.Contains(p, ".tgz") { - // Unpack tar - if err := chartutil.ExpandFile(cli.New().EnvVars()["HELM_CACHE_HOME"], p); err != nil { - return "", err - } - p = filepath.Join(cli.New().EnvVars()["HELM_CACHE_HOME"], c.Name) + p := path + + // Check if path is archive e.g. contains '.tgz' + if strings.Contains(p, ".tgz") { + // Unpack tar + if err := chartutil.ExpandFile(cli.New().EnvVars()["HELM_CACHE_HOME"], p); err != nil { + return "", err } + p = filepath.Join(cli.New().EnvVars()["HELM_CACHE_HOME"], c.Name) + } - return fmt.Sprintf("%s/charts/%s", p, subChart.Name), nil + switch { + case strings.HasPrefix(d.Repository, "file://"): // Helm version >2.2.0 + fallthrough + case d.Repository == "": // Embedded + s := fmt.Sprintf("%s/charts/%s", p, subChart.Name) + return s, nil } // Get Dependency Charts to local filesystem @@ -227,15 +230,7 @@ func (co ChartOption) Run(ctx context.Context, setters ...Option) (ChartData, er } // Create chart for dependency - subChart := Chart{ - Name: d.Name, - Repo: repo.Entry{ - Name: c.Repo.Name + "/" + d.Name, - URL: d.Repository, - }, - Version: d.Version, - Parent: &c, - } + subChart := DependencyToChart(d, c) // Determine path to subChart in filesystem scPath, err := determineSubChartPath(d, &subChart, &c, path, args) @@ -311,7 +306,6 @@ func (co ChartOption) Run(ctx context.Context, setters ...Option) (ChartData, er eg, egCtx := errgroup.WithContext(egCtx) for i, helmValuePaths := range imageMap { - func(i *registry.Image, helmValuePaths []string) { eg.Go(func() error {