Co-authored-by: Alexis Tacnet <alexis@mistral.ai> Co-authored-by: Clément Drouin <clement.drouin@mistral.ai> Co-authored-by: Guillaume LE GOFF <guillaume.lgf@gmail.com> Co-authored-by: Lucas Marandat <31749711+lucasmrdt@users.noreply.github.com> Co-authored-by: Maxime Dolores <maxime.dolores@ext.mistral.ai> Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai> Co-authored-by: Quentin <quentin.torroba@mistral.ai> Co-authored-by: Val <102326092+vdeva@users.noreply.github.com> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: p.vezia <166131032+le-codeur-rapide@users.noreply.github.com> Co-authored-by: Hiba Chaabnia <Hiba-Chaabnia@users.noreply.github.com> Co-authored-by: Nikhil Bhima <nikhilbhima@users.noreply.github.com> Co-authored-by: Nkipohcs <Nkipohcs@users.noreply.github.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
193 lines
6.5 KiB
Python
193 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Literal
|
|
|
|
import pytest
|
|
|
|
from vibe.cli import entrypoint as entrypoint_mod
|
|
from vibe.core.trusted_folders import trusted_folders_manager
|
|
from vibe.setup.trusted_folders.trust_folder_dialog import TrustDecision
|
|
|
|
|
|
def _make_git_repo(path: Path) -> None:
|
|
git_dir = path / ".git"
|
|
git_dir.mkdir()
|
|
(git_dir / "HEAD").write_text("ref: refs/heads/main\n", encoding="utf-8")
|
|
|
|
|
|
def _git_sub_with_agents(
|
|
tmp_path: Path, *, agents_at_sub: bool = True
|
|
) -> tuple[Path, Path]:
|
|
repo = tmp_path / "repo"
|
|
repo.mkdir()
|
|
_make_git_repo(repo)
|
|
sub = repo / "src"
|
|
sub.mkdir()
|
|
if agents_at_sub:
|
|
(sub / "AGENTS.md").write_text("# Agents", encoding="utf-8")
|
|
else:
|
|
(repo / "AGENTS.md").write_text("# Agents", encoding="utf-8")
|
|
return repo, sub
|
|
|
|
|
|
def _patch_ask(
|
|
monkeypatch: pytest.MonkeyPatch, *, decision: TrustDecision = TrustDecision.DECLINE
|
|
) -> dict[str, object]:
|
|
captured: dict[str, object] = {"called": False}
|
|
|
|
def fake_ask(
|
|
cwd: Path,
|
|
repo_root: Path | None,
|
|
detected_files: list[str],
|
|
repo_detected_files: list[str] | None = None,
|
|
offer_repo_trust: bool = False,
|
|
repo_explicitly_untrusted: bool = False,
|
|
) -> TrustDecision:
|
|
captured["called"] = True
|
|
captured["cwd"] = cwd
|
|
captured["repo_root"] = repo_root
|
|
captured["detected_files"] = detected_files
|
|
captured["repo_detected_files"] = repo_detected_files
|
|
captured["offer_repo_trust"] = offer_repo_trust
|
|
captured["repo_explicitly_untrusted"] = repo_explicitly_untrusted
|
|
return decision
|
|
|
|
monkeypatch.setattr(entrypoint_mod, "ask_trust_folder", fake_ask)
|
|
return captured
|
|
|
|
|
|
@pytest.fixture
|
|
def away_from_home(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
|
monkeypatch.setattr(Path, "home", classmethod(lambda _cls: tmp_path / "elsewhere"))
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"setup",
|
|
[
|
|
pytest.param("repo_already_trusted", id="repo_already_trusted"),
|
|
pytest.param("cwd_explicitly_untrusted", id="cwd_explicitly_untrusted"),
|
|
],
|
|
)
|
|
def test_skips_trust_dialog(
|
|
setup: Literal["repo_already_trusted", "cwd_explicitly_untrusted"],
|
|
tmp_path: Path,
|
|
away_from_home: None,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
match setup:
|
|
case "repo_already_trusted":
|
|
repo, cwd = _git_sub_with_agents(tmp_path)
|
|
trusted_folders_manager.add_trusted(repo)
|
|
case "cwd_explicitly_untrusted":
|
|
cwd = tmp_path / "plain"
|
|
cwd.mkdir()
|
|
(cwd / "AGENTS.md").write_text("# Agents", encoding="utf-8")
|
|
trusted_folders_manager.add_untrusted(cwd)
|
|
|
|
captured = _patch_ask(monkeypatch)
|
|
entrypoint_mod.check_and_resolve_trusted_folder(cwd)
|
|
assert captured["called"] is False
|
|
|
|
|
|
def test_shows_trust_dialog_when_only_repo_context_files_exist(
|
|
tmp_path: Path, away_from_home: None, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
repo, cwd = _git_sub_with_agents(tmp_path, agents_at_sub=False)
|
|
captured = _patch_ask(monkeypatch)
|
|
entrypoint_mod.check_and_resolve_trusted_folder(cwd)
|
|
|
|
assert captured["called"] is True
|
|
assert captured["detected_files"] == []
|
|
assert captured["repo_detected_files"] == ["AGENTS.md"]
|
|
assert captured["repo_root"] == repo.resolve()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"untrusted_at,offer_repo_trust,repo_explicitly_untrusted",
|
|
[
|
|
pytest.param(None, True, False, id="repo_undecided"),
|
|
pytest.param("repo", False, True, id="repo_explicitly_untrusted"),
|
|
pytest.param("parent", True, False, id="parent_untrusted_only"),
|
|
],
|
|
)
|
|
def test_ask_trust_folder_args_in_git_repo(
|
|
untrusted_at: str | None,
|
|
offer_repo_trust: bool,
|
|
repo_explicitly_untrusted: bool,
|
|
tmp_path: Path,
|
|
away_from_home: None,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
if untrusted_at == "parent":
|
|
parent = tmp_path / "parent"
|
|
parent.mkdir()
|
|
repo = parent / "repo"
|
|
repo.mkdir()
|
|
_make_git_repo(repo)
|
|
cwd = repo / "src"
|
|
cwd.mkdir()
|
|
(cwd / "AGENTS.md").write_text("# Agents", encoding="utf-8")
|
|
trusted_folders_manager.add_untrusted(parent)
|
|
else:
|
|
repo, cwd = _git_sub_with_agents(tmp_path)
|
|
if untrusted_at == "repo":
|
|
trusted_folders_manager.add_untrusted(repo)
|
|
|
|
captured = _patch_ask(monkeypatch)
|
|
entrypoint_mod.check_and_resolve_trusted_folder(cwd)
|
|
|
|
assert captured["called"] is True
|
|
assert captured["cwd"] == cwd
|
|
assert captured["repo_root"] == repo.resolve()
|
|
assert captured["detected_files"] == ["AGENTS.md"]
|
|
assert captured["repo_detected_files"] == []
|
|
assert captured["offer_repo_trust"] is offer_repo_trust
|
|
assert captured["repo_explicitly_untrusted"] is repo_explicitly_untrusted
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("decision", "sub_trusted", "repo_trusted", "sub_explicitly_untrusted"),
|
|
[
|
|
pytest.param(TrustDecision.TRUST_REPO, True, True, False, id="trust_repo"),
|
|
pytest.param(TrustDecision.TRUST_CWD, True, None, False, id="trust_cwd"),
|
|
pytest.param(TrustDecision.DECLINE, False, None, True, id="decline"),
|
|
],
|
|
)
|
|
def test_applies_trust_decision(
|
|
decision: TrustDecision,
|
|
sub_trusted: bool | None,
|
|
repo_trusted: bool | None,
|
|
sub_explicitly_untrusted: bool,
|
|
tmp_path: Path,
|
|
away_from_home: None,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
repo, sub = _git_sub_with_agents(tmp_path)
|
|
_patch_ask(monkeypatch, decision=decision)
|
|
entrypoint_mod.check_and_resolve_trusted_folder(sub)
|
|
|
|
assert trusted_folders_manager.is_trusted(sub) is sub_trusted
|
|
assert trusted_folders_manager.is_trusted(repo) is repo_trusted
|
|
assert (
|
|
trusted_folders_manager.is_explicitly_untrusted(sub) is sub_explicitly_untrusted
|
|
)
|
|
if decision == TrustDecision.TRUST_CWD:
|
|
assert trusted_folders_manager.is_trusted(repo / "other") is None
|
|
|
|
|
|
def test_no_git_repo_offers_no_repo_trust_and_decline_untrusts_cwd(
|
|
tmp_path: Path, away_from_home: None, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
cwd = tmp_path / "plain"
|
|
cwd.mkdir()
|
|
(cwd / "AGENTS.md").write_text("# Agents", encoding="utf-8")
|
|
|
|
captured = _patch_ask(monkeypatch, decision=TrustDecision.DECLINE)
|
|
entrypoint_mod.check_and_resolve_trusted_folder(cwd)
|
|
|
|
assert captured["called"] is True
|
|
assert captured["repo_root"] is None
|
|
assert captured["repo_detected_files"] == []
|
|
assert captured["offer_repo_trust"] is False
|
|
assert trusted_folders_manager.is_explicitly_untrusted(cwd) is True
|