feat(tess): add safe runtime observability
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
Jarvis
2026-07-12 19:50:11 -05:00
parent 7b9f40d3b7
commit 53f5414131
12 changed files with 391 additions and 24 deletions

View File

@@ -0,0 +1,86 @@
import { createHash } from 'node:crypto';
import type { NewAgentLog } from './agent-logs.js';
export type RuntimeAuditOperation =
| 'session.list'
| 'session.tree'
| 'session.stream'
| 'session.send'
| 'session.attach'
| 'session.terminate'
| 'runtime.capabilities'
| 'runtime.health';
export type RuntimeAuditOutcome = 'requested' | 'succeeded' | 'denied' | 'failed';
export type RuntimeAuditErrorCode = 'policy_denied' | 'provider_error';
/**
* Deliberately metadata-only runtime audit record. It has no fields for message
* content, credentials, approval references, tool arguments, or tool output.
*/
export interface RuntimeAuditEvent {
providerId: string;
operation: RuntimeAuditOperation;
outcome: RuntimeAuditOutcome;
actorId: string;
tenantId: string;
channelId: string;
correlationId: string;
resourceId?: string;
durationMs?: number;
errorCode?: RuntimeAuditErrorCode;
}
const SAFE_IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
function safeIdentifier(value: string): string {
if (SAFE_IDENTIFIER.test(value)) return value;
return hashIdentifier(value);
}
function hashIdentifier(value: string): string {
return `sha256:${createHash('sha256').update(value).digest('hex')}`;
}
/**
* Converts a typed audit event into a durable log entry using an explicit
* allowlist. Values that could carry credentials or untrusted content are
* rejected before persistence or structured log emission.
*/
export function createRuntimeAuditLogEntry(event: RuntimeAuditEvent): NewAgentLog {
const providerId = safeIdentifier(event.providerId);
const actorId = safeIdentifier(event.actorId);
const tenantId = safeIdentifier(event.tenantId);
const channelId = safeIdentifier(event.channelId);
const correlationId = safeIdentifier(event.correlationId);
// Provider resource identifiers may be opaque or user-derived, so never persist them raw.
const resourceId = event.resourceId ? hashIdentifier(event.resourceId) : undefined;
const persistedUserId = SAFE_IDENTIFIER.test(event.actorId) ? event.actorId : null;
if (
event.durationMs !== undefined &&
(!Number.isInteger(event.durationMs) || event.durationMs < 0)
) {
throw new Error('Runtime audit duration must be a non-negative integer');
}
return {
sessionId: `runtime:${providerId}`,
userId: persistedUserId,
level: event.outcome === 'failed' ? 'error' : event.outcome === 'denied' ? 'warn' : 'info',
category: event.operation.startsWith('session.') ? 'tool_use' : 'general',
content: 'runtime.provider.audit',
metadata: {
providerId,
operation: event.operation,
outcome: event.outcome,
actorId,
tenantId,
channelId,
correlationId,
...(resourceId ? { resourceId } : {}),
...(event.durationMs !== undefined ? { durationMs: event.durationMs } : {}),
...(event.errorCode ? { errorCode: event.errorCode } : {}),
},
};
}