Skip to content

test(gl): add tests for iCaptcha transparent retry flow (#167)#168

Merged
kevincodex1 merged 21 commits into
Gitlawb:mainfrom
Gravirei:fix/issue-167-add-icaptcha-client-tests
Jul 10, 2026
Merged

test(gl): add tests for iCaptcha transparent retry flow (#167)#168
kevincodex1 merged 21 commits into
Gitlawb:mainfrom
Gravirei:fix/issue-167-add-icaptcha-client-tests

Conversation

@Gravirei

@Gravirei Gravirei commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Add comprehensive tests for the iCaptcha transparent solve-and-retry flow in the gl CLI HTTP client, covering the critical registration path that was blocking new users.

Motivation & context

Closes #167

Node v0.5.0 requires iCaptcha proof for registration, but the released gl v0.3.8 predates the icaptcha-client code. The fix existed on main (transparent solve-and-retry in crates/gl/src/http.rs, crates/icaptcha-client) but lacked test coverage for the retry flow.

Kind of change

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

What changed

  • crates/icaptcha-client/src/lib.rs: Added #[cfg(test)] support in is_https to allow localhost/127.0.0.1 URLs in test builds, enabling mockito-based integration tests for the full iCaptcha retry path.
  • crates/gl/src/http.rs: Added 16 tests:
    • 7 unit tests for icaptcha_cfg (header parsing, defaults, keypair required)
    • 4 tests for send_once (proof header attachment, signing)
    • 3 tests for send_signed (non-iCaptcha 403 passthrough, success, 405 handling)
    • 2 full integration tests using dual mock servers (node + iCaptcha): happy path retry to 201, and retry exhaustion returning 403

How a reviewer can verify

cargo test -p gl -p icaptcha-client
cargo clippy -p gl -p icaptcha-client
cargo fmt -p gl -p icaptcha-client --check

All 266 tests in gl and 12 tests in icaptcha-client pass with no warnings.

Before you request review

  • Scope is one logical change; no unrelated churn
  • cargo test --workspace passes locally (node DB-dependent tests are pre-existing PG auth failures)
  • 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 (test(gl): ...)
  • Docs / .env.example updated if behavior or config changed (or N/A)
  • Checked existing PRs so this isn't a duplicate

Notes for reviewers

The two send_signed integration tests (send_signed_solves_icaptcha_and_retries_to_success, send_signed_returns_403_after_icaptcha_retries_exhausted) use std::env::set_var for GITLAWB_ICAPTCHA_URL. An RAII guard (IcaptchaEnv) ensures cleanup. Tests use #[tokio::test] default single-threaded runtime, so env var races are not a concern.

Summary by CodeRabbit

  • Bug Fixes
    • Profile updates now save/persist content under the correct identifier, improving reliability.
    • Improved iCaptcha and signed request handling: captcha proofs and signing headers are applied consistently, and retry behavior correctly follows iCaptcha challenge outcomes.
    • In insecure mode, HTTP loopback endpoints (localhost/127.0.0.1) are supported, with stricter origin matching (including port) to avoid trusting an unintended solver.

Gravirei added 14 commits June 30, 2026 19:52
Gitlawb#126)

The IPFS visibility gate used withheld_blob_oids (a deny-set enumerating
only reachable blobs), so a dangling/unreachable blob was absent from the
set and served in cleartext to anonymous callers. Flip to an allowed-set
(allowed_blob_set_for_caller) that enumerates reachable blobs the caller
may read: a dangling blob has no path, is never in the set, and 404s.
Move store::read_object before the allowed_blob_set_for_caller
spawn_blocking call so random-CID spray against repos with
path-scoped rules cannot trigger full-history git walks on
repos that don't carry the object.
…tion

✓ P3 blocker fixed: cargo fmt applied — the format gate will pass.

  ✓ P3 cleanup resolved: withheld_blob_oids is still used by replication code in repos.rs, so it stays.

  • P2 follow-up: Tree/commit disclosure tracked in Gitlawb#135 — out of scope here.
Copilot AI review requested due to automatic review settings July 9, 2026 14:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 9, 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: 88736128-15ef-4542-aca3-a1e9831d2ea1

📥 Commits

Reviewing files that changed from the base of the PR and between edaf238 and 58769e7.

📒 Files selected for processing (2)
  • crates/gl/src/http.rs
  • crates/icaptcha-client/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/icaptcha-client/src/lib.rs
  • crates/gl/src/http.rs

📝 Walkthrough

Walkthrough

This PR tightens iCaptcha solver trust to exact origins, including ports, and adds NodeClient tests for configuration, signing, proof retries, and retry exhaustion. It also removes a redundant borrow from profile pin-name formatting.

Changes

iCaptcha Trust and Client Behavior

Layer / File(s) Summary
Exact-origin iCaptcha trust
crates/icaptcha-client/src/lib.rs
URL trust parses schemes and normalized origins; insecure mode permits loopback HTTP, while advertised solver URLs and API-key trust require exact origin matches including ports.
NodeClient configuration and request tests
crates/gl/src/http.rs
Adds helpers and tests for iCaptcha header parsing, proof attachment, RFC 9421 signing, and response passthrough behavior.
iCaptcha solve and retry coverage
crates/gl/src/http.rs
Mocks challenge and answer endpoints to verify successful proof retries and exhausted retry behavior.
Profile pin-name formatting cleanup
crates/gitlawb-node/src/api/profiles.rs
Removes a redundant borrow when formatting the Pinata profile pin object name.

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

Sequence Diagram(s)

sequenceDiagram
    participant GlClient as gl NodeClient
    participant Node as gitlawb-node
    participant Icaptcha as iCaptcha Server

    GlClient->>Node: send_signed(request)
    Node-->>GlClient: 403 iCaptcha challenge
    GlClient->>Icaptcha: request challenge
    Icaptcha-->>GlClient: challenge
    GlClient->>Icaptcha: submit answer
    Icaptcha-->>GlClient: proof
    GlClient->>Node: retry with x-icaptcha-proof
    Node-->>GlClient: successful response
Loading

Suggested labels: sev:medium, subsystem:identity

Suggested reviewers: jatmn, kevincodex1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The gitlawb-node profile change is unrelated to the iCaptcha test work and appears to be incidental churn. Remove the gitlawb-node/profile borrow tweak or explain why it is required for the iCaptcha test work.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding iCaptcha retry-flow tests.
Description check ✅ Passed The PR description follows the template and covers summary, motivation, change type, changed files, verification, and review checklist.
Linked Issues check ✅ Passed The changes address #167 by covering the transparent iCaptcha solve-and-retry flow and the localhost test support needed to validate it.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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.

@beardthelion beardthelion added crate:gl gl — the contributor CLI crate:node gitlawb-node — the serving node and REST API kind:test Test coverage or harness labels Jul 9, 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.

Thanks for adding coverage here. The blocker is that the two "full integration" tests don't exercise the iCaptcha retry path they're named for — they fall through to the real production service — so the transparent-retry flow has no real coverage.

I verified by execution: the mockito iCaptcha server is never contacted, and the solve resolves to DEFAULT_URL (https://icaptcha.gitlawb.com) and makes a live network call. Root cause: is_https gates the localhost allowance behind #[cfg(test)], but cfg(test) is not set for icaptcha-client when it's compiled as gl's dependency, so that branch is compiled out during cargo test -p gl. With is_https(http://127.0.0.1:port) false, resolve_solver_url drops both the operator env URL and the advertised header URL and falls back to DEFAULT_URL. Pointing DEFAULT_URL at a bogus host makes both tests fail with a DNS error on {DEFAULT_URL}/v1/challenge; removing the relaxation entirely leaves the tests passing, confirming it's inert.

Findings

  • [P1] Make the integration tests exercise the mock, not the live service. crates/gl/src/http.rs (send_signed_solves_icaptcha_and_retries_to_success, send_signed_returns_403_after_icaptcha_retries_exhausted). Both resolve the solve to https://icaptcha.gitlawb.com and make a real network call — the mock's /v1/challenge and /v1/answer are never hit, and with DEFAULT_URL pointed at a bogus host both fail with a DNS error. So they're network-dependent (fail in a no-egress CI, hit production on every run) and the retry flow is uncovered; the exhaustion test even panics on the live-call error before its assert_eq!(403), so retry-exhaustion is untested. The #[cfg(test)] approach can't work because cfg(test) doesn't propagate to a dependency. Test the localhost solve inside icaptcha-client's own #[cfg(test)] module instead, where the relaxation is live — I confirmed the localhost path is reachable there; alternatively inject the base URL / reqwest client into gl's solve path.

  • [P2] Assert the mocks and the retry count. crates/gl/src/http.rs. Both tests bind their mocks with _ and never call .assert(); the exhaustion test comments "3 node calls" but sets no .expect(3). That silence is exactly why the live-service fallthrough passes unnoticed — add .assert()/.expect(N) so an unreached mock fails loudly.

  • [P2] Drop or rework the is_https #[cfg(test)] relaxation. crates/icaptcha-client/src/lib.rs. It's inert where it's meant to help (removing it changes no test) and nothing depends on it. It does not reach release builds — I confirmed a non-test release build rejects a localhost URL and falls back to DEFAULT_URL — so it's not a security hole, just dead code that implies coverage which isn't there.

  • [P3] The clippy borrow fix in crates/gitlawb-node/src/api/profiles.rs is unrelated to a test(gl) PR and duplicates the identical one-liner already in #156 and #134; drop it here to avoid a conflict/no-op once one of those merges.

Happy to re-review once the tests drive the mock.

@Gravirei Gravirei requested a review from beardthelion July 9, 2026 16:53

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/icaptcha-client/src/lib.rs (1)

84-105: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Doc comment overstates the safety of this gate; the insecure branch is compiled into production.

Two small points on is_https:

  1. The doc says this avoids "shipping the backdoor to production", but the check is runtime env-gated (GITLAWB_ICAPTCHA_INSECURE), not cfg(test)-gated, so the code path is present in release binaries and merely dormant. Consider rewording so maintainers don't assume it's compiled out.
  2. The insecure branch matches on host only and never asserts scheme() == "http", so any non-https scheme (e.g. ftp://localhost) would also be trusted when the flag is set. Tightening to http closes that gap.
♻️ Optional hardening
     if std::env::var_os("GITLAWB_ICAPTCHA_INSECURE").is_some()
         && parsed
             .as_ref()
-            .map(|p| p.host_str() == Some("127.0.0.1") || p.host_str() == Some("localhost"))
+            .map(|p| {
+                p.scheme() == "http"
+                    && (p.host_str() == Some("127.0.0.1") || p.host_str() == Some("localhost"))
+            })
             .unwrap_or(false)
     {
         return true;
     }
🤖 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/icaptcha-client/src/lib.rs` around lines 84 - 105, Update the
`is_https` doc comment to avoid implying the insecure path is compiled out of
production; clarify that `GITLAWB_ICAPTCHA_INSECURE` only enables a runtime
escape hatch. Also tighten the insecure branch in `is_https` so it only trusts
`http://localhost` and `http://127.0.0.1`, not any non-https scheme, by
explicitly checking the parsed URL’s scheme alongside the host.
🤖 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.

Inline comments:
In `@crates/gl/src/http.rs`:
- Around line 537-538: The fixed hit count is being asserted on the existing
mock after registration, but mockito expectations are set when the mock is
created. Update MockIcaptcha::new to register the challenge and answer mocks
with an expectation of 2 hits, or recreate the mock with the correct count
before the two requests are made, so the assertion matches the actual request
sequence.

---

Nitpick comments:
In `@crates/icaptcha-client/src/lib.rs`:
- Around line 84-105: Update the `is_https` doc comment to avoid implying the
insecure path is compiled out of production; clarify that
`GITLAWB_ICAPTCHA_INSECURE` only enables a runtime escape hatch. Also tighten
the insecure branch in `is_https` so it only trusts `http://localhost` and
`http://127.0.0.1`, not any non-https scheme, by explicitly checking the parsed
URL’s scheme alongside the host.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6f6f6b73-1d8f-4622-841e-f4183d09cc89

📥 Commits

Reviewing files that changed from the base of the PR and between 26bc3f6 and d98e202.

📒 Files selected for processing (3)
  • crates/gitlawb-node/src/api/profiles.rs
  • crates/gl/src/http.rs
  • crates/icaptcha-client/src/lib.rs

Comment thread crates/gl/src/http.rs Outdated
@beardthelion beardthelion dismissed their stale review July 9, 2026 19:49

Superseded by 5698c2e: the two blocking findings (tests hitting the live iCaptcha service, no mock assertions) are resolved. Re-reviewing the new head.

beardthelion
beardthelion previously approved these changes Jul 9, 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.

Approving. The blocker from the last round is genuinely fixed: the two integration tests now exercise the iCaptcha retry flow against their mock instead of falling through to the live service. I confirmed it by poisoning DEFAULT_URL to a bogus host and re-running — both tests stay green, so the mock is actually consumed and no live call happens; removing the new GITLAWB_ICAPTCHA_INSECURE branch makes them fail with a DNS error on that poisoned host, so the flag is load-bearing. The .expect(N) + .assert() on every mock closes the earlier no-assertions gap. The runtime flag is contained: with it set, a hostile x-icaptcha-url: http://127.0.0.1 (or 169.254.169.254 / [::1] / a userinfo trick) is still rejected and falls back, and the API key stays with the operator origin — I drove those cases through resolve_solver_url and IcaptchaCfg::new.

Three small non-blocking follow-ups:

Findings

  • [P3] Tighten the flag's presence check — crates/icaptcha-client/src/lib.rs:97. std::env::var_os("GITLAWB_ICAPTCHA_INSECURE").is_some() treats any value as enabled, so GITLAWB_ICAPTCHA_INSECURE=0 or =false still turns the insecure loopback path on. A truthy check (== "1" / parse a bool) would honor disable-intent.
  • [P3] The relaxation is now reachable in a non-test build, not just tests — crates/icaptcha-client/src/lib.rs:90-104. I verified it's inert without a localhost operator URL (a hostile node can't reach it, no key leaks), so this is fine as a default-off escape hatch. If you'd rather keep insecure code out of the shipped binary entirely, injecting the base URL/client at a test seam in gl would avoid the runtime flag.
  • [P3] crates/gitlawb-node/src/api/profiles.rs — the clippy borrow tweak is unrelated to this PR and is the same one-liner as #169; it'll no-op once either merges.

Core is solid. @kevincodex1 good to merge once you're happy with it.

@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 two issues that need to be addressed before this is ready.

Findings

  • [P2] Keep a loopback test origin from trusting a different loopback port
    crates/icaptcha-client/src/lib.rs:97
    With GITLAWB_ICAPTCHA_INSECURE=1, an operator URL of http://localhost:3000, and GITLAWB_ICAPTCHA_API_KEY configured, a hostile node can advertise x-icaptcha-url: http://localhost:9000. The new branch accepts both URLs, while resolve_solver_url allowlists and marks the selected endpoint key-trusted using only host_str; it therefore chooses :9000 and sends the operator's bearer key there. Compare normalized origins (including the effective port) before honoring an insecure advertised URL, or keep advertised HTTP URLs untrusted, and add the distinct-port regression case.

  • [P2] Assert that the retry uses the proof produced by the solver
    crates/gl/src/http.rs:503
    The success-path node mock accepts any x-icaptcha-proof, so this test remains green if send_signed substitutes a stale or unrelated nonempty token instead of the mock.proof returned by the iCaptcha answer mock. Match x-icaptcha-proof: mock.proof here so the new full-flow test makes the solve-to-retry value transfer load-bearing.

@kevincodex1

Copy link
Copy Markdown
Contributor

hello @Gravirei thanks for the contribution please address @jatmn comments

@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/icaptcha-client/src/lib.rs (1)

432-453: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Serialize this env-var test. Mirror the ICAPTCHA_ENV_LOCK/IcaptchaEnv pattern here: GITLAWB_ICAPTCHA_INSECURE is process-global, so this test can race with other parallel unit tests that call is_https and flake.

🤖 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/icaptcha-client/src/lib.rs` around lines 432 - 453, Serialize this
environment-variable test using the existing ICAPTCHA_ENV_LOCK/IcaptchaEnv
pattern. Update rejects_insecure_advertised_url_on_different_port to acquire the
shared lock and use the guard for setting and restoring
GITLAWB_ICAPTCHA_INSECURE, removing the local _EnvGuard implementation while
preserving the test assertions.
🤖 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/icaptcha-client/src/lib.rs`:
- Around line 432-453: Serialize this environment-variable test using the
existing ICAPTCHA_ENV_LOCK/IcaptchaEnv pattern. Update
rejects_insecure_advertised_url_on_different_port to acquire the shared lock and
use the guard for setting and restoring GITLAWB_ICAPTCHA_INSECURE, removing the
local _EnvGuard implementation while preserving the test assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 39dfdd7c-4690-4df1-94d4-2f903a36a319

📥 Commits

Reviewing files that changed from the base of the PR and between d98e202 and edaf238.

📒 Files selected for processing (2)
  • crates/gl/src/http.rs
  • crates/icaptcha-client/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/gl/src/http.rs

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

Thanks for the update. I rechecked the changed paths and found one issue that still needs to be addressed.

Findings

  • [P3] Restore the inherited iCaptcha test environment after each mock test
    crates/gl/src/http.rs:428
    crates/icaptcha-client/src/lib.rs:437
    Both new guards replace process-wide iCaptcha variables and then unconditionally remove them on drop. A cargo test run launched with GITLAWB_ICAPTCHA_URL or GITLAWB_ICAPTCHA_INSECURE set therefore loses its original configuration after these tests, which can make later in-process tests (including consumers of the configured URL) order-dependent. Save the prior OsString values before installing the mock settings, then restore each value on drop (removing it only when it was originally absent).

…itional remove; share lock in icaptcha-client tests
@Gravirei Gravirei requested a review from jatmn July 10, 2026 06:10

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

Thanks for the update. I rechecked the changed paths and found one issue that still needs to be addressed.

Findings

  • [P2] Make the negative send_once checks reject the headers they prohibit
    crates/gl/src/http.rs:305
    send_once_omits_proof_header_when_not_provided and send_once_does_not_sign_when_no_keypair create unconstrained Mockito handlers, so both tests still receive 200 if send_once starts attaching x-icaptcha-proof with None or emits Signature, Signature-Input, and Content-Digest without a keypair. Match those headers with mockito::Matcher::Missing so the newly added negative cases actually protect the unsigned/no-proof contract.

@Gravirei Gravirei requested review from beardthelion and jatmn July 10, 2026 08:10
@beardthelion beardthelion dismissed their stale review July 10, 2026 13:18

Stale: head advanced to 58769e7 after this approval, and jatmn found issues on the intervening heads. Dismissing and re-reviewing the current head.

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

Approving at 58769e7. jatmn's two open findings are both addressed here, and I confirmed each holds under a break rather than just that the suite is green.

  • The negative send_once tests now protect the contract: attaching x-icaptcha-proof when none was provided, or emitting the signature headers with no keypair, makes each test fail (the Matcher::Missing matchers reject the request). Before this they passed regardless — that was the P2.
  • The retry integration tests exercise the real path: disabling the retry drops send_signed_solves_icaptcha_and_retries_to_success to a 403, and raising the retry cap breaks the exhaustion test's call count. A retry-exhausted 403 is returned to the caller (register reads !status.is_success() and bails), and an unsolvable challenge surfaces as an Err, not a success.
  • The env guards now restore an inherited GITLAWB_ICAPTCHA_URL/INSECURE on drop instead of deleting it (the P3 from the prior round).

INV-8 holds across the denial paths: retry-exhausted → Ok(403) surfaced, unsolvable → Err, no iCaptcha headers → Ok(403) surfaced. The loop is capped and origin trust compares scheme+host+port, so a hostile advert or a different loopback port can't redirect the proof or key.

Three optional follow-ups, none blocking:

  • [P3] The status half of the "only a 403 retries" gate isn't pinned — the header gate short-circuits it, so a non-403 carrying x-icaptcha-* isn't exercised.
  • [P3] No end-to-end test for the level-only advert (x-icaptcha-level present, x-icaptcha-url absent).
  • [P3] A panic while holding the env lock surfaces a sibling test as a poison error rather than its real assertion; lock().unwrap_or_else(|e| e.into_inner()) fixes the ergonomics.

One housekeeping item: the base is behind main and the one-line profiles.rs change is already identical in main, so please rebase before merge — it resolves to a no-op, no gate dropped.

@kevincodex1 good to merge once rebased.

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

lgtm

@kevincodex1 kevincodex1 merged commit ad7c2b2 into Gitlawb:main Jul 10, 2026
10 checks passed
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 crate:node gitlawb-node — the serving node and REST API kind:test Test coverage or harness

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Registration hard-blocked for new users: node v0.5.0 requires iCaptcha proof but released gl v0.3.8 predates icaptcha-client

5 participants