From 70f152f0ba3bff270b06df3399ae94bb46c54d41 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 16 Oct 2025 08:51:15 +0200 Subject: [PATCH] Changes auto-committed by Conductor --- bootstrap/helpers/docker.php | 10 +++ bootstrap/helpers/shared.php | 20 +++++ tests/Unit/DockerComposeLabelParsingTest.php | 79 ++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 tests/Unit/DockerComposeLabelParsingTest.php diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 5f87260d1..d6c9b5bdf 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -378,6 +378,16 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_ if ($serviceLabels) { $middlewares_from_labels = $serviceLabels->map(function ($item) { + // Handle array values from YAML parsing (e.g., "traefik.enable: true" becomes an array) + if (is_array($item)) { + // Convert array to string format "key=value" + $key = collect($item)->keys()->first(); + $value = collect($item)->values()->first(); + $item = "$key=$value"; + } + if (! is_string($item)) { + return null; + } if (preg_match('/traefik\.http\.middlewares\.(.*?)(\.|$)/', $item, $matches)) { return $matches[1]; } diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 308f522fb..35ee54fcf 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -1285,6 +1285,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if ($serviceLabels->count() > 0) { $removedLabels = collect([]); $serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) { + // Handle array values from YAML (e.g., "traefik.enable: true" becomes an array) + if (is_array($serviceLabel)) { + $removedLabels->put($serviceLabelName, $serviceLabel); + + return false; + } if (! str($serviceLabel)->contains('=')) { $removedLabels->put($serviceLabelName, $serviceLabel); @@ -1294,6 +1300,10 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal return $serviceLabel; }); foreach ($removedLabels as $removedLabelName => $removedLabel) { + // Convert array values to strings + if (is_array($removedLabel)) { + $removedLabel = (string) collect($removedLabel)->first(); + } $serviceLabels->push("$removedLabelName=$removedLabel"); } } @@ -2005,6 +2015,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if ($serviceLabels->count() > 0) { $removedLabels = collect([]); $serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) { + // Handle array values from YAML (e.g., "traefik.enable: true" becomes an array) + if (is_array($serviceLabel)) { + $removedLabels->put($serviceLabelName, $serviceLabel); + + return false; + } if (! str($serviceLabel)->contains('=')) { $removedLabels->put($serviceLabelName, $serviceLabel); @@ -2014,6 +2030,10 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal return $serviceLabel; }); foreach ($removedLabels as $removedLabelName => $removedLabel) { + // Convert array values to strings + if (is_array($removedLabel)) { + $removedLabel = (string) collect($removedLabel)->first(); + } $serviceLabels->push("$removedLabelName=$removedLabel"); } } diff --git a/tests/Unit/DockerComposeLabelParsingTest.php b/tests/Unit/DockerComposeLabelParsingTest.php new file mode 100644 index 000000000..a2a3c0883 --- /dev/null +++ b/tests/Unit/DockerComposeLabelParsingTest.php @@ -0,0 +1,79 @@ +toContain('// Handle array values from YAML (e.g., "traefik.enable: true" becomes an array)') + ->toContain('if (is_array($serviceLabel)) {'); +}); + +it('ensures label parsing converts array values to strings', function () { + // Read the parseDockerComposeFile function from shared.php + $sharedFile = file_get_contents(__DIR__.'/../../bootstrap/helpers/shared.php'); + + // Check that array to string conversion exists + expect($sharedFile) + ->toContain('// Convert array values to strings') + ->toContain('if (is_array($removedLabel)) {') + ->toContain('$removedLabel = (string) collect($removedLabel)->first();'); +}); + +it('verifies label parsing array check occurs before preg_match', function () { + // Read the parseDockerComposeFile function from shared.php + $sharedFile = file_get_contents(__DIR__.'/../../bootstrap/helpers/shared.php'); + + // Get the position of array check and str() call + $arrayCheckPos = strpos($sharedFile, 'if (is_array($serviceLabel)) {'); + $strCallPos = strpos($sharedFile, "str(\$serviceLabel)->contains('=')"); + + // Ensure array check comes before str() call + expect($arrayCheckPos) + ->toBeLessThan($strCallPos) + ->toBeGreaterThan(0); +}); + +it('ensures traefik middleware parsing handles array values in docker.php', function () { + // Read the fqdnLabelsForTraefik function from docker.php + $dockerFile = file_get_contents(__DIR__.'/../../bootstrap/helpers/docker.php'); + + // Check that array handling is present before preg_match + expect($dockerFile) + ->toContain('// Handle array values from YAML parsing (e.g., "traefik.enable: true" becomes an array)') + ->toContain('if (is_array($item)) {'); +}); + +it('ensures traefik middleware parsing checks string type before preg_match in docker.php', function () { + // Read the fqdnLabelsForTraefik function from docker.php + $dockerFile = file_get_contents(__DIR__.'/../../bootstrap/helpers/docker.php'); + + // Check that string type check exists + expect($dockerFile) + ->toContain('if (! is_string($item)) {') + ->toContain('return null;'); +}); + +it('verifies array check occurs before preg_match in traefik middleware parsing', function () { + // Read the fqdnLabelsForTraefik function from docker.php + $dockerFile = file_get_contents(__DIR__.'/../../bootstrap/helpers/docker.php'); + + // Get the position of array check and preg_match call + $arrayCheckPos = strpos($dockerFile, 'if (is_array($item)) {'); + $pregMatchPos = strpos($dockerFile, "preg_match('/traefik\\.http\\.middlewares\\.(.*?)(\\.|$)/', \$item"); + + // Ensure array check comes before preg_match call (find first occurrence after array check) + $pregMatchAfterArrayCheck = strpos($dockerFile, "preg_match('/traefik\\.http\\.middlewares\\.(.*?)(\\.|$)/', \$item", $arrayCheckPos); + expect($arrayCheckPos) + ->toBeLessThan($pregMatchAfterArrayCheck) + ->toBeGreaterThan(0); +});