An independent review found no way to send a token to another host on an
address that was typed right, and these gaps.
- An address that is refused is no longer repeated in the message: one that
was refused for the password or the token in it put that into the text.
- 'https:/host' with one slash was taken for a host named 'https'. Text
without a scheme is a host with at most a port; anything else is refused.
A host with characters that have no place in a name is refused instead of
throwing.
- The client all accounts share keeps no cookies: what one account's server
set travelled with another account's token.
- A Link header that is not about paging (one a proxy added) ended a list
after its first page. Only paging relations say that there is no next page.
- A connection lost while an answer is read is 'unavailable', not an
unexpected error. A page with more items than were asked for is refused, so
a list has an upper bound. A token with a space or a line break in it is
refused before anything is sent, and is not repeated.
- A token that may not read organizations is refused at an organization's
list whatever the name is: the account path is tried then too, so it still
lists its own account.
- A redirect says that the organization or account may have been renamed;
408 is 'retry later'; other statuses no longer claim there is no API.
- Tests for each, for the escaping of names in requests and clone addresses,
for the time limit covering the reading of an answer, and that the client
of production is the one built on the handler whose settings are asserted.
Refs #202
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
The engine can list the organizations and repositories of a Gitea server (or
one that speaks its API) beside GitHub. Library only: accounts, the CLI and
the app do not use it yet (#201).
- ForgeKind, and ForgeAccessException with ForgeAccessKind: what a failed
request to any forge means to a caller. GitHubAccessException derives from
it and keeps its own Kind, so code written against it still compiles and
still catches.
- GiteaServerUrl: the address of a server is HTTPS, without credentials, and
without anything after its path. There is no setting for http.
- GiteaRepositoryLister and GiteaOrganizationLister, on HttpClient and
source-generated JSON, with no new package. The token goes to the server
the lister was made for and nowhere else: redirects are not followed, the
address of a next page is never taken from an answer, and clone addresses
are built from the configured address instead of being read from the
server. Certificates are validated by the platform; nothing switches that
off. Answers, lists and requests are bounded.
- Paging follows what the server says about a next page: a Gitea server caps
the page size and leaves out what the token may not see, so a short or
empty page does not end a list.
- A lister contract test suite that the listers of both forges pass.
- ADR 0010; threat model T16.
Closes#202
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>