Skip to content

feat(http): add authenticated Git hosting and collaboration - #150

Merged
forhappy merged 116 commits into
mainfrom
codex/http-server-product
Sep 7, 2026
Merged

feat(http): add authenticated Git hosting and collaboration#150
forhappy merged 116 commits into
mainfrom
codex/http-server-product

Conversation

@forhappy

@forhappy forhappy commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Build an object-storage-backed repository application from the remote-Git examples: one Rust HTTP server embeds a React frontend and serves authenticated browsing, native Git fetch/push, issues, pull requests, releases, and commit-bound review decisions. The server reads Crab repositories directly and does not invoke Git, clone repositories, or maintain a local Git object database. Native receive uses private temporary pack files and shared publication machinery.

Rebased onto main. Draft: this is progress toward the complete self-hosted GitHub replacement, not a production-readiness claim.

Latest changes

  • Fixed the failed architecture CI gate from run 33951375552: the policy now records crab-http-server as the product composition boundary and matches crab-write’s production use of crab-remote-git. The local architecture gate passes all checks (103 direct workspace dependency edges).
  • Added GitHub-style release assets. Writers can stream up to 512 MiB per asset, receive SHA-256 metadata, replay an upload by request ID, and get explicit duplicate-name/version conflicts. Readers can download assets with content metadata; writers can remove them. Draft assets remain private.
  • Fixed the initial repository overview loading layout by keeping the toolbar in the first grid row, restoring the expected spacing before the tree/content panel.

Behavior and ownership

  • The server binary now initializes every configured empty repository prefix through explicit --initialize mode, using the same canonical initializer as crab init. default_branch selects the unborn HEAD and defaults to main. Repeated or concurrent initialization adopts the validated canonical roots; a nonempty prefix without the canonical layout fails closed without conversion or overwrite. The bucket must already exist, and the normal server path never mutates repository roots implicitly.
  • crates/crab-http-server owns the configured bucket catalog, HTTP policy, OIDC sign-in, repository membership, session-bound Git tokens, issues, pull requests, releases, repository labels, commit statuses, detailed check runs and embedded assets. packages/repository owns the React application, using Primer primitives/components and Pierre Trees/Diffs. Node is needed only to build the assets.
  • The production container builds locked frontend and Rust inputs from digest-pinned base images, installs no runtime packages, runs as UID/GID 10001, probes every configured repository through the binary's bounded --healthcheck mode, and drains on SIGTERM. Configuration, identity secrets and object-storage credentials remain operator-mounted inputs.
  • The browser supports case-insensitive issue/pull search across title, description and author, plus a searchable branch/tag picker with default-branch identification, keyboard selection, restored focus and writer-only branch creation from the exact viewed commit. Branch and tag counts now open dedicated searchable pages with default/protected state, copy controls, immutable tip links and exact default-branch comparisons. GitHub-style Releases and Tags views list durable Markdown release notes and tag-pinned source archives. Release search matches tag, title, notes and author case-insensitively. Writers can save private drafts, edit them with version checks, and publish them later; draft creation does not create a Git tag, and readers cannot list or open drafts. Writers can also publish from an existing lightweight or annotated tag, or atomically create a new lightweight tag from an exact visible commit. Writers can edit version-bound release metadata and delete release records through an explicit confirmation; deletion retains the native Git tag, and a later release can reuse it without resurrecting the deleted request. Writers can delete unprotected, non-default branches through an inline confirmation; the request is bound to the displayed tip and stale state refreshes the refs view before retry. The browser also supports raw-byte paths, paginated trees/history, highlighted files, exact blob downloads, commit changes, split/unified diffs, first-parent blame, GitHub-style repository READMEs and Markdown discussions. Writers can manage repository-scoped labels and assign labels or configured repository members to issues and pull requests; colored badges, assignee avatars and responsive pickers follow the same Primer design system. The repository overview, navigation, Code menu and light/dark themes were compared with screenshots of actual GitHub Kubernetes pages. File navigation opens the tree sidebar. A directory click keeps the sidebar mounted, selects and expands the directory on the first click, and loads only its children; a second click collapses it. Go to file searches every file in the pinned snapshot without expanding parent directories or fetching blob bodies. Directory listings and the virtualized tree group folders before files and naturally sort each group by ascending filename. Markdown files switch between source, rendered repository-aware preview and blame. The selected System, Light or Dark appearance persists across navigation. Writers can upload up to 100 text or binary files in one atomic browser commit. Create, edit, delete and upload forms can instead publish directly to a new review branch and open the pull-request composer with the exact source/head refs and a prefilled title; protected branches default to this path and disable direct commits. Timing is available beside the current read without duplicate page-level controls. The Code menu also downloads a ZIP pinned to the resolved commit; the server streams it from bounded remote tree/blob reads with backpressure, byte-safe paths and disconnect cancellation.
  • Git fetch supports protocol v2, shallow/deepen requests, filters, bounded streaming, gzip and chunked request forms. Native receive accepts bounded shallow-client declarations while still requiring every omitted parent from the authoritative remote graph. Canonical clone URLs end in .git, matching GitHub and allowing native Git LFS endpoint discovery without client-specific configuration. Git LFS Basic transfers provide authenticated batch, upload and download endpoints backed directly by object storage; payload size and SHA-256 are verified, request bodies and multipart work are bounded, disconnected uploads drain before capacity is released, and locking reports the protocol-defined unsupported response. Browser reads reopen journal-aware snapshots; pending committed work runs under a generation-owner lease and both GC fence domains before becoming readable.
  • Native receive-pack accepts atomic branch/tag creation, fast-forward updates and deletions while preserving submitted OIDs. Non-fast-forward batches and deletion of the current symbolic HEAD are rejected atomically. Other branches and tags remain deletable; policy follows the recorded HEAD rather than a fixed branch name. Exact configured protected branches reject direct changes after initialization, including an entire atomic batch, while pull request merge retains the canonical publication path. Protection rules can require 0–20 approvals and up to 50 required status contexts. Only each reviewer's latest decision on the exact current head counts, a current change request blocks admission, and every required context must have a latest successful commit status or check run on that same head. Intake has a five-minute cooperative deadline and bounded wire, object, inflation, graph and dependency work. Four transfer slots are shared with fetch; disconnected receive workers drain before releasing capacity or closing the runtime.
  • Repository writers can merge a pull request from its displayed base and head commit IDs after configured current-head approval requirements pass. The default creates a real two-parent merge commit directly from remote commits, trees and blobs; fast-forward-only remains available when the base is an ancestor of the head. The merge engine skips unchanged subtrees, performs bounded text merges for files changed on both sides, and rejects content conflicts, binary merges, symlink/submodule/type conflicts, delete/modify conflicts and merge candidates over 8 MiB. Review decisions advance the pull version so concurrent stale merge inputs cannot claim it. Merge uses the same validation, ref lease, GC fences, dependency proof, visibility evidence and journal publication path as native push. An object-storage marker records the exact generated commit OID and timestamp, blocks concurrent edits and makes an uncertain response or restart recoverable with the same request; completed pulls retain the exact pre-merge comparison after source-branch deletion.
  • crab-git owns receive framing, private pack quarantine/preparation and exact graph/ref/visibility validation. crab-read proves Crab/LFS pointer dependencies from a pinned snapshot. crab-write, metadata and coordination own canonical journal/catalog publication, ref/namespace serialization, GC fencing and cleanup. CLI consumers share these engines; protected-view commit translation remains independently owned.
  • Repository administrators can change the symbolic default branch through Settings after an explicit confirmation. The request is bound to the displayed current HEAD and target tip, publishes through the same ref lease, GC fences, visibility evidence and journal path as native Git, and becomes authoritative for both the browser and native git ls-remote --symref. Git tokens remain limited to explicit read or write scope. Writers can explicitly generate read/write tokens for one repository. Read tokens retain read scope even for a writer. Repository-scoped write tokens can report pending, success, failure and error commit statuses through the canonical GitHub-style route; readers can inspect the combined latest state. Status contexts are case-insensitive, retries are immutable and ordered, and stale retries cannot replace newer results. Detailed check runs add queued/in-progress/completed lifecycle, bounded Markdown output, plain-text step logs, file annotations and external detail links; the newest status or run for a required context controls merge admission. Authorization is rechecked before intake and publication. The catalog exposes effective access; changing selection or permission clears the displayed secret. Revocation invalidates subsequent requests.
  • Repository administrators can create, edit and remove up to 100 exact branch protection rules under Settings → Branches, following GitHub’s classic settings hierarchy. Rules are conditionally versioned in object storage so stale administrators receive a conflict instead of overwriting newer state. Stored rules override configuration after restart. Catalog reads, native pushes, pull-request views and merge admission reload the versioned object, so separately running servers observe completed changes while a monotonic local snapshot prevents delayed reads from rolling policy backward. Configuration remains the version-zero seed for repositories without stored settings.
  • Repository administrators can archive or unarchive a repository from Settings → General → Danger Zone after entering its exact owner/name, following GitHub’s archive confirmation flow. The versioned lifecycle object rejects stale updates and reloads across servers. Archived repositories remain browsable and searchable while repository API mutations, native pushes and Git LFS uploads return read-only errors; native Git and LFS recheck immediately before publication. The React application shows a global Archived label and warning, hides code and collaboration write controls, and restores them after unarchive.
  • The native tag-deletion test exposed a shared catalog defect: removed tips were omitted from the ordinal lookup when no surviving ref/evidence mentioned them. c9b4190 resolves those tips before checking their prior closure. e86129e adds the HTTP composition, token UI and qualification.

The added Rust dependency edges reuse pinned workspace packages; Cargo.lock adds only dependency references, with no external version changes. The implementation does not add a second publication format. Browser-created blob, tree and commit objects are packed in process, then pass through the same quarantine, graph validation, ref lease, GC fences, dependency proof, visibility evidence and journal publication path as native push.

Verification

  • The rebuilt release server resolved first-parent blame for the exact Kubernetes cmd/kubelet/kubelet.go blob directly from the existing RustFS repository without a checkout: two fresh runtimes returned HTTP 200 in 32.12 and 32.70 seconds, with 18 ranges covering all 39 lines at generation 10. The accepted 2,048-commit wave recorded 125,471 logical objects, 103,768 storage requests and 164,389,032 fetched bytes. An 8,192-commit candidate fetched 412,666,490 bytes and was slower, so it was rejected. The same endpoint is fast once the immutable blame cache is warm. This reproduces the previously failing UI request and proves the deep-history path is active in the binary now serving port 8787.
  • Release drafts, search and the GitHub-style release list/detail layout pass the authenticated Rust integration flow, nine frontend unit tests, TypeScript checking, formatting and a production build. Drafts stay invisible to readers and avoid native tag creation until publication.
  • An isolated RustFS prefix was initialized by the release crab-http-server binary with unborn refs/heads/trunk in 0.84 seconds; the same command adopted it in 0.34 seconds. The resulting server passed readiness, advertised the exact unborn branch, accepted the first native smart-HTTP push in 0.15 seconds, served the exact 150-byte Markdown blob through the API, and produced a byte-identical independent depth-one clone in 0.07 seconds at commit 341f2d14f8b2548e9a42a9cb61bcbc556101b2a0. The source repository path was never provided to the server. Three shared initializer tests, 30 existing CLI initialization tests, the complete 21-test crab-write suite, 57 HTTP-server tests, strict all-target Clippy, formatting, CLI check and release build pass.
  • Helper-list regression: a real git ls-remote --symref test fails before the fix with an all-zero HEAD, then passes for empty and tag-only advertisements. All 126 remote-helper unit tests and seven optional gix-transport contract tests pass. The typed formatter applies the same resolved-target rule; shared metadata, HTTP APIs and both protocol-v2 implementations retain unborn HEAD. Live RustFS checks through the rebuilt helper verify exact annotated-tag/peeled OIDs over protocols 0 and 2, with an explicit unborn-main packet in v2 and no zero HEAD. This matches Git’s helper-list parser and protocol-v2 unborn contract. Formatting and the CLI correctness/suspicious Clippy gate pass with gix-transport enabled. An additional strict all-warning lint attempt fails on eight existing VFS warnings in files unchanged from origin/main; no lint suppression or VFS changes were added.
  • 175 remote-reader tests and 57 HTTP-server tests pass; three manual issuer/RustFS tests are ignored by default. Coverage includes native push/fetch, atomic rewrite rejection, deletion, API visibility, cancellation/admission cleanup, explicit token scopes and existing auth/discussion/maintenance behavior. Server all-target Clippy with -D warnings, formatting, frontend TypeScript/build and the Rust release build pass. Nine frontend unit tests and all 30 Chromium browser flows pass. The focused default-branch flow covers stale-state handling, confirmation, dark theme, mobile layout and axe-core. Theme changes now suppress Primer button color interpolation only until the replacement tokens have painted, preventing the transient 4.01:1 foreground/background state while retaining normal interaction transitions. The picker regression covers case-insensitive filtering, empty results, branch/tag switching, keyboard focus and long branch names at a 360px viewport. The rebuilt release server also passes real RustFS tag selection and file browsing in light/dark/mobile layouts; native controls follow the selected color scheme. Browser branch creation and deletion pass writer authorization, CSRF, canonical ref-name, protected/default-branch, exact-source/tip, duplicate, stale-state and native Git advertisement coverage. Archive coverage persists the versioned lifecycle, rejects stale unarchive, browser collaboration changes, native pushes and Git LFS uploads, keeps repository and LFS reads available, restores the same push after unarchive, and checks the GitHub-referenced Danger Zone in dark 390-pixel and axe accessibility runs. Deletion reuses the native ref lease, validation, journal publication and cache invalidation path. A signed-in Kubernetes/RustFS run created qualification/browser-create-20260904 from the visible commit in 49 ms of server handling and 422 ms from click to selected URL; the picker showed the new branch as checked without reloading repository content. Against the real Kubernetes repository, one click on cmd/dependencycheck selected and expanded the row, exposed both children, and updated the directory pane without clearing or refetching the root tree. The rebuilt release also separated the live default branch from three qualification branches, exposed exact commit and compare links, rendered the empty Tags state, and had no horizontal overflow in the 1,280-pixel dark browser. The signed-in refs page deleted one disposable qualification branch in 820 ms from confirmation click to row removal; a fresh RustFS-backed page read still omitted it and kept the default branch without a delete control. A live two-file Kubernetes/RustFS upload committed Markdown and exact binary bytes in 771 ms; the signed-in browser immediately displayed the new commit, retained the selected branch, and rendered the Markdown preview. A separate blob read matched all six binary bytes. A second signed-in run proposed an edit from that source branch in 887 ms of server publication and reached the prefilled pull-request composer 1.77 seconds after clicking. The source ref stayed unchanged; an independent protocol-v2 fetch verified proposal commit d582073d614d070f5bec5c7c78710b4ddfbc585b, parent f1b63c52755b1c27befccd5bad654a5d564d7d79, its message and all 95 Markdown bytes.
  • Releases use immutable request/tag claims, sparse numbered records and the canonical native ref-publication path. The authenticated integration test proves CSRF and membership boundaries, lightweight and annotated tags, changed-request and competing-tag conflicts, version-bound edit/delete conflicts, interrupted-delete recovery, no resurrection by a deleted create replay, retained-tag reuse, archived read-only behavior, git ls-remote, and an independent fetch. A fresh RustFS lifecycle prefix published a release in 141 ms, edited its title, notes and prerelease state in 1.6 ms, and returned the exact edit after restart in 2.8 ms. Deletion took 8.4 ms, the same-version recovery replay took 1.9 ms, list/detail omitted the tombstone, and native Git retained the exact tag. A new request reused that tag in 40.7 ms with a new release number; after another restart, the list returned only the replacement in 3.5 ms. The GitHub-referenced Releases/Tags/edit flow passes light, dark, 390px, axe and no-overflow browser checks.
  • Automated axe-core scans enforce WCAG 2.0, 2.1 and 2.2 Level A and AA rules across core repository, Markdown, refs, issue, pull-request, label, Git-token and Pierre diff states in both light and dark themes. The scan exposed and now guards the assignee-avatar semantic role, Markdown link distinction, dark primary-button interaction contrast and Pierre addition/deletion count contrast. The online npm audit reports zero vulnerabilities.
  • Revision ZIP qualification passed on a fresh isolated RustFS prefix: native smart-HTTP publication created the repository, the HTTP archive was parsed as ZIP, and its README.md matched the exact Git bytes. Against the canonical Kubernetes bucket, the pinned archive returned HTTP 200 with 106 ms time to first byte and streamed 4.06 MB in five seconds before a deliberate disconnect; the remote operation reported cancellation and /readyz remained healthy. The server keeps at most two decoded archive entries queued, preserves file modes and symlinks, sanitizes byte paths, and caps the encoded response at 3 GiB without creating a checkout or local Git object database.
  • The file shell was compared against both GitHub's current public Crab file view and the supplied signed-in GitHub reference at desktop scale. Crab's light, dark and 390px captures now use one repository identity row, compact underline navigation, a 356px full-height file pane, 32px rows, GitHub-style folder and file icons, compact branch/search controls, segmented breadcrumbs, the latest-commit strip and the Code/Blame metadata toolbar. Direct deep links load their ancestor directories from object storage, expand the path, select and center the active file. The active row now follows both supplied GitHub references: a neutral Primer background with a 3px accent rail aligned to the pane edge, while preserving the 32px row height and 16px tree inset. The shared breadcrumb now includes GitHub's copy-path action; Chromium verifies its 28px Primer button writes the exact decoded repository-relative path and exposes success feedback with either sidebar state. The file-tree controls now match GitHub's branch/add/search row with a 52px control band and square 32px buttons. Writers can create nested UTF-8 files and use contiguous 32px raw/copy/download/edit/delete controls on branch files. Edit and delete open reviewable commit forms; stale heads, stale blobs, existing or missing paths, non-directory ancestors, permissions, CSRF and protected branches remain enforced by the server. The collapsed state uses the same expand/branch/breadcrumb/search/action row as the supplied GitHub reference, and the T shortcut restores file-search focus. Search uses a debounced accessible combobox with keyboard selection, loading, empty, error and truncation states; choosing a result restores the expanded tree at that path. Against the RustFS Kubernetes snapshot, an uncached kubelet.go search traversed 6,100 tree objects in 2.22 seconds, transferred 1.42 MB from RustFS, returned 50 ranked paths without blob bodies, and opened cmd/kubelet/kubelet.go by keyboard. A repeat on the same runtime completed in 45 ms with no storage requests. Batched raw first-parent history now deduplicates repeated directory tree OIDs while retaining exact request-order results. The rebuilt release resolved cmd/kubelet/kubelet.go to 5e83b9c2c24636e06158f257113f378bcf360da7, matching native git log --first-parent, in 11.1 seconds with 7,742 logical objects and 9,419 storage requests; the previous reader exhausted the 10,000-object budget. The 390px document remains exactly viewport-width.
  • Full commit IDs now use the validated complete split graph for reachability instead of replaying remote ancestry. On the exact Kubernetes file revision from the reported failure (5e83b9c), a cold authenticated blame returned all 18 ranges in 36.1 seconds; the previous combined reachability and blame request exhausted its two-minute budget. An unreachable full SHA still returned 404 in 89 ms.
  • Deep first-parent blame now consumes the validated split commit graph in 1,024-commit batches, validates every positional parent against raw commit objects, batches path-tree lookups, skips unchanged blob reads and retains metadata only for commits that still own a final line. Batched object reads materialize selected entries and their delta dependencies together, then retain verified bases in the bounded runtime cache instead of repeating locator and range reads in later waves. The HTTP server detects a missing generation-bound graph during repository open and builds it through the shared generation-owner path from bounded remote commit-object batches, reusing the preceding graph when available. It uploads immutable graph data before a generation-identity CAS and never downloads packs or creates a checkout. A fresh isolated RustFS native-push/API qualification attached the missing graph automatically and completed in 6.23 seconds. On a cold rebuilt release server, Kubernetes blame traversed nearly 59,000 commits and returned all 39 cmd/kubelet/kubelet.go line attributions in 44.45 seconds (125,525 logical objects, 108,831 storage requests, 109,141,824 fetched bytes and 155,228,135 inflated bytes); all 39 owners and 18 contiguous ranges match native git blame --first-parent. The immutable warm result returned in 123 ms with two storage requests. The reader now uses the same bounded Myers line engine and slider heuristics as Gitoxide blame instead of an O(rows × columns) matrix whose tie-breaking misattributed four repeated lines. The prior unindexed traversal reached only 24,429 logical objects in 103 seconds before cancellation.
  • File and directory commit strips now resolve the latest commit that changed the exact path, and History preserves the selected revision, raw-byte path and entry kind through signed pagination and branch changes. Exact tree lookup uses canonical Git file/directory ordering without materializing and charging every sibling; first-parent path history carries the parent commit and entry forward instead of rereading both sides. Against the RustFS Kubernetes repository at 160bd16d, the rebuilt release server returned the exact native-Git README change 2eec33d9 in 950 ms of cold server work and 10 ms warm, using 226 logical objects instead of the previous 444. The full remote-reader suite (175 tests), HTTP suite (55 passed, three documented ignores), strict all-target Clippy, release build, nine frontend unit tests and 28 Chromium flows pass.
  • The repository overview restores the shared 16px toolbar bottom margin that the overview override had removed. Chromium measures both the computed margin and a 16px visual gap before the folders-and-files panel, matching the supplied GitHub reference.
  • Default-branch administration passed against the real RustFS Kubernetes repository. The release server changed HEAD from refs/heads/main at 160bd16d98b7f688ce4f3b5ab0c5e4c045f36233 to refs/heads/qualification/browser-proposal-20260905 at d582073d614d070f5bec5c7c78710b4ddfbc585b in 406.3 ms; the refs API and independent native git ls-remote --symref HEAD returned the exact new symbolic ref and OID. Restoring main took 362.9 ms and a fresh read returned the original symbolic ref and tip. Integration coverage also proves admin-only authorization, invalid input rejection, stale current-HEAD and stale target-tip conflicts, and the native/browser authority boundary.
  • Branch protection administration passes through the real native Git boundary: an administrator added a two-approval/two-check rule for feature/policy, the next native push was rejected with the protected-branch reason, a stale version returned 409, and removing the rule allowed the exact same commit to publish and appear through git ls-remote. The persisted object reloads as the effective runtime state. A second repository instance then wrote version 3 while the serving instance remained at version 2; the next native push refreshed the remote policy, rejected the update, and exposed version 3 through the catalog. Integration coverage also proves invalid-rule rejection, administrator-only authorization and repository hiding for outsiders. The Chromium settings flow creates, edits and deletes a versioned rule, verifies each request body, passes dark-theme and 390px no-overflow checks, and passes axe-core.
  • Repository README files now render below directory listings with Primer/GitHub typography and revision-pinned relative links. Relative PNG, JPEG, GIF and WebP images use a signature-checked inline endpoint; SVG, other formats and external images remain links. The rebuilt release server rendered Kubernetes' 4,236-byte README from RustFS in 27.1 ms without browser errors or desktop/mobile overflow. Its inline endpoint returned logo/logo.png as image/png in 95.6 ms; Chromium decoded it at 3,600×3,493, all 302,153 bytes matched native Git, and requesting README text through the endpoint returned 415.
  • The Issues list was compared against GitHub's current public Crab and Kubernetes issue views at 1440×1100. Its light, dark and 390px captures now use the observed 256px Issues/Labels rail, All issues heading, full-width query control, bordered state/list panel and compact rows; the mobile rail becomes tabs with an exactly viewport-width document. A live issue-detail comparison keeps that rail off individual discussions.
  • The locked, digest-pinned container build and runtime inspection pass on Linux at exact head 9f96fd6. Native RustFS qualification verifies --healthcheck succeeds while repository metadata is reachable, fails after the listener stops, and SIGTERM exits cleanly.
  • GC fence renewal continues while cancelled work drains, until the owner stops or drops the heartbeat. This prevents a cleaned-up writer from leaving an expiry quarantine. Seven coordination fence tests and all-target Clippy pass; the new regression fails before the fix and passes afterward.
  • Four injected commit faults pass in memory and against isolated RustFS prefixes: lost marker replies, rejected marker writes, and cancellation before/after commit. Fresh server instances verify exact refs and blob bytes, retained uncertain recovery evidence, explicit retry, and released fences. These tests cover cooperative shutdown, not abrupt process termination.
  • Default-ref deletion has a red/green native Git regression, tested with main and trunk. A fresh RustFS fixture confirms rejection of both single deletion and an atomic deletion/create batch, permitted non-default branch/tag deletion, exact API HEAD and independent fetch. The server suite, all-target Clippy and release build pass with this change.
  • Unborn-HEAD proof: 22 minimal-feature manifest tests, 16 remote repository tests, four ref-advertisement tests, and focused CLI read/publication and protected candidate tests pass. All-target Clippy passes across the five affected shared/server crates. A fresh RustFS flow pushes tags before branches, clones through native protocol v2 with the correct unborn HEAD, reads exact tag bytes, then establishes a branch. The release frontend browses a separate tag-only prefix in light/dark/mobile layouts; exact blobs remain readable after deleting its client and restarting the server. Eight existing test-only lint findings were resolved without changing their assertions.
  • The metadata deletion regression fails against the previous implementation with the missing-old-tip error and passes with the fix. Existing update handoff assertions remain intact. The catalog handoff regression also creates a new ref from a prior tip while another ref moves, proving that base-closure selection uses reconstructed prior refs rather than target-manifest ordering.
  • A fresh isolated RustFS prefix passes browser create, edit and delete publication through the shared receive path. The server builds exact blob/tree/commit objects without a checkout, rejects stale branch and blob state, preserves the edited bytes through an independent protocol-v2 fetch, then deletes the file and prunes its empty parent directory. Authenticated outsiders receive 404 for POST, PATCH and DELETE before publication. The GitHub-referenced toolbar and commit forms passed light desktop and dark 390px inspection without horizontal overflow.
  • An isolated RustFS prefix passes initial native branch/annotated-tag push, a chunked fast-forward, atomic rejection, existing-object tag creation/deletion, exact API tip and independent native fetch. Every retained commit/tree/blob matches Git bytes after deleting the client repositories. Canonical Kubernetes data is unchanged.
  • A built release server completes browser sign-in → scoped write token → native Git push → exact API/browser commit → token revocation. The pushed commit remains visible after graceful restart and renewed sign-in. Light/dark screenshots were inspected. The local issuer is a test fixture, not production identity-provider qualification. The authenticated push took 228 ms in this small shared-cache local fixture; this is not production or Kubernetes push latency.
  • A fresh isolated RustFS pull request created merge commit 0b807e1946dbb3774439173544b2938c0630ea01 in 541.8 ms and replayed the same merge in 3.1 ms. Its Commits tab returned only head commit 14439070de6b58d66d9cafbc3c16174671e5de31 in 121.4 ms, excluded the base ancestry, opened the exact immutable commit view, and had no horizontal overflow at 610px. An independent protocol-v2 fetch verified its exact first parent be2090b49a5aee1d819d8bdabd70f6b4e614e527, second parent 14439070de6b58d66d9cafbc3c16174671e5de31, message Merge RustFS qualification and MERGE_RESULT.md bytes. Pull creation took 51.2 ms and the independent native fetch took about 230 ms on localhost. The integration suite also proves protected direct push rejection, fast-forward merge/replay, two-parent publication through a protected base, and a same-file conflict that returns 409 without moving the base ref.
  • Pull requests persist exact base/head branch names, original commit IDs, Markdown conversations, versioned state and commit-bound review decisions in object storage. The React flow uses the standard Conversation, Commits, Checks and Files changed tabs; the Commits tab walks every parent, excludes the exact base ancestry, paginates with signed head/base-bound cursors and links each result to its immutable commit view. The flow also covers list/filter, branch comparison, creation, Pierre file diffs, comments and close/reopen controls. A real depth-one client pushed a RustFS branch, then pull request 1 and comment 1 survived restart; exact comparison returned only the added fixture. After branch deletion and client removal, the conversation retained its original IDs and disabled only the unavailable live diff. Warm detail, comment-list, list and exact-change reads took 14.2, 1.3, 0.9 and 8.4 ms; idempotent write replays took 552.7 and 581.5 ms on localhost. A second RustFS flow recorded one review against the original head, marked it outdated after a push, bound another review to the new head, retained both across restart, and kept them after source-branch deletion. Initial pull/review writes took 38.2/16.3 ms, the post-restart list took 33.1 ms, and replay took 560.8 ms. A third RustFS flow fast-forwarded pull request 3 through the HTTP API, then independently cloned the exact merged commit and file from main. The merged pull and its exact one-file comparison survived source-branch deletion and server restart. Pull creation, merge and idempotent replay took 34.1/391.2/1.0 ms; post-restart detail and changes took 25.4/55.8 ms of server work on localhost. With main protected, a native atomic push touching it failed in 126.7 ms and left both refs unchanged; pull request 4 published that exact head in 259.6 ms. A fresh depth-one clone read the exact commit/file in 163.5 ms, and source deletion plus restart retained main and the exact comparison. The authenticated two-user native-Git test now proves merge is blocked before approval, another member's current approval unlocks it, a head advance invalidates the approval, a current change request blocks again, and the same reviewer can replace that decision with a current approval. The rebuilt server loaded the existing RustFS repository with the structured protection config; catalog, merged pull, exact comparison and native refs remained readable. A fourth RustFS flow proved required checks end to end: missing and pending ci/test statuses blocked pull request 5, a repository-token success unlocked it, and replaying the older pending request returned its original result without regressing the combined success. Merge took 297.9 ms and an independent depth-one clone read the exact merged commit/file in 723.1 ms after source removal. After restart, pull detail, combined status, exact changes and native ref discovery took 45.8/42.4/21.1/42.7 ms. Light, dark and 390px check-panel screenshots were inspected without horizontal overflow. The rebuilt server also filtered the six persisted pull records directly from object storage: a title/description query returned pulls 6 and 5 in 8.4 ms, an uppercase author query returned all six in 2.0 ms, and a miss returned an empty page in 1.5 ms. The GitHub-referenced pull-list search retained state and pagination in the URL and had no horizontal overflow in light, dark or 390px screenshots.
  • Repository labels use a bounded conditionally updated catalog, stable IDs, immutable create reservations and durable deletion tombstones. Writer-only create/edit/delete/assignment, case-insensitive uniqueness, stale-version rejection, duplicate/unknown selection rejection, replay after rename, idempotent delete and no-resurrection behavior pass in the authenticated integration suite. Issue and pull assignments store stable IDs, so rename and deletion propagate without rewriting discussion records. A real RustFS pull retained its final label across restart; warm edit/delete/replay took 1.8/1.5/0.8 ms and pull assignment took 37.9 ms round trip. The Primer management view and picker passed light, dark and 390px inspection with no runtime errors or horizontal overflow.
  • Repository assignees come from the configured membership directory, use stable member subjects in issue and pull documents, resolve current configured names on reads, and require write access to change. Authenticated integration tests cover writer assignment, repository ordering, duplicate/unknown rejection, read-only denial, issue lists and pull lists. A real RustFS pull retained its local-operator assignment after a server restart. A warm assignment took 29.1 ms round trip (28.7 ms server time); ten catalog reads took 0.17–0.32 ms and ten full pull-detail reads took 25.7–30.2 ms on localhost. The GitHub-referenced Primer metadata rail passed light, dark and 390px inspection; the mobile picker spans the viewport without horizontal overflow or runtime errors.
  • Detailed check runs use immutable create/update reservations, versioned output objects and conditional per-commit catalogs. The authenticated suite covers token create/update, reader visibility, writer ownership, stale replay without rollback, completed-run immutability, annotation validation and required-check precedence. A real RustFS run advanced queued → in progress → successful with two logs and a file annotation, then returned byte-identical detail after server restart. Create took 99.12 ms, updates took 32.63–36.95 ms, and warm list/detail reads took 27.39–31.86 ms locally. A native HTTP push supplied a live pull head; light, dark and 390px browser checks rendered the stored result without horizontal overflow.
  • Native Git LFS qualification passes a 10 MiB multipart upload and independent clone in memory. A fresh isolated RustFS prefix passes a 32 MiB LFS push in 491 ms, independent exact-byte hydration in 352 ms, and exact hydration in 378 ms after a graceful server restart. Source and client repositories were deleted between checks, so the retained bytes came from object storage rather than a server checkout or local Git object database. These localhost timings are functional latency evidence, not production benchmarks.
  • Earlier Kubernetes/RustFS read qualification verifies all 31,328 HEAD blobs, lazy content, history deepening and independent buffered/gzip/chunked clients. Shared pack/graph/dependency, namespace-race and uncertain-marker tests have scoped proof documented in the README and WRITE-DESIGN. Full Rust CI passed at 9ea35df; full Rust CI for e86129e passed. Full CI for edcf83f exposed two remote-helper listing failures. 64135b2 fixes their source: helper-list serialization omits unresolved HEAD instead of giving Git a null object ID. Both original assertions remain intact and pass. Full CI for 64135b2 passed build, formatting and Clippy, then failed one unchanged crab-staging concurrent prepared-write test; the affected source is identical to origin/main. The Git LFS commit bb95348 has scoped local and live RustFS proof. Full CI for bb95348 passed build, formatting and Clippy, then failed the existing sigint_is_forwarded_to_child_and_run_terminates workflow test after its 10-second exit deadline; this PR does not touch that test or workflow runner.

The architecture guardrail now documents the HTTP server’s expanded shared-crate composition and the production crab-writecrab-remote-git edge. The local gate passes with the updated policy; hosted CI should rerun from this commit.

Remaining requirements

Wildcard rules and rulesets beyond exact branch protection, protected-view/active-active publication coexistence, durable push receipts and abrupt process-crash qualification remain unfinished. Git LFS HTTP locking and resumable range downloads also remain pending; interrupted Basic downloads currently restart. On a lost response or 503, inspect remote refs before retrying: a journal commit may already exist. Later indexing or cleanup failures never become an invented per-ref rejection. Missing visibility reconstruction and index receipts also need completion.

Team membership administration, multi-instance session/identity and publication admission, and production backup/recovery remain part of the full objective. The merge-base search selects one closest common ancestor and does not yet synthesize recursive virtual merge bases for pathological criss-cross histories. Repositories currently require initialization before serving. Tag-only initialization now preserves an unborn branch through shared manifest/journal validation, readers, CLI/protected candidate publication, HTTP APIs and the browser. Deploy these updated components together: tagged v1.0.1 and v1.1.0 readers reject this newly supported state. Existing resolved-HEAD repositories need no migration. Sessions/tokens are in memory; restart revokes them, membership changes require restart and provider revocation is not immediately propagated. Browser pointer views and raw downloads expose exact Git pointer blobs; native Git LFS clients hydrate through the new transfer endpoints. Manual assistive-technology and complete keyboard accessibility audits, plus external identity-provider qualification, remain pending.

The OIDC dependency includes RUSTSEC-2023-0071 (rsa private-key timing); this server verifies signatures and holds no RSA private key. No dependency overrides or advisory suppressions were introduced.

@forhappy forhappy changed the title feat(http): add repository browser with embedded React application feat(http): add authenticated repository browser Sep 4, 2026
@forhappy forhappy changed the title feat(http): add authenticated repository browser feat(http): add authenticated repository browser and Git fetch Sep 4, 2026
@forhappy forhappy changed the title feat(http): add authenticated repository browser and Git fetch feat(http): add authenticated repository browser, Git fetch and issues Sep 4, 2026
@forhappy forhappy changed the title feat(http): add authenticated repository browser, Git fetch and issues feat(http): add authenticated repository hosting, native Git push and issues Sep 4, 2026
@forhappy forhappy changed the title feat(http): add authenticated repository hosting, native Git push and issues feat(http): add authenticated Git hosting and collaboration Sep 4, 2026
@forhappy
forhappy force-pushed the codex/http-server-product branch 2 times, most recently from f2e33f9 to 661bb6b Compare September 6, 2026 02:47
@forhappy
forhappy changed the base branch from codex/remote-git-http-qualification to main September 6, 2026 02:49
@forhappy
forhappy marked this pull request as ready for review September 6, 2026 02:52
@forhappy
forhappy force-pushed the codex/http-server-product branch from 01c48af to 4b87472 Compare September 6, 2026 06:32
@forhappy
forhappy merged commit 3f21529 into main Sep 7, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant