Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions charts/camunda-platform-8.10/templates/common/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ If the "overlay" values exist, they will override the "base" values, otherwise t
Usage: {{ include "camundaPlatform.imageTagByParams" (dict "base" .Values.global "overlay" .Values.console) }}
*/}}
{{- define "camundaPlatform.imageTagByParams" -}}
{{- .overlay.image.tag | default .base.image.tag -}}
{{- .overlay.image.tag | default .base.image.tag | default "" -}}
{{- end -}}

{{/*
Expand All @@ -140,11 +140,15 @@ Usage: {{ include "camundaPlatform.imageByParams" (dict "base" .Values.global "o
-}}
{{- else }}
{{- /* original tag path */ -}}
{{- $imageTag := include "camundaPlatform.imageTagByParams" (dict "base" .base "overlay" .overlay) -}}
{{- if not $imageTag -}}
{{- fail (printf "camundaPlatform.imageByParams: image %q has neither a tag nor a digest; set image.tag or image.digest" $imageRepository) -}}
{{- end -}}
{{- printf "%s%s%s:%s"
$imageRegistry
(empty $imageRegistry | ternary "" "/")
$imageRepository
(include "camundaPlatform.imageTagByParams" (dict "base" .base "overlay" .overlay))
$imageTag
-}}
{{- end }}
{{- end -}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ func (s *DeploymentTemplateTest) TestDifferentValuesInputs() {
"camundaHub.webModeler.restapi.mail.fromAddress": "example@example.com",
"global.image.pullSecrets[0].name": "SecretName",
"camundaHub.webModeler.image.pullSecrets[0].name": "SecretNameSubChart",
"camundaHub.webModeler.image.tag": "snapshot",
"global.elasticsearch.enabled": "true",
},
Verifier: func(t *testing.T, output string, err error) {
Expand All @@ -232,6 +233,19 @@ func (s *DeploymentTemplateTest) TestDifferentValuesInputs() {
// then
s.Require().Equal("SecretNameSubChart", deployment.Spec.Template.Spec.ImagePullSecrets[0].Name)
},
}, {
Name: "TestContainerImageWithoutTagOrDigestFails",
Values: map[string]string{
"identity.enabled": "true",
"webModeler.enabled": "true",
"camundaHub.webModeler.restapi.mail.fromAddress": "example@example.com",
"camundaHub.webModeler.image.repository": "camunda/custom-web-modeler",
"global.elasticsearch.enabled": "true",
},
Verifier: func(t *testing.T, output string, err error) {
s.Require().Error(err)
s.Require().Contains(err.Error(), "neither a tag nor a digest")
},
}, {
Name: "TestContainerOverwriteImageTag",
Values: map[string]string{
Expand Down
8 changes: 6 additions & 2 deletions charts/camunda-platform-8.8/templates/common/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ If the "overlay" values exist, they will override the "base" values, otherwise t
Usage: {{ include "camundaPlatform.imageTagByParams" (dict "base" .Values.global "overlay" .Values.console) }}
*/}}
{{- define "camundaPlatform.imageTagByParams" -}}
{{- .overlay.image.tag | default .base.image.tag -}}
{{- .overlay.image.tag | default .base.image.tag | default "" -}}
{{- end -}}

{{/*
Expand All @@ -104,11 +104,15 @@ Usage: {{ include "camundaPlatform.imageByParams" (dict "base" .Values.global "o
-}}
{{- else }}
{{- /* original tag path */ -}}
{{- $imageTag := include "camundaPlatform.imageTagByParams" (dict "base" .base "overlay" .overlay) -}}
{{- if not $imageTag -}}
{{- fail (printf "camundaPlatform.imageByParams: image %q has neither a tag nor a digest; set image.tag or image.digest" $imageRepository) -}}
{{- end -}}
{{- printf "%s%s%s:%s"
$imageRegistry
(empty $imageRegistry | ternary "" "/")
$imageRepository
(include "camundaPlatform.imageTagByParams" (dict "base" .base "overlay" .overlay))
$imageTag
-}}
{{- end }}
{{- end -}}
Expand Down
8 changes: 6 additions & 2 deletions charts/camunda-platform-8.9/templates/common/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ If the "overlay" values exist, they will override the "base" values, otherwise t
Usage: {{ include "camundaPlatform.imageTagByParams" (dict "base" .Values.global "overlay" .Values.console) }}
*/}}
{{- define "camundaPlatform.imageTagByParams" -}}
{{- .overlay.image.tag | default .base.image.tag -}}
{{- .overlay.image.tag | default .base.image.tag | default "" -}}
{{- end -}}

{{/*
Expand All @@ -140,11 +140,15 @@ Usage: {{ include "camundaPlatform.imageByParams" (dict "base" .Values.global "o
-}}
{{- else }}
{{- /* original tag path */ -}}
{{- $imageTag := include "camundaPlatform.imageTagByParams" (dict "base" .base "overlay" .overlay) -}}
{{- if not $imageTag -}}
{{- fail (printf "camundaPlatform.imageByParams: image %q has neither a tag nor a digest; set image.tag or image.digest" $imageRepository) -}}
{{- end -}}
{{- printf "%s%s%s:%s"
$imageRegistry
(empty $imageRegistry | ternary "" "/")
$imageRepository
(include "camundaPlatform.imageTagByParams" (dict "base" .base "overlay" .overlay))
$imageTag
-}}
{{- end }}
{{- end -}}
Expand Down
18 changes: 18 additions & 0 deletions scripts/deploy-camunda/deploy/digest_overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func neutralizeOverriddenDigests(overlayPath string, extraValues []string, tempD
// Collect the dotted image-paths overridden by --extra-values: an image block
// that sets registry/repository/tag but does not pin its own digest.
overridden := map[string]bool{}
var emptyTagOverrides []string
for _, f := range extraValues {
doc, readErr := loadValuesDoc(f)
if readErr != nil {
Expand All @@ -55,11 +56,22 @@ func neutralizeOverriddenDigests(overlayPath string, extraValues []string, tempD
if _, hasDigest := img["digest"]; hasDigest {
return // caller pinned an explicit digest — let it win via merge
}
// Present-but-empty tag with no digest: stripping the overlay digest
// would render a version-less "<repository>:" (invalid YAML). Flag it.
if tag, hasTag := img["tag"]; hasTag && isBlankScalar(tag) {
emptyTagOverrides = append(emptyTagOverrides, path)
return
Comment on lines +59 to +63
}
if img["registry"] != nil || img["repository"] != nil || img["tag"] != nil {
overridden[path] = true
}
})
}
if len(emptyTagOverrides) > 0 {
sort.Strings(emptyTagOverrides)
return "", fmt.Errorf("--extra-values image override for %v sets registry/repository with an empty tag and no digest; "+
"set image.tag or image.digest for these component(s)", emptyTagOverrides)
}
if len(overridden) == 0 {
return overlayPath, nil
}
Expand Down Expand Up @@ -96,6 +108,12 @@ func neutralizeOverriddenDigests(overlayPath string, extraValues []string, tempD
return sanitizedPath, nil
}

// isBlankScalar reports whether a YAML scalar is unset: a nil value (a bare
// "tag:" key) or an empty string ("tag: \"\"").
func isBlankScalar(v any) bool {
return v == nil || v == ""
}

// walkImageBlocks recursively walks a values document and invokes fn for every
// map node that contains an "image" sub-map, passing the dotted path of the
// component owning the image (e.g. "orchestration", "webModeler.restapi") and the
Expand Down
49 changes: 49 additions & 0 deletions scripts/deploy-camunda/deploy/digest_overlay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,55 @@ global:
}
}

// TestNeutralizeOverriddenDigestsEmptyTag verifies that an --extra-values image
// override which redirects registry/repository but leaves the tag empty (or null)
// and pins no digest fails fast with an actionable error, rather than stripping
// the overlay digest and rendering a version-less "<repository>:" image that helm
// rejects as invalid YAML.
func TestNeutralizeOverriddenDigestsEmptyTag(t *testing.T) {
tests := []struct {
name string
extraValues string
}{
{
name: "null tag",
extraValues: `
orchestration:
image:
registry: registry.camunda.cloud
repository: team-camunda/camunda
tag:
`,
},
{
name: "empty-string tag",
extraValues: `
orchestration:
image:
registry: registry.camunda.cloud
repository: team-camunda/camunda
tag: ""
`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := t.TempDir()
overlayPath := writeTempYAML(t, dir, "values-digest.yaml", digestOverlay)
extraPath := writeTempYAML(t, dir, "extra-values.yaml", tt.extraValues)

_, err := neutralizeOverriddenDigests(overlayPath, []string{extraPath}, dir)
if err == nil {
t.Fatal("expected an error for an empty-tag image override, got nil")
}
if !strings.Contains(err.Error(), "orchestration") || !strings.Contains(err.Error(), "empty tag") {
t.Fatalf("error should name the component and the empty tag, got: %v", err)
}
})
}
}

// TestNeutralizeOverriddenDigestsNoDigestInOverlay verifies that when the caller
// overrides a component whose overlay block has no digest, the overlay is
// returned unchanged (nothing to strip).
Expand Down
Loading