Skip to content

feat: harden validation edge cases, add immutable with*() builders, and unify transport HTTP handling - #637

Merged
rowan-m merged 3 commits into
mainfrom
feat/validation-and-transport-hardening
Sep 23, 2026
Merged

rowan-m merged 3 commits into
mainfrom
feat/validation-and-transport-hardening

Conversation

@rowan-m

@rowan-m rowan-m commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the remaining backwards-compatible validation, transport consistency, and developer experience improvements:

  • Score Threshold & Challenge Timeout Hardening (ReCaptcha::verify()):
    • Fix setScoreThreshold(0.0) null-coercion bypass when score is omitted (null) from the API response so it properly records ReCaptcha::E_SCORE_THRESHOLD_NOT_MET.
    • Make setChallengeTimeout() fail closed (ReCaptcha::E_CHALLENGE_TIMEOUT) when challenge_ts is missing or unparseable instead of silently skipping timeout enforcement.
  • Immutable with*() Builder Methods (ReCaptcha):
    • Add withExpectedHostname(), withExpectedApkPackageName(), withExpectedAction(), withScoreThreshold(), and withChallengeTimeout() that clone the ReCaptcha instance before applying expectations—allowing safe singleton injection in DI containers and persistent worker runtimes (FrankenPHP, RoadRunner, Swoole, Laravel Octane) while remaining 100% backwards-compatible with set*().
  • Consistent HTTP Status Validation & Connection Reuse Across Transports:
    • CurlPost: Lazily initialize and reuse the CurlHandle across submit() calls for TLS session/keep-alive reuse, handle curl_init() failure cleanly, and validate CURLINFO_HTTP_CODE === 200 (returning ReCaptcha::E_BAD_RESPONSE on non-200 responses, matching SocketPost).
    • Post: Enable 'ignore_errors' => true and validate the HTTP 200 status line via http_get_last_response_headers() to return ReCaptcha::E_BAD_RESPONSE on non-200 HTTP responses without emitting PHP warnings.
    • SocketPost: Loop fwrite() until all request bytes are written on the TLS socket stream and fail cleanly with ReCaptcha::E_CONNECTION_FAILED (closing the socket handle) if fwrite() fails or writes 0 bytes.
  • Test Coverage & CI:
    • Maintain 100% statement and method coverage (185/185 statements, 32/32 methods across 85 tests and 247 assertions), including standalone src/autoload.php verification.
    • Pin roave/backward-compatibility-check:^8.22 in .github/workflows/php.yml.

@coveralls

coveralls commented Sep 23, 2026 •

Copy link
Copy Markdown

Coverage Status

coverage: 100.0%. remained the same — feat/validation-and-transport-hardening into main

@rowan-m
rowan-m merged commit a6df771 into main Sep 23, 2026
13 checks passed
@rowan-m
rowan-m deleted the feat/validation-and-transport-hardening branch September 23, 2026 15:46
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.

2 participants