Summary
Several gl CLI and MCP read commands build their NodeClient with no keypair and call the unsigned client.get(...) against node read endpoints that are visibility-gated (authorize_repo_read). For a private repo this returns 404, so the repo's own owner cannot read it through these commands. The node is correct (it denies an unauthenticated caller); the clients are wrong (they never present the owner's identity). This is not a data leak.
These endpoints were already gated before #94, so this is pre-existing and independent of PR #113. #113 fixed only the clients whose endpoints it newly gated (gl webhook list, gl protect list, gl repo replicas, and the replica/branch/info fetches in gl repo info / gl repo owner) and added NodeClient::get_maybe_signed (signs when an identity is present, anonymous otherwise) as the pattern to reuse.
Affected call sites (all unsigned get to a gated endpoint)
CLI:
crates/gl/src/repo.rs:499 — cmd_commits -> GET /api/v1/repos/{o}/{n}/commits
crates/gl/src/pr.rs:258 — cmd_list -> GET .../pulls
crates/gl/src/pr.rs:302,325,358 — cmd_view -> .../pulls/{n}, /reviews, /comments
crates/gl/src/pr.rs:390 — cmd_diff -> .../pulls/{n}/diff
MCP (crates/gl/src/mcp.rs):
:691 repo_get -> GET /api/v1/repos/{o}/{n}
:702 repo_commits -> .../commits
:829 pr_list, :841/:846 pr_view, :862 pr_diff
(The MCP repo_get/repo_commits/pr_* clients already hold the loaded keypair, so they only need the .get( -> .get_maybe_signed( switch.)
The node-side gates are confirmed on main: list_commits, list_prs, get_pr, get_pr_diff, list_reviews, list_comments, and get_repo all call authorize_repo_read.
Fix
Route each of these through get_maybe_signed and build the client with load_keypair_from_dir(dir.as_deref()).ok() (mirroring the #113 fixes), so public repos still work anonymously and a private repo's owner is authenticated. gl repo commits and the relevant pr subcommands already accept --dir; confirm each does and thread it where missing. Add signature-header assertions to the tests (the existing pattern in protect.rs / repo.rs tests).
Related
Summary
Several
glCLI and MCP read commands build theirNodeClientwith no keypair and call the unsignedclient.get(...)against node read endpoints that are visibility-gated (authorize_repo_read). For a private repo this returns 404, so the repo's own owner cannot read it through these commands. The node is correct (it denies an unauthenticated caller); the clients are wrong (they never present the owner's identity). This is not a data leak.These endpoints were already gated before #94, so this is pre-existing and independent of PR #113. #113 fixed only the clients whose endpoints it newly gated (
gl webhook list,gl protect list,gl repo replicas, and the replica/branch/info fetches ingl repo info/gl repo owner) and addedNodeClient::get_maybe_signed(signs when an identity is present, anonymous otherwise) as the pattern to reuse.Affected call sites (all unsigned
getto a gated endpoint)CLI:
crates/gl/src/repo.rs:499—cmd_commits->GET /api/v1/repos/{o}/{n}/commitscrates/gl/src/pr.rs:258—cmd_list->GET .../pullscrates/gl/src/pr.rs:302,325,358—cmd_view->.../pulls/{n},/reviews,/commentscrates/gl/src/pr.rs:390—cmd_diff->.../pulls/{n}/diffMCP (
crates/gl/src/mcp.rs)::691repo_get->GET /api/v1/repos/{o}/{n}:702repo_commits->.../commits:829pr_list,:841/:846pr_view,:862pr_diff(The MCP
repo_get/repo_commits/pr_*clients already hold the loaded keypair, so they only need the.get(->.get_maybe_signed(switch.)The node-side gates are confirmed on
main:list_commits,list_prs,get_pr,get_pr_diff,list_reviews,list_comments, andget_repoall callauthorize_repo_read.Fix
Route each of these through
get_maybe_signedand build the client withload_keypair_from_dir(dir.as_deref()).ok()(mirroring the #113 fixes), so public repos still work anonymously and a private repo's owner is authenticated.gl repo commitsand the relevantprsubcommands already accept--dir; confirm each does and thread it where missing. Add signature-header assertions to the tests (the existing pattern inprotect.rs/repo.rstests).Related