c229b4b79b
An admin/analyst's pet counted every user's sessions (live, waiting, errors) because their WebSocket carries everyone's. Server mode now marks their session/agent/event frames `mine: true|false` (scope.broadcastAudience owners, worked out once per broadcast), and GET /api/sessions?mine=1 lists only the caller's own sessions (ownSessionWhere). The pet seeds from mine=1 and skips frames marked mine: false. Developers and local mode are unchanged.
103 lines
3.5 KiB
JavaScript
103 lines
3.5 KiB
JavaScript
/**
|
|
* @file websocket-mine.test.js
|
|
* @description Server mode broadcasts (server/websocket.js `broadcast`): an
|
|
* admin/analyst's session, agent and event frames say whether the session is
|
|
* their OWN (`mine`), a developer's and local mode's never carry it, and
|
|
* `GET /api/sessions?mine=1` (server/routes/sessions.js) lists only the
|
|
* caller's own sessions whatever their role — the pet counts only those.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
const { describe, it, before, after } = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const path = require("node:path");
|
|
const fs = require("node:fs");
|
|
const os = require("node:os");
|
|
|
|
const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "ws-mine-test-"));
|
|
process.env.DASHBOARD_DB_PATH = path.join(TMP, "dashboard.db");
|
|
|
|
const { db } = require("../db");
|
|
const ws = require("../websocket");
|
|
|
|
const prevMode = process.env.AGENTHUB_MODE;
|
|
before(() => {
|
|
const lane = db.prepare("INSERT INTO lanes (cwd, tool, owner_id) VALUES (?, 'claude', ?)");
|
|
lane.run("/w/boss", 99); // id 1, the admin's
|
|
lane.run("/w/dev", 2); // id 2, a developer's
|
|
const s = db.prepare(
|
|
"INSERT INTO sessions (id, name, status, cwd, lane_id) VALUES (?, ?, 'active', '/w', ?)"
|
|
);
|
|
s.run("s-boss", "boss", 1);
|
|
s.run("s-dev", "dev", 2);
|
|
});
|
|
|
|
after(() => {
|
|
ws._setClientsForTest(null);
|
|
if (prevMode === undefined) delete process.env.AGENTHUB_MODE;
|
|
else process.env.AGENTHUB_MODE = prevMode;
|
|
fs.rmSync(TMP, { recursive: true, force: true });
|
|
});
|
|
|
|
function client(user) {
|
|
const got = [];
|
|
return { readyState: 1, user, got, send: (m) => got.push(JSON.parse(m)) };
|
|
}
|
|
|
|
describe("broadcast `mine`", () => {
|
|
it("marks an admin's frames by whose session it is; a developer gets only theirs, unmarked", () => {
|
|
process.env.AGENTHUB_MODE = "server";
|
|
const boss = client({ id: 99, username: "boss", role: "admin" });
|
|
const dev = client({ id: 2, username: "dev", role: "developer" });
|
|
ws._setClientsForTest(new Set([boss, dev]));
|
|
ws.broadcast("session_updated", { id: "s-boss", status: "active" });
|
|
ws.broadcast("new_event", { session_id: "s-dev", event_type: "PostToolUse" });
|
|
ws.broadcast("lane_update", { lane: { id: 2 } });
|
|
assert.deepEqual(
|
|
boss.got.map((m) => [m.type, m.mine]),
|
|
[
|
|
["session_updated", true],
|
|
["new_event", false],
|
|
["lane_update", undefined],
|
|
]
|
|
);
|
|
assert.deepEqual(
|
|
dev.got.map((m) => [m.type, m.mine]),
|
|
[
|
|
["new_event", undefined],
|
|
["lane_update", undefined],
|
|
]
|
|
);
|
|
});
|
|
|
|
it("adds nothing in local mode", () => {
|
|
delete process.env.AGENTHUB_MODE;
|
|
const me = client(null);
|
|
ws._setClientsForTest(new Set([me]));
|
|
ws.broadcast("session_updated", { id: "s-dev" });
|
|
assert.equal(me.got[0].mine, undefined);
|
|
});
|
|
});
|
|
|
|
describe("GET /api/sessions?mine=1", () => {
|
|
it("lists only the caller's own sessions, an admin's too", async () => {
|
|
const express = require("express");
|
|
const app = express();
|
|
app.use((req, _res, next) => {
|
|
req.user = { id: 99, username: "boss", role: "admin" };
|
|
next();
|
|
});
|
|
app.use("/api/sessions", require("../routes/sessions"));
|
|
const srv = app.listen(0);
|
|
try {
|
|
const base = `http://127.0.0.1:${srv.address().port}/api/sessions`;
|
|
const ids = async (qs) =>
|
|
(await (await fetch(base + qs)).json()).sessions.map((s) => s.id).sort();
|
|
assert.deepEqual(await ids("?mine=1"), ["s-boss"]);
|
|
assert.deepEqual(await ids(""), ["s-boss", "s-dev"]);
|
|
} finally {
|
|
srv.close();
|
|
}
|
|
});
|
|
});
|