Documentation
¶
Overview ¶
Package git is Git hosting for your org: create repos, clone, push, and see what they cost.
It mounts the Hanzo Cloud /v1/git surface: S3-backed Git hosting native in the unified cloud binary — Hanzo Git, the internal git host foundation agents push code into.
A repo is the Git LAYER (source code, buildable/deployable) that lives UNDER an IAM project. It is NOT the IAM project itself: `project` is org-scoping CONTEXT (org → project → env); a repo is scoped BY that context. Every repo belongs to exactly one org (the gateway-minted X-Org-Id, HIP-0026) and an optional project sub-scope (X-Project-Id), enforced on every query, so one org can never read, clone, push to, or delete another's repos.
Surface:
POST /v1/git/repos create a bare repo -> repoView (201)
GET /v1/git/repos list the org's repos -> {data:[repoView]}
GET /v1/git/repos/:name repo detail (branches, HEAD) -> repoView
DELETE /v1/git/repos/:name delete + purge storage -> 204
GET /v1/git/usage per-repo + total bytes -> usageView
Smart-HTTP git protocol (so `git clone` / `git push` work natively):
GET /v1/git/:org/:repo/info/refs?service=git-upload-pack|git-receive-pack POST /v1/git/:org/:repo/git-upload-pack (clone/fetch) POST /v1/git/:org/:repo/git-receive-pack (push)
A project-scoped repo names its project as a middle segment (/v1/git/:org/:project/:repo/…, git@host:org/project/repo.git). The scope otherwise rides X-Project-Id, and a git client sends no headers, so the path is the only channel that reaches a remote. Two names are only unique within one project — hanzo/hanzo-apps/ai and hanzo/hanzo-docs/ai are distinct repos.
Storage is bare git repos on a real filesystem (osfs) rooted under {DataDir}/git; go-git initializes + reads them, while the heavy clone/push/ mirror paths stream through the `git` CLI (gitexec.go) so multi-GB packs stay bounded in memory. See storage.go for the hanzoai/vfs (S3) storage seam.
Billing: every repo tracks sizeBytes, re-measured on create and after each push. /v1/git/usage exposes per-repo + total bytes per org, and each measurement emits a "git.usage" log line a metering consumer can bill on.
Index ¶
- Variables
- func CloneURL(org, name string) string
- func IndexRepoActivity(ctx context.Context, in indexInput) error
- func IndexRepoWorkflow(ctx workflow.Context, in indexInput) error
- func MatchPaths(ctx context.Context, repo Repository, rev Revision, glob string) ([]string, error)
- func Mount(app cloud.Router, deps cloud.Deps) error
- func NotifyPostActivity(ctx context.Context, in notifyPost) error
- func NotifyTargetsActivity(ctx context.Context, ev cloud.LifecycleEvent) ([]string, error)
- func NotifyWorkflow(ctx workflow.Context, ev cloud.LifecycleEvent) error
- func SetIndexer(fn Indexer)
- func ShortRev(r Revision) string
- func Shutdown() error
- func VerifyRef(ctx context.Context, org, repo, branch string) (sha string, ok bool)
- type Blob
- type Change
- type Entry
- type IndexedFile
- type Indexer
- type MirrorTarget
- type Ref
- type Repo
- type Repository
- type Revision
- type Store
- func (s *Store) ClearConflict(ctx context.Context, org, project, repo, branch string) error
- func (s *Store) ClearRepoConflicts(ctx context.Context, org, project, repo string) error
- func (s *Store) Close() error
- func (s *Store) ConflictRepoSet(ctx context.Context, org, project string) (map[string]bool, error)
- func (s *Store) Create(ctx context.Context, r Repo) error
- func (s *Store) CreateMirror(ctx context.Context, v MirrorTarget) error
- func (s *Store) CreateSubscription(ctx context.Context, v Subscription) error
- func (s *Store) Delete(ctx context.Context, org, project, name string) (bool, error)
- func (s *Store) DeleteMirror(ctx context.Context, org, project, repo, id string) (bool, error)
- func (s *Store) DeleteSubscription(ctx context.Context, org, project, repo, id string) (bool, error)
- func (s *Store) Get(ctx context.Context, org, project, name string) (Repo, error)
- func (s *Store) List(ctx context.Context, org, project string) ([]Repo, error)
- func (s *Store) ListMirrors(ctx context.Context, org, project, repo string) ([]MirrorTarget, error)
- func (s *Store) ListOrg(ctx context.Context, org string) ([]Repo, error)
- func (s *Store) ListPublic(ctx context.Context, org string) ([]Repo, error)
- func (s *Store) ListSubscriptions(ctx context.Context, org, project, repo string) ([]Subscription, error)
- func (s *Store) RecordConflict(ctx context.Context, org, project, repo, branch, detail string, at int64) error
- func (s *Store) SetPublic(ctx context.Context, org, project, name string, public bool, updatedAt int64) error
- func (s *Store) SetSize(ctx context.Context, org, project, name string, sizeBytes, updatedAt int64) error
- type Subscription
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoRepository — the repository does not exist, or has no object store yet. ErrNoRepository = errors.New("git: no such repository") // ErrNoRevision — the ref or revision does not resolve. An empty repository // with no commits answers this too. ErrNoRevision = errors.New("git: no such revision") // ErrNoPath — the path does not exist at that revision. ErrNoPath = errors.New("git: no such path") // StopWalk ends a WalkText early without being an error. StopWalk = errors.New("git: stop walk") )
Errors a Repository returns, so handlers can map to HTTP without knowing which backend produced them. Before this, browse.go turned ANY error from resolveRef into 404 "unknown ref", which quietly reported a broken repository as a missing branch.
Functions ¶
func CloneURL ¶
CloneURL returns the HTTPS smart-HTTP clone URL for an org's repo (https://<domain>/v1/git/<org>/<repo>.git) — the exact URL the git handlers serve. Empty when git is not mounted. The credential is NEVER embedded here; the sandbox presents it out of band (env-fed http.extraHeader), so this URL is safe to log and to hand to a subprocess on argv.
func IndexRepoActivity ¶
IndexRepoActivity is the durable index step: read the repo tip's tree from the object plane and fold its text files into the org's code index. Idempotent (full-tree reconcile with prune), so a retry or redelivery re-converges. Exported for worker registration; not called directly.
func IndexRepoWorkflow ¶
IndexRepoWorkflow indexes one repo's pushed tip as a single durable activity, with retry/backoff. Exported for worker registration; not called directly.
func MatchPaths ¶
MatchPaths lists every file path at rev selected by glob, sorted.
The glob is matched SEGMENT BY SEGMENT with path.Match, so `*` never crosses a `/` — `values/*/*.yaml` selects `values/hanzo/www.yaml` and not `values/a/b/c.yaml`. `**` matches zero or more whole segments; as the final segment it selects every file beneath. Only files are returned: a directory is something to descend, never a result.
Matching is prefix-pruned — a segment that matches nothing stops that branch — so a specific glob reads a handful of trees rather than the whole commit.
func NotifyPostActivity ¶
NotifyPostActivity renders and posts one message to one channel. Exported for worker registration; not called directly.
func NotifyTargetsActivity ¶
NotifyTargetsActivity resolves the channels subscribed to the event's repo that opted into its kind. It is an activity because it reads a store — a workflow must stay deterministic on replay, so the resolved list is recorded in history instead. Exported for worker registration; not called directly.
func NotifyWorkflow ¶
func NotifyWorkflow(ctx workflow.Context, ev cloud.LifecycleEvent) error
NotifyWorkflow delivers one lifecycle fact to every subscribed channel: one activity resolves the targets, then ONE activity per channel.
Per-channel activities are what make retry safe. Durable execution replays a completed activity from history instead of re-running it, so a retry never re-posts to a channel that already received the message — the duplicate-delivery hazard of retrying one activity that loops over every channel.
A channel whose retries are exhausted does not withhold the others: the pre-durable behaviour was that a failed post is logged and never fatal, and that is preserved. Exported for worker registration; not called directly.
func SetIndexer ¶
func SetIndexer(fn Indexer)
SetIndexer injects the code-index reactor. The composition root calls it once, after the git and code subsystems both mount. Nil leaves push-index inert.
func ShortRev ¶
ShortRev is the abbreviated form used for display. It is a projection, never an identifier: pass the full Revision back to the Repository. Seven characters, matching the shortSha the browse API has always emitted.
func Shutdown ¶
func Shutdown() error
Shutdown stops the SSH listener and closes every open store (per-org repo metadata + the SSH key registry). Idempotent.
func VerifyRef ¶
VerifyRef reports the tip commit of branch in an org's repo, reading the on-disk bare repo directly (the shared git storage every cloud replica mounts). It is the independent, in-process confirmation that a branch a sandbox claims to have pushed actually LANDED in native git — cloud trusts the branch tips it can read, not the remote runner's self-report. ok is false when git is unmounted, the repo/branch is absent, or the read fails (fail-closed: an unverifiable ref is treated as absent).
Types ¶
type Blob ¶
Blob is the content of one path at one revision. Binary reports that the bytes are not valid text; Truncated reports that the file exceeded the caller's limit, in which case Content is empty — a large file is offered as a clone, never as megabytes of JSON.
type Change ¶
type Change struct {
Rev Revision
Message string
AuthorName string
AuthorEmail string
When time.Time
}
Change is one entry of a revision's history.
type Entry ¶
Entry is one immediate child of a directory in a revision's tree. Dir distinguishes a subtree from a file; Mode is the backend's own permission string (octal for git), carried through for display only.
type IndexedFile ¶
IndexedFile is one text file handed across the seam to the code index: its repo-relative path and content.
type Indexer ¶
type Indexer func(ctx context.Context, org, billingOrg, project, repo string, files []IndexedFile) error
Indexer folds a pushed repo's text files into the code-intelligence index. Injected at the composition root so the git plane stays free of a clients/code import (the two planes never import each other).
type MirrorTarget ¶
type MirrorTarget struct {
ID string
Org string
Project string
Repo string
Host string
URL string
CreatedAt int64
}
MirrorTarget is a downstream remote a repo's advanced refs are mirrored to (GitHub/GitLab/self). Keyed by (org, repo, host): one target per host per repo.
type Ref ¶
Ref is a human-facing name — a branch or a tag — bound to the revision it currently points at.
type Repo ¶
type Repo struct {
ID string
Org string
Project string // may be "" (org-level repo)
Name string
Description string
DefaultBranch string
Public bool // public repos allow ANONYMOUS read (upload-pack); writes stay org-authed
SizeBytes int64
CreatedAt int64
UpdatedAt int64
}
Repo is the org-scoped, canonical metadata record for one Git repository. Org isolation is the (org, project) pair, enforced at the query layer; the gateway-minted X-Org-Id (HIP-0026) selects the org and X-Project-Id an optional sub-scope. The repo's OBJECTS (packs, refs) live on the billy-backed storage under the same (org, project, name) path — this row is only the metadata + the last-measured storage size that commerce meters on.
type Repository ¶
type Repository interface {
// Refs lists branches and tags, each sorted by name.
Refs(ctx context.Context) (branches, tags []Ref, err error)
// Resolve turns a ref name into a revision. An empty name means the
// repository's own default (HEAD, else the configured default branch). It
// returns the revision plus the label that was actually used, so a caller
// can echo "which branch am I looking at" without re-deriving it.
Resolve(ctx context.Context, ref string) (Revision, string, error)
// Tree lists the immediate children of dir at rev, directories first then
// files, each group sorted by name. The root is "".
Tree(ctx context.Context, rev Revision, dir string) ([]Entry, error)
// Blob reads one path at rev. A file larger than maxBytes comes back with
// Truncated set and no content; maxBytes <= 0 means no limit.
Blob(ctx context.Context, rev Revision, path string, maxBytes int64) (Blob, error)
// Log walks history from rev, newest first, at most limit entries. A
// non-empty path restricts the walk to changes touching that path.
Log(ctx context.Context, rev Revision, path string, limit int) ([]Change, error)
// DefaultBranch reports the branch the repository points HEAD at.
DefaultBranch(ctx context.Context) (string, error)
// WalkText visits every TEXT file in rev's tree. Binary files are skipped —
// the one consumer is code intelligence, which indexes source, not blobs.
// A file larger than maxFileBytes is skipped WITHOUT being read, so a huge
// blob never lands in memory (maxFileBytes <= 0 means no limit); this is why
// the cap belongs here and not in the callback. Returning an error from fn
// stops the walk and surfaces that error; returning StopWalk stops it cleanly.
WalkText(ctx context.Context, rev Revision, maxFileBytes int64, fn func(path, content string) error) error
}
The read model. Every method is safe to call on an empty repository: an unborn tree answers ErrNoRevision rather than panicking, which is what lets Refs report an empty-but-valid repo instead of a 500.
type Revision ¶
type Revision string
Revision identifies one immutable state of a Repository. It is OPAQUE: consumers pass it back to the Repository that produced it and never parse it. The git backend fills it with a commit sha; that is an implementation detail and the reason this is a distinct type rather than a bare string.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is one org's repo-metadata database — ONE SQLite file per org at {DataDir}/orgs/{orgSlug}/git.db (opened via cloud.OrgDB). git is org-scoped, not project-scoped: /v1/git/usage is a deliberate org-wide rollup across every project, so the physical boundary is the org and the (optional) project is a row column. MaxOpenConns(1) serializes writes against the file lock.
func (*Store) ClearConflict ¶
ClearConflict removes one branch's divergence marker — a later ff-apply reconciled it. Idempotent (no row ⇒ no-op).
func (*Store) ClearRepoConflicts ¶
ClearRepoConflicts removes every branch's divergence marker for a repo — a full re-import force-fetches every ref, reconciling the repo wholesale. Idempotent.
func (*Store) ConflictRepoSet ¶
ConflictRepoSet returns the set of repos (by name) with ≥1 unresolved inbound conflict in (org, project) — one query backing the repo-list status roll-up.
func (*Store) Create ¶
Create inserts a new repo row. Returns errConflict when (org,project,name) already exists in the org.
func (*Store) CreateMirror ¶
func (s *Store) CreateMirror(ctx context.Context, v MirrorTarget) error
CreateMirror inserts a mirror target. errConflict when (org,repo,host) exists.
func (*Store) CreateSubscription ¶
func (s *Store) CreateSubscription(ctx context.Context, v Subscription) error
CreateSubscription inserts a subscription. errConflict when (org,repo,channel) already exists — one repo can subscribe a given channel exactly once.
func (*Store) Delete ¶
Delete removes a repo row AND cascade-deletes its lifecycle config (subscriptions + mirror targets) in one transaction, so a deleted repo can never leave an orphaned external mirror target that a re-created repo of the same name would silently inherit (Red MED-3: exfil-on-recreate). Reports whether the repo row went.
func (*Store) DeleteMirror ¶
DeleteMirror removes a mirror target by (org, project, repo, id). Reports whether a row went.
func (*Store) DeleteSubscription ¶
func (s *Store) DeleteSubscription(ctx context.Context, org, project, repo, id string) (bool, error)
DeleteSubscription removes a subscription by (org, project, repo, id) — a caller may only delete their own org's subscription of the named repo IN SCOPE. Reports whether a row went.
func (*Store) ListMirrors ¶
ListMirrors returns every mirror target for the repo (org, project, repo), newest first.
func (*Store) ListOrg ¶
ListOrg returns every repo across ALL projects for org (usage rollup), most-recently-updated first.
func (*Store) ListPublic ¶
ListPublic returns every PUBLIC repo across all projects for org, newest first — the per-org half of the anonymous explore/discovery surface.
func (*Store) ListSubscriptions ¶
func (s *Store) ListSubscriptions(ctx context.Context, org, project, repo string) ([]Subscription, error)
ListSubscriptions returns every subscription for the repo (org, project, repo), newest first.
func (*Store) RecordConflict ¶
func (s *Store) RecordConflict(ctx context.Context, org, project, repo, branch, detail string, at int64) error
RecordConflict upserts the divergence marker for one branch: the upstream push could not fast-forward native, so native was preserved and this row records the split-brain for the console + operator. Upsert (not insert) so a repeated diverging push refreshes the detail/timestamp instead of erroring.
func (*Store) SetPublic ¶
func (s *Store) SetPublic(ctx context.Context, org, project, name string, public bool, updatedAt int64) error
SetPublic flips a repo's visibility and bumps updated_at. Public grants ANONYMOUS READ (upload-pack) only — receive-pack stays org-authed always.
func (*Store) SetSize ¶
func (s *Store) SetSize(ctx context.Context, org, project, name string, sizeBytes, updatedAt int64) error
SetSize records the last-measured storage size for a repo and bumps updated_at. Called on create and after each push, so the metered number is always the real on-disk size, never a fabricated rollup.
type Subscription ¶
type Subscription struct {
ID string
Org string
Project string
Repo string
Channel string
Events string
CreatedAt int64
}
Subscription binds a repo (by org+name) to a Slack channel for lifecycle notifications. Events is a CSV of LifecycleKind wire names; "" means every supported kind. Project is the scope it was created in (display only) — routing keys on (org, repo).
Source Files
¶
- browse.go
- build_on_push.go
- community.go
- community_github.go
- core.go
- explore.go
- export.go
- files.go
- git.go
- gitbackend.go
- gitexec.go
- github_import.go
- import_plane.go
- index_on_import.go
- index_on_push.go
- keys.go
- keystore.go
- maintenance.go
- match.go
- mirror.go
- mirror_control.go
- mirror_out.go
- notify.go
- ops.go
- pack.go
- push.go
- reactor.go
- repository.go
- smart_http.go
- ssh.go
- storage.go
- store.go
- subscriptions.go
- ui.go
- ui_templates.go
- webhook.go
- zap.go
- zipdoc_gen.go