Repository navigation
Add BSOD AI: ask questions about a finished scan (Turnstile + layered abuse protection) - #386
Merged
Merged
Conversation
…d layered abuse protection After a scan the summary strip can show a wand button that opens a chat about the visitor's own crash, answered by gpt-6-luna. Dormant unless BSOD_AI_CHAT_ENABLED is set (a typo keeps it off); when off, the pass and ask routes answer 503 with no limiter in front of them. Protection, in the order a request meets it: - same-origin check, lockout check, then a Turnstile-backed pass: a signed, session-bound, 15-minute cookie with its own HKDF purpose, minted only for a token of the action "bsod-ai" on an allowed hostname (single-use through the existing replay guard) - strict body validation, input screening for prompt injection (look-alike letters folded, spacing-insensitive) and off-topic use, applied to the question and to the history and report text sent back by the browser - strikes and lockouts (a session at 4, an address at 12), per-address and per-session limiters, one question in flight per session, a global concurrency cap, a per-tier hourly quota on the session and the address, and a global daily ceiling, all reserved before the evidence fetch - the case file (the owned job's WinDBG evidence plus the report) and the history are redacted, capped and fenced as untrusted data; the model answers in JSON and the answer is scrubbed (no links, bare domains, emails, phone numbers, HTML, markdown, or destructive / download-and-run commands) before the browser renders it as text Cost: free providers only (Experiential, then the OpenAI free route), never the billed legs; with neither the chat rests and the question is refunded. The chat yields to scans on both legs: it is admitted only while total usage is under BSOD_AI_CHAT_BUDGET_FRACTION of the budget (OpenAI's budget gains a `fraction`). Chat turns are not stored; /privacy and CLAUDE.md say so. The mascot moves into components/Mascot.tsx so the chat avatar can reuse it. Tests cover the pure rules, the routes over real HTTP with fakes, the component in jsdom, the env switch and the budget share. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The provider adapters read the upstream SSE (retries and error mapping stay shared); the model replies in text with a topic line, and createAnswerStream releases the answer a sentence at a time, each one scrubbed first. Anything before the first sentence (pass, screening, quota, off-topic, provider failure) stays plain JSON and refunded as before; after text went out a failure is an error event with no refund and no provider fall-through. Off-topic stops the upstream call after the first line, and a closed connection aborts it. The non-streaming JSON path is unchanged. The chat shows the growing text aria-hidden and swaps in the finished message, so a screen reader announces it once; the typewriter is gone. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
BSOD_AI_CHAT_ENABLED=trueto turn it on. When off,/api/bsod-ai/passand/askanswer 503 with no limiter in front.bsod-aion an allowed hostname; the existing single-use replay guard applies.BSOD_AI_CHAT_BUDGET_FRACTION, default 0.4, of each budget)./privacyandCLAUDE.mddocument what is sent.Test plan
npm run check(903 tests, typecheck, build, hydration)Enabling
gcloud run services update bsod-analyzer --region us-east1 --update-env-vars BSOD_AI_CHAT_ENABLED=true(limits and budget share are env vars, seeCLAUDE.md).🤖 Generated with Claude Code