Skip to content

test(icaptcha): assert obtain_proof consumes the mocked service#184

Open
beardthelion wants to merge 3 commits into
mainfrom
test/icaptcha-mock-consumed
Open

test(icaptcha): assert obtain_proof consumes the mocked service#184
beardthelion wants to merge 3 commits into
mainfrom
test/icaptcha-mock-consumed

Conversation

@beardthelion

@beardthelion beardthelion commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Adds an integration test that runs obtain_proof against a mockito server and asserts both /v1/challenge and /v1/answer are consumed. This proves the iCaptcha client actually calls the service rather than short-circuiting or making a live call: a regression that skipped the network would fail the test, since the mock-consumed assertions go red when the endpoints are not hit.

Adds mockito as a dev-dependency.

Verified: the test is load-bearing (red when the mock is under-consumed or the client points elsewhere, green when the service is consumed), and cargo build --workspace, fmt --check, and clippy -D warnings are clean.

Summary by CodeRabbit

  • Tests
    • Added an integration test that verifies the CAPTCHA flow performs the challenge and answer HTTP POST requests against the configured mocked service.
    • Ensures each mocked endpoint is consumed exactly once and that the returned proof matches the mocked response.
    • Hardened the test environment to prevent accidental live network calls by blackholing non-local traffic.

Add an integration test that runs obtain_proof against a mockito server and
asserts both /v1/challenge and /v1/answer were consumed, so the flow is proven
to call the service rather than short-circuit or make a live call. Adds mockito
as a dev-dependency.
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a9ec864-3a0a-47b8-9f91-cf817050cbc1

📥 Commits

Reviewing files that changed from the base of the PR and between 8c25af6 and 593b83f.

📒 Files selected for processing (1)
  • crates/icaptcha-client/tests/icaptcha_mock_consumed.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/icaptcha-client/tests/icaptcha_mock_consumed.rs

📝 Walkthrough

Walkthrough

Adds mockito as a development dependency and introduces an integration test verifying that obtain_proof calls mocked challenge and answer endpoints exactly once and returns the expected proof.

Changes

iCaptcha mock coverage

Layer / File(s) Summary
Mocked service setup
crates/icaptcha-client/Cargo.toml, crates/icaptcha-client/tests/icaptcha_mock_consumed.rs
Adds the mockito test dependency, prevents non-loopback network access, and configures exactly-once challenge and answer responses.
Mocked proof acquisition flow
crates/icaptcha-client/tests/icaptcha_mock_consumed.rs
Wires the mock server into IcaptchaCfg, supplies a solver, validates the returned proof, and asserts both endpoints were consumed.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main change: a test ensuring obtain_proof consumes the mocked service.
Description check ✅ Passed It covers the change, motivation, and verification, though it doesn't use the template's exact section headings.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/icaptcha-mock-consumed

Comment @coderabbitai help to get the list of available commands.

@beardthelion beardthelion added the kind:test Test coverage or harness label Jul 11, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These assertions only verify that the local mock received one request for each route. A regression can make those two requests and also send the challenge, answer, or configured API key to DEFAULT_URL (or another origin), while this test still passes. That leaves the stated guard against unintended live iCaptcha traffic and token exposure untested. Please either constrain the test's HTTP transport so every non-mock destination fails, or narrow the test name/comments and PR claim to endpoint consumption only.

…al (#184)

The mock-consumed assertions only prove the two mock endpoints were hit; they
cannot see a request that also leaks the DID, answer, or API key to DEFAULT_URL
or any other origin, so the test's stated "no live call" guarantee was untested.

Blackhole every non-loopback destination for the flow: NO_PROXY lets the
loopback mock through while ALL_PROXY routes any other host to a closed port, so
the client contacting anything but the injected mock fails the request. Verified
load-bearing: pointing cfg.url at DEFAULT_URL makes obtain_proof fail with a
proxy tunnel error (RED), and the loopback-mock path still passes (GREEN).
@beardthelion

Copy link
Copy Markdown
Collaborator Author

Addressed via your option (a) on 8c25af6. The test now blackholes every non-loopback origin: NO_PROXY lets the loopback mock through, ALL_PROXY routes any other host to a closed port, so the client contacting anything but the injected mock fails the request. Verified load-bearing: pointing cfg.url at DEFAULT_URL makes obtain_proof fail with a proxy tunnel error, and the loopback-mock path still passes.

@beardthelion
beardthelion requested a review from jatmn July 13, 2026 21:40

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found issues that need to be addressed before this is ready.

Findings

  • [P2] Make the non-mock egress block override scheme-specific proxies
    crates/icaptcha-client/tests/icaptcha_mock_consumed.rs:26
    This still does not guarantee the requested no-live-call behavior on a proxied runner. obtain_proof uses reqwest's default system-proxy configuration, and its HTTPS_PROXY/https_proxy (or HTTP equivalents) take precedence over the ALL_PROXY set here. Therefore an environment with a working HTTPS proxy can let a regression additionally send the DID, answer, or API key to DEFAULT_URL while both loopback mock requests are consumed and this test remains green. Override or clear the scheme-specific proxy variables too (restoring the prior environment safely), or enforce the transport policy directly, so the test actually detects that egress.

@beardthelion beardthelion added the crate:icaptcha icaptcha-client — proof-of-personhood captcha client label Jul 14, 2026
…all guard covers https

The mock-consumed guard blackholed non-loopback egress with ALL_PROXY only, but
reqwest honors HTTPS_PROXY/https_proxy (and the http equivalents) OVER ALL_PROXY
for https URLs. On a runner whose environment has a working HTTPS_PROXY, a
regression could still leak the DID/answer/API key to the https DEFAULT_URL while
both loopback mock calls are consumed and the test stayed green. Override the
scheme-specific proxy vars (both cases) to the closed port too; NO_PROXY keeps the
loopback mock direct. Single #[test] per process, so the override needs no restore.

Verified: a throwaway repro showed reqwest routing an https request to HTTPS_PROXY
past the ALL_PROXY blackhole (the gap); with the fix the override sends that egress
to the closed port even when a working HTTPS_PROXY is pre-set; the guard still goes
RED when cfg.url points off-loopback.
@beardthelion

Copy link
Copy Markdown
Collaborator Author

Confirmed and fixed at 593b83f.

The finding is real. I reproduced the precedence directly: with ALL_PROXY pointed at a closed port and HTTPS_PROXY at a live listener, reqwest routed a https:// request to HTTPS_PROXY, past the ALL_PROXY blackhole. Since obtain_proof builds a default reqwest::blocking::Client (lib.rs:252) with no transport control and DEFAULT_URL is https, an ALL_PROXY-only blackhole leaves an https leak open on any runner whose environment already has a working HTTPS_PROXY.

Fix: the test now blackholes the scheme-specific variables too (HTTPS_PROXY/https_proxy/HTTP_PROXY/http_proxy, both cases) to the closed port, with NO_PROXY still letting the loopback mock through. No env restore: this file has a single #[test], so it runs in its own process and the override never races a sibling.

Vetted both ways:

  • The override defeats a pre-set working HTTPS_PROXY — with one set to a reachable listener, applying the blackhole sends the https request to the closed port and the listener is never contacted.
  • No regression — the guard still passes with cfg.url at the loopback mock.
  • Still load-bearing — pointing cfg.url off-loopback turns it RED (obtain_proof blackholed), confirmed by a revert-check.

fmt and clippy -D warnings clean. @jatmn ready for another look.

@beardthelion
beardthelion requested a review from jatmn July 15, 2026 03:56

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crate:icaptcha icaptcha-client — proof-of-personhood captcha client kind:test Test coverage or harness

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants