@siduri-x/core 2.0.0 → 2.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.
@@ -36,7 +36,12 @@ class SqliteActionStore {
36
36
  execution_id TEXT PRIMARY KEY,
37
37
  approver_actor_id TEXT NOT NULL,
38
38
  reason TEXT,
39
- approved_at TEXT NOT NULL
39
+ approver_role TEXT,
40
+ approved_at TEXT NOT NULL,
41
+ tool_name TEXT,
42
+ parameters_hash TEXT,
43
+ companion_id TEXT,
44
+ actor_id TEXT
40
45
  );
41
46
 
42
47
  CREATE TABLE IF NOT EXISTS action_audit_log (
@@ -62,6 +67,28 @@ class SqliteActionStore {
62
67
  timestamp TEXT NOT NULL
63
68
  );
64
69
  `);
70
+ try {
71
+ this.db.exec('ALTER TABLE action_approvals ADD COLUMN approver_role TEXT;');
72
+ }
73
+ catch {
74
+ // Column already exists or table freshly created
75
+ }
76
+ try {
77
+ this.db.exec('ALTER TABLE action_approvals ADD COLUMN tool_name TEXT;');
78
+ }
79
+ catch { }
80
+ try {
81
+ this.db.exec('ALTER TABLE action_approvals ADD COLUMN parameters_hash TEXT;');
82
+ }
83
+ catch { }
84
+ try {
85
+ this.db.exec('ALTER TABLE action_approvals ADD COLUMN companion_id TEXT;');
86
+ }
87
+ catch { }
88
+ try {
89
+ this.db.exec('ALTER TABLE action_approvals ADD COLUMN actor_id TEXT;');
90
+ }
91
+ catch { }
65
92
  }
66
93
  initLastAuditHash() {
67
94
  const row = this.db.prepare('SELECT event_hash FROM action_audit_log ORDER BY id DESC LIMIT 1').get();
@@ -127,22 +154,48 @@ class SqliteActionStore {
127
154
  updatedAt: row.updated_at,
128
155
  };
129
156
  }
130
- async saveApproval(executionId, approverActorId, reason) {
157
+ async saveApproval(executionId, approverActorId, reason, approverRole, toolName, parametersHash, companionId, actorId) {
131
158
  const stmt = this.db.prepare(`
132
- INSERT INTO action_approvals (execution_id, approver_actor_id, reason, approved_at)
133
- VALUES (?, ?, ?, ?)
159
+ INSERT INTO action_approvals (
160
+ execution_id, approver_actor_id, reason, approver_role, approved_at,
161
+ tool_name, parameters_hash, companion_id, actor_id
162
+ )
163
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
134
164
  ON CONFLICT(execution_id) DO UPDATE SET
135
165
  approver_actor_id = excluded.approver_actor_id,
136
166
  reason = excluded.reason,
137
- approved_at = excluded.approved_at
167
+ approver_role = excluded.approver_role,
168
+ approved_at = excluded.approved_at,
169
+ tool_name = excluded.tool_name,
170
+ parameters_hash = excluded.parameters_hash,
171
+ companion_id = excluded.companion_id,
172
+ actor_id = excluded.actor_id
138
173
  `);
139
- stmt.run(executionId, approverActorId, reason ?? null, new Date().toISOString());
174
+ stmt.run(executionId, approverActorId, reason ?? null, approverRole ?? null, new Date().toISOString(), toolName ?? null, parametersHash ?? null, companionId ?? null, actorId ?? null);
140
175
  }
141
176
  async isActionApproved(executionId) {
142
177
  const stmt = this.db.prepare('SELECT 1 FROM action_approvals WHERE execution_id = ?');
143
178
  const row = stmt.get(executionId);
144
179
  return !!row;
145
180
  }
181
+ async getApproval(executionId) {
182
+ const stmt = this.db.prepare('SELECT * FROM action_approvals WHERE execution_id = ?');
183
+ const row = stmt.get(executionId);
184
+ if (!row) {
185
+ return undefined;
186
+ }
187
+ return {
188
+ executionId: row.execution_id,
189
+ approverActorId: row.approver_actor_id,
190
+ reason: row.reason ?? undefined,
191
+ approverRole: row.approver_role ?? undefined,
192
+ approvedAt: row.approved_at,
193
+ toolName: row.tool_name ?? undefined,
194
+ parametersHash: row.parameters_hash ?? undefined,
195
+ companionId: row.companion_id ?? undefined,
196
+ actorId: row.actor_id ?? undefined,
197
+ };
198
+ }
146
199
  async appendAudit(event) {
147
200
  const prevHash = this.lastAuditHash;
148
201
  const eventPayload = {
@@ -164,6 +217,7 @@ class SqliteActionStore {
164
217
  decisionCode: event.decision.decisionCode,
165
218
  } : null,
166
219
  parametersHash: event.parametersHash || null,
220
+ resultHash: event.resultHash || null,
167
221
  error: event.error || null,
168
222
  timestamp: event.timestamp,
169
223
  };
@@ -152,6 +152,7 @@ describe('SqliteActionStore Implementation & Durability', () => {
152
152
  lifecycle: event1.lifecycle,
153
153
  decision: null,
154
154
  parametersHash: null,
155
+ resultHash: null,
155
156
  error: null,
156
157
  timestamp: event1.timestamp,
157
158
  });
@@ -228,6 +229,7 @@ describe('SqliteActionStore Implementation & Durability', () => {
228
229
  await engine1.approveAction({
229
230
  executionId: 'exec-danger-1',
230
231
  approverActorId: 'local-owner',
232
+ approverRole: 'owner',
231
233
  reason: 'Owner confirmed cleanup',
232
234
  });
233
235
  store1.close();
@@ -246,6 +248,14 @@ describe('SqliteActionStore Implementation & Durability', () => {
246
248
  expect(eval2.decision.decisionCode).toBe('ALLOWED_POLICY');
247
249
  expect(eval2.capability).toBeDefined();
248
250
  expect((0, capability_1.verifyCapabilitySignature)(eval2.capability, secretKey)).toBe(true);
251
+ // 5. Tampered action after restart -> rejected due to approval parameter mismatch
252
+ const tamperedAction = {
253
+ ...action,
254
+ parameters: { force: true, dropDatabase: true },
255
+ };
256
+ const evalTampered = await engine2.evaluateAction(tamperedAction);
257
+ expect(evalTampered.decision.allowed).toBe(false);
258
+ expect(evalTampered.decision.decisionCode).toBe('REJECTED_APPROVAL_MISMATCH');
249
259
  store2.close();
250
260
  });
251
261
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siduri-x/core",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Core runtime types, evidence protocol, action dispatcher, capability validation, and SiduriRuntime protocol",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -17,7 +17,7 @@
17
17
  "LICENSE"
18
18
  ],
19
19
  "engines": {
20
- "node": ">=20"
20
+ "node": ">=22.16.0"
21
21
  },
22
22
  "main": "dist/index.js",
23
23
  "types": "dist/index.d.ts",
@@ -29,11 +29,11 @@
29
29
  }
30
30
  },
31
31
  "devDependencies": {
32
- "@types/jest": "^29.5.14",
33
- "@types/node": "^26.2.0",
34
- "jest": "^29.7.0",
32
+ "@types/jest": "^30.0.0",
33
+ "@types/node": "^26.5.1",
34
+ "jest": "^30.5.1",
35
35
  "ts-jest": "^29.4.12",
36
- "typescript": "^5.3.3"
36
+ "typescript": "^5.9.3"
37
37
  },
38
38
  "scripts": {
39
39
  "build": "tsc",