@the-ai-company/cbio-node-runtime 1.48.5 → 1.49.0

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.
Files changed (126) hide show
  1. package/README.md +40 -25
  2. package/dist/clients/agent/client.d.ts +8 -6
  3. package/dist/clients/agent/client.js +67 -49
  4. package/dist/clients/agent/client.js.map +1 -1
  5. package/dist/clients/agent/contracts.d.ts +13 -1
  6. package/dist/clients/agent/index.d.ts +1 -1
  7. package/dist/clients/owner/client.d.ts +20 -14
  8. package/dist/clients/owner/client.js +140 -50
  9. package/dist/clients/owner/client.js.map +1 -1
  10. package/dist/clients/owner/contracts.d.ts +58 -26
  11. package/dist/clients/owner/index.d.ts +1 -1
  12. package/dist/runtime/index.d.ts +4 -3
  13. package/dist/runtime/index.js +5 -1
  14. package/dist/runtime/index.js.map +1 -1
  15. package/dist/vault-core/contracts.d.ts +90 -3
  16. package/dist/vault-core/contracts.js +3 -0
  17. package/dist/vault-core/contracts.js.map +1 -1
  18. package/dist/vault-core/core.d.ts +44 -25
  19. package/dist/vault-core/core.js +290 -73
  20. package/dist/vault-core/core.js.map +1 -1
  21. package/dist/vault-core/defaults.d.ts +9 -1
  22. package/dist/vault-core/defaults.js +39 -6
  23. package/dist/vault-core/defaults.js.map +1 -1
  24. package/dist/vault-core/index.d.ts +3 -3
  25. package/dist/vault-core/index.js +1 -1
  26. package/dist/vault-core/index.js.map +1 -1
  27. package/dist/vault-core/persistence.d.ts +1 -0
  28. package/dist/vault-core/persistence.js +7 -1
  29. package/dist/vault-core/persistence.js.map +1 -1
  30. package/dist/vault-core/ports.d.ts +8 -0
  31. package/dist/vault-ingress/defaults.d.ts +4 -1
  32. package/dist/vault-ingress/defaults.js +12 -3
  33. package/dist/vault-ingress/defaults.js.map +1 -1
  34. package/dist/vault-ingress/index.d.ts +137 -21
  35. package/dist/vault-ingress/index.js +156 -46
  36. package/dist/vault-ingress/index.js.map +1 -1
  37. package/dist/vault-ingress/remote-transport.d.ts +7 -2
  38. package/dist/vault-ingress/remote-transport.js +61 -3
  39. package/dist/vault-ingress/remote-transport.js.map +1 -1
  40. package/dist/vault-ingress/server-utils.d.ts +2 -1
  41. package/dist/vault-ingress/server-utils.js +42 -1
  42. package/dist/vault-ingress/server-utils.js.map +1 -1
  43. package/docs/REFERENCE.md +46 -17
  44. package/docs/api/README.md +10 -3
  45. package/docs/api/classes/IdentityError.md +1 -1
  46. package/docs/api/classes/VaultCore.md +258 -102
  47. package/docs/api/classes/VaultCoreError.md +1 -1
  48. package/docs/api/enumerations/IdentityErrorCode.md +1 -1
  49. package/docs/api/functions/createAgentClient.md +1 -1
  50. package/docs/api/functions/createIdentity.md +1 -1
  51. package/docs/api/functions/createOwnerHttpFlowBoundary.md +1 -1
  52. package/docs/api/functions/createPersistentVaultCoreDependencies.md +1 -1
  53. package/docs/api/functions/createStandardAcquireBoundary.md +1 -1
  54. package/docs/api/functions/createStandardDispatchBoundary.md +1 -1
  55. package/docs/api/functions/createVault.md +1 -1
  56. package/docs/api/functions/createVaultClient.md +1 -1
  57. package/docs/api/functions/createVaultCore.md +1 -1
  58. package/docs/api/functions/createVaultCoreDependencies.md +1 -1
  59. package/docs/api/functions/createVaultService.md +1 -1
  60. package/docs/api/functions/createWorkspaceStorage.md +1 -1
  61. package/docs/api/functions/deriveIdentityId.md +1 -1
  62. package/docs/api/functions/deriveVaultWorkingKeyFromPassword.md +1 -1
  63. package/docs/api/functions/getDefaultWorkspaceDir.md +1 -1
  64. package/docs/api/functions/handleVaultAgentControlHttp.md +21 -0
  65. package/docs/api/functions/handleVaultHttpDispatch.md +1 -1
  66. package/docs/api/functions/initializeVaultCustody.md +1 -1
  67. package/docs/api/functions/listVaults.md +1 -1
  68. package/docs/api/functions/readVaultProfile.md +1 -1
  69. package/docs/api/functions/recoverVault.md +1 -1
  70. package/docs/api/functions/recoverVaultWorkingKey.md +1 -1
  71. package/docs/api/functions/restoreIdentity.md +1 -1
  72. package/docs/api/functions/updateVaultMetadata.md +1 -1
  73. package/docs/api/functions/wrapVaultCoreAsVaultService.md +1 -1
  74. package/docs/api/functions/writeVaultProfile.md +1 -1
  75. package/docs/api/interfaces/AgentClient.md +41 -5
  76. package/docs/api/interfaces/AgentDispatchIntent.md +1 -1
  77. package/docs/api/interfaces/AgentDispatchTransport.md +51 -3
  78. package/docs/api/interfaces/AgentIdentity.md +1 -1
  79. package/docs/api/interfaces/AgentSigner.md +1 -1
  80. package/docs/api/interfaces/AgentSubmitCapabilityRequestInput.md +41 -0
  81. package/docs/api/interfaces/CbioRuntime.md +21 -1
  82. package/docs/api/interfaces/CreateAgentClientOptions.md +3 -9
  83. package/docs/api/interfaces/CreateIdentityOptions.md +1 -1
  84. package/docs/api/interfaces/CreatePersistentVaultCoreDependenciesOptions.md +1 -1
  85. package/docs/api/interfaces/CreateVaultClientOptions.md +1 -1
  86. package/docs/api/interfaces/CreateVaultOptions.md +1 -1
  87. package/docs/api/interfaces/CreatedVault.md +1 -1
  88. package/docs/api/interfaces/DefaultPolicyEngineOptions.md +1 -1
  89. package/docs/api/interfaces/IStorageProvider.md +1 -1
  90. package/docs/api/interfaces/InitializeVaultCustodyOptions.md +1 -1
  91. package/docs/api/interfaces/InitializedVaultCustody.md +1 -1
  92. package/docs/api/interfaces/OwnerAgentProvisionResult.md +17 -0
  93. package/docs/api/interfaces/OwnerDefineSecretTargetsInput.md +1 -1
  94. package/docs/api/interfaces/OwnerSecretTargetBinding.md +1 -1
  95. package/docs/api/interfaces/OwnerStoreSecretInput.md +1 -1
  96. package/docs/api/interfaces/OwnerWriteSecretInput.md +1 -1
  97. package/docs/api/interfaces/RecoverVaultOptions.md +1 -1
  98. package/docs/api/interfaces/RecoveredVault.md +1 -1
  99. package/docs/api/interfaces/RestoreIdentityOptions.md +1 -1
  100. package/docs/api/interfaces/Signer.md +1 -1
  101. package/docs/api/interfaces/VaultApproveCapabilityRequestInput.md +23 -0
  102. package/docs/api/interfaces/VaultAuditQueryInput.md +1 -1
  103. package/docs/api/interfaces/VaultClient.md +123 -33
  104. package/docs/api/interfaces/VaultCoreDependenciesOptions.md +1 -1
  105. package/docs/api/interfaces/VaultCreateAgentInput.md +1 -1
  106. package/docs/api/interfaces/VaultDeleteSecretInput.md +1 -1
  107. package/docs/api/interfaces/VaultExportSecretInput.md +1 -1
  108. package/docs/api/interfaces/VaultGrantCapabilityInput.md +13 -19
  109. package/docs/api/interfaces/VaultIdentity.md +1 -1
  110. package/docs/api/interfaces/{VaultRegisterAgentInput.md → VaultImportAgentInput.md} +4 -10
  111. package/docs/api/interfaces/VaultListAgentsInput.md +1 -1
  112. package/docs/api/interfaces/VaultListCapabilitiesInput.md +1 -1
  113. package/docs/api/interfaces/VaultListSecretsInput.md +11 -0
  114. package/docs/api/interfaces/VaultMetadata.md +1 -1
  115. package/docs/api/interfaces/VaultObject.md +1 -1
  116. package/docs/api/interfaces/VaultProfile.md +1 -1
  117. package/docs/api/interfaces/VaultRegisterFlowInput.md +1 -1
  118. package/docs/api/interfaces/VaultRevokeCapabilityInput.md +1 -1
  119. package/docs/api/interfaces/VaultSigner.md +1 -1
  120. package/docs/api/interfaces/VaultSubmitCapabilityRequestInput.md +79 -0
  121. package/docs/api/type-aliases/AgentCapabilityEnvelope.md +1 -1
  122. package/docs/api/type-aliases/AgentVisibleSecretRecord.md +7 -0
  123. package/docs/api/type-aliases/CbioRuntimeModule.md +1 -1
  124. package/docs/api/variables/DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY.md +1 -1
  125. package/examples/process-isolation.ts +24 -15
  126. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { AuditAction, AuditOutcome, DispatchStatus, } from "./contracts.js";
2
2
  import { VaultCoreError } from "./errors.js";
3
+ import { verifySignature } from "../protocol/crypto.js";
3
4
  function toAuditEntry(deps, actor, action, outcome, detail, options) {
4
5
  return {
5
6
  entryId: deps.ids.newAuditEntryId(),
@@ -33,6 +34,21 @@ function buildSecretRecord(deps, command) {
33
34
  updatedAt: now,
34
35
  };
35
36
  }
37
+ function isScopeMatch(scope, targetUrl) {
38
+ if (scope.endsWith("*")) {
39
+ return targetUrl.startsWith(scope.slice(0, -1));
40
+ }
41
+ return scope === targetUrl;
42
+ }
43
+ function createAgentControlBinding(requestId, requestedAt, agentId, action, payload = {}) {
44
+ return JSON.stringify({
45
+ requestId,
46
+ requestedAt,
47
+ agentId,
48
+ action,
49
+ ...payload,
50
+ });
51
+ }
36
52
  /**
37
53
  * The Sovereign Vault Core.
38
54
  * This is the primary implementation of the Vault logic.
@@ -40,13 +56,14 @@ function buildSecretRecord(deps, command) {
40
56
  export class VaultCore {
41
57
  _deps;
42
58
  _pendingObservers = new Set();
59
+ _pendingCapabilityObservers = new Set();
43
60
  constructor(_deps) {
44
61
  this._deps = _deps;
45
62
  }
46
63
  get vaultId() {
47
64
  return this._deps.vaultId;
48
65
  }
49
- async appendAudit(entry) {
66
+ async _appendAudit(entry) {
50
67
  try {
51
68
  await this._deps.audit.append(entry);
52
69
  }
@@ -55,8 +72,8 @@ export class VaultCore {
55
72
  throw new VaultCoreError(`audit append failed: ${message}`, "VAULT_AUDIT_FAILED");
56
73
  }
57
74
  }
58
- async appendDecisionAudit(request, outcome, detail, options) {
59
- await this.appendAudit(toAuditEntry(this._deps, request.agent, AuditAction.AUTHORIZE_DISPATCH, outcome, detail, {
75
+ async _appendDecisionAudit(request, outcome, detail, options) {
76
+ await this._appendAudit(toAuditEntry(this._deps, request.agent, AuditAction.AUTHORIZE_DISPATCH, outcome, detail, {
60
77
  requestId: request.requestId,
61
78
  capabilityId: request.capability?.capabilityId,
62
79
  operation: request.capability?.operation ?? AuditAction.AUTHORIZE_DISPATCH,
@@ -65,13 +82,75 @@ export class VaultCore {
65
82
  secretId: options?.secretId,
66
83
  }));
67
84
  }
68
- onPendingRequest(callback) {
85
+ async _verifyAgentControlProof(request, action, payload = {}) {
86
+ if (request.proof.agentId !== request.agent.id) {
87
+ throw new VaultCoreError("agent identity mismatch", "VAULT_DISPATCH_DENIED");
88
+ }
89
+ if (request.proof.token) {
90
+ const valid = await this._deps.sessionTokens.verify(request.proof.token, request.agent.id);
91
+ if (!valid) {
92
+ throw new VaultCoreError("invalid or expired session token", "VAULT_DISPATCH_DENIED");
93
+ }
94
+ return;
95
+ }
96
+ if (!request.proof.signature) {
97
+ throw new VaultCoreError("missing agent proof (signature or token required)", "VAULT_DISPATCH_DENIED");
98
+ }
99
+ if (request.proof.requestId !== request.requestId || request.proof.requestedAt !== request.requestedAt) {
100
+ throw new VaultCoreError("proof binding mismatch", "VAULT_DISPATCH_DENIED");
101
+ }
102
+ const identity = await this._deps.agentIdentities.get(request.vaultId, request.agent.id);
103
+ if (!identity) {
104
+ throw new VaultCoreError("agent identity not registered", "VAULT_DISPATCH_DENIED");
105
+ }
106
+ const binding = createAgentControlBinding(request.requestId, request.requestedAt, request.agent.id, action, payload);
107
+ if (!verifySignature(identity.publicKey, request.proof.signature, binding)) {
108
+ throw new VaultCoreError("invalid proof signature", "VAULT_DISPATCH_DENIED");
109
+ }
110
+ }
111
+ async _listVisibleSecretsForAgent(agentId) {
112
+ const capabilities = await this._deps.capabilities.list(this._deps.vaultId, agentId);
113
+ const capabilityMap = new Map();
114
+ for (const capability of capabilities) {
115
+ for (const alias of capability.secretAliases ?? []) {
116
+ const existing = capabilityMap.get(alias) ?? [];
117
+ existing.push({
118
+ capabilityId: capability.capabilityId,
119
+ scope: capability.scope,
120
+ methods: [...capability.methods],
121
+ });
122
+ capabilityMap.set(alias, existing);
123
+ }
124
+ }
125
+ const records = await this._deps.secrets.list(this._deps.vaultId);
126
+ return records.map((record) => {
127
+ const authorizedCapabilities = capabilityMap.get(record.alias.value) ?? [];
128
+ return {
129
+ vaultId: record.vaultId,
130
+ secretId: record.secretId,
131
+ alias: record.alias,
132
+ issuerId: record.issuerId,
133
+ targetBindings: [...record.targetBindings],
134
+ createdAt: record.createdAt,
135
+ updatedAt: record.updatedAt,
136
+ isAuthorizedForAgent: authorizedCapabilities.length > 0,
137
+ authorizedCapabilities,
138
+ };
139
+ });
140
+ }
141
+ ownerOnPendingDispatch(callback) {
69
142
  this._pendingObservers.add(callback);
70
143
  return () => {
71
144
  this._pendingObservers.delete(callback);
72
145
  };
73
146
  }
74
- async registerAgentIdentity(command) {
147
+ ownerOnPendingCapabilityRequest(callback) {
148
+ this._pendingCapabilityObservers.add(callback);
149
+ return () => {
150
+ this._pendingCapabilityObservers.delete(callback);
151
+ };
152
+ }
153
+ async ownerRegisterAgentIdentity(command) {
75
154
  if (command.vaultId.value !== this._deps.vaultId.value) {
76
155
  throw new VaultCoreError("identity registration vault mismatch", "VAULT_IDENTITY_DENIED");
77
156
  }
@@ -81,15 +160,15 @@ export class VaultCore {
81
160
  try {
82
161
  // Sovereign Vault: Owner has full privileges. No signature required for unlocked vault.
83
162
  await this._deps.agentIdentities.register(command.agentIdentity);
84
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_AGENT_IDENTITY, AuditOutcome.SUCCEEDED, `agent identity registered: ${command.agentIdentity.agentId}`));
163
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_AGENT_IDENTITY, AuditOutcome.SUCCEEDED, `agent identity registered: ${command.agentIdentity.agentId}`));
85
164
  }
86
165
  catch (error) {
87
166
  const detail = error instanceof Error ? error.message : String(error);
88
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_AGENT_IDENTITY, AuditOutcome.DENIED, detail));
167
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_AGENT_IDENTITY, AuditOutcome.DENIED, detail));
89
168
  throw error;
90
169
  }
91
170
  }
92
- async registerCapability(command) {
171
+ async ownerRegisterCapability(command) {
93
172
  if (command.vaultId.value !== this._deps.vaultId.value) {
94
173
  throw new VaultCoreError("capability registration vault mismatch", "VAULT_IDENTITY_DENIED");
95
174
  }
@@ -104,27 +183,73 @@ export class VaultCore {
104
183
  }
105
184
  try {
106
185
  await this._deps.capabilities.register(command.capability);
107
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CAPABILITY, AuditOutcome.SUCCEEDED, `capability registered: ${command.capability.capabilityId}`, {
186
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CAPABILITY, AuditOutcome.SUCCEEDED, `capability registered: ${command.capability.capabilityId}`, {
108
187
  capabilityId: command.capability.capabilityId,
109
188
  operation: command.capability.operation,
110
189
  }));
111
190
  }
112
191
  catch (error) {
113
192
  const detail = error instanceof Error ? error.message : String(error);
114
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CAPABILITY, AuditOutcome.DENIED, detail, {
193
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CAPABILITY, AuditOutcome.DENIED, detail, {
115
194
  capabilityId: command.capability.capabilityId,
116
195
  operation: command.capability.operation,
117
196
  }));
118
197
  throw error;
119
198
  }
120
199
  }
121
- async getCapability(vaultId, agentId, capabilityId) {
200
+ async ownerSubmitCapabilityRequest(command) {
201
+ if (command.vaultId.value !== this._deps.vaultId.value) {
202
+ throw new VaultCoreError("capability request vault mismatch", "VAULT_IDENTITY_DENIED");
203
+ }
204
+ if (!command.agentId.trim()) {
205
+ throw new VaultCoreError("capability request agent id required", "VAULT_IDENTITY_DENIED");
206
+ }
207
+ if (!command.scope.scope.trim()) {
208
+ throw new VaultCoreError("capability request scope required", "VAULT_IDENTITY_DENIED");
209
+ }
210
+ if (command.scope.methods.length === 0) {
211
+ throw new VaultCoreError("capability request method required", "VAULT_IDENTITY_DENIED");
212
+ }
213
+ const pendingRecord = {
214
+ vaultId: this._deps.vaultId,
215
+ requestId: command.requestId,
216
+ requester: command.requester,
217
+ agentId: command.agentId,
218
+ scope: {
219
+ operation: command.scope.operation,
220
+ secretAliases: command.scope.secretAliases ? [...command.scope.secretAliases] : [],
221
+ scope: command.scope.scope,
222
+ methods: [...command.scope.methods],
223
+ rateLimit: command.scope.rateLimit,
224
+ skipAudit: command.scope.skipAudit,
225
+ expiresAt: command.scope.expiresAt,
226
+ },
227
+ justification: command.justification,
228
+ requestedAt: command.requestedAt,
229
+ };
230
+ await this._deps.pendingCapabilityRequests.save(pendingRecord);
231
+ for (const observer of this._pendingCapabilityObservers) {
232
+ try {
233
+ observer(pendingRecord);
234
+ }
235
+ catch (error) {
236
+ console.error("VaultCore: error in pending capability observer:", error);
237
+ }
238
+ }
239
+ await this._appendAudit(toAuditEntry(this._deps, command.requester, AuditAction.SUBMIT_CAPABILITY_REQUEST, AuditOutcome.PENDING, `capability request submitted for agent: ${command.agentId}`, {
240
+ requestId: command.requestId,
241
+ agentId: command.agentId,
242
+ operation: command.scope.operation,
243
+ }));
244
+ return pendingRecord;
245
+ }
246
+ async _getCapability(vaultId, agentId, capabilityId) {
122
247
  if (vaultId.value !== this._deps.vaultId.value) {
123
248
  throw new VaultCoreError("capability lookup vault mismatch", "VAULT_IDENTITY_DENIED");
124
249
  }
125
250
  return this._deps.capabilities.get(vaultId, agentId, capabilityId);
126
251
  }
127
- async registerCustomFlow(command) {
252
+ async ownerRegisterCustomFlow(command) {
128
253
  if (command.vaultId.value !== this._deps.vaultId.value) {
129
254
  throw new VaultCoreError("custom flow vault mismatch", "VAULT_IDENTITY_DENIED");
130
255
  }
@@ -146,15 +271,15 @@ export class VaultCore {
146
271
  responseSecret: command.flow.responseSecret,
147
272
  createdAt: this._deps.clock.nowIso(),
148
273
  });
149
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CUSTOM_FLOW, AuditOutcome.SUCCEEDED, `custom http flow registered: ${command.flow.flowId}`));
274
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CUSTOM_FLOW, AuditOutcome.SUCCEEDED, `custom http flow registered: ${command.flow.flowId}`));
150
275
  }
151
276
  catch (error) {
152
277
  const detail = error instanceof Error ? error.message : String(error);
153
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CUSTOM_FLOW, AuditOutcome.DENIED, detail));
278
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REGISTER_CUSTOM_FLOW, AuditOutcome.DENIED, detail));
154
279
  throw error;
155
280
  }
156
281
  }
157
- async storeCustomFlowSecret(flow, alias, plaintext) {
282
+ async _storeCustomFlowSecret(flow, alias, plaintext) {
158
283
  const actor = { kind: "owner", id: flow.ownerId };
159
284
  const targetBindings = [{
160
285
  kind: "site",
@@ -165,7 +290,7 @@ export class VaultCore {
165
290
  }];
166
291
  const existing = await this._deps.secrets.getByAlias({ value: alias });
167
292
  if (existing) {
168
- await this.appendAudit(toAuditEntry(this._deps, actor, AuditAction.REASSIGN_ALIAS, AuditOutcome.DENIED, "alias already bound to existing secret; explicit alias lifecycle required", {
293
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.REASSIGN_ALIAS, AuditOutcome.DENIED, "alias already bound to existing secret; explicit alias lifecycle required", {
169
294
  secretAlias: existing.alias.value,
170
295
  secretId: existing.secretId.value,
171
296
  }));
@@ -184,7 +309,7 @@ export class VaultCore {
184
309
  try {
185
310
  await this._deps.custody.store(record.secretId, plaintext);
186
311
  await this._deps.secrets.save(record);
187
- await this.appendAudit(toAuditEntry(this._deps, actor, AuditAction.WRITE_SECRET, AuditOutcome.SUCCEEDED, `custom flow stored secret: ${alias}`, {
312
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.WRITE_SECRET, AuditOutcome.SUCCEEDED, `custom flow stored secret: ${alias}`, {
188
313
  secretAlias: record.alias.value,
189
314
  secretId: record.secretId.value,
190
315
  }));
@@ -198,7 +323,7 @@ export class VaultCore {
198
323
  }
199
324
  return record;
200
325
  }
201
- async writeSecret(command) {
326
+ async ownerWriteSecret(command) {
202
327
  if (command.vaultId.value !== this._deps.vaultId.value) {
203
328
  throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
204
329
  }
@@ -207,14 +332,14 @@ export class VaultCore {
207
332
  }
208
333
  catch (error) {
209
334
  const detail = error instanceof Error ? error.message : String(error);
210
- await this.appendAudit(toAuditEntry(this._deps, command.kind === "owner.write_secret" ? command.owner : command.issuer, AuditAction.WRITE_SECRET, AuditOutcome.DENIED, detail, {
335
+ await this._appendAudit(toAuditEntry(this._deps, command.kind === "owner.write_secret" ? command.owner : command.issuer, AuditAction.WRITE_SECRET, AuditOutcome.DENIED, detail, {
211
336
  secretAlias: command.alias,
212
337
  }));
213
338
  throw error;
214
339
  }
215
340
  const existing = await this._deps.secrets.getByAlias({ value: command.alias });
216
341
  if (existing) {
217
- await this.appendAudit(toAuditEntry(this._deps, command.kind === "owner.write_secret" ? command.owner : command.issuer, AuditAction.REASSIGN_ALIAS, AuditOutcome.DENIED, "alias already bound to existing secret; explicit alias lifecycle required", {
342
+ await this._appendAudit(toAuditEntry(this._deps, command.kind === "owner.write_secret" ? command.owner : command.issuer, AuditAction.REASSIGN_ALIAS, AuditOutcome.DENIED, "alias already bound to existing secret; explicit alias lifecycle required", {
218
343
  secretAlias: existing.alias.value,
219
344
  secretId: existing.secretId.value,
220
345
  }));
@@ -224,7 +349,7 @@ export class VaultCore {
224
349
  try {
225
350
  await this._deps.custody.store(record.secretId, command.plaintext);
226
351
  await this._deps.secrets.save(record);
227
- await this.appendAudit(toAuditEntry(this._deps, command.kind === "owner.write_secret" ? command.owner : command.issuer, AuditAction.WRITE_SECRET, AuditOutcome.SUCCEEDED, "secret stored", {
352
+ await this._appendAudit(toAuditEntry(this._deps, command.kind === "owner.write_secret" ? command.owner : command.issuer, AuditAction.WRITE_SECRET, AuditOutcome.SUCCEEDED, "secret stored", {
228
353
  secretAlias: record.alias.value,
229
354
  secretId: record.secretId.value,
230
355
  }));
@@ -238,20 +363,20 @@ export class VaultCore {
238
363
  }
239
364
  return record;
240
365
  }
241
- async deleteSecret(command) {
366
+ async ownerDeleteSecret(command) {
242
367
  const record = await this._deps.secrets.getByAlias({ value: command.alias });
243
368
  if (!record) {
244
369
  throw new VaultCoreError(`secret not found: ${command.alias}`, "VAULT_SECRET_NOT_FOUND");
245
370
  }
246
371
  await this._deps.secrets.delete(record.secretId);
247
372
  await this._deps.custody.delete(record.secretId);
248
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DELETE_SECRET, AuditOutcome.SUCCEEDED, `deleted secret ${command.alias}`, {
373
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DELETE_SECRET, AuditOutcome.SUCCEEDED, `deleted secret ${command.alias}`, {
249
374
  requestId: command.requestId,
250
375
  secretAlias: command.alias,
251
376
  secretId: record.secretId.value,
252
377
  }));
253
378
  }
254
- async defineSecretTargets(command) {
379
+ async ownerDefineSecretTargets(command) {
255
380
  if (command.vaultId.value !== this._deps.vaultId.value) {
256
381
  throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
257
382
  }
@@ -260,7 +385,7 @@ export class VaultCore {
260
385
  }
261
386
  catch (error) {
262
387
  const detail = error instanceof Error ? error.message : String(error);
263
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DEFINE_SECRET_TARGETS, AuditOutcome.DENIED, detail, {
388
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DEFINE_SECRET_TARGETS, AuditOutcome.DENIED, detail, {
264
389
  secretAlias: command.alias,
265
390
  }));
266
391
  throw error;
@@ -268,7 +393,7 @@ export class VaultCore {
268
393
  const existing = await this._deps.secrets.getByAlias({ value: command.alias });
269
394
  if (!existing) {
270
395
  const error = new VaultCoreError("secret not found", "VAULT_SECRET_NOT_FOUND");
271
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DEFINE_SECRET_TARGETS, AuditOutcome.DENIED, error.message, {
396
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DEFINE_SECRET_TARGETS, AuditOutcome.DENIED, error.message, {
272
397
  secretAlias: command.alias,
273
398
  }));
274
399
  throw error;
@@ -279,14 +404,14 @@ export class VaultCore {
279
404
  updatedAt: this._deps.clock.nowIso(),
280
405
  };
281
406
  await this._deps.secrets.save(nextRecord);
282
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DEFINE_SECRET_TARGETS, AuditOutcome.SUCCEEDED, "secret targets defined", {
407
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DEFINE_SECRET_TARGETS, AuditOutcome.SUCCEEDED, "secret targets defined", {
283
408
  requestId: command.requestId,
284
409
  secretAlias: nextRecord.alias.value,
285
410
  secretId: nextRecord.secretId.value,
286
411
  }));
287
412
  return nextRecord;
288
413
  }
289
- async authorizeDispatch(request) {
414
+ async agentAuthorizeDispatch(request) {
290
415
  if (request.vaultId.value !== this._deps.vaultId.value) {
291
416
  throw new VaultCoreError("request vault mismatch", "VAULT_DISPATCH_DENIED");
292
417
  }
@@ -294,7 +419,7 @@ export class VaultCore {
294
419
  ? await this._deps.secrets.getByAlias({ value: request.secretAlias })
295
420
  : null;
296
421
  if (request.secretAlias && !record) {
297
- await this.appendDecisionAudit(request, AuditOutcome.DENIED, "secret not found");
422
+ await this._appendDecisionAudit(request, AuditOutcome.DENIED, "secret not found");
298
423
  return {
299
424
  vaultId: this._deps.vaultId,
300
425
  decision: "deny",
@@ -310,7 +435,7 @@ export class VaultCore {
310
435
  }
311
436
  catch (error) {
312
437
  const detail = error instanceof Error ? error.message : String(error);
313
- await this.appendDecisionAudit(request, AuditOutcome.DENIED, detail, {
438
+ await this._appendDecisionAudit(request, AuditOutcome.DENIED, detail, {
314
439
  secretAlias: record?.alias.value ?? request.secretAlias,
315
440
  secretId: record?.secretId.value,
316
441
  });
@@ -352,7 +477,7 @@ export class VaultCore {
352
477
  console.error("VaultCore: error in pending observer:", error);
353
478
  }
354
479
  }
355
- await this.appendDecisionAudit(request, AuditOutcome.PENDING, "dispatch stalled for manual discovery approval", {
480
+ await this._appendDecisionAudit(request, AuditOutcome.PENDING, "dispatch stalled for manual discovery approval", {
356
481
  secretAlias: record?.alias.value ?? request.secretAlias,
357
482
  secretId: record?.secretId.value,
358
483
  });
@@ -366,7 +491,7 @@ export class VaultCore {
366
491
  }
367
492
  // Capability found, proceed
368
493
  if (!capability.skipAudit) {
369
- await this.appendDecisionAudit(request, AuditOutcome.ALLOWED, "dispatch authorized", {
494
+ await this._appendDecisionAudit(request, AuditOutcome.ALLOWED, "dispatch authorized", {
370
495
  secretAlias: record?.alias.value ?? request.secretAlias,
371
496
  secretId: record?.secretId.value,
372
497
  });
@@ -380,8 +505,8 @@ export class VaultCore {
380
505
  capability, // Expose the found capability for subsequent steps
381
506
  };
382
507
  }
383
- async dispatchSecret(request) {
384
- const authorization = await this.authorizeDispatch(request);
508
+ async agentDispatchSecret(request) {
509
+ const authorization = await this.agentAuthorizeDispatch(request);
385
510
  if (authorization.decision === "deny" || !authorization.secretId) {
386
511
  throw new VaultCoreError("dispatch denied", "VAULT_DISPATCH_DENIED");
387
512
  }
@@ -411,7 +536,7 @@ export class VaultCore {
411
536
  headers: request.headers,
412
537
  body: request.body,
413
538
  }, { record, plaintext });
414
- await this.appendAudit(toAuditEntry(this._deps, request.agent, AuditAction.DISPATCH_SECRET, result.status === DispatchStatus.SUCCEEDED ? AuditOutcome.SUCCEEDED : AuditOutcome.FAILED, result.status === DispatchStatus.SUCCEEDED ? "dispatch completed" : (result.error ?? "dispatch failed"), {
539
+ await this._appendAudit(toAuditEntry(this._deps, request.agent, AuditAction.DISPATCH_SECRET, result.status === DispatchStatus.SUCCEEDED ? AuditOutcome.SUCCEEDED : AuditOutcome.FAILED, result.status === DispatchStatus.SUCCEEDED ? "dispatch completed" : (result.error ?? "dispatch failed"), {
415
540
  requestId: request.requestId,
416
541
  capabilityId: authorization.capability?.capabilityId,
417
542
  operation: authorization.capability?.operation,
@@ -424,12 +549,12 @@ export class VaultCore {
424
549
  vaultId: this._deps.vaultId,
425
550
  };
426
551
  }
427
- async getAudit(actor, query, request) {
552
+ async ownerReadAudit(actor, query, request) {
428
553
  const entries = await this._deps.audit.query(query);
429
- await this.appendAudit(toAuditEntry(this._deps, actor, AuditAction.READ_AUDIT, AuditOutcome.ALLOWED, "audit queried"));
554
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.READ_AUDIT, AuditOutcome.ALLOWED, "audit queried"));
430
555
  return entries;
431
556
  }
432
- async exportSecret(actor, alias, request) {
557
+ async ownerExportSecret(actor, alias, request) {
433
558
  try {
434
559
  const record = await this._deps.secrets.getByAlias({ value: alias });
435
560
  if (!record) {
@@ -440,7 +565,7 @@ export class VaultCore {
440
565
  throw new VaultCoreError("secret material not found", "VAULT_SECRET_NOT_FOUND");
441
566
  }
442
567
  const exportedAt = this._deps.clock.nowIso();
443
- await this.appendAudit(toAuditEntry(this._deps, actor, AuditAction.EXPORT_SECRET, AuditOutcome.SUCCEEDED, "secret exported", {
568
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.EXPORT_SECRET, AuditOutcome.SUCCEEDED, "secret exported", {
444
569
  requestId: request?.requestId,
445
570
  secretAlias: record.alias.value,
446
571
  secretId: record.secretId.value,
@@ -455,7 +580,7 @@ export class VaultCore {
455
580
  }
456
581
  catch (error) {
457
582
  const detail = error instanceof Error ? error.message : String(error);
458
- await this.appendAudit(toAuditEntry(this._deps, actor, AuditAction.EXPORT_SECRET, AuditOutcome.DENIED, detail, {
583
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.EXPORT_SECRET, AuditOutcome.DENIED, detail, {
459
584
  requestId: request?.requestId,
460
585
  secretAlias: alias,
461
586
  }));
@@ -467,47 +592,88 @@ export class VaultCore {
467
592
  if (request.secretAlias && !capability.secretAliases?.includes(request.secretAlias)) {
468
593
  return false;
469
594
  }
470
- if (request.method && capability.allowedMethods?.length > 0 && !capability.allowedMethods.includes(request.method)) {
595
+ if (request.method && capability.methods?.length > 0 && !capability.methods.includes(request.method)) {
471
596
  return false;
472
597
  }
473
- // Target match (supports glob-like patterns in simple string comparison for now)
474
- if (capability.allowedTargets?.length > 0) {
475
- const match = capability.allowedTargets.some(target => {
476
- if (target.endsWith("*")) {
477
- const prefix = target.slice(0, -1);
478
- return request.targetUrl.startsWith(prefix);
479
- }
480
- return target === request.targetUrl;
481
- });
482
- if (!match)
483
- return false;
598
+ if (capability.scope && !isScopeMatch(capability.scope, request.targetUrl)) {
599
+ return false;
484
600
  }
485
601
  return true;
486
602
  }
487
- async listAgents(actor, request) {
603
+ async ownerListAgents(actor, request) {
488
604
  const identities = await this._deps.agentIdentities.list(this._deps.vaultId);
489
- await this.appendAudit(toAuditEntry(this._deps, actor, AuditAction.LIST_AGENTS, AuditOutcome.ALLOWED, "agent identities listed", {
605
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.LIST_AGENTS, AuditOutcome.ALLOWED, "agent identities listed", {
490
606
  requestId: request?.requestId,
491
607
  }));
492
608
  return identities;
493
609
  }
494
- async listCapabilities(actor, agentId, request) {
610
+ async ownerListCapabilities(actor, agentId, request) {
495
611
  const capabilities = await this._deps.capabilities.list(this._deps.vaultId, agentId);
496
- await this.appendAudit(toAuditEntry(this._deps, actor, AuditAction.LIST_CAPABILITIES, AuditOutcome.ALLOWED, "capabilities listed", {
612
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.LIST_CAPABILITIES, AuditOutcome.ALLOWED, "capabilities listed", {
497
613
  requestId: request?.requestId,
498
614
  agentId,
499
615
  }));
500
616
  return capabilities;
501
617
  }
502
- async revokeCapability(command) {
618
+ async ownerListSecrets(actor, request) {
619
+ const records = await this._deps.secrets.list(this._deps.vaultId);
620
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.READ_AUDIT, AuditOutcome.ALLOWED, "secret metadata listed", {
621
+ requestId: request?.requestId,
622
+ }));
623
+ return records.map((record) => ({
624
+ vaultId: record.vaultId,
625
+ secretId: record.secretId,
626
+ alias: record.alias,
627
+ issuerId: record.issuerId,
628
+ targetBindings: [...record.targetBindings],
629
+ createdAt: record.createdAt,
630
+ updatedAt: record.updatedAt,
631
+ }));
632
+ }
633
+ async agentListCapabilities(request) {
634
+ if (request.vaultId.value !== this._deps.vaultId.value) {
635
+ throw new VaultCoreError("read vault mismatch", "VAULT_READ_DENIED");
636
+ }
637
+ await this._verifyAgentControlProof(request, "list_capabilities");
638
+ return this._deps.capabilities.list(this._deps.vaultId, request.agent.id);
639
+ }
640
+ async agentListSecrets(request) {
641
+ if (request.vaultId.value !== this._deps.vaultId.value) {
642
+ throw new VaultCoreError("read vault mismatch", "VAULT_READ_DENIED");
643
+ }
644
+ await this._verifyAgentControlProof(request, "list_secrets");
645
+ return this._listVisibleSecretsForAgent(request.agent.id);
646
+ }
647
+ async agentSubmitCapabilityRequest(command) {
648
+ if (command.vaultId.value !== this._deps.vaultId.value) {
649
+ throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
650
+ }
651
+ await this._verifyAgentControlProof(command, "submit_capability_request", {
652
+ scope: command.scope.scope,
653
+ methods: command.scope.methods,
654
+ operation: command.scope.operation,
655
+ secretAliases: command.scope.secretAliases ?? [],
656
+ justification: command.justification ?? null,
657
+ });
658
+ return this.ownerSubmitCapabilityRequest({
659
+ vaultId: command.vaultId,
660
+ requestId: command.requestId,
661
+ requester: command.agent,
662
+ agentId: command.agent.id,
663
+ scope: command.scope,
664
+ justification: command.justification,
665
+ requestedAt: command.requestedAt,
666
+ });
667
+ }
668
+ async ownerRevokeCapability(command) {
503
669
  await this._deps.policy.revokeCapability(command.vaultId, command.agentId, command.capabilityId);
504
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REVOKE_CAPABILITY, AuditOutcome.SUCCEEDED, "capability revoked", {
670
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REVOKE_CAPABILITY, AuditOutcome.SUCCEEDED, "capability revoked", {
505
671
  requestId: command.requestId,
506
672
  agentId: command.agentId,
507
673
  capabilityId: command.capabilityId,
508
674
  }));
509
675
  }
510
- async issueAgentSessionToken(request) {
676
+ async ownerIssueSessionToken(request) {
511
677
  if (request.vaultId.value !== this._deps.vaultId.value) {
512
678
  throw new VaultCoreError("session token vault mismatch", "VAULT_IDENTITY_DENIED");
513
679
  }
@@ -517,19 +683,19 @@ export class VaultCore {
517
683
  }
518
684
  const token = await this._deps.sessionTokens.issue(request.agentId);
519
685
  const issuedAt = this._deps.clock.nowIso();
520
- await this.appendAudit(toAuditEntry(this._deps, request.actor, AuditAction.ISSUE_SESSION_TOKEN, AuditOutcome.SUCCEEDED, `session token issued for agent: ${request.agentId}`));
686
+ await this._appendAudit(toAuditEntry(this._deps, request.actor, AuditAction.ISSUE_SESSION_TOKEN, AuditOutcome.SUCCEEDED, `session token issued for agent: ${request.agentId}`));
521
687
  return {
522
688
  token,
523
689
  agentId: request.agentId,
524
690
  issuedAt,
525
691
  };
526
692
  }
527
- async issueAllAgentSessionTokens(actor) {
693
+ async ownerIssueAllAgentSessionTokens(actor) {
528
694
  const agents = await this._deps.agentIdentities.list(this._deps.vaultId);
529
695
  const results = [];
530
696
  const requestedAt = this._deps.clock.nowIso();
531
697
  for (const agent of agents) {
532
- results.push(await this.issueAgentSessionToken({
698
+ results.push(await this.ownerIssueSessionToken({
533
699
  vaultId: this._deps.vaultId,
534
700
  requestId: `warmup_${this._deps.ids.newVersion().value}`,
535
701
  actor,
@@ -539,20 +705,72 @@ export class VaultCore {
539
705
  }
540
706
  return results;
541
707
  }
542
- async revokeAgentSessionToken(request) {
708
+ async ownerRevokeSessionToken(request) {
543
709
  if (request.vaultId.value !== this._deps.vaultId.value) {
544
710
  throw new VaultCoreError("session token vault mismatch", "VAULT_IDENTITY_DENIED");
545
711
  }
546
712
  await this._deps.sessionTokens.revoke(request.token);
547
- await this.appendAudit(toAuditEntry(this._deps, request.actor, AuditAction.REVOKE_SESSION_TOKEN, AuditOutcome.SUCCEEDED, "session token revoked"));
713
+ await this._appendAudit(toAuditEntry(this._deps, request.actor, AuditAction.REVOKE_SESSION_TOKEN, AuditOutcome.SUCCEEDED, "session token revoked"));
548
714
  }
549
- async listPendingDispatches(command) {
715
+ async ownerListPendingDispatches(command) {
550
716
  if (command.vaultId.value !== this._deps.vaultId.value) {
551
717
  throw new VaultCoreError("read vault mismatch", "VAULT_READ_DENIED");
552
718
  }
553
719
  return this._deps.pendingRequests.list(command.vaultId);
554
720
  }
555
- async approveDispatch(command) {
721
+ async ownerListPendingCapabilityRequests(command) {
722
+ if (command.vaultId.value !== this._deps.vaultId.value) {
723
+ throw new VaultCoreError("read vault mismatch", "VAULT_READ_DENIED");
724
+ }
725
+ return this._deps.pendingCapabilityRequests.list(command.vaultId);
726
+ }
727
+ async ownerApproveCapabilityRequest(command) {
728
+ if (command.vaultId.value !== this._deps.vaultId.value) {
729
+ throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
730
+ }
731
+ const pending = await this._deps.pendingCapabilityRequests.get(command.requestId);
732
+ if (!pending) {
733
+ throw new VaultCoreError("pending capability request not found", "VAULT_REQUEST_NOT_FOUND");
734
+ }
735
+ const capability = {
736
+ vaultId: this._deps.vaultId,
737
+ agentId: pending.agentId,
738
+ capabilityId: command.capabilityId ?? `cap_${this._deps.ids.newVersion().value}`,
739
+ operation: pending.scope.operation,
740
+ secretAliases: pending.scope.secretAliases ? [...pending.scope.secretAliases] : [],
741
+ scope: pending.scope.scope,
742
+ methods: [...pending.scope.methods],
743
+ rateLimit: pending.scope.rateLimit,
744
+ skipAudit: pending.scope.skipAudit,
745
+ expiresAt: pending.scope.expiresAt,
746
+ issuedAt: this._deps.clock.nowIso(),
747
+ };
748
+ await this._deps.capabilities.register(capability);
749
+ await this._deps.pendingCapabilityRequests.delete(command.requestId);
750
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.APPROVE_CAPABILITY_REQUEST, AuditOutcome.SUCCEEDED, `approved capability request ${command.requestId}`, {
751
+ requestId: command.requestId,
752
+ agentId: pending.agentId,
753
+ capabilityId: capability.capabilityId,
754
+ operation: capability.operation,
755
+ }));
756
+ return capability;
757
+ }
758
+ async ownerRejectCapabilityRequest(command) {
759
+ if (command.vaultId.value !== this._deps.vaultId.value) {
760
+ throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
761
+ }
762
+ const pending = await this._deps.pendingCapabilityRequests.get(command.requestId);
763
+ if (!pending) {
764
+ throw new VaultCoreError("pending capability request not found", "VAULT_REQUEST_NOT_FOUND");
765
+ }
766
+ await this._deps.pendingCapabilityRequests.delete(command.requestId);
767
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REJECT_CAPABILITY_REQUEST, AuditOutcome.SUCCEEDED, `rejected capability request ${command.requestId}`, {
768
+ requestId: command.requestId,
769
+ agentId: pending.agentId,
770
+ operation: pending.scope.operation,
771
+ }));
772
+ }
773
+ async ownerApproveDispatch(command) {
556
774
  if (command.vaultId.value !== this._deps.vaultId.value) {
557
775
  throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
558
776
  }
@@ -580,9 +798,8 @@ export class VaultCore {
580
798
  agentId: pending.agentId,
581
799
  capabilityId,
582
800
  secretAliases: [pending.secretAlias],
583
- allowedMethods: [pending.method],
584
- allowedTargets: [pending.targetUrl],
585
- allowedPaths: [],
801
+ methods: [pending.method],
802
+ scope: pending.targetUrl,
586
803
  operation: "dispatch_http",
587
804
  issuedAt: this._deps.clock.nowIso(),
588
805
  skipAudit: command.skipAudit ?? false,
@@ -591,7 +808,7 @@ export class VaultCore {
591
808
  await this._deps.capabilities.register(capability);
592
809
  }
593
810
  }
594
- const result = await this.dispatchSecret({
811
+ const result = await this.agentDispatchSecret({
595
812
  vaultId: this._deps.vaultId,
596
813
  agent: { kind: "agent", id: pending.agentId },
597
814
  capability: capability,
@@ -605,14 +822,14 @@ export class VaultCore {
605
822
  requestedAt: pending.requestedAt,
606
823
  });
607
824
  await this._deps.pendingRequests.delete(command.requestId);
608
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.APPROVE_DISPATCH, AuditOutcome.SUCCEEDED, `approved dispatch ${command.requestId}${command.permanent ? " and granted permanent capability" : ""}`, {
825
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.APPROVE_DISPATCH, AuditOutcome.SUCCEEDED, `approved dispatch ${command.requestId}${command.permanent ? " and granted permanent capability" : ""}`, {
609
826
  requestId: command.requestId,
610
827
  agentId: pending.agentId,
611
828
  capabilityId: capability.capabilityId,
612
829
  }));
613
830
  return result;
614
831
  }
615
- async rejectDispatch(command) {
832
+ async ownerRejectDispatch(command) {
616
833
  if (command.vaultId.value !== this._deps.vaultId.value) {
617
834
  throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
618
835
  }
@@ -621,7 +838,7 @@ export class VaultCore {
621
838
  throw new VaultCoreError("pending request not found", "VAULT_REQUEST_NOT_FOUND");
622
839
  }
623
840
  await this._deps.pendingRequests.delete(command.requestId);
624
- await this.appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REJECT_DISPATCH, AuditOutcome.SUCCEEDED, `rejected dispatch ${command.requestId}`, {
841
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.REJECT_DISPATCH, AuditOutcome.SUCCEEDED, `rejected dispatch ${command.requestId}`, {
625
842
  requestId: command.requestId,
626
843
  }));
627
844
  }