gl: add --icaptcha-proof flag to register command#193
Conversation
This allows users to provide a pre-obtained iCaptcha proof token when registering with a node, sent as the x-icaptcha-proof header on the initial POST /api/register request. Usage: gl register --icaptcha-proof "<token>" GITLAWB_ICAPTCHA_PROOF="<token>" gl register The existing automatic iCaptcha retry flow (403 -> solve -> retry) remains unchanged and is still available if no initial proof is provided.
|
Thanks for the contribution. A couple of things will help us review this faster:
See CONTRIBUTING.md. Update the PR and these notes will clear automatically. |
📝 WalkthroughWalkthroughRegistration now accepts an optional iCaptcha proof from CLI or environment configuration and sends it through a proof-aware signed POST flow. Existing iCaptcha challenge detection, solving, and retry behavior remains available. ChangesiCaptcha registration support
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant CLI
participant RegisterArgs
participant NodeClient
participant NodeAPI
CLI->>RegisterArgs: Read icaptcha proof
RegisterArgs->>NodeClient: post_with_proof(/api/register, body, proof)
NodeClient->>NodeAPI: Send signed POST with proof
NodeAPI-->>NodeClient: Return registration response or iCaptcha challenge
NodeClient->>NodeAPI: Solve challenge and retry when required
Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/gl/src/register.rs (1)
148-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test that verifies the proof header is forwarded.
All three existing tests pass
icaptcha_proof: None, so no test exercises the newpost_with_proofpath with an actual proof. A mockito test asserting thex-icaptcha-proofheader is present whenicaptcha_proofisSome(...)would protect this new feature path against regressions.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/gl/src/register.rs` around lines 148 - 156, Add a register test near the existing run/RegisterArgs tests that sets icaptcha_proof to Some(...) and configures the mock server to assert the x-icaptcha-proof header value, thereby exercising the post_with_proof path while preserving the existing no-proof coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@crates/gl/src/register.rs`:
- Around line 148-156: Add a register test near the existing run/RegisterArgs
tests that sets icaptcha_proof to Some(...) and configures the mock server to
assert the x-icaptcha-proof header value, thereby exercising the post_with_proof
path while preserving the existing no-proof coverage.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b6f3668d-c02b-4b0a-bbe5-e4396b941cef
📒 Files selected for processing (2)
crates/gl/src/http.rscrates/gl/src/register.rs
beardthelion
left a comment
There was a problem hiding this comment.
Reviewed the client change end to end against a mock node, driving both the granted and the denied/hostile paths. The core is sound and the trust boundary is respected: a pre-supplied proof rides only the first request and does not change the retry budget (1 initial + MAX_ICAPTCHA_RETRIES), a stale token is discarded and re-solved rather than looped, a malformed proof value is rejected at header build instead of being sent, and a bogus proof grants nothing the automatic solve path doesn't since the node re-verifies the iCaptcha signature and the sub/DID binding. Requesting changes for one missing test on the new path plus two minor cleanups; none of these are correctness or security blockers.
What I verified by execution (both directions): valid proof forwards on the first request with zero solves; a bogus proof against an always-403 node stays bounded at exactly 3 requests / 2 solves, identical to the no-proof path; the retry carries the freshly solved proof, not the stale user token; Some("") sends a present-but-empty header (distinct from the omitted None path); and CR/LF/NUL in the token fail with builder error: failed to parse header value rather than being sent.
Findings
-
[P3] Add a test that the proof is forwarded on the first request.
crates/gl/src/register.rs:57/crates/gl/src/http.rs:119— the newpost_with_proof->send_signed_with_proof(initial_proof)branch ships with no coverage: all three register fixtures passicaptcha_proof: None, and everyhttp.rstest drivessend_signed(theNonepath), so nothing exercises aSome(proof)value reaching the first request. A regression that dropped or mis-threaded the initial proof would stay green. A drop-in that mirrors the existingtest_register_success_saves_ucansetup:#[tokio::test] async fn register_forwards_icaptcha_proof_header() { let dir = TempDir::new().unwrap(); write_identity(&dir); let mut server = mockito::Server::new_async().await; let m = server .mock("POST", "/api/register") .match_header("x-icaptcha-proof", "pre.solved.token") .with_status(200) .with_header("content-type", "application/json") .with_body(r#"{"message":"Welcome","ucan":"eyJhbGci.test.token","trust_score":0.5,"expires":"2026-12-31"}"#) .expect(1) .create_async() .await; run(RegisterArgs { node: server.url(), capabilities: vec!["git:push".to_string()], model: None, dir: Some(dir.path().to_path_buf()), icaptcha_proof: Some("pre.solved.token".to_string()), }) .await .unwrap(); m.assert(); assert!(dir.path().join("ucan.json").exists()); }
I ran this against the branch and it passes; flipping the matched header value makes it fail, so it is load-bearing.
-
[P3] Document the
--icaptcha-proofflag.crates/gl/src/register.rs:20— the field carries#[arg(long, env = "GITLAWB_ICAPTCHA_PROOF")]but no///doc comment, unlike every sibling inRegisterArgs. clap renders the field doc as the flag's help text, sogl register --helplists--icaptcha-proof <ICAPTCHA_PROOF>with an empty description. One line describing that it accepts a pre-obtained iCaptcha proof token fixes it. -
[P3] Don't report a malformed proof as a connection failure.
crates/gl/src/register.rs:59— a token containing bytes outside the header grammar fails at header build, but.context("failed to connect to node")surfaces it asfailed to connect to node: ... builder error: failed to parse header value, which points the user at their network rather than their input. Reachable now that the token is user-supplied. Either validate/trim the token at the CLI boundary or give this call site a context that doesn't assert a connection error.
The rest checks out: post/put/delete are behaviorally unchanged (they delegate with None), the full gl suite stays green, and the PR body's claim that the automatic retry flow is unchanged is accurate.
This allows users to provide a pre-obtained iCaptcha proof token when registering with a node, sent as the x-icaptcha-proof header on the initial POST /api/register request.
Usage:
gl register --icaptcha-proof "<token>"GITLAWB_ICAPTCHA_PROOF="<token>" gl registerThe existing automatic iCaptcha retry flow (403 -> solve -> retry) remains unchanged and is still available if no initial proof is provided.
Summary
Add an optional
--icaptcha-proof / GITLAWB_ICAPTCHA_PROOFargument togl registerthat sends the proof as the x-icaptcha-proof header on the initial /api/register request.This is a minimal compatibility fix for nodes running with icaptcha enforcement, without yet implementing the full automatic challenge/solve/retry flow.
Motivation & context
When registering an agent with a node that has iCaptcha enforcement enabled, the current gl register command has no way to provide a pre-obtained proof token. This forces users to either:
Disable iCaptcha on the node (reduces security), or
Manually modify the CLI source to add the header
issue #190
Kind of change
What changed
crates/gl/src/register.rscrates/gl/src/http.rsHow a reviewer can verify
replace the crates, fmt and build then run
gl register --icaptcha-proof "your-proof"a new proof from theapi/register/endpoint (i used postman to get the process done)Before you request review
cargo test --workspacepasses locallycargo fmt --allandcargo clippy --workspace --all-targets -- -D warningsare cleanfeat(...),fix(...),docs(...)).env.exampleupdated if behavior or config changed (or N/A)Notes for reviewers
simplify the process of registering new agents without touching your codebase