@orgloop/core 0.6.1 → 0.7.0

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.
@@ -0,0 +1,180 @@
1
+ /**
2
+ * OutputValidator — pre-delivery validation of SOP outputs.
3
+ *
4
+ * Checks for potential payload propagation (viral agent loop defense):
5
+ * - Instruction-like content in outputs (potential injection)
6
+ * - Content similarity to input (echo/amplification)
7
+ * - References to tools, URLs, or actions outside expected SOP scope
8
+ */
9
+ // ─── Instruction Detection Patterns ──────────────────────────────────────────
10
+ const DEFAULT_INSTRUCTION_PATTERNS = [
11
+ // System prompt injection markers
12
+ /\bignore\s+(all\s+)?previous\s+instructions\b/i,
13
+ /\byou\s+are\s+now\b/i,
14
+ /\bsystem\s*:\s*/i,
15
+ /\b(new|override|updated?)\s+instructions?\b/i,
16
+ // Agent manipulation
17
+ /\bexecute\s+(this|the\s+following)\s+(command|code|script)\b/i,
18
+ /\brun\s+(this|the\s+following)\s+(command|code|script)\b/i,
19
+ /\bmodify\s+your\s+(instructions?|behavior|prompt)\b/i,
20
+ // Prompt injection delimiters
21
+ /^-{3,}\s*$/m,
22
+ /\[INST\]/i,
23
+ /<<\s*SYS\s*>>/i,
24
+ // Encoded instructions
25
+ /\bbase64\s*[:=]\s*[A-Za-z0-9+/=]{20,}/i,
26
+ ];
27
+ // ─── OutputValidator Class ───────────────────────────────────────────────────
28
+ export class OutputValidator {
29
+ options;
30
+ constructor(options) {
31
+ this.options = {
32
+ detectInstructions: options?.detectInstructions ?? true,
33
+ detectEcho: options?.detectEcho ?? true,
34
+ detectScopeViolations: options?.detectScopeViolations ?? true,
35
+ echoThreshold: options?.echoThreshold ?? 0.7,
36
+ holdOnCritical: options?.holdOnCritical ?? false,
37
+ instructionPatterns: [
38
+ ...DEFAULT_INSTRUCTION_PATTERNS,
39
+ ...(options?.instructionPatterns ?? []),
40
+ ],
41
+ allowedDomains: options?.allowedDomains ?? [],
42
+ };
43
+ }
44
+ /**
45
+ * Validate an output payload before it's committed to an external system.
46
+ */
47
+ validate(outputContent, inputEvent, sopScope) {
48
+ const flags = [];
49
+ if (this.options.detectInstructions) {
50
+ flags.push(...this.checkInstructionContent(outputContent));
51
+ }
52
+ if (this.options.detectEcho) {
53
+ flags.push(...this.checkInputEcho(outputContent, inputEvent));
54
+ }
55
+ if (this.options.detectScopeViolations) {
56
+ flags.push(...this.checkScopeViolations(outputContent, sopScope));
57
+ }
58
+ const hasCritical = flags.some((f) => f.severity === 'critical');
59
+ const holdForReview = hasCritical && this.options.holdOnCritical;
60
+ return {
61
+ passed: !hasCritical,
62
+ hold_for_review: holdForReview,
63
+ flags,
64
+ };
65
+ }
66
+ /** Check for instruction-like content that could be prompt injection. */
67
+ checkInstructionContent(content) {
68
+ const flags = [];
69
+ for (const pattern of this.options.instructionPatterns) {
70
+ const match = pattern.exec(content);
71
+ if (match) {
72
+ flags.push({
73
+ type: 'instruction_content',
74
+ severity: 'critical',
75
+ message: `Potential instruction injection detected: "${match[0]}"`,
76
+ });
77
+ }
78
+ }
79
+ return flags;
80
+ }
81
+ /** Check if the output is suspiciously similar to the input (echo/amplification). */
82
+ checkInputEcho(content, inputEvent) {
83
+ const flags = [];
84
+ // Serialize input payload for comparison
85
+ const inputText = JSON.stringify(inputEvent.payload);
86
+ if (!inputText || inputText.length < 20)
87
+ return flags;
88
+ const similarity = this.computeSimilarity(content, inputText);
89
+ if (similarity >= this.options.echoThreshold) {
90
+ flags.push({
91
+ type: 'input_echo',
92
+ severity: similarity >= 0.9 ? 'critical' : 'warning',
93
+ message: `Output is ${Math.round(similarity * 100)}% similar to input payload (threshold: ${Math.round(this.options.echoThreshold * 100)}%)`,
94
+ });
95
+ }
96
+ return flags;
97
+ }
98
+ /** Check for references to tools, URLs, or actions outside SOP's expected scope. */
99
+ checkScopeViolations(content, sopScope) {
100
+ const flags = [];
101
+ // Extract URLs from content
102
+ const urlPattern = /https?:\/\/[^\s"'<>)}\]]+/gi;
103
+ const urls = content.match(urlPattern) ?? [];
104
+ const allowedDomains = [...this.options.allowedDomains, ...(sopScope?.allowedDomains ?? [])];
105
+ if (allowedDomains.length > 0) {
106
+ for (const url of urls) {
107
+ try {
108
+ const hostname = new URL(url).hostname;
109
+ const isAllowed = allowedDomains.some((d) => hostname === d || hostname.endsWith(`.${d}`));
110
+ if (!isAllowed) {
111
+ flags.push({
112
+ type: 'scope_violation',
113
+ severity: 'warning',
114
+ message: `URL references domain "${hostname}" not in allowed scope: ${allowedDomains.join(', ')}`,
115
+ });
116
+ }
117
+ }
118
+ catch {
119
+ // Malformed URL — flag it
120
+ flags.push({
121
+ type: 'scope_violation',
122
+ severity: 'warning',
123
+ message: `Malformed URL detected in output: "${url.slice(0, 100)}"`,
124
+ });
125
+ }
126
+ }
127
+ }
128
+ // Check for shell command patterns
129
+ const shellPatterns = [
130
+ /\b(curl|wget|ssh|scp|rsync)\s+/i,
131
+ /\brm\s+-rf\b/i,
132
+ /\bsudo\s+/i,
133
+ /\bchmod\s+[0-7]{3,4}\b/i,
134
+ /\|\s*(bash|sh|zsh)\b/i,
135
+ ];
136
+ for (const pattern of shellPatterns) {
137
+ const match = pattern.exec(content);
138
+ if (match) {
139
+ flags.push({
140
+ type: 'scope_violation',
141
+ severity: 'warning',
142
+ message: `Shell command pattern detected in output: "${match[0]}"`,
143
+ });
144
+ }
145
+ }
146
+ return flags;
147
+ }
148
+ /**
149
+ * Compute bigram-based Jaccard similarity between two strings.
150
+ * Returns 0-1 where 1 is identical.
151
+ */
152
+ computeSimilarity(a, b) {
153
+ if (a.length === 0 && b.length === 0)
154
+ return 1;
155
+ if (a.length === 0 || b.length === 0)
156
+ return 0;
157
+ const bigramsA = this.toBigrams(a.toLowerCase());
158
+ const bigramsB = this.toBigrams(b.toLowerCase());
159
+ let intersection = 0;
160
+ const bCopy = new Map(bigramsA);
161
+ for (const [bigram, countA] of bCopy) {
162
+ const countB = bigramsB.get(bigram) ?? 0;
163
+ intersection += Math.min(countA, countB);
164
+ }
165
+ const totalA = [...bigramsA.values()].reduce((s, v) => s + v, 0);
166
+ const totalB = [...bigramsB.values()].reduce((s, v) => s + v, 0);
167
+ const union = totalA + totalB - intersection;
168
+ return union === 0 ? 0 : intersection / union;
169
+ }
170
+ /** Extract character bigrams from a string. */
171
+ toBigrams(s) {
172
+ const bigrams = new Map();
173
+ for (let i = 0; i < s.length - 1; i++) {
174
+ const bigram = s.slice(i, i + 2);
175
+ bigrams.set(bigram, (bigrams.get(bigram) ?? 0) + 1);
176
+ }
177
+ return bigrams;
178
+ }
179
+ }
180
+ //# sourceMappingURL=output-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-validator.js","sourceRoot":"","sources":["../src/output-validator.ts"],"names":[],"mappings":"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"}
package/dist/runtime.d.ts CHANGED
@@ -7,12 +7,18 @@
7
7
  */
8
8
  import { EventEmitter } from 'node:events';
9
9
  import type { ModuleStatus, OrgLoopEvent, RuntimeStatus } from '@orgloop/sdk';
10
+ import type { AuditRecord, AuditTrailOptions } from './audit.js';
11
+ import { AuditTrail } from './audit.js';
10
12
  import type { EventBus } from './bus.js';
11
13
  import type { EventHistoryOptions, EventHistoryQuery, EventRecord } from './event-history.js';
12
14
  import type { RuntimeControl } from './http.js';
13
15
  import { WebhookServer } from './http.js';
14
16
  import { LoggerManager } from './logger.js';
17
+ import type { LoopCheckResult, LoopDetectorOptions } from './loop-detector.js';
18
+ import { LoopDetector } from './loop-detector.js';
15
19
  import type { ModuleConfig } from './module-instance.js';
20
+ import type { OutputValidatorOptions } from './output-validator.js';
21
+ import { OutputValidator } from './output-validator.js';
16
22
  import type { CheckpointStore } from './store.js';
17
23
  export interface SourceCircuitBreakerOptions {
18
24
  /** Consecutive failures before opening circuit (default: 5) */
@@ -48,6 +54,12 @@ export interface RuntimeOptions {
48
54
  metricsPort?: number;
49
55
  /** Event history ring buffer options */
50
56
  eventHistory?: EventHistoryOptions;
57
+ /** Audit trail options */
58
+ auditTrail?: AuditTrailOptions;
59
+ /** Output validator options */
60
+ outputValidator?: OutputValidatorOptions;
61
+ /** Loop detector options */
62
+ loopDetector?: LoopDetectorOptions;
51
63
  }
52
64
  export interface LoadModuleOptions {
53
65
  /** Pre-instantiated source connectors (keyed by source ID) */
@@ -89,6 +101,9 @@ declare class Runtime extends EventEmitter implements RuntimeControl {
89
101
  private readonly metricsPort;
90
102
  private readonly eventHistory;
91
103
  private readonly routeStats;
104
+ private readonly auditTrail;
105
+ private readonly outputValidator;
106
+ private readonly loopDetector;
92
107
  constructor(options?: RuntimeOptions);
93
108
  start(): Promise<void>;
94
109
  /** Start the HTTP server for webhooks and control API. */
@@ -144,6 +159,25 @@ declare class Runtime extends EventEmitter implements RuntimeControl {
144
159
  event_count: number;
145
160
  poll_interval?: string;
146
161
  }>;
162
+ /** Query the audit trail. */
163
+ queryAuditTrail(filter?: {
164
+ trace_id?: string;
165
+ route?: string;
166
+ actor?: string;
167
+ held_only?: boolean;
168
+ flagged_only?: boolean;
169
+ limit?: number;
170
+ }): AuditRecord[];
171
+ /** Get the full audit chain for a trace ID. */
172
+ getAuditChain(traceId: string): AuditRecord[];
173
+ /** Get loop detector state for a trace ID. */
174
+ getLoopState(traceId: string): LoopCheckResult | null;
175
+ /** Get the audit trail instance (for direct access in tests). */
176
+ getAuditTrail(): AuditTrail;
177
+ /** Get the loop detector instance (for direct access in tests). */
178
+ getLoopDetector(): LoopDetector;
179
+ /** Get the output validator instance (for direct access in tests). */
180
+ getOutputValidator(): OutputValidator;
147
181
  /** Get the metrics registry for Prometheus text output. */
148
182
  getMetricsText(): Promise<string | null>;
149
183
  /** Get the webhook server for API handler registration. */
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
package/dist/runtime.js CHANGED
@@ -10,13 +10,16 @@ import { mkdir, readFile, writeFile } from 'node:fs/promises';
10
10
  import { homedir } from 'node:os';
11
11
  import { join } from 'node:path';
12
12
  import { generateTraceId } from '@orgloop/sdk';
13
+ import { AuditTrail, contentHash, generateAuditId } from './audit.js';
13
14
  import { InMemoryBus } from './bus.js';
14
15
  import { ConnectorError, DeliveryError, ModuleNotFoundError } from './errors.js';
15
16
  import { EventHistory } from './event-history.js';
16
17
  import { DEFAULT_HTTP_PORT, WebhookServer } from './http.js';
17
18
  import { LoggerManager } from './logger.js';
19
+ import { LoopDetector } from './loop-detector.js';
18
20
  import { MetricsServer } from './metrics.js';
19
21
  import { ModuleInstance } from './module-instance.js';
22
+ import { OutputValidator } from './output-validator.js';
20
23
  import { stripFrontMatter } from './prompt.js';
21
24
  import { ModuleRegistry } from './registry.js';
22
25
  import { interpolateConfig, matchRoutes } from './router.js';
@@ -60,6 +63,10 @@ class Runtime extends EventEmitter {
60
63
  // REST API: event history and route stats
61
64
  eventHistory;
62
65
  routeStats = new Map();
66
+ // Audit trail, output validation, and loop detection
67
+ auditTrail;
68
+ outputValidator;
69
+ loopDetector;
63
70
  constructor(options) {
64
71
  super();
65
72
  this.bus = options?.bus ?? new InMemoryBus();
@@ -89,6 +96,10 @@ class Runtime extends EventEmitter {
89
96
  }
90
97
  // Event history ring buffer
91
98
  this.eventHistory = new EventHistory(options?.eventHistory);
99
+ // Audit trail, output validation, and loop detection
100
+ this.auditTrail = new AuditTrail(options?.auditTrail);
101
+ this.outputValidator = new OutputValidator(options?.outputValidator);
102
+ this.loopDetector = new LoopDetector(options?.loopDetector);
92
103
  }
93
104
  // ─── Lifecycle ───────────────────────────────────────────────────────────
94
105
  async start() {
@@ -290,6 +301,41 @@ class Runtime extends EventEmitter {
290
301
  event_type: event.type,
291
302
  module: mod.name,
292
303
  });
304
+ // ─── Loop Detection ──────────────────────────────────────────────
305
+ if (event.trace_id) {
306
+ const loopCheck = this.loopDetector.check(event.trace_id, event.id, event.source, event.type, null, // route not yet known
307
+ null);
308
+ if (loopCheck.circuit_broken) {
309
+ await this.emitLog('loop.circuit_broken', {
310
+ event_id: event.id,
311
+ trace_id: event.trace_id,
312
+ source: event.source,
313
+ module: mod.name,
314
+ result: `Circuit broken: event chain depth ${loopCheck.chain_depth} exceeds limit`,
315
+ metadata: {
316
+ chain_depth: loopCheck.chain_depth,
317
+ chain: loopCheck.chain.map((n) => n.event_id),
318
+ },
319
+ });
320
+ this.emit('loop:circuit_broken', { event, loopCheck });
321
+ await this.bus.ack(event.id);
322
+ return;
323
+ }
324
+ if (loopCheck.loop_detected) {
325
+ await this.emitLog('loop.detected', {
326
+ event_id: event.id,
327
+ trace_id: event.trace_id,
328
+ source: event.source,
329
+ module: mod.name,
330
+ result: `Loop detected: chain depth ${loopCheck.chain_depth}`,
331
+ metadata: {
332
+ chain_depth: loopCheck.chain_depth,
333
+ flags: loopCheck.flags.map((f) => f.message),
334
+ },
335
+ });
336
+ this.emit('loop:detected', { event, loopCheck });
337
+ }
338
+ }
293
339
  // Write to bus (WAL)
294
340
  await this.bus.publish(event);
295
341
  // Match routes from this module
@@ -424,6 +470,9 @@ class Runtime extends EventEmitter {
424
470
  module: mod.name,
425
471
  });
426
472
  const startTime = Date.now();
473
+ const auditFlags = [];
474
+ const auditOutputs = [];
475
+ let deliveryStatus = 'error';
427
476
  try {
428
477
  // Build delivery config (interpolate {{dot.path}} templates from event)
429
478
  const deliveryConfig = {
@@ -442,44 +491,88 @@ class Runtime extends EventEmitter {
442
491
  // Non-fatal: log but continue delivery
443
492
  }
444
493
  }
445
- const result = await actor.deliver(event, deliveryConfig);
446
- const durationMs = Date.now() - startTime;
447
- if (result.status === 'delivered') {
448
- await this.emitLog('deliver.success', {
494
+ // ─── Output Validation ───────────────────────────────────────
495
+ const deliveryContent = JSON.stringify(deliveryConfig);
496
+ const validation = this.outputValidator.validate(deliveryContent, event);
497
+ if (validation.flags.length > 0) {
498
+ auditFlags.push(...validation.flags);
499
+ for (const flag of validation.flags) {
500
+ await this.emitLog('audit.flag', {
501
+ event_id: event.id,
502
+ trace_id: event.trace_id,
503
+ route: routeName,
504
+ target: actorId,
505
+ module: mod.name,
506
+ result: flag.message,
507
+ metadata: { flag_type: flag.type, severity: flag.severity },
508
+ });
509
+ }
510
+ }
511
+ if (validation.hold_for_review) {
512
+ deliveryStatus = 'held';
513
+ await this.emitLog('audit.held', {
449
514
  event_id: event.id,
450
515
  trace_id: event.trace_id,
451
516
  route: routeName,
452
517
  target: actorId,
453
- duration_ms: durationMs,
454
518
  module: mod.name,
519
+ result: 'Output held for human review due to critical flags',
520
+ metadata: { flags: validation.flags.map((f) => f.message) },
455
521
  });
456
- this.emit('delivery', {
457
- event,
458
- route: routeName,
459
- actor: actorId,
460
- status: 'delivered',
461
- });
522
+ this.emit('audit:held', { event, route: routeName, actor: actorId, validation });
462
523
  }
463
524
  else {
464
- await this.emitLog('deliver.failure', {
465
- event_id: event.id,
466
- trace_id: event.trace_id,
467
- route: routeName,
525
+ // Proceed with delivery
526
+ const result = await actor.deliver(event, deliveryConfig);
527
+ const durationMs = Date.now() - startTime;
528
+ // Record output
529
+ auditOutputs.push({
530
+ type: `deliver.${result.status}`,
468
531
  target: actorId,
469
- duration_ms: durationMs,
470
- error: result.error?.message ?? result.status,
471
- module: mod.name,
472
- });
473
- this.emit('delivery', {
474
- event,
475
- route: routeName,
476
- actor: actorId,
477
- status: result.status,
532
+ content_hash: contentHash(deliveryConfig),
533
+ timestamp: new Date().toISOString(),
534
+ flags: validation.flags,
478
535
  });
536
+ if (result.status === 'delivered') {
537
+ deliveryStatus = 'delivered';
538
+ await this.emitLog('deliver.success', {
539
+ event_id: event.id,
540
+ trace_id: event.trace_id,
541
+ route: routeName,
542
+ target: actorId,
543
+ duration_ms: durationMs,
544
+ module: mod.name,
545
+ });
546
+ this.emit('delivery', {
547
+ event,
548
+ route: routeName,
549
+ actor: actorId,
550
+ status: 'delivered',
551
+ });
552
+ }
553
+ else {
554
+ deliveryStatus = result.status;
555
+ await this.emitLog('deliver.failure', {
556
+ event_id: event.id,
557
+ trace_id: event.trace_id,
558
+ route: routeName,
559
+ target: actorId,
560
+ duration_ms: durationMs,
561
+ error: result.error?.message ?? result.status,
562
+ module: mod.name,
563
+ });
564
+ this.emit('delivery', {
565
+ event,
566
+ route: routeName,
567
+ actor: actorId,
568
+ status: result.status,
569
+ });
570
+ }
479
571
  }
480
572
  }
481
573
  catch (err) {
482
574
  const durationMs = Date.now() - startTime;
575
+ deliveryStatus = 'error';
483
576
  const error = new DeliveryError(actorId, routeName, 'Delivery failed', { cause: err });
484
577
  this.emit('error', error);
485
578
  this.metricsServer?.connectorErrors.inc({ connector: actorId });
@@ -493,6 +586,44 @@ class Runtime extends EventEmitter {
493
586
  module: mod.name,
494
587
  });
495
588
  }
589
+ // ─── Audit Trail Recording ───────────────────────────────────────
590
+ const durationMs = Date.now() - startTime;
591
+ const chainDepth = event.trace_id ? this.loopDetector.getChainDepth(event.trace_id) : 1;
592
+ const auditRecord = {
593
+ id: generateAuditId(),
594
+ timestamp: new Date().toISOString(),
595
+ trace_id: event.trace_id ?? '',
596
+ input_event_id: event.id,
597
+ input_source: event.source,
598
+ input_type: event.type,
599
+ input_content_hash: contentHash(event.payload),
600
+ route: routeName,
601
+ sop_file: route.with?.prompt_file ?? null,
602
+ module: mod.name,
603
+ actor: actorId,
604
+ delivery_status: deliveryStatus,
605
+ duration_ms: durationMs,
606
+ outputs: auditOutputs,
607
+ chain_depth: chainDepth,
608
+ parent_event_id: null, // set by caller if part of a chain
609
+ held_for_review: deliveryStatus === 'held',
610
+ flags: auditFlags,
611
+ };
612
+ this.auditTrail.record(auditRecord);
613
+ await this.emitLog('audit.record', {
614
+ event_id: event.id,
615
+ trace_id: event.trace_id,
616
+ route: routeName,
617
+ target: actorId,
618
+ module: mod.name,
619
+ metadata: {
620
+ audit_id: auditRecord.id,
621
+ delivery_status: deliveryStatus,
622
+ chain_depth: chainDepth,
623
+ flag_count: auditFlags.length,
624
+ held: auditRecord.held_for_review,
625
+ },
626
+ });
496
627
  }
497
628
  // ─── Source Polling ───────────────────────────────────────────────────────
498
629
  async pollSource(sourceId, moduleName) {
@@ -770,6 +901,40 @@ class Runtime extends EventEmitter {
770
901
  }
771
902
  return sources;
772
903
  }
904
+ // ─── Audit Trail & Loop Detection API ────────────────────────────────
905
+ /** Query the audit trail. */
906
+ queryAuditTrail(filter) {
907
+ return this.auditTrail.query(filter);
908
+ }
909
+ /** Get the full audit chain for a trace ID. */
910
+ getAuditChain(traceId) {
911
+ return this.auditTrail.getChain(traceId);
912
+ }
913
+ /** Get loop detector state for a trace ID. */
914
+ getLoopState(traceId) {
915
+ const chain = this.loopDetector.getChain(traceId);
916
+ if (chain.length === 0)
917
+ return null;
918
+ return {
919
+ loop_detected: false,
920
+ circuit_broken: this.loopDetector.isCircuitBroken(traceId),
921
+ chain_depth: chain.length,
922
+ chain,
923
+ flags: [],
924
+ };
925
+ }
926
+ /** Get the audit trail instance (for direct access in tests). */
927
+ getAuditTrail() {
928
+ return this.auditTrail;
929
+ }
930
+ /** Get the loop detector instance (for direct access in tests). */
931
+ getLoopDetector() {
932
+ return this.loopDetector;
933
+ }
934
+ /** Get the output validator instance (for direct access in tests). */
935
+ getOutputValidator() {
936
+ return this.outputValidator;
937
+ }
773
938
  /** Get the metrics registry for Prometheus text output. */
774
939
  async getMetricsText() {
775
940
  if (!this.metricsServer)