Wild repos are unreachable over HTTP: discover is non-recursive #64

Closed
opened 2026-08-11 15:38:02 +00:00 by a73x · 1 comment
a73x commented 2026-08-11 15:38:02 +00:00 (Migrated from git.a73x.sh)

Governance (b6dcbb7b) implements gitolite-style wild repos — repo agents/[a-z].* with C = @agents and RW+ = CREATOR — and they work over SSH.

They do not work over HTTP. repos::discover (repos.rs:243) reads exactly one level of repos_dir and never recurses, so agents/claude-a.git is never discovered. The web UI cannot list it, browse it, or serve its collab refs. The same non-recursion means tools.git and tools still collide when resolved by final path component.

The governance spec calls this a prerequisite; it was left out of the implementation, and the implementer flagged it rather than working around it. So the feature is half-delivered: an agent can be granted a wild repo and push to it, and then nobody can see it in the UI.

Fix is a self-contained rework of discovery and HTTP path resolution: recurse into subdirectories, and resolve repositories by their full path under repos_dir rather than by the last component.

Worth doing before wild repos are used for anything real, because the failure is invisible — the push succeeds and the repo simply never appears.


Migrated from git-collab issue d0d1bf5ca63c6ba4df198a6fbf24c262f6eb8e67.

Original author: a73x dev@a73x.sh.

Close reason: merged in patch 02671b2a

Governance (`b6dcbb7b`) implements gitolite-style wild repos — `repo agents/[a-z].*` with `C = @agents` and `RW+ = CREATOR` — and they work over SSH. They do not work over HTTP. `repos::discover` (repos.rs:243) reads exactly one level of `repos_dir` and never recurses, so `agents/claude-a.git` is never discovered. The web UI cannot list it, browse it, or serve its collab refs. The same non-recursion means `tools.git` and `tools` still collide when resolved by final path component. The governance spec calls this a prerequisite; it was left out of the implementation, and the implementer flagged it rather than working around it. So the feature is half-delivered: an agent can be granted a wild repo and push to it, and then nobody can see it in the UI. Fix is a self-contained rework of discovery and HTTP path resolution: recurse into subdirectories, and resolve repositories by their full path under `repos_dir` rather than by the last component. Worth doing before wild repos are used for anything real, because the failure is invisible — the push succeeds and the repo simply never appears. --- Migrated from git-collab issue `d0d1bf5ca63c6ba4df198a6fbf24c262f6eb8e67`. Original author: a73x <dev@a73x.sh>. Close reason: merged in patch 02671b2a
a73x commented 2026-08-11 15:44:23 +00:00 (Migrated from git.a73x.sh)

Confirmed empirically against a running server, not just by reading discover.

Setup — two valid bare repos on disk, one nested:

repos/alpha.git
repos/agents/claude-a.git

Against git-collab-server with that repos_dir:

repo list page:      href="/alpha"        <- agents/claude-a absent entirely
GET /alpha           200
GET /agents/claude-a 404
GET /claude-a        404

So it is not merely a listing omission: the repo is unreachable by any HTTP path. Not browsable, and its collab refs are not served — which matters more than the UI, because it means a clone over HTTP cannot fetch refs/collab/* from a wild repo at all.

Mechanism: resolve(repos_dir, name) (repos.rs:272) calls discover() and matches e.name. discover (repos.rs:243) does a single read_dir with no recursion; agents/ is a plain directory, not a repo, so repo_entry_from_path returns None for it and its contents are never examined.

Over SSH this works because the client names the path explicitly and the session resolves it directly, checks governance, and creates on demand. There is no equivalent path over HTTP.

A first attempt at this reproduction proved nothing and is worth recording so nobody repeats it: the server failed to start on a missing authorized_keys field, and the curls hit the sandbox's port forwarder instead, so every path 404'd including /alpha. Check the title on the served page matches your own config before trusting any result.

Confirmed empirically against a running server, not just by reading `discover`. Setup — two valid bare repos on disk, one nested: ``` repos/alpha.git repos/agents/claude-a.git ``` Against `git-collab-server` with that `repos_dir`: ``` repo list page: href="/alpha" <- agents/claude-a absent entirely GET /alpha 200 GET /agents/claude-a 404 GET /claude-a 404 ``` So it is not merely a listing omission: the repo is unreachable by any HTTP path. Not browsable, and its collab refs are not served — which matters more than the UI, because it means a clone over HTTP cannot fetch `refs/collab/*` from a wild repo at all. Mechanism: `resolve(repos_dir, name)` (repos.rs:272) calls `discover()` and matches `e.name`. `discover` (repos.rs:243) does a single `read_dir` with no recursion; `agents/` is a plain directory, not a repo, so `repo_entry_from_path` returns `None` for it and its contents are never examined. Over SSH this works because the client names the path explicitly and the session resolves it directly, checks governance, and creates on demand. There is no equivalent path over HTTP. A first attempt at this reproduction proved nothing and is worth recording so nobody repeats it: the server failed to start on a missing `authorized_keys` field, and the curls hit the sandbox's port forwarder instead, so *every* path 404'd including `/alpha`. Check the title on the served page matches your own config before trusting any result.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
a73x/git-collab#64
No description provided.