From 34b3a18307528c2b534f4d7740769e8a466864ad Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Sun, 18 Oct 2026 12:09:42 +0200 Subject: [PATCH] fix(compose): resolve ../ bind sources in raw compose mode oldRawParser made the bind directory of a long-syntax source like ../data at {workdir}./data, next to the path that Docker Compose uses. Resolve the source with replaceLocalSource(), as the compose parsers do, so Coolify makes the directory that the container mounts. A source that resolves above / now stops the deployment before remote work. Closes #4055 --- app/Models/Application.php | 2 +- tests/Unit/RawComposeVolumePathTest.php | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/Models/Application.php b/app/Models/Application.php index 8c575eb841..02c6d0935b 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -2132,7 +2132,7 @@ class Application extends BaseModel continue; } if ($source->startsWith('.')) { - $source = str($workdir.$source->after('.')); + $source = replaceLocalSource($source, str($workdir)); } $mkdirCommand = rawComposeBindMkdirCommand($source->value()); if ($mkdirCommand !== null) { diff --git a/tests/Unit/RawComposeVolumePathTest.php b/tests/Unit/RawComposeVolumePathTest.php index 685f84d84f..ec30253f58 100644 --- a/tests/Unit/RawComposeVolumePathTest.php +++ b/tests/Unit/RawComposeVolumePathTest.php @@ -246,3 +246,14 @@ YAML); expect($application->docker_compose_raw)->toContain('appdata'); }); + +it('resolves parent directory segments in long-form bind sources before remote work', function () { + Process::fake(); + + $application = makeRawComposeApplication(rawComposeBindSource('../../../../../../outside')); + + expect(fn () => $application->oldRawParser()) + ->toThrow(Exception::class, 'resolves to a path above /'); + + Process::assertNothingRan(); +});