cipher-security 5.0.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.
Files changed (75) hide show
  1. package/bin/cipher.js +465 -0
  2. package/lib/api/billing.js +321 -0
  3. package/lib/api/compliance.js +693 -0
  4. package/lib/api/controls.js +1401 -0
  5. package/lib/api/index.js +49 -0
  6. package/lib/api/marketplace.js +467 -0
  7. package/lib/api/openai-proxy.js +383 -0
  8. package/lib/api/server.js +685 -0
  9. package/lib/autonomous/feedback-loop.js +554 -0
  10. package/lib/autonomous/framework.js +512 -0
  11. package/lib/autonomous/index.js +97 -0
  12. package/lib/autonomous/leaderboard.js +594 -0
  13. package/lib/autonomous/modes/architect.js +412 -0
  14. package/lib/autonomous/modes/blue.js +386 -0
  15. package/lib/autonomous/modes/incident.js +684 -0
  16. package/lib/autonomous/modes/privacy.js +369 -0
  17. package/lib/autonomous/modes/purple.js +294 -0
  18. package/lib/autonomous/modes/recon.js +250 -0
  19. package/lib/autonomous/parallel.js +587 -0
  20. package/lib/autonomous/researcher.js +583 -0
  21. package/lib/autonomous/runner.js +955 -0
  22. package/lib/autonomous/scheduler.js +615 -0
  23. package/lib/autonomous/task-parser.js +127 -0
  24. package/lib/autonomous/validators/forensic.js +266 -0
  25. package/lib/autonomous/validators/osint.js +216 -0
  26. package/lib/autonomous/validators/privacy.js +296 -0
  27. package/lib/autonomous/validators/purple.js +298 -0
  28. package/lib/autonomous/validators/sigma.js +248 -0
  29. package/lib/autonomous/validators/threat-model.js +363 -0
  30. package/lib/benchmark/agent.js +119 -0
  31. package/lib/benchmark/baselines.js +43 -0
  32. package/lib/benchmark/builder.js +143 -0
  33. package/lib/benchmark/config.js +35 -0
  34. package/lib/benchmark/coordinator.js +91 -0
  35. package/lib/benchmark/index.js +20 -0
  36. package/lib/benchmark/llm.js +58 -0
  37. package/lib/benchmark/models.js +137 -0
  38. package/lib/benchmark/reporter.js +103 -0
  39. package/lib/benchmark/runner.js +103 -0
  40. package/lib/benchmark/sandbox.js +96 -0
  41. package/lib/benchmark/scorer.js +32 -0
  42. package/lib/benchmark/solver.js +166 -0
  43. package/lib/benchmark/tools.js +62 -0
  44. package/lib/bot/bot.js +130 -0
  45. package/lib/commands.js +99 -0
  46. package/lib/complexity.js +377 -0
  47. package/lib/config.js +213 -0
  48. package/lib/gateway/client.js +309 -0
  49. package/lib/gateway/commands.js +830 -0
  50. package/lib/gateway/config-validate.js +109 -0
  51. package/lib/gateway/gateway.js +367 -0
  52. package/lib/gateway/index.js +62 -0
  53. package/lib/gateway/mode.js +309 -0
  54. package/lib/gateway/plugins.js +222 -0
  55. package/lib/gateway/prompt.js +214 -0
  56. package/lib/mcp/server.js +262 -0
  57. package/lib/memory/compressor.js +425 -0
  58. package/lib/memory/engine.js +763 -0
  59. package/lib/memory/evolution.js +668 -0
  60. package/lib/memory/index.js +58 -0
  61. package/lib/memory/orchestrator.js +506 -0
  62. package/lib/memory/retriever.js +515 -0
  63. package/lib/memory/synthesizer.js +333 -0
  64. package/lib/pipeline/async-scanner.js +510 -0
  65. package/lib/pipeline/binary-analysis.js +1043 -0
  66. package/lib/pipeline/dom-xss-scanner.js +435 -0
  67. package/lib/pipeline/github-actions.js +792 -0
  68. package/lib/pipeline/index.js +124 -0
  69. package/lib/pipeline/osint.js +498 -0
  70. package/lib/pipeline/sarif.js +373 -0
  71. package/lib/pipeline/scanner.js +880 -0
  72. package/lib/pipeline/template-manager.js +525 -0
  73. package/lib/pipeline/xss-scanner.js +353 -0
  74. package/lib/setup-wizard.js +229 -0
  75. package/package.json +30 -0
@@ -0,0 +1,58 @@
1
+ // Copyright (c) 2026 defconxt. All rights reserved.
2
+ // Licensed under AGPL-3.0 — see LICENSE file for details.
3
+ // CIPHER is a trademark of defconxt.
4
+
5
+ /**
6
+ * CIPHER Memory Core — Tri-Stage Pipeline + Evolution Engine
7
+ *
8
+ * Public API surface for the memory module. All downstream consumers
9
+ * (gateway, API, MCP) import from this barrel.
10
+ */
11
+
12
+ // Core engine
13
+ export {
14
+ CipherMemory,
15
+ MemoryEntry,
16
+ MemoryType,
17
+ Confidence,
18
+ SymbolicStore,
19
+ MemoryConsolidator,
20
+ reciprocalRankFusion,
21
+ } from './engine.js';
22
+
23
+ // Stage 1: Compressor
24
+ export {
25
+ SemanticCompressor,
26
+ DensityGate,
27
+ DialogueTurn,
28
+ CompressedEntry,
29
+ extractSecurityEntities,
30
+ } from './compressor.js';
31
+
32
+ // Stage 2: Synthesizer
33
+ export {
34
+ SemanticSynthesizer,
35
+ SynthesisResult,
36
+ } from './synthesizer.js';
37
+
38
+ // Stage 3: Retriever
39
+ export {
40
+ AdaptiveRetriever,
41
+ IntentClassifier,
42
+ QueryDecomposer,
43
+ ContextBuilder,
44
+ RetrievalPlan,
45
+ } from './retriever.js';
46
+
47
+ // Evolution
48
+ export {
49
+ ResponseScorer,
50
+ SkillEvolver,
51
+ ScoredResponse,
52
+ } from './evolution.js';
53
+
54
+ // Orchestrator
55
+ export {
56
+ CipherOrchestrator,
57
+ createOrchestrator,
58
+ } from './orchestrator.js';
@@ -0,0 +1,506 @@
1
+ // Copyright (c) 2026 defconxt. All rights reserved.
2
+ // Licensed under AGPL-3.0 — see LICENSE file for details.
3
+ // CIPHER is a trademark of defconxt.
4
+
5
+ /**
6
+ * CIPHER Memory — Session Orchestrator
7
+ *
8
+ * Ties together the 3-stage memory pipeline + evolution engine:
9
+ * Stage 1: SemanticCompressor (dialogue → atomic entries)
10
+ * Stage 2: SemanticSynthesizer (dedup, merge, link)
11
+ * Stage 3: AdaptiveRetriever (intent-aware search + context building)
12
+ * Evolution: ResponseScorer + SkillEvolver (learn from failures)
13
+ *
14
+ * Manages the full session lifecycle:
15
+ * startSession → recordTurn / recordToolUse / scoreResponse → stopSession
16
+ *
17
+ * Ported from Python memory/core/orchestrator.py.
18
+ */
19
+
20
+ import { randomUUID } from 'node:crypto';
21
+ import { join } from 'node:path';
22
+ import { homedir } from 'node:os';
23
+
24
+ import { CipherMemory, MemoryEntry, MemoryType, Confidence } from './engine.js';
25
+ import { SemanticCompressor, CompressedEntry, DialogueTurn } from './compressor.js';
26
+ import { SemanticSynthesizer } from './synthesizer.js';
27
+ import { AdaptiveRetriever, ContextBuilder } from './retriever.js';
28
+ import { ResponseScorer, SkillEvolver } from './evolution.js';
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Session data structures
32
+ // ---------------------------------------------------------------------------
33
+
34
+ /**
35
+ * Create a new SessionState object.
36
+ * @param {{ sessionId: string, engagementId: string, startedAt: string }} opts
37
+ * @returns {object}
38
+ */
39
+ function createSessionState(opts) {
40
+ return {
41
+ sessionId: opts.sessionId,
42
+ engagementId: opts.engagementId,
43
+ startedAt: opts.startedAt,
44
+ turns: [],
45
+ scoredResponses: [],
46
+ entriesStored: 0,
47
+ active: true,
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Create a SessionReport from processing results.
53
+ * @param {object} opts
54
+ * @returns {object}
55
+ */
56
+ function createSessionReport(opts) {
57
+ return {
58
+ sessionId: opts.sessionId ?? '',
59
+ engagementId: opts.engagementId ?? '',
60
+ durationSeconds: opts.durationSeconds ?? 0,
61
+ turnsRecorded: opts.turnsRecorded ?? 0,
62
+ entriesStored: opts.entriesStored ?? 0,
63
+ entriesDeduplicated: opts.entriesDeduplicated ?? 0,
64
+ entriesMerged: opts.entriesMerged ?? 0,
65
+ evolutionTriggered: opts.evolutionTriggered ?? false,
66
+ skillsGenerated: opts.skillsGenerated ?? 0,
67
+ memoryStats: opts.memoryStats ?? {},
68
+ };
69
+ }
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // MemoryType / Confidence value lookup helpers
73
+ // ---------------------------------------------------------------------------
74
+
75
+ /** Set of valid MemoryType values for fast lookup. */
76
+ const _VALID_MEMORY_TYPES = new Set(Object.values(MemoryType));
77
+
78
+ /** Set of valid Confidence values for fast lookup. */
79
+ const _VALID_CONFIDENCE = new Set(Object.values(Confidence));
80
+
81
+ /**
82
+ * Resolve a string to a MemoryType value, defaulting to NOTE if invalid.
83
+ * @param {string} value
84
+ * @returns {string}
85
+ */
86
+ function _resolveMemoryType(value) {
87
+ return _VALID_MEMORY_TYPES.has(value) ? value : MemoryType.NOTE;
88
+ }
89
+
90
+ /**
91
+ * Resolve a string to a Confidence value, defaulting to CONFIRMED if invalid.
92
+ * @param {string} value
93
+ * @returns {string}
94
+ */
95
+ function _resolveConfidence(value) {
96
+ return _VALID_CONFIDENCE.has(value) ? value : Confidence.CONFIRMED;
97
+ }
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // CipherOrchestrator
101
+ // ---------------------------------------------------------------------------
102
+
103
+ /**
104
+ * Full session lifecycle orchestrator for CIPHER memory.
105
+ *
106
+ * Usage:
107
+ * const orch = new CipherOrchestrator({ memoryDir: '/tmp/mem' });
108
+ * const ctx = orch.startSession('ENG-001', 'Pentest of ACME Corp');
109
+ * orch.recordTurn(ctx.sessionId, 'user', 'Scan 10.10.14.5 for open ports');
110
+ * orch.recordTurn(ctx.sessionId, 'assistant', 'Found ports 22, 80, 443...');
111
+ * orch.recordToolUse(ctx.sessionId, 'nmap', '-sV 10.10.14.5', '22/tcp ssh...');
112
+ * orch.scoreResponse(ctx.sessionId, query, response, 'RED');
113
+ * const report = await orch.stopSession(ctx.sessionId);
114
+ * orch.close();
115
+ */
116
+ class CipherOrchestrator {
117
+ /**
118
+ * @param {{
119
+ * memoryDir?: string,
120
+ * skillsDir?: string,
121
+ * llmClient?: any,
122
+ * enableEvolution?: boolean,
123
+ * evolutionThreshold?: number,
124
+ * contextTokens?: number,
125
+ * }} opts
126
+ */
127
+ constructor(opts = {}) {
128
+ const {
129
+ memoryDir,
130
+ skillsDir = 'skills',
131
+ llmClient = null,
132
+ enableEvolution = true,
133
+ evolutionThreshold = 0.4,
134
+ contextTokens = 4000,
135
+ } = opts;
136
+
137
+ if (!memoryDir) {
138
+ throw new Error('CipherOrchestrator requires memoryDir');
139
+ }
140
+
141
+ // Core memory engine
142
+ this.memory = new CipherMemory(memoryDir);
143
+
144
+ // Stage 1: Compressor
145
+ this.compressor = new SemanticCompressor({ llmClient });
146
+
147
+ // Stage 2: Synthesizer
148
+ this.synthesizer = new SemanticSynthesizer();
149
+
150
+ // Stage 3: Retriever
151
+ this.retriever = new AdaptiveRetriever(this.memory, {
152
+ enableReflection: true,
153
+ });
154
+
155
+ // Context builder
156
+ this.contextBuilder = new ContextBuilder({ maxTokens: contextTokens });
157
+
158
+ // Evolution engine
159
+ this.scorer = new ResponseScorer({ llmClient });
160
+ this.evolver = enableEvolution
161
+ ? new SkillEvolver({
162
+ skillsDir,
163
+ llmClient,
164
+ historyPath: join(memoryDir, 'evolution_history.jsonl'),
165
+ })
166
+ : null;
167
+ this.evolutionThreshold = evolutionThreshold;
168
+
169
+ // Active sessions
170
+ this._sessions = new Map();
171
+ }
172
+
173
+ // -------------------------------------------------------------------------
174
+ // Session lifecycle
175
+ // -------------------------------------------------------------------------
176
+
177
+ /**
178
+ * Start a new memory session.
179
+ *
180
+ * Automatically retrieves and injects context from previous sessions
181
+ * for the same engagement.
182
+ *
183
+ * @param {string} [engagementId='']
184
+ * @param {string} [userPrompt='']
185
+ * @returns {{ sessionId: string, engagementId: string, context: string, contextEntries: number }}
186
+ */
187
+ startSession(engagementId = '', userPrompt = '') {
188
+ const sessionId = randomUUID();
189
+ const now = new Date().toISOString();
190
+
191
+ const effectiveEngagement = engagementId || `session-${sessionId.slice(0, 8)}`;
192
+
193
+ const state = createSessionState({
194
+ sessionId,
195
+ engagementId: effectiveEngagement,
196
+ startedAt: now,
197
+ });
198
+ this._sessions.set(sessionId, state);
199
+
200
+ // Retrieve context from previous sessions
201
+ let context = '';
202
+ if (userPrompt || engagementId) {
203
+ const query = userPrompt || `engagement ${engagementId}`;
204
+ const entries = this.retriever.retrieve(query, engagementId, 20);
205
+ if (entries.length > 0) {
206
+ context = this.contextBuilder.build(entries, query);
207
+ }
208
+ }
209
+
210
+ return {
211
+ sessionId,
212
+ engagementId: effectiveEngagement,
213
+ context,
214
+ contextEntries: context ? context.split('\n').length : 0,
215
+ };
216
+ }
217
+
218
+ /**
219
+ * Record a dialogue turn in the session.
220
+ * @param {string} sessionId
221
+ * @param {string} role
222
+ * @param {string} content
223
+ * @param {string} [timestamp='']
224
+ * @returns {boolean}
225
+ */
226
+ recordTurn(sessionId, role, content, timestamp = '') {
227
+ const state = this._sessions.get(sessionId);
228
+ if (!state || !state.active) {
229
+ return false;
230
+ }
231
+
232
+ const turn = new DialogueTurn({
233
+ turnId: state.turns.length + 1,
234
+ role,
235
+ content,
236
+ timestamp: timestamp || new Date().toISOString(),
237
+ });
238
+ state.turns.push(turn);
239
+ return true;
240
+ }
241
+
242
+ /**
243
+ * Record a tool use event in the session.
244
+ * @param {string} sessionId
245
+ * @param {string} toolName
246
+ * @param {string} toolInput
247
+ * @param {string} toolOutput
248
+ * @returns {boolean}
249
+ */
250
+ recordToolUse(sessionId, toolName, toolInput, toolOutput) {
251
+ const state = this._sessions.get(sessionId);
252
+ if (!state || !state.active) {
253
+ return false;
254
+ }
255
+
256
+ const turn = new DialogueTurn({
257
+ turnId: state.turns.length + 1,
258
+ role: 'tool',
259
+ content: `Used ${toolName}: ${toolInput}`,
260
+ toolName,
261
+ toolOutput,
262
+ timestamp: new Date().toISOString(),
263
+ });
264
+ state.turns.push(turn);
265
+ return true;
266
+ }
267
+
268
+ /**
269
+ * Score a response and track for evolution.
270
+ * @param {string} sessionId
271
+ * @param {string} query
272
+ * @param {string} response
273
+ * @param {string} [mode='']
274
+ * @param {string} [skillUsed='']
275
+ * @returns {import('./evolution.js').ScoredResponse}
276
+ */
277
+ scoreResponse(sessionId, query, response, mode = '', skillUsed = '') {
278
+ const scored = this.scorer.score(query, response, mode, skillUsed);
279
+
280
+ const state = this._sessions.get(sessionId);
281
+ if (state) {
282
+ state.scoredResponses.push(scored);
283
+ }
284
+
285
+ return scored;
286
+ }
287
+
288
+ // -------------------------------------------------------------------------
289
+ // Session finalization (async — compressor.compress is async)
290
+ // -------------------------------------------------------------------------
291
+
292
+ /**
293
+ * Finalize session: compress, synthesize, store, and optionally evolve.
294
+ *
295
+ * This is the main processing step that converts dialogue into
296
+ * persistent memory entries.
297
+ *
298
+ * @param {string} sessionId
299
+ * @returns {Promise<object>} SessionReport
300
+ */
301
+ async stopSession(sessionId) {
302
+ const state = this._sessions.get(sessionId);
303
+ if (!state) {
304
+ throw new Error(`Session not found: ${sessionId}`);
305
+ }
306
+
307
+ state.active = false;
308
+ const started = new Date(state.startedAt);
309
+ const duration = (Date.now() - started.getTime()) / 1000;
310
+
311
+ // Stage 1: Compress dialogue into atomic entries
312
+ const compressed = await this.compressor.compress(
313
+ state.turns,
314
+ state.engagementId,
315
+ );
316
+
317
+ // Stage 2: Synthesize with existing memory
318
+ const existing = this.memory.getEngagementContext(state.engagementId);
319
+ const existingCompressed = existing.map(
320
+ (e) =>
321
+ new CompressedEntry({
322
+ entryId: e.entryId,
323
+ losslessRestatement: e.content,
324
+ memoryType: e.memoryType,
325
+ targets: e.targets,
326
+ cveIds: e.cveIds,
327
+ mitreAttack: e.mitreAttack,
328
+ keywords: e.keywords,
329
+ }),
330
+ );
331
+ const synthesis = this.synthesizer.synthesize(compressed, existingCompressed);
332
+
333
+ // Store new entries
334
+ let stored = 0;
335
+ for (const entry of synthesis.newEntries) {
336
+ const memEntry = new MemoryEntry({
337
+ entryId: entry.entryId,
338
+ content: entry.losslessRestatement,
339
+ memoryType: _resolveMemoryType(entry.memoryType),
340
+ confidence: _resolveConfidence(entry.confidence),
341
+ engagementId: entry.engagementId,
342
+ sourceSkill: entry.sourceSkill,
343
+ timestamp: entry.timestamp,
344
+ targets: entry.targets,
345
+ mitreAttack: entry.mitreAttack,
346
+ cveIds: entry.cveIds,
347
+ severity: entry.severity,
348
+ keywords: entry.keywords,
349
+ });
350
+ this.memory.store(memEntry);
351
+ stored++;
352
+ }
353
+
354
+ // Update merged entries
355
+ for (const merged of synthesis.mergedEntries) {
356
+ const memEntry = new MemoryEntry({
357
+ entryId: merged.entryId,
358
+ content: merged.losslessRestatement,
359
+ memoryType: _resolveMemoryType(merged.memoryType),
360
+ engagementId: merged.engagementId,
361
+ targets: merged.targets,
362
+ mitreAttack: merged.mitreAttack,
363
+ cveIds: merged.cveIds,
364
+ keywords: merged.keywords,
365
+ });
366
+ this.memory.store(memEntry);
367
+ }
368
+
369
+ state.entriesStored = stored;
370
+
371
+ // Evolution check
372
+ let evolutionTriggered = false;
373
+ let skillsGenerated = 0;
374
+ if (this.evolver && state.scoredResponses.length > 0) {
375
+ const failed = state.scoredResponses.filter((r) => r.score <= 0);
376
+ if (this.evolver.shouldEvolve(state.scoredResponses, this.evolutionThreshold)) {
377
+ const generated = this.evolver.evolve(failed);
378
+ skillsGenerated = generated.length;
379
+ evolutionTriggered = true;
380
+ }
381
+ }
382
+
383
+ // Memory maintenance
384
+ this.memory.consolidate();
385
+
386
+ const report = createSessionReport({
387
+ sessionId,
388
+ engagementId: state.engagementId,
389
+ durationSeconds: duration,
390
+ turnsRecorded: state.turns.length,
391
+ entriesStored: stored,
392
+ entriesDeduplicated: synthesis.stats.deduplicated ?? 0,
393
+ entriesMerged: synthesis.stats.merged ?? 0,
394
+ evolutionTriggered,
395
+ skillsGenerated,
396
+ memoryStats: this.memory.stats(),
397
+ });
398
+
399
+ return report;
400
+ }
401
+
402
+ // -------------------------------------------------------------------------
403
+ // Search & context
404
+ // -------------------------------------------------------------------------
405
+
406
+ /**
407
+ * Search memory with intent-aware retrieval.
408
+ * @param {string} query
409
+ * @param {string} [engagementId='']
410
+ * @param {number} [limit=10]
411
+ * @returns {MemoryEntry[]}
412
+ */
413
+ search(query, engagementId = '', limit = 10) {
414
+ return this.retriever.retrieve(query, engagementId, limit);
415
+ }
416
+
417
+ /**
418
+ * Get formatted context for prompt injection.
419
+ * @param {string} query
420
+ * @param {string} [engagementId='']
421
+ * @param {number} [maxTokens=4000]
422
+ * @returns {string}
423
+ */
424
+ getContext(query, engagementId = '', maxTokens = 4000) {
425
+ const entries = this.retriever.retrieve(query, engagementId);
426
+ const builder = new ContextBuilder({ maxTokens });
427
+ return builder.build(entries, query);
428
+ }
429
+
430
+ // -------------------------------------------------------------------------
431
+ // Diagnostics
432
+ // -------------------------------------------------------------------------
433
+
434
+ /**
435
+ * Get orchestrator statistics.
436
+ * @returns {{ memory: object, evolution: object, active_sessions: number }}
437
+ */
438
+ stats() {
439
+ const memoryStats = this.memory.stats();
440
+ const evolutionStats = this.evolver ? this.evolver.getSummary() : {};
441
+ return {
442
+ memory: memoryStats,
443
+ evolution: evolutionStats,
444
+ active_sessions: [...this._sessions.values()].filter((s) => s.active).length,
445
+ };
446
+ }
447
+
448
+ /**
449
+ * Clean up session state without closing memory.
450
+ * @param {string} sessionId
451
+ */
452
+ endSession(sessionId) {
453
+ this._sessions.delete(sessionId);
454
+ }
455
+
456
+ /**
457
+ * Clean up all resources.
458
+ */
459
+ close() {
460
+ this.memory.close();
461
+ this._sessions.clear();
462
+ }
463
+ }
464
+
465
+ // ---------------------------------------------------------------------------
466
+ // Factory function
467
+ // ---------------------------------------------------------------------------
468
+
469
+ /**
470
+ * Factory function to create a configured CipherOrchestrator.
471
+ *
472
+ * @param {{
473
+ * project?: string,
474
+ * memoryDir?: string,
475
+ * skillsDir?: string,
476
+ * [key: string]: any,
477
+ * }} opts
478
+ * @returns {CipherOrchestrator}
479
+ */
480
+ function createOrchestrator(opts = {}) {
481
+ const {
482
+ project = 'cipher',
483
+ memoryDir,
484
+ skillsDir = 'skills',
485
+ ...rest
486
+ } = opts;
487
+
488
+ const effectiveDir = memoryDir || join(homedir(), '.cipher', 'memory', project);
489
+
490
+ return new CipherOrchestrator({
491
+ memoryDir: effectiveDir,
492
+ skillsDir,
493
+ ...rest,
494
+ });
495
+ }
496
+
497
+ // ---------------------------------------------------------------------------
498
+ // Exports
499
+ // ---------------------------------------------------------------------------
500
+
501
+ export {
502
+ CipherOrchestrator,
503
+ createOrchestrator,
504
+ createSessionState,
505
+ createSessionReport,
506
+ };