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,321 @@
1
+ // Copyright (c) 2026 defconxt. All rights reserved.
2
+ // Licensed under AGPL-3.0 — see LICENSE file for details.
3
+
4
+ /**
5
+ * CIPHER Billing Engine — usage-based metering middleware.
6
+ *
7
+ * Tracks API usage per client via SQLite: request counting,
8
+ * credit consumption, tier enforcement, and quota checks.
9
+ */
10
+
11
+ import { homedir } from 'node:os';
12
+ import { join, dirname } from 'node:path';
13
+ import { mkdirSync } from 'node:fs';
14
+
15
+ /** @type {typeof import('better-sqlite3')} */
16
+ let Database;
17
+
18
+ /** Billing plan tiers. */
19
+ export const BillingTier = Object.freeze({
20
+ FREE: 'free',
21
+ STARTER: 'starter',
22
+ PROFESSIONAL: 'professional',
23
+ ENTERPRISE: 'enterprise',
24
+ });
25
+
26
+ /**
27
+ * Tier limits keyed by BillingTier value.
28
+ * Each entry: { requestsPerHour, scansPerDay, memoryEntries, skillSearchesPerHour,
29
+ * complianceReportsPerDay, marketplaceDownloadsPerDay, maxResponseSizeKb }
30
+ */
31
+ export const TIER_LIMITS = {
32
+ [BillingTier.FREE]: {
33
+ requestsPerHour: 60,
34
+ scansPerDay: 3,
35
+ memoryEntries: 100,
36
+ skillSearchesPerHour: 20,
37
+ complianceReportsPerDay: 1,
38
+ marketplaceDownloadsPerDay: 5,
39
+ maxResponseSizeKb: 256,
40
+ },
41
+ [BillingTier.STARTER]: {
42
+ requestsPerHour: 500,
43
+ scansPerDay: 20,
44
+ memoryEntries: 5000,
45
+ skillSearchesPerHour: 200,
46
+ complianceReportsPerDay: 10,
47
+ marketplaceDownloadsPerDay: 50,
48
+ maxResponseSizeKb: 1024,
49
+ },
50
+ [BillingTier.PROFESSIONAL]: {
51
+ requestsPerHour: 5000,
52
+ scansPerDay: 100,
53
+ memoryEntries: 50000,
54
+ skillSearchesPerHour: 2000,
55
+ complianceReportsPerDay: 50,
56
+ marketplaceDownloadsPerDay: 500,
57
+ maxResponseSizeKb: 4096,
58
+ },
59
+ [BillingTier.ENTERPRISE]: {
60
+ requestsPerHour: 50000,
61
+ scansPerDay: 1000,
62
+ memoryEntries: 500000,
63
+ skillSearchesPerHour: 20000,
64
+ complianceReportsPerDay: 500,
65
+ marketplaceDownloadsPerDay: 5000,
66
+ maxResponseSizeKb: 16384,
67
+ },
68
+ };
69
+
70
+ /** Credit costs per endpoint type. */
71
+ export const ENDPOINT_CREDITS = {
72
+ scan: 10.0,
73
+ diff: 2.0,
74
+ secrets: 2.0,
75
+ 'memory/store': 1.0,
76
+ 'memory/search': 1.0,
77
+ score: 5.0,
78
+ compliance: 5.0,
79
+ workflow: 3.0,
80
+ skills: 0.5,
81
+ 'skills/search': 0.5,
82
+ leaderboard: 0.5,
83
+ health: 0.0,
84
+ stats: 0.0,
85
+ };
86
+
87
+ /**
88
+ * Usage-based billing and metering engine backed by SQLite.
89
+ */
90
+ export class MeteringEngine {
91
+ /**
92
+ * @param {string} [dbPath] - Path to SQLite database file. Default: ~/.cipher/billing.db
93
+ */
94
+ constructor(dbPath) {
95
+ if (!Database) {
96
+ Database = require('better-sqlite3');
97
+ }
98
+ const resolved = dbPath || join(homedir(), '.cipher', 'billing.db');
99
+ mkdirSync(dirname(resolved), { recursive: true });
100
+ this._db = new Database(resolved);
101
+ this._db.pragma('journal_mode = WAL');
102
+ this._clientTiers = new Map();
103
+ this._initDb();
104
+ }
105
+
106
+ _initDb() {
107
+ this._db.exec(`
108
+ CREATE TABLE IF NOT EXISTS usage_events (
109
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
110
+ client_id TEXT NOT NULL,
111
+ endpoint TEXT NOT NULL,
112
+ credits REAL NOT NULL DEFAULT 1.0,
113
+ response_bytes INTEGER DEFAULT 0,
114
+ timestamp REAL NOT NULL,
115
+ metadata TEXT DEFAULT '{}'
116
+ );
117
+ CREATE INDEX IF NOT EXISTS idx_usage_client_ts
118
+ ON usage_events(client_id, timestamp);
119
+ CREATE INDEX IF NOT EXISTS idx_usage_endpoint
120
+ ON usage_events(endpoint, timestamp);
121
+
122
+ CREATE TABLE IF NOT EXISTS client_tiers (
123
+ client_id TEXT PRIMARY KEY,
124
+ tier TEXT NOT NULL DEFAULT 'free',
125
+ created_at REAL NOT NULL,
126
+ updated_at REAL NOT NULL
127
+ );
128
+ `);
129
+ }
130
+
131
+ /**
132
+ * Set or update a client's billing tier.
133
+ * @param {string} clientId
134
+ * @param {string} tier - BillingTier value
135
+ */
136
+ setClientTier(clientId, tier) {
137
+ const now = Date.now() / 1000;
138
+ this._db
139
+ .prepare(
140
+ `INSERT INTO client_tiers (client_id, tier, created_at, updated_at)
141
+ VALUES (?, ?, ?, ?)
142
+ ON CONFLICT(client_id) DO UPDATE SET tier=?, updated_at=?`,
143
+ )
144
+ .run(clientId, tier, now, now, tier, now);
145
+ this._clientTiers.set(clientId, tier);
146
+ }
147
+
148
+ /**
149
+ * Get a client's billing tier.
150
+ * @param {string} clientId
151
+ * @returns {string} BillingTier value
152
+ */
153
+ getClientTier(clientId) {
154
+ if (this._clientTiers.has(clientId)) {
155
+ return this._clientTiers.get(clientId);
156
+ }
157
+ const row = this._db
158
+ .prepare('SELECT tier FROM client_tiers WHERE client_id = ?')
159
+ .get(clientId);
160
+ const tier = row ? row.tier : BillingTier.FREE;
161
+ this._clientTiers.set(clientId, tier);
162
+ return tier;
163
+ }
164
+
165
+ /**
166
+ * Record a usage event.
167
+ * @param {object} record
168
+ * @param {string} record.clientId
169
+ * @param {string} record.endpoint
170
+ * @param {number} [record.timestamp]
171
+ * @param {number} [record.creditsConsumed]
172
+ * @param {number} [record.responseSizeBytes]
173
+ * @param {object} [record.metadata]
174
+ */
175
+ recordUsage(record) {
176
+ const ts = record.timestamp ?? Date.now() / 1000;
177
+ const credits = record.creditsConsumed ?? 1.0;
178
+ this._db
179
+ .prepare(
180
+ `INSERT INTO usage_events (client_id, endpoint, credits, response_bytes, timestamp, metadata)
181
+ VALUES (?, ?, ?, ?, ?, ?)`,
182
+ )
183
+ .run(
184
+ record.clientId,
185
+ record.endpoint,
186
+ credits,
187
+ record.responseSizeBytes ?? 0,
188
+ ts,
189
+ JSON.stringify(record.metadata ?? {}),
190
+ );
191
+ }
192
+
193
+ /**
194
+ * Check if a client has quota remaining for an endpoint.
195
+ * @param {string} clientId
196
+ * @param {string} endpoint
197
+ * @returns {{ allowed: boolean, remaining: number, limit: number, resetsInS: number, reason?: string }}
198
+ */
199
+ checkQuota(clientId, endpoint) {
200
+ const tier = this.getClientTier(clientId);
201
+ const limits = TIER_LIMITS[tier] || TIER_LIMITS[BillingTier.FREE];
202
+ const now = Date.now() / 1000;
203
+ const hourAgo = now - 3600;
204
+ const dayAgo = now - 86400;
205
+
206
+ // Hourly request limit
207
+ const hourlyRow = this._db
208
+ .prepare('SELECT COUNT(*) as cnt FROM usage_events WHERE client_id = ? AND timestamp > ?')
209
+ .get(clientId, hourAgo);
210
+ const hourlyCount = hourlyRow?.cnt ?? 0;
211
+
212
+ if (hourlyCount >= limits.requestsPerHour) {
213
+ return {
214
+ allowed: false,
215
+ remaining: 0,
216
+ limit: limits.requestsPerHour,
217
+ resetsInS: 3600,
218
+ reason: 'hourly request limit exceeded',
219
+ };
220
+ }
221
+
222
+ // Scan-specific daily limit
223
+ if (endpoint === 'scan') {
224
+ const scanRow = this._db
225
+ .prepare(
226
+ "SELECT COUNT(*) as cnt FROM usage_events WHERE client_id = ? AND endpoint = 'scan' AND timestamp > ?",
227
+ )
228
+ .get(clientId, dayAgo);
229
+ const dailyScans = scanRow?.cnt ?? 0;
230
+ if (dailyScans >= limits.scansPerDay) {
231
+ return {
232
+ allowed: false,
233
+ remaining: 0,
234
+ limit: limits.scansPerDay,
235
+ resetsInS: 86400,
236
+ reason: 'daily scan limit exceeded',
237
+ };
238
+ }
239
+ return {
240
+ allowed: true,
241
+ remaining: limits.scansPerDay - dailyScans,
242
+ limit: limits.scansPerDay,
243
+ resetsInS: 86400,
244
+ };
245
+ }
246
+
247
+ return {
248
+ allowed: true,
249
+ remaining: limits.requestsPerHour - hourlyCount,
250
+ limit: limits.requestsPerHour,
251
+ resetsInS: 3600,
252
+ };
253
+ }
254
+
255
+ /**
256
+ * Get usage summary for a client over a time period.
257
+ * @param {string} clientId
258
+ * @param {number} [periodHours=24]
259
+ * @returns {object}
260
+ */
261
+ getUsageSummary(clientId, periodHours = 24) {
262
+ const tier = this.getClientTier(clientId);
263
+ const now = Date.now() / 1000;
264
+ const periodStart = now - periodHours * 3600;
265
+
266
+ const rows = this._db
267
+ .prepare(
268
+ `SELECT endpoint, COUNT(*) as cnt, SUM(credits) as total_credits
269
+ FROM usage_events
270
+ WHERE client_id = ? AND timestamp > ?
271
+ GROUP BY endpoint`,
272
+ )
273
+ .all(clientId, periodStart);
274
+
275
+ const byEndpoint = {};
276
+ let totalRequests = 0;
277
+ let totalCredits = 0;
278
+ let totalScans = 0;
279
+
280
+ for (const row of rows) {
281
+ byEndpoint[row.endpoint] = row.cnt;
282
+ totalRequests += row.cnt;
283
+ totalCredits += row.total_credits;
284
+ if (row.endpoint === 'scan') totalScans = row.cnt;
285
+ }
286
+
287
+ const limits = TIER_LIMITS[tier] || TIER_LIMITS[BillingTier.FREE];
288
+ return {
289
+ clientId,
290
+ tier,
291
+ periodStart,
292
+ periodEnd: now,
293
+ totalRequests,
294
+ totalScans,
295
+ totalCredits,
296
+ byEndpoint,
297
+ quotaRemaining: {
298
+ requestsHourly: Math.max(0, limits.requestsPerHour - totalRequests),
299
+ scansDaily: Math.max(0, limits.scansPerDay - totalScans),
300
+ },
301
+ overage: totalRequests > limits.requestsPerHour,
302
+ };
303
+ }
304
+
305
+ /**
306
+ * Get the credit cost for an endpoint.
307
+ * @param {string} endpoint
308
+ * @returns {number}
309
+ */
310
+ getCreditsForEndpoint(endpoint) {
311
+ for (const [ep, credits] of Object.entries(ENDPOINT_CREDITS)) {
312
+ if (endpoint.endsWith(ep)) return credits;
313
+ }
314
+ return 1.0;
315
+ }
316
+
317
+ /** Close database connection. */
318
+ close() {
319
+ this._db.close();
320
+ }
321
+ }