aiox-core 5.0.0 → 5.0.2
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.
- package/.aiox-core/data/entity-registry.yaml +5297 -1814
- package/.aiox-core/data/registry-update-log.jsonl +2 -0
- package/.aiox-core/development/templates/service-template/README.md.hbs +158 -158
- package/.aiox-core/development/templates/service-template/__tests__/index.test.ts.hbs +237 -237
- package/.aiox-core/development/templates/service-template/client.ts.hbs +403 -403
- package/.aiox-core/development/templates/service-template/errors.ts.hbs +182 -182
- package/.aiox-core/development/templates/service-template/index.ts.hbs +120 -120
- package/.aiox-core/development/templates/service-template/package.json.hbs +87 -87
- package/.aiox-core/development/templates/service-template/types.ts.hbs +145 -145
- package/.aiox-core/development/templates/squad-template/LICENSE +21 -21
- package/.aiox-core/infrastructure/scripts/tool-resolver.js +4 -4
- package/.aiox-core/infrastructure/templates/aiox-sync.yaml.template +182 -182
- package/.aiox-core/infrastructure/templates/coderabbit.yaml.template +279 -279
- package/.aiox-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
- package/.aiox-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
- package/.aiox-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
- package/.aiox-core/infrastructure/templates/gitignore/gitignore-aiox-base.tmpl +63 -63
- package/.aiox-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
- package/.aiox-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
- package/.aiox-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
- package/.aiox-core/install-manifest.yaml +58 -58
- package/.aiox-core/local-config.yaml.template +71 -71
- package/.aiox-core/monitor/hooks/lib/__init__.py +1 -1
- package/.aiox-core/monitor/hooks/lib/enrich.py +58 -58
- package/.aiox-core/monitor/hooks/lib/send_event.py +47 -47
- package/.aiox-core/monitor/hooks/notification.py +29 -29
- package/.aiox-core/monitor/hooks/post_tool_use.py +45 -45
- package/.aiox-core/monitor/hooks/pre_compact.py +29 -29
- package/.aiox-core/monitor/hooks/pre_tool_use.py +40 -40
- package/.aiox-core/monitor/hooks/stop.py +29 -29
- package/.aiox-core/monitor/hooks/subagent_stop.py +29 -29
- package/.aiox-core/monitor/hooks/user_prompt_submit.py +38 -38
- package/.aiox-core/product/templates/adr.hbs +125 -125
- package/.aiox-core/product/templates/dbdr.hbs +241 -241
- package/.aiox-core/product/templates/engine/elicitation.js +2 -3
- package/.aiox-core/product/templates/epic.hbs +212 -212
- package/.aiox-core/product/templates/pmdr.hbs +186 -186
- package/.aiox-core/product/templates/prd-v2.0.hbs +216 -216
- package/.aiox-core/product/templates/prd.hbs +201 -201
- package/.aiox-core/product/templates/story.hbs +263 -263
- package/.aiox-core/product/templates/task.hbs +170 -170
- package/.aiox-core/product/templates/tmpl-comment-on-examples.sql +158 -158
- package/.aiox-core/product/templates/tmpl-migration-script.sql +91 -91
- package/.aiox-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
- package/.aiox-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
- package/.aiox-core/product/templates/tmpl-rls-roles.sql +135 -135
- package/.aiox-core/product/templates/tmpl-rls-simple.sql +77 -77
- package/.aiox-core/product/templates/tmpl-rls-tenant.sql +152 -152
- package/.aiox-core/product/templates/tmpl-rollback-script.sql +77 -77
- package/.aiox-core/product/templates/tmpl-seed-data.sql +140 -140
- package/.aiox-core/product/templates/tmpl-smoke-test.sql +16 -16
- package/.aiox-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
- package/.aiox-core/product/templates/tmpl-stored-proc.sql +140 -140
- package/.aiox-core/product/templates/tmpl-trigger.sql +152 -152
- package/.aiox-core/product/templates/tmpl-view-materialized.sql +133 -133
- package/.aiox-core/product/templates/tmpl-view.sql +177 -177
- package/.aiox-core/scripts/pm.sh +0 -0
- package/.claude/hooks/code-intel-pretool.cjs +107 -0
- package/.claude/hooks/enforce-architecture-first.py +196 -196
- package/.claude/hooks/mind-clone-governance.py +192 -192
- package/.claude/hooks/read-protection.py +151 -151
- package/.claude/hooks/slug-validation.py +176 -176
- package/.claude/hooks/sql-governance.py +182 -182
- package/.claude/hooks/write-path-validation.py +194 -194
- package/LICENSE +33 -33
- package/bin/aiox-graph.js +0 -0
- package/bin/aiox-minimal.js +0 -0
- package/bin/aiox.js +0 -0
- package/docs/guides/aios-workflows/README.md +247 -0
- package/docs/guides/aios-workflows/bob-orchestrator-workflow.md +1536 -0
- package/package.json +1 -1
- package/packages/aiox-install/bin/aiox-install.js +0 -0
- package/packages/aiox-install/bin/edmcp.js +0 -0
- package/packages/aiox-pro-cli/bin/aiox-pro.js +0 -0
- package/packages/installer/src/wizard/pro-setup.js +210 -123
- package/pro/README.md +66 -0
- package/pro/license/degradation.js +220 -0
- package/pro/license/errors.js +450 -0
- package/pro/license/feature-gate.js +354 -0
- package/pro/license/index.js +181 -0
- package/pro/license/license-api.js +679 -0
- package/pro/license/license-cache.js +523 -0
- package/pro/license/license-crypto.js +303 -0
- package/scripts/check-markdown-links.py +352 -352
- package/scripts/dashboard-parallel-dev.sh +0 -0
- package/scripts/dashboard-parallel-phase3.sh +0 -0
- package/scripts/dashboard-parallel-phase4.sh +0 -0
- package/scripts/glue/README.md +355 -0
- package/scripts/glue/compose-agent-prompt.cjs +362 -0
- package/scripts/install-monitor-hooks.sh +0 -0
- package/.aiox-core/lib/build.json +0 -1
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License Crypto Module
|
|
3
|
+
*
|
|
4
|
+
* Provides cryptographic utilities for license cache encryption:
|
|
5
|
+
* - Machine ID generation (deterministic fingerprint)
|
|
6
|
+
* - PBKDF2 key derivation
|
|
7
|
+
* - AES-256-GCM encryption/decryption
|
|
8
|
+
* - HMAC-SHA256 integrity verification
|
|
9
|
+
*
|
|
10
|
+
* @module pro/license/license-crypto
|
|
11
|
+
* @see ADR-PRO-003 - Feature Gating & Licensing
|
|
12
|
+
* @see Story PRO-6 - License Key & Feature Gating System
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const crypto = require('crypto');
|
|
18
|
+
const os = require('os');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Configuration constants for cryptographic operations.
|
|
22
|
+
* These values follow security best practices per ADR-PRO-003.
|
|
23
|
+
*/
|
|
24
|
+
const CONFIG = {
|
|
25
|
+
// PBKDF2 settings
|
|
26
|
+
PBKDF2_ITERATIONS: 100000, // Minimum per ADR-PRO-003
|
|
27
|
+
PBKDF2_KEY_LENGTH: 32, // 256 bits for AES-256
|
|
28
|
+
PBKDF2_DIGEST: 'sha256',
|
|
29
|
+
|
|
30
|
+
// AES-256-GCM settings
|
|
31
|
+
AES_ALGORITHM: 'aes-256-gcm',
|
|
32
|
+
AES_IV_LENGTH: 12, // 96 bits recommended for GCM
|
|
33
|
+
AES_TAG_LENGTH: 16, // 128 bits auth tag
|
|
34
|
+
|
|
35
|
+
// HMAC settings
|
|
36
|
+
HMAC_ALGORITHM: 'sha256',
|
|
37
|
+
|
|
38
|
+
// Salt settings
|
|
39
|
+
SALT_LENGTH: 16, // 128 bits
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Generate a deterministic machine identifier.
|
|
44
|
+
*
|
|
45
|
+
* Combines hostname + CPU model + first MAC address to create
|
|
46
|
+
* a unique but reproducible identifier for this machine.
|
|
47
|
+
*
|
|
48
|
+
* @returns {string} SHA-256 hash of machine fingerprint components
|
|
49
|
+
*/
|
|
50
|
+
function generateMachineId() {
|
|
51
|
+
const components = [];
|
|
52
|
+
|
|
53
|
+
// Hostname
|
|
54
|
+
const hostname = os.hostname();
|
|
55
|
+
components.push(hostname);
|
|
56
|
+
|
|
57
|
+
// CPU model (first CPU)
|
|
58
|
+
const cpus = os.cpus();
|
|
59
|
+
if (cpus.length > 0) {
|
|
60
|
+
components.push(cpus[0].model);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// First non-internal MAC address
|
|
64
|
+
const networkInterfaces = os.networkInterfaces();
|
|
65
|
+
for (const [, interfaces] of Object.entries(networkInterfaces)) {
|
|
66
|
+
for (const iface of interfaces) {
|
|
67
|
+
if (!iface.internal && iface.mac && iface.mac !== '00:00:00:00:00:00') {
|
|
68
|
+
components.push(iface.mac);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Only use first valid MAC
|
|
73
|
+
if (components.length > 2) {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Create deterministic hash
|
|
79
|
+
const fingerprint = components.join('|');
|
|
80
|
+
return crypto.createHash('sha256').update(fingerprint).digest('hex');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Generate a cryptographically secure random salt.
|
|
85
|
+
*
|
|
86
|
+
* @param {number} [length=16] - Salt length in bytes
|
|
87
|
+
* @returns {Buffer} Random salt buffer
|
|
88
|
+
*/
|
|
89
|
+
function generateSalt(length = CONFIG.SALT_LENGTH) {
|
|
90
|
+
return crypto.randomBytes(length);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Derive an encryption key from machine ID using PBKDF2.
|
|
95
|
+
*
|
|
96
|
+
* Uses 100,000 iterations minimum per ADR-PRO-003 security requirements.
|
|
97
|
+
*
|
|
98
|
+
* @param {string} machineId - Machine identifier from generateMachineId()
|
|
99
|
+
* @param {Buffer|string} salt - Random salt (Buffer or hex string)
|
|
100
|
+
* @returns {Buffer} 256-bit derived key
|
|
101
|
+
*/
|
|
102
|
+
function deriveCacheKey(machineId, salt) {
|
|
103
|
+
const saltBuffer = Buffer.isBuffer(salt) ? salt : Buffer.from(salt, 'hex');
|
|
104
|
+
|
|
105
|
+
return crypto.pbkdf2Sync(
|
|
106
|
+
machineId,
|
|
107
|
+
saltBuffer,
|
|
108
|
+
CONFIG.PBKDF2_ITERATIONS,
|
|
109
|
+
CONFIG.PBKDF2_KEY_LENGTH,
|
|
110
|
+
CONFIG.PBKDF2_DIGEST,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Encrypt data using AES-256-GCM.
|
|
116
|
+
*
|
|
117
|
+
* Returns an object containing the encrypted ciphertext, initialization vector,
|
|
118
|
+
* and authentication tag for integrity verification.
|
|
119
|
+
*
|
|
120
|
+
* @param {string|object} data - Data to encrypt (objects are JSON stringified)
|
|
121
|
+
* @param {Buffer|string} key - 256-bit encryption key (Buffer or hex string)
|
|
122
|
+
* @returns {{ ciphertext: string, iv: string, tag: string }} Encrypted data components (hex encoded)
|
|
123
|
+
* @throws {Error} If encryption fails
|
|
124
|
+
*/
|
|
125
|
+
function encrypt(data, key) {
|
|
126
|
+
const keyBuffer = Buffer.isBuffer(key) ? key : Buffer.from(key, 'hex');
|
|
127
|
+
|
|
128
|
+
if (keyBuffer.length !== 32) {
|
|
129
|
+
throw new Error('Encryption key must be 256 bits (32 bytes)');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Generate random IV
|
|
133
|
+
const iv = crypto.randomBytes(CONFIG.AES_IV_LENGTH);
|
|
134
|
+
|
|
135
|
+
// Stringify objects
|
|
136
|
+
const plaintext = typeof data === 'object' ? JSON.stringify(data) : String(data);
|
|
137
|
+
|
|
138
|
+
// Create cipher and encrypt
|
|
139
|
+
const cipher = crypto.createCipheriv(CONFIG.AES_ALGORITHM, keyBuffer, iv, {
|
|
140
|
+
authTagLength: CONFIG.AES_TAG_LENGTH,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
let ciphertext = cipher.update(plaintext, 'utf8', 'hex');
|
|
144
|
+
ciphertext += cipher.final('hex');
|
|
145
|
+
|
|
146
|
+
// Get auth tag
|
|
147
|
+
const tag = cipher.getAuthTag();
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
ciphertext,
|
|
151
|
+
iv: iv.toString('hex'),
|
|
152
|
+
tag: tag.toString('hex'),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Decrypt data using AES-256-GCM.
|
|
158
|
+
*
|
|
159
|
+
* Verifies the authentication tag to ensure data integrity.
|
|
160
|
+
*
|
|
161
|
+
* @param {{ ciphertext: string, iv: string, tag: string }} encryptedData - Encrypted data object
|
|
162
|
+
* @param {Buffer|string} key - 256-bit encryption key (Buffer or hex string)
|
|
163
|
+
* @param {boolean} [parseJson=true] - Whether to parse result as JSON
|
|
164
|
+
* @returns {string|object} Decrypted data
|
|
165
|
+
* @throws {Error} If decryption fails or authentication fails
|
|
166
|
+
*/
|
|
167
|
+
function decrypt(encryptedData, key, parseJson = true) {
|
|
168
|
+
const { ciphertext, iv, tag } = encryptedData;
|
|
169
|
+
|
|
170
|
+
const keyBuffer = Buffer.isBuffer(key) ? key : Buffer.from(key, 'hex');
|
|
171
|
+
|
|
172
|
+
if (keyBuffer.length !== 32) {
|
|
173
|
+
throw new Error('Decryption key must be 256 bits (32 bytes)');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const ivBuffer = Buffer.from(iv, 'hex');
|
|
177
|
+
const tagBuffer = Buffer.from(tag, 'hex');
|
|
178
|
+
|
|
179
|
+
// Create decipher
|
|
180
|
+
const decipher = crypto.createDecipheriv(CONFIG.AES_ALGORITHM, keyBuffer, ivBuffer, {
|
|
181
|
+
authTagLength: CONFIG.AES_TAG_LENGTH,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
decipher.setAuthTag(tagBuffer);
|
|
185
|
+
|
|
186
|
+
let plaintext = decipher.update(ciphertext, 'hex', 'utf8');
|
|
187
|
+
plaintext += decipher.final('utf8');
|
|
188
|
+
|
|
189
|
+
// Optionally parse as JSON
|
|
190
|
+
if (parseJson) {
|
|
191
|
+
try {
|
|
192
|
+
return JSON.parse(plaintext);
|
|
193
|
+
} catch {
|
|
194
|
+
// Return as string if not valid JSON
|
|
195
|
+
return plaintext;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return plaintext;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Compute HMAC-SHA256 for data integrity verification.
|
|
204
|
+
*
|
|
205
|
+
* @param {string|Buffer} data - Data to compute HMAC for
|
|
206
|
+
* @param {Buffer|string} key - HMAC key (Buffer or hex string)
|
|
207
|
+
* @returns {string} HMAC as hex string
|
|
208
|
+
*/
|
|
209
|
+
function computeHMAC(data, key) {
|
|
210
|
+
const keyBuffer = Buffer.isBuffer(key) ? key : Buffer.from(key, 'hex');
|
|
211
|
+
const dataString = Buffer.isBuffer(data) ? data.toString('utf8') : String(data);
|
|
212
|
+
|
|
213
|
+
return crypto.createHmac(CONFIG.HMAC_ALGORITHM, keyBuffer).update(dataString).digest('hex');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Verify HMAC matches expected value.
|
|
218
|
+
*
|
|
219
|
+
* Uses timing-safe comparison to prevent timing attacks.
|
|
220
|
+
*
|
|
221
|
+
* @param {string|Buffer} data - Data to verify
|
|
222
|
+
* @param {Buffer|string} key - HMAC key
|
|
223
|
+
* @param {string} expectedHmac - Expected HMAC value (hex string)
|
|
224
|
+
* @returns {boolean} true if HMAC matches
|
|
225
|
+
*/
|
|
226
|
+
function verifyHMAC(data, key, expectedHmac) {
|
|
227
|
+
const computedHmac = computeHMAC(data, key);
|
|
228
|
+
|
|
229
|
+
// Use timing-safe comparison
|
|
230
|
+
const computedBuffer = Buffer.from(computedHmac, 'hex');
|
|
231
|
+
const expectedBuffer = Buffer.from(expectedHmac, 'hex');
|
|
232
|
+
|
|
233
|
+
if (computedBuffer.length !== expectedBuffer.length) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return crypto.timingSafeEqual(computedBuffer, expectedBuffer);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Mask a license key for display.
|
|
242
|
+
*
|
|
243
|
+
* Shows only first and last 4 characters: PRO-XXXX-****-****-XXXX
|
|
244
|
+
* CRITICAL: Always use this function when logging or displaying keys.
|
|
245
|
+
*
|
|
246
|
+
* @param {string} key - Full license key
|
|
247
|
+
* @returns {string} Masked key for display
|
|
248
|
+
*/
|
|
249
|
+
function maskKey(key) {
|
|
250
|
+
if (!key || typeof key !== 'string') {
|
|
251
|
+
return '****-****-****-****';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Handle PRO-XXXX-XXXX-XXXX-XXXX format
|
|
255
|
+
const parts = key.split('-');
|
|
256
|
+
if (parts.length !== 5 || parts[0] !== 'PRO') {
|
|
257
|
+
// Non-standard format, mask all but first/last 4
|
|
258
|
+
if (key.length <= 8) {
|
|
259
|
+
return '****';
|
|
260
|
+
}
|
|
261
|
+
return `${key.slice(0, 4)}-****-****-${key.slice(-4)}`;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Standard format: PRO-XXXX-XXXX-XXXX-XXXX
|
|
265
|
+
return `${parts[0]}-${parts[1]}-****-****-${parts[4]}`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Validate license key format.
|
|
270
|
+
*
|
|
271
|
+
* Expected format: PRO-XXXX-XXXX-XXXX-XXXX
|
|
272
|
+
* Where X is alphanumeric (A-Z0-9)
|
|
273
|
+
*
|
|
274
|
+
* @param {string} key - License key to validate
|
|
275
|
+
* @returns {boolean} true if format is valid
|
|
276
|
+
*/
|
|
277
|
+
function validateKeyFormat(key) {
|
|
278
|
+
if (!key || typeof key !== 'string') {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Format: PRO-XXXX-XXXX-XXXX-XXXX (uppercase alphanumeric)
|
|
283
|
+
const pattern = /^PRO-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/;
|
|
284
|
+
return pattern.test(key);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
module.exports = {
|
|
288
|
+
// Core functions per ADR-PRO-003
|
|
289
|
+
generateMachineId,
|
|
290
|
+
deriveCacheKey,
|
|
291
|
+
encrypt,
|
|
292
|
+
decrypt,
|
|
293
|
+
computeHMAC,
|
|
294
|
+
|
|
295
|
+
// Additional utilities
|
|
296
|
+
generateSalt,
|
|
297
|
+
verifyHMAC,
|
|
298
|
+
maskKey,
|
|
299
|
+
validateKeyFormat,
|
|
300
|
+
|
|
301
|
+
// Exported for testing
|
|
302
|
+
_CONFIG: CONFIG,
|
|
303
|
+
};
|