@o-lang/olang 1.2.18 → 1.2.20

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@o-lang/olang",
3
- "version": "1.2.18",
3
+ "version": "1.2.20",
4
4
  "author": "Olalekan Ogundipe <info@olang.cloud>",
5
5
  "description": "O-Lang: A governance language for user-directed, rule-enforced agent workflows",
6
6
  "main": "./src/runtime/index.js",
@@ -1,81 +1,90 @@
1
1
  // src/runtime/index.js
2
2
  const { RuntimeAPI } = require('./RuntimeAPI');
3
- const { parse } = require('../parser');
4
- const crypto = require('crypto');
5
- const fs = require('fs');
6
- const path = require('path');
3
+ const { parse } = require('../parser');
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
7
 
8
- // Load kernel private key (cached)
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 = process.env.KERNEL_PRIVATE_KEY_PATH || './kernel-keys/kernel-private.pem';
14
- const absolutePath = path.isAbsolute(keyPath) ? keyPath : path.join(process.cwd(), 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');
26
+ console.log('[kernel] ✅ Private key loaded for signing');
23
27
  return KERNEL_PRIVATE_KEY;
24
28
  }
25
29
 
26
- // Sign audit data with kernel private key
27
- function signAuditData(auditData, privateKey) {
28
- if (!privateKey) return null;
29
-
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
+
34
+ function signAuditData(auditData, privateKeyPem) {
35
+ if (!privateKeyPem) return null;
36
+
30
37
  try {
31
- // Serialize audit data EXACTLY as it will be verified
32
- // (sorted keys for deterministic serialization)
38
+ // Serialize with sorted keys must match verifySignature() in server.js
33
39
  const serialized = JSON.stringify(auditData, Object.keys(auditData).sort());
34
-
35
- // Create signature
40
+
36
41
  const sign = crypto.createSign('SHA256');
37
42
  sign.update(serialized);
38
43
  sign.end();
39
-
40
- const signature = sign.sign(privateKey, 'hex');
41
- return signature;
44
+
45
+ return sign.sign(privateKeyPem, 'hex');
42
46
  } catch (err) {
43
47
  console.error('[kernel] Signature error:', err.message);
44
48
  return null;
45
49
  }
46
50
  }
47
51
 
52
+ // ── Main execute function ─────────────────────────────────────────────────────
53
+
48
54
  async function execute(workflow, inputs, agentResolver, verbose = false) {
49
55
  const rt = new RuntimeAPI({ verbose });
50
-
51
- // run the workflow — result only contains Return values
56
+
57
+ // Run the workflow — result contains only Return values
52
58
  const result = await rt.executeWorkflow(workflow, inputs, agentResolver);
53
59
 
54
- // rt is still alive here grab audit before it dies
60
+ // Grab audit data while RuntimeAPI instance is still alive
55
61
  const lastEntry = rt.auditLog.at(-1);
56
62
  const firstEntry = rt.auditLog.at(0);
57
63
 
58
- // Build audit object BEFORE signing
64
+ // Build audit object BEFORE signing — must match verifySignature() structure
59
65
  const auditData = {
60
- execution_hash: lastEntry?.hash ?? null,
61
- previous_hash: firstEntry?.hash ?? 'GENESIS',
66
+ execution_hash: lastEntry?.hash ?? null,
67
+ previous_hash: firstEntry?.hash ?? 'GENESIS',
62
68
  merkle_root: rt._calculateMerkleRoot(),
63
- kernel_version: lastEntry?.details?.kernel_version ?? null,
69
+ kernel_version: lastEntry?.details?.kernel_version ?? null,
64
70
  governance_profile_hash: lastEntry?.details?.governance_profile_hash ?? null,
65
71
  integrity: rt.verifyAuditLogIntegrity(),
66
72
  chain: rt.auditLog,
67
73
  };
68
74
 
69
- // SIGN the audit data
75
+ // Sign the audit data with the kernel private key
70
76
  const privateKey = getKernelPrivateKey();
71
- const signature = signAuditData(auditData, privateKey);
72
-
73
- // Load public key for verification (optional but helpful)
77
+ const signature = signAuditData(auditData, privateKey);
78
+
79
+ // Load public key for client-side verification (stripped PEM)
74
80
  let publicKey = null;
75
81
  if (privateKey) {
76
82
  try {
77
- const pubKeyPath = process.env.KERNEL_PUBLIC_KEY_PATH || './kernel-keys/kernel-public.pem';
78
- const absolutePubPath = path.isAbsolute(pubKeyPath) ? pubKeyPath : path.join(process.cwd(), pubKeyPath);
83
+ const pubKeyPath = process.env.KERNEL_PUBLIC_KEY_PATH || './kernel-keys/kernel-public.pem';
84
+ const absolutePubPath = path.isAbsolute(pubKeyPath)
85
+ ? pubKeyPath
86
+ : path.join(process.cwd(), pubKeyPath);
87
+
79
88
  if (fs.existsSync(absolutePubPath)) {
80
89
  publicKey = fs.readFileSync(absolutePubPath, 'utf8')
81
90
  .replace('-----BEGIN PUBLIC KEY-----', '')
@@ -87,10 +96,11 @@ async function execute(workflow, inputs, agentResolver, verbose = false) {
87
96
  }
88
97
  }
89
98
 
99
+ // Attach audit to result — server.js detaches it before sending to client
90
100
  result.__audit = {
91
101
  ...auditData,
92
- signature, // Cryptographic signature
93
- publicKey, // Public key for verification
102
+ signature, // RSA-SHA256 hex signature
103
+ publicKey, // Stripped PEM for client verification
94
104
  };
95
105
 
96
106
  return result;