Skip to content

feat(repository): support self-hosted servers via repository URLs - #148

Merged
roxblnfk merged 3 commits into
1.xfrom
feat/repository-server
Oct 12, 2026
Merged

roxblnfk merged 3 commits into
1.xfrom
feat/repository-server

Conversation

@roxblnfk

@roxblnfk roxblnfk commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

What was changed

  • A uri with a scheme points a repository at GitHub Enterprise Server, a self-hosted GitLab or a local fake API: https://ghe.example.com/owner/repo, https://gitlab.example.com:8443/group/sub/project, http://127.0.0.1:8080/owner/repo. The API is {server}/api/v3 (GitHub) / {server}/api/v4 (GitLab). owner/repo and https://github.com/owner/repo work as before.
    • A value without a scheme never names a server; github.com/owner/repo and gitlab.com/… still read as the public hosts. For GitHub, a scheme-less value with a foreign host (ghe.example.com/org/repo) is an error: it used to download org/repo from github.com silently.
    • GitHub takes exactly owner/repo, GitLab a project path with subgroups; a trailing / and .git are tolerated, anything pointing inside a repository (/releases, /-/…) is an error. GitLab under a relative URL root is not supported.
  • Tokens are declared per server in DLOAD_TOKEN_<HOST>: a dot becomes _, a hyphen __, a port follows after ___, an IPv6 address starts with _ and lists all eight groups (DLOAD_TOKEN_GHE_EXAMPLE_COM, DLOAD_TOKEN_MY__GHE_CORP___8443), so different servers never share a variable. DLOAD_TOKEN_GITHUB_COM / DLOAD_TOKEN_GITLAB_COM win over GITHUB_TOKEN / GITLAB_TOKEN, which never leave the public hosts. A token goes only to the exact scheme, host and port of its server, and over plain http only to loopback.
  • DLoad follows redirects itself and drops Authorization, PRIVATE-TOKEN, JOB-TOKEN and Cookie when a redirect leaves the scheme, host and port of the request. Symfony HttpClient stripped only Authorization and Cookie, so a GitLab release link to another host received PRIVATE-TOKEN — on gitlab.com too.
  • The version registry keys a self-hosted repository by its server too (github@ghe.example.com/owner/repo); paths and records of the public hosts are unchanged, so existing registries stay valid. Repository::getId() gives the downloader that key.

Why?

Unblocks roadrunner-php/cli#49, whose rr get acceptance tests run against a local fake API. The design started in #143 (comment) with a separate server attribute; it was replaced by the URL in uri before release (see the follow-up comment in #143).

Merge note

Three commits, ready for a rebase merge: chore: Add AGENTS.md, the feature, and fix(repository): keep API tokens on their server across redirects — a fix of its own, since the GitLab token followed redirects on gitlab.com before this PR too.

Checklist

🤖 Generated with Claude Code

@github-actions github-actions Bot added enhancement New feature or request tests labels Oct 10, 2026
@codecov

codecov Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.11321% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...c/Module/HttpClient/Internal/RedirectingClient.php 95.91% 2 Missing ⚠️
src/Module/Repository/Internal/Server.php 95.83% 2 Missing ⚠️
Files with missing lines Coverage Δ
src/Bootstrap.php 100.00% <100.00%> (ø)
src/Module/Config/Schema/Embed/Repository.php 100.00% <ø> (ø)
src/Module/Downloader/Downloader.php 100.00% <100.00%> (ø)
...c/Module/HttpClient/Internal/NyholmFactoryImpl.php 100.00% <100.00%> (ø)
...c/Module/Registry/Internal/FileRegistryStorage.php 100.00% <100.00%> (ø)
src/Module/Registry/Record/RepositoryRecord.php 100.00% <100.00%> (ø)
src/Module/Registry/RepositoryId.php 100.00% <100.00%> (ø)
...c/Module/Repository/Internal/GitHub/Api/Client.php 100.00% <100.00%> (ø)
...pository/Internal/GitHub/Api/ResponseValidator.php 100.00% <100.00%> (ø)
src/Module/Repository/Internal/GitHub/Factory.php 95.83% <100.00%> (ø)
... and 9 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@roxblnfk roxblnfk changed the title feat(repository): support self-hosted servers via the server attribute feat(repository): support self-hosted servers via repository URLs Oct 12, 2026
@roxblnfk
roxblnfk force-pushed the feat/repository-server branch from e11d9bc to 39235b4 Compare October 12, 2026 08:18
fix(repository): send the GitLab token only to the GitLab server
feat(repository): read tokens from `DLOAD_TOKEN_<HOST>`, ahead of `GITHUB_TOKEN` and `GITLAB_TOKEN`

The server comes from the URL in `uri` rather than a separate attribute: `uri` already accepted a URL and dropped its host, so `https://ghe.corp.com/org/repo` silently downloaded `org/repo` from github.com. A value without a scheme never names a server.

The token variable is derived from the server address so that only the user's environment, never a config file, decides which host receives a token; the encoding is injective, so `ghe-example.com` cannot read the token of `ghe.example.com`.

Closes #143

Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
Symfony HttpClient strips only `Authorization` and `Cookie` when a redirect changes the host, so a GitLab release link pointing elsewhere received `PRIVATE-TOKEN`. DLoad follows redirects itself, which keeps the rule independent of header names and Symfony versions.

Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
@roxblnfk
roxblnfk force-pushed the feat/repository-server branch from 39235b4 to 940021f Compare October 12, 2026 08:21
@roxblnfk
roxblnfk merged commit fdb1aeb into 1.x Oct 12, 2026
22 checks passed
@roxblnfk
roxblnfk deleted the feat/repository-server branch October 12, 2026 08:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support a custom host for repositories (GitHub Enterprise, self-hosted GitLab)

1 participant