From 3e3e0916f220badc7b97c48218e2100520e6f442 Mon Sep 17 00:00:00 2001 From: MacRimi <123239993+MacRimi@users.noreply.github.com> Date: Mon, 19 Oct 2026 17:06:49 +0200 Subject: [PATCH] fix(oci): clean format directories of a running container - Open the container root without O_NOFOLLOW, as /proc//root is a link - Keep the /config preparation of JDownloader in its overlay --- oci/catalog/overlays/jdownloader.json | 5 +++++ oci/remote/oci_managed_volumes.py | 3 ++- oci/tests/test_managed_volume_startup.py | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/oci/catalog/overlays/jdownloader.json b/oci/catalog/overlays/jdownloader.json index 8125de69..e8007e6d 100644 --- a/oci/catalog/overlays/jdownloader.json +++ b/oci/catalog/overlays/jdownloader.json @@ -2,6 +2,11 @@ "proxmox": { "installer_profile": { "volume_preparations": [ + { + "container_path": "/config", + "remove_lost_found": true, + "owner_strategy": "mapped-root" + }, { "container_path": "/output", "remove_lost_found": true, diff --git a/oci/remote/oci_managed_volumes.py b/oci/remote/oci_managed_volumes.py index a0068939..575d16aa 100644 --- a/oci/remote/oci_managed_volumes.py +++ b/oci/remote/oci_managed_volumes.py @@ -84,7 +84,8 @@ def remove_empty_format_directories(rootfs, deployment, backed_only=True, target if not paths: return 0 flags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW - root = os.open(rootfs, flags) + # A running container is reached through /proc//root, a link. + root = os.open(rootfs, os.O_RDONLY | os.O_DIRECTORY) removed = 0 try: for path in paths: diff --git a/oci/tests/test_managed_volume_startup.py b/oci/tests/test_managed_volume_startup.py index e2a4ef8d..17df7d1b 100644 --- a/oci/tests/test_managed_volume_startup.py +++ b/oci/tests/test_managed_volume_startup.py @@ -91,6 +91,16 @@ class FormatDirectoryTests(unittest.TestCase): self.assertEqual((root / 'config/keep').read_bytes(), b'application data') self.assertEqual(deployment, before) + def test_running_container_root_reached_through_a_link_is_cleaned(self): + with tempfile.TemporaryDirectory() as tmp: + base = Path(tmp); real = base / 'rootfs'; real.mkdir() + lost, deployment = self.fixture(real) + proc_root = base / 'root'; proc_root.symlink_to(real, target_is_directory=True) + with ext4_metadata(): + self.assertEqual(volumes.remove_empty_format_directories(proc_root, deployment), 1) + self.assertFalse(lost.exists()) + self.assertEqual((real / 'config/keep').read_bytes(), b'application data') + def test_nonempty_format_directory_has_no_remove_call(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp); lost, deployment = self.fixture(root)