git: GitRepo pull/push lack token auth + no Git-LFS support (forces downstream re-implementation) #150

Open
opened 2026-06-12 09:58:55 +00:00 by casper-stevens · 0 comments
Member

Summary

herolib_os::git (crates/os/src/git/) is a capable general-purpose git toolkit, but two gaps in the per-repo GitRepo API forced hero_slides to roll its own ~750-line git module for git-linked deck collections instead of reusing this one. Filing so the gaps are visible and can be closed upstream.

Gap 1 — GitRepo network ops can't authenticate a private repo

GitRepo::pull, push, fetch, and commit shell out to a bare Command::new("git").args(["-C", path, ...]) (see git_core.rs). They inject:

  • no http.extraHeader Authorization token, so a private Forgejo repo can't be pulled/pushed;
  • no GIT_TERMINAL_PROMPT=0, so on a tty-less server git hangs on the credential prompt instead of failing fast.

Token injection today lives only in the Forge workflow layer (forge.rs, http.extraHeader=Authorization: token <FORGE_TOKEN>) and in GitExecutor (Redis-backed). But Forge is hard-wired to the flat $PATH_CODE/{name} layout from env, so it can't operate on an arbitrary working-tree path the way GitRepo::new(path) can. There is no way to do an authenticated pull/push on an arbitrary checkout.

Suggested fix

Give GitRepo an optional token (e.g. GitRepo::new(path).with_token(tok) or a clone_repo(...).token(tok) builder option) that, when set, injects -c http.extraHeader=... on network commands and always sets GIT_TERMINAL_PROMPT=0. This is the one genuinely reusable gap — it would make GitRepo usable for private repos at any path.

Gap 2 — no Git-LFS support at all

There is zero LFS handling anywhere in crates/os/src/git/ (no pointer parsing, no batch API, no smudge handling). hero_slides collections are image-heavy and stored with Git-LFS, so it had to implement:

  • native HTTP LFS batch-API download (operation: download, transfers: [basic]) so no git-lfs binary is required on the host;
  • v1 pointer parsing (oid sha256:, size), sha256 verification of fetched blobs;
  • GIT_LFS_SKIP_SMUDGE=1 on clone so a missing-LFS-auth smudge doesn't abort the checkout;
  • --skip-worktree marking of smudged files so they don't dirty git status / block pull/push;
  • an lfs_counts (present/total) helper for a download progress bar.

Forgejo's LFS endpoint authenticates with HTTP Basic (token as username) — distinct from the http.extraHeader token scheme — which is part of why this is non-trivial and worth having once, centrally.

Suggested fix

Consider an optional LFS module (feature-gated) providing at minimum: pointer detection, batch-API resolve+download, and a present/total count. Even just the native batch download (no git-lfs binary dependency) would let multiple downstream services drop bespoke code.

Context / reference impl

The working reference implementation is hero_slides's crates/hero_slides_lib/src/git.rs (token via per-command http.extraHeader, GIT_TERMINAL_PROMPT=0, GIT_LFS_SKIP_SMUDGE=1, native LFS batch download, skip-worktree, lfs_counts). Tracking issue on the slides side: lhumina_code/hero_slides#97.

Impact

Until at least Gap 1 is closed, services that sync private repos at arbitrary paths cannot use GitRepo and must reach for Forge (wrong layout) or hand-roll git. Gap 2 is a nice-to-have but would eliminate real duplication for image/asset-backed services.

## Summary `herolib_os::git` (`crates/os/src/git/`) is a capable general-purpose git toolkit, but two gaps in the per-repo `GitRepo` API forced `hero_slides` to roll its own ~750-line git module for git-linked deck collections instead of reusing this one. Filing so the gaps are visible and can be closed upstream. ## Gap 1 — `GitRepo` network ops can't authenticate a private repo `GitRepo::pull`, `push`, `fetch`, and `commit` shell out to a bare `Command::new("git").args(["-C", path, ...])` (see `git_core.rs`). They inject: - no `http.extraHeader` Authorization token, so a private Forgejo repo can't be pulled/pushed; - no `GIT_TERMINAL_PROMPT=0`, so on a tty-less server git **hangs** on the credential prompt instead of failing fast. Token injection today lives only in the `Forge` workflow layer (`forge.rs`, `http.extraHeader=Authorization: token <FORGE_TOKEN>`) and in `GitExecutor` (Redis-backed). But `Forge` is hard-wired to the flat `$PATH_CODE/{name}` layout from env, so it can't operate on an arbitrary working-tree path the way `GitRepo::new(path)` can. There is no way to do an authenticated pull/push on an arbitrary checkout. ### Suggested fix Give `GitRepo` an optional token (e.g. `GitRepo::new(path).with_token(tok)` or a `clone_repo(...).token(tok)` builder option) that, when set, injects `-c http.extraHeader=...` on network commands and always sets `GIT_TERMINAL_PROMPT=0`. This is the one genuinely reusable gap — it would make `GitRepo` usable for private repos at any path. ## Gap 2 — no Git-LFS support at all There is zero LFS handling anywhere in `crates/os/src/git/` (no pointer parsing, no batch API, no smudge handling). `hero_slides` collections are image-heavy and stored with Git-LFS, so it had to implement: - native HTTP **LFS batch-API** download (`operation: download`, `transfers: [basic]`) so **no `git-lfs` binary is required on the host**; - v1 pointer parsing (`oid sha256:`, `size`), sha256 verification of fetched blobs; - `GIT_LFS_SKIP_SMUDGE=1` on clone so a missing-LFS-auth smudge doesn't abort the checkout; - `--skip-worktree` marking of smudged files so they don't dirty `git status` / block pull/push; - an `lfs_counts` (present/total) helper for a download progress bar. Forgejo's LFS endpoint authenticates with HTTP Basic (token as username) — distinct from the `http.extraHeader` token scheme — which is part of why this is non-trivial and worth having once, centrally. ### Suggested fix Consider an optional LFS module (feature-gated) providing at minimum: pointer detection, batch-API resolve+download, and a present/total count. Even just the native batch download (no `git-lfs` binary dependency) would let multiple downstream services drop bespoke code. ## Context / reference impl The working reference implementation is `hero_slides`'s `crates/hero_slides_lib/src/git.rs` (token via per-command `http.extraHeader`, `GIT_TERMINAL_PROMPT=0`, `GIT_LFS_SKIP_SMUDGE=1`, native LFS batch download, skip-worktree, lfs_counts). Tracking issue on the slides side: lhumina_code/hero_slides#97. ## Impact Until at least Gap 1 is closed, services that sync **private** repos at arbitrary paths cannot use `GitRepo` and must reach for `Forge` (wrong layout) or hand-roll git. Gap 2 is a nice-to-have but would eliminate real duplication for image/asset-backed services.
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
lhumina_code/hero_lib#150
No description provided.