@kya-os/mcp-i 1.5.9 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * Audit Logging System for MCP-I Runtime
3
3
  *
4
+ * TODO: Update AuditLogger to implement IAuditLogger from @kya-os/mcp-i-core/runtime/audit-logger.
5
+ * Currently using Node.js-specific implementation. This will allow the interface to be used
6
+ * across all platform implementations while maintaining platform-specific crypto implementations.
7
+ *
4
8
  * Handles audit record generation and logging with frozen format
5
9
  * according to requirements 5.4, 5.5, and 6.7 (configurable retention).
6
10
  *
@@ -257,6 +261,38 @@ export interface AuditContext {
257
261
  */
258
262
  scopeId?: string;
259
263
  }
264
+ /**
265
+ * Event context for logging events that bypass session deduplication
266
+ *
267
+ * Used for consent events where multiple events occur in the same session.
268
+ * Unlike AuditContext, this allows multiple events per session.
269
+ */
270
+ export interface AuditEventContext {
271
+ /**
272
+ * Event type identifier
273
+ *
274
+ * @example "consent:page_viewed", "consent:approved", "runtime:initialized"
275
+ */
276
+ eventType: string;
277
+ /**
278
+ * Agent identity
279
+ *
280
+ * Only `did` and `keyId` are logged. Private key is NEVER logged.
281
+ */
282
+ identity: AgentIdentity;
283
+ /**
284
+ * Session context
285
+ *
286
+ * Only `sessionId` and `audience` are logged. Nonce is NEVER logged.
287
+ */
288
+ session: SessionContext;
289
+ /**
290
+ * Optional event-specific data
291
+ *
292
+ * Used for generating event hash. Not logged directly.
293
+ */
294
+ eventData?: Record<string, any>;
295
+ }
260
296
  /**
261
297
  * Audit logger class with event-driven rotation support
262
298
  *
@@ -291,6 +327,23 @@ export declare class AuditLogger {
291
327
  * 4. Triggers rotation hooks if threshold met
292
328
  */
293
329
  logAuditRecord(context: AuditContext): Promise<void>;
330
+ /**
331
+ * Log an event using the frozen audit format WITHOUT session deduplication.
332
+ *
333
+ * Unlike logAuditRecord(), this method ALWAYS logs the event, regardless
334
+ * of whether an event has already been logged for this session. This is
335
+ * necessary for consent events where multiple events occur in the same session.
336
+ *
337
+ * The event still uses the frozen audit.v1 format for consistency, but
338
+ * bypasses the "once per session" constraint.
339
+ *
340
+ * @param context - Event context including eventType, identity, session, and eventData
341
+ */
342
+ logEvent(context: AuditEventContext): Promise<void>;
343
+ /**
344
+ * Generate deterministic hash for event
345
+ */
346
+ private hashEvent;
294
347
  /**
295
348
  * Format audit record as frozen audit line
296
349
  * Format: audit.v1 ts=<unix> session=<id> audience=<host> did=<did> kid=<kid> reqHash=<sha256:..> resHash=<sha256:..> verified=yes|no scope=<scopeId|->
@@ -2,6 +2,10 @@
2
2
  /**
3
3
  * Audit Logging System for MCP-I Runtime
4
4
  *
5
+ * TODO: Update AuditLogger to implement IAuditLogger from @kya-os/mcp-i-core/runtime/audit-logger.
6
+ * Currently using Node.js-specific implementation. This will allow the interface to be used
7
+ * across all platform implementations while maintaining platform-specific crypto implementations.
8
+ *
5
9
  * Handles audit record generation and logging with frozen format
6
10
  * according to requirements 5.4, 5.5, and 6.7 (configurable retention).
7
11
  *
@@ -47,6 +51,7 @@ exports.logKeyRotationAudit = logKeyRotationAudit;
47
51
  exports.parseAuditLine = parseAuditLine;
48
52
  exports.validateAuditRecord = validateAuditRecord;
49
53
  const time_1 = require("./utils/time");
54
+ const crypto_1 = require("crypto");
50
55
  /**
51
56
  * Audit logger class with event-driven rotation support
52
57
  *
@@ -133,6 +138,63 @@ class AuditLogger {
133
138
  // Check if rotation is needed (event-driven)
134
139
  await this.checkRotation();
135
140
  }
141
+ /**
142
+ * Log an event using the frozen audit format WITHOUT session deduplication.
143
+ *
144
+ * Unlike logAuditRecord(), this method ALWAYS logs the event, regardless
145
+ * of whether an event has already been logged for this session. This is
146
+ * necessary for consent events where multiple events occur in the same session.
147
+ *
148
+ * The event still uses the frozen audit.v1 format for consistency, but
149
+ * bypasses the "once per session" constraint.
150
+ *
151
+ * @param context - Event context including eventType, identity, session, and eventData
152
+ */
153
+ async logEvent(context) {
154
+ if (this.destroyed) {
155
+ throw new Error("AuditLogger has been destroyed");
156
+ }
157
+ if (!this.config.enabled) {
158
+ return;
159
+ }
160
+ // Generate event hash
161
+ const eventHash = this.hashEvent(context.eventType, context.eventData);
162
+ // Create audit record (same format as regular audit logs)
163
+ const auditRecord = {
164
+ version: "audit.v1",
165
+ ts: Math.floor(Date.now() / 1000),
166
+ session: context.session.sessionId,
167
+ audience: context.session.audience,
168
+ did: context.identity.did,
169
+ kid: context.identity.kid,
170
+ reqHash: `sha256:${eventHash}`,
171
+ resHash: `sha256:${eventHash}`, // Same hash for events
172
+ verified: "yes",
173
+ scope: context.eventType, // Use eventType as scope
174
+ };
175
+ // Format and log (NO session deduplication check)
176
+ const auditLine = this.formatAuditLine(auditRecord);
177
+ // Track size and count
178
+ const sizeBytes = Buffer.byteLength(auditLine, "utf8");
179
+ this.currentLogSize += sizeBytes;
180
+ this.totalRecordsLogged++;
181
+ // Emit audit record
182
+ this.config.logFunction(auditLine);
183
+ // Check rotation
184
+ await this.checkRotation();
185
+ }
186
+ /**
187
+ * Generate deterministic hash for event
188
+ */
189
+ hashEvent(type, data) {
190
+ const content = JSON.stringify({
191
+ type,
192
+ data,
193
+ ts: Date.now(),
194
+ nonce: (0, crypto_1.randomBytes)(16).toString("hex"),
195
+ });
196
+ return (0, crypto_1.createHash)("sha256").update(content).digest("hex");
197
+ }
136
198
  /**
137
199
  * Format audit record as frozen audit line
138
200
  * Format: audit.v1 ts=<unix> session=<id> audience=<host> did=<did> kid=<kid> reqHash=<sha256:..> resHash=<sha256:..> verified=yes|no scope=<scopeId|->