mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-19 03:12:21 +02:00
feat(design): receipted fetch for OpenAI calls
design/src/receipted-fetch.ts wraps every api.openai.com call: a content-free egress receipt (sink design-openai, sha256 of the JSON body — hash only, never the body) is written BEFORE the send. Polarity is FAIL-OPEN: user-facing generation must not die because an audit log hiccuped, so a receipt failure warns on stderr and the call proceeds. Streams pass through untouched (response bodies returned as-is; non-string request bodies receipted as sha256:null rather than drained to hash). All ten call sites converted with per-command payload classes: generate, variants (injected fetchFn passes through), iterate (both threaded and fresh paths), evolve (image + screenshot analysis), check, diff, design-to-code, memory. Unit-tested with injected fetch: receipt-before-send ordering, stream passthrough, and fail-open on an unwritable ledger. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit c0e5ff6639414ac2fd98e8ac3affb51401746b55)
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* receipted-fetch — egress-receipted wrapper for the design binary's OpenAI
|
||||
* calls (sink 'design-openai').
|
||||
*
|
||||
* Writes a content-free receipt BEFORE the send: sha256 of the JSON body
|
||||
* plus a byte count — the hash only, never the body itself. FAIL-OPEN: a
|
||||
* receipt hiccup warns on stderr and the call proceeds. User-facing image
|
||||
* generation must not die because an audit log could not be written (the
|
||||
* ledger records ATTEMPTED egress for auditing; it is not a send gate here).
|
||||
*
|
||||
* Streams pass through untouched: the response is returned as-is, and a
|
||||
* non-string request body (e.g. a ReadableStream) is receipted as
|
||||
* sha256:null rather than being consumed to hash it.
|
||||
*/
|
||||
|
||||
import { sha256Hex, writeReceipt } from "../../lib/egress-receipt";
|
||||
|
||||
export type FetchLike = typeof globalThis.fetch;
|
||||
|
||||
/**
|
||||
* Drop-in fetch replacement for api.openai.com calls.
|
||||
*
|
||||
* @param payloadClass content-free description of what is being sent
|
||||
* (e.g. 'generate-image-request', 'check-screenshot-request')
|
||||
* @param fetchImpl injectable fetch for tests / callers with their own
|
||||
* fetch (variants.ts passes its stubbed fetchFn through)
|
||||
*/
|
||||
export async function receiptedFetch(
|
||||
payloadClass: string,
|
||||
url: string,
|
||||
init?: RequestInit,
|
||||
fetchImpl: FetchLike = globalThis.fetch,
|
||||
): Promise<Response> {
|
||||
try {
|
||||
const body = init?.body;
|
||||
let bytes = 0;
|
||||
let sha256: string | null = null;
|
||||
if (typeof body === "string") {
|
||||
bytes = Buffer.byteLength(body);
|
||||
sha256 = sha256Hex(body);
|
||||
}
|
||||
writeReceipt({
|
||||
sink: "design-openai",
|
||||
host: new URL(url).host,
|
||||
payloadClass,
|
||||
bytes,
|
||||
sha256,
|
||||
consent: "user ran design command (OPENAI_API_KEY configured)",
|
||||
});
|
||||
} catch (err) {
|
||||
process.stderr.write(
|
||||
`[design] egress receipt could not be written (${(err as Error).message}) — proceeding (fail-open). ` +
|
||||
`gstack records what it ATTEMPTS to send off-machine; see gstack-egress.\n`,
|
||||
);
|
||||
}
|
||||
return fetchImpl(url, init);
|
||||
}
|
||||
Reference in New Issue
Block a user