fix(chart): lock digest differs when dependency build with Helm 2 and then Helm 3 (#7261)

* Fix issue with apiVersion v1 lock digest

When apiVersion v1 chart dependencies are built with Helm 2
and then built with Helm 3, the lock digests differ. To avoid
this issue, a depdendency update is forced.

Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com>

* Check against Helm v2 hash

Handle scenario where dependency hash was generated by Helm v2
but need to do a dependency build with Helm v3.

Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com>

* Add unit test

Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com>

* Refactor unit test

Refactor unit test to use an existing chart as dependency

Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com>

* Update after review

Comments:
- https://github.com/helm/helm/pull/7261#discussion_r373827088
- https://github.com/helm/helm/pull/7261#discussion_r373827250

Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com>
pull/7531/head
Martin Hickey 5 years ago committed by GitHub
parent 7ce29e12fa
commit 5ec70ab27f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -100,3 +100,16 @@ func TestDependencyBuildCmd(t *testing.T) {
t.Errorf("mismatched versions. Expected %q, got %q", "0.1.0", v)
}
}
func TestDependencyBuildCmdWithHelmV2Hash(t *testing.T) {
chartName := "testdata/testcharts/issue-7233"
cmd := fmt.Sprintf("dependency build '%s'", chartName)
_, out, err := executeActionCommand(cmd)
// Want to make sure the build can verify Helm v2 hash
if err != nil {
t.Logf("Output: %s", out)
t.Fatal(err)
}
}

@ -0,0 +1,22 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

@ -0,0 +1,5 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: issue-7233
version: 0.1.0

@ -0,0 +1,6 @@
dependencies:
- name: alpine
repository: file://../alpine
version: 0.1.0
digest: sha256:7b380b1a826e7be1eecb089f66209d6d3df54be4bf879d4a8e6f8a9e871710e5
generated: "2020-01-31T11:30:21.911547651Z"

@ -0,0 +1,4 @@
dependencies:
- name: alpine
version: 0.1.0
repository: file://../alpine

@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favoriteDrink }}

@ -0,0 +1 @@
favoriteDrink: coffee

@ -157,6 +157,22 @@ func HashReq(req, lock []*chart.Dependency) (string, error) {
return "sha256:" + s, err
}
// HashV2Req generates a hash of requirements generated in Helm v2.
//
// This should be used only to compare against another hash generated by the
// Helm v2 hash function. It is to handle issue:
// https://github.com/helm/helm/issues/7233
func HashV2Req(req []*chart.Dependency) (string, error) {
dep := make(map[string][]*chart.Dependency)
dep["dependencies"] = req
data, err := json.Marshal(dep)
if err != nil {
return "", err
}
s, err := provenance.Digest(bytes.NewBuffer(data))
return "sha256:" + s, err
}
// GetLocalPath generates absolute local path when use
// "file://" in repository of dependencies
func GetLocalPath(repo, chartpath string) (string, error) {

@ -19,6 +19,7 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"net/url"
"os"
"path"
@ -86,7 +87,17 @@ func (m *Manager) Build() error {
}
if sum, err := resolver.HashReq(req, lock.Dependencies); err != nil || sum != lock.Digest {
return errors.New("Chart.lock is out of sync with Chart.yaml")
// If lock digest differs and chart is apiVersion v1, it maybe because the lock was built
// with Helm 2 and therefore should be checked with Helm v2 hash
// Fix for: https://github.com/helm/helm/issues/7233
if c.Metadata.APIVersion == chart.APIVersionV1 {
log.Println("warning: a valid Helm v3 hash was not found. Checking against Helm v2 hash...")
if sum, err := resolver.HashV2Req(req); err != nil || sum != lock.Digest {
return errors.New("the lock file (requirements.lock) is out of sync with the dependencies file (requirements.yaml). Please update the dependencies")
}
} else {
return errors.New("the lock file (Chart.lock) is out of sync with the dependencies file (Chart.yaml). Please update the dependencies")
}
}
// Check that all of the repos we're dependent on actually exist.

Loading…
Cancel
Save