From 1085a2280da9ec558f4edc5eeead306bc0cc789f Mon Sep 17 00:00:00 2001 From: didericis Date: Mon, 6 Jul 2026 15:48:23 -0400 Subject: [PATCH] fix(macos_container): mount supervise db's parent dir, not the file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apple's `container run --mount type=bind` only accepts directory sources — a file source fails with "path '' is not a directory". Move the sqlite db into its own ~/.bot-bottle/db/ subdirectory so it can be bind-mounted the same way the CA/routes mounts already are, without exposing the rest of ~/.bot-bottle. Co-Authored-By: Claude Sonnet 5 --- bot_bottle/backend/macos_container/launch.py | 10 +++++++++- bot_bottle/supervise.py | 5 ++++- bot_bottle/supervise_types.py | 9 ++++++++- tests/unit/test_macos_container_launch.py | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/bot_bottle/backend/macos_container/launch.py b/bot_bottle/backend/macos_container/launch.py index 10976d9..6e9034f 100644 --- a/bot_bottle/backend/macos_container/launch.py +++ b/bot_bottle/backend/macos_container/launch.py @@ -405,7 +405,15 @@ def _sidecar_mounts( sp = plan.supervise_plan if sp is not None: - mounts.append((str(sp.db_path), DB_PATH_IN_CONTAINER, False)) + # `container run --mount type=bind` only accepts directory + # sources (a file source fails with "is not a directory") — + # mount db_path's dedicated parent dir instead of the file + # itself, same as the CA/routes mounts above. + mounts.append(( + str(sp.db_path.parent), + str(Path(DB_PATH_IN_CONTAINER).parent), + False, + )) return tuple(mounts) diff --git a/bot_bottle/supervise.py b/bot_bottle/supervise.py index e6b6343..5bcba9c 100644 --- a/bot_bottle/supervise.py +++ b/bot_bottle/supervise.py @@ -110,7 +110,10 @@ def host_db_path() -> Path: # Calls bot_bottle_root() through this module's globals so that patches # on supervise.bot_bottle_root propagate to callers going through # supervise.host_db_path(). - return bot_bottle_root() / HOST_DB_FILENAME + # + # Kept in its own "db" subdirectory (see supervise_types.host_db_path + # for why) — must stay in sync with that copy. + return bot_bottle_root() / "db" / HOST_DB_FILENAME def audit_log_path(component: str, slug: str) -> Path: diff --git a/bot_bottle/supervise_types.py b/bot_bottle/supervise_types.py index 75d9f92..80af0ae 100644 --- a/bot_bottle/supervise_types.py +++ b/bot_bottle/supervise_types.py @@ -50,7 +50,14 @@ def bot_bottle_root() -> Path: def host_db_path() -> Path: # Look up bot_bottle_root through this module's live namespace so that # monkey-patches on supervise_types.bot_bottle_root take effect. - return sys.modules[__name__].bot_bottle_root() / HOST_DB_FILENAME + # + # Lives in its own "db" subdirectory, not directly under + # bot_bottle_root(), so backends that can only bind-mount + # directories (macos_container's `container run --mount`, which + # rejects file sources with "is not a directory") can share this + # one file with a sidecar without also exposing bot_bottle_root()'s + # other contents (git-gate keys, per-bottle state, etc.). + return sys.modules[__name__].bot_bottle_root() / "db" / HOST_DB_FILENAME def _require_str(raw: dict[str, object], key: str) -> str: diff --git a/tests/unit/test_macos_container_launch.py b/tests/unit/test_macos_container_launch.py index 4d1ecb0..7dd9de7 100644 --- a/tests/unit/test_macos_container_launch.py +++ b/tests/unit/test_macos_container_launch.py @@ -139,7 +139,7 @@ class TestMacosContainerLaunchArgv(unittest.TestCase): argv, ) self.assertIn( - "type=bind,source=/state/bot-bottle.db,target=/run/supervise/bot-bottle.db", + "type=bind,source=/state,target=/run/supervise", argv, )