fix(agents): open agy, codex and hermes databases read-only (Issue #64)
This commit is contained in:
1 parent
3ce5d5fdc1
commit
b0eccc5301
8 files changed
+461
-56
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# base.py — BaseAgentAdapter abstract base class, SpawnSpec, and DiscoveryContext
|
||||
|
||||
import os, json, sqlite3, shutil, subprocess
|
||||
import os, json, sqlite3, shutil, subprocess, tempfile
|
||||
from typing import Optional, Dict, Any, List
|
||||
from urllib.parse import quote
|
||||
from lib_py.paths import resolve_home
|
||||
@@ -108,15 +108,41 @@ def scan_names(root: str, uuid: str, skip=()) -> list:
|
||||
return sorted(found)
|
||||
|
||||
|
||||
def _ro_connect(db: str):
|
||||
"""A read that neither creates nor removes anything beside db (Issues #60, #64).
|
||||
Both WAL sidecars (a live writer keeps them): read through them. No -wal:
|
||||
nothing to apply, so the file is read as immutable. A -wal without its
|
||||
-shm (left behind - no writer runs without one) still holds committed
|
||||
rows: they are read from a private copy, where SQLite may rebuild the
|
||||
index, loaded into memory."""
|
||||
path = os.path.abspath(db)
|
||||
wal, shm = os.path.exists(path + "-wal"), os.path.exists(path + "-shm")
|
||||
if wal and shm:
|
||||
return sqlite3.connect(f"file:{quote(path)}?mode=ro", uri=True)
|
||||
if not wal:
|
||||
return sqlite3.connect(f"file:{quote(path)}?mode=ro&immutable=1", uri=True)
|
||||
mem = sqlite3.connect(":memory:")
|
||||
with tempfile.TemporaryDirectory(prefix="mam-ro-") as tmp:
|
||||
copy = os.path.join(tmp, os.path.basename(path) or "state.db")
|
||||
shutil.copyfile(path, copy)
|
||||
shutil.copyfile(path + "-wal", copy + "-wal")
|
||||
src = sqlite3.connect(copy)
|
||||
try:
|
||||
src.backup(mem)
|
||||
finally:
|
||||
src.close()
|
||||
return mem
|
||||
|
||||
|
||||
def db_rows_naming(db: str, uuid: str, columns=(), id_tables=(), connect=None) -> list:
|
||||
""""<db> (<table>.<col>: <n> rows)" for every table holding rows of this
|
||||
conversation in one of `columns`, or in the id column of an `id_tables`
|
||||
(table, column) pair (Issue #31). Read-only; unreadable tables are skipped.
|
||||
`connect(db)` opens the database (default: a mode=ro URI)."""
|
||||
`connect(db)` opens the database (default: `_ro_connect`)."""
|
||||
if not _plausible_id(uuid) or not db or not os.path.isfile(db):
|
||||
return []
|
||||
try:
|
||||
conn = connect(db) if connect else sqlite3.connect(f"file:{quote(os.path.abspath(db))}?mode=ro", uri=True)
|
||||
conn = (connect or _ro_connect)(db)
|
||||
except Exception:
|
||||
return []
|
||||
found = []
|
||||
|
||||
Reference in new issue
Block a user