Something went wrong. Try again.
A local-first event pipeline for independent agents, built on Jazz.
Something went wrong. Try again.
8.9 kB · 150 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151import { createHash, randomUUID } from "node:crypto";import { constants } from "node:fs";import fs from "node:fs/promises";import path from "node:path";import YAML from "yaml";import type { ArtifactBlobReference, ArtifactMediaType } from "./types.js";import { ARTIFACT_MAX_IMAGE_BYTES, ARTIFACT_MAX_TEXT_BYTES } from "./types.js";
const PAIRS: Record<string, readonly ArtifactMediaType[]> = { ".md": ["text/markdown"], ".markdown": ["text/markdown"], ".txt": ["text/plain"], ".json": ["application/json"], ".yaml": ["application/yaml", "text/yaml"], ".yml": ["application/yaml", "text/yaml"], ".png": ["image/png"], ".jpg": ["image/jpeg"], ".jpeg": ["image/jpeg"],};
export function canonicalBlobPath(hash: string): string { return `sha256/${hash.slice(0, 2)}/${hash}` }
export async function readWorkspaceArtifact(rootInput: string, relativeFilePath: string, mediaType: ArtifactMediaType): Promise<Buffer> { if (!path.isAbsolute(rootInput)) throw new Error("Workspace lease root must be absolute"); validateRelative(relativeFilePath); const root = path.resolve(rootInput); const rootStat = await fs.lstat(root); if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) throw new Error("Workspace lease root must be a non-symlink directory"); const canonicalRoot = await fs.realpath(root); if (canonicalRoot !== root) throw new Error("Workspace lease root must be canonical and contain no symlinks"); const parts = relativeFilePath.split("/"); let current = root; for (const part of parts) { current = path.join(current, part); const stat = await fs.lstat(current); if (stat.isSymbolicLink()) throw new Error("Artifact file and parent components must not be symbolic links"); } const candidate = path.resolve(root, ...parts); const relative = path.relative(root, candidate); if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) throw new Error("Artifact file must be contained by the explicit workspace lease root"); const canonical = await fs.realpath(candidate); if (canonical !== candidate) throw new Error("Artifact file and parent components must not be symbolic links"); const stat = await fs.lstat(candidate); if (!stat.isFile()) throw new Error("Artifact path is not a regular file"); const allowed = PAIRS[path.extname(candidate).toLowerCase()]; if (!allowed?.includes(mediaType)) throw new Error("Artifact extension and media type do not match"); const max = maxBytes(mediaType); if (stat.size === 0) throw new Error("Artifact file is empty"); if (stat.size > max) throw new Error(`Artifact file exceeds ${max} bytes`); const handle = await fs.open(candidate, constants.O_RDONLY | constants.O_NOFOLLOW); try { const opened = await handle.stat(); if (!opened.isFile() || opened.size !== stat.size) throw new Error("Artifact file changed during validation"); const bytes = await readHandleBounded(handle, max); if (bytes.byteLength !== opened.size) throw new Error("Artifact file changed during read"); validateBytes(bytes, mediaType); return bytes; } finally { await handle.close(); }}
export async function storeBlob(rootInput: string, bytes: Buffer): Promise<ArtifactBlobReference> { const hash = createHash("sha256").update(bytes).digest("hex"); const relativePath = canonicalBlobPath(hash); const root = path.resolve(rootInput); await ensurePrivateDirectory(root); await rejectSymlinkComponents(root, relativePath.split("/").slice(0, -1), true); const destination = path.join(root, ...relativePath.split("/")); const temporary = path.join(path.dirname(destination), `.${hash}.${randomUUID()}.tmp`); await fs.writeFile(temporary, bytes, { flag: "wx", mode: 0o600 }); try { try { await fs.link(temporary, destination); } catch (error) { if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error; await verifyExisting(destination, bytes, hash); } } finally { await fs.rm(temporary, { force: true }); } return { algorithm: "sha256", sha256: hash, relativePath, byteCount: bytes.byteLength };}
export async function readVerifiedBlob(rootInput: string, blob: ArtifactBlobReference, mediaType: ArtifactMediaType): Promise<Buffer> { if (blob.relativePath !== canonicalBlobPath(blob.sha256)) throw new Error("Artifact blob path is not canonical"); if (blob.byteCount <= 0 || blob.byteCount > maxBytes(mediaType)) throw new Error("Artifact blob size metadata is invalid"); const root = path.resolve(rootInput); const rootStat = await fs.lstat(root); if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || await fs.realpath(root) !== root) throw new Error("Artifact blob root is not canonical"); await rejectSymlinkComponents(root, blob.relativePath.split("/"), false); const destination = path.join(root, ...blob.relativePath.split("/")); const handle = await fs.open(destination, constants.O_RDONLY | constants.O_NOFOLLOW); try { const stat = await handle.stat(); if (!stat.isFile() || stat.size !== blob.byteCount) throw new Error("Artifact blob size integrity check failed"); const bytes = await readHandleBounded(handle, maxBytes(mediaType)); const hash = createHash("sha256").update(bytes).digest("hex"); if (hash !== blob.sha256) throw new Error("Artifact blob hash integrity check failed"); validateBytes(bytes, mediaType); return bytes; } finally { await handle.close(); }}
function validateRelative(value: string): void { if (!value || value.includes("\\") || path.isAbsolute(value) || value.endsWith("/") || value.split("/").some((part) => !part || part === "." || part === "..")) { throw new Error("Artifact file path must be one normalized relative path"); }}function maxBytes(mediaType: ArtifactMediaType): number { return mediaType.startsWith("image/") ? ARTIFACT_MAX_IMAGE_BYTES : ARTIFACT_MAX_TEXT_BYTES }async function readHandleBounded(handle: fs.FileHandle, max: number): Promise<Buffer> { const chunks: Buffer[] = []; let total = 0; let position = 0; while (true) { const chunk = Buffer.alloc(Math.min(64 * 1024, max + 1 - total)); const { bytesRead } = await handle.read(chunk, 0, chunk.length, position); if (bytesRead === 0) break; total += bytesRead; position += bytesRead; if (total > max) throw new Error(`Artifact exceeds ${max} bytes`); chunks.push(chunk.subarray(0, bytesRead)); } return Buffer.concat(chunks, total);}function validateBytes(bytes: Buffer, mediaType: ArtifactMediaType): void { if (mediaType === "image/png") { if (bytes.length < 8 || !bytes.subarray(0, 8).equals(Buffer.from([137,80,78,71,13,10,26,10]))) throw new Error("Artifact PNG magic does not match media type"); return; } if (mediaType === "image/jpeg") { if (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8 || bytes.at(-2) !== 0xff || bytes.at(-1) !== 0xd9) throw new Error("Artifact JPEG magic does not match media type"); return; } const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes); if (text.includes("\0")) throw new Error("Text artifact contains a NUL byte"); if (mediaType === "application/json") JSON.parse(text); if (mediaType === "application/yaml" || mediaType === "text/yaml") YAML.parse(text);}async function ensurePrivateDirectory(root: string): Promise<void> { await fs.mkdir(root, { recursive: true, mode: 0o700 }); const stat = await fs.lstat(root); if (!stat.isDirectory() || stat.isSymbolicLink() || await fs.realpath(root) !== root) throw new Error("Artifact blob root must be a canonical non-symlink directory"); await fs.chmod(root, 0o700);}async function rejectSymlinkComponents(root: string, parts: string[], createDirectories: boolean): Promise<void> { let current = root; for (const part of parts) { current = path.join(current, part); if (createDirectories) await fs.mkdir(current, { mode: 0o700 }).catch((error: NodeJS.ErrnoException) => { if (error.code !== "EEXIST") throw error; }); const stat = await fs.lstat(current); if (stat.isSymbolicLink()) throw new Error("Artifact blob path contains a symbolic link"); if (part !== parts.at(-1) || createDirectories) { if (!stat.isDirectory()) throw new Error("Artifact blob parent is not a directory"); if (createDirectories) await fs.chmod(current, 0o700); } }}async function verifyExisting(destination: string, expected: Buffer, hash: string): Promise<void> { const stat = await fs.lstat(destination); if (!stat.isFile() || stat.isSymbolicLink() || stat.size !== expected.byteLength) throw new Error("Existing artifact blob conflicts with requested bytes"); const actual = await fs.readFile(destination); if (createHash("sha256").update(actual).digest("hex") !== hash || !actual.equals(expected)) throw new Error("Existing artifact blob conflicts with requested bytes");}