Skip to content

gl pr can only address your own repos: eight subcommands hard-code the caller's DID and silently build a broken URL #353

Description

@beardthelion

gl pr create can target another user's repo. The other eight subcommands cannot, and the failure is
silent rather than an error.

Only create has the flag (crates/gl/src/pr.rs:34-36), and its own help text states the intent:

/// Repo owner DID short key (defaults to your DID — use when opening a PR on another user's repo)
#[arg(long)]
owner: Option<String>,

and only create has the resolution chain (pr.rs:220-223):

// Priority: --owner flag > git remote origin > caller's own DID
let owner = owner_override.or_else(detect_remote_owner).unwrap_or_else(|| resolve_owner(&keypair));

list, view, diff, merge, review, comment, comments each get a bare let owner = resolve_owner(&keypair); (pr.rs:254, :298, :386, :407, :441, :481, :506).
detect_remote_owner() is referenced only at line 222, so even the git-remote tier is create-only:
inside a clone of someone else's repo, gl pr create targets them and gl pr list targets you.

pr.rs is the only gl module without owner/name splitting. repo.rs:598
(resolve_owner_repo_pair), star.rs:56, and the issue/cert/protect/visibility modules all accept
it.

The workaround fails silently

Passing owner/name interpolates straight into the path and produces a four-segment URL matching no
route. Built at 50d3cbb against a capture server:

$ gl pr list z6MkSOMEONEELSE/theirrepo --node http://127.0.0.1:8791
No pull requests for z6MkSOMEONEELSE/theirrepo

$ gl pr view z6MkSOMEONEELSE/theirrepo 3 --node http://127.0.0.1:8791
PR #3: ?
  Status: ?

with the captured request lines:

/api/v1/repos/<caller-own-short-did>/z6MkSOMEONEELSE/theirrepo/pulls
/api/v1/repos/<caller-own-short-did>/z6MkSOMEONEELSE/theirrepo/pulls/3

The caller's own DID occupies the owner segment and the intended owner has been folded into the repo
segment. The client then renders the non-match as an empty list and as ? fields, which is the
denial-rendered-as-success shape again rather than an error.

This is a client gap, not an API restriction

server.rs:393 mounts GET /api/v1/repos/{owner}/{repo}/pulls on the public router and
api/pulls.rs:101-108 gates it with authorize_repo_read(..., "/") on an optional identity, so a
public repo owned by any DID is readable. The node permits exactly the operation the CLI cannot
express.

Scope against existing work

#208 explicitly excludes this site in its own scope section: "Genuinely different, leave out of the
duplicate set: ... pr.rs:184 (keypair-only, returns String)". Its subject is the node-DID fallback
in cert/issue/protect/visibility. #159 (webhook owner from caller identity) and #102 are unrelated,
and #148 touches gl pr create error masking only.

PR #186 partly softens the symptom: converting pr.rs to read_json makes the malformed path surface
as a real error instead of the fake PR #3: ? above. That fixes the silence, not the gap.

Severity

Medium, not high. No security or trust-boundary consequence, and the node's authorization is intact.
It is a missing capability plus a silently malformed URL, and it blocks the ordinary maintainer flow
of reviewing a PR on a repo you do not own.

Fix direction

Give the other eight subcommands the same owner/name split the rest of gl already uses, preferably
by adopting the shared helper #208 proposes rather than adding a ninth copy, and keep
detect_remote_owner in the chain so working inside a clone does the right thing everywhere rather
than only on create.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    crate:glgl — the contributor CLIkind:bugDefect fix — wrong or unsafe behaviorsev:mediumDegraded but workaround existssubsystem:apiNode REST API request/response surfacesubsystem:identityDID/UCAN, http-sig auth, push authorization

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions