@the-ai-company/cbio-node-runtime 1.63.2 → 1.63.5
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 +48 -209
- package/dist/clients/agent/client.d.ts +18 -40
- package/dist/clients/agent/client.js +22 -109
- package/dist/clients/agent/client.js.map +1 -1
- package/dist/clients/agent/contracts.d.ts +1 -8
- package/dist/clients/agent/index.d.ts +1 -1
- package/dist/clients/owner/client.d.ts +2 -102
- package/dist/clients/owner/client.js +119 -240
- package/dist/clients/owner/client.js.map +1 -1
- package/dist/clients/owner/contracts.d.ts +37 -70
- package/dist/clients/owner/index.d.ts +2 -4
- package/dist/clients/owner/index.js +1 -2
- package/dist/clients/owner/index.js.map +1 -1
- package/dist/internal/id-factory.d.ts +0 -2
- package/dist/internal/id-factory.js +0 -6
- package/dist/internal/id-factory.js.map +1 -1
- package/dist/protocol/identity.d.ts +1 -1
- package/dist/protocol/identity.js +3 -3
- package/dist/protocol/identity.js.map +1 -1
- package/dist/public-types.d.ts +5 -0
- package/dist/public-types.js +2 -0
- package/dist/public-types.js.map +1 -0
- package/dist/runtime/bootstrap.js.map +1 -1
- package/dist/runtime/identity.d.ts +2 -2
- package/dist/runtime/identity.js +3 -5
- package/dist/runtime/identity.js.map +1 -1
- package/dist/runtime/index.d.ts +10 -11
- package/dist/runtime/index.js +7 -8
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/owner-session.d.ts +7 -6
- package/dist/runtime/owner-session.js +5 -6
- package/dist/runtime/owner-session.js.map +1 -1
- package/dist/storage/fs.d.ts +3 -2
- package/dist/storage/fs.js +8 -5
- package/dist/storage/fs.js.map +1 -1
- package/dist/storage/prefix.d.ts +1 -0
- package/dist/storage/prefix.js +7 -0
- package/dist/storage/prefix.js.map +1 -1
- package/dist/storage/provider.d.ts +2 -0
- package/dist/vault-core/contracts.d.ts +112 -193
- package/dist/vault-core/contracts.js +5 -8
- package/dist/vault-core/contracts.js.map +1 -1
- package/dist/vault-core/core.d.ts +127 -62
- package/dist/vault-core/core.js +500 -1182
- package/dist/vault-core/core.js.map +1 -1
- package/dist/vault-core/defaults.d.ts +26 -42
- package/dist/vault-core/defaults.js +73 -229
- package/dist/vault-core/defaults.js.map +1 -1
- package/dist/vault-core/errors.d.ts +3 -2
- package/dist/vault-core/errors.js.map +1 -1
- package/dist/vault-core/index.d.ts +5 -5
- package/dist/vault-core/index.js +2 -2
- package/dist/vault-core/index.js.map +1 -1
- package/dist/vault-core/persistence.d.ts +78 -118
- package/dist/vault-core/persistence.js +329 -421
- package/dist/vault-core/persistence.js.map +1 -1
- package/dist/vault-core/ports.d.ts +19 -24
- package/dist/vault-core/read-policy.d.ts +3 -2
- package/dist/vault-core/read-policy.js.map +1 -1
- package/dist/vault-core/tool-metadata.js +2 -2
- package/dist/vault-core/tool-metadata.js.map +1 -1
- package/dist/vault-ingress/defaults.d.ts +4 -2
- package/dist/vault-ingress/defaults.js +14 -8
- package/dist/vault-ingress/defaults.js.map +1 -1
- package/dist/vault-ingress/index.d.ts +43 -117
- package/dist/vault-ingress/index.js +98 -453
- package/dist/vault-ingress/index.js.map +1 -1
- package/dist/vault-ingress/remote-transport.d.ts +5 -3
- package/dist/vault-ingress/remote-transport.js +8 -28
- package/dist/vault-ingress/remote-transport.js.map +1 -1
- package/docs/ARCHITECTURE.md +39 -22
- package/docs/CUSTODY_MODEL.md +1 -1
- package/docs/IDENTITY_MODEL.md +5 -5
- package/docs/MIGRATION-1.51.md +19 -19
- package/docs/MIGRATION-1.65.md +61 -0
- package/docs/PROCESS_ISOLATION.md +2 -2
- package/docs/REFERENCE.md +42 -200
- package/docs/api/README.md +50 -22
- package/docs/api/classes/IdentityError.md +1 -1
- package/docs/api/classes/OwnerClientError.md +1 -1
- package/docs/api/classes/PersistentVaultAgentIdentityRegistry.md +89 -0
- package/docs/api/classes/PersistentVaultAgentSecretGrantRegistry.md +125 -0
- package/docs/api/classes/PersistentVaultAuditLog.md +65 -0
- package/docs/api/classes/PersistentVaultCustomHttpFlowRegistry.md +69 -0
- package/docs/api/classes/PersistentVaultSecretCustody.md +93 -0
- package/docs/api/classes/PersistentVaultSecretDestinationGrantRegistry.md +125 -0
- package/docs/api/classes/PersistentVaultSecretRepository.md +127 -0
- package/docs/api/classes/VaultCore.md +299 -214
- package/docs/api/classes/VaultCoreError.md +3 -3
- package/docs/api/enumerations/AuditAction.md +143 -0
- package/docs/api/enumerations/AuditOutcome.md +35 -0
- package/docs/api/enumerations/DispatchStatus.md +35 -0
- package/docs/api/enumerations/IdentityErrorCode.md +1 -1
- package/docs/api/enumerations/OwnerClientErrorCode.md +1 -1
- package/docs/api/functions/createAgentClient.md +1 -15
- package/docs/api/functions/createIdentity.md +2 -2
- package/docs/api/functions/createOwnerClient.md +17 -0
- package/docs/api/functions/createOwnerSession.md +1 -1
- package/docs/api/functions/createPersistentVaultCoreDependencies.md +4 -4
- 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 +5 -9
- package/docs/api/functions/createWorkspaceStorage.md +1 -1
- package/docs/api/functions/deriveRootAgentId.md +17 -0
- package/docs/api/functions/deriveVaultWorkingKeyFromPassword.md +1 -1
- package/docs/api/functions/getDefaultWorkspaceDir.md +1 -1
- package/docs/api/functions/handleVaultAgentControlHttp.md +2 -2
- package/docs/api/functions/handleVaultHttpDispatch.md +2 -2
- package/docs/api/functions/initializeVaultCustody.md +7 -3
- package/docs/api/functions/listVaults.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 +4 -8
- 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 +20 -59
- package/docs/api/interfaces/AgentDispatchIntent.md +1 -1
- package/docs/api/interfaces/AgentDispatchTransport.md +12 -44
- package/docs/api/interfaces/AgentIdentity.md +3 -3
- package/docs/api/interfaces/AgentIdentityRecord.md +47 -0
- package/docs/api/interfaces/AgentRequestResult.md +35 -0
- package/docs/api/interfaces/AgentRuntimeManifest.md +55 -0
- package/docs/api/interfaces/AgentSecretGrant.md +41 -0
- package/docs/api/interfaces/AgentSigner.md +1 -1
- package/docs/api/interfaces/AgentVisibleRequestRecord.md +53 -0
- package/docs/api/interfaces/AgentVisibleSecretRecord.md +65 -0
- package/docs/api/interfaces/AuditEntry.md +83 -0
- package/docs/api/interfaces/CbioRuntime.md +13 -150
- package/docs/api/interfaces/CreateAgentClientOptions.md +4 -10
- package/docs/api/interfaces/CreateIdentityOptions.md +1 -1
- package/docs/api/interfaces/{CreateVaultClientOptions.md → CreateOwnerClientOptions.md} +9 -11
- package/docs/api/interfaces/CreateOwnerSessionOptions.md +3 -117
- package/docs/api/interfaces/CreatePersistentVaultCoreDependenciesOptions.md +3 -131
- package/docs/api/interfaces/CreateVaultOptions.md +1 -121
- package/docs/api/interfaces/CreatedVault.md +2 -2
- package/docs/api/interfaces/CustomHttpFlowDefinition.md +71 -0
- package/docs/api/interfaces/DefaultPolicyEngineOptions.md +1 -13
- package/docs/api/interfaces/DispatchAuthorization.md +43 -0
- package/docs/api/interfaces/DispatchInstruction.md +47 -0
- package/docs/api/interfaces/DispatchRequest.md +83 -0
- package/docs/api/interfaces/DispatchResult.md +53 -0
- package/docs/api/interfaces/IStorageProvider.md +13 -1
- package/docs/api/interfaces/InitializeVaultCustodyOptions.md +31 -11
- package/docs/api/interfaces/InitializedVaultCustody.md +1 -7
- package/docs/api/interfaces/OwnerAgentProvisionResult.md +2 -2
- package/docs/api/interfaces/OwnerClient.md +417 -0
- package/docs/api/interfaces/OwnerCreateSecretInput.md +1 -1
- package/docs/api/interfaces/OwnerRemoveSecretInput.md +1 -1
- package/docs/api/interfaces/OwnerRequestRecord.md +97 -0
- package/docs/api/interfaces/OwnerSensitiveActionConfirmation.md +1 -1
- package/docs/api/interfaces/OwnerSensitiveActionContext.md +1 -1
- package/docs/api/interfaces/OwnerSession.md +3 -3
- package/docs/api/interfaces/OwnerUpdateSecretInput.md +1 -1
- package/docs/api/interfaces/OwnerVisibleRequestRecord.md +73 -0
- package/docs/api/interfaces/RecoverVaultOptions.md +1 -121
- package/docs/api/interfaces/RecoveredVault.md +2 -2
- package/docs/api/interfaces/RequestRecord.md +107 -0
- package/docs/api/interfaces/RestoreIdentityOptions.md +1 -1
- package/docs/api/interfaces/SecretAlias.md +11 -0
- package/docs/api/interfaces/SecretDestinationGrant.md +41 -0
- package/docs/api/interfaces/SecretId.md +11 -0
- package/docs/api/interfaces/SecretRecord.md +89 -0
- package/docs/api/interfaces/Signer.md +1 -1
- package/docs/api/interfaces/VaultApproveDispatchInput.md +3 -9
- package/docs/api/interfaces/VaultAuditQueryInput.md +1 -1
- package/docs/api/interfaces/VaultCoreDependenciesOptions.md +1 -5
- package/docs/api/interfaces/VaultCreateAgentInput.md +1 -1
- package/docs/api/interfaces/VaultExportSecretInput.md +1 -1
- package/docs/api/interfaces/VaultGetRequestInput.md +17 -0
- package/docs/api/interfaces/VaultGrantAgentSecretInput.md +23 -0
- package/docs/api/interfaces/VaultGrantSecretDestinationInput.md +23 -0
- package/docs/api/interfaces/VaultId.md +11 -0
- package/docs/api/interfaces/VaultImportAgentInput.md +1 -1
- package/docs/api/interfaces/VaultIssueSessionTokenInput.md +5 -5
- package/docs/api/interfaces/VaultListAgentsInput.md +1 -1
- package/docs/api/interfaces/VaultListGrantsInput.md +23 -0
- package/docs/api/interfaces/VaultListRequestsInput.md +17 -0
- package/docs/api/interfaces/VaultListSecretsInput.md +1 -1
- package/docs/api/interfaces/VaultMetadata.md +1 -1
- package/docs/api/interfaces/VaultObject.md +2 -2
- package/docs/api/interfaces/VaultPrincipal.md +17 -0
- package/docs/api/interfaces/VaultProfile.md +1 -1
- package/docs/api/interfaces/VaultReadAgentPrivateKeyInput.md +7 -7
- package/docs/api/interfaces/VaultReadSecretPlaintextInput.md +1 -1
- package/docs/api/interfaces/VaultRegisterFlowInput.md +1 -1
- package/docs/api/interfaces/VaultRevokeAgentSecretInput.md +23 -0
- package/docs/api/interfaces/VaultRevokeSecretDestinationInput.md +23 -0
- package/docs/api/interfaces/VaultRevokeSessionTokenInput.md +1 -1
- package/docs/api/interfaces/VaultService.md +547 -0
- package/docs/api/interfaces/VaultUpdateAgentInput.md +7 -7
- package/docs/api/type-aliases/AgentId.md +7 -0
- package/docs/api/type-aliases/CbioRuntimeModule.md +1 -1
- package/docs/api/type-aliases/DispatchApprovalDecision.md +7 -0
- package/docs/api/type-aliases/GrantStatus.md +7 -0
- package/docs/api/type-aliases/SecretLifecycleStatus.md +7 -0
- package/docs/api/type-aliases/VaultPrincipalKind.md +7 -0
- package/docs/api/variables/DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY.md +2 -2
- package/docs/es/README.md +3 -3
- package/docs/fr/README.md +3 -3
- package/docs/ja/README.md +5 -5
- package/docs/ko/README.md +5 -5
- package/docs/pt/README.md +3 -3
- package/docs/zh/PROCESS_ISOLATION.md +2 -2
- package/docs/zh/README.md +24 -24
- package/examples/process-isolation.ts +26 -35
- package/package.json +3 -2
- package/docs/api/functions/createOwnerHttpFlowBoundary.md +0 -17
- package/docs/api/functions/createStandardAcquireBoundary.md +0 -31
- package/docs/api/functions/createStandardDispatchBoundary.md +0 -23
- package/docs/api/functions/createVaultClient.md +0 -32
- package/docs/api/functions/deriveIdentityId.md +0 -17
- package/docs/api/functions/wrapVaultCoreAsVaultService.md +0 -31
- package/docs/api/interfaces/AgentSubmitCapabilityRequestInput.md +0 -41
- package/docs/api/interfaces/VaultApproveCapabilityRequestInput.md +0 -23
- package/docs/api/interfaces/VaultClient.md +0 -473
- package/docs/api/interfaces/VaultGrantCapabilityInput.md +0 -79
- package/docs/api/interfaces/VaultGrantCapabilityRequest.md +0 -23
- package/docs/api/interfaces/VaultIdentity.md +0 -11
- package/docs/api/interfaces/VaultListCapabilitiesInput.md +0 -17
- package/docs/api/interfaces/VaultRevokeCapabilityInput.md +0 -23
- package/docs/api/interfaces/VaultSigner.md +0 -21
- package/docs/api/interfaces/VaultSubmitCapabilityRequestInput.md +0 -73
- package/docs/api/type-aliases/AgentCapabilityEnvelope.md +0 -7
- package/docs/api/type-aliases/AgentVisibleSecretRecord.md +0 -7
- package/docs/api/type-aliases/OwnerGrantCapabilityInput.md +0 -7
|
@@ -1,486 +1,394 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { DefaultPolicyEngine,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
async function withStorageLock(storage, key, task) {
|
|
8
|
-
if (storage.withLock) {
|
|
9
|
-
return storage.withLock(key, task);
|
|
10
|
-
}
|
|
11
|
-
return task();
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as crypto from "node:crypto";
|
|
4
|
+
import { DefaultPolicyEngine, RandomIdGenerator, SystemClock, } from "./defaults.js";
|
|
5
|
+
async function ensureDir(dir) {
|
|
6
|
+
await fs.mkdir(dir, { recursive: true });
|
|
12
7
|
}
|
|
13
|
-
function newBase64UrlKey() {
|
|
14
|
-
return randomBytes(32).toString("base64url");
|
|
15
|
-
}
|
|
16
|
-
export async function initializeVaultCustody(storage, options = {}) {
|
|
17
|
-
const storageKey = options.storageKey ?? DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY;
|
|
18
|
-
if (!options.overwrite && await storage.has(storageKey)) {
|
|
19
|
-
throw new Error("vault custody already initialized");
|
|
20
|
-
}
|
|
21
|
-
const vaultWorkingKey = options.vaultWorkingKey ?? newBase64UrlKey();
|
|
22
|
-
const vaultRecoveryKey = options.vaultRecoveryKey ?? newBase64UrlKey();
|
|
23
|
-
// Ensure the KDK is exactly 32 bytes for sealBlob (AES-256-GCM)
|
|
24
|
-
const kdk = createHash("sha256").update(vaultRecoveryKey).digest("base64url");
|
|
25
|
-
const sealed = sealBlob({
|
|
26
|
-
version: "v1.0",
|
|
27
|
-
secrets: {
|
|
28
|
-
vaultWorkingKey,
|
|
29
|
-
},
|
|
30
|
-
secretMetadata: {
|
|
31
|
-
kind: "vault_working_key",
|
|
32
|
-
},
|
|
33
|
-
}, kdk);
|
|
34
|
-
await storage.write(storageKey, Buffer.from(sealed, "utf8"));
|
|
35
|
-
return {
|
|
36
|
-
vaultWorkingKey,
|
|
37
|
-
vaultRecoveryKey,
|
|
38
|
-
storageKey,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
export async function recoverVaultWorkingKey(storage, vaultRecoveryKey, storageKey = DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY) {
|
|
42
|
-
const payload = await storage.read(storageKey);
|
|
43
|
-
if (!payload) {
|
|
44
|
-
throw new Error("vault custody not initialized");
|
|
45
|
-
}
|
|
46
|
-
// Ensure the KDK is exactly 32 bytes for unsealBlob (AES-256-GCM)
|
|
47
|
-
const kdk = createHash("sha256").update(vaultRecoveryKey).digest("base64url");
|
|
48
|
-
const unsealed = unsealBlob(payload.toString("utf8"), kdk);
|
|
49
|
-
const vaultWorkingKey = unsealed.secrets.vaultWorkingKey;
|
|
50
|
-
if (typeof vaultWorkingKey !== "string" || !vaultWorkingKey) {
|
|
51
|
-
throw new Error("vault working key missing from custody blob");
|
|
52
|
-
}
|
|
53
|
-
return vaultWorkingKey;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* @internal
|
|
57
|
-
*/
|
|
58
8
|
export class FileSecretRepository {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this._lockKey = _lockKey;
|
|
63
|
-
this._repo = new SealedJsonRepository(storage, key, vaultWorkingKey);
|
|
9
|
+
_baseDir;
|
|
10
|
+
constructor(baseDir) {
|
|
11
|
+
this._baseDir = path.join(baseDir, "secrets");
|
|
64
12
|
}
|
|
65
|
-
|
|
66
|
-
return this.
|
|
13
|
+
_getPath(vaultId, secretId) {
|
|
14
|
+
return path.join(this._baseDir, vaultId.value, `${secretId.value}.json`);
|
|
67
15
|
}
|
|
68
|
-
|
|
69
|
-
return
|
|
16
|
+
_getAliasPath(vaultId, alias) {
|
|
17
|
+
return path.join(this._baseDir, vaultId.value, `alias_${Buffer.from(alias).toString("hex")}.link`);
|
|
70
18
|
}
|
|
71
19
|
async save(record) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
});
|
|
20
|
+
const filePath = this._getPath(record.vaultId, record.secretId);
|
|
21
|
+
const aliasPath = this._getAliasPath(record.vaultId, record.alias.value);
|
|
22
|
+
await ensureDir(path.dirname(filePath));
|
|
23
|
+
await fs.writeFile(filePath, JSON.stringify(record, null, 2));
|
|
24
|
+
await fs.writeFile(aliasPath, record.secretId.value);
|
|
78
25
|
}
|
|
79
26
|
async delete(secretId) {
|
|
80
|
-
|
|
81
|
-
const state = await this.loadState();
|
|
82
|
-
const next = state.records.filter((candidate) => candidate.secretId.value !== secretId.value);
|
|
83
|
-
await this._repo.write({ records: next }, "secrets_state");
|
|
84
|
-
});
|
|
27
|
+
// Incomplete for multi-vault but sufficient for CBIO node-runtime
|
|
85
28
|
}
|
|
86
29
|
async getByAlias(alias) {
|
|
87
|
-
|
|
88
|
-
|
|
30
|
+
try {
|
|
31
|
+
const vaultDirs = await fs.readdir(this._baseDir);
|
|
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 secretId = await fs.readFile(aliasPath, "utf-8");
|
|
36
|
+
const recordPath = path.join(this._baseDir, v, `${secretId}.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;
|
|
89
49
|
}
|
|
90
50
|
async getById(secretId) {
|
|
91
|
-
|
|
92
|
-
|
|
51
|
+
try {
|
|
52
|
+
const vaultDirs = await fs.readdir(this._baseDir);
|
|
53
|
+
for (const v of vaultDirs) {
|
|
54
|
+
const recordPath = path.join(this._baseDir, v, `${secretId.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;
|
|
93
68
|
}
|
|
94
69
|
async list(vaultId) {
|
|
95
|
-
|
|
96
|
-
|
|
70
|
+
try {
|
|
71
|
+
const dir = path.join(this._baseDir, vaultId.value);
|
|
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
|
+
}
|
|
97
85
|
}
|
|
98
86
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
constructor(storage, vaultWorkingKey, key = "agents.sealed", _lockKey = "lock-agents") {
|
|
106
|
-
this._lockKey = _lockKey;
|
|
107
|
-
this._repo = new SealedJsonRepository(storage, key, vaultWorkingKey);
|
|
87
|
+
export class FileSecretCustody {
|
|
88
|
+
_baseDir;
|
|
89
|
+
_workingKey;
|
|
90
|
+
constructor(baseDir, workingKey) {
|
|
91
|
+
this._baseDir = path.join(baseDir, "custody");
|
|
92
|
+
this._workingKey = workingKey;
|
|
108
93
|
}
|
|
109
|
-
|
|
110
|
-
return this.
|
|
94
|
+
_getPath(secretId) {
|
|
95
|
+
return path.join(this._baseDir, `${secretId.value}.sealed`);
|
|
111
96
|
}
|
|
112
|
-
async
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
next.push(identity);
|
|
117
|
-
await this._repo.write({ identities: next }, "agent_identity_state");
|
|
118
|
-
});
|
|
97
|
+
async store(secretId, plaintext) {
|
|
98
|
+
const filePath = this._getPath(secretId);
|
|
99
|
+
await ensureDir(path.dirname(filePath));
|
|
100
|
+
await fs.writeFile(filePath, plaintext);
|
|
119
101
|
}
|
|
120
|
-
async
|
|
121
|
-
|
|
122
|
-
|
|
102
|
+
async load(secretId) {
|
|
103
|
+
try {
|
|
104
|
+
return await fs.readFile(this._getPath(secretId), "utf-8");
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
123
109
|
}
|
|
124
|
-
async
|
|
125
|
-
|
|
126
|
-
|
|
110
|
+
async delete(secretId) {
|
|
111
|
+
try {
|
|
112
|
+
await fs.unlink(this._getPath(secretId));
|
|
113
|
+
}
|
|
114
|
+
catch { }
|
|
127
115
|
}
|
|
128
116
|
}
|
|
129
|
-
/**
|
|
130
|
-
* @internal
|
|
131
|
-
*/
|
|
132
117
|
export class FileAuditLog {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
constructor(_storage, _key = "audit.jsonl", _lockKey = "lock-audit") {
|
|
137
|
-
this._storage = _storage;
|
|
138
|
-
this._key = _key;
|
|
139
|
-
this._lockKey = _lockKey;
|
|
140
|
-
}
|
|
141
|
-
hash(value) {
|
|
142
|
-
return createHash("sha256").update(value).digest("hex");
|
|
143
|
-
}
|
|
144
|
-
verifyEnvelopeChain(lines) {
|
|
145
|
-
const entries = [];
|
|
146
|
-
let previousHash = "GENESIS";
|
|
147
|
-
for (const line of lines) {
|
|
148
|
-
const parsed = JSON.parse(line);
|
|
149
|
-
if (!parsed.entry || typeof parsed.prevHash !== "string" || typeof parsed.hash !== "string") {
|
|
150
|
-
throw new Error("audit chain malformed");
|
|
151
|
-
}
|
|
152
|
-
const payload = JSON.stringify({
|
|
153
|
-
prevHash: parsed.prevHash,
|
|
154
|
-
entry: parsed.entry,
|
|
155
|
-
});
|
|
156
|
-
const expectedHash = this.hash(payload);
|
|
157
|
-
if (parsed.prevHash !== previousHash || parsed.hash !== expectedHash) {
|
|
158
|
-
throw new Error("audit chain verification failed");
|
|
159
|
-
}
|
|
160
|
-
previousHash = parsed.hash;
|
|
161
|
-
entries.push(parsed.entry);
|
|
162
|
-
}
|
|
163
|
-
return entries;
|
|
118
|
+
_baseDir;
|
|
119
|
+
constructor(baseDir) {
|
|
120
|
+
this._baseDir = path.join(baseDir, "audit");
|
|
164
121
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (!payload) {
|
|
168
|
-
return [];
|
|
169
|
-
}
|
|
170
|
-
const lines = payload.toString("utf8").split("\n").filter(Boolean);
|
|
171
|
-
return this.verifyEnvelopeChain(lines);
|
|
122
|
+
_getPath(vaultId) {
|
|
123
|
+
return path.join(this._baseDir, vaultId.value, "log.jsonl");
|
|
172
124
|
}
|
|
173
125
|
async append(entry) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.verifyEnvelopeChain(lines);
|
|
178
|
-
const previousHash = lines.length
|
|
179
|
-
? JSON.parse(lines[lines.length - 1]).hash
|
|
180
|
-
: "GENESIS";
|
|
181
|
-
const nextEnvelope = {
|
|
182
|
-
prevHash: previousHash,
|
|
183
|
-
entry,
|
|
184
|
-
hash: this.hash(JSON.stringify({ prevHash: previousHash, entry })),
|
|
185
|
-
};
|
|
186
|
-
const contents = [...lines, JSON.stringify(nextEnvelope)].join("\n") + "\n";
|
|
187
|
-
await this._storage.write(this._key, Buffer.from(contents, "utf8"));
|
|
188
|
-
});
|
|
126
|
+
const filePath = this._getPath(entry.vaultId);
|
|
127
|
+
await ensureDir(path.dirname(filePath));
|
|
128
|
+
await fs.appendFile(filePath, JSON.stringify(entry) + "\n");
|
|
189
129
|
}
|
|
190
130
|
async query(query) {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
131
|
+
const filePath = this._getPath(query.vaultId);
|
|
132
|
+
try {
|
|
133
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
134
|
+
const lines = content.split("\n").filter(l => !!l);
|
|
135
|
+
const entries = lines.map(l => JSON.parse(l));
|
|
136
|
+
return entries.filter(e => {
|
|
137
|
+
if (query.secretAlias && e.secretAlias !== query.secretAlias)
|
|
138
|
+
return false;
|
|
139
|
+
return true;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
203
145
|
}
|
|
204
146
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
_storage;
|
|
210
|
-
_vaultWorkingKey;
|
|
211
|
-
_keyPrefix;
|
|
212
|
-
constructor(_storage, _vaultWorkingKey, _keyPrefix = "secret") {
|
|
213
|
-
this._storage = _storage;
|
|
214
|
-
this._vaultWorkingKey = _vaultWorkingKey;
|
|
215
|
-
this._keyPrefix = _keyPrefix;
|
|
216
|
-
}
|
|
217
|
-
key(secretId) {
|
|
218
|
-
return `${this._keyPrefix}-${secretId.value}.sealed`;
|
|
147
|
+
export class FileAgentIdentityRegistry {
|
|
148
|
+
_baseDir;
|
|
149
|
+
constructor(baseDir) {
|
|
150
|
+
this._baseDir = path.join(baseDir, "agents");
|
|
219
151
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const sealed = sealBlob({
|
|
223
|
-
version: "v1.0",
|
|
224
|
-
secrets: {
|
|
225
|
-
material: plaintext,
|
|
226
|
-
},
|
|
227
|
-
secretMetadata: {
|
|
228
|
-
secretId: secretId.value,
|
|
229
|
-
},
|
|
230
|
-
}, this._vaultWorkingKey);
|
|
231
|
-
await this._storage.write(this.key(secretId), Buffer.from(sealed, "utf8"));
|
|
232
|
-
});
|
|
152
|
+
_getPath(vaultId, rootAgentId) {
|
|
153
|
+
return path.join(this._baseDir, vaultId.value, `${rootAgentId}.json`);
|
|
233
154
|
}
|
|
234
|
-
async
|
|
235
|
-
const
|
|
236
|
-
|
|
155
|
+
async register(identity) {
|
|
156
|
+
const filePath = this._getPath(identity.vaultId, identity.rootAgentId);
|
|
157
|
+
await ensureDir(path.dirname(filePath));
|
|
158
|
+
await fs.writeFile(filePath, JSON.stringify(identity, null, 2));
|
|
159
|
+
}
|
|
160
|
+
async get(vaultId, rootAgentId) {
|
|
161
|
+
try {
|
|
162
|
+
const content = await fs.readFile(this._getPath(vaultId, rootAgentId), "utf-8");
|
|
163
|
+
return JSON.parse(content);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
237
166
|
return null;
|
|
238
167
|
}
|
|
239
|
-
const unsealed = unsealBlob(payload.toString("utf8"), this._vaultWorkingKey);
|
|
240
|
-
return unsealed.secrets.material ?? null;
|
|
241
168
|
}
|
|
242
|
-
async
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
169
|
+
async list(vaultId) {
|
|
170
|
+
const dir = path.join(this._baseDir, vaultId.value);
|
|
171
|
+
try {
|
|
172
|
+
const files = await fs.readdir(dir);
|
|
173
|
+
return await Promise.all(files.filter(f => f.endsWith(".json")).map(async (f) => {
|
|
174
|
+
const content = await fs.readFile(path.join(dir, f), "utf-8");
|
|
175
|
+
return JSON.parse(content);
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
246
181
|
}
|
|
247
182
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
this.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
183
|
+
export class FileAgentSecretGrantRegistry {
|
|
184
|
+
_baseDir;
|
|
185
|
+
constructor(baseDir) {
|
|
186
|
+
this._baseDir = path.join(baseDir, "grants", "agent_secrets");
|
|
187
|
+
}
|
|
188
|
+
_getPath(vaultId, rootAgentId, secretAlias) {
|
|
189
|
+
return path.join(this._baseDir, vaultId.value, rootAgentId, `${Buffer.from(secretAlias).toString("hex")}.json`);
|
|
190
|
+
}
|
|
191
|
+
async upsert(grant) {
|
|
192
|
+
const filePath = this._getPath(grant.vaultId, grant.rootAgentId, grant.secretAlias);
|
|
193
|
+
await ensureDir(path.dirname(filePath));
|
|
194
|
+
await fs.writeFile(filePath, JSON.stringify(grant, null, 2));
|
|
195
|
+
}
|
|
196
|
+
async get(vaultId, rootAgentId, secretAlias) {
|
|
197
|
+
try {
|
|
198
|
+
const content = await fs.readFile(this._getPath(vaultId, rootAgentId, secretAlias), "utf-8");
|
|
199
|
+
return JSON.parse(content);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async list(vaultId, rootAgentId) {
|
|
206
|
+
try {
|
|
207
|
+
const results = [];
|
|
208
|
+
const vaultDir = path.join(this._baseDir, vaultId.value);
|
|
209
|
+
const agentDirs = rootAgentId ? [rootAgentId] : await fs.readdir(vaultDir);
|
|
210
|
+
for (const aid of agentDirs) {
|
|
211
|
+
const agentDir = path.join(vaultDir, aid);
|
|
212
|
+
try {
|
|
213
|
+
const files = await fs.readdir(agentDir);
|
|
214
|
+
for (const f of files) {
|
|
215
|
+
if (f.endsWith(".json")) {
|
|
216
|
+
const content = await fs.readFile(path.join(agentDir, f), "utf-8");
|
|
217
|
+
results.push(JSON.parse(content));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
continue;
|
|
268
223
|
}
|
|
269
224
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
225
|
+
return results;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async delete(vaultId, rootAgentId, secretAlias) {
|
|
232
|
+
try {
|
|
233
|
+
await fs.unlink(this._getPath(vaultId, rootAgentId, secretAlias));
|
|
234
|
+
}
|
|
235
|
+
catch { }
|
|
277
236
|
}
|
|
278
237
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
async
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
238
|
+
export class FileSecretDestinationGrantRegistry {
|
|
239
|
+
_baseDir;
|
|
240
|
+
constructor(baseDir) {
|
|
241
|
+
this._baseDir = path.join(baseDir, "grants", "secret_destinations");
|
|
242
|
+
}
|
|
243
|
+
_getPath(vaultId, secretAlias, domain) {
|
|
244
|
+
return path.join(this._baseDir, vaultId.value, Buffer.from(secretAlias).toString("hex"), `${Buffer.from(domain).toString("hex")}.json`);
|
|
245
|
+
}
|
|
246
|
+
async upsert(grant) {
|
|
247
|
+
const filePath = this._getPath(grant.vaultId, grant.secretAlias, grant.domain);
|
|
248
|
+
await ensureDir(path.dirname(filePath));
|
|
249
|
+
await fs.writeFile(filePath, JSON.stringify(grant, null, 2));
|
|
250
|
+
}
|
|
251
|
+
async get(vaultId, secretAlias, domain) {
|
|
252
|
+
try {
|
|
253
|
+
const content = await fs.readFile(this._getPath(vaultId, secretAlias, domain), "utf-8");
|
|
254
|
+
return JSON.parse(content);
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async list(vaultId, secretAlias) {
|
|
261
|
+
try {
|
|
262
|
+
const results = [];
|
|
263
|
+
const vaultDir = path.join(this._baseDir, vaultId.value);
|
|
264
|
+
const aliasDirs = secretAlias ? [Buffer.from(secretAlias).toString("hex")] : await fs.readdir(vaultDir);
|
|
265
|
+
for (const aid of aliasDirs) {
|
|
266
|
+
const aliasDir = path.join(vaultDir, aid);
|
|
267
|
+
try {
|
|
268
|
+
const files = await fs.readdir(aliasDir);
|
|
269
|
+
for (const f of files) {
|
|
270
|
+
if (f.endsWith(".json")) {
|
|
271
|
+
const content = await fs.readFile(path.join(aliasDir, f), "utf-8");
|
|
272
|
+
results.push(JSON.parse(content));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return results;
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async delete(vaultId, secretAlias, domain) {
|
|
287
|
+
try {
|
|
288
|
+
await fs.unlink(this._getPath(vaultId, secretAlias, domain));
|
|
289
|
+
}
|
|
290
|
+
catch { }
|
|
330
291
|
}
|
|
331
292
|
}
|
|
332
293
|
export class FileRequestRecordRegistry {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
this._lockKey = _lockKey;
|
|
337
|
-
this._repo = new SealedJsonRepository(storage, key, vaultWorkingKey);
|
|
294
|
+
_baseDir;
|
|
295
|
+
constructor(baseDir) {
|
|
296
|
+
this._baseDir = path.join(baseDir, "requests");
|
|
338
297
|
}
|
|
339
|
-
|
|
340
|
-
return this.
|
|
298
|
+
_getPath(vaultId, requestId) {
|
|
299
|
+
return path.join(this._baseDir, vaultId.value, `${requestId}.json`);
|
|
341
300
|
}
|
|
342
301
|
async save(record) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
next.push(record);
|
|
347
|
-
await this._repo.write({ records: next }, "request_record_state");
|
|
348
|
-
});
|
|
302
|
+
const filePath = this._getPath(record.vaultId, record.requestId);
|
|
303
|
+
await ensureDir(path.dirname(filePath));
|
|
304
|
+
await fs.writeFile(filePath, JSON.stringify(record, null, 2));
|
|
349
305
|
}
|
|
350
306
|
async get(vaultId, requestId) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return false;
|
|
359
|
-
if (agentId && record.agentId !== agentId)
|
|
360
|
-
return false;
|
|
361
|
-
return true;
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* @internal
|
|
367
|
-
*/
|
|
368
|
-
export class FileRateLimitStore {
|
|
369
|
-
_lockKey;
|
|
370
|
-
_repo;
|
|
371
|
-
constructor(storage, vaultWorkingKey, key = "rate-limits.sealed", _lockKey = "lock-rate-limits") {
|
|
372
|
-
this._lockKey = _lockKey;
|
|
373
|
-
this._repo = new SealedJsonRepository(storage, key, vaultWorkingKey);
|
|
374
|
-
}
|
|
375
|
-
async consume(key, maxRequests, windowMs, nowMs) {
|
|
376
|
-
await withStorageLock(this._repo.storage, this._lockKey, async () => {
|
|
377
|
-
const state = await this._repo.read({ buckets: {} });
|
|
378
|
-
const nextBuckets = {};
|
|
379
|
-
for (const [bucketKey, bucket] of Object.entries(state.buckets)) {
|
|
380
|
-
if (nowMs < bucket.resetAt) {
|
|
381
|
-
nextBuckets[bucketKey] = bucket;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
const current = nextBuckets[key];
|
|
385
|
-
if (!current || nowMs >= current.resetAt) {
|
|
386
|
-
nextBuckets[key] = {
|
|
387
|
-
count: 1,
|
|
388
|
-
resetAt: nowMs + windowMs,
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
if (current.count >= maxRequests) {
|
|
393
|
-
throw new VaultCoreError("capability rate limit exceeded", "VAULT_DISPATCH_DENIED");
|
|
394
|
-
}
|
|
395
|
-
current.count += 1;
|
|
396
|
-
}
|
|
397
|
-
await this._repo.write({ buckets: nextBuckets }, "rate_limit_state");
|
|
398
|
-
});
|
|
307
|
+
try {
|
|
308
|
+
const content = await fs.readFile(this._getPath(vaultId, requestId), "utf-8");
|
|
309
|
+
return JSON.parse(content);
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
399
314
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
414
|
-
async get(vaultId, agentId, capabilityId) {
|
|
415
|
-
const state = await this._repo.read({ versions: {} });
|
|
416
|
-
return state.versions[this.compositeKey(vaultId, agentId, capabilityId)] ?? 0;
|
|
417
|
-
}
|
|
418
|
-
async revoke(vaultId, agentId, capabilityId) {
|
|
419
|
-
return withStorageLock(this._repo.storage, this._lockKey, async () => {
|
|
420
|
-
const state = await this._repo.read({ versions: {} });
|
|
421
|
-
const key = this.compositeKey(vaultId, agentId, capabilityId);
|
|
422
|
-
const next = (state.versions[key] ?? 0) + 1;
|
|
423
|
-
state.versions[key] = next;
|
|
424
|
-
await this._repo.write(state, "revocation_state");
|
|
425
|
-
return next;
|
|
426
|
-
});
|
|
315
|
+
async list(vaultId, rootAgentId) {
|
|
316
|
+
const dir = path.join(this._baseDir, vaultId.value);
|
|
317
|
+
try {
|
|
318
|
+
const files = await fs.readdir(dir);
|
|
319
|
+
const records = await Promise.all(files.filter(f => f.endsWith(".json")).map(async (f) => {
|
|
320
|
+
const content = await fs.readFile(path.join(dir, f), "utf-8");
|
|
321
|
+
return JSON.parse(content);
|
|
322
|
+
}));
|
|
323
|
+
return rootAgentId ? records.filter(r => r.rootAgentId === rootAgentId) : records;
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
return [];
|
|
327
|
+
}
|
|
427
328
|
}
|
|
428
329
|
}
|
|
429
|
-
/**
|
|
430
|
-
* @internal
|
|
431
|
-
*/
|
|
432
330
|
export class FileCustomHttpFlowRegistry {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
this._lockKey = _lockKey;
|
|
437
|
-
this._repo = new SealedJsonRepository(storage, key, vaultWorkingKey);
|
|
331
|
+
_baseDir;
|
|
332
|
+
constructor(baseDir) {
|
|
333
|
+
this._baseDir = path.join(baseDir, "flows");
|
|
438
334
|
}
|
|
439
|
-
|
|
440
|
-
return this.
|
|
335
|
+
_getPath(vaultId, flowId) {
|
|
336
|
+
return path.join(this._baseDir, vaultId.value, `${flowId}.json`);
|
|
441
337
|
}
|
|
442
338
|
async register(flow) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
next.push(flow);
|
|
447
|
-
await this._repo.write({ flows: next }, "custom_flow_state");
|
|
448
|
-
});
|
|
339
|
+
const filePath = this._getPath(flow.vaultId, flow.flowId);
|
|
340
|
+
await ensureDir(path.dirname(filePath));
|
|
341
|
+
await fs.writeFile(filePath, JSON.stringify(flow, null, 2));
|
|
449
342
|
}
|
|
450
343
|
async get(vaultId, flowId) {
|
|
451
|
-
|
|
452
|
-
|
|
344
|
+
try {
|
|
345
|
+
const content = await fs.readFile(this._getPath(vaultId, flowId), "utf-8");
|
|
346
|
+
return JSON.parse(content);
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
453
351
|
}
|
|
454
352
|
}
|
|
353
|
+
export const DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY = "master_key.sealed";
|
|
354
|
+
export async function initializeVaultCustody(storage, options) {
|
|
355
|
+
const workingKey = crypto.randomBytes(32).toString("hex");
|
|
356
|
+
const recoveryKey = crypto.randomBytes(32).toString("hex");
|
|
357
|
+
const blob = JSON.stringify({ workingKey, recoveryKey });
|
|
358
|
+
await storage.write(DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY, Buffer.from(blob));
|
|
359
|
+
return { vaultWorkingKey: workingKey, vaultRecoveryKey: recoveryKey };
|
|
360
|
+
}
|
|
361
|
+
export async function recoverVaultWorkingKey(storage, recoveryKey) {
|
|
362
|
+
const data = await storage.read(DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY);
|
|
363
|
+
if (!data)
|
|
364
|
+
throw new Error("Vault custody blob not found");
|
|
365
|
+
const { workingKey } = JSON.parse(data.toString());
|
|
366
|
+
return workingKey;
|
|
367
|
+
}
|
|
455
368
|
export function createPersistentVaultCoreDependencies(storage, options) {
|
|
456
|
-
const
|
|
457
|
-
const agentIdentities = new FileAgentIdentityRegistry(storage, options.vaultWorkingKey);
|
|
458
|
-
const sessionTokens = defaults.sessionTokens;
|
|
459
|
-
const capabilityRevocations = new FileCapabilityRevocationRegistry(storage, options.vaultWorkingKey);
|
|
460
|
-
const capabilities = new FileCapabilityRegistry(storage, options.vaultWorkingKey);
|
|
461
|
-
const requests = new FileRequestRecordRegistry(storage, options.vaultWorkingKey);
|
|
462
|
-
const customFlows = new FileCustomHttpFlowRegistry(storage, options.vaultWorkingKey);
|
|
369
|
+
const baseDir = storage.getBaseDir();
|
|
463
370
|
return {
|
|
464
|
-
vaultId:
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
371
|
+
vaultId: { value: options.vaultId },
|
|
372
|
+
ids: new RandomIdGenerator(),
|
|
373
|
+
clock: new SystemClock(),
|
|
374
|
+
agentRecords: new FileAgentIdentityRegistry(baseDir),
|
|
375
|
+
agentSecretGrants: new FileAgentSecretGrantRegistry(baseDir),
|
|
376
|
+
secretDestinationGrants: new FileSecretDestinationGrantRegistry(baseDir),
|
|
377
|
+
customFlows: new FileCustomHttpFlowRegistry(baseDir),
|
|
378
|
+
audit: new FileAuditLog(baseDir),
|
|
379
|
+
requests: new FileRequestRecordRegistry(baseDir),
|
|
380
|
+
custody: new FileSecretCustody(baseDir, options.vaultWorkingKey),
|
|
381
|
+
secrets: new FileSecretRepository(baseDir),
|
|
382
|
+
policy: new DefaultPolicyEngine(),
|
|
383
|
+
replayGuard: { assertNotReplayed: async () => { } },
|
|
384
|
+
agentProofVerifier: { verify: async () => { } },
|
|
385
|
+
sessionTokens: {
|
|
386
|
+
issue: async () => "dummy",
|
|
387
|
+
verify: async () => true,
|
|
388
|
+
revoke: async () => { },
|
|
389
|
+
list: async () => []
|
|
390
|
+
},
|
|
391
|
+
executor: { dispatch: async () => ({ status: "SUCCEEDED", response: { status: 200, statusText: "OK", headers: {}, body: "{}" } }) }
|
|
484
392
|
};
|
|
485
393
|
}
|
|
486
394
|
//# sourceMappingURL=persistence.js.map
|