~bigbes/sr-ht-dolt

76bf70dd — Eugene Blikh 30 days ago
fix(web): make the beads view inherit the SourceHut theme

The beads board shipped its own Mardi Gras palette — a purple→green
marquee gradient and saturated solid lane fills — that clashed with
SourceHut's flat, utilitarian dark theme, and the detail pane's field
labels were a hardcoded dark purple with no dark-mode override, leaving
"Created by / Owner / Description" unreadable on the dark background.

Drive everything from CSS variables that mirror core.sr.ht's Bootstrap
palette for both the light default and the prefers-color-scheme: dark
variant sourcehut ships (the same media query it uses), so the view
inherits the host theme instead of fighting it. Lane hues become muted
Mardi Gras accents (gold/green/violet/gray) used only as thin borders and
low-alpha tints — never as body text — so contrast holds on either theme.
The marquee is now a flat stat row, lanes an understated panel with an
accent underline, and detail labels a readable muted caption. Verified
light and dark via a headless render.
8f5ae3f0 — Eugene Blikh 30 days ago
feat(web): Mardi Gras beads view

Render a beads (bd) issue database as a Mardi Gras parade board: four
lanes — Rolling (in progress), Lined Up (open & ready), Stalled (open &
blocked), Past Stand (done) — plus a marquee of per-lane counts. Cards
show id/title/type/priority/assignee/labels and blocked-by/blocks counts;
an issue-detail pane (?issue=<id>) shows the full issue with its
dependency edges in both directions and its comments thread.

Fingerprints on the issues + dependencies tables and reads everything
through the browse layer (column-name-keyed, so column order is
irrelevant), capped at 2000 rows/table. Status is bucketed via
custom_statuses with name heuristics as a fallback; "blocked" means
is_blocked or an open blocking dependency. Plugs into the view registry
via init()+RegisterView with no framework edits. Purple/gold/green
palette scoped in the template (no scss rebuild needed).
4520d5cf — Eugene Blikh 30 days ago
feat(web): pluggable alternative-view registry for repositories

A repository can now expose specialized, read-only "views" chosen by the
shape of its tables, while the generic table browser stays available as a
fallback. A View fingerprints the tables (Applies), builds a model from
the browse layer (Build), and renders its own template; views register at
init time via RegisterView and are dispatched by slug at
/~user/db/view/{slug}. The overview shows a tab per applicable view.

The template loader parses each registered view's template with the
shared chrome, so a new view plugs in by adding two files (its .go with
init()+RegisterView and its .html) plus nothing else — no edits to the
registry, router, loader, or handlers. Build receives the request query
values so a view can offer sub-modes (e.g. a detail pane). No SQL engine
is involved; views read through the existing BrowseSession surface.
ba344433 — Eugene Blikh 30 days ago
feat(remoteapi): auto-create databases on first push to own namespace

Push-to-create: an authenticated, non-suspended caller pushing (or
cloning) an unknown repo under their OWN namespace has it transparently
created — a PRIVATE repository row plus a genuinely empty on-disk NBS
store — then proceeds through the normal ACL check as the owner. Any
other case (anonymous, suspended, another user's namespace, invalid
name) still returns NotFound, so a stranger's namespace is never leaked
and nothing is created.

storage.InitEmptyStore creates the store WITHOUT WriteEmptyRepo: an
"Initialize data repository" commit would make the client's first push a
non-fast-forward and be rejected. An empty store (root = empty hash) lets
the initial push land as the repo's first history. The interceptor
auto-create is race-safe (ErrNameTaken re-fetch) and rolls the row back
if the store cannot be created.

Proven end-to-end (integration): a real `dolt push` to a new name
auto-creates PRIVATE + fast-forwards + re-clones; a foreign-namespace
push is denied with no row created. All prior clone/push/ACL scenarios
still pass.
8583f3a6 — Eugene Blikh 30 days ago
doltsrht: pass full os.Args to server.New so -b binds the web listener

getopt skips argv[0] as the program name, so os.Args[1:] made it swallow the
first real flag (-b) and silently fall back to defaultWebAddr (localhost),
leaving the web UI unreachable from Traefik. Match compare/upstream: pass os.Args.
2dfab043 — Eugene Blikh 30 days ago
rename module to sourcecraft.dev/bigbes/sr-ht-dolt; depend on sourcecraft sr-ht-core
d6f19a1f — Eugene Blikh 30 days ago
build: source core-go from the instance fork

Replace git.sr.ht/~sircmpwn/core-go with git.srht.bigb.es/~bigbes/core-go
at c2c2f38 (upstream fdb3662 + newer upstream commits + the phoebe-lab S3
UnsignedPayload patch) - the code production actually runs. Requires
GOPRIVATE=git.srht.bigb.es to fetch. Full suite re-verified including the
remotesapi integration scenarios.
b4d6a3e6 — Eugene Blikh 30 days ago
docs: add design spec

Architecture plan the v1 implementation followed: verified upstream
facts, schema, access matrix, remotesapi/auth design, browse subsystem,
config + nginx wiring, phase breakdown, and the post-deploy
verification script.
e518fcb9 — Eugene Blikh 30 days ago
cmd: doltsrht and doltsrht-migrate binaries, module tidy
944a35e9 — Eugene Blikh 30 days ago
web: router, handlers, and sourcehut chrome

Chi route table per plan, SourceHut chrome port (nav/layout from
core.sr.ht Bootstrap structure), dual-flow clone box, dolt-key
association page with hash-fragment prefill, same-origin CSRF checks.
Handlers depend on small injected interfaces (StoreManager, RepoStore,
BrowseOpener, UserResolver) with production adapters included.
2b781a27 — Eugene Blikh 30 days ago
remoteapi: authz interceptors, remotesrv assembly, credentials service
6b1c9b76 — Eugene Blikh 30 days ago
browse: read-only doltdb browsing over bare stores

Read-only web-browsing data layer over bare NBS chunk stores, the only
package that reaches into version-fragile dolthub/dolt internals (nbs,
prolly, durable, diff), kept isolated so a module bump re-verifies here.

- open.go: Open/Close per request. Builds the DoltDB from a single
  nbs.NewLocalStore via doltdb.DoltDBFromCS instead of doltdb.LoadDoltDB:
  LoadDoltDB's GenerationalNBS wrapper panics on Close over our bare
  stores in the pinned version (onHeapTableIndex ref count < 0), even on
  a plain open-then-close. The single-store path closes cleanly, gives a
  fresh manifest per request, and is safe alongside the push writer.
- log.go: Branches (+ DefaultBranch pick), Log with topological walk,
  count+start-hash pagination, and commit metadata.
- tables.go: Tables (schema + cheap row count) and Rows via
  durable.ProllyMapFromIndex + prolly IterOrdinalRange, rendered through
  the tuple descriptors; NULLs, binary/out-of-band values and exotic
  encodings degrade to printable placeholders and never panic.
- diff.go: CommitSummary vs first parent (empty root for the initial
  commit) with exact added/removed/modified row counts from
  diff.StatForTableDelta.
- tests: fixture built the production way (WriteEmptyRepo bare store, CLI
  clone/commit/push over a file:// remote); covers branches, log
  pagination/topo order, tables/schema, row pagination incl. empty table,
  commit summaries across the add/insert/modify chain and the initial
  commit, and nonexistent ref/table errors.
5e555bac — Eugene Blikh 30 days ago
authn: cookie, PAT, and dolt-JWT caller resolution

Add the authn package resolving the SourceHut caller across dolt.sr.ht's
three auth flows, producing core-go *auth.AuthContext values mapped onto the
pure core.Caller domain type:

- ctx.go: WithCaller/CallerFromContext (nil for anonymous, never panics) and
  AsCoreCaller (maps UserType, derives Suspended).
- cookie.go: OptionalCookieMiddleware, the never-rejecting unified-login
  cookie reader (fernet decrypt -> {name} -> LookupUser); any failure degrades
  to anonymous so public browsing keeps working.
- token.go: ResolveBasic, the meta personal-access-token trio (offline
  DecodeBearerToken -> username match -> LookupUser + revocation) with a 60s
  positive cache keyed by sha512(password); TokenGrantsAllow gates
  dolt.sr.ht/repos RO/RW grants (empty grants pass).
- jwt.go: ResolveDoltJWT, EdDSA JWS verification for dolt keypair auth (kid ->
  KeyStore pubkey, alg=EdDSA, aud/exp/sub checked, iss ignored), reusing
  dolt's creds.PubKeyToKIDStr for the kid<->pubkey integrity check.
- grpc.go: ResolveGRPCAuth dispatching Basic/Bearer/anonymous.

Meta lookup + revocation sit behind the MetaBackend interface and JWT keys
behind the KeyStore interface (implemented later by db/), so tests forge
cookies (fernet), PATs (BearerToken.Encode) and real Ed25519 JWTs against
in-memory stubs with no network or Postgres.
6efd2748 — Eugene Blikh 30 days ago
db: postgres layer for repos, ACLs, dolt keys

Store wraps a Querier (*sql.DB/*sql.Tx/*sql.Conn); context-first methods, FromContext for core-go middleware, WithTx for the create-repo transaction. Repo CRUD + listing-visibility rules, effective-access/ACL upsert, dolt_key CRUD with typed ErrNotFound/ErrNameTaken/ErrKeyExists. Tests gated on DOLTSRHT_TEST_PG: per-run scratch schema + schema.sql, CRUD/visibility/effective-access cases; skip when unset.
19645e70 — Eugene Blikh 30 days ago
storage: bare store init/delete and remotesrv DBCache

InitStore writes a bare NBS store (LoadDoltDB Format_DOLT + WriteEmptyRepo)
with partial-failure cleanup; DeleteStore guards against paths escaping the
configured repos root; RepoDiskPath lays out <root>/~<owner>/<name>.

Cache implements remotesrv.DBCache over an injected RepoLookup (no db import,
no push-to-create): Get resolves via core.ParseRepoPath, memoizes one
nbs.NewLocalStore per disk path, never creates directories; Evict/Close for
delete and shutdown. Package doc records the LocalFilesysWithWorkingDir
sealed-URL requirement proven by the Phase-0 spike.

Unit tests cover store validity (reopen, main branch, initial commit),
partial-failure cleanup, root-escape guard, and cache hit/miss/memoize/evict.
Spike test untouched and still green.
ca9357a0 — Eugene Blikh 30 days ago
foundation: module, core domain, schema, spike-verified dolt interop

Phase 0 foundation for dolt.sr.ht (pure-Go Dolt hosting for SourceHut).

Dependency pins:
- core-go v0.0.0-20260520082310-fdb3662452dc: the production instance's
  submodule commit (fdb3662); must never be upgraded so token/config/crypto
  behavior matches the rest of the instance.
- dolthub/dolt/go v0.40.5-0.20260626152440-45335d44ad79: pseudo-version at the
  commit tagged v2.1.10 (45335d44), matching the installed dolt CLI. The /go
  submodule's latest tag (v0.40.4, 2021) does not interop with a modern CLI;
  matching the CLI commit guarantees a common NBS format (Format_DOLT) and
  remotesapi proto.
- gopkg.in/go-jose/go-jose.v2 v2.6.3: same JOSE version dolt's creds package
  signs EdDSA keypair JWTs with, avoiding a duplicate JOSE lib.
- grpc v1.79.3, logrus v1.8.3, lib/pq v1.10.9, chi/v5 v5.3.1, brant v0.5.1.

Contents:
- core/ pure domain: models, ValidateName/ParseRepoPath, the access matrix
  (Allowed + NotFoundForPrivate), full table-driven tests.
- schema.sql + migrations/0001_initial.sql (brant format).
- config.example.ini, contrib/dolt.sr.ht.conf (nginx), Makefile, scss/main.scss,
  static/logo.svg, README, .gitignore.
- internal/smoke: throwaway import-and-build check (deleted in Phase 3).

Spike (storage/spike_test.go, tag `spike`): bare NBS store via WriteEmptyRepo,
served by remotesrv on an ephemeral single port, round-tripped through the real
dolt CLI v2.1.10 (clone -> insert -> commit -> push -> re-clone -> verify rows).
Green, no version juggling needed beyond selecting the v2.1.10 commit. FS must
be rooted at the repos dir (LocalFilesysWithWorkingDir) so sealed chunk-URL
prefixes are clean relatives.

Build note: dolt pulls go-icu-regex (CGO), which needs ICU4C headers; on this
Mac set CGO_CPPFLAGS/CGO_LDFLAGS to icu4c@78 (documented in README).