From cb97257cc5c333af3ca95c81d978df939a7bda84 Mon Sep 17 00:00:00 2001 From: Mike Henry <11765982+mikemhenry@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:35:46 -0700 Subject: [PATCH 1/5] Fix bug with traversing extracted packages when cleaning tarballs --- libmamba/src/api/clean.cpp | 17 +++++++++++---- micromamba/tests/test_clean.py | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/libmamba/src/api/clean.cpp b/libmamba/src/api/clean.cpp index 1e542ef073..e4f40132ef 100644 --- a/libmamba/src/api/clean.cpp +++ b/libmamba/src/api/clean.cpp @@ -233,21 +233,30 @@ namespace mamba ++it) { const auto& p = *it; + if (p.is_symlink()) + { + continue; + } if (p.is_directory()) { - if (is_inside_cache_metadata(p.path(), cache_root)) + const bool is_extracted_package = fs::exists( + p.path() / "info" / "index.json" + ); + if (is_inside_cache_metadata(p.path(), cache_root) + || is_extracted_package) { it.disable_recursion_pending(); } continue; } - if (!p.is_directory() + if (p.is_regular_file() && (util::ends_with(p.path().string(), ".tar.bz2") || util::ends_with(p.path().string(), ".conda"))) { + const auto size = p.file_size(); res.push_back(p.path()); - rows.push_back({ p.path().filename().string(), get_file_size(p.file_size()) }); - total_size += p.file_size(); + rows.push_back({ p.path().filename().string(), get_file_size(size) }); + total_size += size; } } std::sort( diff --git a/micromamba/tests/test_clean.py b/micromamba/tests/test_clean.py index 95e0954245..d7717f1f67 100644 --- a/micromamba/tests/test_clean.py +++ b/micromamba/tests/test_clean.py @@ -43,6 +43,44 @@ def test_clean_all_removes_nested_package_cache_entries(tmp_home, tmp_root_prefi assert not extracted.exists() +def test_clean_tarballs_does_not_enter_extracted_packages(tmp_home, tmp_root_prefix): + pkgs_dir = tmp_home / "pkgs" + os.environ["CONDA_PKGS_DIRS"] = str(pkgs_dir) + + channel_dir = pkgs_dir / "https" / "conda.anaconda.org" / "conda-forge" / "linux-64" + channel_dir.mkdir(parents=True, exist_ok=True) + + tarball = channel_dir / "ambertools-26.0-test.conda" + tarball.write_bytes(b"cached package archive") + + extracted = channel_dir / "ambertools-26.0-test" + (extracted / "info").mkdir(parents=True) + (extracted / "info" / "index.json").write_text("{}") + + payload_file = extracted / "share" / "example.conda" + payload_file.parent.mkdir(parents=True) + payload_file.write_bytes(b"package payload") + + # AmberTools ships a bin/amber.conda symlink. On conda-forge it can be + # dangling because the package does not include Amber's bundled Miniconda. + # Creating symlinks may require elevated privileges on Windows, so the + # regular payload file above provides cross-platform coverage. + dangling_symlink = None + if os.name != "nt": + dangling_symlink = extracted / "bin" / "amber.conda" + dangling_symlink.parent.mkdir() + dangling_symlink.symlink_to("../miniconda/bin/conda") + assert dangling_symlink.is_symlink() + + helpers.clean("--tarballs", "--no-rc", no_dry_run=True) + + assert not tarball.exists() + assert extracted.exists() + assert payload_file.exists() + if dangling_symlink is not None: + assert dangling_symlink.is_symlink() + + def test_clean_all_clears_all_cache_kinds(tmp_home, tmp_root_prefix): pkgs_dir = tmp_home / "pkgs" os.environ["CONDA_PKGS_DIRS"] = str(pkgs_dir) From ecd94b1bed26fff84c7d623caf2f3c2c1adf1ba4 Mon Sep 17 00:00:00 2001 From: Mike Henry <11765982+mikemhenry@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:42:03 -0700 Subject: [PATCH 2/5] fix issue with clang format --- libmamba/src/api/clean.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libmamba/src/api/clean.cpp b/libmamba/src/api/clean.cpp index e4f40132ef..9ca6cc37f1 100644 --- a/libmamba/src/api/clean.cpp +++ b/libmamba/src/api/clean.cpp @@ -239,11 +239,8 @@ namespace mamba } if (p.is_directory()) { - const bool is_extracted_package = fs::exists( - p.path() / "info" / "index.json" - ); - if (is_inside_cache_metadata(p.path(), cache_root) - || is_extracted_package) + const bool is_extracted_package = fs::exists(p.path() / "info" / "index.json"); + if (is_inside_cache_metadata(p.path(), cache_root) || is_extracted_package) { it.disable_recursion_pending(); } From 8b4628c2a0d5feefe14fbfd2d153fd7447709afe Mon Sep 17 00:00:00 2001 From: Mike Henry <11765982+mikemhenry@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:41:46 -0700 Subject: [PATCH 3/5] thanks for the feedback @jjerphan --- libmamba/src/api/clean.cpp | 11 +++-------- micromamba/tests/test_clean.py | 4 ++-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/libmamba/src/api/clean.cpp b/libmamba/src/api/clean.cpp index 9ca6cc37f1..8d29afb647 100644 --- a/libmamba/src/api/clean.cpp +++ b/libmamba/src/api/clean.cpp @@ -233,14 +233,10 @@ namespace mamba ++it) { const auto& p = *it; - if (p.is_symlink()) - { - continue; - } if (p.is_directory()) { const bool is_extracted_package = fs::exists(p.path() / "info" / "index.json"); - if (is_inside_cache_metadata(p.path(), cache_root) || is_extracted_package) + if (is_extracted_package || is_inside_cache_metadata(p.path(), cache_root)) { it.disable_recursion_pending(); } @@ -250,10 +246,9 @@ namespace mamba && (util::ends_with(p.path().string(), ".tar.bz2") || util::ends_with(p.path().string(), ".conda"))) { - const auto size = p.file_size(); res.push_back(p.path()); - rows.push_back({ p.path().filename().string(), get_file_size(size) }); - total_size += size; + rows.push_back({ p.path().filename().string(), get_file_size(p.file_size()) }); + total_size += p.file_size(); } } std::sort( diff --git a/micromamba/tests/test_clean.py b/micromamba/tests/test_clean.py index d7717f1f67..fc73524360 100644 --- a/micromamba/tests/test_clean.py +++ b/micromamba/tests/test_clean.py @@ -43,9 +43,9 @@ def test_clean_all_removes_nested_package_cache_entries(tmp_home, tmp_root_prefi assert not extracted.exists() -def test_clean_tarballs_does_not_enter_extracted_packages(tmp_home, tmp_root_prefix): +def test_clean_tarballs_does_not_enter_extracted_packages(tmp_home, tmp_root_prefix, monkeypatch): pkgs_dir = tmp_home / "pkgs" - os.environ["CONDA_PKGS_DIRS"] = str(pkgs_dir) + monkeypatch.setenv("CONDA_PKGS_DIRS", str(pkgs_dir)) channel_dir = pkgs_dir / "https" / "conda.anaconda.org" / "conda-forge" / "linux-64" channel_dir.mkdir(parents=True, exist_ok=True) From c180b62545adf551b92229c8547b80bbf8506b91 Mon Sep 17 00:00:00 2001 From: Mike Henry <11765982+mikemhenry@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:19:34 -0700 Subject: [PATCH 4/5] thanks for the feedback again @jjerphan --- libmamba/src/api/clean.cpp | 2 +- micromamba/tests/test_clean.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libmamba/src/api/clean.cpp b/libmamba/src/api/clean.cpp index 8d29afb647..d069735e50 100644 --- a/libmamba/src/api/clean.cpp +++ b/libmamba/src/api/clean.cpp @@ -242,7 +242,7 @@ namespace mamba } continue; } - if (p.is_regular_file() + if (!p.is_directory() && (util::ends_with(p.path().string(), ".tar.bz2") || util::ends_with(p.path().string(), ".conda"))) { diff --git a/micromamba/tests/test_clean.py b/micromamba/tests/test_clean.py index fc73524360..7a4396c183 100644 --- a/micromamba/tests/test_clean.py +++ b/micromamba/tests/test_clean.py @@ -66,7 +66,7 @@ def test_clean_tarballs_does_not_enter_extracted_packages(tmp_home, tmp_root_pre # Creating symlinks may require elevated privileges on Windows, so the # regular payload file above provides cross-platform coverage. dangling_symlink = None - if os.name != "nt": + if platform.system() != "Windows": dangling_symlink = extracted / "bin" / "amber.conda" dangling_symlink.parent.mkdir() dangling_symlink.symlink_to("../miniconda/bin/conda") From a0f9d5d3b5253e5a6ecdc58272091da7d94dd2ce Mon Sep 17 00:00:00 2001 From: Mike Henry <11765982+mikemhenry@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:20:28 -0700 Subject: [PATCH 5/5] forgot import --- micromamba/tests/test_clean.py | 1 + 1 file changed, 1 insertion(+) diff --git a/micromamba/tests/test_clean.py b/micromamba/tests/test_clean.py index 7a4396c183..650e361b57 100644 --- a/micromamba/tests/test_clean.py +++ b/micromamba/tests/test_clean.py @@ -1,4 +1,5 @@ import os +import platform from .helpers import * # noqa: F403 from . import helpers