From 3067b067d2514ba808cd379c2f1b8c7b37e12c4d Mon Sep 17 00:00:00 2001 From: codex Date: Wed, 1 Jul 2026 19:33:43 +0000 Subject: [PATCH] fix(supervise): store queue rows in host sqlite db --- bot_bottle/backend/docker/compose.py | 8 ++ bot_bottle/backend/macos_container/launch.py | 4 +- bot_bottle/backend/smolmachines/launch.py | 4 +- bot_bottle/git_gate_render.py | 77 ++++++++++---------- bot_bottle/supervise.py | 70 +++++++++++++----- docs/prds/prd-new-sqlite-local-storage.md | 39 +++++----- tests/unit/test_compose.py | 3 + tests/unit/test_contrib_claude_provider.py | 1 + tests/unit/test_contrib_codex_provider.py | 1 + tests/unit/test_git_gate.py | 4 +- tests/unit/test_macos_container_launch.py | 9 ++- tests/unit/test_smolmachines_provision.py | 1 + tests/unit/test_supervise.py | 1 + tests/unit/test_supervise_edge.py | 2 +- tests/unit/test_supervise_server.py | 5 +- 15 files changed, 142 insertions(+), 87 deletions(-) diff --git a/bot_bottle/backend/docker/compose.py b/bot_bottle/backend/docker/compose.py index 11ebc2c..78112fc 100644 --- a/bot_bottle/backend/docker/compose.py +++ b/bot_bottle/backend/docker/compose.py @@ -34,6 +34,7 @@ from ...egress import ( from ...git_gate import GIT_GATE_HOSTNAME from ...log import die, warn from ...supervise import ( + DB_PATH_IN_CONTAINER, QUEUE_DIR_IN_CONTAINER, SUPERVISE_HOSTNAME, SUPERVISE_PORT, @@ -163,9 +164,16 @@ def _sidecar_bundle_service(plan: DockerBottlePlan) -> dict[str, Any]: if sp is not None: env += [ f"SUPERVISE_BOTTLE_SLUG={plan.slug}", + f"SUPERVISE_DB_PATH={DB_PATH_IN_CONTAINER}", f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", f"SUPERVISE_PORT={SUPERVISE_PORT}", ] + volumes.append({ + "type": "bind", + "source": str(sp.db_path), + "target": DB_PATH_IN_CONTAINER, + "read_only": False, + }) volumes.append({ "type": "bind", "source": str(sp.queue_dir), diff --git a/bot_bottle/backend/macos_container/launch.py b/bot_bottle/backend/macos_container/launch.py index e0fe254..518644a 100644 --- a/bot_bottle/backend/macos_container/launch.py +++ b/bot_bottle/backend/macos_container/launch.py @@ -33,7 +33,7 @@ from ...git_gate import ( revoke_git_gate_provisioned_keys, ) from ...log import die, info, warn -from ...supervise import QUEUE_DIR_IN_CONTAINER, SUPERVISE_PORT +from ...supervise import DB_PATH_IN_CONTAINER, QUEUE_DIR_IN_CONTAINER, SUPERVISE_PORT from ...util import expand_tilde from ..docker.egress import EGRESS_CA_IN_CONTAINER, EGRESS_PORT from ..docker.git_gate import ( @@ -379,6 +379,7 @@ def _sidecar_env_entries(plan: MacosContainerBottlePlan) -> tuple[str, ...]: if plan.supervise_plan is not None: env += [ f"SUPERVISE_BOTTLE_SLUG={plan.slug}", + f"SUPERVISE_DB_PATH={DB_PATH_IN_CONTAINER}", f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", f"SUPERVISE_PORT={SUPERVISE_PORT}", ] @@ -405,6 +406,7 @@ def _sidecar_mounts( sp = plan.supervise_plan if sp is not None: + mounts.append((str(sp.db_path), DB_PATH_IN_CONTAINER, False)) mounts.append((str(sp.queue_dir), QUEUE_DIR_IN_CONTAINER, False)) return tuple(mounts) diff --git a/bot_bottle/backend/smolmachines/launch.py b/bot_bottle/backend/smolmachines/launch.py index 483cf85..57de70b 100644 --- a/bot_bottle/backend/smolmachines/launch.py +++ b/bot_bottle/backend/smolmachines/launch.py @@ -27,7 +27,7 @@ from ...egress import ( egress_resolve_token_values, egress_sidecar_env_entries, ) -from ...supervise import QUEUE_DIR_IN_CONTAINER, SUPERVISE_PORT +from ...supervise import DB_PATH_IN_CONTAINER, QUEUE_DIR_IN_CONTAINER, SUPERVISE_PORT from ...util import expand_tilde from ..docker import util as docker_mod from ..docker.egress import ( @@ -369,9 +369,11 @@ def _bundle_launch_spec( daemons.append("supervise") env += [ f"SUPERVISE_BOTTLE_SLUG={plan.slug}", + f"SUPERVISE_DB_PATH={DB_PATH_IN_CONTAINER}", f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", f"SUPERVISE_PORT={SUPERVISE_PORT}", ] + volumes.append((str(sp.db_path), DB_PATH_IN_CONTAINER, False)) volumes.append((str(sp.queue_dir), QUEUE_DIR_IN_CONTAINER, False)) # Container ports the agent reaches from the smolvm guest — diff --git a/bot_bottle/git_gate_render.py b/bot_bottle/git_gate_render.py index 8a442b8..656f0e9 100644 --- a/bot_bottle/git_gate_render.py +++ b/bot_bottle/git_gate_render.py @@ -234,9 +234,10 @@ import hashlib import json import os import sys -import uuid from pathlib import Path +from bot_bottle import supervise as _sv + report_path = Path(sys.argv[1]) queue_dir = os.environ.get("SUPERVISE_QUEUE_DIR", "") slug = os.environ.get("SUPERVISE_BOTTLE_SLUG", "") @@ -277,31 +278,19 @@ for i, finding in enumerate(raw, 1): ]) payload = "\n".join(lines).rstrip() + "\n" -proposal_id = str(uuid.uuid4()) -proposal = { - "id": proposal_id, - "bottle_slug": slug, - "tool": "gitleaks-allow", - "proposed_file": payload, - "justification": ( +proposal = _sv.Proposal.new( + bottle_slug=slug, + tool=_sv.TOOL_GITLEAKS_ALLOW, + proposed_file=payload, + justification=( "git-gate found gitleaks findings hidden by # gitleaks:allow; " "approve only for dummy test fixtures or confirmed false positives" ), - "arrival_timestamp": datetime.datetime.now( - datetime.timezone.utc - ).isoformat(), - "current_file_hash": hashlib.sha256(payload.encode("utf-8")).hexdigest(), -} -queue = Path(queue_dir) -queue.mkdir(parents=True, exist_ok=True) -path = queue / f"{proposal_id}.proposal.json" -tmp = path.with_suffix(path.suffix + ".tmp") -with tmp.open("w", encoding="utf-8") as f: - json.dump(proposal, f, indent=2) - f.write("\n") -os.chmod(tmp, 0o600) -os.replace(tmp, path) -print(proposal_id) + current_file_hash=hashlib.sha256(payload.encode("utf-8")).hexdigest(), + now=datetime.datetime.now(datetime.timezone.utc), +) +_sv.write_proposal(Path(queue_dir), proposal) +print(proposal.id) PY ) rc=$? @@ -315,7 +304,6 @@ PY fi queue_dir=${SUPERVISE_QUEUE_DIR:-} - response_file="$queue_dir/${proposal_id}.response.json" timeout=${SUPERVISE_GITLEAKS_ALLOW_TIMEOUT_SECONDS:-300} case "$timeout" in ''|*[!0-9]*) @@ -327,26 +315,36 @@ PY echo "git-gate: approve with './cli.py supervise' to continue this push" >&2 waited=0 while [ "$waited" -lt "$timeout" ]; do - if [ -f "$response_file" ]; then - status=$(python3 - "$response_file" <<'PY' -import json + status=$(python3 - "$queue_dir" "$proposal_id" <<'PY' import sys +from pathlib import Path + +from bot_bottle import supervise as _sv + try: - with open(sys.argv[1], encoding="utf-8") as f: - raw = json.load(f) -except (OSError, json.JSONDecodeError): - sys.exit(1) -status = raw.get("status") -if not isinstance(status, str): - sys.exit(1) -print(status) + response = _sv.read_response(Path(sys.argv[1]), sys.argv[2]) +except FileNotFoundError: + sys.exit(2) +print(response.status) PY - ) || status="" + ) + rc=$? + if [ "$rc" -eq 2 ]; then + status="" + elif [ "$rc" -ne 0 ]; then + status="invalid" + fi + if [ -n "$status" ]; then case "$status" in approved|modified) - mkdir -p "$queue_dir/processed" - mv -f "$queue_dir/${proposal_id}.proposal.json" "$queue_dir/processed/" 2>/dev/null || true - mv -f "$queue_dir/${proposal_id}.response.json" "$queue_dir/processed/" 2>/dev/null || true + python3 - "$queue_dir" "$proposal_id" <<'PY' || true +import sys +from pathlib import Path + +from bot_bottle import supervise as _sv + +_sv.archive_proposal(Path(sys.argv[1]), sys.argv[2]) +PY echo "git-gate: supervisor approved # gitleaks:allow for $ref" >&2 return 0 ;; @@ -499,4 +497,3 @@ if ! git -C "$repo_dir" rev-parse --verify HEAD >/dev/null 2>&1; then fi exit 0 """ - diff --git a/bot_bottle/supervise.py b/bot_bottle/supervise.py index ddd6c4f..3ec3679 100644 --- a/bot_bottle/supervise.py +++ b/bot_bottle/supervise.py @@ -34,6 +34,7 @@ from __future__ import annotations import dataclasses import difflib import hashlib +import os import sqlite3 import time import uuid @@ -86,9 +87,9 @@ STATUSES: tuple[str, ...] = (STATUS_APPROVED, STATUS_MODIFIED, STATUS_REJECTED) ACTION_OPERATOR_EDIT = "operator-edit" QUEUE_DIR_IN_CONTAINER = "/run/supervise/queue" +DB_PATH_IN_CONTAINER = "/run/supervise/bot-bottle.db" DEFAULT_POLL_INTERVAL_SEC = 0.5 HOST_DB_FILENAME = "bot-bottle.db" -QUEUE_DB_FILENAME = "supervise.db" # --- Paths ----------------------------------------------------------------- @@ -115,7 +116,9 @@ def host_db_path() -> Path: def queue_db_path(queue_dir: Path) -> Path: - return queue_dir / QUEUE_DB_FILENAME + del queue_dir + env_path = os.environ.get("SUPERVISE_DB_PATH", "").strip() + return Path(env_path) if env_path else host_db_path() # --- Dataclasses ----------------------------------------------------------- @@ -331,6 +334,7 @@ def sha256_hex(content: str) -> str: class _QueueStore: def __init__(self, queue_dir: Path) -> None: + self.queue_key = _queue_key(queue_dir) self.db_path = queue_db_path(queue_dir) self.db_path.parent.mkdir(parents=True, exist_ok=True) self._init() @@ -340,11 +344,12 @@ class _QueueStore: conn.execute( """ INSERT OR REPLACE INTO supervise_proposals ( - id, bottle_slug, tool, proposed_file, justification, + queue_key, id, bottle_slug, tool, proposed_file, justification, arrival_timestamp, current_file_hash, archived - ) VALUES (?, ?, ?, ?, ?, ?, ?, 0) + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0) """, ( + self.queue_key, proposal.id, proposal.bottle_slug, proposal.tool, @@ -362,9 +367,9 @@ class _QueueStore: row = conn.execute( """ SELECT * FROM supervise_proposals - WHERE id = ? AND archived = 0 + WHERE queue_key = ? AND id = ? AND archived = 0 """, - (proposal_id,), + (self.queue_key, proposal_id), ).fetchone() if row is None: raise FileNotFoundError(proposal_id) @@ -378,12 +383,16 @@ class _QueueStore: """ SELECT p.* FROM supervise_proposals p WHERE p.archived = 0 + AND p.queue_key = ? AND NOT EXISTS ( SELECT 1 FROM supervise_responses r - WHERE r.proposal_id = p.id AND r.archived = 0 + WHERE r.queue_key = p.queue_key + AND r.proposal_id = p.id + AND r.archived = 0 ) ORDER BY p.arrival_timestamp, p.id - """ + """, + (self.queue_key,), ).fetchall() return [_proposal_from_row(row) for row in rows] @@ -392,10 +401,11 @@ class _QueueStore: conn.execute( """ INSERT OR REPLACE INTO supervise_responses ( - proposal_id, status, notes, final_file, archived - ) VALUES (?, ?, ?, ?, 0) + queue_key, proposal_id, status, notes, final_file, archived + ) VALUES (?, ?, ?, ?, ?, 0) """, ( + self.queue_key, response.proposal_id, response.status, response.notes, @@ -410,9 +420,9 @@ class _QueueStore: row = conn.execute( """ SELECT * FROM supervise_responses - WHERE proposal_id = ? AND archived = 0 + WHERE queue_key = ? AND proposal_id = ? AND archived = 0 """, - (proposal_id,), + (self.queue_key, proposal_id), ).fetchone() if row is None: raise FileNotFoundError(proposal_id) @@ -423,15 +433,18 @@ class _QueueStore: return with self._connect() as conn: conn.execute( - "UPDATE supervise_proposals SET archived = 1 WHERE id = ?", - (proposal_id,), + """ + UPDATE supervise_proposals SET archived = 1 + WHERE queue_key = ? AND id = ? + """, + (self.queue_key, proposal_id), ) conn.execute( """ UPDATE supervise_responses SET archived = 1 - WHERE proposal_id = ? + WHERE queue_key = ? AND proposal_id = ? """, - (proposal_id,), + (self.queue_key, proposal_id), ) def _connect(self) -> sqlite3.Connection: @@ -444,25 +457,29 @@ class _QueueStore: conn.execute( """ CREATE TABLE IF NOT EXISTS supervise_proposals ( - id TEXT PRIMARY KEY, + queue_key TEXT NOT NULL, + id TEXT NOT NULL, bottle_slug TEXT NOT NULL, tool TEXT NOT NULL, proposed_file TEXT NOT NULL, justification TEXT NOT NULL, arrival_timestamp TEXT NOT NULL, current_file_hash TEXT NOT NULL, - archived INTEGER NOT NULL DEFAULT 0 + archived INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (queue_key, id) ) """ ) conn.execute( """ CREATE TABLE IF NOT EXISTS supervise_responses ( - proposal_id TEXT PRIMARY KEY, + queue_key TEXT NOT NULL, + proposal_id TEXT NOT NULL, status TEXT NOT NULL, notes TEXT NOT NULL, final_file TEXT, - archived INTEGER NOT NULL DEFAULT 0 + archived INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (queue_key, proposal_id) ) """ ) @@ -580,6 +597,13 @@ def _audit_entry_from_row(row: sqlite3.Row) -> AuditEntry: ) +def _queue_key(queue_dir: Path) -> str: + env_slug = os.environ.get("SUPERVISE_BOTTLE_SLUG", "").strip() + if env_slug: + return env_slug + return queue_dir.name + + # --- Sidecar plan + abstract lifecycle ------------------------------------- @@ -594,6 +618,7 @@ class SupervisePlan: slug: str queue_dir: Path + db_path: Path internal_network: str = "" @@ -613,9 +638,13 @@ class Supervise(ABC): del stage_dir queue_dir = queue_dir_for_slug(slug) queue_dir.mkdir(parents=True, exist_ok=True) + db_path = host_db_path() + _QueueStore(queue_dir) + _AuditStore(db_path) return SupervisePlan( slug=slug, queue_dir=queue_dir, + db_path=db_path, ) # --- Helpers --------------------------------------------------------------- @@ -633,6 +662,7 @@ __all__ = [ "AuditEntry", "COMPONENT_FOR_TOOL", "DEFAULT_POLL_INTERVAL_SEC", + "DB_PATH_IN_CONTAINER", "Proposal", "QUEUE_DIR_IN_CONTAINER", "Response", diff --git a/docs/prds/prd-new-sqlite-local-storage.md b/docs/prds/prd-new-sqlite-local-storage.md index 909721f..bde2f6a 100644 --- a/docs/prds/prd-new-sqlite-local-storage.md +++ b/docs/prds/prd-new-sqlite-local-storage.md @@ -49,51 +49,50 @@ one-off persistence. ### Database locations -Queue state remains tied to the mounted per-bottle queue directory: - -```text -~/.bot-bottle/queue//supervise.db -``` - -The supervise sidecar already receives that directory at -`/run/supervise/queue`, so both the sidecar and host TUI can read and write the -same SQLite file without changing backend mounts. - -Audit state uses the host-level local database: +Queue and audit state use the host-level local database: ```text ~/.bot-bottle/bot-bottle.db ``` -This creates the shared host database that later forge/native lifecycle work can +The supervise sidecar receives that database as a writable bind mount at +`/run/supervise/bot-bottle.db` and gets the path through `SUPERVISE_DB_PATH`. +The existing per-slug queue directory mount remains in place for compatibility +with the supervise sidecar contract and any adjacent tooling that still expects a +queue directory, but the active queue records live in the host database. This +creates the shared host database that later forge/native lifecycle work can extend in separate PRDs. ### Tables -`supervise_proposals` lives in the per-queue database: +`supervise_proposals` lives in the host database: ```sql CREATE TABLE supervise_proposals ( - id TEXT PRIMARY KEY, + queue_key TEXT NOT NULL, + id TEXT NOT NULL, bottle_slug TEXT NOT NULL, tool TEXT NOT NULL, proposed_file TEXT NOT NULL, justification TEXT NOT NULL, arrival_timestamp TEXT NOT NULL, current_file_hash TEXT NOT NULL, - archived INTEGER NOT NULL DEFAULT 0 + archived INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (queue_key, id) ); ``` -`supervise_responses` lives in the same per-queue database: +`supervise_responses` lives in the host database: ```sql CREATE TABLE supervise_responses ( - proposal_id TEXT PRIMARY KEY, + queue_key TEXT NOT NULL, + proposal_id TEXT NOT NULL, status TEXT NOT NULL, notes TEXT NOT NULL, final_file TEXT, - archived INTEGER NOT NULL DEFAULT 0 + archived INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (queue_key, proposal_id) ); ``` @@ -115,8 +114,8 @@ CREATE TABLE supervise_audit_entries ( ### Compatibility The existing helper functions keep accepting `Path` arguments for queue -directories. Internally, they map the queue directory to `supervise.db` and -perform equivalent operations: +directories. Internally, they map the queue directory to a queue key and perform +equivalent operations against `~/.bot-bottle/bot-bottle.db`: - `list_pending_proposals` returns non-archived proposals without a non-archived response, sorted by arrival time. diff --git a/tests/unit/test_compose.py b/tests/unit/test_compose.py index 9f75be5..e874423 100644 --- a/tests/unit/test_compose.py +++ b/tests/unit/test_compose.py @@ -108,6 +108,7 @@ def _supervise_plan() -> SupervisePlan: return SupervisePlan( slug=SLUG, queue_dir=STATE / "supervise" / "queue", + db_path=STATE / "bot-bottle.db", internal_network=f"bot-bottle-net-{SLUG}", ) @@ -392,6 +393,7 @@ class TestSidecarBundleShape(unittest.TestCase): sc = self._render(supervise=True)["services"]["sidecars"] env_strings = sc["environment"] self.assertIn(f"SUPERVISE_BOTTLE_SLUG={SLUG}", env_strings) + self.assertIn("SUPERVISE_DB_PATH=/run/supervise/bot-bottle.db", env_strings) self.assertTrue(any(e.startswith("SUPERVISE_QUEUE_DIR=") for e in env_strings)) self.assertTrue(any(e.startswith("SUPERVISE_PORT=") for e in env_strings)) @@ -408,6 +410,7 @@ class TestSidecarBundleShape(unittest.TestCase): self.assertIn("/etc/egress", targets) self.assertIn("/git-gate-entrypoint.sh", targets) self.assertIn("/git-gate/creds/upstream-known_hosts", targets) + self.assertIn("/run/supervise/bot-bottle.db", targets) self.assertTrue(any("supervise/queue" in t or t.startswith("/run/supervise") for t in targets)) diff --git a/tests/unit/test_contrib_claude_provider.py b/tests/unit/test_contrib_claude_provider.py index 91bf73e..86d5231 100644 --- a/tests/unit/test_contrib_claude_provider.py +++ b/tests/unit/test_contrib_claude_provider.py @@ -75,6 +75,7 @@ def _plan( supervise_plan = SupervisePlan( slug="demo-abc12", queue_dir=Path("/tmp/queue"), + db_path=Path("/tmp/bot-bottle.db"), ) return DockerBottlePlan( spec=spec, diff --git a/tests/unit/test_contrib_codex_provider.py b/tests/unit/test_contrib_codex_provider.py index 3d3cf1c..97c45c5 100644 --- a/tests/unit/test_contrib_codex_provider.py +++ b/tests/unit/test_contrib_codex_provider.py @@ -78,6 +78,7 @@ def _plan( supervise_plan = SupervisePlan( slug="demo-abc12", queue_dir=Path("/tmp/queue"), + db_path=Path("/tmp/bot-bottle.db"), ) return DockerBottlePlan( spec=spec, diff --git a/tests/unit/test_git_gate.py b/tests/unit/test_git_gate.py index be6fc32..2f4e2f0 100644 --- a/tests/unit/test_git_gate.py +++ b/tests/unit/test_git_gate.py @@ -210,7 +210,9 @@ class TestHookRender(unittest.TestCase): # the suppressed findings for human approval. self.assertIn("--ignore-gitleaks-allow", hook) self.assertIn("--report-format=json", hook) - self.assertIn('"tool": "gitleaks-allow"', hook) + self.assertIn("tool=_sv.TOOL_GITLEAKS_ALLOW", hook) + self.assertIn("_sv.write_proposal", hook) + self.assertIn("_sv.read_response", hook) self.assertIn("SUPERVISE_QUEUE_DIR", hook) self.assertIn("SUPERVISE_BOTTLE_SLUG", hook) self.assertIn("supervisor approved # gitleaks:allow", hook) diff --git a/tests/unit/test_macos_container_launch.py b/tests/unit/test_macos_container_launch.py index 3e1038e..d96a055 100644 --- a/tests/unit/test_macos_container_launch.py +++ b/tests/unit/test_macos_container_launch.py @@ -71,7 +71,10 @@ def _plan( else: git_gate_plan = SimpleNamespace(upstreams=()) supervise_plan = ( - SimpleNamespace(queue_dir=Path("/state/supervise/queue")) + SimpleNamespace( + queue_dir=Path("/state/supervise/queue"), + db_path=Path("/state/bot-bottle.db"), + ) if supervise else None ) agent_provision = SimpleNamespace( @@ -136,6 +139,10 @@ class TestMacosContainerLaunchArgv(unittest.TestCase): f"type=bind,source={self.stage_dir},target=/etc/egress,readonly", argv, ) + self.assertIn( + "type=bind,source=/state/bot-bottle.db,target=/run/supervise/bot-bottle.db", + argv, + ) self.assertIn( "type=bind,source=/state/supervise/queue,target=/run/supervise/queue", argv, diff --git a/tests/unit/test_smolmachines_provision.py b/tests/unit/test_smolmachines_provision.py index d6b28c5..df92867 100644 --- a/tests/unit/test_smolmachines_provision.py +++ b/tests/unit/test_smolmachines_provision.py @@ -131,6 +131,7 @@ def _plan( supervise_plan = SupervisePlan( slug="demo-abc12", queue_dir=Path("/tmp/queue"), + db_path=Path("/tmp/bot-bottle.db"), ) return SmolmachinesBottlePlan( spec=spec, diff --git a/tests/unit/test_supervise.py b/tests/unit/test_supervise.py index 0e97d32..3d7419e 100644 --- a/tests/unit/test_supervise.py +++ b/tests/unit/test_supervise.py @@ -382,6 +382,7 @@ class TestSupervisePrepare(unittest.TestCase): def test_prepare_creates_queue(self): plan = _StubSupervise().prepare("dev", self.stage_dir) self.assertTrue(plan.queue_dir.is_dir()) + self.assertTrue(plan.db_path.is_file()) self.assertEqual("dev", plan.slug) self.assertEqual("", plan.internal_network) diff --git a/tests/unit/test_supervise_edge.py b/tests/unit/test_supervise_edge.py index 069d91d..d709a3f 100644 --- a/tests/unit/test_supervise_edge.py +++ b/tests/unit/test_supervise_edge.py @@ -44,7 +44,7 @@ class TestPathHelpers(unittest.TestCase): def test_queue_db_path_for_slug_dir(self) -> None: self.assertEqual( - Path("/tmp/queue/supervise.db"), + supervise.host_db_path(), supervise.queue_db_path(Path("/tmp/queue")), ) diff --git a/tests/unit/test_supervise_server.py b/tests/unit/test_supervise_server.py index 088dd39..8a95aa6 100644 --- a/tests/unit/test_supervise_server.py +++ b/tests/unit/test_supervise_server.py @@ -122,9 +122,10 @@ class TestRpcInternalErrorOnIoFailure(unittest.TestCase): def test_write_proposal_os_error_raises_internal(self): config = ServerConfig( bottle_slug="dev", - queue_dir=Path("/dev/null/cannot-exist"), + queue_dir=Path("/unused"), ) - with self.assertRaises(_RpcInternalError) as cm: + with patch.object(_sv, "write_proposal", side_effect=OSError("disk full")), \ + self.assertRaises(_RpcInternalError) as cm: handle_tools_call( { "name": _sv.TOOL_EGRESS_ALLOW,