@the-ai-company/cbio-node-runtime 1.68.0 → 1.70.1
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/README.md +40 -6
- package/dist/clients/owner/client.js +11 -2
- package/dist/clients/owner/client.js.map +1 -1
- package/dist/clients/owner/contracts.d.ts +4 -2
- package/dist/public-types.d.ts +2 -1
- package/dist/public-types.js.map +1 -1
- package/dist/runtime/index.d.ts +4 -2
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/vault-core/contracts.d.ts +49 -29
- package/dist/vault-core/contracts.js +0 -6
- package/dist/vault-core/contracts.js.map +1 -1
- package/dist/vault-core/core.d.ts +4 -5
- package/dist/vault-core/core.js +65 -37
- package/dist/vault-core/core.js.map +1 -1
- package/dist/vault-core/defaults.d.ts +8 -6
- package/dist/vault-core/defaults.js +98 -16
- package/dist/vault-core/defaults.js.map +1 -1
- package/dist/vault-core/index.d.ts +3 -3
- package/dist/vault-core/index.js +1 -1
- package/dist/vault-core/index.js.map +1 -1
- package/dist/vault-core/persistence.d.ts +34 -36
- package/dist/vault-core/persistence.js +268 -333
- package/dist/vault-core/persistence.js.map +1 -1
- package/dist/vault-core/ports.d.ts +5 -3
- package/dist/vault-ingress/defaults.d.ts +1 -1
- package/dist/vault-ingress/index.d.ts +2 -1
- package/dist/vault-ingress/index.js +5 -2
- package/dist/vault-ingress/index.js.map +1 -1
- package/dist/vault-ingress/server-utils.d.ts +30 -0
- package/dist/vault-ingress/server-utils.js +151 -0
- package/dist/vault-ingress/server-utils.js.map +1 -1
- package/docs/REFERENCE.md +4 -0
- package/docs/api/README.md +9 -3
- package/docs/api/classes/IdentityError.md +1 -1
- package/docs/api/classes/OwnerClientError.md +1 -1
- package/docs/api/classes/PersistentVaultAgentIdentityRegistry.md +5 -5
- package/docs/api/classes/PersistentVaultAgentSecretGrantRegistry.md +5 -5
- package/docs/api/classes/PersistentVaultAuditLog.md +29 -5
- package/docs/api/classes/PersistentVaultSecretCustody.md +5 -5
- package/docs/api/classes/PersistentVaultSecretDestinationGrantRegistry.md +5 -5
- package/docs/api/classes/PersistentVaultSecretRepository.md +5 -5
- package/docs/api/classes/VaultCore.md +10 -10
- package/docs/api/classes/VaultCoreError.md +1 -1
- package/docs/api/enumerations/AuditOperation.md +1 -37
- package/docs/api/enumerations/DispatchStatus.md +1 -1
- package/docs/api/enumerations/IdentityErrorCode.md +1 -1
- package/docs/api/enumerations/OwnerClientErrorCode.md +1 -1
- package/docs/api/functions/createAgentClient.md +1 -1
- package/docs/api/functions/createIdentity.md +1 -1
- package/docs/api/functions/createOwnerClient.md +1 -1
- package/docs/api/functions/createPersistentVaultCoreDependencies.md +1 -1
- package/docs/api/functions/createVault.md +1 -1
- package/docs/api/functions/createVaultCore.md +1 -1
- package/docs/api/functions/createVaultCoreDependencies.md +1 -1
- package/docs/api/functions/createVaultService.md +1 -1
- package/docs/api/functions/createWorkspaceStorage.md +1 -1
- package/docs/api/functions/deriveRootAgentId.md +1 -1
- package/docs/api/functions/deriveVaultWorkingKeyFromPassword.md +1 -1
- package/docs/api/functions/getDefaultWorkspaceDir.md +1 -1
- package/docs/api/functions/handleVaultAgentControlHttp.md +1 -1
- package/docs/api/functions/handleVaultAuditSse.md +30 -0
- package/docs/api/functions/handleVaultHttpDispatch.md +1 -1
- package/docs/api/functions/handleVaultPendingDispatchSse.md +30 -0
- package/docs/api/functions/initializeVaultCustody.md +1 -1
- package/docs/api/functions/listVaults.md +1 -1
- package/docs/api/functions/openOwnerSession.md +1 -1
- package/docs/api/functions/readVaultProfile.md +1 -1
- package/docs/api/functions/recoverVault.md +1 -1
- package/docs/api/functions/recoverVaultWorkingKey.md +1 -1
- package/docs/api/functions/restoreIdentity.md +1 -1
- package/docs/api/functions/updateVaultMetadata.md +1 -1
- package/docs/api/functions/writeVaultProfile.md +1 -1
- package/docs/api/interfaces/AgentClient.md +3 -3
- package/docs/api/interfaces/AgentDispatchIntent.md +1 -1
- package/docs/api/interfaces/AgentDispatchTransport.md +3 -3
- package/docs/api/interfaces/AgentIdentity.md +1 -1
- package/docs/api/interfaces/AgentIdentityRecord.md +1 -1
- package/docs/api/interfaces/AgentRequestRecord.md +83 -0
- package/docs/api/interfaces/AgentRuntimeManifest.md +1 -1
- package/docs/api/interfaces/AgentSecretGrant.md +1 -1
- package/docs/api/interfaces/AgentSigner.md +1 -1
- package/docs/api/interfaces/AgentVisibleRequestRecord.md +1 -1
- package/docs/api/interfaces/AgentVisibleSecretRecord.md +1 -1
- package/docs/api/interfaces/AuditEntry.md +1 -1
- package/docs/api/interfaces/CbioRuntime.md +59 -1
- package/docs/api/interfaces/CreateAgentClientOptions.md +1 -1
- package/docs/api/interfaces/CreateIdentityOptions.md +1 -1
- package/docs/api/interfaces/CreateOwnerClientOptions.md +1 -1
- package/docs/api/interfaces/CreatePersistentVaultCoreDependenciesOptions.md +1 -1
- package/docs/api/interfaces/CreateVaultOptions.md +1 -1
- package/docs/api/interfaces/CreatedVault.md +1 -1
- package/docs/api/interfaces/DefaultPolicyEngineOptions.md +1 -23
- package/docs/api/interfaces/DispatchAuthorization.md +1 -1
- package/docs/api/interfaces/DispatchInstruction.md +1 -1
- package/docs/api/interfaces/DispatchRequest.md +1 -1
- package/docs/api/interfaces/DispatchResult.md +7 -1
- package/docs/api/interfaces/IStorageProvider.md +1 -1
- package/docs/api/interfaces/InitializeVaultCustodyOptions.md +1 -1
- package/docs/api/interfaces/InitializedVaultCustody.md +1 -1
- package/docs/api/interfaces/OpenOwnerSessionOptions.md +1 -1
- package/docs/api/interfaces/OwnerAgentProvisionResult.md +1 -1
- package/docs/api/interfaces/OwnerAuditSubscription.md +45 -0
- package/docs/api/interfaces/OwnerClient.md +20 -4
- package/docs/api/interfaces/OwnerCreateSecretInput.md +1 -1
- package/docs/api/interfaces/OwnerPendingDispatchSubscription.md +27 -0
- package/docs/api/interfaces/OwnerRemoveSecretInput.md +1 -1
- package/docs/api/interfaces/OwnerRequestRecord.md +7 -1
- package/docs/api/interfaces/OwnerSensitiveActionConfirmation.md +1 -1
- package/docs/api/interfaces/OwnerSensitiveActionContext.md +1 -1
- package/docs/api/interfaces/OwnerSession.md +1 -1
- package/docs/api/interfaces/OwnerUpdateSecretInput.md +9 -3
- package/docs/api/interfaces/OwnerVisibleRequestRecord.md +1 -1
- package/docs/api/interfaces/PendingDispatchEvent.md +23 -0
- package/docs/api/interfaces/RecoverVaultOptions.md +1 -1
- package/docs/api/interfaces/RecoveredVault.md +1 -1
- package/docs/api/interfaces/RequestRecord.md +21 -1
- package/docs/api/interfaces/RestoreIdentityOptions.md +1 -1
- package/docs/api/interfaces/SecretAlias.md +1 -1
- package/docs/api/interfaces/SecretDestinationGrant.md +1 -1
- package/docs/api/interfaces/SecretId.md +1 -1
- package/docs/api/interfaces/SecretRecord.md +1 -1
- package/docs/api/interfaces/Signer.md +1 -1
- package/docs/api/interfaces/VaultApproveDispatchInput.md +1 -1
- package/docs/api/interfaces/VaultAuditQueryInput.md +1 -1
- package/docs/api/interfaces/VaultCoreDependenciesOptions.md +1 -1
- package/docs/api/interfaces/VaultCreateAgentInput.md +1 -1
- package/docs/api/interfaces/VaultExportSecretInput.md +1 -1
- package/docs/api/interfaces/VaultGetRequestInput.md +1 -1
- package/docs/api/interfaces/VaultGrantAgentSecretInput.md +1 -1
- package/docs/api/interfaces/VaultGrantSecretDestinationInput.md +1 -1
- package/docs/api/interfaces/VaultId.md +1 -1
- package/docs/api/interfaces/VaultImportAgentInput.md +1 -1
- package/docs/api/interfaces/VaultIssueSessionTokenInput.md +1 -1
- package/docs/api/interfaces/VaultListAgentsInput.md +1 -1
- package/docs/api/interfaces/VaultListGrantsInput.md +1 -1
- package/docs/api/interfaces/VaultListRequestsInput.md +1 -1
- package/docs/api/interfaces/VaultListSecretsInput.md +1 -1
- package/docs/api/interfaces/VaultMetadata.md +1 -1
- package/docs/api/interfaces/VaultObject.md +1 -1
- package/docs/api/interfaces/VaultPrincipal.md +1 -1
- package/docs/api/interfaces/VaultProfile.md +1 -1
- package/docs/api/interfaces/VaultReadAgentPrivateKeyInput.md +1 -1
- package/docs/api/interfaces/VaultReadSecretPlaintextInput.md +1 -1
- package/docs/api/interfaces/VaultRevokeAgentSecretInput.md +1 -1
- package/docs/api/interfaces/VaultRevokeSecretDestinationInput.md +1 -1
- package/docs/api/interfaces/VaultRevokeSessionTokenInput.md +1 -1
- package/docs/api/interfaces/VaultService.md +22 -6
- package/docs/api/interfaces/VaultUpdateAgentInput.md +1 -1
- package/docs/api/type-aliases/AgentId.md +1 -1
- package/docs/api/type-aliases/AgentRequestResult.md +7 -0
- package/docs/api/type-aliases/CbioRuntimeModule.md +1 -1
- package/docs/api/type-aliases/DispatchApprovalDecision.md +1 -1
- package/docs/api/type-aliases/GrantStatus.md +1 -1
- package/docs/api/type-aliases/SecretLifecycleStatus.md +1 -1
- package/docs/api/type-aliases/VaultPrincipalKind.md +2 -2
- package/docs/api/variables/DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY.md +1 -1
- package/docs/zh/README.md +11 -3
- package/package.json +5 -3
- package/docs/api/interfaces/AgentRequestResult.md +0 -35
|
@@ -1,411 +1,321 @@
|
|
|
1
|
-
import * as fs from "node:fs/promises";
|
|
2
1
|
import * as path from "node:path";
|
|
3
2
|
import * as crypto from "node:crypto";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import Database from "better-sqlite3";
|
|
5
|
+
import { DispatchStatus, } from "./contracts.js";
|
|
4
6
|
import { DefaultPolicyEngine, HttpDispatchExecutor, InMemoryReplayGuard, RandomIdGenerator, SignatureAgentProofVerifier, SystemClock, } from "./defaults.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
_baseDir;
|
|
10
|
-
constructor(baseDir) {
|
|
11
|
-
this._baseDir = path.join(baseDir, "secrets");
|
|
12
|
-
}
|
|
13
|
-
_getPath(vault_id, secret_id) {
|
|
14
|
-
return path.join(this._baseDir, vault_id.value, `${secret_id.value}.json`);
|
|
15
|
-
}
|
|
16
|
-
_getAliasPath(vault_id, alias) {
|
|
17
|
-
return path.join(this._baseDir, vault_id.value, `alias_${Buffer.from(alias).toString("hex")}.link`);
|
|
7
|
+
export class SqliteSecretRepository {
|
|
8
|
+
db;
|
|
9
|
+
constructor(db) {
|
|
10
|
+
this.db = db;
|
|
18
11
|
}
|
|
19
12
|
async save(record) {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
const stmt = this.db.prepare(`
|
|
14
|
+
INSERT INTO secrets (secret_id, vault_id, alias, record)
|
|
15
|
+
VALUES (?, ?, ?, ?)
|
|
16
|
+
ON CONFLICT(secret_id) DO UPDATE SET record = excluded.record, alias = excluded.alias
|
|
17
|
+
`);
|
|
18
|
+
stmt.run(record.secret_id.value, record.vault_id.value, record.alias.value, JSON.stringify(record));
|
|
25
19
|
}
|
|
26
20
|
async delete(secret_id) {
|
|
27
|
-
|
|
21
|
+
this.db.prepare(`DELETE FROM secrets WHERE secret_id = ?`).run(secret_id.value);
|
|
28
22
|
}
|
|
29
23
|
async getByAlias(alias) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
for (const v of vaultDirs) {
|
|
33
|
-
const aliasPath = path.join(this._baseDir, v, `alias_${Buffer.from(alias.value).toString("hex")}.link`);
|
|
34
|
-
try {
|
|
35
|
-
const secret_id = await fs.readFile(aliasPath, "utf-8");
|
|
36
|
-
const recordPath = path.join(this._baseDir, v, `${secret_id}.json`);
|
|
37
|
-
const content = await fs.readFile(recordPath, "utf-8");
|
|
38
|
-
return JSON.parse(content);
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
async getById(secret_id) {
|
|
51
|
-
try {
|
|
52
|
-
const vaultDirs = await fs.readdir(this._baseDir);
|
|
53
|
-
for (const v of vaultDirs) {
|
|
54
|
-
const recordPath = path.join(this._baseDir, v, `${secret_id.value}.json`);
|
|
55
|
-
try {
|
|
56
|
-
const content = await fs.readFile(recordPath, "utf-8");
|
|
57
|
-
return JSON.parse(content);
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
return null;
|
|
24
|
+
const row = this.db.prepare(`SELECT record FROM secrets WHERE alias = ?`).get(alias.value);
|
|
25
|
+
return row ? JSON.parse(row.record) : null;
|
|
68
26
|
}
|
|
69
27
|
async list(vault_id) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const files = await fs.readdir(dir);
|
|
73
|
-
const results = [];
|
|
74
|
-
for (const f of files) {
|
|
75
|
-
if (f.endsWith(".json")) {
|
|
76
|
-
const content = await fs.readFile(path.join(dir, f), "utf-8");
|
|
77
|
-
results.push(JSON.parse(content));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return results;
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return [];
|
|
84
|
-
}
|
|
28
|
+
const rows = this.db.prepare(`SELECT record FROM secrets WHERE vault_id = ?`).all(vault_id.value);
|
|
29
|
+
return rows.map(r => JSON.parse(r.record));
|
|
85
30
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
_workingKey;
|
|
90
|
-
constructor(baseDir, workingKey) {
|
|
91
|
-
this._baseDir = path.join(baseDir, "custody");
|
|
92
|
-
this._workingKey = workingKey;
|
|
31
|
+
async getById(secret_id) {
|
|
32
|
+
const row = this.db.prepare(`SELECT record FROM secrets WHERE secret_id = ?`).get(secret_id.value);
|
|
33
|
+
return row ? JSON.parse(row.record) : null;
|
|
93
34
|
}
|
|
94
|
-
|
|
95
|
-
|
|
35
|
+
}
|
|
36
|
+
// AES-GCM Implementation
|
|
37
|
+
const ALGORITHM = "aes-256-gcm";
|
|
38
|
+
export class SqliteSecretCustody {
|
|
39
|
+
db;
|
|
40
|
+
keyBuffer;
|
|
41
|
+
constructor(db, workingKey) {
|
|
42
|
+
this.db = db;
|
|
43
|
+
this.keyBuffer = Buffer.from(workingKey, 'base64url');
|
|
96
44
|
}
|
|
97
45
|
async store(secret_id, plaintext) {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
46
|
+
const iv = crypto.randomBytes(12);
|
|
47
|
+
const cipher = crypto.createCipheriv(ALGORITHM, this.keyBuffer, iv);
|
|
48
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
|
|
49
|
+
const tag = cipher.getAuthTag();
|
|
50
|
+
const payload = JSON.stringify({
|
|
51
|
+
iv: iv.toString('hex'),
|
|
52
|
+
tag: tag.toString('hex'),
|
|
53
|
+
ciphertext: encrypted.toString('hex')
|
|
54
|
+
});
|
|
55
|
+
this.db.prepare(`INSERT INTO custody (secret_id, encrypted_payload) VALUES (?, ?) ON CONFLICT(secret_id) DO UPDATE SET encrypted_payload = excluded.encrypted_payload`).run(secret_id.value, payload);
|
|
101
56
|
}
|
|
102
57
|
async load(secret_id) {
|
|
58
|
+
const row = this.db.prepare(`SELECT encrypted_payload FROM custody WHERE secret_id = ?`).get(secret_id.value);
|
|
59
|
+
if (!row)
|
|
60
|
+
return null;
|
|
103
61
|
try {
|
|
104
|
-
|
|
62
|
+
const data = JSON.parse(row.encrypted_payload);
|
|
63
|
+
const iv = Buffer.from(data.iv, 'hex');
|
|
64
|
+
const tag = Buffer.from(data.tag, 'hex');
|
|
65
|
+
const encrypted = Buffer.from(data.ciphertext, 'hex');
|
|
66
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, this.keyBuffer, iv);
|
|
67
|
+
decipher.setAuthTag(tag);
|
|
68
|
+
return decipher.update(encrypted, undefined, 'utf8') + decipher.final('utf8');
|
|
105
69
|
}
|
|
106
70
|
catch {
|
|
107
71
|
return null;
|
|
108
72
|
}
|
|
109
73
|
}
|
|
110
74
|
async delete(secret_id) {
|
|
111
|
-
|
|
112
|
-
await fs.unlink(this._getPath(secret_id));
|
|
113
|
-
}
|
|
114
|
-
catch { }
|
|
75
|
+
this.db.prepare(`DELETE FROM custody WHERE secret_id = ?`).run(secret_id.value);
|
|
115
76
|
}
|
|
116
77
|
}
|
|
117
|
-
export class
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return path.join(this._baseDir, vault_id.value, "log.jsonl");
|
|
78
|
+
export class SqliteAuditLog {
|
|
79
|
+
db;
|
|
80
|
+
static subscribers = new Map();
|
|
81
|
+
get subscribers() { return SqliteAuditLog.subscribers; }
|
|
82
|
+
constructor(db) {
|
|
83
|
+
this.db = db;
|
|
124
84
|
}
|
|
125
85
|
async append(entry) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
86
|
+
this.db.prepare(`INSERT INTO audit_logs (event_id, vault_id, root_agent_id, request_id, secret_alias, ts, entry) VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
|
87
|
+
.run(entry.event_id, entry.vault_id, entry.root_agent_id || null, entry.request_id || null, entry.secret_alias || null, entry.ts, JSON.stringify(entry));
|
|
88
|
+
const subs = this.subscribers.get(entry.vault_id);
|
|
89
|
+
if (subs) {
|
|
90
|
+
for (const cb of subs)
|
|
91
|
+
cb(entry);
|
|
92
|
+
}
|
|
129
93
|
}
|
|
130
94
|
async query(query) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
95
|
+
let sql = `SELECT entry FROM audit_logs WHERE vault_id = ?`;
|
|
96
|
+
const params = [query.vault_id];
|
|
97
|
+
if (query.actor_id) {
|
|
98
|
+
sql += ` AND entry LIKE ?`;
|
|
99
|
+
params.push(`%"id":"${query.actor_id}"%`);
|
|
100
|
+
}
|
|
101
|
+
if (query.root_agent_id) {
|
|
102
|
+
sql += ` AND root_agent_id = ?`;
|
|
103
|
+
params.push(query.root_agent_id);
|
|
104
|
+
}
|
|
105
|
+
if (query.secret_alias) {
|
|
106
|
+
sql += ` AND secret_alias = ?`;
|
|
107
|
+
params.push(query.secret_alias);
|
|
108
|
+
}
|
|
109
|
+
if (query.request_id) {
|
|
110
|
+
sql += ` AND request_id = ?`;
|
|
111
|
+
params.push(query.request_id);
|
|
112
|
+
}
|
|
113
|
+
if (query.since) {
|
|
114
|
+
sql += ` AND ts >= ?`;
|
|
115
|
+
params.push(query.since);
|
|
116
|
+
}
|
|
117
|
+
sql += ` ORDER BY ts ASC LIMIT 1000`; // Limit to avoid massive memory issues conceptually
|
|
118
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
119
|
+
return rows.map(r => JSON.parse(r.entry));
|
|
120
|
+
}
|
|
121
|
+
subscribe(vault_id, subscription) {
|
|
122
|
+
let subs = this.subscribers.get(vault_id.value);
|
|
123
|
+
if (!subs) {
|
|
124
|
+
subs = new Set();
|
|
125
|
+
this.subscribers.set(vault_id.value, subs);
|
|
126
|
+
}
|
|
127
|
+
const callback = (entry) => {
|
|
128
|
+
if (subscription.afterEventId && entry.event_id <= subscription.afterEventId)
|
|
129
|
+
return;
|
|
130
|
+
if (subscription.operations && !subscription.operations.includes(entry.operation))
|
|
131
|
+
return;
|
|
132
|
+
if (subscription.root_agent_id && entry.root_agent_id !== subscription.root_agent_id)
|
|
133
|
+
return;
|
|
134
|
+
if (subscription.request_id && entry.request_id !== subscription.request_id)
|
|
135
|
+
return;
|
|
136
|
+
subscription.onEvent(entry);
|
|
137
|
+
};
|
|
138
|
+
subs.add(callback);
|
|
139
|
+
return () => {
|
|
140
|
+
const current = this.subscribers.get(vault_id.value);
|
|
141
|
+
if (current) {
|
|
142
|
+
current.delete(callback);
|
|
143
|
+
if (current.size === 0)
|
|
144
|
+
this.subscribers.delete(vault_id.value);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
153
147
|
}
|
|
154
148
|
}
|
|
155
|
-
export class
|
|
156
|
-
|
|
157
|
-
constructor(
|
|
158
|
-
this.
|
|
159
|
-
}
|
|
160
|
-
_getPath(vault_id, root_agent_id) {
|
|
161
|
-
return path.join(this._baseDir, vault_id.value, `${root_agent_id}.json`);
|
|
149
|
+
export class SqliteAgentIdentityRegistry {
|
|
150
|
+
db;
|
|
151
|
+
constructor(db) {
|
|
152
|
+
this.db = db;
|
|
162
153
|
}
|
|
163
154
|
async register(identity) {
|
|
164
|
-
|
|
165
|
-
await ensureDir(path.dirname(filePath));
|
|
166
|
-
await fs.writeFile(filePath, JSON.stringify(identity, null, 2));
|
|
155
|
+
this.db.prepare(`INSERT INTO agents (vault_id, root_agent_id, record) VALUES (?, ?, ?) ON CONFLICT(vault_id, root_agent_id) DO UPDATE SET record = excluded.record`).run(identity.vault_id.value, identity.root_agent_id, JSON.stringify(identity));
|
|
167
156
|
}
|
|
168
157
|
async get(vault_id, root_agent_id) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return JSON.parse(content);
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
158
|
+
const row = this.db.prepare(`SELECT record FROM agents WHERE vault_id = ? AND root_agent_id = ?`).get(vault_id.value, root_agent_id);
|
|
159
|
+
return row ? JSON.parse(row.record) : null;
|
|
176
160
|
}
|
|
177
161
|
async list(vault_id) {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
const files = await fs.readdir(dir);
|
|
181
|
-
return await Promise.all(files.filter(f => f.endsWith(".json")).map(async (f) => {
|
|
182
|
-
const content = await fs.readFile(path.join(dir, f), "utf-8");
|
|
183
|
-
return JSON.parse(content);
|
|
184
|
-
}));
|
|
185
|
-
}
|
|
186
|
-
catch {
|
|
187
|
-
return [];
|
|
188
|
-
}
|
|
162
|
+
const rows = this.db.prepare(`SELECT record FROM agents WHERE vault_id = ?`).all(vault_id.value);
|
|
163
|
+
return rows.map(r => JSON.parse(r.record));
|
|
189
164
|
}
|
|
190
165
|
}
|
|
191
|
-
export class
|
|
192
|
-
|
|
193
|
-
constructor(
|
|
194
|
-
this.
|
|
195
|
-
}
|
|
196
|
-
_getPath(vault_id, root_agent_id, secret_alias) {
|
|
197
|
-
return path.join(this._baseDir, vault_id.value, root_agent_id, `${Buffer.from(secret_alias).toString("hex")}.json`);
|
|
166
|
+
export class SqliteAgentSecretGrantRegistry {
|
|
167
|
+
db;
|
|
168
|
+
constructor(db) {
|
|
169
|
+
this.db = db;
|
|
198
170
|
}
|
|
199
171
|
async upsert(grant) {
|
|
200
|
-
|
|
201
|
-
await ensureDir(path.dirname(filePath));
|
|
202
|
-
await fs.writeFile(filePath, JSON.stringify(grant, null, 2));
|
|
172
|
+
this.db.prepare(`INSERT INTO grants (vault_id, root_agent_id, secret_alias, record) VALUES (?, ?, ?, ?) ON CONFLICT(vault_id, root_agent_id, secret_alias) DO UPDATE SET record = excluded.record`).run(grant.vault_id.value, grant.root_agent_id, grant.secret_alias, JSON.stringify(grant));
|
|
203
173
|
}
|
|
204
174
|
async get(vault_id, root_agent_id, secret_alias) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return JSON.parse(content);
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
175
|
+
const row = this.db.prepare(`SELECT record FROM grants WHERE vault_id = ? AND root_agent_id = ? AND secret_alias = ?`).get(vault_id.value, root_agent_id, secret_alias);
|
|
176
|
+
return row ? JSON.parse(row.record) : null;
|
|
212
177
|
}
|
|
213
178
|
async list(vault_id, root_agent_id) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const agentDir = path.join(vaultDir, aid);
|
|
220
|
-
try {
|
|
221
|
-
const files = await fs.readdir(agentDir);
|
|
222
|
-
for (const f of files) {
|
|
223
|
-
if (f.endsWith(".json")) {
|
|
224
|
-
const content = await fs.readFile(path.join(agentDir, f), "utf-8");
|
|
225
|
-
results.push(JSON.parse(content));
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return results;
|
|
234
|
-
}
|
|
235
|
-
catch {
|
|
236
|
-
return [];
|
|
179
|
+
let sql = `SELECT record FROM grants WHERE vault_id = ?`;
|
|
180
|
+
const params = [vault_id.value];
|
|
181
|
+
if (root_agent_id) {
|
|
182
|
+
sql += ` AND root_agent_id = ?`;
|
|
183
|
+
params.push(root_agent_id);
|
|
237
184
|
}
|
|
185
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
186
|
+
return rows.map(r => JSON.parse(r.record));
|
|
238
187
|
}
|
|
239
188
|
async delete(vault_id, root_agent_id, secret_alias) {
|
|
240
|
-
|
|
241
|
-
await fs.unlink(this._getPath(vault_id, root_agent_id, secret_alias));
|
|
242
|
-
}
|
|
243
|
-
catch { }
|
|
189
|
+
this.db.prepare(`DELETE FROM grants WHERE vault_id = ? AND root_agent_id = ? AND secret_alias = ?`).run(vault_id.value, root_agent_id, secret_alias);
|
|
244
190
|
}
|
|
245
191
|
}
|
|
246
|
-
export class
|
|
247
|
-
|
|
248
|
-
constructor(
|
|
249
|
-
this.
|
|
250
|
-
}
|
|
251
|
-
_getPath(vault_id, secret_alias, site_id) {
|
|
252
|
-
return path.join(this._baseDir, vault_id.value, Buffer.from(secret_alias).toString("hex"), `${Buffer.from(site_id).toString("hex")}.json`);
|
|
192
|
+
export class SqliteSecretDestinationGrantRegistry {
|
|
193
|
+
db;
|
|
194
|
+
constructor(db) {
|
|
195
|
+
this.db = db;
|
|
253
196
|
}
|
|
254
197
|
async upsert(grant) {
|
|
255
|
-
|
|
256
|
-
await ensureDir(path.dirname(filePath));
|
|
257
|
-
await fs.writeFile(filePath, JSON.stringify(grant, null, 2));
|
|
198
|
+
this.db.prepare(`INSERT INTO destination_grants (vault_id, secret_alias, site_id, record) VALUES (?, ?, ?, ?) ON CONFLICT(vault_id, secret_alias, site_id) DO UPDATE SET record = excluded.record`).run(grant.vault_id.value, grant.secret_alias, grant.site_id, JSON.stringify(grant));
|
|
258
199
|
}
|
|
259
200
|
async get(vault_id, secret_alias, site_id) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return JSON.parse(content);
|
|
263
|
-
}
|
|
264
|
-
catch {
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
201
|
+
const row = this.db.prepare(`SELECT record FROM destination_grants WHERE vault_id = ? AND secret_alias = ? AND site_id = ?`).get(vault_id.value, secret_alias, site_id);
|
|
202
|
+
return row ? JSON.parse(row.record) : null;
|
|
267
203
|
}
|
|
268
204
|
async list(vault_id, secret_alias) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const aliasDir = path.join(vaultDir, aid);
|
|
275
|
-
try {
|
|
276
|
-
const files = await fs.readdir(aliasDir);
|
|
277
|
-
for (const f of files) {
|
|
278
|
-
if (f.endsWith(".json")) {
|
|
279
|
-
const content = await fs.readFile(path.join(aliasDir, f), "utf-8");
|
|
280
|
-
results.push(JSON.parse(content));
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
catch {
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return results;
|
|
289
|
-
}
|
|
290
|
-
catch {
|
|
291
|
-
return [];
|
|
205
|
+
let sql = `SELECT record FROM destination_grants WHERE vault_id = ?`;
|
|
206
|
+
const params = [vault_id.value];
|
|
207
|
+
if (secret_alias) {
|
|
208
|
+
sql += ` AND secret_alias = ?`;
|
|
209
|
+
params.push(secret_alias);
|
|
292
210
|
}
|
|
211
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
212
|
+
return rows.map(r => JSON.parse(r.record));
|
|
293
213
|
}
|
|
294
214
|
async delete(vault_id, secret_alias, site_id) {
|
|
295
|
-
|
|
296
|
-
await fs.unlink(this._getPath(vault_id, secret_alias, site_id));
|
|
297
|
-
}
|
|
298
|
-
catch { }
|
|
215
|
+
this.db.prepare(`DELETE FROM destination_grants WHERE vault_id = ? AND secret_alias = ? AND site_id = ?`).run(vault_id.value, secret_alias, site_id);
|
|
299
216
|
}
|
|
300
217
|
}
|
|
301
|
-
export class
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
return path.join(this._baseDir, vault_id.value, `${request_id}.json`);
|
|
218
|
+
export class SqliteRequestRecordRegistry {
|
|
219
|
+
db;
|
|
220
|
+
static subscribers = new Map();
|
|
221
|
+
get subscribers() { return SqliteRequestRecordRegistry.subscribers; }
|
|
222
|
+
constructor(db) {
|
|
223
|
+
this.db = db;
|
|
308
224
|
}
|
|
309
225
|
async save(record) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
226
|
+
this.db.prepare(`INSERT INTO requests (vault_id, request_id, root_agent_id, record) VALUES (?, ?, ?, ?) ON CONFLICT(request_id) DO UPDATE SET record = excluded.record`).run(record.vault_id.value, record.request_id, record.root_agent_id, JSON.stringify(record));
|
|
227
|
+
const subs = this.subscribers.get(record.vault_id.value);
|
|
228
|
+
if (subs) {
|
|
229
|
+
for (const cb of subs)
|
|
230
|
+
cb(record);
|
|
231
|
+
}
|
|
313
232
|
}
|
|
314
233
|
async get(vault_id, request_id) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
return JSON.parse(content);
|
|
318
|
-
}
|
|
319
|
-
catch {
|
|
320
|
-
return null;
|
|
321
|
-
}
|
|
234
|
+
const row = this.db.prepare(`SELECT record FROM requests WHERE vault_id = ? AND request_id = ?`).get(vault_id.value, request_id);
|
|
235
|
+
return row ? JSON.parse(row.record) : null;
|
|
322
236
|
}
|
|
323
237
|
async list(vault_id, root_agent_id) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
238
|
+
let sql = `SELECT record FROM requests WHERE vault_id = ?`;
|
|
239
|
+
const params = [vault_id.value];
|
|
240
|
+
if (root_agent_id) {
|
|
241
|
+
sql += ` AND root_agent_id = ?`;
|
|
242
|
+
params.push(root_agent_id);
|
|
243
|
+
}
|
|
244
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
245
|
+
return rows.map(r => JSON.parse(r.record));
|
|
246
|
+
}
|
|
247
|
+
subscribePending(vault_id, subscription) {
|
|
248
|
+
const rows = this.db.prepare(`SELECT record FROM requests WHERE vault_id = ?`).all(vault_id.value);
|
|
249
|
+
const replay = rows.map(r => JSON.parse(r.record))
|
|
250
|
+
.filter((record) => record.execution.status === DispatchStatus.AWAITING_APPROVAL && !!record.pending_dispatch_event)
|
|
251
|
+
.map((record) => ({
|
|
252
|
+
event_id: record.pending_dispatch_event.event_id,
|
|
253
|
+
emitted_at: record.pending_dispatch_event.emitted_at,
|
|
254
|
+
record
|
|
255
|
+
}))
|
|
256
|
+
.filter((event) => !subscription.afterEventId || event.event_id > subscription.afterEventId)
|
|
257
|
+
.sort((a, b) => a.event_id.localeCompare(b.event_id));
|
|
258
|
+
for (const event of replay)
|
|
259
|
+
subscription.onEvent(event);
|
|
260
|
+
let subs = this.subscribers.get(vault_id.value);
|
|
261
|
+
if (!subs) {
|
|
262
|
+
subs = new Set();
|
|
263
|
+
this.subscribers.set(vault_id.value, subs);
|
|
264
|
+
}
|
|
265
|
+
const callback = (record) => {
|
|
266
|
+
if (record.execution.status !== DispatchStatus.AWAITING_APPROVAL || !record.pending_dispatch_event)
|
|
267
|
+
return;
|
|
268
|
+
const event = {
|
|
269
|
+
event_id: record.pending_dispatch_event.event_id,
|
|
270
|
+
emitted_at: record.pending_dispatch_event.emitted_at,
|
|
271
|
+
record,
|
|
272
|
+
};
|
|
273
|
+
if (subscription.afterEventId && event.event_id <= subscription.afterEventId)
|
|
274
|
+
return;
|
|
275
|
+
subscription.onEvent(event);
|
|
276
|
+
};
|
|
277
|
+
subs.add(callback);
|
|
278
|
+
return () => {
|
|
279
|
+
const current = this.subscribers.get(vault_id.value);
|
|
280
|
+
if (current) {
|
|
281
|
+
current.delete(callback);
|
|
282
|
+
if (current.size === 0)
|
|
283
|
+
this.subscribers.delete(vault_id.value);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
336
286
|
}
|
|
337
287
|
}
|
|
338
|
-
export class
|
|
339
|
-
|
|
340
|
-
constructor(
|
|
341
|
-
this.
|
|
342
|
-
}
|
|
343
|
-
_getPath(root_agent_id) {
|
|
344
|
-
return path.join(this._baseDir, `${root_agent_id}.json`);
|
|
288
|
+
export class SqliteSessionTokenRegistry {
|
|
289
|
+
db;
|
|
290
|
+
constructor(db) {
|
|
291
|
+
this.db = db;
|
|
345
292
|
}
|
|
346
293
|
async issue(root_agent_id) {
|
|
347
294
|
const token = `sat_${crypto.randomBytes(16).toString("hex")}`;
|
|
348
|
-
const stored = {
|
|
349
|
-
|
|
350
|
-
root_agent_id,
|
|
351
|
-
issued_at: new Date().toISOString(),
|
|
352
|
-
};
|
|
353
|
-
const filePath = this._getPath(root_agent_id);
|
|
354
|
-
await ensureDir(path.dirname(filePath));
|
|
355
|
-
await fs.writeFile(filePath, JSON.stringify(stored, null, 2));
|
|
295
|
+
const stored = { token, root_agent_id, issued_at: new Date().toISOString() };
|
|
296
|
+
this.db.prepare(`INSERT INTO session_tokens (root_agent_id, token, record) VALUES (?, ?, ?) ON CONFLICT(root_agent_id) DO UPDATE SET record = excluded.record, token = excluded.token`).run(root_agent_id, token, JSON.stringify(stored));
|
|
356
297
|
return token;
|
|
357
298
|
}
|
|
358
299
|
async inspect(token, root_agent_id) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const stored = JSON.parse(content);
|
|
362
|
-
if (stored.token === token) {
|
|
363
|
-
return { ok: true, token: stored };
|
|
364
|
-
}
|
|
365
|
-
const tokens = await this.list();
|
|
366
|
-
if (tokens.some((entry) => entry.token === token)) {
|
|
367
|
-
return { ok: false, reason: "agent_mismatch" };
|
|
368
|
-
}
|
|
369
|
-
return { ok: false, reason: "token_not_found" };
|
|
370
|
-
}
|
|
371
|
-
catch {
|
|
372
|
-
const tokens = await this.list();
|
|
373
|
-
if (tokens.some((entry) => entry.token === token)) {
|
|
374
|
-
return { ok: false, reason: "agent_mismatch" };
|
|
375
|
-
}
|
|
300
|
+
const row = this.db.prepare(`SELECT record, root_agent_id FROM session_tokens WHERE token = ?`).get(token);
|
|
301
|
+
if (!row)
|
|
376
302
|
return { ok: false, reason: "token_not_found" };
|
|
377
|
-
|
|
303
|
+
if (row.root_agent_id !== root_agent_id)
|
|
304
|
+
return { ok: false, reason: "agent_mismatch" };
|
|
305
|
+
return { ok: true, token: JSON.parse(row.record) };
|
|
378
306
|
}
|
|
379
307
|
async revoke(token) {
|
|
380
|
-
|
|
381
|
-
const stored = tokens.find((entry) => entry.token === token);
|
|
382
|
-
if (!stored)
|
|
383
|
-
return;
|
|
384
|
-
try {
|
|
385
|
-
await fs.unlink(this._getPath(stored.root_agent_id));
|
|
386
|
-
}
|
|
387
|
-
catch { }
|
|
308
|
+
this.db.prepare(`DELETE FROM session_tokens WHERE token = ?`).run(token);
|
|
388
309
|
}
|
|
389
310
|
async list(root_agent_id) {
|
|
311
|
+
let sql = `SELECT record FROM session_tokens`;
|
|
312
|
+
const params = [];
|
|
390
313
|
if (root_agent_id) {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return [JSON.parse(content)];
|
|
394
|
-
}
|
|
395
|
-
catch {
|
|
396
|
-
return [];
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
try {
|
|
400
|
-
const files = await fs.readdir(this._baseDir);
|
|
401
|
-
return await Promise.all(files.filter((f) => f.endsWith(".json")).map(async (f) => {
|
|
402
|
-
const content = await fs.readFile(path.join(this._baseDir, f), "utf-8");
|
|
403
|
-
return JSON.parse(content);
|
|
404
|
-
}));
|
|
405
|
-
}
|
|
406
|
-
catch {
|
|
407
|
-
return [];
|
|
314
|
+
sql += ` WHERE root_agent_id = ?`;
|
|
315
|
+
params.push(root_agent_id);
|
|
408
316
|
}
|
|
317
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
318
|
+
return rows.map(r => JSON.parse(r.record));
|
|
409
319
|
}
|
|
410
320
|
}
|
|
411
321
|
export const DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY = "master_key.sealed";
|
|
@@ -423,21 +333,46 @@ export async function recoverVaultWorkingKey(storage, recoveryKey) {
|
|
|
423
333
|
const { workingKey } = JSON.parse(data.toString());
|
|
424
334
|
return workingKey;
|
|
425
335
|
}
|
|
336
|
+
const dbCache = new Map();
|
|
337
|
+
function initDb(baseDir) {
|
|
338
|
+
if (dbCache.has(baseDir))
|
|
339
|
+
return dbCache.get(baseDir);
|
|
340
|
+
const dbPath = path.join(baseDir, "vault.sqlite");
|
|
341
|
+
const db = new Database(dbPath);
|
|
342
|
+
db.pragma('journal_mode = WAL');
|
|
343
|
+
db.exec(`
|
|
344
|
+
CREATE TABLE IF NOT EXISTS secrets (secret_id TEXT PRIMARY KEY, vault_id TEXT, alias TEXT UNIQUE, record TEXT);
|
|
345
|
+
CREATE TABLE IF NOT EXISTS custody (secret_id TEXT PRIMARY KEY, encrypted_payload TEXT);
|
|
346
|
+
CREATE TABLE IF NOT EXISTS audit_logs (event_id TEXT PRIMARY KEY, vault_id TEXT, root_agent_id TEXT, request_id TEXT, secret_alias TEXT, ts INTEGER, entry TEXT);
|
|
347
|
+
CREATE TABLE IF NOT EXISTS agents (vault_id TEXT, root_agent_id TEXT, record TEXT, PRIMARY KEY(vault_id, root_agent_id));
|
|
348
|
+
CREATE TABLE IF NOT EXISTS grants (vault_id TEXT, root_agent_id TEXT, secret_alias TEXT, record TEXT, PRIMARY KEY(vault_id, root_agent_id, secret_alias));
|
|
349
|
+
CREATE TABLE IF NOT EXISTS destination_grants (vault_id TEXT, secret_alias TEXT, site_id TEXT, record TEXT, PRIMARY KEY(vault_id, secret_alias, site_id));
|
|
350
|
+
CREATE TABLE IF NOT EXISTS requests (vault_id TEXT, request_id TEXT PRIMARY KEY, root_agent_id TEXT, record TEXT);
|
|
351
|
+
CREATE TABLE IF NOT EXISTS session_tokens (root_agent_id TEXT PRIMARY KEY, token TEXT UNIQUE, record TEXT);
|
|
352
|
+
`);
|
|
353
|
+
dbCache.set(baseDir, db);
|
|
354
|
+
return db;
|
|
355
|
+
}
|
|
426
356
|
export function createPersistentVaultCoreDependencies(storage, options) {
|
|
427
357
|
const baseDir = storage.getBaseDir();
|
|
428
|
-
|
|
429
|
-
|
|
358
|
+
// Ensure black-box environment directory exists synchronously.
|
|
359
|
+
if (!fs.existsSync(baseDir)) {
|
|
360
|
+
fs.mkdirSync(baseDir, { recursive: true });
|
|
361
|
+
}
|
|
362
|
+
const db = initDb(baseDir);
|
|
363
|
+
const agentRecords = new SqliteAgentIdentityRegistry(db);
|
|
364
|
+
const sessionTokenRegistry = new SqliteSessionTokenRegistry(db);
|
|
430
365
|
return {
|
|
431
366
|
vault_id: { value: options.vault_id },
|
|
432
367
|
ids: new RandomIdGenerator(),
|
|
433
368
|
clock: new SystemClock(),
|
|
434
369
|
agentRecords,
|
|
435
|
-
agent_secretGrants: new
|
|
436
|
-
secret_destinationGrants: new
|
|
437
|
-
audit: new
|
|
438
|
-
requests: new
|
|
439
|
-
custody: new
|
|
440
|
-
secrets: new
|
|
370
|
+
agent_secretGrants: new SqliteAgentSecretGrantRegistry(db),
|
|
371
|
+
secret_destinationGrants: new SqliteSecretDestinationGrantRegistry(db),
|
|
372
|
+
audit: new SqliteAuditLog(db),
|
|
373
|
+
requests: new SqliteRequestRecordRegistry(db),
|
|
374
|
+
custody: new SqliteSecretCustody(db, options.vaultWorkingKey),
|
|
375
|
+
secrets: new SqliteSecretRepository(db),
|
|
441
376
|
policy: new DefaultPolicyEngine(),
|
|
442
377
|
replayGuard: options.replayGuard ?? new InMemoryReplayGuard(options.proofVerifier),
|
|
443
378
|
agentProofVerifier: new SignatureAgentProofVerifier(agentRecords, sessionTokenRegistry, options.proofVerifier),
|