feat(cli): 1.29.0 — per-session IPC tokens + auto-scoping
every claudemesh launch-spawned session now mints a 32-byte random token, writes it under tmpdir (mode 0600), and registers it with the daemon. cli invocations from inside that session inherit CLAUDEMESH_IPC_TOKEN_FILE in env, attach the token via Authorization: ClaudeMesh-Session <hex>, and the daemon resolves it to a SessionInfo. server-side: every read route that filters by mesh now uses meshFromCtx — explicit query/body wins, session default fills in when missing. write routes follow the same pattern. cli-side: peers.ts (and other multi-mesh-iterating verbs in future) prefers session-token mesh over all joined meshes when the user didn't pass --mesh explicitly. backward-compatible in both directions — tokenless callers behave exactly as before. registry is in-memory; daemon restart loses it but the 30s reaper handles dead pids and most callers re-register on next launch. verified end-to-end: peer list with token returns 4 prueba1 peers, without token returns 3 meshes' peers (aggregate). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { request as httpRequest } from "node:http";
|
||||
|
||||
import { DAEMON_PATHS, DAEMON_TCP_HOST, DAEMON_TCP_DEFAULT_PORT } from "../paths.js";
|
||||
import { readLocalToken } from "../local-token.js";
|
||||
import { readSessionTokenFromEnv } from "~/services/session/token.js";
|
||||
|
||||
export interface IpcRequestOptions {
|
||||
method?: "GET" | "POST" | "PATCH" | "DELETE";
|
||||
@@ -44,6 +45,19 @@ export async function ipc<T = unknown>(opts: IpcRequestOptions): Promise<IpcResp
|
||||
headers.authorization = `Bearer ${tok}`;
|
||||
}
|
||||
|
||||
// Per-session token attribution. When the calling process has
|
||||
// CLAUDEMESH_IPC_TOKEN_FILE set (a launched session and its
|
||||
// descendants), attach the session token. The daemon's auth
|
||||
// middleware resolves it to a SessionInfo and uses it for default-
|
||||
// mesh scoping. Sent as a second Authorization header is not
|
||||
// possible per HTTP semantics, so we layer: when both UDS and a
|
||||
// session token exist, send the session token; the bearer remains
|
||||
// only for TCP loopback callers.
|
||||
if (!useTcp) {
|
||||
const sessionTok = readSessionTokenFromEnv();
|
||||
if (sessionTok) headers.authorization = `ClaudeMesh-Session ${sessionTok}`;
|
||||
}
|
||||
|
||||
return new Promise<IpcResponse<T>>((resolve, reject) => {
|
||||
const req = httpRequest(
|
||||
useTcp
|
||||
|
||||
Reference in New Issue
Block a user