From 3d450fa5952ea4f3122934654cdb2030f4687191 Mon Sep 17 00:00:00 2001 From: TastyHeadphones Date: Sun, 20 Sep 2026 01:17:01 +0000 Subject: [PATCH] compose: don't treat hyphens in :? / ? messages as defaults hardDefault ran before requiredNonEmpty and matched any "-", so a required-variable error message like "must be set - try again" was parsed as ${VAR-default} and silently succeeded. Fixes #7313 --- cli/compose/template/template.go | 16 +++++++++++----- cli/compose/template/template_test.go | 9 +++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/cli/compose/template/template.go b/cli/compose/template/template.go index 14ba09de3599..5e21e194c302 100644 --- a/cli/compose/template/template.go +++ b/cli/compose/template/template.go @@ -34,10 +34,10 @@ type regexper interface { // DefaultSubstituteFuncs contains the default SubstituteFunc used by the docker cli var DefaultSubstituteFuncs = []SubstituteFunc{ - softDefault, - hardDefault, - requiredNonEmpty, - required, + softDefault, // :- + requiredNonEmpty, // :? + required, // ? + hardDefault, // - (after ? operators so hyphens in error messages are safe) } // InvalidTemplateError is returned when a variable template is not in a valid @@ -212,8 +212,14 @@ func softDefault(substitution string, mapping Mapping) (string, bool, error) { return value, true, nil } -// Hard default (fall back if-and-only-if empty) +// Hard default (fall back if-and-only-if unset) func hardDefault(substitution string, mapping Mapping) (string, bool, error) { + // "?" / ":?" error messages may contain hyphens (e.g. "must be set - try again"). + // Those operators are handled by required/requiredNonEmpty; do not treat the + // hyphen inside the message as the default-value separator. + if strings.Contains(substitution, "?") { + return "", false, nil + } sep := "-" if !strings.Contains(substitution, sep) { return "", false, nil diff --git a/cli/compose/template/template_test.go b/cli/compose/template/template_test.go index 0b2d463ebbe8..fbf6c7a8c1d6 100644 --- a/cli/compose/template/template_test.go +++ b/cli/compose/template/template_test.go @@ -123,6 +123,15 @@ func TestMandatoryVariableErrors(t *testing.T) { template: "not ok ${UNSET_VAR?}", expectedError: "required variable UNSET_VAR is missing a value", }, + { + // Error message itself contains a hyphen; must not be treated as ${VAR-default}. + template: "not ok ${UNSET_VAR:?must be set - hyphen in this message}", + expectedError: "required variable UNSET_VAR is missing a value: must be set - hyphen in this message", + }, + { + template: "not ok ${UNSET_VAR?must be set - hyphen in this message}", + expectedError: "required variable UNSET_VAR is missing a value: must be set - hyphen in this message", + }, } for _, tc := range testCases {