421d31c32f
Create bot_bottle/paths.py as the canonical home for the app-root path helpers (bot_bottle_root, host_db_path, HOST_DB_FILENAME) — foundational, not supervise- or db-specific. `bot_bottle_root()` now honours a BOT_BOTTLE_ROOT env override. Repoint every consumer (supervise, supervise_types, db_store, queue_store, audit_store, store_manager, bottle_state, cli/supervise, docker/cleanup, orchestrator/registry) at paths; remove the definitions (and supervise's duplicate host_db_path) and the now-dead `import sys`. Add paths.py to the sidecar bundle (Dockerfile.sidecars) for the flat-import copies. Tests: replace ~12 files' monkeypatching of supervise.bot_bottle_root (and the flat/pkg/supervise_types triple-patch dance) with a single `use_bottle_root()` helper that sets BOT_BOTTLE_ROOT — every module and flat/package copy reads the same env var, so one override covers them all. Net -97 lines. Behaviour-preserving: full unit suite unchanged (only the pre-existing /bin/sleep sidecar-init errors remain). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
94 lines
3.4 KiB
Python
94 lines
3.4 KiB
Python
"""SQLite-backed audit store for supervise (PRD 0013)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
from pathlib import Path
|
|
|
|
try:
|
|
from .supervise_types import AuditEntry
|
|
from .paths import host_db_path
|
|
from .db_store import DbStore
|
|
from .migrations import TableMigrations
|
|
except ImportError:
|
|
from supervise_types import AuditEntry # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module
|
|
from paths import host_db_path # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module
|
|
from db_store import DbStore # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module
|
|
from migrations import TableMigrations # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module
|
|
|
|
|
|
class AuditStore(DbStore):
|
|
"""SQLite-backed persistent store for supervise audit entries."""
|
|
|
|
def __init__(self, db_path: Path | None = None) -> None:
|
|
# One entry per schema version: migrations[0] brings a fresh DB to
|
|
# version 1, [1] to version 2, etc. Add new entries at the end; never
|
|
# edit existing ones.
|
|
migrations = TableMigrations("audit_store", [
|
|
# v1 — initial schema
|
|
"""
|
|
CREATE TABLE IF NOT EXISTS supervise_audit_entries (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
timestamp TEXT NOT NULL,
|
|
bottle_slug TEXT NOT NULL,
|
|
component TEXT NOT NULL,
|
|
operator_action TEXT NOT NULL,
|
|
operator_notes TEXT NOT NULL,
|
|
justification TEXT NOT NULL,
|
|
diff TEXT NOT NULL
|
|
)
|
|
""",
|
|
])
|
|
super().__init__(db_path or host_db_path(), migrations)
|
|
|
|
def write_audit_entry(self, entry: AuditEntry) -> Path:
|
|
with self._connect() as conn:
|
|
conn.execute(
|
|
"""
|
|
INSERT INTO supervise_audit_entries (
|
|
timestamp, bottle_slug, component, operator_action,
|
|
operator_notes, justification, diff
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
""",
|
|
(
|
|
entry.timestamp,
|
|
entry.bottle_slug,
|
|
entry.component,
|
|
entry.operator_action,
|
|
entry.operator_notes,
|
|
entry.justification,
|
|
entry.diff,
|
|
),
|
|
)
|
|
self._chmod()
|
|
return self.db_path
|
|
|
|
def read_audit_entries(self, component: str, slug: str) -> list[AuditEntry]:
|
|
if not self.db_path.is_file():
|
|
return []
|
|
with self._connect() as conn:
|
|
rows = conn.execute(
|
|
"""
|
|
SELECT * FROM supervise_audit_entries
|
|
WHERE component = ? AND bottle_slug = ?
|
|
ORDER BY id
|
|
""",
|
|
(component, slug),
|
|
).fetchall()
|
|
return [self._row_to_entry(row) for row in rows]
|
|
|
|
@staticmethod
|
|
def _row_to_entry(row: sqlite3.Row) -> AuditEntry:
|
|
return AuditEntry(
|
|
timestamp=row["timestamp"],
|
|
bottle_slug=row["bottle_slug"],
|
|
component=row["component"],
|
|
operator_action=row["operator_action"],
|
|
operator_notes=row["operator_notes"],
|
|
justification=row["justification"],
|
|
diff=row["diff"],
|
|
)
|
|
|
|
|
|
__all__ = ["AuditStore"]
|