@sema-agent/core
Version:
Stateless, task-oriented AI agent core
48 lines (47 loc) • 3.05 kB
JavaScript
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" });
}