CI / lint (push) Successful in 57s
CI / security (push) Successful in 39s
CI / test (push) Failing after 41s
CI / build (push) Skipped
CI / e2e (push) Skipped
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
- backend/tools/: ToolContext, registry @tool + schemas JSON, audit ai_tool_call - Services lecture/recherche: list_vaults, list_directory, read_file, search_fulltext, list_tags - Permissions check_vault_access + resolve_safe_path, confirmation gating (two-step) - Redaction des secrets, limites de taille, audit JSONL (args sensibles resumes) - tests/test_tools.py: 30 tests (registry, contexte, execution, confirmation, audit) - ROADMAP: item #79 phase A livree (A2 partiel)
55 lines
1.5 KiB
Python
55 lines
1.5 KiB
Python
"""Audit logging for AI tool calls.
|
|
|
|
Reuses the application audit log (``data/audit.log``, JSON lines) and adds an
|
|
``ai_tool_call`` action. Argument values that may contain sensitive payloads
|
|
(file content, prompts) are summarized rather than stored verbatim.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
from typing import Any
|
|
|
|
from backend.audit import _write_entry
|
|
|
|
# Argument keys whose values may contain secrets or large payloads.
|
|
_SENSITIVE_ARG_KEYS = {"content", "text", "body"}
|
|
_MAX_ARG_CHARS = 200
|
|
|
|
|
|
def _sanitize_arguments(arguments: dict[str, Any] | None) -> dict[str, Any]:
|
|
"""Return a log-safe view of tool arguments."""
|
|
safe: dict[str, Any] = {}
|
|
for key, value in (arguments or {}).items():
|
|
if key in _SENSITIVE_ARG_KEYS:
|
|
safe[key] = f"<{len(str(value))} chars>"
|
|
else:
|
|
safe[key] = str(value)[:_MAX_ARG_CHARS]
|
|
return safe
|
|
|
|
|
|
def log_tool_call(
|
|
*,
|
|
username: str,
|
|
mode: str,
|
|
tool: str,
|
|
arguments: dict[str, Any] | None = None,
|
|
ok: bool = True,
|
|
vault: str | None = None,
|
|
ip: str | None = None,
|
|
error: str | None = None,
|
|
) -> None:
|
|
"""Append an ``ai_tool_call`` entry to the audit log."""
|
|
_write_entry({
|
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
"action": "ai_tool_call",
|
|
"username": username,
|
|
"ip": ip or "unknown",
|
|
"mode": mode,
|
|
"tool": tool,
|
|
"vault": vault,
|
|
"ok": ok,
|
|
"error": error,
|
|
"arguments": _sanitize_arguments(arguments),
|
|
})
|