e24b62b6b9
Addresses findings from a high-effort review of the PRD 0070 macOS backend. Correctness: - Stamp identity_token onto MacosContainerBottlePlan after registration. git's gitconfig extraHeader and the supervise MCP --header read getattr(plan,"identity_token","") at provision time, and both reach the gateway on NO_PROXY (bypassing the egress proxy that carries the token). The plan never carried it, so /resolve fail-closed and every git fetch/push and supervise call from a macOS bottle would have been denied. Registration precedes provision(), so — unlike the run-time env — the plan can carry it. - Self-heal the orchestrator: recreate when it is not (source-current AND answering /health), not on the source-hash label alone. A container running current code but with a wedged HTTP server was left alone and polled to death, failing every launch until manual deletion. - image_digest and container_image_digest now read the same descriptor.digest field; dropped image_digest's id/tag fallback that could yield a value the container side can't produce — a permanent mismatch would have recreated the shared gateway on every launch (severing every live bottle's egress, since the replacement gets a new DHCP address). - Poll for the agent's and gateway's DHCP address instead of a fatal read right after `container run` (there is no --ip; the address can lag start). Cleanup: - One _inspect_first + _descriptor_digest behind the four inspect readers. - Shared bind_mount_spec (util) and host_db_dir (paths) replace per-module copies; _GIT_HTTP_PORT now imports git_http_backend.DEFAULT_PORT. - Drop the dead _url cache / url property and the write-only agent_proxy_url. Deferred (noted on the PR, not fixed here): the gateway image rebuilding on every launch (needs source-hash-labeled build), SQLite shared across VM guests, and the sh -lc profile-override edge — each is design-level or behavior-risk beyond a review fix. Verified: real Apple Container bring-up is green and idempotent; 1826 unit tests pass with `container` absent (CI parity), pyright clean, pylint 9.86. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
53 lines
2.0 KiB
Python
53 lines
2.0 KiB
Python
"""Foundational filesystem paths for bot-bottle.
|
|
|
|
`bot_bottle_root()` is the app data root — state, queue, audit logs,
|
|
git-gate keys, and the shared DB all live under it. It defaults to
|
|
`~/.bot-bottle` and is overridable with the **`BOT_BOTTLE_ROOT`** env var.
|
|
|
|
The env override is the single knob for redirecting the root: the test
|
|
suite points it at a throwaway dir instead of monkey-patching the function
|
|
(every module and every flat/package copy reads the same env var, so one
|
|
override covers them all), and operators can relocate the root if needed.
|
|
|
|
This module has no bot-bottle imports, so it is safe to import from any
|
|
layer (and to COPY flat into the gateway).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
# The single shared host state DB. All bot-bottle SQLite stores (supervise
|
|
# queue, audit, the orchestrator registry) co-tenant this one file — the
|
|
# TableMigrations schema_key namespaces each store's tables.
|
|
HOST_DB_FILENAME = "bot-bottle.db"
|
|
|
|
|
|
def bot_bottle_root() -> Path:
|
|
"""The app data root — `$BOT_BOTTLE_ROOT` if set, else `~/.bot-bottle`."""
|
|
override = os.environ.get("BOT_BOTTLE_ROOT")
|
|
return Path(override) if override else Path.home() / ".bot-bottle"
|
|
|
|
|
|
def host_db_path() -> Path:
|
|
"""Path to the shared host state DB, `<root>/db/bot-bottle.db`.
|
|
|
|
Kept in its own `db/` subdirectory (not directly under the root) so a
|
|
backend that can only bind-mount *directories* can share this one file
|
|
with a gateway without exposing the root's other contents (git-gate
|
|
keys, per-bottle state, ...)."""
|
|
return bot_bottle_root() / "db" / HOST_DB_FILENAME
|
|
|
|
|
|
def host_db_dir() -> Path:
|
|
"""The directory holding the shared host state DB, created if missing.
|
|
Backends bind-mount this into their gateway so the supervise daemon writes
|
|
to the one DB the orchestrator (and the operator over HTTP) reads."""
|
|
db_dir = host_db_path().parent
|
|
db_dir.mkdir(parents=True, exist_ok=True)
|
|
return db_dir
|
|
|
|
|
|
__all__ = ["HOST_DB_FILENAME", "bot_bottle_root", "host_db_path", "host_db_dir"]
|