From a84598617f5e82ac633c05743260c4a83b9278b9 Mon Sep 17 00:00:00 2001 From: Manfred Riem <15701806+mnriem@users.noreply.github.com> Date: Tue, 31 Mar 2026 09:48:06 -0500 Subject: [PATCH] fix: handle non-files in check_modified/uninstall, validate manifest key - check_modified() treats non-regular-files (dirs, symlinks) as modified instead of crashing with IsADirectoryError - uninstall() skips directories (adds to skipped list), only unlinks files and symlinks - load() validates stored integration key matches the requested key --- src/specify_cli/integrations/manifest.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/specify_cli/integrations/manifest.py b/src/specify_cli/integrations/manifest.py index d3ca486b2..da71a2bd4 100644 --- a/src/specify_cli/integrations/manifest.py +++ b/src/specify_cli/integrations/manifest.py @@ -119,6 +119,10 @@ class IntegrationManifest: continue if not abs_path.exists(): continue + # Treat non-regular-files (directories, symlinks) as modified + if not abs_path.is_file(): + modified.append(rel) + continue if _sha256(abs_path) != expected_hash: modified.append(rel) return modified @@ -157,6 +161,10 @@ class IntegrationManifest: continue if not path.exists(): continue + # Skip directories — manifest only tracks files + if not path.is_file() and not path.is_symlink(): + skipped.append(path) + continue if not force and _sha256(path) != expected_hash: skipped.append(path) continue @@ -234,4 +242,12 @@ class IntegrationManifest: inst.version = data.get("version", "") inst._installed_at = data.get("installed_at", "") inst._files = files + + stored_key = data.get("integration", "") + if stored_key and stored_key != key: + raise ValueError( + f"Manifest at {path} belongs to integration {stored_key!r}, " + f"not {key!r}" + ) + return inst