Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 8 additions & 32 deletions reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,6 @@ def _storage_config_kind(storage_config: dict[str, object]) -> str:
).lower()
if explicit_type in {"supabase", "postgres"}:
return "remote"
if explicit_type == "disk":
return "disk"
if explicit_type == "sqlite":
return "sqlite"
if (
Expand All @@ -376,10 +374,13 @@ def _storage_config_kind(storage_config: dict[str, object]) -> str:
return "remote"
if "db_url" in storage_config:
return "remote"
if "dir_path" in storage_config:
return "disk"
if "db_path" in storage_config or not storage_config:
return "sqlite"
# Reached by any shape this build cannot interpret -- including a config
# left over from the removed disk backend (#98). `validate_stored_config`
# rejects those outright, so the server cannot load such an org either: we
# do not know what storage it uses, and guessing is not an option for a
# destructive command.
raise _ClearAllError(
"unsupported reflexio storage_config shape; refusing to delete local data"
)
Expand Down Expand Up @@ -408,23 +409,6 @@ def _validate_deletion_target(path: Path) -> None:
raise _ClearAllError(f"refusing to delete dangerous path: {resolved}")


def _disk_org_targets(base_dir: Path) -> list[_ClearAllTarget]:
if base_dir.exists() and base_dir.is_symlink():
raise _ClearAllError(
f"refusing to inspect symlink disk storage dir: {base_dir}"
)
if not base_dir.exists():
return []
if not base_dir.is_dir():
raise _ClearAllError(
f"configured disk storage path is not a directory: {base_dir}"
)
return [
_ClearAllTarget(child, "dir", "disk org data")
for child in sorted(base_dir.glob("disk_*"))
]


def _derive_db_filename(org_id: str) -> str:
"""Return the database filename *org_id* owns.

Expand Down Expand Up @@ -496,9 +480,9 @@ def _identity_owned_targets(root: Path, org_id: str) -> list[_ClearAllTarget]:

The storage root is shared: after dataset isolation it holds one
``reflexio_<org>.db`` per identity, alongside artifacts this plugin does not
own (the enterprise ``sql_app.db``, ``disk_*`` trees). ``derive_db_path``
documents those siblings as untouched, so enumerate what we own instead of
deleting the directory that contains them.
own -- the enterprise ``sql_app.db``, for one. ``derive_db_path`` documents
those siblings as untouched, so enumerate what we own instead of deleting
the directory that contains them.

Args:
root (Path): The storage root.
Expand Down Expand Up @@ -563,14 +547,6 @@ def _resolve_clear_all_targets() -> list[_ClearAllTarget]:
targets.extend(
_sqlite_artifact_targets(db_path, "configured SQLite data")
)
elif kind == "disk":
raw_dir_path = storage_config.get("dir_path")
if not isinstance(raw_dir_path, str) or not raw_dir_path.strip():
raise _ClearAllError("configured disk storage is missing dir_path")
disk_base = _resolve_absolute_path(
raw_dir_path.strip(), source="configured disk dir_path"
)
targets.extend(_disk_org_targets(disk_base))

deduped: list[_ClearAllTarget] = []
seen: set[Path] = set()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from __future__ import annotations

import json
import os
import sqlite3
from pathlib import Path
Expand Down Expand Up @@ -184,6 +185,40 @@ def test_missing_root_resolves_without_creating_it(monkeypatch, tmp_path):
assert not absent.exists()


@pytest.mark.parametrize(
"storage_config",
[
{"type": "disk", "dir_path": "/tmp/legacy"},
{"dir_path": "/tmp/legacy"},
],
ids=["explicit-type", "bare-dir-path"],
)
def test_a_config_this_build_cannot_interpret_deletes_nothing(
monkeypatch, root, tmp_path, storage_config
):
"""A leftover disk config refuses, rather than being reinterpreted.

The disk backend was removed in #98 with no deprecation window, and
`validate_stored_config` rejects both of these shapes outright -- so the
server cannot load such an org either. We do not know what storage it uses.
Mapping them onto `sqlite` would assert something false and delete a
database on the strength of a guess; refusing is the existing behaviour for
any shape this build cannot interpret, and a destructive command should
take it.
"""
ours = root / f"reflexio_{OUR_ORG}.db"
_make_db(ours, claimed_by=OUR_ORG)

config = tmp_path / "config.json"
config.write_text(json.dumps({"storage_config": storage_config}))
monkeypatch.setattr(cli, "_REFLEXIO_CONFIG_PATH", config)

with pytest.raises(cli._ClearAllError, match="unsupported"):
cli._resolve_clear_all_targets()

assert ours.exists(), "refused resolution must not have deleted anything"


def test_derived_filename_matches_the_canonical_resolver():
"""Anti-drift guard for the one thing this module duplicates.

Expand Down
Loading