test: expand security regression coverage
Agent-Logs-Url: https://github.com/MemPalace/mempalace/sessions/775f2fc4-3051-462e-8586-6d694b55da0d Co-authored-by: igorls <4753812+igorls@users.noreply.github.com>
This commit is contained in:
committed by
Igor Lins e Silva
parent
c478dfa173
commit
d2d4e62543
+7
-4
@@ -170,7 +170,7 @@ def cmd_repair(args):
|
|||||||
"""Rebuild palace vector index from SQLite metadata."""
|
"""Rebuild palace vector index from SQLite metadata."""
|
||||||
import chromadb
|
import chromadb
|
||||||
import shutil
|
import shutil
|
||||||
from .migrate import confirm_destructive_action, has_palace_database
|
from .migrate import confirm_destructive_action, contains_palace_database
|
||||||
|
|
||||||
palace_path = os.path.abspath(
|
palace_path = os.path.abspath(
|
||||||
os.path.expanduser(args.palace) if args.palace else MempalaceConfig().palace_path
|
os.path.expanduser(args.palace) if args.palace else MempalaceConfig().palace_path
|
||||||
@@ -180,7 +180,7 @@ def cmd_repair(args):
|
|||||||
if not os.path.isdir(palace_path):
|
if not os.path.isdir(palace_path):
|
||||||
print(f"\n No palace found at {palace_path}")
|
print(f"\n No palace found at {palace_path}")
|
||||||
return
|
return
|
||||||
if not has_palace_database(palace_path):
|
if not contains_palace_database(palace_path):
|
||||||
print(f"\n No palace database found at {db_path}")
|
print(f"\n No palace database found at {db_path}")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -226,8 +226,11 @@ def cmd_repair(args):
|
|||||||
palace_path = palace_path.rstrip(os.sep)
|
palace_path = palace_path.rstrip(os.sep)
|
||||||
backup_path = palace_path + ".backup"
|
backup_path = palace_path + ".backup"
|
||||||
if os.path.exists(backup_path):
|
if os.path.exists(backup_path):
|
||||||
if not has_palace_database(backup_path):
|
if not contains_palace_database(backup_path):
|
||||||
print(f" Refusing to delete non-palace backup path: {backup_path}")
|
print(
|
||||||
|
" Cannot proceed: backup path exists but is not a valid palace database. "
|
||||||
|
f"Please remove or rename: {backup_path}"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
shutil.rmtree(backup_path)
|
shutil.rmtree(backup_path)
|
||||||
print(f" Backing up to {backup_path}...")
|
print(f" Backing up to {backup_path}...")
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ def detect_chromadb_version(db_path: str) -> str:
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def has_palace_database(path: str) -> bool:
|
def contains_palace_database(path: str) -> bool:
|
||||||
"""Return True when path looks like a MemPalace ChromaDB directory."""
|
"""Return True when path looks like a MemPalace ChromaDB directory."""
|
||||||
return os.path.isfile(os.path.join(path, "chroma.sqlite3"))
|
return os.path.isfile(os.path.join(path, "chroma.sqlite3"))
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ def migrate(palace_path: str, dry_run: bool = False, confirm: bool = False):
|
|||||||
palace_path = os.path.abspath(os.path.expanduser(palace_path))
|
palace_path = os.path.abspath(os.path.expanduser(palace_path))
|
||||||
db_path = os.path.join(palace_path, "chroma.sqlite3")
|
db_path = os.path.join(palace_path, "chroma.sqlite3")
|
||||||
|
|
||||||
if not os.path.isdir(palace_path) or not has_palace_database(palace_path):
|
if not os.path.isdir(palace_path) or not contains_palace_database(palace_path):
|
||||||
print(f"\n No palace database found at {db_path}")
|
print(f"\n No palace database found at {db_path}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,20 @@ class TestTailSentence:
|
|||||||
assert result["was_sanitized"] is True
|
assert result["was_sanitized"] is True
|
||||||
assert "MemPalace" in result["clean_query"] or "ChromaDB" in result["clean_query"]
|
assert "MemPalace" in result["clean_query"] or "ChromaDB" in result["clean_query"]
|
||||||
|
|
||||||
|
def test_long_candidate_uses_last_sentence_fragment(self):
|
||||||
|
query = ("Prompt sentence. " * 30) + "Final search intent for architecture migration"
|
||||||
|
result = sanitize_query(query)
|
||||||
|
assert result["method"] == "tail_sentence"
|
||||||
|
assert result["clean_query"] == "Final search intent for architecture migration"
|
||||||
|
|
||||||
|
def test_long_candidate_strips_wrapping_quotes(self):
|
||||||
|
query = ("Prefix text " * 30) + '\n"' + ("x" * 260) + '"'
|
||||||
|
result = sanitize_query(query)
|
||||||
|
assert result["method"] == "tail_sentence"
|
||||||
|
assert not result["clean_query"].startswith('"')
|
||||||
|
assert not result["clean_query"].endswith('"')
|
||||||
|
assert len(result["clean_query"]) <= MAX_QUERY_LENGTH
|
||||||
|
|
||||||
|
|
||||||
class TestTailTruncation:
|
class TestTailTruncation:
|
||||||
"""Step 4: Fallback — take the last MAX_QUERY_LENGTH characters."""
|
"""Step 4: Fallback — take the last MAX_QUERY_LENGTH characters."""
|
||||||
@@ -119,6 +133,12 @@ class TestTailTruncation:
|
|||||||
result = sanitize_query(filler)
|
result = sanitize_query(filler)
|
||||||
assert "IMPORTANT_QUERY_CONTENT" in result["clean_query"]
|
assert "IMPORTANT_QUERY_CONTENT" in result["clean_query"]
|
||||||
|
|
||||||
|
def test_tail_sentence_fallback_preserves_tail_without_delimiters(self):
|
||||||
|
filler = ("x" * 260) + "IMPORTANT_QUERY_CONTENT"
|
||||||
|
result = sanitize_query(filler)
|
||||||
|
assert result["method"] == "tail_sentence"
|
||||||
|
assert "IMPORTANT_QUERY_CONTENT" in result["clean_query"]
|
||||||
|
|
||||||
|
|
||||||
class TestLengthGuards:
|
class TestLengthGuards:
|
||||||
"""Verify output length constraints."""
|
"""Verify output length constraints."""
|
||||||
|
|||||||
Reference in New Issue
Block a user