Governance spec's bootstrap section contradicts the supersede decision #65

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

The governance spec says to move server settings (site_title, max_release_size) into git and replace --config with startup flags, so the server is configured entirely from settings.git.

That is incoherent with the decision the implementation actually made, and the implementer refused to build it rather than working around it silently — correctly.

b6dcbb7b has settings.git supersede server.toml on the access axis only: access.conf is the sole authority on what an authenticated principal may do, keydir/ the sole authority on which keys authenticate, and server.toml keeps visibility / [ui] anonymous / [http] anonymous_clone. The axes are disjoint so the two files cannot disagree — layering would let a forgotten server.toml silently subtract access that access.conf visibly grants.

Deleting server.toml would delete the anonymous axis with nothing left to express it: access.conf grants to named principals, and @all means every enrolled key, so no rule in it can describe an anonymous HTTP request.

So this needs re-deciding, not implementing. Options roughly: keep server.toml for the anonymous/visibility axis permanently (what the code does today, and arguably right — it is per-deployment, not per-project); or extend the rule language with a genuine anonymous principal, which is a real design change and would want its own spec section.

Until then the spec's bootstrap section should be marked as superseded so nobody implements it as written.


Migrated from git-collab issue 094e0f5046f8e021851de7bea374e518207b57b7.

Original author: a73x dev@a73x.sh.

Close reason: merged in patch 1beeb03e

The governance spec says to move server settings (`site_title`, `max_release_size`) into git and replace `--config` with startup flags, so the server is configured entirely from `settings.git`. That is incoherent with the decision the implementation actually made, and the implementer refused to build it rather than working around it silently — correctly. `b6dcbb7b` has `settings.git` **supersede** `server.toml` on the access axis only: `access.conf` is the sole authority on what an authenticated principal may do, `keydir/` the sole authority on which keys authenticate, and `server.toml` keeps `visibility` / `[ui] anonymous` / `[http] anonymous_clone`. The axes are disjoint so the two files cannot disagree — layering would let a forgotten `server.toml` silently subtract access that `access.conf` visibly grants. Deleting `server.toml` would delete the **anonymous** axis with nothing left to express it: `access.conf` grants to *named principals*, and `@all` means every enrolled key, so no rule in it can describe an anonymous HTTP request. So this needs re-deciding, not implementing. Options roughly: keep `server.toml` for the anonymous/visibility axis permanently (what the code does today, and arguably right — it is per-deployment, not per-project); or extend the rule language with a genuine anonymous principal, which is a real design change and would want its own spec section. Until then the spec's bootstrap section should be marked as superseded so nobody implements it as written. --- Migrated from git-collab issue `094e0f5046f8e021851de7bea374e518207b57b7`. Original author: a73x <dev@a73x.sh>. Close reason: merged in patch 1beeb03e
a73x commented 2026-08-11 16:45:41 +00:00 (Migrated from git.a73x.sh)

Resolved by inverting the default. Spec revised in 423e2c3.

A repository is unlisted and unreadable without authentication unless a rule says otherwise. Absence of configuration becomes a decision rather than a gap, and settings.git only ever expresses the exception — a positive grant, which is what the rule language is already good at.

Two axes, kept separate:

repo tools
    RW+                   =   @admins
    RW      refs/collab/  =   @agents
    R                     =   @all          # every enrolled key
    R                     =   @anonymous    # unauthenticated read: reachable by name
    option listed         =   yes           # and advertised in the repo list

@anonymous is a reserved principal in the rule table, because it is an access decision — resolved by the same first-match-wins evaluation, including - to deny it back. listed is an option, because advertising is a display concern; that is gitolite's existing option line, stolen rather than invented. They are separate because "not in the list" and "404 to a direct URL" are genuinely different states, and a repo reachable if you know its name is a real configuration people use.

Guard: @anonymous must never satisfy a write grant. RW = @anonymous is a config error rejected by push validation, not silently ignored.

--config stays, reduced to bootstrap. The original spec was wrong to delete it: repos_dir and the listener addresses have to be read before any git object can be opened, including settings.git itself, which lives under repos_dir. Everything not needed to reach settings.git does move into it — site_title, max_release_size, and the exposure axes above.

This also generalises a special case b6dcbb7b had to hand-code: settings.git is forced off the anonymous surface unless it opts in, because creating it must not publish the key roster to an internet-facing UI. Under the new default that falls out of the rule instead of being special.

Implementation is not started. This issue now tracks building it rather than deciding it.

Resolved by inverting the default. Spec revised in `423e2c3`. **A repository is unlisted and unreadable without authentication unless a rule says otherwise.** Absence of configuration becomes a decision rather than a gap, and `settings.git` only ever expresses the *exception* — a positive grant, which is what the rule language is already good at. Two axes, kept separate: ``` repo tools RW+ = @admins RW refs/collab/ = @agents R = @all # every enrolled key R = @anonymous # unauthenticated read: reachable by name option listed = yes # and advertised in the repo list ``` `@anonymous` is a reserved principal in the rule table, because it is an access decision — resolved by the same first-match-wins evaluation, including `-` to deny it back. `listed` is an `option`, because advertising is a display concern; that is gitolite's existing `option` line, stolen rather than invented. They are separate because "not in the list" and "404 to a direct URL" are genuinely different states, and a repo reachable if you know its name is a real configuration people use. Guard: `@anonymous` must never satisfy a write grant. `RW = @anonymous` is a config error rejected by push validation, not silently ignored. **`--config` stays**, reduced to bootstrap. The original spec was wrong to delete it: `repos_dir` and the listener addresses have to be read before any git object can be opened, including `settings.git` itself, which lives under `repos_dir`. Everything not needed to *reach* settings.git does move into it — `site_title`, `max_release_size`, and the exposure axes above. This also generalises a special case `b6dcbb7b` had to hand-code: `settings.git` is forced off the anonymous surface unless it opts in, because creating it must not publish the key roster to an internet-facing UI. Under the new default that falls out of the rule instead of being special. Implementation is not started. This issue now tracks building it rather than deciding it.
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#65
No description provided.