Skip to content

gl: add --icaptcha-proof flag to register command#193

Open
jilt wants to merge 1 commit into
Gitlawb:mainfrom
jilt:feat/gl-icaptcha-proof-register
Open

gl: add --icaptcha-proof flag to register command#193
jilt wants to merge 1 commit into
Gitlawb:mainfrom
jilt:feat/gl-icaptcha-proof-register

Conversation

@jilt

@jilt jilt commented Jul 12, 2026

Copy link
Copy Markdown

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.

Summary

Add an optional --icaptcha-proof / GITLAWB_ICAPTCHA_PROOF argument to gl register that 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

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

What changed

crates/gl/src/register.rs

  • Added icaptcha_proof: Option field to RegisterArgs
  • Changed the POST call from client.post(...) to client.post_with_proof(...) to attach the proof header

crates/gl/src/http.rs

  • Added pub async fn post_with_proof(...) method to NodeClient
  • Refactored send_signed() to call a new send_signed_with_proof() helper that accepts an optional initial proof
  • The existing automatic iCaptcha retry flow remains intact for 403 challenges

How a reviewer can verify

replace the crates, fmt and build then run gl register --icaptcha-proof "your-proof" a new proof from the api/register/ endpoint (i used postman to get the process done)

Before you request review

  • Scope is one logical change; no unrelated churn
  • cargo test --workspace 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

Notes for reviewers

simplify the process of registering new agents without touching your codebase

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.
@github-actions github-actions Bot added needs-issue PR has no linked issue needs-tests Source changed without accompanying tests (advisory) labels Jul 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the contribution. A couple of things will help us review this faster:

  • Link the issue this addresses (Closes #123). For protocol changes, open an issue first.
  • This changes Rust source but no tests changed. Tests are required for fixes and strongly encouraged for features.

See CONTRIBUTING.md. Update the PR and these notes will clear automatically.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

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

Changes

iCaptcha registration support

Layer / File(s) Summary
Proof-aware signed HTTP requests
crates/gl/src/http.rs
NodeClient adds post_with_proof, and signed requests initialize proof state from the optional input before using the existing retry flow.
Registration proof wiring and validation
crates/gl/src/register.rs
RegisterArgs exposes the proof option, /api/register forwards it, and registration tests initialize the new field.

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
Loading

Possibly related issues

Possibly related PRs

  • Gitlawb/node#108 — Adds server-side iCaptcha header verification corresponding to this client-side proof submission.
  • Gitlawb/node#168 — Covers iCaptcha proof attachment and signed-request solve-and-retry behavior in crates/gl/src/http.rs.

Suggested labels: kind:feature, crate:gl

Suggested reviewers: jatmn, beardthelion, kevincodex1

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly describes the main change: adding an iCaptcha proof flag for the register command.
Description check ✅ Passed The description covers the summary, motivation, changed files, verification steps, and checklist items required by the template.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/gl/src/register.rs (1)

148-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test that verifies the proof header is forwarded.

All three existing tests pass icaptcha_proof: None, so no test exercises the new post_with_proof path with an actual proof. A mockito test asserting the x-icaptcha-proof header is present when icaptcha_proof is Some(...) 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

📥 Commits

Reviewing files that changed from the base of the PR and between ad7c2b2 and d454de4.

📒 Files selected for processing (2)
  • crates/gl/src/http.rs
  • crates/gl/src/register.rs

@github-actions github-actions Bot removed the needs-issue PR has no linked issue label Jul 12, 2026
@beardthelion beardthelion added the crate:gl gl — the contributor CLI label Jul 12, 2026

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

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 new post_with_proof -> send_signed_with_proof(initial_proof) branch ships with no coverage: all three register fixtures pass icaptcha_proof: None, and every http.rs test drives send_signed (the None path), so nothing exercises a Some(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 existing test_register_success_saves_ucan setup:

    #[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-proof flag. crates/gl/src/register.rs:20 — the field carries #[arg(long, env = "GITLAWB_ICAPTCHA_PROOF")] but no /// doc comment, unlike every sibling in RegisterArgs. clap renders the field doc as the flag's help text, so gl register --help lists --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 as failed 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.

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

Labels

crate:gl gl — the contributor CLI needs-tests Source changed without accompanying tests (advisory)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants