diff --git a/apps/dokploy/__test__/compose/volume/volume-services.test.ts b/apps/dokploy/__test__/compose/volume/volume-services.test.ts index a42ab5fa9..8213404bb 100644 --- a/apps/dokploy/__test__/compose/volume/volume-services.test.ts +++ b/apps/dokploy/__test__/compose/volume/volume-services.test.ts @@ -42,6 +42,39 @@ test("Add suffix to volumes declared directly in services", () => { ); }); +const composeFileAccessMode = ` +version: "3.8" + +services: + web: + image: nginx:alpine + volumes: + - web_config:/etc/nginx/conf.d:ro + - certs/sub:/etc/certs:Z +`; + +test("Add suffix to volumes preserves access mode (:ro, :z, :Z)", () => { + const composeData = parse(composeFileAccessMode) as ComposeSpecification; + + const suffix = generateRandomHash(); + + if (!composeData.services) { + return; + } + + const updatedComposeData = addSuffixToVolumesInServices( + composeData.services, + suffix, + ); + + expect(updatedComposeData.web?.volumes).toContain( + `web_config-${suffix}:/etc/nginx/conf.d:ro`, + ); + expect(updatedComposeData.web?.volumes).toContain( + `certs-${suffix}/sub:/etc/certs:Z`, + ); +}); + const composeFileTypeVolume = ` version: "3.8" diff --git a/packages/server/src/utils/docker/compose/volume.ts b/packages/server/src/utils/docker/compose/volume.ts index be4c7b206..6708758cb 100644 --- a/packages/server/src/utils/docker/compose/volume.ts +++ b/packages/server/src/utils/docker/compose/volume.ts @@ -26,11 +26,14 @@ export const addSuffixToVolumesInServices = ( if (_.has(newServiceConfig, "volumes")) { newServiceConfig.volumes = _.map(newServiceConfig.volumes, (volume) => { if (_.isString(volume)) { - const [volumeName, path] = volume.split(":"); + // remainder is the container path plus optional access mode (:ro, :z, :Z) + const [volumeName, ...pathAndMode] = volume.split(":"); + const remainder = pathAndMode.join(":"); // skip bind mounts and variables (e.g. $PWD) if ( !volumeName || + !remainder || volumeName.startsWith(".") || volumeName.startsWith("/") || volumeName.startsWith("$") @@ -43,10 +46,10 @@ export const addSuffixToVolumesInServices = ( if (parts.length > 1) { const baseName = parts[0]; const rest = parts.slice(1).join("/"); - return `${baseName}-${suffix}/${rest}:${path}`; + return `${baseName}-${suffix}/${rest}:${remainder}`; } - return `${volumeName}-${suffix}:${path}`; + return `${volumeName}-${suffix}:${remainder}`; } if (_.isObject(volume) && volume.type === "volume" && volume.source) { return {