f571627a6b
Les jetons MCP sont désormais chiffrés (Fernet dérivée de SECRET_KEY) en plus du hash conservé pour l'auth, permettant leur ré-affichage/copie à tout moment. Getter scopé au propriétaire, dégradation propre si clé absente/changée. Migration 0013 + colonne token_enc. UI alignée sur « Copier le lien » des vues. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
103 lines
3.2 KiB
Python
103 lines
3.2 KiB
Python
def test_section_connecteur_mcp_present():
|
|
from src.pages._compte_shell import SECTIONS
|
|
|
|
keys = {s["key"]: s for s in SECTIONS}
|
|
assert "mcp" in keys
|
|
assert keys["mcp"]["label"] == "Connecteur MCP"
|
|
assert keys["mcp"]["href"] == "/compte/mcp"
|
|
assert keys["mcp"]["require_subscription"] is True
|
|
|
|
|
|
def test_page_module_registers_and_builds_client_instructions():
|
|
# importe l'app pour la découverte use_pages en contexte propre
|
|
from src.app import app # noqa: F401
|
|
from src.pages.compte import mcp as mcp_page
|
|
|
|
# helper pur : construit les 4 blocs d'instructions clients
|
|
blocks = mcp_page.client_instructions(
|
|
"https://colibre.fr/_mcp", "colibre_TESTTOKEN"
|
|
)
|
|
text = str(blocks)
|
|
assert "colibre_TESTTOKEN" in text
|
|
assert "https://colibre.fr/_mcp" in text
|
|
for client_name in ("Claude", "Gemini", "Mistral", "ChatGPT"):
|
|
assert client_name in text
|
|
|
|
|
|
def test_client_instructions_include_oauth_apps():
|
|
from src.app import app # noqa: F401
|
|
from src.pages.compte.mcp import client_instructions
|
|
|
|
comp = client_instructions("https://colibre.fr/_mcp", "<VOTRE_JETON>")
|
|
titles = _collect_titles(comp)
|
|
assert any("Claude.ai" in t for t in titles)
|
|
assert any("ChatGPT" in t for t in titles)
|
|
|
|
|
|
def test_prompt_tips_mentions_columns_and_examples():
|
|
from src.app import app # noqa: F401
|
|
from src.pages.compte.mcp import prompt_tips
|
|
|
|
text = str(prompt_tips())
|
|
assert "Morbihan" in text # un exemple de prompt concret
|
|
assert "colonnes" in text # l'astuce sur le choix des colonnes
|
|
assert "lien" in text # mention du lien vers la fiche marché
|
|
|
|
|
|
def test_token_row_has_copy_button_when_token_available():
|
|
from src.app import app # noqa: F401
|
|
from src.pages.compte.mcp import _token_row
|
|
|
|
text = str(
|
|
_token_row(
|
|
{
|
|
"id": 42,
|
|
"label": "l",
|
|
"created_at": "c",
|
|
"last_used_at": None,
|
|
"revoked_at": None,
|
|
"token_plain": "colibre_abc123",
|
|
}
|
|
)
|
|
)
|
|
assert "Copier le jeton" in text
|
|
assert "colibre_abc123" in text # contenu du presse-papier (dcc.Clipboard)
|
|
|
|
|
|
def test_token_row_no_copy_button_when_token_unavailable():
|
|
from src.app import app # noqa: F401
|
|
from src.pages.compte.mcp import _token_row
|
|
|
|
text = str(
|
|
_token_row(
|
|
{
|
|
"id": 42,
|
|
"label": "l",
|
|
"created_at": "c",
|
|
"last_used_at": None,
|
|
"revoked_at": None,
|
|
"token_plain": None, # ancien jeton haché, non récupérable
|
|
}
|
|
)
|
|
)
|
|
assert "Copier le jeton" not in text
|
|
|
|
|
|
def _collect_titles(component):
|
|
# Parcourt récursivement les AccordionItem pour collecter leurs `title`.
|
|
found = []
|
|
|
|
def walk(node):
|
|
title = getattr(node, "title", None)
|
|
if isinstance(title, str):
|
|
found.append(title)
|
|
children = getattr(node, "children", None)
|
|
if isinstance(children, (list, tuple)):
|
|
for c in children:
|
|
walk(c)
|
|
elif children is not None:
|
|
walk(children)
|
|
|
|
walk(component)
|
|
return found
|