chainlesschain 0.166.89 → 0.166.91

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 (181) hide show
  1. package/README.md +91 -5
  2. package/package.json +3 -3
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/assets/{AIOps-C8AkN9R5.js → AIOps-DgV7xb8F.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-BrAzSQor.js → ActionButton-CgANpkKu.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-Cu56X8Oh.js → Analytics-DnvpX7RB.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-BP1Riofl.js → AppLayout-C2bHccBM.js} +4 -4
  9. package/src/assets/web-panel/assets/{Artifacts-CIW-nNAz.js → Artifacts-BIhijC9g.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-CJtDabk-.js → Audit-CKRjWGdp.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-DYIHeQ_P.js → BackgroundAgents-CblYtgBE.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-B4CsFzj7.js → Backup-Cq35b78a.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-3eoJ5kfb.js → BaseInput-DcB7NoRz.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-BBhX2L_E.js → Chat-tc3b-s7i.js} +5 -5
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-RN8cbv7w.js → ChatBubbleRenderer-fcc_Tvqu.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-5UvmwHVk.js → Checkbox-BLD5bH5u.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-BFy8zsBN.js → Codegen-BLOsoazN.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-4M6bKRRO.js → Col-Bdr7JwIx.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-D6LC0j7_.js → Community-C84BsWE0.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-Dd48xMcv.js → Compact-Dzdwd04z.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-Ba85ggmy.js → Compliance-CCG-R0EV.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-D1BXlkuK.js → Cowork-BYj72SK0.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-Ca2Uy7Ia.js → Cron-B6iKAwOf.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-C2bDRXZg.js → Crosschain-BJ-oDC6u.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-DySZKAJf.js → DID-BnMckGLr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-DDpYf-TT.js → Dashboard-Cyje-gCO.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-DGjROfPv.js → Dropdown-BpNlenjK.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-DxX9QYiB.js → EmailListRenderer-BhonO7Nv.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-TBCZyrSJ.js → EvolutionSettings-DVoNU-Id.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BeqwTXBa.js → FamilyGuardDashboard-tdn-KC67.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-CiCpKJQ1.js → Federation--EEVrHhz.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-CdTmbLkU.js → FormItemContext-Cy8zr0-4.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-BwbkEY-5.js → GenericCardRenderer-BuUhpgFi.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-VnAga2vv.js → Git-Ctd3E5Pe.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-i-4Ebs-H.js → Governance-Ce7dV6aU.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-CirjTgNw.js → Inference-CD1vExIH.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-CunS7vhA.js → KnowledgeGraph-Dn64OdQ7.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-DBuTF0c6.js → Logs-PmElVRrT.js} +2 -2
  39. package/src/assets/web-panel/assets/{MarkdownRenderer-B-iE-tt_.js → MarkdownRenderer-BFiVKf5t.js} +1 -1
  40. package/src/assets/web-panel/assets/{Marketplace-BK6ZivTS.js → Marketplace-OW4jTXwx.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-CUnCRnd3.js → McpTools-BEq2Ib4x.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-CBGGr8Gy.js → Memory-Can_P2oK.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-reB6iaWD.js → MobileBridge-DJ8R-dn3.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-o1YdVB7i.js → MobileProjects-B7kV9GOt.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-if5OE3GH.js → Mtc-BfxamolS.js} +2 -2
  46. package/src/assets/web-panel/assets/{MtcAudit-BTZWpq0j.js → MtcAudit-DHtuv7av.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-8cvMAYFL.js → Multisig-DLkLpvxc.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-BMvUXAWo.js → NLProgramming-u4XtJTIt.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-BWWjColh.js → Notes-BwuuPJLS.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-Ccr4lIhS.js → NotificationSettings-HEeu-E9v.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-DhksGy6D.js → OrderTableRenderer-BtvN-Qwh.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-DciXQfdY.js → Organization-Yh-czs3b.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-8DR7uMSx.js → Overflow-DmE8mYVM.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-DE6euHYl.js → P2P-CWVck8WN.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-ByuWoauq.js → PdhVaultBrowser-DgFqekod.js} +4 -4
  56. package/src/assets/web-panel/assets/{Permissions-DkjM87ac.js → Permissions-BtJBVOHV.js} +3 -3
  57. package/src/assets/web-panel/assets/{PersonalDataHub-2DLp0KTL.js → PersonalDataHub-6VBObXzd.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-Ci2Qlkfr.js → Pipeline-D222FmqY.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-DlwDnDVA.js → Privacy-Bi9FMikp.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-CmMifW39.js → ProjectInit-Bo52H47H.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-DJVFIh-6.js → ProjectSettings-BPkesfOc.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-P2nWBS70.js → Projects-GynohSFX.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-B2cxaGCU.js → Providers-DVdMg04n.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-CpO77kcE.js → QrScannerModal-DqJCb595.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-BDQl1hb0.js → QuickAsk-J7loQbXi.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-DTD2f3IN.js → Recommend-BI5aURVc.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-DGZAnwvs.js → RemoteSession-BN2sqGvz.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-B_R4vitb.js → Reputation-BGOND-Fi.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-4Jj6JyXN.js → Row-77dfwaUk.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-D1t1MCZ-.js → RssFeed-FtBAxS3g.js} +2 -2
  71. package/src/assets/web-panel/assets/{Search-CyOUlIn7.js → Search-BaYVLFb7.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-BmknPT5Q.js → Security-LE3Vv6ab.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-DkEK8mpa.js → Services-C5pP-Whz.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-Bvo5bpuk.js → Skeleton-CLqKUVsF.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-AMmG8fim.js → Skills-BPjN0SX5.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-Dl7-OKOV.js → Sla-14jD70kg.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-DtiGKu0E.js → SpeechSettings-Dr9ij42W.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-Ch7mp3ES.js → SyncSettings-BzLHP7B8.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-Ck-sEgj-.js → Tasks-YqV9b0rV.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-BlV22Il8.js → Templates-CxxAE4PK.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-CaaAu0mX.js → Tenant-CRb3PcKJ.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-lA9g3FtJ.js → Terminal-CTzPpBaP.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-CG26IFC3.js → TimelineRenderer-DjFUj_hy.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-iaJUBLBm.js → Tokens-Bbb8tPvx.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-DWQJtLK3.js → Trigger-CSeWGM0W.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-CTjmUwqp.js → Trust-JgESMBo3.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-CMnxufgD.js → UkeySign-CiObLk0T.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-diCFSWJw.js → VideoEditing-CFEZaQ2x.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-Ba1oND1K.js → Wallet-DR8ZGDNn.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-DZDqPS-S.js → WebAuthn-DxZukvu7.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-CfN8fPMe.js → WorkflowEditor-CKgSZQwn.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-BiqMsO_i.js → chat-CTxEQE66.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-By8LkjqH.js → colors-CAjKMUu3.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-B0mxvRe3.js → compact-item-BXuz49at.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-Li2ub348.js → createContext-CFN_Hwr9.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-DYbHPkbl.js → hasIn-BwoSBSfP.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CVZNYRzM.js → index-B0QbLlWn.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CGZzexNa.js → index-B2o_BBjg.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CYv3JIzl.js → index-B2tEnBPx.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-1lVoRUrQ.js → index-B7kp-zRE.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CTVPeUh3.js → index-B9yR7zqr.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BFhksbXp.js → index-BK4ftQ4d.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-B0D0HkkM.js → index-Bj4hIiLW.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CEp_3fKJ.js → index-BmQITjMU.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DIImi0cd.js → index-BmXpdcHI.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-D6qL3QBU.js → index-Bqv_Cray.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BSk0xuXP.js → index-Bu2P6u8m.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-zSzXsF9b.js → index-Bw9s2d3c.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-beDji-cB.js → index-C8er4W9u.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C-RE3mFh.js → index-CB3kVd9c.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CCsRfd0k.js +1 -0
  113. package/src/assets/web-panel/assets/{index-CA0AOURT.js → index-CF9lWi1o.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CMh3VxgO.js → index-CN53dE_u.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-KWt8Owo8.js → index-CSmFby3Q.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DB4DCzqU.js → index-CehdwJ_Q.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CHgiSV6R.js → index-Cgk0YEiq.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-b4O_YBVR.js → index-Cp5y7lX_.js} +1 -1
  119. package/src/assets/web-panel/assets/index-CsmiZIQ4.js +1 -0
  120. package/src/assets/web-panel/assets/{index-DAOpBv3C.js → index-DTX9CJPx.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BZqTG7fP.js → index-DViK2bkv.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Bc6bxU24.js → index-DY-gBSm8.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Czt7WAtA.js → index-DjF5BOZx.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-KqfqSdAC.js → index-DmkbAADP.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Bd5znvCV.js → index-DpdDnZX_.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-C5Se6Lnv.js → index-Dv7V2kg6.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Cpfn4YbT.js → index-DxunxaTw.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BcOJEgBE.js → index-F2E5RCwz.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CgyrklzQ.js → index-IY9bd5az.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-ClsJN8sW.js → index-IahILygB.js} +3 -3
  131. package/src/assets/web-panel/assets/{index-hw3sCYAz.js → index-T3MTE6jB.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Bm2P2Kgp.js → index-Tz5dheZa.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BRzewWeE.js → index-_ZtCyUdz.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-DPRgnazi.js → index-o9DpkZKf.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-ByqFKMWL.js → index-t2Ch_JKn.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DgMFnBOv.js → index-u9_DM3ZC.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-TgDL_7OY.js → initDefaultProps-BoiGJDoO.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-fHosyV5c.js → motion-5eL4E0pA.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-C_QfW5qg.js → move-DjggDi_1.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-u7ywDVOg.js → mtc-parser-Ce8Vo2T3.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-BEJdUgE9.js → omit-D1yOBaO2.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-DGkQFAJ5.js → pickAttrs-8NLceQe8.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-DUyZXAjt.js → placementArrow-CsIdBRmQ.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-B4xDxO7Q.js → responsiveObserve-GM5NE8En.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-B8WuJtst.js → slide-44yj3u49.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-DLUqy7JO.js → statusUtils-B8tqtWcX.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-BYOJOyqL.js → styleChecker-NhDPBbyB.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-WChWQURv.js → useFlexGapSupport-C8Qz1GtN.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-vLNpm3dv.js → useFs-ClUv4kih.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-DSZ8unoU.js → usePersonalDataHub-BwkOVEh6.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-C4Xf7Kg1.js → vnode--gMF33R0.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-BulmeAGy.js → zoom-DXg3TqOP.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +5 -5
  155. package/src/commands/agent-process-ownership.js +121 -0
  156. package/src/commands/agent.js +2 -0
  157. package/src/commands/automation.js +35 -8
  158. package/src/commands/hub.js +224 -0
  159. package/src/commands/project.js +162 -0
  160. package/src/data/changelog.json +26 -0
  161. package/src/gateways/ws/personal-data-hub-protocol.js +54 -8
  162. package/src/lib/audit-logger.js +59 -46
  163. package/src/lib/audit-sanitizer.js +279 -0
  164. package/src/lib/automation-center.js +14 -4
  165. package/src/lib/automation-engine.js +151 -39
  166. package/src/lib/checkpoint-restore-saga.js +11 -1
  167. package/src/lib/eval/verify01-host-evidence.js +36 -3
  168. package/src/lib/knowledge-graph.js +27 -0
  169. package/src/lib/personal-data-hub-wiring.js +44 -1
  170. package/src/lib/process-execution-broker/index.js +91 -1
  171. package/src/lib/process-execution-broker/platform-sandbox.js +42 -0
  172. package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +757 -0
  173. package/src/lib/process-execution-broker/windows-native-evaluator.js +316 -0
  174. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  175. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  176. package/src/lib/process-execution-broker/windows-sandbox.cs +383 -11
  177. package/src/lib/scheduler-kernel/automation-adapter.js +15 -3
  178. package/src/lib/scheduler-kernel/automation-event-adapter.js +15 -3
  179. package/src/assets/web-panel/assets/devWarning-D90arbUg.js +0 -1
  180. package/src/assets/web-panel/assets/index-CeP1oROI.js +0 -1
  181. package/src/assets/web-panel/assets/index-Cu9gkyRc.js +0 -1
@@ -6,6 +6,18 @@
6
6
  import crypto from "crypto";
7
7
  import { safeJsonParse } from "./safe-json.js";
8
8
  import { escapeLike } from "./sql-like.js";
9
+ import { sanitizeAuditDetails } from "./audit-sanitizer.js";
10
+ import auditDataPolicy from "@chainlesschain/session-core/audit-data-policy";
11
+ import restrictedAudit from "@chainlesschain/session-core/restricted-audit-store";
12
+
13
+ const { projectAuditMetadata, projectAuditField, validateRetentionDays } =
14
+ auditDataPolicy;
15
+
16
+ // Host API: authorization must come from the invoking host, never event details.
17
+ // No general audit query/export includes this separate store.
18
+ export function createAuditDiagnostics(db, options) {
19
+ return new restrictedAudit.RestrictedAuditStore(db, options);
20
+ }
9
21
 
10
22
  /**
11
23
  * Event types for audit logging.
@@ -112,29 +124,15 @@ export function assessRisk(eventType, operation, details) {
112
124
  * Sanitize sensitive data from log details.
113
125
  */
114
126
  export function sanitizeDetails(details) {
115
- if (!details || typeof details !== "object") return details;
116
-
117
- const sanitized = { ...details };
118
- const sensitiveKeys = [
119
- "password",
120
- "secret",
121
- "secretKey",
122
- "secret_key",
123
- "privateKey",
124
- "private_key",
125
- "token",
126
- "apiKey",
127
- "api_key",
128
- "mnemonic",
129
- ];
130
-
131
- for (const key of sensitiveKeys) {
132
- if (sanitized[key]) {
133
- sanitized[key] = "[REDACTED]";
134
- }
135
- }
127
+ return sanitizeAuditDetails(details);
128
+ }
136
129
 
137
- return sanitized;
130
+ function sanitizeErrorMessage(value) {
131
+ const sanitized = projectAuditMetadata(value);
132
+ if (sanitized == null) return null;
133
+ return typeof sanitized === "object"
134
+ ? JSON.stringify(sanitized)
135
+ : String(sanitized);
138
136
  }
139
137
 
140
138
  /**
@@ -144,26 +142,26 @@ export function logEvent(db, event) {
144
142
  ensureAuditTables(db);
145
143
 
146
144
  const id = crypto.randomUUID();
147
- const sanitized = sanitizeDetails(event.details);
148
- const risk =
149
- event.riskLevel ||
150
- assessRisk(event.eventType, event.operation, event.details);
145
+ const sanitized = projectAuditMetadata(event.details);
146
+ const risk = Object.values(RISK_LEVELS).includes(event.riskLevel)
147
+ ? event.riskLevel
148
+ : assessRisk(event.eventType, event.operation || "unknown", sanitized);
151
149
 
152
150
  db.prepare(
153
151
  `INSERT INTO audit_log (id, event_type, operation, actor, target, details, risk_level, ip_address, user_agent, success, error_message)
154
152
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
155
153
  ).run(
156
154
  id,
157
- event.eventType || EVENT_TYPES.SYSTEM,
158
- event.operation || "unknown",
159
- event.actor || null,
160
- event.target || null,
161
- sanitized ? JSON.stringify(sanitized) : null,
155
+ projectAuditField("eventType", event.eventType || EVENT_TYPES.SYSTEM),
156
+ projectAuditField("operation", event.operation || "unknown"),
157
+ projectAuditField("actor", event.actor || null),
158
+ projectAuditField("target", event.target || null),
159
+ sanitized == null ? null : JSON.stringify(sanitized),
162
160
  risk,
163
- event.ipAddress || null,
164
- event.userAgent || null,
161
+ event.ipAddress ? projectAuditField("ipAddress", event.ipAddress) : null,
162
+ event.userAgent ? projectAuditField("userAgent", event.userAgent) : null,
165
163
  event.success !== false ? 1 : 0,
166
- event.errorMessage || null,
164
+ sanitizeErrorMessage(event.errorMessage),
167
165
  );
168
166
 
169
167
  return { id, riskLevel: risk, createdAt: new Date().toISOString() };
@@ -234,8 +232,21 @@ export function queryLogs(db, filters = {}) {
234
232
  const rows = db.prepare(sql).all(...params);
235
233
  return rows.map((r) => ({
236
234
  ...r,
235
+ event_type: projectAuditField("eventType", r.event_type),
236
+ operation: projectAuditField("operation", r.operation),
237
237
  // One corrupt details cell must not throw out of the whole query.
238
- details: safeJsonParse(r.details, null),
238
+ details: projectAuditMetadata(safeJsonParse(r.details, null)),
239
+ error_message: sanitizeErrorMessage(
240
+ safeJsonParse(r.error_message, r.error_message),
241
+ ),
242
+ actor: projectAuditField("actor", r.actor),
243
+ target: projectAuditField("target", r.target),
244
+ ip_address: r.ip_address
245
+ ? projectAuditField("ipAddress", r.ip_address)
246
+ : null,
247
+ user_agent: r.user_agent
248
+ ? projectAuditField("userAgent", r.user_agent)
249
+ : null,
239
250
  success: r.success === 1,
240
251
  }));
241
252
  }
@@ -347,6 +358,7 @@ export function exportLogs(db, format = "json", filters = {}) {
347
358
  * Delete old audit logs.
348
359
  */
349
360
  export function purgeLogs(db, daysToKeep = 90) {
361
+ validateRetentionDays(daysToKeep);
350
362
  ensureAuditTables(db);
351
363
 
352
364
  const cutoff = new Date();
@@ -516,23 +528,24 @@ export function logEventV2(
516
528
  if (_logStatesV2.has(logId)) {
517
529
  throw new Error(`Log already registered: ${logId}`);
518
530
  }
519
- const risk = riskLevel || assessRisk(eventType, operation, details);
531
+ const sanitized = projectAuditMetadata(details);
532
+ const risk = riskLevel || assessRisk(eventType, operation, sanitized);
520
533
  if (!RISK_LEVELS_V2.includes(risk)) {
521
534
  throw new Error(`Invalid riskLevel: ${risk}`);
522
535
  }
523
536
  const now = Date.now();
524
537
  const entry = {
525
538
  logId,
526
- eventType,
527
- operation,
528
- actor: actor || null,
529
- target: target || null,
530
- details: sanitizeDetails(details) || null,
539
+ eventType: projectAuditField("eventType", eventType),
540
+ operation: projectAuditField("operation", operation),
541
+ actor: projectAuditField("actor", actor || null),
542
+ target: projectAuditField("target", target || null),
543
+ details: sanitized ?? null,
531
544
  riskLevel: risk,
532
- ipAddress: ipAddress || null,
533
- userAgent: userAgent || null,
545
+ ipAddress: ipAddress ? projectAuditField("ipAddress", ipAddress) : null,
546
+ userAgent: userAgent ? projectAuditField("userAgent", userAgent) : null,
534
547
  success: success !== false,
535
- errorMessage: errorMessage || null,
548
+ errorMessage: sanitizeErrorMessage(errorMessage),
536
549
  status: LOG_STATUS_V2.ACTIVE,
537
550
  integrityStatus: INTEGRITY_STATUS_V2.UNVERIFIED,
538
551
  prevHash: _lastChainHash,
@@ -552,8 +565,8 @@ export function logEventV2(
552
565
  _alertStatesV2.set(alertId, {
553
566
  alertId,
554
567
  logId,
555
- actor,
556
- operation,
568
+ actor: entry.actor,
569
+ operation: entry.operation,
557
570
  riskLevel: risk,
558
571
  status: ALERT_STATUS_V2.OPEN,
559
572
  reason: null,
@@ -0,0 +1,279 @@
1
+ /**
2
+ * JSON-safe audit details. Limits apply before string processing and while
3
+ * traversing; getters and user-provided toJSON methods are never invoked.
4
+ * This is field/credential redaction, not detection of arbitrary secrets in prose.
5
+ */
6
+ const REDACTED = "[REDACTED]";
7
+ const TRUNCATED = "[Truncated]";
8
+ const LIMITS = Object.freeze({
9
+ depth: 8,
10
+ entries: 100,
11
+ nodes: 512,
12
+ stringLength: 4096,
13
+ keyLength: 256,
14
+ totalCharacters: 16384,
15
+ serializedBytes: 65536,
16
+ });
17
+
18
+ const SENSITIVE_KEYS = new Set([
19
+ "password",
20
+ "passwd",
21
+ "pwd",
22
+ "passphrase",
23
+ "secret",
24
+ "secretkey",
25
+ "privatekey",
26
+ "apikey",
27
+ "token",
28
+ "authorization",
29
+ "proxyauthorization",
30
+ "cookie",
31
+ "setcookie",
32
+ "mnemonic",
33
+ "seedphrase",
34
+ "credentials",
35
+ "credential",
36
+ "encryptionkey",
37
+ "signingkey",
38
+ "sessionid",
39
+ "auth",
40
+ ]);
41
+
42
+ function normalizeKey(key) {
43
+ return key.toLowerCase().replace(/[\s_.-]/g, "");
44
+ }
45
+
46
+ function isSensitiveKey(key) {
47
+ const normalized = normalizeKey(key);
48
+ return (
49
+ SENSITIVE_KEYS.has(normalized) ||
50
+ /(?:password|secret|privatekey|apikey|token)$/.test(normalized)
51
+ );
52
+ }
53
+
54
+ function isSensitiveQueryKey(key) {
55
+ return isSensitiveKey(key) || /^(?:key|code|sig|signature)$/i.test(key);
56
+ }
57
+
58
+ function sanitizeUrl(text) {
59
+ try {
60
+ const url = new URL(text);
61
+ if (url.username || url.password) {
62
+ url.username = REDACTED;
63
+ url.password = "";
64
+ }
65
+ const params = new URLSearchParams();
66
+ for (const [key, value] of url.searchParams) {
67
+ params.append(key, isSensitiveQueryKey(key) ? REDACTED : value);
68
+ }
69
+ url.search = params.toString();
70
+ // OAuth implicit responses put credentials in the fragment instead of query.
71
+ if (url.hash.includes("=")) {
72
+ const fragment = new URLSearchParams(url.hash.slice(1));
73
+ const sanitized = new URLSearchParams();
74
+ for (const [key, value] of fragment) {
75
+ sanitized.append(key, isSensitiveQueryKey(key) ? REDACTED : value);
76
+ }
77
+ url.hash = sanitized.toString();
78
+ }
79
+ return url.toString();
80
+ } catch {
81
+ return "[REDACTED URL]";
82
+ }
83
+ }
84
+
85
+ function sanitizeString(value) {
86
+ // Drop oversized strings whole: slicing can expose half of a credential.
87
+ if (value.length > LIMITS.stringLength) return TRUNCATED;
88
+ return value
89
+ .replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s<>"'`]+/gi, sanitizeUrl)
90
+ .replace(/\b(?:Bearer|Basic)\s+[a-z0-9._~+/=-]+/gi, REDACTED)
91
+ .replace(
92
+ /\b((?:proxy[-_ ]?)?authorization|(?:set[-_ ]?)?cookie)\s*:\s*[^\r\n]+/gi,
93
+ "$1: [REDACTED]",
94
+ )
95
+ .replace(
96
+ /\b((?:[a-z0-9_.-]{0,64})?(?:password|secret|private[-_.]?key|api[-_.]?key|token)|passwd|pwd|passphrase|mnemonic|seed[-_.]?phrase|credentials?|encryption[-_.]?key|signing[-_.]?key|session[-_.]?id|auth|(?:proxy[-_.]?)?authorization|(?:set[-_.]?)?cookie)(["']?\s*[=:]\s*)("(?:\\.|[^"\\\r\n])*"|'(?:\\.|[^'\\\r\n])*'|[^\s&,;"']+)/gi,
97
+ (_match, key, separator, value) => {
98
+ const quote = value[0] === '"' || value[0] === "'" ? value[0] : "";
99
+ return `${key}${separator}${quote}${REDACTED}${quote}`;
100
+ },
101
+ );
102
+ }
103
+
104
+ function readDataProperty(value, key) {
105
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
106
+ return descriptor && "value" in descriptor
107
+ ? descriptor.value
108
+ : "[Accessor omitted]";
109
+ }
110
+
111
+ function errorName(value) {
112
+ let prototype = value;
113
+ for (let i = 0; prototype && i < LIMITS.depth; i += 1) {
114
+ if (Object.hasOwn(prototype, "name")) {
115
+ const name = readDataProperty(prototype, "name");
116
+ return typeof name === "string" ? name : "Error";
117
+ }
118
+ prototype = Object.getPrototypeOf(prototype);
119
+ }
120
+ return "Error";
121
+ }
122
+
123
+ function setDataProperty(target, key, value) {
124
+ // Defining __proto__ as data cannot mutate the output object's prototype.
125
+ Object.defineProperty(target, key, {
126
+ value,
127
+ enumerable: true,
128
+ configurable: true,
129
+ writable: true,
130
+ });
131
+ }
132
+
133
+ export function sanitizeAuditDetails(details) {
134
+ const ancestors = new WeakSet();
135
+ let remainingNodes = LIMITS.nodes;
136
+ let remainingCharacters = LIMITS.totalCharacters;
137
+
138
+ function text(value) {
139
+ const sanitized = sanitizeString(value);
140
+ if (sanitized.length > remainingCharacters) return TRUNCATED;
141
+ remainingCharacters -= sanitized.length;
142
+ return sanitized;
143
+ }
144
+
145
+ function visit(value, depth = 0, context = "") {
146
+ if (remainingNodes-- <= 0) return TRUNCATED;
147
+ if (value === null || value === undefined) return value;
148
+ if (typeof value === "string") return text(value);
149
+ if (typeof value === "bigint") return text(value.toString());
150
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
151
+ if (typeof value === "boolean") return value;
152
+ if (typeof value === "function") return "[Function omitted]";
153
+ if (typeof value === "symbol") return "[Symbol omitted]";
154
+ if (depth >= LIMITS.depth) return TRUNCATED;
155
+ if (ancestors.has(value)) return "[Circular Reference]";
156
+ ancestors.add(value);
157
+ try {
158
+ if (value instanceof Date) {
159
+ return text(Date.prototype.toISOString.call(value));
160
+ }
161
+ if (value instanceof URL) {
162
+ return text(URL.prototype.toString.call(value));
163
+ }
164
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
165
+ return "[Binary omitted]";
166
+ }
167
+
168
+ // Native fetch headers and query objects have no useful enumerable fields.
169
+ if (value instanceof Headers || value instanceof URLSearchParams) {
170
+ const result = {};
171
+ const iterator =
172
+ value instanceof Headers
173
+ ? Headers.prototype.entries.call(value)
174
+ : URLSearchParams.prototype.entries.call(value);
175
+ let count = 0;
176
+ for (const [key, item] of iterator) {
177
+ if (count++ >= LIMITS.entries || remainingNodes <= 0) {
178
+ setDataProperty(result, "[Truncated]", true);
179
+ break;
180
+ }
181
+ if (key.length > LIMITS.keyLength) continue;
182
+ setDataProperty(
183
+ result,
184
+ text(key),
185
+ isSensitiveQueryKey(key) ? REDACTED : visit(item, depth + 1),
186
+ );
187
+ }
188
+ return result;
189
+ }
190
+
191
+ if (Array.isArray(value)) {
192
+ const result = [];
193
+ const isHeaderList = normalizeKey(context).endsWith("headers");
194
+ // Header tuple arrays are commonly returned by fetch/HTTP clients.
195
+ const first = readDataProperty(value, "0");
196
+ const isSensitivePair =
197
+ value.length === 2 &&
198
+ typeof first === "string" &&
199
+ isSensitiveKey(first);
200
+ for (let i = 0; i < value.length; i += 1) {
201
+ if (i >= LIMITS.entries || remainingNodes <= 0) {
202
+ result.push(TRUNCATED);
203
+ break;
204
+ }
205
+ const previous =
206
+ i % 2 === 1 && isHeaderList
207
+ ? readDataProperty(value, String(i - 1))
208
+ : null;
209
+ const redact =
210
+ (isSensitivePair && i === 1) ||
211
+ (typeof previous === "string" && isSensitiveKey(previous));
212
+ result.push(
213
+ redact
214
+ ? REDACTED
215
+ : visit(readDataProperty(value, String(i)), depth + 1, context),
216
+ );
217
+ }
218
+ return result;
219
+ }
220
+
221
+ const result = {};
222
+ if (value instanceof Error) {
223
+ setDataProperty(result, "name", text(errorName(value)));
224
+ // message/stack/cause are usually non-enumerable. Do not call getters.
225
+ for (const key of ["name", "message", "stack", "cause"]) {
226
+ if (Object.hasOwn(value, key)) {
227
+ setDataProperty(
228
+ result,
229
+ key,
230
+ visit(readDataProperty(value, key), depth + 1),
231
+ );
232
+ }
233
+ }
234
+ }
235
+ let count = 0;
236
+ const headerName = normalizeKey(context).endsWith("headers")
237
+ ? readDataProperty(value, "name")
238
+ : null;
239
+ for (const key in value) {
240
+ if (
241
+ count++ >= LIMITS.entries ||
242
+ remainingNodes <= 0 ||
243
+ remainingCharacters <= 0
244
+ ) {
245
+ setDataProperty(result, "[Truncated]", true);
246
+ break;
247
+ }
248
+ if (!Object.hasOwn(value, key)) continue;
249
+ if (key.length > LIMITS.keyLength) {
250
+ setDataProperty(result, "[Truncated key]", true);
251
+ continue;
252
+ }
253
+ setDataProperty(
254
+ result,
255
+ text(key),
256
+ isSensitiveKey(key) ||
257
+ (key === "value" &&
258
+ typeof headerName === "string" &&
259
+ isSensitiveKey(headerName))
260
+ ? REDACTED
261
+ : visit(readDataProperty(value, key), depth + 1, key),
262
+ );
263
+ }
264
+ return result;
265
+ } catch {
266
+ // Proxies, invalid native objects, etc. must not break event persistence.
267
+ return "[Unserializable]";
268
+ } finally {
269
+ ancestors.delete(value);
270
+ }
271
+ }
272
+
273
+ const sanitized = visit(details);
274
+ const serialized = JSON.stringify(sanitized);
275
+ return serialized &&
276
+ Buffer.byteLength(serialized, "utf8") > LIMITS.serializedBytes
277
+ ? TRUNCATED
278
+ : sanitized;
279
+ }
@@ -18,6 +18,7 @@ import {
18
18
  buildAutomationCenterRuntimeProjection,
19
19
  } from "./automation-center-runtime.js";
20
20
  import {
21
+ AUTOMATION_EXECUTION_CAPABILITY,
21
22
  EXECUTION_STATUS,
22
23
  FLOW_STATUS,
23
24
  TRIGGER_TYPE,
@@ -117,6 +118,7 @@ function projectExecution(execution) {
117
118
  return {
118
119
  id: execution.id,
119
120
  status: execution.status,
121
+ mode: execution.mode,
120
122
  triggerType: execution.triggerType || null,
121
123
  durationMs: Number(execution.durationMs) || 0,
122
124
  startedAt: execution.startedAt || null,
@@ -213,6 +215,7 @@ function projectFlow(db, flow, { historyLimit, now }) {
213
215
  history,
214
216
  incidents,
215
217
  security,
218
+ executionCapability: AUTOMATION_EXECUTION_CAPABILITY,
216
219
  };
217
220
  const revision = digest(content);
218
221
  const active = flow.status === FLOW_STATUS.ACTIVE;
@@ -225,21 +228,28 @@ function projectFlow(db, flow, { historyLimit, now }) {
225
228
  actions: [
226
229
  action(
227
230
  "run_now",
228
- active && security.ready,
231
+ active && security.ready && AUTOMATION_EXECUTION_CAPABILITY.live,
229
232
  !active
230
233
  ? "flow is not active"
231
- : "permission or budget preflight denied",
234
+ : !security.ready
235
+ ? "permission or budget preflight denied"
236
+ : AUTOMATION_EXECUTION_CAPABILITY.reason,
232
237
  flow.id,
233
238
  revision,
234
239
  ),
235
240
  action(
236
241
  "retry_failed",
237
- active && latestFailed && security.ready,
242
+ active &&
243
+ latestFailed &&
244
+ security.ready &&
245
+ AUTOMATION_EXECUTION_CAPABILITY.live,
238
246
  !active
239
247
  ? "flow is not active"
240
248
  : !latestFailed
241
249
  ? "latest run did not fail"
242
- : "permission or budget preflight denied",
250
+ : !security.ready
251
+ ? "permission or budget preflight denied"
252
+ : AUTOMATION_EXECUTION_CAPABILITY.reason,
243
253
  flow.id,
244
254
  revision,
245
255
  ),