Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package melange for openSUSE:Factory checked 
in at 2026-03-09 16:18:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/melange (Old)
 and      /work/SRC/openSUSE:Factory/.melange.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "melange"

Mon Mar  9 16:18:46 2026 rev:143 rq:1337571 version:0.43.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/melange/melange.changes  2026-03-05 
17:30:18.868359109 +0100
+++ /work/SRC/openSUSE:Factory/.melange.new.8177/melange.changes        
2026-03-09 16:23:42.367575368 +0100
@@ -1,0 +2,18 @@
+Mon Mar 09 07:02:45 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 0.43.7:
+  * build(deps): bump step-security/harden-runner from 2.15.0 to
+    2.15.1 in the actions group (#2402)
+  * build(deps): bump github.com/docker/cli from
+    29.2.1+incompatible to 29.3.0+incompatible in the gomod group
+    (#2401)
+  * Replace goparsify with recursive descent parser (#2399)
+  * Re-enable "set -u" in git-checkout, AFTER adding a test for it
+    (#2398)
+  * Remove erroneous variable quoting (#2397)
+  * build(deps): bump docker/setup-docker-action from 4.7.0 to
+    5.0.0 (#2393)
+  * build(deps): bump the gomod group across 1 directory with 4
+    updates (#2396)
+
+-------------------------------------------------------------------

Old:
----
  melange-0.43.6.obscpio

New:
----
  melange-0.43.7.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ melange.spec ++++++
--- /var/tmp/diff_new_pack.QDU2vs/_old  2026-03-09 16:23:44.727672212 +0100
+++ /var/tmp/diff_new_pack.QDU2vs/_new  2026-03-09 16:23:44.727672212 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           melange
-Version:        0.43.6
+Version:        0.43.7
 Release:        0
 Summary:        Build APKs from source code
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.QDU2vs/_old  2026-03-09 16:23:44.771674018 +0100
+++ /var/tmp/diff_new_pack.QDU2vs/_new  2026-03-09 16:23:44.775674182 +0100
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/chainguard-dev/melange</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v0.43.6</param>
+    <param name="revision">v0.43.7</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.QDU2vs/_old  2026-03-09 16:23:44.803675331 +0100
+++ /var/tmp/diff_new_pack.QDU2vs/_new  2026-03-09 16:23:44.807675495 +0100
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/chainguard-dev/melange</param>
-              <param 
name="changesrevision">44654e54749503cf5425d09c4460170bf6801575</param></service></servicedata>
+              <param 
name="changesrevision">d8dfccb7dcd1156156ea3d11d08c541a7c3c5068</param></service></servicedata>
 (No newline at EOF)
 

++++++ melange-0.43.6.obscpio -> melange-0.43.7.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.43.6/go.mod new/melange-0.43.7/go.mod
--- old/melange-0.43.6/go.mod   2026-03-04 12:01:24.000000000 +0100
+++ new/melange-0.43.7/go.mod   2026-03-08 16:25:37.000000000 +0100
@@ -8,15 +8,14 @@
        github.com/chainguard-dev/go-pkgconfig 
v0.0.0-20240404163941-6351b37b2a10
        github.com/chainguard-dev/yam v0.2.51
        github.com/charmbracelet/log v0.4.2
-       github.com/docker/cli v29.2.1+incompatible
+       github.com/docker/cli v29.3.0+incompatible
        github.com/docker/docker v28.5.2+incompatible
        github.com/dprotaso/go-yit v0.0.0-20250513224043-18a80f8f6df4
        github.com/github/go-spdx/v2 v2.4.0
        github.com/go-git/go-git/v5 v5.17.0
        github.com/google/go-cmp v0.7.0
-       github.com/google/go-containerregistry v0.21.1
+       github.com/google/go-containerregistry v0.21.2
        github.com/google/licenseclassifier/v2 v2.0.0
-       github.com/ijt/goparsify v0.0.0-20221203142333-3a5276334b8d
        github.com/in-toto/attestation v1.1.2
        github.com/invopop/jsonschema v0.13.0
        github.com/joho/godotenv v1.5.1
@@ -34,9 +33,9 @@
        github.com/ulikunitz/xz v0.5.15
        github.com/yookoala/realpath v1.0.0
        github.com/zealic/xignore v0.3.3
-       go.opentelemetry.io/otel v1.40.0
-       go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0
-       go.opentelemetry.io/otel/sdk v1.40.0
+       go.opentelemetry.io/otel v1.41.0
+       go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.41.0
+       go.opentelemetry.io/otel/sdk v1.41.0
        go.yaml.in/yaml/v2 v2.4.3
        golang.org/x/crypto v0.48.0
        golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546
@@ -61,6 +60,7 @@
        github.com/google/martian/v3 v3.3.3 // indirect
        github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus 
v1.1.0 // indirect
        github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect
+       github.com/ijt/goparsify v0.0.0-20221203142333-3a5276334b8d // indirect
        github.com/klauspost/cpuid/v2 v2.3.0 // indirect
        github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 // indirect
        go.opencensus.io v0.24.0 // indirect
@@ -164,8 +164,8 @@
        go.opentelemetry.io/auto/sdk v1.2.1 // indirect
        
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc 
v0.63.0 // indirect
        go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 
// indirect
-       go.opentelemetry.io/otel/metric v1.40.0 // indirect
-       go.opentelemetry.io/otel/trace v1.40.0 // indirect
+       go.opentelemetry.io/otel/metric v1.41.0 // indirect
+       go.opentelemetry.io/otel/trace v1.41.0 // indirect
        go.step.sm/crypto v0.76.2 // indirect
        golang.org/x/mod v0.33.0 // indirect
        golang.org/x/net v0.50.0 // indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.43.6/go.sum new/melange-0.43.7/go.sum
--- old/melange-0.43.6/go.sum   2026-03-04 12:01:24.000000000 +0100
+++ new/melange-0.43.7/go.sum   2026-03-08 16:25:37.000000000 +0100
@@ -91,8 +91,8 @@
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/distribution/reference v0.6.0 
h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
 github.com/distribution/reference v0.6.0/go.mod 
h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/docker/cli v29.2.1+incompatible 
h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg=
-github.com/docker/cli v29.2.1+incompatible/go.mod 
h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v29.3.0+incompatible 
h1:z3iWveU7h19Pqx7alZES8j+IeFQZ1lhTwb2F+V9SVvk=
+github.com/docker/cli v29.3.0+incompatible/go.mod 
h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v2.8.3+incompatible 
h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
 github.com/docker/distribution v2.8.3+incompatible/go.mod 
h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/docker v28.5.2+incompatible 
h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
@@ -171,8 +171,8 @@
 github.com/google/go-cmp v0.5.9/go.mod 
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
 github.com/google/go-cmp v0.7.0/go.mod 
h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/google/go-containerregistry v0.21.1 
h1:sOt/o9BS2b87FnR7wxXPvRKU1XVJn2QCwOS5g8zQXlc=
-github.com/google/go-containerregistry v0.21.1/go.mod 
h1:ctO5aCaewH4AK1AumSF5DPW+0+R+d2FmylMJdp5G7p0=
+github.com/google/go-containerregistry v0.21.2 
h1:vYaMU4nU55JJGFC9JR/s8NZcTjbE9DBBbvusTW9NeS0=
+github.com/google/go-containerregistry v0.21.2/go.mod 
h1:ctO5aCaewH4AK1AumSF5DPW+0+R+d2FmylMJdp5G7p0=
 github.com/google/go-licenses/v2 v2.0.1 
h1:ti+9bi5o7DKbeeg5eBb/uZTgsaPNoJaLCh93cRcXsW8=
 github.com/google/go-licenses/v2 v2.0.1/go.mod 
h1:efibo0EDNGkau6AIMOViGW+rTNPudhxX9rCxtfw5zKE=
 github.com/google/go-replayers/httpreplay v1.2.0 
h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk=
@@ -366,22 +366,22 @@
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc 
v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 
h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod 
h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
-go.opentelemetry.io/otel v1.40.0 
h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
-go.opentelemetry.io/otel v1.40.0/go.mod 
h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
+go.opentelemetry.io/otel v1.41.0 
h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
+go.opentelemetry.io/otel v1.41.0/go.mod 
h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 
h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod 
h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 
h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod 
h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0 
h1:MzfofMZN8ulNqobCmCAVbqVL5syHw+eB2qPRkCMA/fQ=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0/go.mod 
h1:E73G9UFtKRXrxhBsHtG00TB5WxX57lpsQzogDkqBTz8=
-go.opentelemetry.io/otel/metric v1.40.0 
h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
-go.opentelemetry.io/otel/metric v1.40.0/go.mod 
h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
-go.opentelemetry.io/otel/sdk v1.40.0 
h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
-go.opentelemetry.io/otel/sdk v1.40.0/go.mod 
h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
-go.opentelemetry.io/otel/sdk/metric v1.40.0 
h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
-go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod 
h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
-go.opentelemetry.io/otel/trace v1.40.0 
h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
-go.opentelemetry.io/otel/trace v1.40.0/go.mod 
h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.41.0 
h1:61oRQmYGMW7pXmFjPg1Muy84ndqMxQ6SH2L8fBG8fSY=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.41.0/go.mod 
h1:c0z2ubK4RQL+kSDuuFu9WnuXimObon3IiKjJf4NACvU=
+go.opentelemetry.io/otel/metric v1.41.0 
h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
+go.opentelemetry.io/otel/metric v1.41.0/go.mod 
h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
+go.opentelemetry.io/otel/sdk v1.41.0 
h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8=
+go.opentelemetry.io/otel/sdk v1.41.0/go.mod 
h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90=
+go.opentelemetry.io/otel/sdk/metric v1.41.0 
h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8=
+go.opentelemetry.io/otel/sdk/metric v1.41.0/go.mod 
h1:HNBuSvT7ROaGtGI50ArdRLUnvRTRGniSUZbxiWxSO8Y=
+go.opentelemetry.io/otel/trace v1.41.0 
h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
+go.opentelemetry.io/otel/trace v1.41.0/go.mod 
h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
 go.opentelemetry.io/proto/otlp v1.7.1 
h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
 go.opentelemetry.io/proto/otlp v1.7.1/go.mod 
h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
 go.step.sm/crypto v0.76.2 h1:JJ/yMcs/rmcCAwlo+afrHjq74XBFRTJw5B2y4Q4Z4c4=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.43.6/pkg/build/build_integration_test.go 
new/melange-0.43.7/pkg/build/build_integration_test.go
--- old/melange-0.43.6/pkg/build/build_integration_test.go      2026-03-04 
12:01:24.000000000 +0100
+++ new/melange-0.43.7/pkg/build/build_integration_test.go      2026-03-08 
16:25:37.000000000 +0100
@@ -40,6 +40,10 @@
                        expectedVersion: "1.0.0_b6",
                        buildErrMatch:   regexp.MustCompile("parse version"),
                },
+               {
+                       name:            "sed",
+                       expectedVersion: "4.9-r8",
+               },
        }
 
        const arch = "x86_64"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.43.6/pkg/build/pipelines/git-checkout.yaml 
new/melange-0.43.7/pkg/build/pipelines/git-checkout.yaml
--- old/melange-0.43.6/pkg/build/pipelines/git-checkout.yaml    2026-03-04 
12:01:24.000000000 +0100
+++ new/melange-0.43.7/pkg/build/pipelines/git-checkout.yaml    2026-03-08 
16:25:37.000000000 +0100
@@ -94,7 +94,7 @@
   - runs: |
       #!/bin/sh
       # shellcheck shell=busybox
-      set -e
+      set -eu
 
       msg() { echo "[git checkout]" "$@"; }
       fail() { msg FAIL "$@"; exit 1; }
@@ -153,7 +153,7 @@
         local fetched_branches=""
         local sdate=${SOURCE_DATE_EPOCH:-0}
         if [ "$sdate" -lt 315532800 ]; then
-            msg "Setting commit date to Jan 1, 1980 (SOURCE_DATE_EPOCH found 
${SOURCE_DATE_EPOCH})"
+            msg "Setting commit date to Jan 1, 1980 (SOURCE_DATE_EPOCH found 
${SOURCE_DATE_EPOCH:-(not set)})"
             sdate=315532800
         fi
         if [ -z "$cpicksf" ]; then
@@ -177,7 +177,8 @@
             # Split the line into branch/hash and comment parts
             branch=${line%%:*}
             comment=${line#*:}
-            comment=$(set -f; echo "$comment") # Strip leading/trailing 
whitespace
+            # shellcheck disable=SC2086
+            comment=$(set -f; echo $comment) # Strip leading/trailing 
whitespace
 
             if [ -z "$comment" ]; then
                 msg "Empty comment for cherry-pick: $line"
@@ -292,7 +293,7 @@
               "--config=user.name=Melange Build" \
               "[email protected]" \
               $flags \
-              ${depthflag:+"$depthflag"} "$repo" "$workdir" ||
+              ${depthflag:+"${depthflag}"} "$repo" "$workdir" ||
               fail "git clone failed after $max_retries retries"
 
           vr cd "$workdir"
@@ -300,7 +301,8 @@
           # Configure sparse-checkout if paths were provided
           if [ -n "$sparse_paths" ]; then
               msg "Configuring sparse-checkout with paths: $sparse_paths"
-              vr git sparse-checkout set --cone "$sparse_paths" ||
+              # shellcheck disable=SC2086
+              vr git sparse-checkout set --cone $sparse_paths ||
                   fail "failed to configure sparse-checkout --filter=blob:none"
           fi
 
@@ -335,7 +337,7 @@
           # git clone --branch=X will pick the branch X if there
           # exists both a tag and a branch by that name.
           # since a tag was given, we want the tag.
-          vr git fetch $quiet $remote "${depthflag:-"$depthflag"}" --no-tags \
+          vr git fetch $quiet $remote ${depthflag:+"${depthflag}"} --no-tags \
               "+refs/tags/$tag:refs/$remote/tags/$tag"
           vr git checkout $quiet "$remote/tags/$tag"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/melange-0.43.6/pkg/build/testdata/build_configs/sed.yaml 
new/melange-0.43.7/pkg/build/testdata/build_configs/sed.yaml
--- old/melange-0.43.6/pkg/build/testdata/build_configs/sed.yaml        
1970-01-01 01:00:00.000000000 +0100
+++ new/melange-0.43.7/pkg/build/testdata/build_configs/sed.yaml        
2026-03-08 16:25:37.000000000 +0100
@@ -0,0 +1,63 @@
+package:
+  name: sed
+  version: "4.9"
+  epoch: 8 # go/wolfi-rsc/sed
+  description: "GNU stream editor"
+  copyright:
+    - license: GPL-3.0-or-later
+  resources:
+    cpu: "7"
+    memory: 7Gi
+
+environment:
+  contents:
+    packages:
+      - autoconf
+      - automake
+      - build-base
+      - busybox
+      - ca-certificates-bundle
+      - coreutils
+      - gettext-dev
+      - rsync # for gnulib translations
+      - texinfo
+      - wget # for gnulib translations
+
+pipeline:
+  - uses: git-checkout
+    with:
+      repository: https://git.savannah.gnu.org/git/sed.git
+      tag: v${{package.version}}
+      expected-commit: 7e2e575a36bc88c0f3f3d6d8083c5f5b0ed44009
+      recurse-submodules: true
+      shallow-submodules: true
+      submodule-jobs: $(nproc)
+
+  # - name: git.savannah.gnu.org is flaky
+  #   runs: git submodule set-url gnulib 
https://github.com/coreutils/gnulib.git
+
+  - runs: echo ${{package.version}} >.tarball-version
+
+  - runs: ./bootstrap
+
+  - uses: autoconf/configure
+
+  - uses: autoconf/make
+
+  - uses: autoconf/make-install
+
+  - runs: |
+      rm -f "${{targets.destdir}}"/usr/share/info/dir
+
+  - uses: strip
+
+update:
+  enabled: true
+  release-monitor:
+    identifier: 4789
+
+test:
+  pipeline:
+    - runs: |
+        sed --version
+        sed --help
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/melange-0.43.6/pkg/build/testdata/goldenfiles/sboms/sed-4.9-r8.spdx.json 
new/melange-0.43.7/pkg/build/testdata/goldenfiles/sboms/sed-4.9-r8.spdx.json
--- 
old/melange-0.43.6/pkg/build/testdata/goldenfiles/sboms/sed-4.9-r8.spdx.json    
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/melange-0.43.7/pkg/build/testdata/goldenfiles/sboms/sed-4.9-r8.spdx.json    
    2026-03-08 16:25:37.000000000 +0100
@@ -0,0 +1,102 @@
+{
+  "SPDXID": "SPDXRef-DOCUMENT",
+  "name": "apk-sed-4.9-r8",
+  "spdxVersion": "SPDX-2.3",
+  "creationInfo": {
+    "created": "0001-01-01T00:00:00Z",
+    "creators": [
+      "Tool: melange (devel)",
+      "Organization: Chainguard, Inc"
+    ],
+    "licenseListVersion": "3.22"
+  },
+  "dataLicense": "CC0-1.0",
+  "documentNamespace": 
"https://spdx.org/spdxdocs/chainguard/melange/753938d770e34672abb2696f6a4bc0fc";,
+  "documentDescribes": [
+    "SPDXRef-Package-apk-sed-4.9-r8"
+  ],
+  "packages": [
+    {
+      "SPDXID": "SPDXRef-OperatingSystem",
+      "name": "wolfi",
+      "filesAnalyzed": false,
+      "licenseConcluded": "NOASSERTION",
+      "licenseDeclared": "NOASSERTION",
+      "description": "Operating System",
+      "downloadLocation": "NOASSERTION",
+      "originator": "Organization: Wolfi",
+      "supplier": "Organization: Wolfi",
+      "primaryPackagePurpose": "OPERATING-SYSTEM"
+    },
+    {
+      "SPDXID": "SPDXRef-Package-apk-sed-4.9-r8",
+      "name": "sed",
+      "versionInfo": "4.9-r8",
+      "filesAnalyzed": false,
+      "licenseConcluded": "NOASSERTION",
+      "licenseDeclared": "GPL-3.0-or-later",
+      "downloadLocation": "NOASSERTION",
+      "originator": "Organization: Wolfi",
+      "supplier": "Organization: Wolfi",
+      "copyrightText": "NOASSERTION",
+      "primaryPackagePurpose": "APPLICATION",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceLocator": 
"pkg:apk/wolfi/[email protected]?arch=x86_64\u0026distro=wolfi",
+          "referenceType": "purl"
+        }
+      ]
+    },
+    {
+      "SPDXID": 
"SPDXRef-Package-Melange-testdata-buildC95configs-sed.yaml-c0ffee",
+      "name": "testdata/build_configs/sed.yaml",
+      "versionInfo": "c0ffee",
+      "filesAnalyzed": false,
+      "licenseConcluded": "NOASSERTION",
+      "licenseDeclared": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "originator": "Organization: Wolfi",
+      "supplier": "Organization: Wolfi",
+      "primaryPackagePurpose": "INSTALL",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceLocator": 
"pkg:github/wolfi-dev/os@c0ffee#testdata/build_configs/sed.yaml",
+          "referenceType": "purl"
+        }
+      ]
+    },
+    {
+      "SPDXID": 
"SPDXRef-Package-Source-git.savannah.gnu.org-git-sed.git-v4.9-7e2e575a36bc88c0f3f3d6d8083c5f5b0ed44009-0",
+      "name": "git/sed",
+      "versionInfo": "v4.9",
+      "filesAnalyzed": false,
+      "licenseConcluded": "NOASSERTION",
+      "licenseDeclared": "GPL-3.0-or-later",
+      "downloadLocation": 
"https://tarballs.cgr.dev/g/43acfa56015925be19247bfc05ac5dec36f9df5e86ded6e5b74b85038e00b203-7e2e575a36bc88c0f3f3d6d8083c5f5b0ed44009.tar.gz";,
+      "originator": "Organization: Wolfi",
+      "supplier": "Organization: Wolfi",
+      "primaryPackagePurpose": "SOURCE",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceLocator": 
"pkg:generic/git%[email protected]?vcs_url=git%2Bhttps:%2F%2Fgit.savannah.gnu.org%2Fgit%2Fsed.git%407e2e575a36bc88c0f3f3d6d8083c5f5b0ed44009",
+          "referenceType": "purl"
+        }
+      ]
+    }
+  ],
+  "relationships": [
+    {
+      "spdxElementId": "SPDXRef-Package-apk-sed-4.9-r8",
+      "relationshipType": "DESCRIBED_BY",
+      "relatedSpdxElement": 
"SPDXRef-Package-Melange-testdata-buildC95configs-sed.yaml-c0ffee"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-apk-sed-4.9-r8",
+      "relationshipType": "GENERATED_FROM",
+      "relatedSpdxElement": 
"SPDXRef-Package-Source-git.savannah.gnu.org-git-sed.git-v4.9-7e2e575a36bc88c0f3f3d6d8083c5f5b0ed44009-0"
+    }
+  ]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.43.6/pkg/cond/parser.go 
new/melange-0.43.7/pkg/cond/parser.go
--- old/melange-0.43.6/pkg/cond/parser.go       2026-03-04 12:01:24.000000000 
+0100
+++ new/melange-0.43.7/pkg/cond/parser.go       2026-03-08 16:25:37.000000000 
+0100
@@ -16,51 +16,198 @@
 
 import (
        "fmt"
-
-       "github.com/ijt/goparsify"
+       "strings"
 )
 
-func combineOp(n *goparsify.Result) {
-       switch n.Child[1].Token {
-       case "&&":
-               n.Result = n.Child[0].Result == true && n.Child[2].Result == 
true
-       case "||":
-               n.Result = n.Child[0].Result == true || n.Child[2].Result == 
true
-       default:
-               panic(fmt.Errorf("unrecognized op"))
+// A VariableLookupFunction designates how variables should be
+// resolved when evaluating expressions.
+type VariableLookupFunction func(key string) (string, error)
+
+// NullLookup returns an empty value for any requested variable and
+// does not return an error.  This is the default variable lookup
+// function used by Evaluate.
+func NullLookup(key string) (string, error) {
+       return "", nil
+}
+
+// parser is a simple recursive descent parser for condition expressions.
+type parser struct {
+       input    string
+       pos      int
+       lookupFn VariableLookupFunction
+}
+
+func isWhitespace(c byte) bool {
+       return c == ' ' || c == '\t' || c == '\n' || c == '\r'
+}
+
+func (p *parser) skipWhitespace() {
+       for p.pos < len(p.input) && isWhitespace(p.input[p.pos]) {
+               p.pos++
+       }
+}
+
+func (p *parser) peek(s string) bool {
+       p.skipWhitespace()
+       return p.pos+len(s) <= len(p.input) && p.input[p.pos:p.pos+len(s)] == s
+}
+
+func (p *parser) expect(s string) error {
+       p.skipWhitespace()
+       if p.pos+len(s) > len(p.input) || p.input[p.pos:p.pos+len(s)] != s {
+               return fmt.Errorf("expected %q at position %d", s, p.pos)
        }
+       p.pos += len(s)
+       return nil
 }
 
-func collapseOp(n *goparsify.Result) {
-       n.Result = true
-       for _, child := range n.Child {
-               if child.Result != true {
-                       n.Result = false
-                       return
+func isVarChar(c byte) bool {
+       return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && 
c <= '9') || c == '.' || c == '-' || c == '_'
+}
+
+// parseValue parses a string literal ('...' or "...") or a variable 
(${{...}}).
+func (p *parser) parseValue() (string, error) {
+       p.skipWhitespace()
+       if p.pos >= len(p.input) {
+               return "", fmt.Errorf("unexpected end of input at position %d", 
p.pos)
+       }
+
+       // String literal
+       if p.input[p.pos] == '\'' || p.input[p.pos] == '"' {
+               quote := p.input[p.pos]
+               p.pos++
+               var b strings.Builder
+               for p.pos < len(p.input) && p.input[p.pos] != quote {
+                       if p.input[p.pos] == '\\' && p.pos+1 < len(p.input) {
+                               p.pos++ // skip backslash
+                               switch p.input[p.pos] {
+                               case '\\', '\'', '"':
+                                       b.WriteByte(p.input[p.pos])
+                               case 'n':
+                                       b.WriteByte('\n')
+                               case 't':
+                                       b.WriteByte('\t')
+                               default:
+                                       // Preserve unknown escapes as-is.
+                                       b.WriteByte('\\')
+                                       b.WriteByte(p.input[p.pos])
+                               }
+                       } else {
+                               b.WriteByte(p.input[p.pos])
+                       }
+                       p.pos++
+               }
+               if p.pos >= len(p.input) {
+                       return "", fmt.Errorf("unterminated string literal at 
position %d", p.pos)
                }
+               p.pos++ // consume closing quote
+               return b.String(), nil
        }
+
+       // Variable: ${{name}}
+       if p.peek("${{") {
+               p.pos += 3 // consume ${{
+               p.skipWhitespace()
+               start := p.pos
+               for p.pos < len(p.input) && isVarChar(p.input[p.pos]) {
+                       p.pos++
+               }
+               if p.pos == start {
+                       return "", fmt.Errorf("empty variable name at position 
%d", p.pos)
+               }
+               name := p.input[start:p.pos]
+               p.skipWhitespace()
+               if err := p.expect("}}"); err != nil {
+                       return "", fmt.Errorf("unterminated variable reference 
%q at position %d: %w", name, start, err)
+               }
+               resolved, err := p.lookupFn(name)
+               if err != nil {
+                       return "", fmt.Errorf("error resolving variable %q at 
position %d: %w", name, start, err)
+               }
+               return resolved, nil
+       }
+
+       return "", fmt.Errorf("unexpected character %q at position %d", 
p.input[p.pos], p.pos)
 }
 
-func comparisonOp(n *goparsify.Result) {
-       switch n.Child[1].Token {
-       case "==":
-               n.Result = n.Child[0].Token == n.Child[2].Token
-       case "!=":
-               n.Result = n.Child[0].Token != n.Child[2].Token
-       default:
-               panic(fmt.Errorf("unrecognized op"))
+// parseComparison parses: value ('==' | '!=') value
+func (p *parser) parseComparison() (bool, error) {
+       lhs, err := p.parseValue()
+       if err != nil {
+               return false, err
        }
+
+       p.skipWhitespace()
+       if p.pos+2 > len(p.input) {
+               return false, fmt.Errorf("expected comparison operator at 
position %d", p.pos)
+       }
+
+       op := p.input[p.pos : p.pos+2]
+       if op != "==" && op != "!=" {
+               return false, fmt.Errorf("expected '==' or '!=' at position %d, 
got %q", p.pos, op)
+       }
+       p.pos += 2
+
+       rhs, err := p.parseValue()
+       if err != nil {
+               return false, err
+       }
+
+       if op == "==" {
+               return lhs == rhs, nil
+       }
+       return lhs != rhs, nil
 }
 
-// A VariableLookupFunction designates how variables should be
-// resolved when evaluating expressions.
-type VariableLookupFunction func(key string) (string, error)
+// parseAtom parses a grouped expression or a comparison.
+func (p *parser) parseAtom() (bool, error) {
+       p.skipWhitespace()
+       if p.pos < len(p.input) && p.input[p.pos] == '(' {
+               p.pos++ // consume '('
+               result, err := p.parseExpr()
+               if err != nil {
+                       return false, err
+               }
+               if err := p.expect(")"); err != nil {
+                       return false, fmt.Errorf("expected ')' at position %d: 
%w", p.pos, err)
+               }
+               return result, nil
+       }
+       return p.parseComparison()
+}
 
-// NullLookup returns an empty value for any requested variable and
-// does not return an error.  This is the default variable lookup
-// function used by Evaluate.
-func NullLookup(key string) (string, error) {
-       return "", nil
+// parseExpr parses atoms chained with && and ||.
+func (p *parser) parseExpr() (bool, error) {
+       result, err := p.parseAtom()
+       if err != nil {
+               return false, err
+       }
+
+       for {
+               p.skipWhitespace()
+               if p.pos+2 > len(p.input) {
+                       break
+               }
+               op := p.input[p.pos : p.pos+2]
+               if op != "&&" && op != "||" {
+                       break
+               }
+               p.pos += 2
+
+               rhs, err := p.parseAtom()
+               if err != nil {
+                       return false, err
+               }
+
+               switch op {
+               case "&&":
+                       result = result && rhs
+               case "||":
+                       result = result || rhs
+               }
+       }
+
+       return result, nil
 }
 
 // Evaluate evaluates an input expression.
@@ -76,44 +223,21 @@
                lookupFn = lookupFns[0]
        }
 
-       equal := goparsify.Exact("==")
-       unequal := goparsify.Exact("!=")
-       comps := goparsify.Any(equal, unequal)
-
-       variableName := goparsify.Chars("a-zA-Z0-9.\\-_")
-       variable := goparsify.Seq("${{", variableName, "}}").Map(func(n 
*goparsify.Result) {
-               if resolved, err := lookupFn(n.Child[1].Token); err == nil {
-                       n.Token = resolved
-                       n.Result = resolved
-               }
-       })
-
-       value := goparsify.Any(goparsify.StringLit("'\""), variable)
-       expr := goparsify.Seq(value, comps, value).Map(comparisonOp)
-
-       and := goparsify.Exact("&&")
-       or := goparsify.Exact("||")
-       chain := goparsify.Any(and, or)
-       combinedExpr := goparsify.Seq(expr, chain, expr).Map(combineOp)
-
-       exprChain := goparsify.Some(goparsify.Any(combinedExpr, expr), 
chain).Map(collapseOp)
-
-       group := goparsify.Seq("(", goparsify.Cut(), exprChain, ")").Map(func(n 
*goparsify.Result) {
-               n.Result = n.Child[2].Result
-       })
-       groupOrExpr := goparsify.Any(group, exprChain)
-       combinedGroup := goparsify.Seq(groupOrExpr, chain, 
groupOrExpr).Map(combineOp)
-
-       groupChain := goparsify.Some(goparsify.Any(combinedGroup, groupOrExpr), 
chain).Map(collapseOp)
+       p := &parser{
+               input:    inputExpr,
+               pos:      0,
+               lookupFn: lookupFn,
+       }
 
-       result, _, err := goparsify.Run(groupChain, inputExpr, 
goparsify.UnicodeWhitespace)
+       result, err := p.parseExpr()
        if err != nil {
                return false, err
        }
 
-       if rbool, ok := result.(bool); ok {
-               return rbool, nil
+       p.skipWhitespace()
+       if p.pos != len(p.input) {
+               return false, fmt.Errorf("unexpected trailing input at position 
%d: %q", p.pos, p.input[p.pos:])
        }
 
-       return false, fmt.Errorf("got non-boolean result from parser")
+       return result, nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.43.6/pkg/cond/parser_test.go 
new/melange-0.43.7/pkg/cond/parser_test.go
--- old/melange-0.43.6/pkg/cond/parser_test.go  2026-03-04 12:01:24.000000000 
+0100
+++ new/melange-0.43.7/pkg/cond/parser_test.go  2026-03-08 16:25:37.000000000 
+0100
@@ -76,6 +76,80 @@
        require.Equal(t, true, result, "${{foo.bar}} definitely equals baz")
 }
 
+func TestEvaluateUnterminatedVariable(t *testing.T) {
+       _, err := Evaluate("${{foo.bar} == 'baz'", placeholderLookup)
+       require.Error(t, err)
+       require.Contains(t, err.Error(), "unterminated variable reference")
+       require.Contains(t, err.Error(), "foo.bar")
+}
+
+func TestStringLiteralEscapes(t *testing.T) {
+       // Escaped double quote inside double-quoted string.
+       result, err := Evaluate(`"hello \"world\"" == "hello \"world\""`)
+       require.NoError(t, err)
+       require.True(t, result)
+
+       // Escaped backslash.
+       result, err = Evaluate(`"a\\b" == "a\\b"`)
+       require.NoError(t, err)
+       require.True(t, result)
+
+       // Escaped single quote inside single-quoted string.
+       result, err = Evaluate(`'it\'s' == 'it\'s'`)
+       require.NoError(t, err)
+       require.True(t, result)
+
+       // Newline and tab escapes.
+       result, err = Evaluate(`"line1\nline2" == "line1\nline2"`)
+       require.NoError(t, err)
+       require.True(t, result)
+
+       // Mismatch: escaped vs literal.
+       result, err = Evaluate(`"a\\b" == "ab"`)
+       require.NoError(t, err)
+       require.False(t, result)
+}
+
+func FuzzEvaluate(f *testing.F) {
+       // Seed with valid and interesting expressions.
+       f.Add("'foo' == 'foo'")
+       f.Add("'foo' != 'bar'")
+       f.Add("${{foo.bar}} == 'baz'")
+       f.Add("${{ foo.bar }} == 'baz'")
+       f.Add(`"hello \"world\"" == "hello \"world\""`)
+       f.Add(`"a\\b" == "a\\b"`)
+       f.Add("('a' == 'a' && 'b' == 'b') || 'c' == 'd'")
+       f.Add("${{")
+       f.Add("${{ }}")
+       f.Add("'unterminated")
+       f.Add("")
+
+       f.Fuzz(func(t *testing.T, input string) {
+               // Evaluate must never panic regardless of input.
+               Evaluate(input, func(key string) (string, error) { 
//nolint:errcheck
+                       return "x", nil
+               })
+       })
+}
+
+func FuzzSubst(f *testing.F) {
+       f.Add("Hello ${{foo.bar}}!")
+       f.Add("${{foo}} ${{bar}}")
+       f.Add("${{ foo.bar }}")
+       f.Add("no variables here")
+       f.Add("${{")
+       f.Add("${{ }}")
+       f.Add("${{foo.bar}")
+       f.Add("")
+
+       f.Fuzz(func(t *testing.T, input string) {
+               // Subst must never panic regardless of input.
+               Subst(input, func(key string) (string, error) { 
//nolint:errcheck
+                       return "x", nil
+               })
+       })
+}
+
 func TestVariableLookupWhitespace(t *testing.T) {
        result, err := Evaluate("${{ foo.bar }} == 'baz'", placeholderLookup)
        require.NoErrorf(t, err, "got error: %v", err)
@@ -84,4 +158,13 @@
        result, err = Evaluate("'baz' == ${{ foo.bar }}", placeholderLookup)
        require.NoErrorf(t, err, "got error: %v", err)
        require.Equal(t, true, result, "${{ foo.bar }} definitely equals baz")
+
+       // Tabs and newlines inside braces.
+       result, err = Evaluate("${{\tfoo.bar\t}} == 'baz'", placeholderLookup)
+       require.NoErrorf(t, err, "got error: %v", err)
+       require.Equal(t, true, result, "tabs inside variable braces should be 
accepted")
+
+       result, err = Evaluate("${{\n foo.bar \n}} == 'baz'", placeholderLookup)
+       require.NoErrorf(t, err, "got error: %v", err)
+       require.Equal(t, true, result, "newlines inside variable braces should 
be accepted")
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.43.6/pkg/cond/subst.go 
new/melange-0.43.7/pkg/cond/subst.go
--- old/melange-0.43.6/pkg/cond/subst.go        2026-03-04 12:01:24.000000000 
+0100
+++ new/melange-0.43.7/pkg/cond/subst.go        2026-03-08 16:25:37.000000000 
+0100
@@ -18,8 +18,6 @@
        "errors"
        "fmt"
        "strings"
-
-       "github.com/ijt/goparsify"
 )
 
 func Subst(inputExpr string, lookupFns ...VariableLookupFunction) (string, 
error) {
@@ -29,43 +27,64 @@
                lookupFn = lookupFns[0]
        }
 
-       whiteSpace := goparsify.Many(goparsify.Exact(" "))
-       variableName := goparsify.Chars("a-zA-Z0-9.\\-_")
-       errs := []error{}
-       variable := goparsify.Seq("${{", whiteSpace, variableName, whiteSpace, 
"}}").Map(func(n *goparsify.Result) {
-               if resolved, err := lookupFn(n.Child[2].Token); err == nil {
-                       n.Token = resolved
-                       n.Result = resolved
-               } else {
-                       errs = append(errs, err)
-                       n.Token = ""
-                       n.Result = ""
+       var b strings.Builder
+       b.Grow(len(inputExpr))
+
+       var errs []error
+       i := 0
+       for i < len(inputExpr) {
+               // Look for the next ${{ marker.
+               idx := strings.Index(inputExpr[i:], "${{")
+               if idx < 0 {
+                       // No more variables, write the rest.
+                       b.WriteString(inputExpr[i:])
+                       break
+               }
+
+               // Write text before the variable.
+               b.WriteString(inputExpr[i : i+idx])
+               i += idx + 3 // skip past ${{
+
+               // Skip whitespace inside braces.
+               for i < len(inputExpr) && isWhitespace(inputExpr[i]) {
+                       i++
+               }
+
+               // Read variable name.
+               start := i
+               for i < len(inputExpr) && isVarChar(inputExpr[i]) {
+                       i++
                }
-       })
+               name := inputExpr[start:i]
 
-       text := goparsify.Until("${{")
-       node := goparsify.Any(text, variable)
+               if name == "" {
+                       errs = append(errs, fmt.Errorf("empty variable name at 
position %d", start))
+                       continue
+               }
+
+               // Skip whitespace before }}.
+               for i < len(inputExpr) && isWhitespace(inputExpr[i]) {
+                       i++
+               }
 
-       document := goparsify.Many(node).Map(func(n *goparsify.Result) {
-               tokens := make([]string, 0, len(n.Child))
-               for _, tok := range n.Child {
-                       tokens = append(tokens, tok.Token)
+               // Expect }}.
+               if i+2 > len(inputExpr) || inputExpr[i:i+2] != "}}" {
+                       errs = append(errs, fmt.Errorf("unterminated variable 
reference %q at position %d", name, start))
+                       continue
                }
-               n.Result = strings.Join(tokens, "")
-       })
+               i += 2
 
-       result, _, err := goparsify.Run(document, inputExpr, 
goparsify.NoWhitespace)
-       if err != nil {
-               return "", fmt.Errorf("parser error: %w", err)
+               resolved, err := lookupFn(name)
+               if err != nil {
+                       errs = append(errs, err)
+               } else {
+                       b.WriteString(resolved)
+               }
        }
 
        if err := errors.Join(errs...); err != nil {
                return "", err
        }
 
-       if rstr, ok := result.(string); ok {
-               return rstr, nil
-       }
-
-       return "", fmt.Errorf("got non-string result from parser")
+       return b.String(), nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.43.6/pkg/cond/subst_test.go 
new/melange-0.43.7/pkg/cond/subst_test.go
--- old/melange-0.43.6/pkg/cond/subst_test.go   2026-03-04 12:01:24.000000000 
+0100
+++ new/melange-0.43.7/pkg/cond/subst_test.go   2026-03-08 16:25:37.000000000 
+0100
@@ -47,6 +47,15 @@
        require.Equal(t, expected, result, "result does not match expected 
result")
 }
 
+func TestSubstVarWhitespaceTabsNewlines(t *testing.T) {
+       doc := "Hello ${{\tfoo.bar\t}} ${{\nfoo.bar\n}}!"
+       expected := "Hello baz baz!"
+       result, err := Subst(doc, placeholderLookup)
+
+       require.NoErrorf(t, err, "got error: %v", err)
+       require.Equal(t, expected, result, "result does not match expected 
result")
+}
+
 func TestSubstVarUnderscore(t *testing.T) {
        doc := "Hello ${{foo.BAR_BAZ}}!"
        expected := "Hello bar-baz!"
@@ -90,6 +99,30 @@
        require.Equal(t, expected, result, "result does not match expected 
result")
 }
 
+func TestSubstMissingClosingBraces(t *testing.T) {
+       doc := "Hello ${{foo.bar}!"
+       _, err := Subst(doc, placeholderLookup)
+       require.Error(t, err)
+       require.Contains(t, err.Error(), "unterminated variable reference")
+}
+
+func TestSubstEmptyVarName(t *testing.T) {
+       doc := "Hello ${{ }}!"
+       _, err := Subst(doc, placeholderLookup)
+       require.Error(t, err)
+       require.Contains(t, err.Error(), "empty variable name")
+}
+
+func TestSubstTrailingMarker(t *testing.T) {
+       _, err := Subst("hello ${{", placeholderLookup)
+       require.Error(t, err)
+       require.Contains(t, err.Error(), "empty variable name")
+
+       _, err = Subst("hello ${{foo", placeholderLookup)
+       require.Error(t, err)
+       require.Contains(t, err.Error(), "unterminated variable reference")
+}
+
 func TestSubstVarShellFragment(t *testing.T) {
        doc := `if [ "${{inputs.expected-sha256}}" == "" ] && [ 
"${{inputs.expected-sha512}}" == "" ]; then
   printf "One of expected-sha256 or expected-sha512 is required"

++++++ melange.obsinfo ++++++
--- /var/tmp/diff_new_pack.QDU2vs/_old  2026-03-09 16:23:46.571747882 +0100
+++ /var/tmp/diff_new_pack.QDU2vs/_new  2026-03-09 16:23:46.575748047 +0100
@@ -1,5 +1,5 @@
 name: melange
-version: 0.43.6
-mtime: 1772622084
-commit: 44654e54749503cf5425d09c4460170bf6801575
+version: 0.43.7
+mtime: 1772983537
+commit: d8dfccb7dcd1156156ea3d11d08c541a7c3c5068
 

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/melange/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.melange.new.8177/vendor.tar.gz differ: char 13, 
line 1

Reply via email to