~bigbes/sr-ht-dolt

ref: 0638c16f7ac54e5ab2e398ac748c28a1475ebb04 sr-ht-dolt/graph d---------
b525a62b — Eugene Blikh a day ago
authn: name the grant scope dolt.sr.ht/DATABASES

api-meta.json published the scope as lowercase "repos" while every other
service on the instance publishes it upper case — git.sr.ht/REPOSITORIES,
todo.sr.ht/TRACKERS, paste.sr.ht/PASTES, builds.sr.ht/JOBS. Upstream derives
those from a GraphQL enum; this service has no @access directive to derive
from, so the spelling was free and drifted.

It matters because meta.sr.ht compares the string verbatim. Its oauth2
blueprint fetches every service's api-meta.json once at import time and
validates a requested grant with `scope in service_scopes[svc]` — no case
folding, no aliasing. So a grant typed by hand as dolt.sr.ht/REPOS:RO was
refused, by analogy with every neighbouring service.

DATABASES rather than REPOS: that is what the surface calls the object
everywhere a user meets it — the GraphQL databases connection, the web pages,
the docs. The storage layer underneath still says "repo"; renaming that is a
deeper change and is not what a token grant names.

No backward compatibility. auth.Grants.Has is a map lookup, so a PAT minted
against the old spelling is refused rather than quietly honoured, and two table
cases assert that instead of leaving it implied. Deploying this is two-sided:
meta.sr.ht has to be restarted before anyone can mint a token carrying the new
name.

The federation gateway is unaffected — it forwards the client's Authorization
header to each service and never reads api-meta.json.

sr-ht-dolt-xic
ecfc6bb2 — Eugene Blikh 4 days ago
graph: a read schema for dolt.sr.ht at /query

This service had no GraphQL at all, so nothing on the instance that already
speaks SourceHut GraphQL could read it — not hut, not a script written
against git.sr.ht's API, not api.sr.ht, which federates by fetching each
service's /query. Everything else here has one; this is the missing surface
rather than a new idea.

The schema answers what a database IS: the listings under the store's own
visibility rule, one database by owner and name, its branches, commit log and
table list, and its ACL to the owner alone. Rows and diffs stay on /mcp,
where a read that had to be clipped says so in its own answer — a shape this
schema would have to reproduce field by field to stay honest. There are no
mutations, for spec.sr.ht's reason: a federated type is a consumed contract,
and creating, renaming and deleting a database is young code.

Access is not spec.sr.ht's single-owner gate but this service's own matrix,
applied per field: the bearer plane /mcp defines, then core.Allowed over the
caller's grant. Anonymous is a normal caller — which is why the endpoint
cannot be mounted the way core-go's WithSchema mounts one — and a database
the caller may not see resolves to null rather than to an authorization
error, so its existence cannot be read out of the shape of the refusal.

model.Database is hand-written and branches/log/tables/acl are resolver
fields on purpose: as generated struct fields they would open one bare store
per row of every listing. A test asserts a metadata query opens none.

Codegen is a module-independent `go run …@v0.17.94`, so the generator's
dependency tree stays out of go.mod. v0.17.36 — the version spec.sr.ht
pins — still cannot be run that way: its module pins an x/tools this
toolchain refuses to compile, which generate.go records.