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.
- package/README.md +91 -5
- package/package.json +3 -3
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-C8AkN9R5.js → AIOps-DgV7xb8F.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BrAzSQor.js → ActionButton-CgANpkKu.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Cu56X8Oh.js → Analytics-DnvpX7RB.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BP1Riofl.js → AppLayout-C2bHccBM.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-CIW-nNAz.js → Artifacts-BIhijC9g.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CJtDabk-.js → Audit-CKRjWGdp.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DYIHeQ_P.js → BackgroundAgents-CblYtgBE.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B4CsFzj7.js → Backup-Cq35b78a.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-3eoJ5kfb.js → BaseInput-DcB7NoRz.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BBhX2L_E.js → Chat-tc3b-s7i.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-RN8cbv7w.js → ChatBubbleRenderer-fcc_Tvqu.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-5UvmwHVk.js → Checkbox-BLD5bH5u.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BFy8zsBN.js → Codegen-BLOsoazN.js} +1 -1
- package/src/assets/web-panel/assets/{Col-4M6bKRRO.js → Col-Bdr7JwIx.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D6LC0j7_.js → Community-C84BsWE0.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dd48xMcv.js → Compact-Dzdwd04z.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Ba85ggmy.js → Compliance-CCG-R0EV.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-D1BXlkuK.js → Cowork-BYj72SK0.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Ca2Uy7Ia.js → Cron-B6iKAwOf.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-C2bDRXZg.js → Crosschain-BJ-oDC6u.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DySZKAJf.js → DID-BnMckGLr.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DDpYf-TT.js → Dashboard-Cyje-gCO.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DGjROfPv.js → Dropdown-BpNlenjK.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DxX9QYiB.js → EmailListRenderer-BhonO7Nv.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-TBCZyrSJ.js → EvolutionSettings-DVoNU-Id.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BeqwTXBa.js → FamilyGuardDashboard-tdn-KC67.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CiCpKJQ1.js → Federation--EEVrHhz.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CdTmbLkU.js → FormItemContext-Cy8zr0-4.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BwbkEY-5.js → GenericCardRenderer-BuUhpgFi.js} +1 -1
- package/src/assets/web-panel/assets/{Git-VnAga2vv.js → Git-Ctd3E5Pe.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-i-4Ebs-H.js → Governance-Ce7dV6aU.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CirjTgNw.js → Inference-CD1vExIH.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CunS7vhA.js → KnowledgeGraph-Dn64OdQ7.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DBuTF0c6.js → Logs-PmElVRrT.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-B-iE-tt_.js → MarkdownRenderer-BFiVKf5t.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BK6ZivTS.js → Marketplace-OW4jTXwx.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CUnCRnd3.js → McpTools-BEq2Ib4x.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CBGGr8Gy.js → Memory-Can_P2oK.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-reB6iaWD.js → MobileBridge-DJ8R-dn3.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-o1YdVB7i.js → MobileProjects-B7kV9GOt.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-if5OE3GH.js → Mtc-BfxamolS.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BTZWpq0j.js → MtcAudit-DHtuv7av.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-8cvMAYFL.js → Multisig-DLkLpvxc.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BMvUXAWo.js → NLProgramming-u4XtJTIt.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BWWjColh.js → Notes-BwuuPJLS.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Ccr4lIhS.js → NotificationSettings-HEeu-E9v.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DhksGy6D.js → OrderTableRenderer-BtvN-Qwh.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DciXQfdY.js → Organization-Yh-czs3b.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-8DR7uMSx.js → Overflow-DmE8mYVM.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DE6euHYl.js → P2P-CWVck8WN.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-ByuWoauq.js → PdhVaultBrowser-DgFqekod.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-DkjM87ac.js → Permissions-BtJBVOHV.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-2DLp0KTL.js → PersonalDataHub-6VBObXzd.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-Ci2Qlkfr.js → Pipeline-D222FmqY.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DlwDnDVA.js → Privacy-Bi9FMikp.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CmMifW39.js → ProjectInit-Bo52H47H.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DJVFIh-6.js → ProjectSettings-BPkesfOc.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-P2nWBS70.js → Projects-GynohSFX.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-B2cxaGCU.js → Providers-DVdMg04n.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CpO77kcE.js → QrScannerModal-DqJCb595.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BDQl1hb0.js → QuickAsk-J7loQbXi.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DTD2f3IN.js → Recommend-BI5aURVc.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DGZAnwvs.js → RemoteSession-BN2sqGvz.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-B_R4vitb.js → Reputation-BGOND-Fi.js} +1 -1
- package/src/assets/web-panel/assets/{Row-4Jj6JyXN.js → Row-77dfwaUk.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-D1t1MCZ-.js → RssFeed-FtBAxS3g.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CyOUlIn7.js → Search-BaYVLFb7.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BmknPT5Q.js → Security-LE3Vv6ab.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DkEK8mpa.js → Services-C5pP-Whz.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Bvo5bpuk.js → Skeleton-CLqKUVsF.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-AMmG8fim.js → Skills-BPjN0SX5.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Dl7-OKOV.js → Sla-14jD70kg.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DtiGKu0E.js → SpeechSettings-Dr9ij42W.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Ch7mp3ES.js → SyncSettings-BzLHP7B8.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Ck-sEgj-.js → Tasks-YqV9b0rV.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BlV22Il8.js → Templates-CxxAE4PK.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CaaAu0mX.js → Tenant-CRb3PcKJ.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-lA9g3FtJ.js → Terminal-CTzPpBaP.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CG26IFC3.js → TimelineRenderer-DjFUj_hy.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-iaJUBLBm.js → Tokens-Bbb8tPvx.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DWQJtLK3.js → Trigger-CSeWGM0W.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CTjmUwqp.js → Trust-JgESMBo3.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CMnxufgD.js → UkeySign-CiObLk0T.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-diCFSWJw.js → VideoEditing-CFEZaQ2x.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Ba1oND1K.js → Wallet-DR8ZGDNn.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DZDqPS-S.js → WebAuthn-DxZukvu7.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CfN8fPMe.js → WorkflowEditor-CKgSZQwn.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BiqMsO_i.js → chat-CTxEQE66.js} +1 -1
- package/src/assets/web-panel/assets/{colors-By8LkjqH.js → colors-CAjKMUu3.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-B0mxvRe3.js → compact-item-BXuz49at.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Li2ub348.js → createContext-CFN_Hwr9.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DYbHPkbl.js → hasIn-BwoSBSfP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVZNYRzM.js → index-B0QbLlWn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGZzexNa.js → index-B2o_BBjg.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYv3JIzl.js → index-B2tEnBPx.js} +1 -1
- package/src/assets/web-panel/assets/{index-1lVoRUrQ.js → index-B7kp-zRE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTVPeUh3.js → index-B9yR7zqr.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFhksbXp.js → index-BK4ftQ4d.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0D0HkkM.js → index-Bj4hIiLW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEp_3fKJ.js → index-BmQITjMU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIImi0cd.js → index-BmXpdcHI.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6qL3QBU.js → index-Bqv_Cray.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSk0xuXP.js → index-Bu2P6u8m.js} +1 -1
- package/src/assets/web-panel/assets/{index-zSzXsF9b.js → index-Bw9s2d3c.js} +1 -1
- package/src/assets/web-panel/assets/{index-beDji-cB.js → index-C8er4W9u.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-RE3mFh.js → index-CB3kVd9c.js} +1 -1
- package/src/assets/web-panel/assets/index-CCsRfd0k.js +1 -0
- package/src/assets/web-panel/assets/{index-CA0AOURT.js → index-CF9lWi1o.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMh3VxgO.js → index-CN53dE_u.js} +1 -1
- package/src/assets/web-panel/assets/{index-KWt8Owo8.js → index-CSmFby3Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-DB4DCzqU.js → index-CehdwJ_Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHgiSV6R.js → index-Cgk0YEiq.js} +1 -1
- package/src/assets/web-panel/assets/{index-b4O_YBVR.js → index-Cp5y7lX_.js} +1 -1
- package/src/assets/web-panel/assets/index-CsmiZIQ4.js +1 -0
- package/src/assets/web-panel/assets/{index-DAOpBv3C.js → index-DTX9CJPx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZqTG7fP.js → index-DViK2bkv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bc6bxU24.js → index-DY-gBSm8.js} +1 -1
- package/src/assets/web-panel/assets/{index-Czt7WAtA.js → index-DjF5BOZx.js} +1 -1
- package/src/assets/web-panel/assets/{index-KqfqSdAC.js → index-DmkbAADP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bd5znvCV.js → index-DpdDnZX_.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5Se6Lnv.js → index-Dv7V2kg6.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cpfn4YbT.js → index-DxunxaTw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcOJEgBE.js → index-F2E5RCwz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgyrklzQ.js → index-IY9bd5az.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClsJN8sW.js → index-IahILygB.js} +3 -3
- package/src/assets/web-panel/assets/{index-hw3sCYAz.js → index-T3MTE6jB.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bm2P2Kgp.js → index-Tz5dheZa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRzewWeE.js → index-_ZtCyUdz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPRgnazi.js → index-o9DpkZKf.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByqFKMWL.js → index-t2Ch_JKn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgMFnBOv.js → index-u9_DM3ZC.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-TgDL_7OY.js → initDefaultProps-BoiGJDoO.js} +1 -1
- package/src/assets/web-panel/assets/{motion-fHosyV5c.js → motion-5eL4E0pA.js} +1 -1
- package/src/assets/web-panel/assets/{move-C_QfW5qg.js → move-DjggDi_1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-u7ywDVOg.js → mtc-parser-Ce8Vo2T3.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BEJdUgE9.js → omit-D1yOBaO2.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DGkQFAJ5.js → pickAttrs-8NLceQe8.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DUyZXAjt.js → placementArrow-CsIdBRmQ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B4xDxO7Q.js → responsiveObserve-GM5NE8En.js} +1 -1
- package/src/assets/web-panel/assets/{slide-B8WuJtst.js → slide-44yj3u49.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DLUqy7JO.js → statusUtils-B8tqtWcX.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BYOJOyqL.js → styleChecker-NhDPBbyB.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-WChWQURv.js → useFlexGapSupport-C8Qz1GtN.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-vLNpm3dv.js → useFs-ClUv4kih.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DSZ8unoU.js → usePersonalDataHub-BwkOVEh6.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C4Xf7Kg1.js → vnode--gMF33R0.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BulmeAGy.js → zoom-DXg3TqOP.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +5 -5
- package/src/commands/agent-process-ownership.js +121 -0
- package/src/commands/agent.js +2 -0
- package/src/commands/automation.js +35 -8
- package/src/commands/hub.js +224 -0
- package/src/commands/project.js +162 -0
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/personal-data-hub-protocol.js +54 -8
- package/src/lib/audit-logger.js +59 -46
- package/src/lib/audit-sanitizer.js +279 -0
- package/src/lib/automation-center.js +14 -4
- package/src/lib/automation-engine.js +151 -39
- package/src/lib/checkpoint-restore-saga.js +11 -1
- package/src/lib/eval/verify01-host-evidence.js +36 -3
- package/src/lib/knowledge-graph.js +27 -0
- package/src/lib/personal-data-hub-wiring.js +44 -1
- package/src/lib/process-execution-broker/index.js +91 -1
- package/src/lib/process-execution-broker/platform-sandbox.js +42 -0
- package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +757 -0
- package/src/lib/process-execution-broker/windows-native-evaluator.js +316 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +383 -11
- package/src/lib/scheduler-kernel/automation-adapter.js +15 -3
- package/src/lib/scheduler-kernel/automation-event-adapter.js +15 -3
- package/src/assets/web-panel/assets/devWarning-D90arbUg.js +0 -1
- package/src/assets/web-panel/assets/index-CeP1oROI.js +0 -1
- package/src/assets/web-panel/assets/index-Cu9gkyRc.js +0 -1
package/src/lib/audit-logger.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 =
|
|
148
|
-
const risk =
|
|
149
|
-
event.riskLevel
|
|
150
|
-
assessRisk(event.eventType, event.operation,
|
|
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)
|
|
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
|
|
164
|
-
event.userAgent
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
533
|
-
userAgent: userAgent
|
|
545
|
+
ipAddress: ipAddress ? projectAuditField("ipAddress", ipAddress) : null,
|
|
546
|
+
userAgent: userAgent ? projectAuditField("userAgent", userAgent) : null,
|
|
534
547
|
success: success !== false,
|
|
535
|
-
errorMessage: errorMessage
|
|
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
|
-
:
|
|
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 &&
|
|
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
|
-
:
|
|
250
|
+
: !security.ready
|
|
251
|
+
? "permission or budget preflight denied"
|
|
252
|
+
: AUTOMATION_EXECUTION_CAPABILITY.reason,
|
|
243
253
|
flow.id,
|
|
244
254
|
revision,
|
|
245
255
|
),
|