Listing isolation
Overview
A listing returns only the rows you are allowed to see. When it gathers rows from many repositories or groups at once — every merge request across an organization, the work assigned to you everywhere, a search — each row is checked on its own, so a listing never reveals a private repository you cannot open.
That is why two people can read the same URL and get different rows, and why a count on a listing is a count of what you can see, not of what exists.
How it works
Visibility decides who can see a resource
Every group and repository has one of three visibilities:
| Visibility | Who can read it |
|---|---|
| Public | anyone, including a request with no credentials |
| Internal | anyone signed in to Gitmoap, from any organization |
| Private | its members, at Reporter or above |
A repository or subgroup can never be more visible than the group above it. Public and internal are deliberate acts of publication; private content never crosses from one organization to another, although one person may belong to several.
A private resource you are not a member of answers 404 Not Found, never 403. Answering differently for "does not exist" and "exists, but not for you" would tell anyone guessing names which private repositories exist, so the two get the same answer.
Two kinds of listing
The API reference marks every listing with one of two kinds, and the difference is where its rows come from.
single_or_self_scoped — every row belongs to something the request already proved you can see. That is one of three things:
- the one resource the URL names — a repository's branches, a group's members — so the check made on that resource covers every row;
- your own data — your access tokens, your connected apps, your teams;
- a catalogue that carries its own filter, such as file templates or the provider marketplace.
A listing that also shows settings inherited from the groups above — a repository's branch rules with inherited=true — still belongs here, because those settings already govern the resource you asked about.
cross_resource_filtered — the rows come from resources the URL does not name, so being allowed to read the container is not enough. Each row is filtered by whether you can see the repository or group it belongs to before it is returned. Examples:
| Listing | Where its rows come from |
|---|---|
| A group's merge requests or work items | every repository beneath the group |
| Your review requests, your assigned work, your attention inbox | every repository where something names you |
| Search, at any level | every repository and group in reach |
| The repository and group listings | the whole platform |
| A group's or a person's activity | everything that happened in reach |
What follows from this
A public group can hold private repositories. Listing that group's merge requests shows rows only from the repositories you can open; the others are not hidden behind a placeholder, they are simply absent.
A token narrows this further, never wider: a listing read with a token is still bounded by the token's scopes, and by its owner's access to each row's repository.
Rows you cannot see are left out entirely; nothing marks where they would have been. Pagination explains how to read a listing to its end.
Related
- Groupssetting visibility, and why a child cannot be more visible than its parent
- Accesswho can reach what, and explaining a person's access to one resource
- Searchthe cross-resource listing people use most
- Paginationreading a listing to its end
- Errorsthe
404a private resource answers