Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: helm charts have the potential to clobber each other and don't match repo names #2066

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3d9a4a1
feat: add support for local helm chart tarballs
Racer159 Oct 12, 2023
3174e92
chore: update package-lock.json
Racer159 Oct 12, 2023
7a563d1
Add fixes for #2062
Racer159 Oct 13, 2023
1513345
Update docs
Racer159 Oct 13, 2023
94f9461
Merge branch 'main' into 2063-local-path-tarball-and-fixes
Racer159 Oct 13, 2023
2953e46
Update golang.org/x/net to fix GHSA-4374-p667-p6c8
Racer159 Oct 13, 2023
1078169
Add chart lookup on not found error
Racer159 Oct 13, 2023
1954234
Adjust messaging slightly
Racer159 Oct 13, 2023
09de061
Fix spacing
Racer159 Oct 13, 2023
ae4d3f1
Fix chart names in deps test
Racer159 Oct 13, 2023
03fcbec
correct another test
Racer159 Oct 13, 2023
866251f
Fix update test chart name
Racer159 Oct 13, 2023
2b12016
add a timeout to the upgrade test deploy upgrade package step
Racer159 Oct 26, 2023
7d39262
Merge branch 'main' into 2063-local-path-tarball-and-fixes
Racer159 Oct 26, 2023
a481dc6
Merge branch 'main' into 2063-local-path-tarball-and-fixes
Racer159 Oct 26, 2023
2b34582
Merge branch 'main' into 2063-local-path-tarball-and-fixes
Racer159 Oct 26, 2023
327495e
Fix the upgrade tests
Racer159 Oct 27, 2023
a6b1a58
Initial refactor of Helm Chart configs
Racer159 Oct 27, 2023
144b592
Improve tests, UX and loading of values files
Racer159 Oct 27, 2023
fb4c3d2
Improve creating helm cfgs from manifests
Racer159 Oct 27, 2023
f6d59bf
Fix creating skeletons with remote charts and local values
Racer159 Oct 27, 2023
f0b9857
Add back support for cosign key paths on values files
Racer159 Oct 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/3-create-a-zarf-package/4-zarf-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -1190,7 +1190,7 @@ Must be one of:
 
<blockquote>

**Description:** The path to the chart folder
**Description:** The path to the local chart's folder or .tgz archive

| | |
| -------- | -------- |
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.16.0
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.13.0
golang.org/x/crypto v0.14.0
golang.org/x/sync v0.3.0
golang.org/x/term v0.12.0
golang.org/x/term v0.13.0
helm.sh/helm/v3 v3.12.3
k8s.io/api v0.28.2
k8s.io/apimachinery v0.28.2
Expand Down Expand Up @@ -432,9 +432,9 @@ require (
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.11.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.13.0 // indirect
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1739,8 +1739,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -1846,8 +1846,8 @@ golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -1990,8 +1990,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
Expand All @@ -2004,8 +2004,8 @@ golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
18 changes: 6 additions & 12 deletions src/cmd/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
"github.com/defenseunicorns/zarf/src/pkg/utils"

"github.com/pterm/pterm"
"oras.land/oras-go/v2/registry"

"github.com/AlecAivazis/survey/v2"
Expand Down Expand Up @@ -156,27 +155,22 @@ var packageListCmd = &cobra.Command{
message.Fatalf(errs, lang.CmdPackageListNoPackageWarn)
}

// Populate a pterm table of all the deployed packages
packageTable := pterm.TableData{
{" Package ", "Version", "Components"},
}

packageData := [][]string{}
for _, pkg := range deployedZarfPackages {
var components []string

for _, component := range pkg.DeployedComponents {
components = append(components, component.Name)
}

packageTable = append(packageTable, pterm.TableData{{
fmt.Sprintf(" %s", pkg.Name),
pkg.Data.Metadata.Version,
fmt.Sprintf("%v", components),
}}...)
packageData = append(packageData, []string{
pkg.Name, pkg.Data.Metadata.Version, fmt.Sprintf("%v", components),
})
}

// Print out the table for the user
_ = pterm.DefaultTable.WithHasHeader().WithData(packageTable).Render()
header := []string{"Package ", "Version", "Components"}
message.Table(header, packageData)

// Print out any unmarshalling errors
if len(errs) > 0 {
Expand Down
135 changes: 109 additions & 26 deletions src/internal/packager/helm/repo.go
Racer159 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ import (
"github.com/defenseunicorns/zarf/src/internal/packager/git"
"github.com/defenseunicorns/zarf/src/pkg/message"
"github.com/defenseunicorns/zarf/src/pkg/transform"
"github.com/defenseunicorns/zarf/src/pkg/utils"
"github.com/defenseunicorns/zarf/src/types"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/helmpath"
"helm.sh/helm/v3/pkg/registry"
"k8s.io/client-go/util/homedir"

Expand All @@ -43,18 +46,20 @@ func (h *Helm) PackageChart(destination string) error {
}

_, err = h.PackageChartFromGit(destination)

if err != nil {
return fmt.Errorf("error creating chart archive, unable to pull the chart from git: %s", err.Error())
return fmt.Errorf("unable to pull the chart %q from git: %w", h.Chart.Name, err)
}
} else {
h.DownloadPublishedChart(destination)
err = h.DownloadPublishedChart(destination)
if err != nil {
return fmt.Errorf("unable to download the published chart %q: %w", h.Chart.Name, err)
}
}

} else {
_, err := h.PackageChartFromLocalFiles(destination)
if err != nil {
return fmt.Errorf("error creating chart archive, unable to package the chart: %s", err.Error())
return fmt.Errorf("unable to package the %q chart: %w", h.Chart.Name, err)
}
}
return nil
Expand All @@ -65,27 +70,29 @@ func (h *Helm) PackageChartFromLocalFiles(destination string) (string, error) {
spinner := message.NewProgressSpinner("Processing helm chart %s:%s from %s", h.Chart.Name, h.Chart.Version, h.Chart.LocalPath)
defer spinner.Stop()

// Validate the chart
_, err := loader.LoadDir(h.Chart.LocalPath)
cl, _, err := h.loadAndValidateChart(h.Chart.LocalPath)
if err != nil {
spinner.Errorf(err, "Validation failed for chart from %s (%s)", h.Chart.LocalPath, err.Error())
return "", err
}

err = h.buildChartDependencies(spinner)
if err != nil {
spinner.Errorf(err, "Unable to build dependencies for the chart: %s", err.Error())
return "", err
}
var path string
if _, ok := cl.(loader.DirLoader); ok {
err = h.buildChartDependencies(spinner)
if err != nil {
return "", fmt.Errorf("unable to build dependencies for the chart: %w", err)
}

client := action.NewPackage()
client := action.NewPackage()

client.Destination = destination
path, err := client.Run(h.Chart.LocalPath, nil)
client.Destination = destination
path, err = client.Run(h.Chart.LocalPath, nil)
} else {
path = filepath.Join(destination, filepath.Base(h.Chart.LocalPath))
err = utils.CreatePathAndCopy(h.Chart.LocalPath, path)
}

if err != nil {
spinner.Errorf(err, "Helm is unable to save the archive and create the package %s", path)
return "", err
return "", fmt.Errorf("unable to save the archive and create the package %s: %w", path, err)
}

spinner.Success()
Expand All @@ -111,7 +118,7 @@ func (h *Helm) PackageChartFromGit(destination string) (string, error) {
}

// DownloadPublishedChart loads a specific chart version from a remote repo.
func (h *Helm) DownloadPublishedChart(destination string) {
func (h *Helm) DownloadPublishedChart(destination string) error {
spinner := message.NewProgressSpinner("Processing helm chart %s:%s from repo %s", h.Chart.Name, h.Chart.Version, h.Chart.URL)
defer spinner.Stop()

Expand All @@ -129,7 +136,7 @@ func (h *Helm) DownloadPublishedChart(destination string) {
if registry.IsOCI(h.Chart.URL) {
regClient, err = registry.NewClient(registry.ClientOptEnableCache(true))
if err != nil {
spinner.Fatalf(err, "Unable to create a new registry client")
return fmt.Errorf("unable to create a new registry client: %w", err)
}
chartURL = h.Chart.URL
// Explicitly set the pull version for OCI
Expand All @@ -138,7 +145,11 @@ func (h *Helm) DownloadPublishedChart(destination string) {
// Perform simple chart download
chartURL, err = repo.FindChartInRepoURL(h.Chart.URL, h.Chart.Name, h.Chart.Version, pull.CertFile, pull.KeyFile, pull.CaFile, getter.All(pull.Settings))
if err != nil {
spinner.Fatalf(err, "Unable to pull the helm chart")
if strings.Contains(err.Error(), "not found") {
// Intentionally dogsled this error since this is a nice to have helper
_ = h.listAvailableChartsAndVersions(pull)
}
return fmt.Errorf("unable to pull the helm chart: %w", err)
}
}

Expand All @@ -157,23 +168,25 @@ func (h *Helm) DownloadPublishedChart(destination string) {
// Download the file (we don't control what name helm creates here)
saved, _, err := chartDownloader.DownloadTo(chartURL, pull.Version, destination)
if err != nil {
spinner.Fatalf(err, "Unable to download the helm chart")
return fmt.Errorf("unable to download the helm chart: %w", err)
}

// Validate the chart
_, err = loader.LoadFile(saved)
_, _, err = h.loadAndValidateChart(saved)
if err != nil {
spinner.Fatalf(err, "Validation failed for chart %s (%s)", h.Chart.Name, err.Error())
return err
}

// Ensure the name is consistent for deployments
destinationTarball := StandardName(destination, h.Chart) + ".tgz"
err = os.Rename(saved, destinationTarball)
if err != nil {
spinner.Fatalf(err, "Unable to save the chart tarball")
return fmt.Errorf("unable to save the chart tarball: %w", err)
}

spinner.Success()

return nil
}

// DownloadChartFromGitToTemp downloads a chart from git into a temp directory
Expand All @@ -184,8 +197,7 @@ func (h *Helm) DownloadChartFromGitToTemp(spinner *message.Spinner) (string, err
// Download the git repo to a temporary directory
err := gitCfg.DownloadRepoToTemp(h.Chart.URL)
if err != nil {
spinner.Errorf(err, "Unable to download the git repo %s", h.Chart.URL)
return "", err
return "", fmt.Errorf("unable to download the git repo %s: %w", h.Chart.URL, err)
}

return gitCfg.GitPath, nil
Expand Down Expand Up @@ -234,3 +246,74 @@ func (h *Helm) buildChartDependencies(spinner *message.Spinner) error {

return nil
}

func (h *Helm) loadAndValidateChart(location string) (loader.ChartLoader, *chart.Chart, error) {
// Validate the chart
cl, err := loader.Loader(location)
if err != nil {
return cl, nil, fmt.Errorf("unable to load the chart from %s: %w", location, err)
}

chart, err := cl.Load()
if err != nil {
return cl, chart, fmt.Errorf("validation failed for chart from %s: %w", location, err)
}

// Check that the chart name matches
if h.Chart.Name != chart.Name() {
return cl, chart, fmt.Errorf("invalid chart name provided, %q does not match %q", h.Chart.Name, chart.Name())
}

return cl, chart, nil
}

func (h *Helm) listAvailableChartsAndVersions(pull *action.Pull) error {
c := repo.Entry{
URL: h.Chart.URL,
CertFile: pull.CertFile,
KeyFile: pull.KeyFile,
CAFile: pull.CaFile,
Name: h.Chart.Name,
}

r, err := repo.NewChartRepository(&c, getter.All(pull.Settings))
if err != nil {
return err
}
idx, err := r.DownloadIndexFile()
if err != nil {
return fmt.Errorf("looks like %q is not a valid chart repository or cannot be reached: %w", h.Chart.URL, err)
}
defer func() {
os.RemoveAll(filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name)))
os.RemoveAll(filepath.Join(r.CachePath, helmpath.CacheIndexFile(r.Config.Name)))
}()

// Read the index file for the repository to get chart information and return chart URL
repoIndex, err := repo.LoadIndexFile(idx)
if err != nil {
return err
}

chartData := [][]string{}
for name, entries := range repoIndex.Entries {
versions := ""
for idx, entry := range entries {
separator := ""
if idx < len(entries)-1 {
separator = ", "
}
versions += entry.Version + separator
}

versions = message.Truncate(versions, 75, false)
chartData = append(chartData, []string{name, versions})
}

message.Notef("Available charts and versions from %q:", h.Chart.URL)

// Print out the table for the user
header := []string{"Chart", "Versions"}
message.Table(header, chartData)
return nil
}
10 changes: 5 additions & 5 deletions src/pkg/message/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import (
"fmt"

"github.com/defenseunicorns/zarf/src/types"
"github.com/pterm/pterm"
)

// PrintConnectStringTable prints a table of connect strings.
func PrintConnectStringTable(connectStrings types.ConnectStrings) {
Debugf("message.PrintConnectStringTable(%#v)", connectStrings)

if len(connectStrings) > 0 {
list := pterm.TableData{{" Connect Command", "Description"}}
connectData := [][]string{}
// Loop over each connectStrings and convert to pterm.TableData
for name, connect := range connectStrings {
name = fmt.Sprintf(" zarf connect %s", name)
list = append(list, []string{name, connect.Description})
name = fmt.Sprintf("zarf connect %s", name)
connectData = append(connectData, []string{name, connect.Description})
}

// Create the table output with the data
_ = pterm.DefaultTable.WithHasHeader().WithData(list).Render()
header := []string{"Connect Command", "Description"}
Table(header, connectData)
}
}
Loading