From 4d0fe7b0792ebed5257fc4afdba06a55a4055f1c Mon Sep 17 00:00:00 2001 From: Arpit Jain Date: Mon, 3 Aug 2026 11:13:57 +0900 Subject: [PATCH] envsubst: support a negative substring length instead of panicking toSubstr parsed the length argument and then sliced s[pos : pos+length] without considering a negative length, so ${VAR:2:-1} produced a backwards slice and panicked with slice bounds out of range [2:1] The template is the manifest text, so a Kustomization using post-build substitution can take down the controller with a substitution expression alone. bash counts a negative length back from the end of the string, so ${VAR:2:-1} on "hello world" is "llo worl", and it rejects the expression when the end lands before the offset. Match that, returning an empty string for the rejected case since these helpers have no error channel. Verified against bash 5. Signed-off-by: Arpit Jain --- envsubst/funcs.go | 12 ++++++++++++ envsubst/funcs_test.go | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/envsubst/funcs.go b/envsubst/funcs.go index a9b6f3298..328cb1d24 100644 --- a/envsubst/funcs.go +++ b/envsubst/funcs.go @@ -121,6 +121,18 @@ func toSubstr(s string, args ...string) string { return s } + if length < 0 { + // a negative length counts back from the end of the string, so + // ${var:1:-1} drops the first and the last character. + end := len(s) + length + if end < pos { + // bash rejects this as a negative substring expression. + return "" + } + + return s[pos:end] + } + if pos+length >= len(s) { if pos < len(s) { // if the position exceeds the length of the diff --git a/envsubst/funcs_test.go b/envsubst/funcs_test.go index 66b05856c..fc5a30300 100644 --- a/envsubst/funcs_test.go +++ b/envsubst/funcs_test.go @@ -121,4 +121,24 @@ func Test_substr(t *testing.T) { if got != want { t.Errorf("Expect substr function to cut entire string if pos is itself out of bound") } + + got, want = toSubstr("hello world", "2", "-1"), "llo worl" + if got != want { + t.Errorf("Expect substr function to count a negative length back from the end, got %q want %q", got, want) + } + + got, want = toSubstr("hello world", "0", "-3"), "hello wo" + if got != want { + t.Errorf("Expect substr function to count a negative length back from the end at offset 0, got %q want %q", got, want) + } + + got, want = toSubstr("hello world", "8", "-8"), "" + if got != want { + t.Errorf("Expect substr function to return empty when a negative length ends before the offset, got %q want %q", got, want) + } + + got, want = toSubstr("hello world", "-4", "-1"), "orl" + if got != want { + t.Errorf("Expect substr function to combine a negative offset with a negative length, got %q want %q", got, want) + } }