gitforge

package
v0.0.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package gitforge stands up a real, hermetic git remote for tests.

Why this exists rather than a mock

pkg/executor/gitprovision and pkg/executor/gitwriteback are the two halves of one circuit: a leased credential reaches a sandbox through the first, and the commits the sandbox produced travel back through the second. Neither half can be proven against a fake. The claims they make — the token is scoped to one origin, the environment handed to git is closed, a refusal happens before any byte reaches the remote — are claims about what the *git binary* does with the environment those packages build. A mock that returned canned output would agree with any of them.

So the remote here is a real bare repository served by real git-http-backend over real TLS, and every assertion about it is an assertion about a repository rather than about a recorded call. It is hermetic all the same: the listener is on loopback, the certificate is minted by httptest, and nothing outside the test's temporary directories is read or written.

Why TLS and not plain HTTP

executor.Workspace refuses a repo URL that is not https, because a brokered token on cleartext http is a published token. A test forge on http would therefore be testing a configuration production cannot express. TLS also makes the transport allowlist observable: the only way a client can trust this forge's certificate is GIT_SSL_CAINFO, which is on gitprovision's allowlist, while GIT_SSL_NO_VERIFY — the shortcut — is deliberately not. A fetch that succeeds here is therefore evidence that the allowlist works, and one that fails without CAINFO is evidence that the shortcut really is absent.

Why it lives under internal/

It imports "testing", so it must never be reachable from a shipped binary. internal/ enforces that, and scopes it to the executor tree where both callers live.

Index

Constants

View Source
const DefaultBranch = "main"

DefaultBranch is the branch a seeded repository puts its first commit on. It is named explicitly everywhere rather than inherited from the git version's default, which has changed.

Variables

This section is empty.

Functions

func FixtureEnv

func FixtureEnv(home string) []string

FixtureEnv is the environment every fixture git command runs in.

It is closed for the same reason the code under test closes its own: a developer's ~/.gitconfig holding a credential helper, an insteadOf rewrite or a commit.gpgsign would otherwise decide the outcome of a test about something else. home isolates anything that still reaches for it.

func Git

func Git(tb testing.TB, tools Tools, home, dir string, args ...string) string

Git runs a fixture git command outside any forge, for tests that only need a local repository. home is the isolated HOME to run it under.

func NoSecretIn

func NoSecretIn(tb testing.TB, set *redact.Set, what, text string)

NoSecretIn fails tb when text contains any value in set.

what names the channel — "the returned error", "the emitted log" — because the first question on a failure is which surface leaked, not what the value was. The value itself is never printed; a test that leaked the credential into the test log would have reproduced the bug it was written to catch.

func NoSecretUnder

func NoSecretUnder(tb testing.TB, set *redact.Set, root string) int

NoSecretUnder walks root and fails tb for any file whose name or contents contain a value in set.

This is the assertion that a credential never reached the disk, and it is deliberately blunt: it does not know whether the leak would be an askpass script, a credential-helper file, a .git/config entry or a stray temporary, and it does not need to. Anything a future change writes lands in one of these files or it does not exist.

It returns the number of files scanned so a caller can refuse a vacuous pass: an assertion over an empty tree succeeds for the wrong reason.

func TryGit

func TryGit(tb testing.TB, tools Tools, home, dir string, args ...string) (string, error)

TryGit is Git without the assertion, for commands expected to fail.

func WriteFile

func WriteFile(tb testing.TB, dir, rel, content string) string

WriteFile creates a file under dir, making parent directories as needed.

Types

type Forge

type Forge struct {
	// contains filtered or unexported fields
}

Forge is a bare-repository host served over TLS.

func Start

func Start(tb testing.TB, opt Options) *Forge

Start brings up a forge and registers its shutdown with tb.

func (*Forge) AddFile

func (f *Forge) AddFile(tb testing.TB, owner, name, branch, path, content, msg string) string

AddFile commits one file onto a branch of an existing repository and returns the new tip.

func (*Forge) CAFile

func (f *Forge) CAFile() string

CAFile is the path to the PEM a client must trust.

func (*Forge) Count

func (f *Forge) Count() int

Count is how many requests the forge has received. Zero is the assertion that matters for every refusal that is supposed to happen before the network.

func (*Forge) Create

func (f *Forge) Create(tb testing.TB, owner, name string) string

Create makes a bare repository and seeds it with one commit on DefaultBranch, returning that commit's SHA.

The seed travels over the filesystem rather than over HTTP: fixture setup must not depend on the path under test, or a broken fetch would show up as a broken fixture.

func (*Forge) Git

func (f *Forge) Git(tb testing.TB, dir string, args ...string) string

Git runs one fixture git command in dir and fails the test if it errors.

func (*Forge) Log

func (f *Forge) Log() string

Log renders the request trail for a failure message.

func (*Forge) Path

func (f *Forge) Path(owner, name string) string

Path is the bare repository's directory, for fixture work that must not go through the path under test.

func (*Forge) RepoURL

func (f *Forge) RepoURL(owner, name string) string

RepoURL is the https clone URL for a repository on this forge.

func (*Forge) Requests

func (f *Forge) Requests() []Request

Requests returns every request the forge has received, oldest first.

func (*Forge) SHA

func (f *Forge) SHA(tb testing.TB, owner, name, branch string) string

SHA resolves a branch on the forge, returning "" when the ref does not exist. The empty string is the useful answer for "the push was refused": a test can assert the ref was never created without special-casing an error.

func (*Forge) Trust

func (f *Forge) Trust(tb testing.TB)

Trust points the process environment at this forge's CA for the duration of the test, which is the one host setting gitprovision's allowlist forwards.

func (*Forge) URL

func (f *Forge) URL() string

URL is the forge's base URL, https on loopback.

type Options

type Options struct {
	// User and Password are the basic credential the forge demands. When
	// Password is empty the forge serves anonymously, which is how a test
	// distinguishes "the client sent no credential" from "the credential was
	// wrong".
	User, Password string
	// Intercept, when non-nil, runs for every request after it is recorded and
	// before it is authenticated. Returning true means it wrote the response
	// itself and git must not be invoked — used to model a redirect, a hang, or
	// a forge that is down.
	Intercept func(w http.ResponseWriter, r *http.Request) bool
}

Options configure a forge.

type Request

type Request struct {
	Method        string
	Path          string
	Authorization string
	User          string
	Password      string
	Authorized    bool
}

Request is one HTTP request the forge received.

Authorization is recorded verbatim, which is what lets a test assert the negative that matters most: that a host the grant does not cover never saw the header at all.

type Tools

type Tools struct {
	// Git is the client and fixture binary.
	Git string
	// Backend is git-http-backend, which serves the smart-HTTP protocol as CGI.
	Backend string
}

Tools are the binaries a forge needs.

func RequireGit

func RequireGit(tb testing.TB) Tools

RequireGit locates git and git-http-backend, or ends the test.

The interesting decision is what "or ends the test" means, and it is not always a skip. A skipped test is reported as a pass by every summary anyone actually reads, so a suite that skips itself into silence is worse than one that was never written: it occupies the place where coverage is supposed to be. These tests are the only executable proof that a leased credential does not leak, which makes them precisely the ones that must not disappear quietly.

So the rule is conditional on whether the environment is one where git is guaranteed. In CI it is: this repository cannot be checked out without git, so a runner that cannot find it is misconfigured and the suite says so with a failure. On a developer machine — where git-http-backend genuinely may not be installed, since several distributions package it separately — the skip stands, and it names the package to install rather than leaving the reader to guess.

CLOOP_REQUIRE_GIT_E2E=1 forces the failing behaviour anywhere, so an operator debugging a suspiciously green run can prove the tests really ran.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL