@rubytech/create-sitedesk-code 0.1.608 → 0.1.609
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/package.json +1 -1
- package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.js +86 -0
- package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.js.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.d.ts +30 -9
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +22 -2
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/__tests__/account-id-gate.test.ts +99 -1
- package/payload/platform/lib/graph-write/src/index.ts +47 -12
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +45 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +8 -0
- package/payload/platform/plugins/docs/references/telegram-guide.md +44 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +65 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/xacct-counters.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/xacct-counters.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/xacct-counters.test.js +169 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/xacct-counters.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/xacct-counters.d.ts +63 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/xacct-counters.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/xacct-counters.js +114 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/xacct-counters.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-cross-account.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-cross-account.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-cross-account.test.js +123 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-cross-account.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/xacct-write-gate.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/xacct-write-gate.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/xacct-write-gate.test.js +110 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/xacct-write-gate.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +7 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/vitest.config.ts +2 -0
- package/payload/platform/services/claude-session-manager/dist/claude-trust-preflight.d.ts +43 -0
- package/payload/platform/services/claude-session-manager/dist/claude-trust-preflight.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/claude-trust-preflight.js +88 -0
- package/payload/platform/services/claude-session-manager/dist/claude-trust-preflight.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +125 -4
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +26 -1
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +26 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/recover-account.d.ts +54 -0
- package/payload/platform/services/claude-session-manager/dist/recover-account.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/recover-account.js +141 -0
- package/payload/platform/services/claude-session-manager/dist/recover-account.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/session-account-census.d.ts +30 -0
- package/payload/platform/services/claude-session-manager/dist/session-account-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/session-account-census.js +96 -0
- package/payload/platform/services/claude-session-manager/dist/session-account-census.js.map +1 -0
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts +9 -0
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js +15 -0
- package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +6 -4
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +15 -1
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/server/{chunk-GI5AVCRG.js → chunk-DRDU74ZM.js} +1 -1
- package/payload/server/{chunk-MNN2RWJR.js → chunk-IOPUA7QV.js} +1 -1
- package/payload/server/{chunk-6AQYMT6C.js → chunk-T6NXRWMG.js} +43 -8
- package/payload/server/{manager-VDHT3YYI.js → manager-O5L2SKW7.js} +2 -2
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/agents.html +5 -5
- package/payload/server/public/assets/{AdminLoginScreens-DuQ3ax5U.js → AdminLoginScreens-BBKEIEjY.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-BBKEIEjY.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-BBKEIEjY.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-1HyATV_t.js → AdminShell-CrCdEMNW.js} +1 -1
- package/payload/server/public/assets/AdminShell-CrCdEMNW.js.br +0 -0
- package/payload/server/public/assets/AdminShell-CrCdEMNW.js.gz +0 -0
- package/payload/server/public/assets/{activity-C2qWlcJ5.js → activity-CbR3vaq1.js} +1 -1
- package/payload/server/public/assets/activity-CbR3vaq1.js.br +0 -0
- package/payload/server/public/assets/activity-CbR3vaq1.js.gz +0 -0
- package/payload/server/public/assets/{admin-DqpfY8-t.js → admin-D8qKnmhE.js} +1 -1
- package/payload/server/public/assets/admin-D8qKnmhE.js.br +0 -0
- package/payload/server/public/assets/admin-D8qKnmhE.js.gz +0 -0
- package/payload/server/public/assets/{agents-DoGVAjIT.js → agents-8gAQjRqI.js} +1 -1
- package/payload/server/public/assets/agents-8gAQjRqI.js.br +0 -0
- package/payload/server/public/assets/agents-8gAQjRqI.js.gz +0 -0
- package/payload/server/public/assets/{browser-DjqS897k.js → browser-jAje5ILy.js} +1 -1
- package/payload/server/public/assets/browser-jAje5ILy.js.br +0 -0
- package/payload/server/public/assets/browser-jAje5ILy.js.gz +0 -0
- package/payload/server/public/assets/{calendar-DJeOm0WS.js → calendar-xEmCJif9.js} +1 -1
- package/payload/server/public/assets/calendar-xEmCJif9.js.br +0 -0
- package/payload/server/public/assets/calendar-xEmCJif9.js.gz +0 -0
- package/payload/server/public/assets/chat-Ct5RDmv6.js +1 -0
- package/payload/server/public/assets/chat-Ct5RDmv6.js.br +0 -0
- package/payload/server/public/assets/chat-Ct5RDmv6.js.gz +0 -0
- package/payload/server/public/assets/{chevron-left-D9z1aK3p.js → chevron-left-DV8gIVC9.js} +1 -1
- package/payload/server/public/assets/chevron-left-DV8gIVC9.js.br +0 -0
- package/payload/server/public/assets/clock-PnR4Tlg9.js +1 -0
- package/payload/server/public/assets/clock-PnR4Tlg9.js.br +0 -0
- package/payload/server/public/assets/{copy-p9ZM9fnn.js → copy-b6MpzRz9.js} +1 -1
- package/payload/server/public/assets/copy-b6MpzRz9.js.br +0 -0
- package/payload/server/public/assets/copy-b6MpzRz9.js.gz +0 -0
- package/payload/server/public/assets/data-BxFc9wPl.js +1 -0
- package/payload/server/public/assets/data-BxFc9wPl.js.br +2 -0
- package/payload/server/public/assets/data-BxFc9wPl.js.gz +0 -0
- package/payload/server/public/assets/{field-WRk67lvr.js → field-CiIsn-47.js} +1 -1
- package/payload/server/public/assets/field-CiIsn-47.js.br +0 -0
- package/payload/server/public/assets/field-CiIsn-47.js.gz +0 -0
- package/payload/server/public/assets/{file-text-BJDCb334.js → file-text-Cy-IjCf8.js} +1 -1
- package/payload/server/public/assets/file-text-Cy-IjCf8.js.br +0 -0
- package/payload/server/public/assets/file-text-Cy-IjCf8.js.gz +0 -0
- package/payload/server/public/assets/{graph-CAU2xh2Z.js → graph-BdC2IGOT.js} +1 -1
- package/payload/server/public/assets/graph-BdC2IGOT.js.br +0 -0
- package/payload/server/public/assets/graph-BdC2IGOT.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-CEDmX7qW.js → graph-labels-3bstML8n.js} +1 -1
- package/payload/server/public/assets/graph-labels-3bstML8n.js.br +0 -0
- package/payload/server/public/assets/graph-labels-3bstML8n.js.gz +0 -0
- package/payload/server/public/assets/{jsx-runtime-hPFGo4rC.css → jsx-runtime-JxxB_2S6.css} +1 -1
- package/payload/server/public/assets/jsx-runtime-JxxB_2S6.css.br +0 -0
- package/payload/server/public/assets/{jsx-runtime-hPFGo4rC.css.gz → jsx-runtime-JxxB_2S6.css.gz} +0 -0
- package/payload/server/public/assets/{operator-1WFztEQA.js → operator-D7L2SA16.js} +1 -1
- package/payload/server/public/assets/operator-D7L2SA16.js.br +0 -0
- package/payload/server/public/assets/operator-D7L2SA16.js.gz +0 -0
- package/payload/server/public/assets/{page-B72XigcU.js → page-DspGbDgK.js} +1 -1
- package/payload/server/public/assets/page-DspGbDgK.js.br +0 -0
- package/payload/server/public/assets/page-DspGbDgK.js.gz +0 -0
- package/payload/server/public/assets/{page-nT8l_cX1.js → page-ObXxk8ol.js} +1 -1
- package/payload/server/public/assets/page-ObXxk8ol.js.br +0 -0
- package/payload/server/public/assets/page-ObXxk8ol.js.gz +0 -0
- package/payload/server/public/assets/play-BL4ztD3m.js +1 -0
- package/payload/server/public/assets/play-BL4ztD3m.js.br +0 -0
- package/payload/server/public/assets/play-BL4ztD3m.js.gz +0 -0
- package/payload/server/public/assets/{public-DAea6w7w.js → public-CEXKl8wg.js} +1 -1
- package/payload/server/public/assets/public-CEXKl8wg.js.br +0 -0
- package/payload/server/public/assets/public-CEXKl8wg.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-CqlRlGsY.js → rotate-ccw-ckXDebK2.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-ckXDebK2.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-ckXDebK2.js.gz +0 -0
- package/payload/server/public/assets/{routines-vy5xsyqx.js → routines-Dwc2meN2.js} +1 -1
- package/payload/server/public/assets/routines-Dwc2meN2.js.br +0 -0
- package/payload/server/public/assets/routines-Dwc2meN2.js.gz +0 -0
- package/payload/server/public/assets/{skills-X7FTilVy.js → skills-DdHKHl4Z.js} +1 -1
- package/payload/server/public/assets/skills-DdHKHl4Z.js.br +0 -0
- package/payload/server/public/assets/skills-DdHKHl4Z.js.gz +0 -0
- package/payload/server/public/assets/{tasks-BXx_jk_p.js → tasks-C_yWRvOG.js} +1 -1
- package/payload/server/public/assets/tasks-C_yWRvOG.js.br +0 -0
- package/payload/server/public/assets/tasks-C_yWRvOG.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-CuWcGaRo.js → triangle-alert-C-7A00P0.js} +1 -1
- package/payload/server/public/assets/triangle-alert-C-7A00P0.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-C-7A00P0.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-DLSKs6r2.js → useCopyFeedback-CWvSi-Qe.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-CWvSi-Qe.js.br +2 -0
- package/payload/server/public/assets/useCopyFeedback-CWvSi-Qe.js.gz +0 -0
- package/payload/server/public/assets/{useMediaQuery-C_1CV_iW.js → useMediaQuery-CLVRXJMp.js} +1 -1
- package/payload/server/public/assets/useMediaQuery-CLVRXJMp.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-CLVRXJMp.js.gz +0 -0
- package/payload/server/public/assets/{useVoiceRecorder-DBzM_HIx.js → useVoiceRecorder-BbJad9CQ.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-BbJad9CQ.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BbJad9CQ.js.gz +0 -0
- package/payload/server/public/assets/{wrench-nDMQ6x-6.js → wrench-Cl6TUm2T.js} +1 -1
- package/payload/server/public/assets/wrench-Cl6TUm2T.js.br +0 -0
- package/payload/server/public/assets/wrench-Cl6TUm2T.js.gz +0 -0
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +8 -8
- package/payload/server/public/chat.html +14 -14
- package/payload/server/public/data.html +12 -12
- package/payload/server/public/field.html +3 -3
- package/payload/server/public/graph.html +10 -10
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +16 -16
- package/payload/server/public/public.html +14 -14
- package/payload/server/public/routines.html +8 -8
- package/payload/server/public/skills.html +6 -6
- package/payload/server/public/tasks.html +7 -7
- package/payload/server/server.js +511 -283
- package/payload/server/public/assets/AdminLoginScreens-DuQ3ax5U.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-DuQ3ax5U.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-1HyATV_t.js.br +0 -0
- package/payload/server/public/assets/AdminShell-1HyATV_t.js.gz +0 -0
- package/payload/server/public/assets/activity-C2qWlcJ5.js.br +0 -0
- package/payload/server/public/assets/activity-C2qWlcJ5.js.gz +0 -0
- package/payload/server/public/assets/admin-DqpfY8-t.js.br +0 -0
- package/payload/server/public/assets/admin-DqpfY8-t.js.gz +0 -0
- package/payload/server/public/assets/agents-DoGVAjIT.js.br +0 -0
- package/payload/server/public/assets/agents-DoGVAjIT.js.gz +0 -0
- package/payload/server/public/assets/browser-DjqS897k.js.br +0 -0
- package/payload/server/public/assets/browser-DjqS897k.js.gz +0 -0
- package/payload/server/public/assets/calendar-DJeOm0WS.js.br +0 -0
- package/payload/server/public/assets/calendar-DJeOm0WS.js.gz +0 -0
- package/payload/server/public/assets/chat-BrRE0Dck.js +0 -1
- package/payload/server/public/assets/chat-BrRE0Dck.js.br +0 -0
- package/payload/server/public/assets/chat-BrRE0Dck.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-D9z1aK3p.js.br +0 -0
- package/payload/server/public/assets/clock-BqHWMICF.js +0 -1
- package/payload/server/public/assets/clock-BqHWMICF.js.br +0 -0
- package/payload/server/public/assets/clock-BqHWMICF.js.gz +0 -0
- package/payload/server/public/assets/copy-p9ZM9fnn.js.br +0 -0
- package/payload/server/public/assets/copy-p9ZM9fnn.js.gz +0 -0
- package/payload/server/public/assets/data-CPsqW0qW.js +0 -1
- package/payload/server/public/assets/data-CPsqW0qW.js.br +0 -0
- package/payload/server/public/assets/data-CPsqW0qW.js.gz +0 -0
- package/payload/server/public/assets/field-WRk67lvr.js.br +0 -0
- package/payload/server/public/assets/field-WRk67lvr.js.gz +0 -0
- package/payload/server/public/assets/file-text-BJDCb334.js.br +0 -0
- package/payload/server/public/assets/file-text-BJDCb334.js.gz +0 -0
- package/payload/server/public/assets/graph-CAU2xh2Z.js.br +0 -0
- package/payload/server/public/assets/graph-CAU2xh2Z.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-CEDmX7qW.js.br +0 -0
- package/payload/server/public/assets/graph-labels-CEDmX7qW.js.gz +0 -0
- package/payload/server/public/assets/jsx-runtime-hPFGo4rC.css.br +0 -0
- package/payload/server/public/assets/operator-1WFztEQA.js.br +0 -0
- package/payload/server/public/assets/operator-1WFztEQA.js.gz +0 -0
- package/payload/server/public/assets/page-B72XigcU.js.br +0 -0
- package/payload/server/public/assets/page-B72XigcU.js.gz +0 -0
- package/payload/server/public/assets/page-nT8l_cX1.js.br +0 -0
- package/payload/server/public/assets/page-nT8l_cX1.js.gz +0 -0
- package/payload/server/public/assets/play-CYqOCqm6.js +0 -1
- package/payload/server/public/assets/play-CYqOCqm6.js.br +0 -0
- package/payload/server/public/assets/play-CYqOCqm6.js.gz +0 -0
- package/payload/server/public/assets/public-DAea6w7w.js.br +0 -0
- package/payload/server/public/assets/public-DAea6w7w.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-CqlRlGsY.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-CqlRlGsY.js.gz +0 -0
- package/payload/server/public/assets/routines-vy5xsyqx.js.br +0 -0
- package/payload/server/public/assets/routines-vy5xsyqx.js.gz +0 -0
- package/payload/server/public/assets/skills-X7FTilVy.js.br +0 -0
- package/payload/server/public/assets/skills-X7FTilVy.js.gz +0 -0
- package/payload/server/public/assets/tasks-BXx_jk_p.js.br +0 -0
- package/payload/server/public/assets/tasks-BXx_jk_p.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-CuWcGaRo.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-CuWcGaRo.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-DLSKs6r2.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-DLSKs6r2.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-C_1CV_iW.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-C_1CV_iW.js.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DBzM_HIx.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DBzM_HIx.js.gz +0 -0
- package/payload/server/public/assets/wrench-nDMQ6x-6.js.br +0 -0
- package/payload/server/public/assets/wrench-nDMQ6x-6.js.gz +0 -0
- /package/payload/server/public/assets/{jsx-runtime-CvVXOszc.js → jsx-runtime-BCAZhYqz.js} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-CvVXOszc.js.br → jsx-runtime-BCAZhYqz.js.br} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-CvVXOszc.js.gz → jsx-runtime-BCAZhYqz.js.gz} +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
|
|
2
|
+
import { noteXacctWriteCall, noteXacctWriteOutcome, readXacctWindow, __resetXacctWindow, formatWriteOutcome, formatXacctCensus, writeOutcomeReason, startXacctCensus, } from "../xacct-counters.js";
|
|
3
|
+
import { INVALID_ACCOUNT_ID_REASON } from "../../../../../../lib/graph-write/dist/index.js";
|
|
4
|
+
// Task 2731 — the two signals that make an allow-then-refuse pair visible.
|
|
5
|
+
//
|
|
6
|
+
// Both halves of the defect were already logged before this task, in one file,
|
|
7
|
+
// and nothing reconciled them: `[xacct] op=call … decision=allow` from the
|
|
8
|
+
// resolver, `[graph-write] reject reason=invalid-account-id` from the gate. The
|
|
9
|
+
// write-outcome line pairs them on one row. The census answers the other
|
|
10
|
+
// question a per-call line cannot: whether the feature is being exercised at
|
|
11
|
+
// all, because a capability nobody invokes reads identically to one that works.
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
__resetXacctWindow();
|
|
14
|
+
});
|
|
15
|
+
describe("cross-account write counters", () => {
|
|
16
|
+
it("starts empty", () => {
|
|
17
|
+
expect(readXacctWindow()).toEqual({
|
|
18
|
+
writeCalls: 0,
|
|
19
|
+
allowed: 0,
|
|
20
|
+
gatePassed: 0,
|
|
21
|
+
gateRejected: 0,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it("counts an allowed call and its passing write", () => {
|
|
25
|
+
noteXacctWriteCall(true);
|
|
26
|
+
noteXacctWriteOutcome("passed");
|
|
27
|
+
expect(readXacctWindow()).toEqual({
|
|
28
|
+
writeCalls: 1,
|
|
29
|
+
allowed: 1,
|
|
30
|
+
gatePassed: 1,
|
|
31
|
+
gateRejected: 0,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
it("counts a denied call as a call but never as allowed", () => {
|
|
35
|
+
noteXacctWriteCall(false);
|
|
36
|
+
expect(readXacctWindow()).toEqual({
|
|
37
|
+
writeCalls: 1,
|
|
38
|
+
allowed: 0,
|
|
39
|
+
gatePassed: 0,
|
|
40
|
+
gateRejected: 0,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
it("counts a gate rejection separately from a pass", () => {
|
|
44
|
+
noteXacctWriteCall(true);
|
|
45
|
+
noteXacctWriteOutcome("rejected");
|
|
46
|
+
expect(readXacctWindow()).toEqual({
|
|
47
|
+
writeCalls: 1,
|
|
48
|
+
allowed: 1,
|
|
49
|
+
gatePassed: 0,
|
|
50
|
+
gateRejected: 1,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe("write-outcome line", () => {
|
|
55
|
+
it("renders the pass case with reason=none", () => {
|
|
56
|
+
expect(formatWriteOutcome({
|
|
57
|
+
tool: "memory-write",
|
|
58
|
+
caller: "20028fb5-db26-4de7-bff6-c5ec2d4fc766",
|
|
59
|
+
target: "8a160746-1111-2222-3333-444444444444",
|
|
60
|
+
gate: "passed",
|
|
61
|
+
reason: null,
|
|
62
|
+
})).toBe("[xacct] op=write-outcome tool=memory-write caller=20028fb5 target=8a160746 gate=passed reason=none\n");
|
|
63
|
+
});
|
|
64
|
+
it("renders the defect signature: an allowed call the gate refused", () => {
|
|
65
|
+
expect(formatWriteOutcome({
|
|
66
|
+
tool: "memory-write",
|
|
67
|
+
caller: "20028fb5-db26-4de7-bff6-c5ec2d4fc766",
|
|
68
|
+
target: "8a160746-1111-2222-3333-444444444444",
|
|
69
|
+
gate: "rejected",
|
|
70
|
+
reason: "invalid-account-id",
|
|
71
|
+
})).toBe("[xacct] op=write-outcome tool=memory-write caller=20028fb5 target=8a160746 gate=rejected reason=invalid-account-id\n");
|
|
72
|
+
});
|
|
73
|
+
it("names a non-gate failure without claiming the gate refused it", () => {
|
|
74
|
+
const line = formatWriteOutcome({
|
|
75
|
+
tool: "memory-write",
|
|
76
|
+
caller: "20028fb5-db26-4de7-bff6-c5ec2d4fc766",
|
|
77
|
+
target: "8a160746-1111-2222-3333-444444444444",
|
|
78
|
+
gate: "passed",
|
|
79
|
+
reason: "schema-validation",
|
|
80
|
+
});
|
|
81
|
+
expect(line).toContain("gate=passed");
|
|
82
|
+
expect(line).toContain("reason=schema-validation");
|
|
83
|
+
});
|
|
84
|
+
it("collapses whitespace in a reason so one failure cannot become two fields", () => {
|
|
85
|
+
const line = formatWriteOutcome({
|
|
86
|
+
tool: "memory-write",
|
|
87
|
+
caller: "20028fb5-db26-4de7-bff6-c5ec2d4fc766",
|
|
88
|
+
target: "8a160746-1111-2222-3333-444444444444",
|
|
89
|
+
gate: "passed",
|
|
90
|
+
reason: "write blocked (system-managed-key)",
|
|
91
|
+
});
|
|
92
|
+
// [xacct] op= tool= caller= target= gate= reason= — seven, always.
|
|
93
|
+
expect(line.trimEnd().split(" ")).toHaveLength(7);
|
|
94
|
+
expect(line).toContain("reason=write-blocked-(system-managed-key)");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe("reason vocabulary", () => {
|
|
98
|
+
it("names a gate rejection with the code an operator greps", () => {
|
|
99
|
+
expect(writeOutcomeReason("rejected", true)).toBe("invalid-account-id");
|
|
100
|
+
});
|
|
101
|
+
it("uses the chokepoint's own constant, so the two cannot drift", () => {
|
|
102
|
+
expect(writeOutcomeReason("rejected", true)).toBe(INVALID_ACCOUNT_ID_REASON);
|
|
103
|
+
});
|
|
104
|
+
it("names a non-gate failure without claiming the gate refused it", () => {
|
|
105
|
+
expect(writeOutcomeReason("passed", true)).toBe("write-failed");
|
|
106
|
+
});
|
|
107
|
+
it("is null when the write succeeded", () => {
|
|
108
|
+
expect(writeOutcomeReason("passed", false)).toBeNull();
|
|
109
|
+
});
|
|
110
|
+
it("never yields an error message, whatever the failure", () => {
|
|
111
|
+
// The whole point: `reason` is a name. A message would carry spaces,
|
|
112
|
+
// punctuation and an account slice into a field an operator greps by
|
|
113
|
+
// equality, and match nothing.
|
|
114
|
+
for (const gate of ["passed", "rejected"]) {
|
|
115
|
+
const reason = writeOutcomeReason(gate, true);
|
|
116
|
+
expect(reason).toMatch(/^[a-z-]+$/);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe("census line", () => {
|
|
121
|
+
it("renders every counter for the window", () => {
|
|
122
|
+
expect(formatXacctCensus(1, {
|
|
123
|
+
writeCalls: 13,
|
|
124
|
+
allowed: 13,
|
|
125
|
+
gatePassed: 0,
|
|
126
|
+
gateRejected: 13,
|
|
127
|
+
})).toBe("[xacct-census] window=1 writeCalls=13 allowed=13 gatePassed=0 gateRejected=13\n");
|
|
128
|
+
});
|
|
129
|
+
it("emits a zero window rather than staying silent", () => {
|
|
130
|
+
// A quiet period and a broken feature must be distinguishable. Suppressing
|
|
131
|
+
// the zero line would render them identically.
|
|
132
|
+
expect(formatXacctCensus(1, readXacctWindow())).toBe("[xacct-census] window=1 writeCalls=0 allowed=0 gatePassed=0 gateRejected=0\n");
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe("census timer", () => {
|
|
136
|
+
afterEach(() => {
|
|
137
|
+
vi.useRealTimers();
|
|
138
|
+
});
|
|
139
|
+
it("emits once per window and resets the counters", () => {
|
|
140
|
+
vi.useFakeTimers();
|
|
141
|
+
const emit = vi.fn();
|
|
142
|
+
const handle = startXacctCensus({ intervalMs: 1000, windowHours: 1, emit });
|
|
143
|
+
try {
|
|
144
|
+
noteXacctWriteCall(true);
|
|
145
|
+
noteXacctWriteOutcome("rejected");
|
|
146
|
+
vi.advanceTimersByTime(1000);
|
|
147
|
+
expect(emit).toHaveBeenCalledTimes(1);
|
|
148
|
+
expect(emit.mock.calls[0][0]).toBe("[xacct-census] window=1 writeCalls=1 allowed=1 gatePassed=0 gateRejected=1\n");
|
|
149
|
+
vi.advanceTimersByTime(1000);
|
|
150
|
+
expect(emit.mock.calls[1][0]).toBe("[xacct-census] window=1 writeCalls=0 allowed=0 gatePassed=0 gateRejected=0\n");
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
clearInterval(handle);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
it("does not hold the MCP child open", () => {
|
|
157
|
+
// The memory plugin is a stdio child of a session. A referenced timer keeps
|
|
158
|
+
// the event loop alive, so the child would outlive the session that spawned
|
|
159
|
+
// it. Real timers here on purpose: a faked handle has no ref to inspect.
|
|
160
|
+
const handle = startXacctCensus({ intervalMs: 1000, windowHours: 1, emit: vi.fn() });
|
|
161
|
+
try {
|
|
162
|
+
expect(handle.hasRef()).toBe(false);
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
clearInterval(handle);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
//# sourceMappingURL=xacct-counters.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xacct-counters.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/xacct-counters.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface XacctWindow {
|
|
2
|
+
/** Write-tool calls that carried a `targetAccountId`. */
|
|
3
|
+
writeCalls: number;
|
|
4
|
+
/** Of those, the ones `resolveToolAccount` authorised. */
|
|
5
|
+
allowed: number;
|
|
6
|
+
/** Of those allowed, the ones that got past the graph-write account gate. */
|
|
7
|
+
gatePassed: number;
|
|
8
|
+
/** Of those allowed, the ones the account gate refused. Healthy = 0. */
|
|
9
|
+
gateRejected: number;
|
|
10
|
+
}
|
|
11
|
+
/** Record a cross-account write-tool call and whether the resolver allowed it. */
|
|
12
|
+
export declare function noteXacctWriteCall(allowed: boolean): void;
|
|
13
|
+
/** Record what the graph-write account gate did with an allowed call. */
|
|
14
|
+
export declare function noteXacctWriteOutcome(gate: "passed" | "rejected"): void;
|
|
15
|
+
export declare function readXacctWindow(): XacctWindow;
|
|
16
|
+
/** Test seam. Production resets happen only on a census emit. */
|
|
17
|
+
export declare function __resetXacctWindow(): void;
|
|
18
|
+
export interface WriteOutcome {
|
|
19
|
+
tool: string;
|
|
20
|
+
/** The calling session's own account. */
|
|
21
|
+
caller: string;
|
|
22
|
+
/** The authorised target account this write was resolved to. */
|
|
23
|
+
target: string;
|
|
24
|
+
/**
|
|
25
|
+
* `rejected` iff the graph-write ACCOUNT gate refused the write. A write that
|
|
26
|
+
* failed for any other reason got past that gate, so it reads `passed` with
|
|
27
|
+
* the failure named in `reason` — conflating the two would hide the one
|
|
28
|
+
* pairing this line exists to catch.
|
|
29
|
+
*/
|
|
30
|
+
gate: "passed" | "rejected";
|
|
31
|
+
/** `null` when the write succeeded. */
|
|
32
|
+
reason: string | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The three names `reason` may take, and nothing else. An operator greps
|
|
36
|
+
* `reason=invalid-account-id`; an error message pasted into the field would
|
|
37
|
+
* carry its own punctuation and account slice and match nothing. The detail of a
|
|
38
|
+
* non-gate failure is already on the `[mcp:memory] … result=error` line for the
|
|
39
|
+
* same call, so nothing is lost by naming it `write-failed` here.
|
|
40
|
+
*/
|
|
41
|
+
export declare function writeOutcomeReason(gate: "passed" | "rejected", failed: boolean): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* The paired line. `caller` and `target` are sliced to 8 characters to match the
|
|
44
|
+
* `[xacct] op=call` line a reader joins this against.
|
|
45
|
+
*/
|
|
46
|
+
export declare function formatWriteOutcome(o: WriteOutcome): string;
|
|
47
|
+
export declare function formatXacctCensus(windowHours: number, w: XacctWindow): string;
|
|
48
|
+
export interface CensusOptions {
|
|
49
|
+
intervalMs?: number;
|
|
50
|
+
windowHours?: number;
|
|
51
|
+
emit?: (line: string) => void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Arm the standing census. The returned handle is unref'd: this runs inside a
|
|
55
|
+
* stdio child of a session, and a referenced timer would keep that child alive
|
|
56
|
+
* after the session it serves has gone.
|
|
57
|
+
*
|
|
58
|
+
* A window with no cross-account calls still emits. Suppressing the zero would
|
|
59
|
+
* make a quiet period and a dead feature look identical, which is the failure
|
|
60
|
+
* this census exists to catch.
|
|
61
|
+
*/
|
|
62
|
+
export declare function startXacctCensus(opts?: CensusOptions): NodeJS.Timeout;
|
|
63
|
+
//# sourceMappingURL=xacct-counters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xacct-counters.d.ts","sourceRoot":"","sources":["../../src/lib/xacct-counters.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;CACtB;AASD,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAGzD;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,IAAI,CAGvE;AAED,wBAAgB,eAAe,IAAI,WAAW,CAE7C;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC;AAWD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,uCAAuC;IACvC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,GAAG,UAAU,EAC3B,MAAM,EAAE,OAAO,GACd,MAAM,GAAG,IAAI,CAMf;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAM1D;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,GAAG,MAAM,CAK7E;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAID;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,aAAkB,GAAG,MAAM,CAAC,OAAO,CAUzE"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-account write observability (Task 2731).
|
|
3
|
+
*
|
|
4
|
+
* Task 1455 authorises a house-scoped session to write into a sub-account
|
|
5
|
+
* subgraph; the graph-write account gate then refused that same write because
|
|
6
|
+
* the stamped account was not the process's own. Both halves were logged, in
|
|
7
|
+
* one file, and nothing reconciled them — so the feature was broken on every
|
|
8
|
+
* account and every install for as long as it existed, while the tool
|
|
9
|
+
* descriptions advertised it.
|
|
10
|
+
*
|
|
11
|
+
* Two signals close that. `formatWriteOutcome` pairs the resolver's decision
|
|
12
|
+
* with the write's fate on one row, so `decision=allow` followed by
|
|
13
|
+
* `gate=rejected` is a single greppable shape rather than two lines a reader
|
|
14
|
+
* has to join. `formatXacctCensus` answers the question a per-call line cannot:
|
|
15
|
+
* whether the capability is being exercised at all, because a feature nobody
|
|
16
|
+
* invokes reads identically to one that works.
|
|
17
|
+
*
|
|
18
|
+
* The counters live here, in the memory MCP child, because that is the process
|
|
19
|
+
* that observes both halves. A census keyed on grepping `server.log` would go
|
|
20
|
+
* blind exactly when the install is busiest — `dispatch-tg-census.ts` documents
|
|
21
|
+
* why. The cost of counting in the child is that the window is per-child: a
|
|
22
|
+
* short session emits no census at all.
|
|
23
|
+
*
|
|
24
|
+
* Only cross-account calls are counted, so `writeCalls=0` means precisely "no
|
|
25
|
+
* session targeted another account this window", not "no writes happened".
|
|
26
|
+
*/
|
|
27
|
+
import { INVALID_ACCOUNT_ID_REASON } from "../../../../../lib/graph-write/dist/index.js";
|
|
28
|
+
const window = {
|
|
29
|
+
writeCalls: 0,
|
|
30
|
+
allowed: 0,
|
|
31
|
+
gatePassed: 0,
|
|
32
|
+
gateRejected: 0,
|
|
33
|
+
};
|
|
34
|
+
/** Record a cross-account write-tool call and whether the resolver allowed it. */
|
|
35
|
+
export function noteXacctWriteCall(allowed) {
|
|
36
|
+
window.writeCalls++;
|
|
37
|
+
if (allowed)
|
|
38
|
+
window.allowed++;
|
|
39
|
+
}
|
|
40
|
+
/** Record what the graph-write account gate did with an allowed call. */
|
|
41
|
+
export function noteXacctWriteOutcome(gate) {
|
|
42
|
+
if (gate === "passed")
|
|
43
|
+
window.gatePassed++;
|
|
44
|
+
else
|
|
45
|
+
window.gateRejected++;
|
|
46
|
+
}
|
|
47
|
+
export function readXacctWindow() {
|
|
48
|
+
return { ...window };
|
|
49
|
+
}
|
|
50
|
+
/** Test seam. Production resets happen only on a census emit. */
|
|
51
|
+
export function __resetXacctWindow() {
|
|
52
|
+
window.writeCalls = 0;
|
|
53
|
+
window.allowed = 0;
|
|
54
|
+
window.gatePassed = 0;
|
|
55
|
+
window.gateRejected = 0;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A log field must never split into two. A reason sourced from an error message
|
|
59
|
+
* can carry spaces, which would shift every field after it and make the line
|
|
60
|
+
* unparseable, so whitespace collapses to a single dash.
|
|
61
|
+
*/
|
|
62
|
+
function field(value) {
|
|
63
|
+
return value.trim().replace(/\s+/g, "-");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The three names `reason` may take, and nothing else. An operator greps
|
|
67
|
+
* `reason=invalid-account-id`; an error message pasted into the field would
|
|
68
|
+
* carry its own punctuation and account slice and match nothing. The detail of a
|
|
69
|
+
* non-gate failure is already on the `[mcp:memory] … result=error` line for the
|
|
70
|
+
* same call, so nothing is lost by naming it `write-failed` here.
|
|
71
|
+
*/
|
|
72
|
+
export function writeOutcomeReason(gate, failed) {
|
|
73
|
+
if (!failed)
|
|
74
|
+
return null;
|
|
75
|
+
// Imported, never spelled out again: the operator's grep and the chokepoint's
|
|
76
|
+
// own reason code must be the same string, and a second literal would let
|
|
77
|
+
// them drift silently.
|
|
78
|
+
return gate === "rejected" ? INVALID_ACCOUNT_ID_REASON : "write-failed";
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The paired line. `caller` and `target` are sliced to 8 characters to match the
|
|
82
|
+
* `[xacct] op=call` line a reader joins this against.
|
|
83
|
+
*/
|
|
84
|
+
export function formatWriteOutcome(o) {
|
|
85
|
+
return (`[xacct] op=write-outcome tool=${field(o.tool)} caller=${o.caller.slice(0, 8)} ` +
|
|
86
|
+
`target=${o.target.slice(0, 8)} gate=${o.gate} ` +
|
|
87
|
+
`reason=${o.reason === null ? "none" : field(o.reason)}\n`);
|
|
88
|
+
}
|
|
89
|
+
export function formatXacctCensus(windowHours, w) {
|
|
90
|
+
return (`[xacct-census] window=${windowHours} writeCalls=${w.writeCalls} ` +
|
|
91
|
+
`allowed=${w.allowed} gatePassed=${w.gatePassed} gateRejected=${w.gateRejected}\n`);
|
|
92
|
+
}
|
|
93
|
+
const HOUR_MS = 60 * 60 * 1000;
|
|
94
|
+
/**
|
|
95
|
+
* Arm the standing census. The returned handle is unref'd: this runs inside a
|
|
96
|
+
* stdio child of a session, and a referenced timer would keep that child alive
|
|
97
|
+
* after the session it serves has gone.
|
|
98
|
+
*
|
|
99
|
+
* A window with no cross-account calls still emits. Suppressing the zero would
|
|
100
|
+
* make a quiet period and a dead feature look identical, which is the failure
|
|
101
|
+
* this census exists to catch.
|
|
102
|
+
*/
|
|
103
|
+
export function startXacctCensus(opts = {}) {
|
|
104
|
+
const intervalMs = opts.intervalMs ?? HOUR_MS;
|
|
105
|
+
const windowHours = opts.windowHours ?? intervalMs / HOUR_MS;
|
|
106
|
+
const emit = opts.emit ?? ((line) => void process.stderr.write(line));
|
|
107
|
+
const handle = setInterval(() => {
|
|
108
|
+
emit(formatXacctCensus(windowHours, readXacctWindow()));
|
|
109
|
+
__resetXacctWindow();
|
|
110
|
+
}, intervalMs);
|
|
111
|
+
handle.unref();
|
|
112
|
+
return handle;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=xacct-counters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xacct-counters.js","sourceRoot":"","sources":["../../src/lib/xacct-counters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-write-cross-account.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-write-cross-account.test.ts"],"names":[],"mappings":""}
|
package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-cross-account.test.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Task 2731 — a house-scoped session writing into an authorised sub-account.
|
|
2
|
+
//
|
|
3
|
+
// The graph-write account gate runs for real here. Only Neo4j and the embedder
|
|
4
|
+
// are stubbed, so the test exercises the same chain the defect lived on:
|
|
5
|
+
// `memoryWrite` receives the account `resolveToolAccount` authorised, stamps it
|
|
6
|
+
// on the node, and hands it to the chokepoint as `expectedAccountId`. Before
|
|
7
|
+
// this task the last step was missing, the chokepoint fell back to
|
|
8
|
+
// `process.env.ACCOUNT_ID` (the house account), and every cross-account write
|
|
9
|
+
// was allowed by the resolver and then refused by the chokepoint.
|
|
10
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
11
|
+
const HOUSE_ACCOUNT = "20028fb5-db26-4de7-bff6-c5ec2d4fc766";
|
|
12
|
+
const SUB_ACCOUNT = "8a160746-1111-2222-3333-444444444444";
|
|
13
|
+
const TARGET_NODE = "target-element-id";
|
|
14
|
+
let createdProps = null;
|
|
15
|
+
function rec(map) {
|
|
16
|
+
return { get: (k) => map[k] };
|
|
17
|
+
}
|
|
18
|
+
/** Resolves the edge-target pre-check, the node CREATE, and the edge CREATE. */
|
|
19
|
+
function makeStubSession() {
|
|
20
|
+
const tx = {
|
|
21
|
+
run: vi.fn(async (cypher, params = {}) => {
|
|
22
|
+
if (cypher.includes("RETURN elementId(t) AS id, labels(t) AS labels")) {
|
|
23
|
+
const ids = params.ids ?? [];
|
|
24
|
+
return { records: ids.filter((id) => id === TARGET_NODE).map((id) => rec({ id, labels: ["Person"] })) };
|
|
25
|
+
}
|
|
26
|
+
if (cypher.includes("CREATE (n:")) {
|
|
27
|
+
createdProps = params.props;
|
|
28
|
+
return { records: [rec({ nodeId: "new-node-id", nodeLabels: ["Person"] })] };
|
|
29
|
+
}
|
|
30
|
+
return { summary: { counters: { updates: () => ({ relationshipsCreated: 1 }) } } };
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
run: vi.fn(async () => ({ records: [] })),
|
|
35
|
+
close: vi.fn(async () => undefined),
|
|
36
|
+
executeWrite: async (work) => work(tx),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
vi.mock("../../lib/neo4j.js", () => ({ getSession: () => makeStubSession() }));
|
|
40
|
+
vi.mock("../../lib/embeddings.js", () => ({ embed: async () => [0.1, 0.2, 0.3] }));
|
|
41
|
+
const { memoryWrite } = await import("../memory-write.js");
|
|
42
|
+
const PERSON = new Set(["Person"]);
|
|
43
|
+
// The smallest validator env that lets a `Person` write through: `Person` is
|
|
44
|
+
// recognised, nothing is a synonym, nothing is forbidden, nothing is required.
|
|
45
|
+
// Schema rules are not what this test is about.
|
|
46
|
+
const VALIDATOR = {
|
|
47
|
+
schema: {
|
|
48
|
+
markdownLabels: new Map(),
|
|
49
|
+
wrongToCorrect: new Map(),
|
|
50
|
+
forbiddenByLabel: new Map(),
|
|
51
|
+
documentedCanonicals: [],
|
|
52
|
+
sourceFiles: ["schema-base.md"],
|
|
53
|
+
brandVertical: null,
|
|
54
|
+
relationshipPatterns: [],
|
|
55
|
+
},
|
|
56
|
+
liveSource: {
|
|
57
|
+
liveLabels: () => PERSON,
|
|
58
|
+
declaredLabels: () => PERSON,
|
|
59
|
+
recognisedLabels: () => PERSON,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
const RELATIONSHIPS = [
|
|
63
|
+
{ type: "KNOWS", direction: "outgoing", targetNodeId: TARGET_NODE },
|
|
64
|
+
];
|
|
65
|
+
function write(accountId) {
|
|
66
|
+
return memoryWrite({
|
|
67
|
+
labels: ["Person"],
|
|
68
|
+
properties: { name: "Ada Lovelace" },
|
|
69
|
+
accountId,
|
|
70
|
+
scope: "admin",
|
|
71
|
+
relationships: RELATIONSHIPS,
|
|
72
|
+
createdBy: { agent: "test-agent", session: "s1", tool: "memory-write" },
|
|
73
|
+
validator: VALIDATOR,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
describe("memory-write cross-account gate (Task 2731)", () => {
|
|
77
|
+
let originalAccountId;
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
createdProps = null;
|
|
80
|
+
originalAccountId = process.env.ACCOUNT_ID;
|
|
81
|
+
// The spawning process is the house account, as it is on every real
|
|
82
|
+
// cross-account call: the sub-account never spawns this child.
|
|
83
|
+
process.env.ACCOUNT_ID = HOUSE_ACCOUNT;
|
|
84
|
+
});
|
|
85
|
+
afterEach(() => {
|
|
86
|
+
if (originalAccountId === undefined)
|
|
87
|
+
delete process.env.ACCOUNT_ID;
|
|
88
|
+
else
|
|
89
|
+
process.env.ACCOUNT_ID = originalAccountId;
|
|
90
|
+
});
|
|
91
|
+
it("writes to an authorised sub-account and stamps that account", async () => {
|
|
92
|
+
const result = await write(SUB_ACCOUNT);
|
|
93
|
+
expect(result.nodeId).toBe("new-node-id");
|
|
94
|
+
expect(createdProps?.accountId).toBe(SUB_ACCOUNT);
|
|
95
|
+
});
|
|
96
|
+
it("still writes own-account when the resolver returned the house account", async () => {
|
|
97
|
+
const result = await write(HOUSE_ACCOUNT);
|
|
98
|
+
expect(result.nodeId).toBe("new-node-id");
|
|
99
|
+
expect(createdProps?.accountId).toBe(HOUSE_ACCOUNT);
|
|
100
|
+
});
|
|
101
|
+
it("ignores an operator-supplied accountId in the properties bag", async () => {
|
|
102
|
+
// `memoryWrite` overwrites `properties.accountId` with the authorised
|
|
103
|
+
// account, so a caller cannot smuggle a different account past the
|
|
104
|
+
// chokepoint by putting it in the bag. This is also why the red-green
|
|
105
|
+
// anchor for the gate itself lives in the graph-write suite
|
|
106
|
+
// (`account-id-gate.test.ts`) rather than here: inside `memoryWrite` the
|
|
107
|
+
// stamped account and `expectedAccountId` are the same variable, and an
|
|
108
|
+
// empty one is refused by schema validation before any write, so the two
|
|
109
|
+
// can never disagree at this layer.
|
|
110
|
+
const result = await memoryWrite({
|
|
111
|
+
labels: ["Person"],
|
|
112
|
+
properties: { name: "Ada Lovelace", accountId: "ffffffff-9999-9999-9999-999999999999" },
|
|
113
|
+
accountId: SUB_ACCOUNT,
|
|
114
|
+
scope: "admin",
|
|
115
|
+
relationships: RELATIONSHIPS,
|
|
116
|
+
createdBy: { agent: "test-agent", session: "s1", tool: "memory-write" },
|
|
117
|
+
validator: VALIDATOR,
|
|
118
|
+
});
|
|
119
|
+
expect(result.nodeId).toBe("new-node-id");
|
|
120
|
+
expect(createdProps?.accountId).toBe(SUB_ACCOUNT);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
//# sourceMappingURL=memory-write-cross-account.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-write-cross-account.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/memory-write-cross-account.test.ts"],"names":[],"mappings":"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"}
|
package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/xacct-write-gate.test.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xacct-write-gate.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/xacct-write-gate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { resolve, dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
// Task 2731 — the audit that stops this defect recurring.
|
|
6
|
+
//
|
|
7
|
+
// Task 1455 lets a house-scoped session resolve a sub-account target, and
|
|
8
|
+
// `resolveToolAccount` returns that authorised account. `writeNodeWithEdges`
|
|
9
|
+
// then compares the stamped `accountId` against `process.env.ACCOUNT_ID` unless
|
|
10
|
+
// the caller supplies `expectedAccountId`. A call site that omits it therefore
|
|
11
|
+
// gets `decision=allow` from the resolver and `reason=invalid-account-id` from
|
|
12
|
+
// the gate, one for one, inside a single process — which is how every
|
|
13
|
+
// cross-account memory write failed from Task 1455 until this fix.
|
|
14
|
+
//
|
|
15
|
+
// The guard is static because the failure is a missing argument, not a wrong
|
|
16
|
+
// value: a behavioural test only sees it on the cross-account path, which is
|
|
17
|
+
// exactly the path nobody exercised for the months the defect lived.
|
|
18
|
+
const SRC = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
19
|
+
/** Every `.ts` under `src/`, excluding test files and compiled output. */
|
|
20
|
+
function sourceFiles(dir) {
|
|
21
|
+
const out = [];
|
|
22
|
+
for (const entry of readdirSync(dir)) {
|
|
23
|
+
const full = join(dir, entry);
|
|
24
|
+
if (statSync(full).isDirectory()) {
|
|
25
|
+
if (entry === "__tests__" || entry === "dist" || entry === "node_modules")
|
|
26
|
+
continue;
|
|
27
|
+
out.push(...sourceFiles(full));
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (entry.endsWith(".ts") && !entry.endsWith(".test.ts"))
|
|
31
|
+
out.push(full);
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The argument list of every `writeNodeWithEdges({ ... })` call in `src`, as
|
|
37
|
+
* `{ file, args }`. The call is always written as a single object literal, so
|
|
38
|
+
* the extent is found by counting braces from the opening `{` — no parser, and
|
|
39
|
+
* no line-window heuristic that a longer call would silently outgrow.
|
|
40
|
+
*/
|
|
41
|
+
function writeCallSites() {
|
|
42
|
+
const sites = [];
|
|
43
|
+
for (const file of sourceFiles(SRC)) {
|
|
44
|
+
const src = readFileSync(file, "utf8");
|
|
45
|
+
const needle = "writeNodeWithEdges({";
|
|
46
|
+
let from = 0;
|
|
47
|
+
for (;;) {
|
|
48
|
+
const at = src.indexOf(needle, from);
|
|
49
|
+
if (at === -1)
|
|
50
|
+
break;
|
|
51
|
+
let depth = 0;
|
|
52
|
+
let end = at + needle.length - 1;
|
|
53
|
+
for (let i = end; i < src.length; i++) {
|
|
54
|
+
if (src[i] === "{")
|
|
55
|
+
depth++;
|
|
56
|
+
else if (src[i] === "}") {
|
|
57
|
+
depth--;
|
|
58
|
+
if (depth === 0) {
|
|
59
|
+
end = i;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
sites.push({ file, args: src.slice(at, end + 1) });
|
|
65
|
+
from = at + needle.length;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return sites;
|
|
69
|
+
}
|
|
70
|
+
/** Every `writeNodeWithEdges(` invocation, whatever the argument's formatting. */
|
|
71
|
+
function totalInvocations() {
|
|
72
|
+
let n = 0;
|
|
73
|
+
for (const file of sourceFiles(SRC)) {
|
|
74
|
+
// The import binding is not an invocation.
|
|
75
|
+
n += (readFileSync(file, "utf8").match(/writeNodeWithEdges\(/g) ?? []).length;
|
|
76
|
+
}
|
|
77
|
+
return n;
|
|
78
|
+
}
|
|
79
|
+
describe("cross-account write gate (Task 2731)", () => {
|
|
80
|
+
it("finds the memory plugin's writeNodeWithEdges call sites", () => {
|
|
81
|
+
// A zero-site pass would make every assertion below vacuous: the guard
|
|
82
|
+
// could not tell "all call sites are correct" from "the call moved and this
|
|
83
|
+
// test stopped measuring anything".
|
|
84
|
+
expect(writeCallSites().length).toBeGreaterThan(0);
|
|
85
|
+
});
|
|
86
|
+
it("matches every invocation, so no call site can slip past unmeasured", () => {
|
|
87
|
+
// The extent scan keys on `writeNodeWithEdges({`. A call formatted with a
|
|
88
|
+
// line break before the brace would not match, and the assertions below
|
|
89
|
+
// would quietly stop covering it — the exact silent-gap failure this guard
|
|
90
|
+
// exists to prevent. Counting invocations independently turns that into a
|
|
91
|
+
// failure instead.
|
|
92
|
+
expect(writeCallSites().length).toBe(totalInvocations());
|
|
93
|
+
});
|
|
94
|
+
it("passes expectedAccountId at every writeNodeWithEdges call site", () => {
|
|
95
|
+
const missing = writeCallSites()
|
|
96
|
+
.filter((s) => !/\bexpectedAccountId\s*:/.test(s.args))
|
|
97
|
+
.map((s) => s.file.slice(SRC.length + 1));
|
|
98
|
+
expect(missing).toEqual([]);
|
|
99
|
+
});
|
|
100
|
+
it("passes the resolved account, never the process env, as expectedAccountId", () => {
|
|
101
|
+
// `process.env.ACCOUNT_ID` is the house account on a cross-account call.
|
|
102
|
+
// Passing it explicitly would restore the exact defect while satisfying the
|
|
103
|
+
// presence check above.
|
|
104
|
+
const wrong = writeCallSites()
|
|
105
|
+
.filter((s) => /expectedAccountId\s*:\s*process\.env/.test(s.args))
|
|
106
|
+
.map((s) => s.file.slice(SRC.length + 1));
|
|
107
|
+
expect(wrong).toEqual([]);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=xacct-write-gate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xacct-write-gate.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/xacct-write-gate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-write.d.ts","sourceRoot":"","sources":["../../src/tools/memory-write.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAoB9E,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACf,MAAM,8CAA8C,CAAC;AAEtD,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6HAA6H;IAC7H,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,+EAA+E;IAC/E,SAAS,EAAE,SAAS,CAAC;IACrB;;;;;;OAMG;IACH,SAAS,EAAE,YAAY,CAAC;IACxB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AA+CD,wBAAsB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAS3E;
|
|
1
|
+
{"version":3,"file":"memory-write.d.ts","sourceRoot":"","sources":["../../src/tools/memory-write.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAoB9E,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACf,MAAM,8CAA8C,CAAC;AAEtD,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6HAA6H;IAC7H,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,+EAA+E;IAC/E,SAAS,EAAE,SAAS,CAAC;IACrB;;;;;;OAMG;IACH,SAAS,EAAE,YAAY,CAAC;IACxB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AA+CD,wBAAsB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAS3E;AAmYD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EAAE,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAYR"}
|