Skip to content

Require a human check on the chat, and stop absence meaning "off" - #248

Merged
adamjohnwright merged 2 commits into
mainfrom
feat/chat-requires-human
Sep 18, 2026
Merged

adamjohnwright merged 2 commits into
mainfrom
feat/chat-requires-human

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

Your requirement, relayed via the website session: "we need to make sure there is also a human checker when going to the regular chat as well."

The obstacle was not the check

The middleware already existed. What did not exist was any way to tell whether a deployment was using it.

is_captcha_exempt treated no CLOUDFLARE_SECRET_KEY as no captcha to enforce and let everything through. So "there is captcha middleware" and "the chat is gated" were different statements with nothing to distinguish them — and beta has been serving an ungated chat, correctly per that rule and invisibly. I verified it directly: captcha_configured = False in the running container.

That is the same failure shape I warned the website session about an hour earlier, pointing back at us.

What changed

CHAT_REQUIRES_HUMAN defaults to on. A deployment that requires a human but has no key refuses to start, naming the two ways out. An ungated chat is still available — beta may want one — but only by setting CHAT_REQUIRES_HUMAN=0, which somebody has to type.

Refusing to start rather than serving unprotected is the trade the answer endpoint's verifying key already makes. Losing the feature is the correct failure; serving it unprotected is not.

Sequencing, because this could otherwise take beta down

Beta has no keys today, so this change alone would refuse every visitor. The deploy script now checks the env file for a key or an explicit opt-out before it stops the running container, exactly as it checks the caller-token key.

Exercised against beta's real env (correctly refuses) and five variants:

env result
CLOUDFLARE_SECRET_KEY=0xabc proceeds
CHAT_REQUIRES_HUMAN=0 proceeds
CLOUDFLARE_SECRET_KEY= (empty) refuses
CHAT_REQUIRES_HUMAN=nope (typo) refuses
nothing set refuses

A mistyped opt-out failing closed is the case I most wanted to get right.

The keys are yours to place

~/install-beta-captcha-keys.sh prompts for them, hides the secret as you type, keeps 0600 and a timestamped backup, and prints neither value. A transcript is a worse home for a credential than the host — the same reasoning that kept the answer endpoint's signing key off this machine entirely.

After running it, redeploy and the chat is gated.

🤖 Generated with Claude Code

adamjohnwright and others added 2 commits September 18, 2026 07:15
Adam asked for a human check when going to the regular chat, not only the
search-page endpoint. The middleware already existed; what did not was any way
to tell whether a given deployment was actually using it.

`is_captcha_exempt` treated "no CLOUDFLARE_SECRET_KEY" as "no captcha to
enforce" and let everything through. So "there is captcha middleware" and "the
chat is gated" were different statements, and the gap was silent: beta has been
serving an ungated chat, correctly per that rule and invisibly.

Now the decision is written down rather than inferred. CHAT_REQUIRES_HUMAN
defaults to on, and a deployment that requires a human but has no key refuses to
start, with a message saying which of the two things to do. An ungated chat is
still available -- beta may want one -- but only by setting
CHAT_REQUIRES_HUMAN=0, which someone has to type.

Refusing to start rather than serving unprotected is the trade the answer
endpoint's verifying key already makes. Losing the feature is the correct
failure.

Sequencing, because this could otherwise take beta down: the deploy script now
checks the env file for a key or an explicit opt-out *before* it stops the
running container, the same way it checks the caller-token key. Exercised
against beta's current env, where it correctly refuses, and against five
variants including an empty value and a mistyped opt-out, both of which fail
closed.

The keys themselves are Adam's to place. ~/install-beta-captcha-keys.sh prompts
for them, hides the secret, keeps 0600 and a backup, and prints neither -- a
transcript is a worse home for a credential than the host, the same reasoning
that kept the signing key off this machine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Committed the previous change with ruff failing: I printed its exit code and
then ran git anyway, which is the second time today that shape has caught me.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit edb5e87 into main Sep 18, 2026
10 checks passed
@adamjohnwright
adamjohnwright deleted the feat/chat-requires-human branch September 18, 2026 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant