From 0d05cfaf5e436b9d54617e811481ff491698941d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?andr=C3=A9s=20gonz=C3=A1lez?= Date: Wed, 11 Nov 2026 16:18:15 +0100 Subject: [PATCH] :sparkles: Add the file to plugin and MCP audit events (#12972) * :sparkles: Add the file and MCP session to plugin audit events Events sent by plugins and the MCP plugin only carried their origin, so the multi-file and dashboard MCP workflows could not be measured, nor duplicated events from several open tabs spotted. The context of se/event and se/add-event now carries the file-id of the file the action ran in (absent on the dashboard) and, for the MCP, the mcp-session-id of the tab connection that ran it. Closes #12902 AI-assisted-by: claude-opus-5-5 * :recycle: Drop the MCP session id from plugin audit events Every audit event already carries the session-id of the tab in its context, and the MCP session id is only a hash of it, so it adds nothing to group events by tab. AI-assisted-by: claude-opus-5-5 * :bug: Use a reified event in the system events test ptk/data-event does not implement IWithMeta, so add-event failed on it. Plugin actions emit reified events, which carry metadata. AI-assisted-by: claude-opus-5-5 --- frontend/src/app/plugins/system_events.cljs | 48 +++++++++-------- .../plugins/system_events_test.cljs | 52 +++++++++++++++++++ frontend/test/frontend_tests/runner.cljs | 2 + 3 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 frontend/test/frontend_tests/plugins/system_events_test.cljs diff --git a/frontend/src/app/plugins/system_events.cljs b/frontend/src/app/plugins/system_events.cljs index 716852d152..99d163e768 100644 --- a/frontend/src/app/plugins/system_events.cljs +++ b/frontend/src/app/plugins/system_events.cljs @@ -10,31 +10,35 @@ [app.main.store :as st] [app.plugins.register :as r])) +(defn- get-origin + [plugin-id] + (if (= plugin-id r/mcp-plugin-id) "mcp" "plugin")) + +(defn- get-context + "Returns the audit context of an action run by a plugin: the file it ran + in (none on the dashboard) and, for plugins other than the MCP, the + plugin name and URL. Events drop the nil values." + [state plugin-id] + (let [file-id (:current-file-id state)] + (if (= plugin-id r/mcp-plugin-id) + {:file-id file-id} + (let [plugin-data (r/get-plugin-data state plugin-id)] + {:file-id file-id + :plugin-name (:name plugin-data) + :plugin-url (:url plugin-data)})))) + ;; Formats an event from the plugin system (defn event [plugin-id name & {:as props}] - (if (= plugin-id r/mcp-plugin-id) - (-> props - (assoc ::ev/name name) - (assoc ::ev/origin "mcp") - (ev/event)) - - (let [plugin-data (r/get-plugin-data @st/state plugin-id)] - (-> props - (assoc ::ev/name name) - (assoc ::ev/origin "plugin") - (assoc ::ev/context - {:plugin-name (:name plugin-data) - :plugin-url (:url plugin-data)}) - (ev/event))))) + (-> props + (assoc ::ev/name name) + (assoc ::ev/origin (get-origin plugin-id)) + (assoc ::ev/context (get-context @st/state plugin-id)) + (ev/event))) (defn add-event [event plugin-id] - (let [plugin-data (r/get-plugin-data @st/state plugin-id)] - (with-meta - event - (if (= plugin-id r/mcp-plugin-id) - {::ev/origin "mcp"} - {::ev/origin "plugin" - ::ev/context {:plugin-name (:name plugin-data) - :plugin-url (:url plugin-data)}})))) + (with-meta + event + {::ev/origin (get-origin plugin-id) + ::ev/context (get-context @st/state plugin-id)})) diff --git a/frontend/test/frontend_tests/plugins/system_events_test.cljs b/frontend/test/frontend_tests/plugins/system_events_test.cljs new file mode 100644 index 0000000000..302a566f9c --- /dev/null +++ b/frontend/test/frontend_tests/plugins/system_events_test.cljs @@ -0,0 +1,52 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS SUBSIDIARY SL + +(ns frontend-tests.plugins.system-events-test + (:require + [app.main.data.event :as ev] + [app.main.store :as st] + [app.plugins.register :as r] + [app.plugins.system-events :as se] + [cljs.test :as t :include-macros true] + [potok.v2.core :as ptk])) + +(def ^:private plugin-id "00000000-0000-0000-0000-000000000000") + +(defn- set-state + [file-id] + (set! st/state + (atom {:current-file-id file-id + :profile {:props {:plugins {:data {plugin-id {:name "Plugin" + :url "https://plugin.test"}}}}}}))) + +(t/deftest mcp-event-carries-file + (let [file-id (random-uuid)] + (set-state file-id) + (let [data (deref (se/event r/mcp-plugin-id "create-version" :file-id file-id))] + (t/is (= "mcp" (::ev/origin data))) + (t/is (= {:file-id file-id} (::ev/context data))) + (t/is (= file-id (:file-id data)))))) + +(t/deftest plugin-event-carries-file-and-plugin + (let [file-id (random-uuid)] + (set-state file-id) + (t/is (= {:file-id file-id + :plugin-name "Plugin" + :plugin-url "https://plugin.test"} + (::ev/context (deref (se/event plugin-id "add-flow"))))))) + +(t/deftest mcp-add-event-carries-file + (let [file-id (random-uuid)] + (set-state file-id) + (t/is (= {::ev/origin "mcp" + ::ev/context {:file-id file-id}} + (meta (se/add-event (ptk/reify ::test) r/mcp-plugin-id)))))) + +(t/deftest event-has-no-file-on-the-dashboard + (set-state nil) + (t/is (nil? (-> (deref (se/event r/mcp-plugin-id "create-project")) + ::ev/context + :file-id)))) diff --git a/frontend/test/frontend_tests/runner.cljs b/frontend/test/frontend_tests/runner.cljs index 135797b7f5..b0f699a220 100644 --- a/frontend/test/frontend_tests/runner.cljs +++ b/frontend/test/frontend_tests/runner.cljs @@ -101,6 +101,7 @@ [frontend-tests.plugins.read-only-test] [frontend-tests.plugins.register-test] [frontend-tests.plugins.shape-bugfixes-test] + [frontend-tests.plugins.system-events-test] [frontend-tests.plugins.text-test] [frontend-tests.plugins.tokens-test] [frontend-tests.plugins.user-test] @@ -301,6 +302,7 @@ 'frontend-tests.plugins.read-only-test 'frontend-tests.plugins.register-test 'frontend-tests.plugins.shape-bugfixes-test + 'frontend-tests.plugins.system-events-test 'frontend-tests.plugins.text-test 'frontend-tests.plugins.tokens-test 'frontend-tests.plugins.user-test