feat: intégration TikTak #197-200 + scoped tokens, webhooks filtrés, listes mtime/size ; fix e2e-server BUG-112
CI / lint (push) Successful in 3m17s
CI / security (push) Failing after 1m51s
CI / test (push) Successful in 5m14s
CI / build (push) Successful in 1m50s
CI / e2e (push) Successful in 18m18s

This commit is contained in:
2026-10-14 11:42:53 -04:00
parent 2be0b15bcf
commit f783394f09
59 changed files with 3233 additions and 77 deletions
+49
View File
@@ -117,6 +117,29 @@ class ToolRateLimitError(ToolError):
self.retry_after = retry_after
#: Tools a ``files``-scoped API token (#199, synchro TikTak) may invoke :
#: vault file read/write surface only — no external calls (git/web), no
#: notifications, no scheduler, no cross-vault analysis beyond file content.
FILES_SCOPE_TOOLS: frozenset[str] = frozenset({
# Lecture / recherche de fichiers
"list_vaults", "list_directory", "list_all_files",
"read_file", "read_file_raw", "get_backlinks",
"get_graph", "search_fulltext", "search_advanced", "search_paths",
"list_tags", "suggest_tags", "list_recent",
"list_backups", "diff_backup", "restore_backup",
"find_duplicates",
# Mutations de fichiers
"create_file", "create_directory", "edit_file", "append_to_file",
"rename_file", "rename_directory", "move_path", "replace_in_files",
"delete_file", "delete_directory", "merge_duplicate_notes",
# Tableurs & documents (création/édition de fichiers du vault)
"create_xlsx", "create_docx", "create_csv", "create_pdf",
"list_xlsx_sheets", "xlsx_to_markdown", "search_workbook",
"analyze_range", "update_xlsx_cells", "append_xlsx_rows",
"edit_xlsx_structure",
})
@dataclass
class ToolContext:
"""Carries the caller identity and execution options for a tool call.
@@ -190,6 +213,32 @@ class ToolContext:
details={"vault": vault},
)
def require_tool_allowed(self, tool: str) -> None:
"""Raise :class:`ToolPermissionError` when the caller's token scope
forbids *tool* (#199).
A ``files``-scoped token is confined to :data:`FILES_SCOPE_TOOLS`
(vault file surface). Full-scope and scopeless callers (session
tokens, pre-#199 API keys) are unaffected ; an unknown scope fails
closed.
"""
token_scope = self.user.get("_token_scope") or "full"
if token_scope == "full":
return
if token_scope == "files":
if tool not in FILES_SCOPE_TOOLS:
raise ToolPermissionError(
f"Token à portée limitée : outil '{tool}' hors périmètre 'files'",
code="token_scope_denied",
details={"tool": tool, "scope": "files"},
)
return
raise ToolPermissionError(
"Token à portée inconnue : appel refusé",
code="token_scope_denied",
details={"tool": tool},
)
def resolve_safe_path(vault_root: Path, relative_path: str | None) -> Path:
"""Resolve a vault-relative path, rejecting traversal outside the vault.