Co-authored-by: Bastien <bastien.baret@gmail.com> Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai> Co-authored-by: Julien Legrand <72564015+JulienLGRD@users.noreply.github.com> Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai> Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai> Co-authored-by: Quentin <quentin.torroba@mistral.ai> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
120 lines
3.6 KiB
Python
120 lines
3.6 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
import tomllib
|
|
|
|
import tomli_w
|
|
|
|
from vibe.core.paths import (
|
|
AGENTS_MD_FILENAME,
|
|
TRUSTED_FOLDERS_FILE,
|
|
walk_local_config_dirs,
|
|
)
|
|
|
|
|
|
def has_agents_md_file(path: Path) -> bool:
|
|
return (path / AGENTS_MD_FILENAME).exists()
|
|
|
|
|
|
def find_trustable_files(path: Path) -> list[str]:
|
|
"""Return relative paths of files/dirs that would modify the agent's behavior."""
|
|
resolved = path.resolve()
|
|
found: list[str] = []
|
|
|
|
if has_agents_md_file(path):
|
|
found.append(AGENTS_MD_FILENAME)
|
|
|
|
for config_dir in walk_local_config_dirs(path).config_dirs:
|
|
label = f"{config_dir.relative_to(resolved)}/"
|
|
if label not in found:
|
|
found.append(label)
|
|
|
|
return found
|
|
|
|
|
|
class TrustedFoldersManager:
|
|
def __init__(self) -> None:
|
|
self._file_path = TRUSTED_FOLDERS_FILE.path
|
|
self._trusted: list[str] = []
|
|
self._untrusted: list[str] = []
|
|
self._load()
|
|
|
|
def _normalize_path(self, path: Path) -> str:
|
|
return str(path.expanduser().resolve())
|
|
|
|
def _load(self) -> None:
|
|
if not self._file_path.is_file():
|
|
self._trusted = []
|
|
self._untrusted = []
|
|
self._save()
|
|
return
|
|
|
|
try:
|
|
with self._file_path.open("rb") as f:
|
|
data = tomllib.load(f)
|
|
self._trusted = list(data.get("trusted", []))
|
|
self._untrusted = list(data.get("untrusted", []))
|
|
except (OSError, tomllib.TOMLDecodeError):
|
|
self._trusted = []
|
|
self._untrusted = []
|
|
self._save()
|
|
|
|
def _save(self) -> None:
|
|
self._file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
data = {"trusted": self._trusted, "untrusted": self._untrusted}
|
|
try:
|
|
with self._file_path.open("wb") as f:
|
|
tomli_w.dump(data, f)
|
|
except OSError:
|
|
pass
|
|
|
|
def is_trusted(self, path: Path) -> bool | None:
|
|
"""Check trust walking up from *path* to filesystem root.
|
|
|
|
The first ancestor (or *path* itself) found in either the trusted
|
|
or untrusted list wins. Returns ``None`` when no decision exists.
|
|
"""
|
|
current = Path(self._normalize_path(path))
|
|
while True:
|
|
s = str(current)
|
|
if s in self._trusted:
|
|
return True
|
|
if s in self._untrusted:
|
|
return False
|
|
parent = current.parent
|
|
if parent == current:
|
|
break
|
|
current = parent
|
|
return None
|
|
|
|
def find_trust_root(self, path: Path) -> Path | None:
|
|
"""Return the closest ancestor (or *path* itself) explicitly in the trusted list."""
|
|
current = Path(self._normalize_path(path))
|
|
while True:
|
|
s = str(current)
|
|
if s in self._trusted:
|
|
return current
|
|
parent = current.parent
|
|
if parent == current:
|
|
break
|
|
current = parent
|
|
return None
|
|
|
|
def add_trusted(self, path: Path) -> None:
|
|
normalized = self._normalize_path(path)
|
|
if normalized not in self._trusted:
|
|
self._trusted.append(normalized)
|
|
if normalized in self._untrusted:
|
|
self._untrusted.remove(normalized)
|
|
self._save()
|
|
|
|
def add_untrusted(self, path: Path) -> None:
|
|
normalized = self._normalize_path(path)
|
|
if normalized not in self._untrusted:
|
|
self._untrusted.append(normalized)
|
|
if normalized in self._trusted:
|
|
self._trusted.remove(normalized)
|
|
self._save()
|
|
|
|
|
|
trusted_folders_manager = TrustedFoldersManager()
|