🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@sleep2agi/commhub-server

Package Overview
Dependencies
Maintainers
1
Versions
91
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sleep2agi/commhub-server - npm Package Compare versions

Comparing version
0.9.0-preview.12
to
0.9.0-preview.13
+2
-2
package.json
{
"name": "@sleep2agi/commhub-server",
"version": "0.9.0-preview.12",
"description": "CommHub Server \u2014 AI Agent communication hub with MCP protocol, multi-network isolation, user auth, and 17 MCP tools.",
"version": "0.9.0-preview.13",
"description": "CommHub Server — AI Agent communication hub with MCP protocol, multi-network isolation, user auth, and 17 MCP tools.",
"type": "module",

@@ -6,0 +6,0 @@ "main": "src/index.ts",

@@ -315,1 +315,67 @@ // #221 — unit tests for the upload primitives. The HTTP wire-up + Bun

});
import { stripHostLocalPathsForCrossHostSafe } from "./uploads";
describe("stripHostLocalPathsForCrossHostSafe (#222 cross-host attachment safety)", () => {
test("strips path when file_id is present (cross-host safe — agent will fetch via /api/files/<id>)", () => {
const meta = {
attachments: [
{ type: "file", file_id: "abc12345", path: "/home/hub/uploads/abc12345.png", mime: "image/png" },
],
otherKey: "preserved",
};
const out = stripHostLocalPathsForCrossHostSafe(meta);
expect(out.attachments[0]).toEqual({ type: "file", file_id: "abc12345", mime: "image/png" });
expect(out.attachments[0].path).toBeUndefined();
expect(out.otherKey).toBe("preserved");
});
test("PRESERVES path when file_id is absent (feishu single-host fallback)", () => {
// 🔴 通信龙 PR #222 pre-review nit — feishu-bridge ships path-only
// attachments (writes /work/feishu-attachments/...). If we strip
// unconditionally those break too. Lock the conditional contract.
const meta = {
attachments: [
{ type: "file", path: "/work/feishu-attachments/feishu-local/oc_xxx/img.jpg", mime: "image/jpeg" },
],
};
const out = stripHostLocalPathsForCrossHostSafe(meta);
expect(out.attachments[0].path).toBe("/work/feishu-attachments/feishu-local/oc_xxx/img.jpg");
expect(out.attachments[0].file_id).toBeUndefined();
});
test("mixed array: strips path on entries with file_id, preserves on path-only entries", () => {
const meta = {
attachments: [
{ type: "file", file_id: "id1xxxxx", path: "/hub/local/id1.png", mime: "image/png" },
{ type: "file", path: "/work/feishu-attachments/x.jpg", mime: "image/jpeg" },
{ type: "file", file_id: "id2yyyyy", mime: "image/gif" }, // already path-free
],
};
const out = stripHostLocalPathsForCrossHostSafe(meta);
expect(out.attachments[0]).toEqual({ type: "file", file_id: "id1xxxxx", mime: "image/png" });
expect(out.attachments[1]).toEqual({ type: "file", path: "/work/feishu-attachments/x.jpg", mime: "image/jpeg" });
expect(out.attachments[2]).toEqual({ type: "file", file_id: "id2yyyyy", mime: "image/gif" });
});
test("no-op when meta has no attachments array", () => {
const meta = { something: "else" };
expect(stripHostLocalPathsForCrossHostSafe(meta)).toBe(meta);
});
test("no-op when nothing to strip (returns SAME object reference, not a copy)", () => {
const meta = { attachments: [{ type: "file", file_id: "x12345xx", mime: "image/png" }] };
expect(stripHostLocalPathsForCrossHostSafe(meta)).toBe(meta);
});
test("handles null / non-object meta gracefully", () => {
expect(stripHostLocalPathsForCrossHostSafe(null)).toBe(null);
expect(stripHostLocalPathsForCrossHostSafe(undefined as any)).toBe(undefined);
expect(stripHostLocalPathsForCrossHostSafe("string" as any)).toBe("string");
});
test("handles non-array attachments field gracefully", () => {
const meta = { attachments: "not-an-array" };
expect(stripHostLocalPathsForCrossHostSafe(meta)).toBe(meta);
});
});

@@ -244,2 +244,38 @@ // #221 — commhub-server file upload primitives.

/**
* #222 cross-host attachment safety — strip `path` from meta.attachments
* entries that ALSO carry a `file_id`. Reason: the hub's /api/upload
* returns `{file_id, path}` where `path` is a hub-machine-local
* absolute path. Senders sometimes echo `path` back into meta.attachments.
* When the receiving agent runs on a different host (Vincent 2026-06-30
* toodadev2 case), that path string is meaningless. agent-node's
* fetch-attachment.ts will fetch via `file_id` regardless, but leaving
* the stale `path` in the JSON misleads any tooling that reads it.
*
* CRITICAL — conditional, not unconditional (通信龙 PR #222 pre-review
* nit): feishu-bridge currently writes `/work/feishu-attachments/<conn>/
* <chat>/` directly and ships path-only attachments (NO file_id). If we
* strip path unconditionally those break too. Only strip when file_id
* is present (the "safe to drop" signal). Single-host feishu fallback
* preserved.
*
* Shared by tools.ts (MCP send_task) and index.ts (REST /api/task) so
* both transports apply the same sanitization to meta.
*/
export function stripHostLocalPathsForCrossHostSafe(meta: any): any {
if (!meta || typeof meta !== "object") return meta;
if (!Array.isArray((meta as any).attachments)) return meta;
let mutated = false;
const sanitized = (meta as any).attachments.map((a: any) => {
if (a && typeof a === "object" && typeof a.file_id === "string" && a.file_id && typeof a.path === "string") {
mutated = true;
const { path: _stripped, ...rest } = a;
return rest;
}
return a;
});
if (!mutated) return meta;
return { ...meta, attachments: sanitized };
}
/** Light validator usable from the REST handler. Returns null on success or an error message string. */

@@ -246,0 +282,0 @@ export function validateAttachments(input: unknown): { ok: true; attachments: TaskAttachment[] } | { ok: false; error: string } {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display