gitprovision

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package gitprovision materialises a workload's source tree where the workload is about to run.

Why this is its own package

Two very different callers have to do exactly the same thing:

  • the remote agent (pkg/executor/agent), which clones onto an edge device before starting a harness there;
  • `cloop workspace provision` (cmd), which the Kubernetes driver runs as an init container before the harness container starts.

The failure this whole subsystem exists to remove is a run that starts cleanly, streams a plausible transcript, and operates on no code at all. Two implementations of "how cloop clones a repo into a sandbox" would be two chances to reintroduce it — and the second copy would drift silently, because the symptom of a drifted provisioner is a run that *looks* fine. So there is one engine, here, and both callers are thin.

The package deliberately depends on nothing but the standard library and pkg/executor. `cloop workspace provision` must not have to import the edge agent (with its transport, vault and session machinery) to clone a repository, and the edge agent must not grow a dependency on the CLI.

What is shared and what is not

executor.Workspace.GitPlan renders the command sequence and is pure: no I/O, no clock, no environment. That is what lets a test assert on the sequence without a git binary. This package is everything the plan cannot be — which directory is safe to write to, whether git exists, how big the disk is — and it is shared because those answers are the same wherever the plan runs. The only thing a caller contributes is Request.Host: how the machine names itself in a diagnostic an operator will read.

The credential

It arrives out of band (the agent's start frame, the init container's environment), never in the Spec, and it leaves this package in exactly one place: the environment of the single git child process whose step is marked Authenticated. It is never written to disk, never placed in an argv (/proc publishes those to every process with the same uid), and never added to the harness's own environment — the harness is the untrusted party here, and a token it can read is a token it can exfiltrate. Everything this package emits or returns is passed through executor.RedactSecrets first, because git is perfectly willing to quote a header back in an error message.

Index

Constants

View Source
const MaxWalkEntries = 500_000

MaxWalkEntries bounds the size check's directory walk.

The walk runs over a tree a remote repository just chose the contents of, so it is attacker-influenced input on a machine the operator may never touch. A repository with ten million tiny files would exceed no byte limit while costing minutes of stat() calls. Half a million entries is far more than any real source tree and small enough to walk in well under a second.

Variables

This section is empty.

Functions

func BoundChild added in v0.0.2

func BoundChild(cmd *exec.Cmd)

BoundChild makes a git child process cancellable and its Wait bounded.

Neither property is free, and the absence of the first one is a hang rather than a slow path. `git fetch` and `git push` do not speak the wire protocol themselves — they exec a transport helper (git-remote-https), which inherits the captured stdout and stderr pipes. exec.CommandContext's default cancellation kills only the process it started, so cancelling a fetch kills git and leaves the helper holding the write end of a pipe that CombinedOutput is still reading. Wait then blocks until the helper exits on its own, which for a remote that has stopped answering means until the TCP stack gives up: the caller's context deadline expires and Provision does not return. That is the failure the context was threaded through this package to prevent, and it is invisible in any test whose remote answers.

So the child gets its own process group and cancellation signals the group, which reaches the helper too; WaitDelay is the backstop for a pipe-holder that somehow survives the group kill. This mirrors pkg/provider/claudecode, pkg/plugin and pkg/hooks, which reached the same conclusion for the same reason — and it is exported so the write-back engine (pkg/executor/gitwriteback) gets it from here rather than growing a fourth copy, exactly as it does with TransportEnv.

The Cmd must have been created by exec.CommandContext: os/exec refuses to Start a command that has a Cancel and no context. That refusal is not theoretical — it is how this function's first version was caught, by a context-less `git config` read that stopped running and reported its silence as "this checkout has no origin remote".

func Collapse

func Collapse(s string) string

Collapse folds command output onto one line for an error message, keeping the tail — git puts the actual reason last.

func EnforceSizeLimit

func EnforceSizeLimit(dir string, w executor.Workspace) error

EnforceSizeLimit refuses a tree that exceeds the workload's disk budget.

The limit comes from the project's .cloop/sandbox.yaml resources.disk, and on a machine with no runtime quota it has to be enforced rather than advertised: the disk being filled belongs to whoever owns the machine, not to the operator who wrote the spec, and a limit that only the least-trusted party can enforce is not a limit. A container driver gets this from the runtime; here there is nothing between the fetch and the filesystem except this check.

func HostLabel

func HostLabel(noun string) string

HostLabel renders how the machine provisioning runs on refers to itself.

The hostname is the identifier an operator can act on — an edge device's name in the fleet, a Pod's name in the namespace. When it is unavailable the phrasing still has to read as a sentence.

func Provision

func Provision(ctx context.Context, r Request) error

Provision clones r.Workspace into r.Dir so the harness starts against real code.

Every error it returns wraps executor.ErrWorkspaceUnavailable and has already been through executor.RedactSecrets, so a caller may log it, ship it across the remote boundary, or print it to a terminal without further filtering.

func SameRemote

func SameRemote(a, b string) bool

SameRemote reports whether two clone URLs name the same repository.

The comparison is deliberately narrow — a trailing slash and a trailing .git are noise that GitHub and every other forge treat as equivalent — and deliberately stops there. Anything cleverer (case folding a path, resolving a redirect) would risk calling two different repositories the same one, and the cost of a false match is a fetch into somebody else's working tree.

func TransportEnv

func TransportEnv() []string

TransportEnv reads the machine's transport settings, skipping anything unset or empty (an empty proxy variable means something different from an absent one to libcurl).

It is exported because the write-back engine (pkg/executor/gitwriteback) has to reach the same remote through the same proxy a moment later. Two allowlists would drift, and the drift would show up as a clone that works and a push that hangs on a machine nobody can reproduce.

func TreeSize

func TreeSize(dir string) (size int64, entries int, err error)

TreeSize sums the regular files under dir, with a bounded walk.

Symlinks are counted as themselves and never followed — filepath.WalkDir does not descend into them — so a repository containing a link to / measures as one small entry rather than as the whole filesystem.

Types

type Request

type Request struct {
	// Dir is the absolute directory the tree is materialised into. It must
	// already exist, and the caller is responsible for having confined it —
	// only the caller knows what its own confinement boundary is (the agent's
	// root, the Pod's workspace volume).
	Dir string
	// Workspace describes what to fetch. Only Kind git is provisionable.
	Workspace executor.Workspace
	// Credential authenticates the single step that contacts the remote. The
	// zero value means an unauthenticated fetch, which only works for a public
	// repository.
	Credential executor.GitCredential
	// Emit receives the git output as it completes, already redacted, so
	// provisioning shows up in the run's live log rather than as a silent pause
	// before the harness starts. It may be nil.
	Emit func(string)
	// Host is how the machine names itself in a diagnostic: "this device
	// (edge-3)". Empty falls back to HostLabel("machine").
	//
	// It is a caller's choice rather than a lookup because the operator reading
	// the failure is looking at a fleet, and "this device" and "this workspace
	// container" send them to different places.
	Host string
}

Request is one provisioning.

Jump to

Keyboard shortcuts

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