@the-ai-company/cbio-node-runtime 1.59.1 → 1.61.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 (125) hide show
  1. package/README.md +7 -4
  2. package/dist/clients/agent/client.d.ts +6 -0
  3. package/dist/clients/agent/client.js.map +1 -1
  4. package/dist/clients/owner/client.d.ts +9 -7
  5. package/dist/clients/owner/client.js +46 -11
  6. package/dist/clients/owner/client.js.map +1 -1
  7. package/dist/clients/owner/contracts.d.ts +22 -11
  8. package/dist/clients/owner/index.d.ts +1 -1
  9. package/dist/runtime/index.d.ts +1 -1
  10. package/dist/vault-core/contracts.d.ts +87 -3
  11. package/dist/vault-core/contracts.js +2 -0
  12. package/dist/vault-core/contracts.js.map +1 -1
  13. package/dist/vault-core/core.d.ts +14 -1
  14. package/dist/vault-core/core.js +254 -24
  15. package/dist/vault-core/core.js.map +1 -1
  16. package/dist/vault-core/defaults.d.ts +1 -0
  17. package/dist/vault-core/defaults.js +8 -4
  18. package/dist/vault-core/defaults.js.map +1 -1
  19. package/dist/vault-core/index.d.ts +1 -1
  20. package/dist/vault-core/index.js.map +1 -1
  21. package/dist/vault-core/persistence.d.ts +1 -0
  22. package/dist/vault-core/persistence.js +6 -3
  23. package/dist/vault-core/persistence.js.map +1 -1
  24. package/dist/vault-core/tool-metadata.js +4 -4
  25. package/dist/vault-core/tool-metadata.js.map +1 -1
  26. package/dist/vault-ingress/index.d.ts +16 -0
  27. package/dist/vault-ingress/index.js +34 -2
  28. package/dist/vault-ingress/index.js.map +1 -1
  29. package/docs/REFERENCE.md +9 -5
  30. package/docs/api/README.md +5 -5
  31. package/docs/api/classes/IdentityError.md +1 -1
  32. package/docs/api/classes/OwnerClientError.md +1 -1
  33. package/docs/api/classes/VaultCore.md +97 -1
  34. package/docs/api/classes/VaultCoreError.md +1 -1
  35. package/docs/api/enumerations/IdentityErrorCode.md +1 -1
  36. package/docs/api/enumerations/OwnerClientErrorCode.md +1 -1
  37. package/docs/api/functions/createAgentClient.md +1 -1
  38. package/docs/api/functions/createIdentity.md +1 -1
  39. package/docs/api/functions/createOwnerHttpFlowBoundary.md +1 -1
  40. package/docs/api/functions/createOwnerSession.md +1 -1
  41. package/docs/api/functions/createPersistentVaultCoreDependencies.md +1 -1
  42. package/docs/api/functions/createStandardAcquireBoundary.md +1 -1
  43. package/docs/api/functions/createStandardDispatchBoundary.md +1 -1
  44. package/docs/api/functions/createVault.md +1 -1
  45. package/docs/api/functions/createVaultClient.md +1 -1
  46. package/docs/api/functions/createVaultCore.md +1 -1
  47. package/docs/api/functions/createVaultCoreDependencies.md +1 -1
  48. package/docs/api/functions/createVaultService.md +1 -1
  49. package/docs/api/functions/createWorkspaceStorage.md +1 -1
  50. package/docs/api/functions/deriveIdentityId.md +1 -1
  51. package/docs/api/functions/deriveVaultWorkingKeyFromPassword.md +1 -1
  52. package/docs/api/functions/getDefaultWorkspaceDir.md +1 -1
  53. package/docs/api/functions/handleVaultAgentControlHttp.md +1 -1
  54. package/docs/api/functions/handleVaultHttpDispatch.md +1 -1
  55. package/docs/api/functions/initializeVaultCustody.md +1 -1
  56. package/docs/api/functions/listVaults.md +1 -1
  57. package/docs/api/functions/readVaultProfile.md +1 -1
  58. package/docs/api/functions/recoverVault.md +1 -1
  59. package/docs/api/functions/recoverVaultWorkingKey.md +1 -1
  60. package/docs/api/functions/restoreIdentity.md +1 -1
  61. package/docs/api/functions/updateVaultMetadata.md +1 -1
  62. package/docs/api/functions/wrapVaultCoreAsVaultService.md +1 -1
  63. package/docs/api/functions/writeVaultProfile.md +1 -1
  64. package/docs/api/interfaces/AgentClient.md +7 -1
  65. package/docs/api/interfaces/AgentDispatchIntent.md +1 -1
  66. package/docs/api/interfaces/AgentDispatchTransport.md +1 -1
  67. package/docs/api/interfaces/AgentIdentity.md +1 -1
  68. package/docs/api/interfaces/AgentSigner.md +1 -1
  69. package/docs/api/interfaces/AgentSubmitCapabilityRequestInput.md +1 -1
  70. package/docs/api/interfaces/CbioRuntime.md +1 -1
  71. package/docs/api/interfaces/CreateAgentClientOptions.md +1 -1
  72. package/docs/api/interfaces/CreateIdentityOptions.md +1 -1
  73. package/docs/api/interfaces/CreateOwnerSessionOptions.md +1 -1
  74. package/docs/api/interfaces/CreatePersistentVaultCoreDependenciesOptions.md +1 -1
  75. package/docs/api/interfaces/CreateVaultClientOptions.md +1 -1
  76. package/docs/api/interfaces/CreateVaultOptions.md +1 -1
  77. package/docs/api/interfaces/CreatedVault.md +1 -1
  78. package/docs/api/interfaces/DefaultPolicyEngineOptions.md +1 -1
  79. package/docs/api/interfaces/IStorageProvider.md +1 -1
  80. package/docs/api/interfaces/InitializeVaultCustodyOptions.md +1 -1
  81. package/docs/api/interfaces/InitializedVaultCustody.md +1 -1
  82. package/docs/api/interfaces/OwnerAgentProvisionResult.md +1 -1
  83. package/docs/api/interfaces/{OwnerStoreSecretInput.md → OwnerCreateSecretInput.md} +2 -2
  84. package/docs/api/interfaces/{VaultDeleteSecretInput.md → OwnerRemoveSecretInput.md} +2 -2
  85. package/docs/api/interfaces/OwnerSensitiveActionConfirmation.md +1 -1
  86. package/docs/api/interfaces/OwnerSensitiveActionContext.md +1 -1
  87. package/docs/api/interfaces/OwnerSession.md +1 -1
  88. package/docs/api/interfaces/{OwnerWriteSecretInput.md → OwnerUpdateSecretInput.md} +2 -2
  89. package/docs/api/interfaces/RecoverVaultOptions.md +1 -1
  90. package/docs/api/interfaces/RecoveredVault.md +1 -1
  91. package/docs/api/interfaces/RestoreIdentityOptions.md +1 -1
  92. package/docs/api/interfaces/Signer.md +1 -1
  93. package/docs/api/interfaces/VaultApproveCapabilityRequestInput.md +7 -1
  94. package/docs/api/interfaces/VaultApproveDispatchInput.md +1 -1
  95. package/docs/api/interfaces/VaultAuditQueryInput.md +1 -1
  96. package/docs/api/interfaces/VaultClient.md +55 -23
  97. package/docs/api/interfaces/VaultCoreDependenciesOptions.md +1 -1
  98. package/docs/api/interfaces/VaultCreateAgentInput.md +1 -1
  99. package/docs/api/interfaces/VaultExportSecretInput.md +1 -1
  100. package/docs/api/interfaces/VaultGrantCapabilityInput.md +1 -1
  101. package/docs/api/interfaces/VaultGrantCapabilityRequest.md +1 -1
  102. package/docs/api/interfaces/VaultIdentity.md +1 -1
  103. package/docs/api/interfaces/VaultImportAgentInput.md +1 -1
  104. package/docs/api/interfaces/VaultIssueSessionTokenInput.md +1 -1
  105. package/docs/api/interfaces/VaultListAgentsInput.md +1 -1
  106. package/docs/api/interfaces/VaultListCapabilitiesInput.md +1 -1
  107. package/docs/api/interfaces/VaultListSecretsInput.md +1 -1
  108. package/docs/api/interfaces/VaultMetadata.md +1 -1
  109. package/docs/api/interfaces/VaultObject.md +1 -1
  110. package/docs/api/interfaces/VaultProfile.md +1 -1
  111. package/docs/api/interfaces/VaultReadAgentPrivateKeyInput.md +1 -1
  112. package/docs/api/interfaces/VaultReadSecretPlaintextInput.md +1 -1
  113. package/docs/api/interfaces/VaultRegisterFlowInput.md +1 -1
  114. package/docs/api/interfaces/VaultRevokeCapabilityInput.md +1 -1
  115. package/docs/api/interfaces/VaultRevokeSessionTokenInput.md +1 -1
  116. package/docs/api/interfaces/VaultSigner.md +1 -1
  117. package/docs/api/interfaces/VaultSubmitCapabilityRequestInput.md +1 -1
  118. package/docs/api/interfaces/VaultUpdateAgentInput.md +1 -1
  119. package/docs/api/type-aliases/AgentCapabilityEnvelope.md +1 -1
  120. package/docs/api/type-aliases/AgentVisibleSecretRecord.md +1 -1
  121. package/docs/api/type-aliases/CbioRuntimeModule.md +1 -1
  122. package/docs/api/type-aliases/OwnerGrantCapabilityInput.md +1 -1
  123. package/docs/api/variables/DEFAULT_VAULT_KEY_CUSTODY_BLOB_KEY.md +1 -1
  124. package/docs/zh/README.md +4 -1
  125. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import type { AgentListCapabilitiesRequest, AgentListSecretsRequest, AgentListRequestsRequest, AgentGetRequestRequest, AgentRequestResult, AgentGetRuntimeManifestRequest, AgentRuntimeManifest, AgentSubmitCapabilityRequestCommand, AgentVisibleRequestRecord, AgentVisibleSecretRecord, AuditEntry, AuditQuery, CustomHttpFlowDefinition, DispatchAuthorization, DispatchRequest, DispatchResult, OwnerAllowAlwaysCommand, OwnerAllowOnceCommand, OwnerIssueSessionTokenRequest, OwnerDenyCommand, OwnerDeleteSecretCommand, OwnerExportSecretRequest, OwnerRegisterAgentIdentityCommand, OwnerUpdateAgentIdentityCommand, OwnerRegisterCapabilityCommand, OwnerRegisterCustomHttpFlowCommand, OwnerRevokeCapabilityCommand, OwnerListAgentsRequest, OwnerListCapabilitiesRequest, OwnerListCapabilityStatesRequest, OwnerSecretExport, OwnerSessionToken, SecretRecord, SubmitCapabilityRequestCommand, VaultId, VaultPrincipal, VaultWriteSecretCommand, AgentIdentityRecord, AgentCapability, CapabilityStateRecord } from "./contracts.js";
1
+ import type { AgentListCapabilitiesRequest, AgentListSecretsRequest, AgentListRequestsRequest, AgentGetRequestRequest, AgentRequestResult, AgentGetRuntimeManifestRequest, AgentRuntimeManifest, AgentSubmitCapabilityRequestCommand, AgentVisibleRequestRecord, OwnerVisibleRequestRecord, OwnerRequestRecord, AgentVisibleSecretRecord, AuditEntry, AuditQuery, CustomHttpFlowDefinition, DispatchAuthorization, DispatchRequest, DispatchResult, OwnerAllowAlwaysCommand, OwnerAllowOnceCommand, OwnerIssueSessionTokenRequest, OwnerDenyCommand, OwnerCreateSecretCommand, OwnerDeleteSecretCommand, OwnerExportSecretRequest, OwnerRegisterAgentIdentityCommand, OwnerUpdateAgentIdentityCommand, OwnerRegisterCapabilityCommand, OwnerRegisterCustomHttpFlowCommand, OwnerRevokeCapabilityCommand, OwnerListAgentsRequest, OwnerListCapabilitiesRequest, OwnerListRequestsRequest, OwnerGetRequestRequest, OwnerListCapabilityStatesRequest, OwnerSecretExport, OwnerSessionToken, SecretRecord, SubmitCapabilityRequestCommand, VaultId, VaultPrincipal, VaultWriteSecretCommand, AgentIdentityRecord, AgentCapability, CapabilityStateRecord } from "./contracts.js";
2
2
  import type { VaultCoreDependencies } from "./ports.js";
3
3
  /**
4
4
  * The Sovereign Vault Core.
@@ -20,6 +20,8 @@ export declare class VaultCore {
20
20
  private _listVisibleSecretsForAgent;
21
21
  private _recordRequestExecution;
22
22
  private toVisibleRequestRecord;
23
+ private toOwnerVisibleRequestRecord;
24
+ private toOwnerRequestRecord;
23
25
  ownerOnCapabilityState(callback: (record: CapabilityStateRecord) => void): () => void;
24
26
  ownerRegisterAgentIdentity(command: OwnerRegisterAgentIdentityCommand): Promise<void>;
25
27
  ownerUpdateAgentIdentity(command: OwnerUpdateAgentIdentityCommand): Promise<AgentIdentityRecord>;
@@ -28,7 +30,12 @@ export declare class VaultCore {
28
30
  _getCapability(vaultId: import("./contracts.js").VaultId, agentId: string, capabilityId: string): Promise<AgentCapability | null>;
29
31
  ownerRegisterCustomFlow(command: OwnerRegisterCustomHttpFlowCommand): Promise<void>;
30
32
  _storeCustomFlowSecret(flow: CustomHttpFlowDefinition, alias: string, plaintext: string): Promise<SecretRecord>;
33
+ private _getActiveSecretByAlias;
34
+ private _persistNewSecretRecord;
35
+ ownerCreateSecret(command: OwnerCreateSecretCommand): Promise<SecretRecord>;
36
+ ownerUpdateSecret(command: import("./contracts.js").OwnerUpdateSecretCommand): Promise<SecretRecord>;
31
37
  ownerWriteSecret(command: VaultWriteSecretCommand): Promise<SecretRecord>;
38
+ ownerRemoveSecret(command: OwnerDeleteSecretCommand): Promise<void>;
32
39
  ownerDeleteSecret(command: OwnerDeleteSecretCommand): Promise<void>;
33
40
  agentAuthorizeDispatch(request: DispatchRequest): Promise<DispatchAuthorization>;
34
41
  agentDispatchSecret(request: DispatchRequest): Promise<DispatchResult>;
@@ -45,6 +52,12 @@ export declare class VaultCore {
45
52
  ownerListCapabilities(actor: VaultPrincipal & {
46
53
  kind: "owner";
47
54
  }, agentId?: string, request?: Omit<OwnerListCapabilitiesRequest, "actor" | "agentId" | "vaultId">): Promise<readonly AgentCapability[]>;
55
+ ownerListRequests(actor: VaultPrincipal & {
56
+ kind: "owner";
57
+ }, agentId?: string, request?: Omit<OwnerListRequestsRequest, "actor" | "agentId" | "vaultId">): Promise<readonly OwnerVisibleRequestRecord[]>;
58
+ ownerGetRequest(actor: VaultPrincipal & {
59
+ kind: "owner";
60
+ }, targetRequestId: string, request?: Omit<OwnerGetRequestRequest, "actor" | "targetRequestId" | "vaultId">): Promise<OwnerRequestRecord>;
48
61
  ownerListSecrets(actor: VaultPrincipal & {
49
62
  kind: "owner";
50
63
  }, request?: {
@@ -4,6 +4,66 @@ import { verifySignature } from "../protocol/crypto.js";
4
4
  import { getAgentToolbox } from "./tool-metadata.js";
5
5
  import { InMemoryRequestRecordRegistry } from "./defaults.js";
6
6
  const VAULT_MASTER_ID = "vault-master";
7
+ function redactResponseShapeValue(value) {
8
+ if (value === null || value === undefined) {
9
+ return null;
10
+ }
11
+ if (Array.isArray(value)) {
12
+ return value.map((entry) => redactResponseShapeValue(entry));
13
+ }
14
+ if (typeof value === "object") {
15
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, redactResponseShapeValue(entry)]));
16
+ }
17
+ return null;
18
+ }
19
+ function applyResponseReadPolicy(body, policy) {
20
+ if (body === undefined)
21
+ return body;
22
+ if (policy.mode === "full")
23
+ return body;
24
+ if (policy.mode === "none")
25
+ return undefined;
26
+ let parsed;
27
+ try {
28
+ parsed = JSON.parse(body);
29
+ }
30
+ catch {
31
+ return policy.mode === "shape_only" ? JSON.stringify(null) : undefined;
32
+ }
33
+ if (policy.mode === "shape_only") {
34
+ return JSON.stringify(redactResponseShapeValue(parsed));
35
+ }
36
+ if (policy.mode !== "custom") {
37
+ return body;
38
+ }
39
+ const result = {};
40
+ for (const path of policy.paths ?? []) {
41
+ const segments = path.split(".").filter(Boolean);
42
+ if (!segments.length)
43
+ continue;
44
+ let source = parsed;
45
+ let valid = true;
46
+ for (const segment of segments) {
47
+ if (source && typeof source === "object" && segment in source) {
48
+ source = source[segment];
49
+ }
50
+ else {
51
+ valid = false;
52
+ break;
53
+ }
54
+ }
55
+ if (!valid)
56
+ continue;
57
+ let target = result;
58
+ for (let index = 0; index < segments.length - 1; index += 1) {
59
+ const segment = segments[index];
60
+ target[segment] ??= {};
61
+ target = target[segment];
62
+ }
63
+ target[segments[segments.length - 1]] = source;
64
+ }
65
+ return JSON.stringify(result);
66
+ }
7
67
  function toAuditEntry(deps, actor, action, outcome, detail, options) {
8
68
  return {
9
69
  entryId: deps.ids.newAuditEntryId(),
@@ -22,22 +82,32 @@ function toAuditEntry(deps, actor, action, outcome, detail, options) {
22
82
  agentId: options?.agentId,
23
83
  };
24
84
  }
25
- function buildSecretRecord(deps, command) {
85
+ function buildSecretRecord(deps, command, previousRecord) {
26
86
  const now = deps.clock.nowIso();
27
87
  const source = command.source?.kind === "request" && command.source.requestId
28
88
  ? { kind: "request", requestId: command.source.requestId }
29
89
  : { kind: "manual" };
90
+ const previousVersion = previousRecord ? Number.parseInt(previousRecord.version.value, 10) : 0;
91
+ const nextVersion = Number.isFinite(previousVersion) ? previousVersion + 1 : 1;
30
92
  return {
31
93
  vaultId: deps.vaultId,
32
94
  secretId: deps.ids.newSecretId(),
33
95
  alias: { value: command.alias },
34
- version: deps.ids.newVersion(),
96
+ version: { value: String(nextVersion) },
97
+ lifecycleStatus: "ACTIVE",
98
+ previousSecretId: previousRecord?.secretId,
35
99
  issuerId: command.kind === "issuer.write_secret" ? command.issuerSiteId : null,
36
100
  source,
37
101
  createdAt: now,
38
102
  updatedAt: now,
39
103
  };
40
104
  }
105
+ function isSecretActive(record) {
106
+ if (record.lifecycleStatus) {
107
+ return record.lifecycleStatus === "ACTIVE";
108
+ }
109
+ return !record.retiredAt;
110
+ }
41
111
  function normalizeScopeTarget(targetUrl) {
42
112
  try {
43
113
  const parsed = new URL(targetUrl);
@@ -203,6 +273,7 @@ export class VaultCore {
203
273
  proof: pending.proof,
204
274
  requestId: pending.requestId,
205
275
  requestedAt: pending.requestedAt,
276
+ skipReplayGuard: true,
206
277
  });
207
278
  }
208
279
  else if (mode === "grant") {
@@ -307,7 +378,10 @@ export class VaultCore {
307
378
  const authorizedCapabilities = capabilityMap.get(record.secretId.value) ?? [];
308
379
  return {
309
380
  vaultId: record.vaultId,
381
+ secretId: record.secretId,
310
382
  alias: record.alias,
383
+ version: record.version,
384
+ lifecycleStatus: record.lifecycleStatus ?? "ACTIVE",
311
385
  issuerId: record.issuerId,
312
386
  source: record.source,
313
387
  createdAt: record.createdAt,
@@ -359,6 +433,52 @@ export class VaultCore {
359
433
  resultVisible: readStatus === "APPROVED",
360
434
  };
361
435
  }
436
+ toOwnerVisibleRequestRecord(record, state) {
437
+ return {
438
+ requestId: record.requestId,
439
+ createdAt: record.createdAt,
440
+ agentId: record.agentId,
441
+ capabilityId: record.capabilityId,
442
+ operation: record.operation,
443
+ targetUrl: record.request.targetUrl,
444
+ method: record.request.method,
445
+ executionStatus: record.execution.status,
446
+ responseStatus: record.response?.status,
447
+ error: record.response?.error,
448
+ writeStatus: state?.actions.write.status ?? "PENDING",
449
+ readStatus: state?.actions.read.status ?? "PENDING",
450
+ hasResponseBody: typeof record.response?.body === "string" && record.response.body.length > 0,
451
+ };
452
+ }
453
+ toOwnerRequestRecord(record, state) {
454
+ return {
455
+ requestId: record.requestId,
456
+ createdAt: record.createdAt,
457
+ agentId: record.agentId,
458
+ capabilityId: record.capabilityId,
459
+ operation: record.operation,
460
+ request: {
461
+ targetUrl: record.request.targetUrl,
462
+ method: record.request.method,
463
+ headers: record.request.headers ? { ...record.request.headers } : undefined,
464
+ body: record.request.body,
465
+ secretId: record.request.secretId,
466
+ },
467
+ response: record.response
468
+ ? {
469
+ status: record.response.status,
470
+ headers: record.response.headers ? { ...record.response.headers } : undefined,
471
+ body: record.response.body,
472
+ error: record.response.error,
473
+ }
474
+ : undefined,
475
+ actions: {
476
+ write: state?.actions.write ?? { action: "write", status: "PENDING" },
477
+ read: state?.actions.read ?? { action: "read", status: "PENDING" },
478
+ },
479
+ executionStatus: record.execution.status,
480
+ };
481
+ }
362
482
  ownerOnCapabilityState(callback) {
363
483
  this._capabilityStateObservers.add(callback);
364
484
  return () => {
@@ -556,7 +676,7 @@ export class VaultCore {
556
676
  throw new VaultCoreError("alias already bound to existing secret", "VAULT_WRITE_DENIED");
557
677
  }
558
678
  const record = buildSecretRecord(this._deps, {
559
- kind: "owner.write_secret",
679
+ kind: "owner.create_secret",
560
680
  vaultId: this._deps.vaultId,
561
681
  requestId,
562
682
  owner: actor,
@@ -585,7 +705,36 @@ export class VaultCore {
585
705
  }
586
706
  return record;
587
707
  }
588
- async ownerWriteSecret(command) {
708
+ async _getActiveSecretByAlias(alias) {
709
+ const matches = (await this._deps.secrets.list(this._deps.vaultId))
710
+ .filter((record) => record.alias.value === alias && isSecretActive(record));
711
+ if (matches.length > 1) {
712
+ throw new VaultCoreError(`multiple active secrets found for alias: ${alias}`, "VAULT_WRITE_DENIED");
713
+ }
714
+ return matches[0] ?? null;
715
+ }
716
+ async _persistNewSecretRecord(record, plaintext, actor, successDetail) {
717
+ try {
718
+ await this._deps.custody.store(record.secretId, plaintext);
719
+ await this._deps.secrets.save(record);
720
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.WRITE_SECRET, AuditOutcome.SUCCEEDED, successDetail, {
721
+ secretAlias: record.alias.value,
722
+ secretId: record.secretId.value,
723
+ }));
724
+ }
725
+ catch (error) {
726
+ await Promise.allSettled([
727
+ this._deps.secrets.delete(record.secretId),
728
+ this._deps.custody.delete(record.secretId),
729
+ ]);
730
+ throw error;
731
+ }
732
+ return record;
733
+ }
734
+ async ownerCreateSecret(command) {
735
+ return this.ownerWriteSecret(command);
736
+ }
737
+ async ownerUpdateSecret(command) {
589
738
  if (command.vaultId.value !== this._deps.vaultId.value) {
590
739
  throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
591
740
  }
@@ -594,47 +743,89 @@ export class VaultCore {
594
743
  }
595
744
  catch (error) {
596
745
  const detail = error instanceof Error ? error.message : String(error);
597
- await this._appendAudit(toAuditEntry(this._deps, command.kind === "owner.write_secret" ? command.owner : command.issuer, AuditAction.WRITE_SECRET, AuditOutcome.DENIED, detail, {
746
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.WRITE_SECRET, AuditOutcome.DENIED, detail, {
598
747
  secretAlias: command.alias,
599
748
  }));
600
749
  throw error;
601
750
  }
602
- const existing = await this._deps.secrets.getByAlias({ value: command.alias });
603
- if (existing) {
604
- 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", {
605
- secretAlias: existing.alias.value,
606
- secretId: existing.secretId.value,
607
- }));
608
- throw new VaultCoreError("alias already bound to existing secret", "VAULT_WRITE_DENIED");
751
+ const existing = await this._getActiveSecretByAlias(command.alias);
752
+ if (!existing) {
753
+ throw new VaultCoreError(`secret not found: ${command.alias}`, "VAULT_SECRET_NOT_FOUND");
609
754
  }
610
- const record = buildSecretRecord(this._deps, command);
755
+ const record = buildSecretRecord(this._deps, command, existing);
756
+ const supersededAt = this._deps.clock.nowIso();
757
+ const superseded = {
758
+ ...existing,
759
+ lifecycleStatus: "SUPERSEDED",
760
+ supersededBySecretId: record.secretId,
761
+ supersededAt,
762
+ retiredAt: supersededAt,
763
+ updatedAt: supersededAt,
764
+ };
765
+ let custodyStored = false;
766
+ let previousSuperseded = false;
767
+ let newRecordSaved = false;
611
768
  try {
612
769
  await this._deps.custody.store(record.secretId, command.plaintext);
770
+ custodyStored = true;
771
+ await this._deps.secrets.save(superseded);
772
+ previousSuperseded = true;
613
773
  await this._deps.secrets.save(record);
614
- await this._appendAudit(toAuditEntry(this._deps, command.kind === "owner.write_secret" ? command.owner : command.issuer, AuditAction.WRITE_SECRET, AuditOutcome.SUCCEEDED, "secret stored", {
774
+ newRecordSaved = true;
775
+ await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.WRITE_SECRET, AuditOutcome.SUCCEEDED, "secret updated", {
615
776
  secretAlias: record.alias.value,
616
777
  secretId: record.secretId.value,
617
778
  }));
779
+ return record;
618
780
  }
619
781
  catch (error) {
782
+ if (previousSuperseded) {
783
+ await Promise.allSettled([this._deps.secrets.save(existing)]);
784
+ }
620
785
  await Promise.allSettled([
621
- this._deps.secrets.delete(record.secretId),
622
- this._deps.custody.delete(record.secretId),
786
+ newRecordSaved ? this._deps.secrets.delete(record.secretId) : Promise.resolve(),
787
+ custodyStored ? this._deps.custody.delete(record.secretId) : Promise.resolve(),
623
788
  ]);
624
789
  throw error;
625
790
  }
626
- return record;
627
791
  }
628
- async ownerDeleteSecret(command) {
629
- const record = await this._deps.secrets.getByAlias({ value: command.alias });
792
+ async ownerWriteSecret(command) {
793
+ if (command.vaultId.value !== this._deps.vaultId.value) {
794
+ throw new VaultCoreError("write vault mismatch", "VAULT_WRITE_DENIED");
795
+ }
796
+ try {
797
+ await this._deps.policy.authorizeWrite(command);
798
+ }
799
+ catch (error) {
800
+ const detail = error instanceof Error ? error.message : String(error);
801
+ await this._appendAudit(toAuditEntry(this._deps, command.kind === "issuer.write_secret" ? command.issuer : command.owner, AuditAction.WRITE_SECRET, AuditOutcome.DENIED, detail, {
802
+ secretAlias: command.alias,
803
+ }));
804
+ throw error;
805
+ }
806
+ const existing = await this._getActiveSecretByAlias(command.alias);
807
+ if (existing) {
808
+ await this._appendAudit(toAuditEntry(this._deps, command.kind === "issuer.write_secret" ? command.issuer : command.owner, AuditAction.REASSIGN_ALIAS, AuditOutcome.DENIED, "alias already bound to existing secret; explicit alias lifecycle required", {
809
+ secretAlias: existing.alias.value,
810
+ secretId: existing.secretId.value,
811
+ }));
812
+ throw new VaultCoreError("alias already bound to existing secret", "VAULT_WRITE_DENIED");
813
+ }
814
+ const record = buildSecretRecord(this._deps, command);
815
+ return this._persistNewSecretRecord(record, command.plaintext, command.kind === "issuer.write_secret" ? command.issuer : command.owner, "secret created");
816
+ }
817
+ async ownerRemoveSecret(command) {
818
+ const record = await this._getActiveSecretByAlias(command.alias);
630
819
  if (!record) {
631
820
  throw new VaultCoreError(`secret not found: ${command.alias}`, "VAULT_SECRET_NOT_FOUND");
632
821
  }
633
- const retiredAt = this._deps.clock.nowIso();
822
+ const removedAt = this._deps.clock.nowIso();
634
823
  await this._deps.secrets.save({
635
824
  ...record,
636
- updatedAt: retiredAt,
637
- retiredAt,
825
+ lifecycleStatus: "REMOVED",
826
+ updatedAt: removedAt,
827
+ removedAt,
828
+ retiredAt: removedAt,
638
829
  });
639
830
  await this._appendAudit(toAuditEntry(this._deps, command.owner, AuditAction.DELETE_SECRET, AuditOutcome.SUCCEEDED, `retired secret ${command.alias}`, {
640
831
  requestId: command.requestId,
@@ -642,6 +833,9 @@ export class VaultCore {
642
833
  secretId: record.secretId.value,
643
834
  }));
644
835
  }
836
+ async ownerDeleteSecret(command) {
837
+ return this.ownerRemoveSecret(command);
838
+ }
645
839
  async agentAuthorizeDispatch(request) {
646
840
  if (request.vaultId.value !== this._deps.vaultId.value) {
647
841
  throw new VaultCoreError("request vault mismatch", "VAULT_DISPATCH_DENIED");
@@ -659,7 +853,9 @@ export class VaultCore {
659
853
  };
660
854
  }
661
855
  try {
662
- await this._deps.replayGuard.assertNotReplayed(request);
856
+ if (!request.skipReplayGuard) {
857
+ await this._deps.replayGuard.assertNotReplayed(request);
858
+ }
663
859
  await this._deps.agentProofVerifier.verify(request);
664
860
  // Removed direct policy.authorizeDispatch here to handle discovery
665
861
  }
@@ -885,6 +1081,28 @@ export class VaultCore {
885
1081
  }));
886
1082
  return capabilities;
887
1083
  }
1084
+ async ownerListRequests(actor, agentId, request) {
1085
+ const records = await this._deps.requests.list(this._deps.vaultId, agentId);
1086
+ const states = await this._deps.capabilityStates.list(this._deps.vaultId, agentId);
1087
+ const stateByRequestId = new Map(states.filter((state) => state.requestId).map((state) => [state.requestId, state]));
1088
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.LIST_REQUESTS, AuditOutcome.ALLOWED, "request records listed", {
1089
+ requestId: request?.requestId,
1090
+ agentId,
1091
+ }));
1092
+ return records.map((record) => this.toOwnerVisibleRequestRecord(record, stateByRequestId.get(record.requestId) ?? null));
1093
+ }
1094
+ async ownerGetRequest(actor, targetRequestId, request) {
1095
+ const record = await this._deps.requests.get(this._deps.vaultId, targetRequestId);
1096
+ if (!record) {
1097
+ throw new VaultCoreError("request record not found", "VAULT_READ_DENIED");
1098
+ }
1099
+ const state = await this._deps.capabilityStates.getByRequestId(this._deps.vaultId, targetRequestId);
1100
+ await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.READ_REQUEST, AuditOutcome.ALLOWED, "request record read", {
1101
+ requestId: request?.requestId,
1102
+ agentId: record.agentId,
1103
+ }));
1104
+ return this.toOwnerRequestRecord(record, state);
1105
+ }
888
1106
  async ownerListSecrets(actor, request) {
889
1107
  const records = await this._deps.secrets.list(this._deps.vaultId);
890
1108
  await this._appendAudit(toAuditEntry(this._deps, actor, AuditAction.READ_AUDIT, AuditOutcome.ALLOWED, "secret metadata listed", {
@@ -892,7 +1110,10 @@ export class VaultCore {
892
1110
  }));
893
1111
  return records.map((record) => ({
894
1112
  vaultId: record.vaultId,
1113
+ secretId: record.secretId,
895
1114
  alias: record.alias,
1115
+ version: record.version,
1116
+ lifecycleStatus: record.lifecycleStatus ?? "ACTIVE",
896
1117
  issuerId: record.issuerId,
897
1118
  source: record.source,
898
1119
  createdAt: record.createdAt,
@@ -934,11 +1155,14 @@ export class VaultCore {
934
1155
  }
935
1156
  const state = await this._deps.capabilityStates.getByRequestId(this._deps.vaultId, request.targetRequestId);
936
1157
  const readApproved = state?.actions.read.status === "APPROVED";
1158
+ const responseBody = readApproved
1159
+ ? applyResponseReadPolicy(record.response?.body, state?.read ?? { mode: "full" })
1160
+ : undefined;
937
1161
  return {
938
1162
  requestId: record.requestId,
939
1163
  executionStatus: record.execution.status,
940
1164
  responseStatus: record.response?.status,
941
- responseBody: readApproved ? record.response?.body : undefined,
1165
+ responseBody,
942
1166
  error: record.response?.error,
943
1167
  };
944
1168
  }
@@ -1105,6 +1329,12 @@ export class VaultCore {
1105
1329
  const decidedAt = this._deps.clock.nowIso();
1106
1330
  const next = {
1107
1331
  ...pending,
1332
+ read: command.read
1333
+ ? {
1334
+ mode: command.read.mode,
1335
+ paths: command.read.paths ? [...command.read.paths] : undefined,
1336
+ }
1337
+ : pending.read,
1108
1338
  decidedAt,
1109
1339
  actions: {
1110
1340
  ...pending.actions,