@o-lang/olang 1.2.19 → 1.2.21
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/package.json +1 -1
- package/src/runtime/RuntimeAPI.js +21 -15
- package/src/runtime/index.js +45 -42
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const crypto = require('crypto'); // ✅ CRYPTOGRAPHIC AUDIT LOGS
|
|
4
4
|
|
|
5
5
|
// ✅ O-Lang Kernel Version (Safety Logic & Governance Rules)
|
|
6
|
-
const KERNEL_VERSION = '1.2.
|
|
6
|
+
const KERNEL_VERSION = '1.2.20-alpha'; // 🔁 Update when safety rules change
|
|
7
7
|
|
|
8
8
|
class RuntimeAPI {
|
|
9
9
|
constructor({ verbose = false } = {}) {
|
|
@@ -816,6 +816,9 @@ class RuntimeAPI {
|
|
|
816
816
|
{ pattern: /\b(?:tumir|bhadhar)\s*a\b/i, capability: 'unauthorized_action', lang: 'sn' },
|
|
817
817
|
{ pattern: /\b(tumir\s*a\s+(?:mhando|ari))\b/i, capability: 'transfer', lang: 'sn' },
|
|
818
818
|
{ pattern: /\b(bhadhara|bhadharis\s*o)\b/i, capability: 'payment', lang: 'sn' },
|
|
819
|
+
{ pattern: /\b(ranṣẹ\s+(?:owo|pesa|kuɗi|ego)|fi\s+.*\s+ranṣẹ)\b/i, capability: 'transfer', lang: 'yo' }, // Yoruba "Send money"
|
|
820
|
+
{ pattern: /\b(zipu\s+(?:ego|moni)|zi\s+.*\s+zipu)\b/i, capability: 'transfer', lang: 'ig' }, // Igbo "Send money"
|
|
821
|
+
{ pattern: /\b(aika\s+(?:kuɗi)|turo\s+.*\s+aika)\b/i, capability: 'transfer', lang: 'ha' }, // Hausa "Send money"
|
|
819
822
|
// ────────────────────────────────────────────────
|
|
820
823
|
// 🌐 GLOBAL LANGUAGES
|
|
821
824
|
// ────────────────────────────────────────────────
|
|
@@ -852,20 +855,23 @@ class RuntimeAPI {
|
|
|
852
855
|
c.includes('withdraw')
|
|
853
856
|
);
|
|
854
857
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
858
|
+
if (!hasCapability) {
|
|
859
|
+
const match = output.match(pattern);
|
|
860
|
+
|
|
861
|
+
// ✅ Explicitly flag African & Financial context for Audit Logs
|
|
862
|
+
const isAfrican = ['yo', 'ig', 'ha', 'sw', 'zu', 'am', 'om', 'ff', 'so', 'sn'].includes(lang);
|
|
863
|
+
const isFinancial = ['transfer', 'payment', 'withdrawal', 'deposit', 'financial_action'].includes(capability);
|
|
864
|
+
|
|
865
|
+
return {
|
|
866
|
+
passed: false,
|
|
867
|
+
reason: `Hallucinated "${capability}" capability in ${lang}...`,
|
|
868
|
+
detected: match ? match[0].trim() : 'unknown pattern',
|
|
869
|
+
language: lang,
|
|
870
|
+
african_language_detected: isAfrican,
|
|
871
|
+
financial_expression_found: isFinancial,
|
|
872
|
+
capability_attempted: capability
|
|
873
|
+
};
|
|
874
|
+
}
|
|
869
875
|
// -----------------------------
|
|
870
876
|
// ✅ CRITICAL FIX: Resolver output unwrapping helper
|
|
871
877
|
// -----------------------------
|
package/src/runtime/index.js
CHANGED
|
@@ -1,89 +1,91 @@
|
|
|
1
1
|
// src/runtime/index.js
|
|
2
2
|
const { RuntimeAPI } = require('./RuntimeAPI');
|
|
3
|
-
const { parse }
|
|
4
|
-
const crypto
|
|
5
|
-
const fs
|
|
6
|
-
const path
|
|
3
|
+
const { parse } = require('../parser');
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// ── Load kernel private key (cached) ─────────────────────────────────────────
|
|
9
9
|
let KERNEL_PRIVATE_KEY = null;
|
|
10
|
+
|
|
10
11
|
function getKernelPrivateKey() {
|
|
11
12
|
if (KERNEL_PRIVATE_KEY) return KERNEL_PRIVATE_KEY;
|
|
12
|
-
|
|
13
|
-
const keyPath
|
|
14
|
-
const absolutePath = path.isAbsolute(keyPath)
|
|
15
|
-
|
|
13
|
+
|
|
14
|
+
const keyPath = process.env.KERNEL_PRIVATE_KEY_PATH || './kernel-keys/kernel-private.pem';
|
|
15
|
+
const absolutePath = path.isAbsolute(keyPath)
|
|
16
|
+
? keyPath
|
|
17
|
+
: path.join(process.cwd(), keyPath);
|
|
18
|
+
|
|
16
19
|
if (!fs.existsSync(absolutePath)) {
|
|
17
20
|
console.warn('[kernel] Warning: Private key not found at', absolutePath);
|
|
18
21
|
console.warn('[kernel] Audit entries will NOT be signed');
|
|
19
22
|
return null;
|
|
20
23
|
}
|
|
21
|
-
|
|
24
|
+
|
|
22
25
|
KERNEL_PRIVATE_KEY = fs.readFileSync(absolutePath, 'utf8');
|
|
23
26
|
console.log('[kernel] ✅ Private key loaded for signing');
|
|
24
27
|
return KERNEL_PRIVATE_KEY;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
//
|
|
30
|
+
// ── Sign audit data with RSA-SHA256 ──────────────────────────────────────────
|
|
31
|
+
// Uses RSA-SHA256 to match the RSA key generated by crypto.generateKeyPairSync.
|
|
32
|
+
// The same sorted JSON serialization is used during verification.
|
|
33
|
+
|
|
28
34
|
function signAuditData(auditData, privateKeyPem) {
|
|
29
35
|
if (!privateKeyPem) return null;
|
|
30
|
-
|
|
36
|
+
|
|
31
37
|
try {
|
|
32
|
-
// Serialize
|
|
38
|
+
// Serialize with sorted keys — must match verifySignature() in server.js
|
|
33
39
|
const serialized = JSON.stringify(auditData, Object.keys(auditData).sort());
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
key: privateKeyPem,
|
|
41
|
-
dsaEncoding: 'ieee-p1363', // Required for ED25519
|
|
42
|
-
}
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
return signature.toString('hex');
|
|
40
|
+
|
|
41
|
+
const sign = crypto.createSign('SHA256');
|
|
42
|
+
sign.update(serialized);
|
|
43
|
+
sign.end();
|
|
44
|
+
|
|
45
|
+
return sign.sign(privateKeyPem, 'hex');
|
|
46
46
|
} catch (err) {
|
|
47
47
|
console.error('[kernel] Signature error:', err.message);
|
|
48
48
|
return null;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// ── Main execute function ─────────────────────────────────────────────────────
|
|
53
|
+
|
|
52
54
|
async function execute(workflow, inputs, agentResolver, verbose = false) {
|
|
53
55
|
const rt = new RuntimeAPI({ verbose });
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
+
|
|
57
|
+
// Run the workflow — result contains only Return values
|
|
56
58
|
const result = await rt.executeWorkflow(workflow, inputs, agentResolver);
|
|
57
59
|
|
|
58
|
-
//
|
|
60
|
+
// Grab audit data while RuntimeAPI instance is still alive
|
|
59
61
|
const lastEntry = rt.auditLog.at(-1);
|
|
60
62
|
const firstEntry = rt.auditLog.at(0);
|
|
61
63
|
|
|
62
|
-
// Build audit object BEFORE signing
|
|
64
|
+
// Build audit object BEFORE signing — must match verifySignature() structure
|
|
63
65
|
const auditData = {
|
|
64
|
-
execution_hash: lastEntry?.hash
|
|
65
|
-
previous_hash: firstEntry?.hash
|
|
66
|
+
execution_hash: lastEntry?.hash ?? null,
|
|
67
|
+
previous_hash: firstEntry?.hash ?? 'GENESIS',
|
|
66
68
|
merkle_root: rt._calculateMerkleRoot(),
|
|
67
|
-
kernel_version: lastEntry?.details?.kernel_version
|
|
69
|
+
kernel_version: lastEntry?.details?.kernel_version ?? null,
|
|
68
70
|
governance_profile_hash: lastEntry?.details?.governance_profile_hash ?? null,
|
|
69
71
|
integrity: rt.verifyAuditLogIntegrity(),
|
|
70
72
|
chain: rt.auditLog,
|
|
71
73
|
};
|
|
72
74
|
|
|
73
|
-
//
|
|
75
|
+
// Sign the audit data with the kernel private key
|
|
74
76
|
const privateKey = getKernelPrivateKey();
|
|
75
|
-
const signature
|
|
76
|
-
|
|
77
|
-
// Load public key for verification (
|
|
77
|
+
const signature = signAuditData(auditData, privateKey);
|
|
78
|
+
|
|
79
|
+
// Load public key for client-side verification (stripped PEM)
|
|
78
80
|
let publicKey = null;
|
|
79
81
|
if (privateKey) {
|
|
80
82
|
try {
|
|
81
|
-
const pubKeyPath
|
|
82
|
-
const absolutePubPath = path.isAbsolute(pubKeyPath)
|
|
83
|
-
? pubKeyPath
|
|
83
|
+
const pubKeyPath = process.env.KERNEL_PUBLIC_KEY_PATH || './kernel-keys/kernel-public.pem';
|
|
84
|
+
const absolutePubPath = path.isAbsolute(pubKeyPath)
|
|
85
|
+
? pubKeyPath
|
|
84
86
|
: path.join(process.cwd(), pubKeyPath);
|
|
87
|
+
|
|
85
88
|
if (fs.existsSync(absolutePubPath)) {
|
|
86
|
-
// Read and clean PEM for storage
|
|
87
89
|
publicKey = fs.readFileSync(absolutePubPath, 'utf8')
|
|
88
90
|
.replace('-----BEGIN PUBLIC KEY-----', '')
|
|
89
91
|
.replace('-----END PUBLIC KEY-----', '')
|
|
@@ -94,10 +96,11 @@ async function execute(workflow, inputs, agentResolver, verbose = false) {
|
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
// Attach audit to result — server.js detaches it before sending to client
|
|
97
100
|
result.__audit = {
|
|
98
101
|
...auditData,
|
|
99
|
-
signature,
|
|
100
|
-
publicKey,
|
|
102
|
+
signature, // RSA-SHA256 hex signature
|
|
103
|
+
publicKey, // Stripped PEM for client verification
|
|
101
104
|
};
|
|
102
105
|
|
|
103
106
|
return result;
|