UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

48 lines (47 loc) • 3.05 kB
import { credentialHeaderValues, holdOwnCredentialValues } from "./secret-env.js"; import { inlineUntrusted } from "./untrusted-text.js"; export function headerOwnershipCollision(t) { const owners = new Map(); for (const name of [...Object.keys(t.headers ?? {}), ...(t.principalHeader ? [t.principalHeader] : [])]) { const prior = owners.get(name.toLowerCase()); if (prior !== undefined) return { first: prior, second: name }; owners.set(name.toLowerCase(), name); } return undefined; } export function resolveProtocolHttpHeaders(protocol, t, principal) { const principalHeader = t.principalHeader; const declared = t.headers; const own = { ...(declared !== undefined ? { headers: { ...declared } } : {}), ...(principalHeader !== undefined ? { principalHeader } : {}) }; holdOwnCredentialValues(credentialHeaderValues(own.headers)); const collision = headerOwnershipCollision(own); if (collision !== undefined) { throw Object.assign(new Error(`${protocol}: the declaration names the header "${inlineUntrusted(collision.first, 80)}" twice ("${inlineUntrusted(collision.second, 80)}" — header names are case-insensitive); ${principalHeader !== undefined && collision.second === principalHeader ? "the principal header is the engine's to send, so remove the static entry" : "keep one spelling"} — this peer is not dialed`), { code: "config.protocol_header_collision" }); } if (principalHeader && principal !== undefined) { if (/[\r\n]/.test(principal)) throw new Error(`${protocol}: principal must not contain CR/LF (header injection guard)`); return Object.freeze({ ...own.headers, [principalHeader]: principal }); } return own.headers === undefined ? undefined : Object.freeze(own.headers); } export function underDeclaredHeaders(defaults, declared) { const owned = new Set(Object.keys(declared ?? {}).map((k) => k.toLowerCase())); return { ...Object.fromEntries(Object.entries(defaults).filter(([k]) => !owned.has(k.toLowerCase()))), ...declared }; } export function carriesDeclaredHeaders(headers) { return headers !== undefined && Object.keys(headers).length > 0; } export function redirectPolicy(headers) { return carriesDeclaredHeaders(headers) ? "manual" : "follow"; } export function assertEndpointBound(protocol, peer, endpoint, declared, headers) { if (!carriesDeclaredHeaders(headers)) return; const origins = declared.map((u) => new URL(u).origin); const at = new URL(endpoint).origin; if (origins.includes(at)) return; throw Object.assign(new Error(`${protocol}: peer "${inlineUntrusted(peer, 80)}" advertises the endpoint origin ${inlineUntrusted(at, 120)}, outside the origins its declaration names (${origins.map((o) => inlineUntrusted(o, 120)).join(", ")}); the declared headers travel only to those — declare that origin as the peer's url (and the card's location as cardUrl) or drop the headers`), { code: "config.protocol_endpoint_unbound" }); }