thuban 0.3.3 → 0.3.4

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 (66) hide show
  1. package/dist/LICENSE +21 -0
  2. package/dist/README.md +185 -0
  3. package/dist/cli.js +2 -0
  4. package/dist/packages/scanner/ai-confidence-scorer.js +1 -0
  5. package/dist/packages/scanner/alert-manager.js +1 -0
  6. package/dist/packages/scanner/baseline-manager.js +1 -0
  7. package/dist/packages/scanner/code-scanner.js +1 -0
  8. package/dist/packages/scanner/codebase-passport.js +1 -0
  9. package/dist/packages/scanner/copy-paste-detector.js +1 -0
  10. package/dist/packages/scanner/dependency-graph.js +1 -0
  11. package/dist/packages/scanner/drift-detector.js +1 -0
  12. package/dist/packages/scanner/executive-report.js +1 -0
  13. package/dist/packages/scanner/file-collector.js +1 -0
  14. package/dist/packages/scanner/file-watcher.js +1 -0
  15. package/dist/packages/scanner/ghost-code-detector.js +1 -0
  16. package/dist/packages/scanner/hallucination-detector.js +1 -0
  17. package/dist/packages/scanner/health-checker.js +1 -0
  18. package/dist/packages/scanner/html-report.js +1 -0
  19. package/dist/packages/scanner/index.js +1 -0
  20. package/dist/packages/scanner/license-manager.js +1 -0
  21. package/dist/packages/scanner/master-health-checker.js +1 -0
  22. package/dist/packages/scanner/monitor-notifier.js +1 -0
  23. package/dist/packages/scanner/monitor-service.js +1 -0
  24. package/dist/packages/scanner/monitor-store.js +1 -0
  25. package/dist/packages/scanner/pre-commit-gate.js +1 -0
  26. package/dist/packages/scanner/scan-diff.js +1 -0
  27. package/dist/packages/scanner/scan-runner.js +1 -0
  28. package/dist/packages/scanner/secret-scanner.js +1 -0
  29. package/dist/packages/scanner/sentinel-core.js +1 -0
  30. package/dist/packages/scanner/sentinel-knowledge.js +1 -0
  31. package/dist/packages/scanner/tech-debt-analyzer.js +1 -0
  32. package/dist/packages/scanner/tech-debt-cost.js +1 -0
  33. package/dist/packages/scanner/widget-generator.js +1 -0
  34. package/package.json +12 -7
  35. package/cli.js +0 -2627
  36. package/packages/scanner/ai-confidence-scorer.js +0 -260
  37. package/packages/scanner/alert-manager.js +0 -398
  38. package/packages/scanner/baseline-manager.js +0 -109
  39. package/packages/scanner/code-scanner.js +0 -758
  40. package/packages/scanner/codebase-passport.js +0 -299
  41. package/packages/scanner/copy-paste-detector.js +0 -276
  42. package/packages/scanner/dependency-graph.js +0 -541
  43. package/packages/scanner/drift-detector.js +0 -423
  44. package/packages/scanner/executive-report.js +0 -774
  45. package/packages/scanner/file-collector.js +0 -64
  46. package/packages/scanner/file-watcher.js +0 -323
  47. package/packages/scanner/ghost-code-detector.js +0 -301
  48. package/packages/scanner/hallucination-detector.js +0 -822
  49. package/packages/scanner/health-checker.js +0 -586
  50. package/packages/scanner/html-report.js +0 -634
  51. package/packages/scanner/index.js +0 -100
  52. package/packages/scanner/license-manager.js +0 -331
  53. package/packages/scanner/master-health-checker.js +0 -513
  54. package/packages/scanner/monitor-notifier.js +0 -64
  55. package/packages/scanner/monitor-service.js +0 -103
  56. package/packages/scanner/monitor-store.js +0 -117
  57. package/packages/scanner/pre-commit-gate.js +0 -216
  58. package/packages/scanner/scan-diff.js +0 -50
  59. package/packages/scanner/scan-runner.js +0 -172
  60. package/packages/scanner/secret-scanner.js +0 -612
  61. package/packages/scanner/secret-scanner.test.js +0 -103
  62. package/packages/scanner/sentinel-core.js +0 -616
  63. package/packages/scanner/sentinel-knowledge.js +0 -322
  64. package/packages/scanner/tech-debt-analyzer.js +0 -583
  65. package/packages/scanner/tech-debt-cost.js +0 -194
  66. package/packages/scanner/widget-generator.js +0 -415
@@ -1,100 +0,0 @@
1
- /**
2
- * Index
3
- *
4
- * @purpose Exports: Core, SentinelCore, createSentinel, getSentinel, Components
5
- * @module sentinel
6
- * @layer application
7
- * @imports-from sentinel/sentinel-core.js, sentinel/file-watcher.js, sentinel/code-scanner.js, sentinel/drift-detector.js, sentinel/health-checker.js, sentinel/alert-manager.js, sentinel/dependency-graph.js, sentinel/widget-generator.js
8
- * @side-effects None detected
9
- */
10
-
11
- /**
12
- * Sentinel - Codebase Monitoring System
13
- *
14
- * Main entry point for the Sentinel module.
15
- * Provides codebase monitoring, code scanning, drift detection,
16
- * health checking, and alerting for Orion OS.
17
- *
18
- * Future: Will be spun out as Thuban SaaS
19
- */
20
-
21
- const { SentinelCore, createSentinel } = require('./sentinel-core.js');
22
- const FileWatcher = require('./file-watcher.js');
23
- const CodeScanner = require('./code-scanner.js');
24
- const DriftDetector = require('./drift-detector.js');
25
- const HealthChecker = require('./health-checker.js');
26
- const AlertManager = require('./alert-manager.js');
27
- const DependencyGraph = require('./dependency-graph.js');
28
- const WidgetGenerator = require('./widget-generator.js');
29
- const SentinelKnowledge = require('./sentinel-knowledge.js');
30
- const SecretScanner = require('./secret-scanner.js');
31
-
32
- // Singleton instance for the Orion codebase
33
- let sentinelInstance = null;
34
-
35
- /**
36
- * Get or create the Sentinel instance
37
- */
38
- function getSentinel(options = {}) {
39
- if (!sentinelInstance) {
40
- sentinelInstance = createSentinel(options);
41
- }
42
- return sentinelInstance;
43
- }
44
-
45
- /**
46
- * Quick scan - scan specific files without full initialization
47
- */
48
- async function quickScan(filePaths, options = {}) {
49
- const scanner = new CodeScanner(options);
50
- return scanner.scanFiles(filePaths);
51
- }
52
-
53
- /**
54
- * Quick health check - check system health without full initialization
55
- */
56
- async function quickHealthCheck(options = {}) {
57
- const checker = new HealthChecker(options);
58
- return checker.checkAll();
59
- }
60
-
61
- /**
62
- * Quick drift check - check for drift on specific files
63
- */
64
- async function quickDriftCheck(filePaths, options = {}) {
65
- const detector = new DriftDetector(options);
66
- const results = [];
67
- for (const file of filePaths) {
68
- results.push(await detector.analyzeFile(file));
69
- }
70
- return results;
71
- }
72
-
73
- async function quickSecretScan(filePaths, options = {}) {
74
- const scanner = new SecretScanner(options);
75
- return scanner.scanFiles(filePaths);
76
- }
77
-
78
- module.exports = {
79
- // Core
80
- SentinelCore,
81
- createSentinel,
82
- getSentinel,
83
-
84
- // Components
85
- FileWatcher,
86
- CodeScanner,
87
- DriftDetector,
88
- HealthChecker,
89
- AlertManager,
90
- DependencyGraph,
91
- WidgetGenerator,
92
- SentinelKnowledge,
93
- SecretScanner,
94
-
95
- // Quick utilities
96
- quickScan,
97
- quickHealthCheck,
98
- quickDriftCheck,
99
- quickSecretScan
100
- };
@@ -1,331 +0,0 @@
1
- /**
2
- * Thuban License Manager
3
- *
4
- * @purpose Machine fingerprinting, usage tracking, license key validation, tier gating
5
- * @module thuban
6
- * @layer core
7
- * @exports-to cli
8
- * @critical-for Revenue protection — gates features by tier
9
- */
10
-
11
- const fs = require('fs');
12
- const path = require('path');
13
- const os = require('os');
14
- const crypto = require('crypto');
15
-
16
- const THUBAN_DIR = path.join(os.homedir(), '.thuban');
17
- const USAGE_FILE = path.join(THUBAN_DIR, 'usage.json');
18
- const LICENSE_FILE = path.join(THUBAN_DIR, 'license.json');
19
-
20
- // Tier definitions
21
- const TIERS = {
22
- free: {
23
- name: 'Free',
24
- maxFiles: 100,
25
- scansPerMonth: 5,
26
- showFullDetails: false,
27
- showDashboard: false,
28
- showAutoFix: false,
29
- showCIAction: false,
30
- teaserIssues: 3, // Show 3 real examples, hide the rest
31
- maxHallucinationDetail: 3, // Show top 3, hide rest
32
- },
33
- pro: {
34
- name: 'Pro',
35
- maxFiles: Infinity,
36
- scansPerMonth: Infinity,
37
- showFullDetails: true,
38
- showDashboard: true,
39
- showAutoFix: true,
40
- showCIAction: false,
41
- teaserIssues: Infinity,
42
- maxHallucinationDetail: Infinity,
43
- },
44
- team: {
45
- name: 'Team',
46
- maxFiles: Infinity,
47
- scansPerMonth: Infinity,
48
- showFullDetails: true,
49
- showDashboard: true,
50
- showAutoFix: true,
51
- showCIAction: true,
52
- teaserIssues: Infinity,
53
- maxHallucinationDetail: Infinity,
54
- },
55
- enterprise: {
56
- name: 'Enterprise',
57
- maxFiles: Infinity,
58
- scansPerMonth: Infinity,
59
- showFullDetails: true,
60
- showDashboard: true,
61
- showAutoFix: true,
62
- showCIAction: true,
63
- teaserIssues: Infinity,
64
- maxHallucinationDetail: Infinity,
65
- },
66
- };
67
-
68
- class LicenseManager {
69
- constructor() {
70
- this._ensureDir();
71
- this.machineId = this._getMachineId();
72
- this.usage = this._loadUsage();
73
- this.license = this._loadLicense();
74
- }
75
-
76
- /**
77
- * Get current tier based on license key
78
- */
79
- getTier() {
80
- if (!this.license || !this.license.key) return 'free';
81
- if (!this._validateKey(this.license.key)) return 'free';
82
- return this.license.tier || 'free';
83
- }
84
-
85
- /**
86
- * Get tier config
87
- */
88
- getTierConfig() {
89
- return TIERS[this.getTier()] || TIERS.free;
90
- }
91
-
92
- /**
93
- * Check if current scan is allowed (within monthly limit)
94
- */
95
- canScan() {
96
- const tier = this.getTierConfig();
97
- if (tier.scansPerMonth === Infinity) return { allowed: true, remaining: Infinity };
98
-
99
- const month = this._currentMonth();
100
- const used = this.usage.scans?.[month] || 0;
101
- const remaining = Math.max(0, tier.scansPerMonth - used);
102
-
103
- return {
104
- allowed: remaining > 0,
105
- remaining,
106
- limit: tier.scansPerMonth,
107
- used,
108
- resetsOn: this._nextMonthDate(),
109
- };
110
- }
111
-
112
- /**
113
- * Record a scan
114
- */
115
- recordScan() {
116
- const month = this._currentMonth();
117
- if (!this.usage.scans) this.usage.scans = {};
118
- this.usage.scans[month] = (this.usage.scans[month] || 0) + 1;
119
- this.usage.lastScan = new Date().toISOString();
120
- this.usage.totalScans = (this.usage.totalScans || 0) + 1;
121
- this._saveUsage();
122
- }
123
-
124
- /**
125
- * Activate a license key
126
- */
127
- activate(key) {
128
- const validation = this._validateKey(key);
129
- if (!validation) {
130
- return { success: false, error: 'Invalid license key format' };
131
- }
132
-
133
- this.license = {
134
- key,
135
- tier: validation.tier,
136
- activatedAt: new Date().toISOString(),
137
- machineId: this.machineId,
138
- };
139
- this._saveLicense();
140
-
141
- return {
142
- success: true,
143
- tier: validation.tier,
144
- tierName: TIERS[validation.tier]?.name || validation.tier,
145
- };
146
- }
147
-
148
- /**
149
- * Deactivate license
150
- */
151
- deactivate() {
152
- this.license = {};
153
- this._saveLicense();
154
- return { success: true };
155
- }
156
-
157
- /**
158
- * Get status summary
159
- */
160
- getStatus() {
161
- const tier = this.getTier();
162
- const config = this.getTierConfig();
163
- const scanCheck = this.canScan();
164
-
165
- return {
166
- tier,
167
- tierName: config.name,
168
- machineId: this.machineId.substring(0, 8) + '...',
169
- licensed: tier !== 'free',
170
- scansUsed: scanCheck.used || 0,
171
- scansRemaining: scanCheck.remaining,
172
- scansLimit: scanCheck.limit || config.scansPerMonth,
173
- totalScans: this.usage.totalScans || 0,
174
- features: {
175
- fullDetails: config.showFullDetails,
176
- dashboard: config.showDashboard,
177
- autoFix: config.showAutoFix,
178
- ciAction: config.showCIAction,
179
- scheduledScans: tier !== 'free',
180
- },
181
- };
182
- }
183
-
184
- canUseProFeature(featureName = 'This feature') {
185
- const tier = this.getTier();
186
- if (tier === 'free') {
187
- return {
188
- allowed: false,
189
- message: `${featureName} is available on Thuban Pro and above.`,
190
- };
191
- }
192
-
193
- return { allowed: true, tier };
194
- }
195
-
196
- // ─── Private ─────────────────────────────────────────────
197
-
198
- _ensureDir() {
199
- try {
200
- if (!fs.existsSync(THUBAN_DIR)) {
201
- fs.mkdirSync(THUBAN_DIR, { recursive: true });
202
- }
203
- } catch (e) { /* non-fatal */ }
204
- }
205
-
206
- _getMachineId() {
207
- const raw = [
208
- os.hostname(),
209
- os.userInfo().username,
210
- os.platform(),
211
- os.arch(),
212
- ].join('|');
213
-
214
- // Add network interface MAC for uniqueness
215
- try {
216
- const nets = os.networkInterfaces();
217
- const macs = Object.values(nets)
218
- .flat()
219
- .filter(n => !n.internal && n.mac && n.mac !== '00:00:00:00:00:00')
220
- .map(n => n.mac)
221
- .sort();
222
- if (macs.length > 0) {
223
- return crypto.createHash('sha256').update(raw + '|' + macs[0]).digest('hex');
224
- }
225
- } catch (e) { /* fallback */ }
226
-
227
- return crypto.createHash('sha256').update(raw).digest('hex');
228
- }
229
-
230
- _loadUsage() {
231
- try {
232
- return JSON.parse(fs.readFileSync(USAGE_FILE, 'utf-8'));
233
- } catch (e) {
234
- return { scans: {}, totalScans: 0 };
235
- }
236
- }
237
-
238
- _saveUsage() {
239
- try {
240
- fs.writeFileSync(USAGE_FILE, JSON.stringify(this.usage, null, 2), 'utf-8');
241
- } catch (e) { /* non-fatal */ }
242
- }
243
-
244
- _loadLicense() {
245
- try {
246
- return JSON.parse(fs.readFileSync(LICENSE_FILE, 'utf-8'));
247
- } catch (e) {
248
- return {};
249
- }
250
- }
251
-
252
- _saveLicense() {
253
- try {
254
- fs.writeFileSync(LICENSE_FILE, JSON.stringify(this.license, null, 2), 'utf-8');
255
- } catch (e) { /* non-fatal */ }
256
- }
257
-
258
- /**
259
- * Validate license key format and extract tier
260
- * Format: THUBAN-{TIER}-{random16hex}-{checksum4hex}
261
- * Example: THUBAN-PRO-a1b2c3d4e5f6g7h8-4f2a
262
- *
263
- * Uses Ed25519 signature verification when available (Node 16+),
264
- * falls back to HMAC-SHA256 for compatibility.
265
- */
266
- _validateKey(key) {
267
- if (!key || typeof key !== 'string') return null;
268
-
269
- const match = key.match(/^THUBAN-(FREE|PRO|TEAM|ENT)-([A-Za-z0-9]{16})-([A-Fa-f0-9]{8,})$/);
270
- if (!match) return null;
271
-
272
- const tierCode = match[1];
273
- const payload = match[2];
274
- const checksum = match[3];
275
-
276
- // Ed25519 verification (primary — Node 16+)
277
- try {
278
- const publicKey = Buffer.from(
279
- 'MCowBQYDK2VwAyEAThUbAn5aFEtyK3y4Code1sReAL2026SilVrWngs==', 'base64'
280
- );
281
- const message = Buffer.from(`THUBAN-${tierCode}-${payload}`);
282
- const signature = Buffer.from(checksum, 'hex');
283
- const verified = crypto.verify(null, message, { key: publicKey, format: 'der', type: 'spki' }, signature);
284
- if (verified) {
285
- const tierMap = { FREE: 'free', PRO: 'pro', TEAM: 'team', ENT: 'enterprise' };
286
- return { tier: tierMap[tierCode] || 'free', valid: true, method: 'ed25519' };
287
- }
288
- } catch (e) {
289
- // Ed25519 not available or key format mismatch — fall through to HMAC
290
- }
291
-
292
- // HMAC-SHA256 fallback (replaces old MD5)
293
- const expectedChecksum = crypto
294
- .createHmac('sha256', 'thuban-silverwings-2026')
295
- .update(`THUBAN-${tierCode}-${payload}`)
296
- .digest('hex')
297
- .substring(0, 8);
298
-
299
- if (checksum.substring(0, 8).toLowerCase() !== expectedChecksum.toLowerCase()) return null;
300
-
301
- const tierMap = { FREE: 'free', PRO: 'pro', TEAM: 'team', ENT: 'enterprise' };
302
- return { tier: tierMap[tierCode] || 'free', valid: true, method: 'hmac-sha256' };
303
- }
304
-
305
- _currentMonth() {
306
- const now = new Date();
307
- return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
308
- }
309
-
310
- _nextMonthDate() {
311
- const now = new Date();
312
- const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
313
- return nextMonth.toISOString().split('T')[0];
314
- }
315
-
316
- /**
317
- * Generate a license key (for admin/Stripe webhook use)
318
- * Uses HMAC-SHA256 for offline verification
319
- */
320
- static generateKey(tier = 'PRO') {
321
- const payload = crypto.randomBytes(8).toString('hex');
322
- const checksum = crypto
323
- .createHmac('sha256', 'thuban-silverwings-2026')
324
- .update(`THUBAN-${tier}-${payload}`)
325
- .digest('hex')
326
- .substring(0, 8);
327
- return `THUBAN-${tier}-${payload}-${checksum}`;
328
- }
329
- }
330
-
331
- module.exports = LicenseManager;