Commit 89cedd2
committed
fix(gchat): per-shape verification + dataclass field order + test env isolation (codex review)
Addresses three findings from Codex's review of #130.
1. Per-shape webhook verification (P1, security).
handle_webhook accepts BOTH direct Google Chat webhooks AND Pub/Sub push
shapes on a single endpoint. The constructor's "at least one verifier OR
disable_signature_verification" check is a coarse gate: an operator who
configured only pubsub_audience left the direct-webhook shape going through
the warned-but-unverified path (and symmetrically for project_number vs
Pub/Sub). An attacker could pick the unconfigured shape to bypass the
configured verifier.
handle_webhook now REJECTS (401) any shape whose verifier isn't configured,
unless disable_signature_verification is explicitly set -- in which case
the existing warn-and-process path is preserved. Mirrors upstream
adapter-gchat/src/index.ts (vercel/chat) faithfully; upstream solves this
the same way (per-path require, construct-time stays any-of).
2. GoogleChatAdapterConfig.disable_signature_verification field order (P2).
The PR inserted the new field in the MIDDLE of the dataclass, shifting
every later positional arg. A caller like
GoogleChatAdapterConfig("creds", "audience", impersonate, logger)
would silently route `impersonate` into `disable_signature_verification`.
Moved the field to the END so existing positional callers keep working
(the field has a default so trailing positional callers are unaffected).
Added a regression test that pins the field's position via
dataclasses.fields().
3. Env-var leakage in fail-closed tests (P2, test isolation).
The env-fallback tests used a manual try/finally that only restored env
vars SET before the test. Setting
GOOGLE_CHAT_DISABLE_SIGNATURE_VERIFICATION=true in a test where the var
was originally absent leaked it to later tests, silently satisfying the
fail-closed gate in unrelated construction tests.
Converted to pytest's monkeypatch fixture, which restores both was-set
and was-absent cases at teardown. Added a load-bearing leak-detection
test that exercises the previously-leaky pattern within a single test.
All three findings have load-bearing tests added under tests/test_gchat_verification.py:
- TestPerShapeVerificationRejection (3 tests; first two would 200 instead of 401 pre-fix)
- TestDisableSignatureVerificationFieldOrder (2 tests; both fail pre-fix)
- TestDisableSignatureVerificationEnvFallback::test_env_does_not_leak_to_subsequent_construction
Validation: uv run ruff check, ruff format --check, audit_test_quality.py
(0 hard failures), full pytest (4063 passed, 3 skipped).
https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj1 parent fcd4a29 commit 89cedd2
3 files changed
Lines changed: 295 additions & 127 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
878 | 878 | | |
879 | 879 | | |
880 | 880 | | |
881 | | - | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
882 | 888 | | |
883 | 889 | | |
884 | 890 | | |
885 | 891 | | |
886 | | - | |
887 | | - | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
888 | 904 | | |
889 | | - | |
890 | | - | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
891 | 908 | | |
| 909 | + | |
892 | 910 | | |
893 | 911 | | |
894 | | - | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
895 | 915 | | |
896 | 916 | | |
897 | 917 | | |
898 | 918 | | |
899 | | - | |
900 | | - | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
901 | 928 | | |
902 | | - | |
903 | | - | |
904 | | - | |
| 929 | + | |
| 930 | + | |
| 931 | + | |
905 | 932 | | |
| 933 | + | |
906 | 934 | | |
907 | 935 | | |
908 | 936 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
301 | 301 | | |
302 | 302 | | |
303 | 303 | | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
310 | | - | |
311 | | - | |
312 | | - | |
313 | 304 | | |
314 | 305 | | |
315 | 306 | | |
| |||
324 | 315 | | |
325 | 316 | | |
326 | 317 | | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
0 commit comments