@sema-agent/server 1.283.0 → 1.284.0
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/dist/http/server.js +15 -3
- package/dist/security.d.ts +4 -0
- package/dist/security.js +3 -2
- package/package.json +1 -1
package/dist/http/server.js
CHANGED
|
@@ -5,7 +5,7 @@ import { sessionLogDigest, sessionLogDigestsComparable, uuidv7, callKeyOrdinal,
|
|
|
5
5
|
import { decideParkedAgent, findParkedAgentForCheckpoint } from "../parked-decide.js";
|
|
6
6
|
import { matchCatalogModel } from "../model-select.js";
|
|
7
7
|
import { mcpForScenario } from "../sema-registry.js";
|
|
8
|
-
import { HttpError, principalFrom, verifiedPrincipal, setSsoPrincipal, ssoVerifiedPrincipal, setSsoScope, isUuidV7, isUuidShape, verifyDirectDoorProof } from "../security.js";
|
|
8
|
+
import { HttpError, principalFrom, verifiedPrincipal, setSsoPrincipal, ssoVerifiedPrincipal, setSsoScope, isUuidV7, isUuidShape, verifyDirectDoorProof, MAX_APPROVAL_REASON_CHARS } from "../security.js";
|
|
9
9
|
import { exportSession, exportSessionManifest, importSession, classifySyncRelationshipByIds, SyncConflictError, stagingIdFor } from "../session-sync.js";
|
|
10
10
|
import { windowMessages, truncateMessageBlobs } from "../audit.js";
|
|
11
11
|
import { parseMemorySyncRequest } from "../memory-sync.js";
|
|
@@ -2898,6 +2898,10 @@ export function createHttpServer(deps) {
|
|
|
2898
2898
|
sendJson(res, 400, { error: "reason must be a string" });
|
|
2899
2899
|
return;
|
|
2900
2900
|
}
|
|
2901
|
+
if (typeof body.reason === "string" && body.reason.length > MAX_APPROVAL_REASON_CHARS) {
|
|
2902
|
+
sendJson(res, 413, { error: `reason too large (max ${MAX_APPROVAL_REASON_CHARS} chars)`, errorCode: "reason_too_large" });
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2901
2905
|
const run = await deps.runStore.getRun(taskId);
|
|
2902
2906
|
if (!run) {
|
|
2903
2907
|
if (deps.config.directDoorActive) {
|
|
@@ -2910,7 +2914,7 @@ export function createHttpServer(deps) {
|
|
|
2910
2914
|
let deciderPrincipal = principal;
|
|
2911
2915
|
if (deps.config.directDoorActive) {
|
|
2912
2916
|
const hdr = (n) => { const h = req.headers[n]; return Array.isArray(h) ? h[0] : h; };
|
|
2913
|
-
const proof = verifyDirectDoorProof({ jwt: hdr("x-approval-principal-token"), mac: hdr("x-approval-mac"), kid: hdr("x-approval-mac-kid") }, { sessionId: run.sessionId, decision }, deps.config, { actionBinding: false });
|
|
2917
|
+
const proof = verifyDirectDoorProof({ jwt: hdr("x-approval-principal-token"), mac: hdr("x-approval-mac"), kid: hdr("x-approval-mac-kid") }, { sessionId: run.sessionId, decision, reason: typeof body.reason === "string" ? body.reason : null }, deps.config, { actionBinding: false });
|
|
2914
2918
|
if (!proof.ok) {
|
|
2915
2919
|
sendJson(res, proof.status, { error: proof.error, errorCode: proof.errorCode });
|
|
2916
2920
|
return;
|
|
@@ -2945,6 +2949,14 @@ export function createHttpServer(deps) {
|
|
|
2945
2949
|
sendJson(res, 400, { error: "body must be { decision: 'approve' | 'deny', reason?, answer?, checkpointToken?, boundCallId?, boundInputHash?, updatedInput?, remember? }" });
|
|
2946
2950
|
return;
|
|
2947
2951
|
}
|
|
2952
|
+
if (body.reason !== undefined && typeof body.reason !== "string") {
|
|
2953
|
+
sendJson(res, 400, { error: "reason must be a string" });
|
|
2954
|
+
return;
|
|
2955
|
+
}
|
|
2956
|
+
if (typeof body.reason === "string" && body.reason.length > MAX_APPROVAL_REASON_CHARS) {
|
|
2957
|
+
sendJson(res, 413, { error: `reason too large (max ${MAX_APPROVAL_REASON_CHARS} chars)`, errorCode: "reason_too_large" });
|
|
2958
|
+
return;
|
|
2959
|
+
}
|
|
2948
2960
|
let remember = false;
|
|
2949
2961
|
if (body.remember !== undefined) {
|
|
2950
2962
|
if (body.remember !== "session") {
|
|
@@ -3002,7 +3014,7 @@ export function createHttpServer(deps) {
|
|
|
3002
3014
|
const h = req.headers[n];
|
|
3003
3015
|
return Array.isArray(h) ? h[0] : h;
|
|
3004
3016
|
};
|
|
3005
|
-
const proof = verifyDirectDoorProof({ jwt: hdr("x-approval-principal-token"), mac: hdr("x-approval-mac"), kid: hdr("x-approval-mac-kid") }, { sessionId, boundCallId: binding.boundCallId, boundInputHash: binding.boundInputHash, decision }, deps.config);
|
|
3017
|
+
const proof = verifyDirectDoorProof({ jwt: hdr("x-approval-principal-token"), mac: hdr("x-approval-mac"), kid: hdr("x-approval-mac-kid") }, { sessionId, boundCallId: binding.boundCallId, boundInputHash: binding.boundInputHash, decision, reason: typeof body.reason === "string" ? body.reason : null }, deps.config);
|
|
3006
3018
|
if (!proof.ok) {
|
|
3007
3019
|
sendJson(res, proof.status, { error: proof.error, errorCode: proof.errorCode });
|
|
3008
3020
|
return;
|
package/dist/security.d.ts
CHANGED
|
@@ -103,12 +103,15 @@ export declare function approvalHmacMessage(env: {
|
|
|
103
103
|
boundCallId?: string | null;
|
|
104
104
|
boundInputHash?: string | null;
|
|
105
105
|
decision: string;
|
|
106
|
+
reason?: string | null;
|
|
106
107
|
}): string;
|
|
108
|
+
export declare const MAX_APPROVAL_REASON_CHARS = 4096;
|
|
107
109
|
export declare function verifyApprovalHmac(env: {
|
|
108
110
|
sessionId: string;
|
|
109
111
|
boundCallId?: string | null;
|
|
110
112
|
boundInputHash?: string | null;
|
|
111
113
|
decision: string;
|
|
114
|
+
reason?: string | null;
|
|
112
115
|
}, mac: string, kid: string | undefined, keys: ApprovalHmacKey[]): boolean;
|
|
113
116
|
export interface PrincipalJwtKey {
|
|
114
117
|
kid: string;
|
|
@@ -141,6 +144,7 @@ export declare function verifyDirectDoorProof(proof: {
|
|
|
141
144
|
boundCallId?: string | null;
|
|
142
145
|
boundInputHash?: string | null;
|
|
143
146
|
decision: string;
|
|
147
|
+
reason?: string | null;
|
|
144
148
|
}, config: {
|
|
145
149
|
principalJwtPubkeys: PrincipalJwtKey[];
|
|
146
150
|
principalJwtIss?: string;
|
package/dist/security.js
CHANGED
|
@@ -176,8 +176,9 @@ export function parseApprovalHmacKeys(raw) {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
export function approvalHmacMessage(env) {
|
|
179
|
-
return JSON.stringify([env.sessionId, env.boundCallId ?? null, env.boundInputHash ?? null, env.decision]);
|
|
179
|
+
return JSON.stringify([env.sessionId, env.boundCallId ?? null, env.boundInputHash ?? null, env.decision, env.reason ?? null]);
|
|
180
180
|
}
|
|
181
|
+
export const MAX_APPROVAL_REASON_CHARS = 4_096;
|
|
181
182
|
export function verifyApprovalHmac(env, mac, kid, keys) {
|
|
182
183
|
if (keys.length === 0)
|
|
183
184
|
return false;
|
|
@@ -303,7 +304,7 @@ export function verifyDirectDoorProof(proof, envelope, config, opts) {
|
|
|
303
304
|
return { ok: false, status: 401, errorCode: "principal_unbound", error: "principal token is not bound to this decision (cnf.bnd mismatch)" };
|
|
304
305
|
if (!proof.mac)
|
|
305
306
|
return { ok: false, status: 401, errorCode: "approval_mac_required", error: "direct door requires an approval MAC (X-Approval-Mac)" };
|
|
306
|
-
const ok = verifyApprovalHmac({ sessionId: envelope.sessionId, boundCallId: envelope.boundCallId ?? null, boundInputHash: envelope.boundInputHash ?? null, decision: envelope.decision }, proof.mac, proof.kid, config.approvalHmacKeys);
|
|
307
|
+
const ok = verifyApprovalHmac({ sessionId: envelope.sessionId, boundCallId: envelope.boundCallId ?? null, boundInputHash: envelope.boundInputHash ?? null, decision: envelope.decision, reason: envelope.reason ?? null }, proof.mac, proof.kid, config.approvalHmacKeys);
|
|
307
308
|
if (!ok)
|
|
308
309
|
return { ok: false, status: 401, errorCode: "approval_mac_invalid", error: "approval envelope MAC invalid" };
|
|
309
310
|
return { ok: true, principal: verified.sub };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.284.0",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|