fix(02-bot-skeleton-initdata-security): WR-02 fail-closed /telegram/webhook — unarmed WEBHOOK_SECRET rejects (constant 500, category-only log) before grammY's accept-everything compare

This commit is contained in:
araharah-executor
2026-10-22 20:18:34 +08:00
parent 8995498bff
commit 3ea1fdd932
3 changed files with 41 additions and 4 deletions
+18 -1
View File
@@ -13,7 +13,7 @@
* live Bot API. Armed-secret behavior is verified by the live smokes in
* plan 02-03 instead.
*
* Cases (WR-01 body cap, T-02-01 gate):
* Cases (WR-01 body cap, WR-02 fail-closed gate, T-02-01 gate):
* WK1 POST valid initData under the cap → 200 {token: uuid};
* exactly two TTL-carrying KV writes (900 s)
* WK2 POST an over-cap (4 KB+) but VALIDLY SIGNED initData → 413
@@ -24,6 +24,9 @@
* WK3 declared-length 999999 + unreadable body stream → 413 resolved
* WITHOUT pulling the stream (the pre-read check refuses to buffer)
* WK4 GET /api/session → 405 (the cap logic never runs on GET)
* WK5 unarmed WEBHOOK_SECRET → /telegram/webhook rejects CLOSED with a
* constant 500 BEFORE grammY's compareSecretToken (which would
* accept every request once the secret is undefined — WR-02)
*/
import { strict as assert } from "node:assert";
import { createHmac } from "node:crypto";
@@ -185,3 +188,17 @@ test("WK4 GET /api/session → 405", async () => {
const res = await handler(req, makeEnv(makeKV()), {});
assert.equal(res.status, 405);
});
/* ————— WK5 — WR-02 fail-closed webhook gate ————— */
test("WK5 unarmed WEBHOOK_SECRET ('') → webhook rejects CLOSED with a constant 500, no bot run, no KV touch", async () => {
const env = { BOT_TOKEN: TEST_TOKEN, WEBHOOK_SECRET: "", chat_sessions: undefined };
const req = () => new Request("https://host/telegram/webhook", { method: "POST", body: '{\"update_id\":1}' });
const res1 = await handler(req(), env, {});
const res2 = await handler(req(), env, {});
assert.equal(res1.status, 500, "missing binding must fail closed, not fall through to grammY's accept-everything compare");
assert.equal(res2.status, 500, "the rejection is constant across calls");
assert.equal(await res1.text(), "Server misconfigured");
assert.equal(await res2.text(), "Server misconfigured");
assert.ok(env.chat_sessions === undefined, "the guard fired before any storage or bot wiring was needed");
});