Skip to content

fix(icaptcha): return unsolved instead of blocking or overflowing - #444

Open
beardthelion wants to merge 1 commit into
mainfrom
fix/issue-345-icaptcha-stdin-overflow
Open

beardthelion wants to merge 1 commit into
mainfrom
fix/issue-345-icaptcha-stdin-overflow

Conversation

@beardthelion

@beardthelion beardthelion commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

obtain_proof could block forever on stdin().read_line when stdin was an open, silent non-TTY (a pipe an orchestrator or agent harness holds open), and the deterministic iCaptcha solvers evaluated service-controlled prompts with unchecked i64 arithmetic, which panics in debug builds and wraps to a wrong answer in release.

Motivation & context

Closes #345. The interactive prompt is the documented last resort (returns None when stdin isn't a usable interactive source), but it never checked whether stdin was a terminal, so the fallback itself was the hang. Separately, every literal in a challenge prompt can individually parse as i64 while the evaluation still overflows.

Kind of change

  • Bug fix
  • Feature
  • Security fix
  • Docs
  • Tests / CI
  • Refactor (no behavior change)
  • Breaking or protocol change (issue required first)

What changed

  • icaptcha-client: interactive_prompt checks IsTerminal before prompting and returns None on non-TTY stdin, so the caller surfaces the existing cannot-solve error.
  • icaptcha-client: solvers.rs uses checked_* arithmetic throughout (add/sub chains, algebra coefficient/constant/denominator/numerator including i64::MIN / -1, sequence diffs, geometric multiply, abs() at i64::MIN, and the isqrt_exact candidate square). Overflow returns None (unsolvable) rather than panicking or submitting a wrapped answer.
  • New end-to-end test (tests/icaptcha_stdin_e2e.rs) runs the real obtain_proof in a child process over real HTTP against a mocked iCaptcha service with stdin held open as a silent pipe, for both an unsolvable type and an overflowing arithmetic prompt; /v1/answer is pinned at zero calls so a wrapped answer would fail the test.
  • Solver overflow regression tests cover arithmetic, algebra, and sequence overflow classes plus boundary-adjacent positive cases.

How a reviewer can verify

cargo test -p icaptcha-client

Reverting the IsTerminal check makes the e2e block for the full 15s deadline; reverting checked_add to += panics the overflow test.

Before you request review

  • Scope is one logical change; no unrelated churn
  • cargo test -p icaptcha-client passes locally
  • New behavior is covered by tests (required for fixes)
  • cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings are clean
  • Commit titles use Conventional Commits (feat(...), fix(...), docs(...))
  • Docs / .env.example updated if behavior or config changed (or N/A)
  • Checked existing PRs so this isn't a duplicate (fix(icaptcha-client): parse GITLAWB_ICAPTCHA_INSECURE as truthy only (#227) #246 touches lib.rs hunks ending ~line 226; disjoint)

Protocol & signing impact

  • Touches DID / did:key, Ed25519 / RFC 9421 signatures, UCAN, ref certs, or P2P wire formats
  • Discussed in an issue before implementation
  • Backward-compatible with existing nodes and previously signed history

None: client-side challenge solving only; no wire format, signature, or API change.

Notes for reviewers

The gl-binary path through send_signed is not exercised end-to-end locally because resolve_solver_url deliberately refuses non-https advertised solver URLs (the SSRF guard); the child-process e2e drives the same obtain_proof gl calls via spawn_blocking.

Summary by CodeRabbit

  • Bug Fixes
    • Prevented interactive prompts from hanging when standard input is open but non-interactive.
    • Added safe handling for arithmetic, algebra, and sequence calculations that exceed supported numeric limits.
    • Overflowing or otherwise unsolvable challenges now fail cleanly instead of producing incorrect results or causing a crash.
    • Improved reliability when processing challenges through silent or redirected input streams.

interactive_prompt waited on stdin().read_line even when stdin was an
open, silent non-TTY (an orchestrator holding the pipe open), which
blocked obtain_proof forever. Check IsTerminal first and return None so
the caller surfaces the "couldn't auto-solve" error.

The deterministic solvers evaluated prompts with unchecked i64
arithmetic; service-controlled literals could push add/sub/mul/div/abs
past the range, panicking in debug builds or wrapping to a wrong answer
in release. Use checked arithmetic throughout and return None on
overflow.

Fixes #345
@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Essentials

Run ID: ad631956-39f1-4955-ac86-ad8cf60f09db

📥 Commits

Reviewing files that changed from the base of the PR and between bfc44f9 and 8eb62e6.

📒 Files selected for processing (3)
  • crates/icaptcha-client/src/lib.rs
  • crates/icaptcha-client/src/solvers.rs
  • crates/icaptcha-client/tests/icaptcha_stdin_e2e.rs

Included review availability: 4 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.


📝 Walkthrough

Walkthrough

The iCaptcha client now skips prompting on non-terminal stdin and uses checked arithmetic throughout its deterministic solvers. Regression tests cover open pipes, overflow boundaries, unsolvable prompts, clean process termination, and zero answer submissions.

Changes

iCaptcha hardening

Layer / File(s) Summary
Non-TTY prompt handling
crates/icaptcha-client/src/lib.rs
interactive_prompt returns None when stdin is not a terminal. A subprocess test verifies that an open, silent pipe does not block.
Checked solver arithmetic
crates/icaptcha-client/src/solvers.rs
Arithmetic, algebra, sequence, alternating-sign, and square calculations return None on overflow. Tests cover overflow and boundary cases.
End-to-end failure validation
crates/icaptcha-client/tests/icaptcha_stdin_e2e.rs
Child-process tests verify clean termination for unsolvable anagram and overflowing arithmetic challenges, with no panic output or answer submissions.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: kevincodex1

Merge Risk: ⚪ Minimal · up to 8eb62

The non-TTY prompt path and checked solver arithmetic are covered without a retained merge-blocking issue.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description is complete and follows the repository template. It explains the two fixes, motivation, concrete changes, verification steps, test coverage, and protocol impact.
Title check ✅ Passed The title clearly and concisely identifies the main changes: preventing blocking and handling overflow by returning unsolved results.
Linked Issues check ✅ Passed The changes satisfy the coding requirements in issue #345. interactive_prompt checks stdin().is_terminal() and returns None for non-TTY input in crates/icaptcha-client/src/lib.rs. `crates/icap…
Out of Scope Changes check ✅ Passed The changes stay within issue #345. The added tests directly verify non-TTY behavior, solver overflow behavior, clean errors, and the absence of answer submissions. The solver changes support the requ…
Docstring Coverage ✅ Passed Docstring coverage is 93.33% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 3 files.
✨ 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 fix/issue-345-icaptcha-stdin-overflow

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

@beardthelion
beardthelion requested a review from jatmn September 11, 2026 19:53
@beardthelion beardthelion added the kind:bug Defect fix — wrong or unsafe behavior label Sep 11, 2026
@greptile-apps

greptile-apps Bot commented Sep 11, 2026

Copy link
Copy Markdown

Greptile Summary

This PR makes iCaptcha failure handling terminate cleanly rather than blocking, panicking, or submitting a wrapped answer.

  • Rejects interactive fallback when stdin is not a terminal.
  • Uses checked arithmetic throughout deterministic arithmetic, algebra, and sequence solving.
  • Adds boundary regression tests and a child-process HTTP test for silent piped stdin.

Confidence Score: 5/5

The PR appears safe to merge, with the non-terminal and arithmetic-overflow failure paths handled consistently and covered by focused regressions.

No actionable failure remains: unsupported or overflowing challenges now return the existing unsolved error without reading non-terminal stdin or submitting overflow-derived answers.

Important Files Changed

Filename Overview
crates/icaptcha-client/src/lib.rs Guards the interactive fallback with IsTerminal and adds a held-open-pipe regression test.
crates/icaptcha-client/src/solvers.rs Replaces overflow-prone solver arithmetic with checked operations and adds boundary coverage.
crates/icaptcha-client/tests/icaptcha_stdin_e2e.rs Exercises real challenge retrieval and unsolved handling in a child with silent non-terminal stdin.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Fetch iCaptcha challenge] --> B[Try deterministic solver]
  B -->|Solved safely| C[Submit answer]
  B -->|Unsupported or overflow| D{stdin is a terminal?}
  D -->|Yes| E[Prompt interactively]
  D -->|No| F[Return cannot-solve error]
Loading

Reviews (1): Last reviewed commit: "fix(icaptcha): return unsolved instead o..." | Re-trigger Greptile

@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.

LGMT

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

Labels

kind:bug Defect fix — wrong or unsafe behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

icaptcha-client: interactive_prompt hangs on non-interactive stdin, and the solvers overflow i64 on service-supplied prompts

2 participants