feat: implementar audit trail con AuditWriter y emision de eventos
Crea shell/audit/ con Writer que escribe eventos de auditoria a archivo JSONL y opcionalmente a un room Matrix. Integra la emision de eventos en los puntos clave del runtime: - message_received: al recibir cualquier evento Matrix (handler.go) - command_exec: al ejecutar un comando (handler.go) - tool_exec: al ejecutar una tool (tools/registry.go via AuditFunc callback) - llm_request / llm_error: al llamar al LLM (llm.go) El Writer se inicializa en agents/runtime.go si security.audit.enabled=true. Usa patron de inyeccion de dependencias (MatrixSender como funcion, AuditFunc como callback) para evitar acoplamiento entre packages. Incluye tests completos para el Writer: escritura JSONL, filtrado por Include, modo solo-file, modo solo-room, auto-set de timestamp. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,11 +12,16 @@ import (
|
||||
"github.com/enmanuel/agents/shell/logger"
|
||||
)
|
||||
|
||||
// AuditFunc is called after each tool execution for audit purposes.
|
||||
// The registry does not depend on the audit package directly.
|
||||
type AuditFunc func(toolName string, durationMS int64, err error)
|
||||
|
||||
// Registry holds available tools keyed by name.
|
||||
type Registry struct {
|
||||
tools map[string]Tool
|
||||
logger *slog.Logger
|
||||
rateLimiter *RateLimiter // nil when rate limiting is disabled
|
||||
auditFn AuditFunc // nil when audit is disabled
|
||||
}
|
||||
|
||||
// NewRegistry creates an empty registry.
|
||||
@@ -60,6 +65,12 @@ func (r *Registry) SetRateLimiter(rl *RateLimiter) {
|
||||
r.rateLimiter = rl
|
||||
}
|
||||
|
||||
// SetAuditFunc attaches an audit callback to the registry.
|
||||
// When set, it is called after each tool execution.
|
||||
func (r *Registry) SetAuditFunc(fn AuditFunc) {
|
||||
r.auditFn = fn
|
||||
}
|
||||
|
||||
// ExecuteForRoom is like Execute but checks the per-room rate limit first.
|
||||
// If the rate limit is exceeded, it returns an error result without executing.
|
||||
func (r *Registry) ExecuteForRoom(ctx context.Context, name, argsJSON, roomID string) Result {
|
||||
@@ -99,6 +110,11 @@ func (r *Registry) Execute(ctx context.Context, name string, argsJSON string) Re
|
||||
r.logger.Info("tool_exec_end", "tool", name, logger.FieldDurationMS, ms)
|
||||
}
|
||||
|
||||
// Audit callback
|
||||
if r.auditFn != nil {
|
||||
r.auditFn(name, ms, result.Err)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user