Documentation
¶
Overview ¶
Package git clones application repositories for the deploy pipeline using the pure-Go go-git library (D-013). Nothing in this package ever spawns a process: the repository URL, branch and base directory are typed fields on the go-git call, so the CWE-78 surface of a shell-invoked git does not exist. go-git's own "file://" transport shells out to git-upload-pack, so it is replaced with go-git's in-process server at package init (D-019); the https transport is replaced with one whose response bodies are bounded (D-025).
Golden rule 3: tokens and deploy keys travel only inside Auth and go-git's AuthMethod. They are never logged, never placed in an error, and never echoed back via a URL — repository URLs carrying userinfo are rejected outright and every logged URL goes through SafeURL.
Index ¶
- Constants
- Variables
- func CleanupWorkspace(root string, keep int) (int, error)
- func GenerateDeployKey() (privatePEM []byte, publicAuthorizedKey, fingerprint string, err error)
- func KnownHostsLine(hostPort string, key ssh.PublicKey) string
- func LoadKnownHosts(path string) (string, error)
- func NewWorkspaceDir(root, deploymentID string) (string, error)
- func ResolveBranchHead(ctx context.Context, src Source) (string, error)
- func SafeURL(u string) string
- func ValidateBaseDir(s string) error
- func ValidateBranch(b string) error
- func ValidateRepoURL(u string, allowLocal bool) error
- func WebhookSecret() (string, error)
- type Auth
- type Checkout
- type Source
Constants ¶
const ( ProviderGitHub = "github" ProviderGitLab = "gitlab" ProviderGitea = "gitea" ProviderGeneric = "generic" )
Providers understood by Auth (they only select the HTTPS basic-auth username).
const DefaultMaxBytes int64 = 512 << 20
DefaultMaxBytes caps a checkout when Clone is called with maxBytes == 0 (512 MiB).
const DeployKeyComment = "redoubt-deploy-key"
DeployKeyComment is the comment attached to generated deploy keys.
const WorkspacePerm fs.FileMode = 0o700
WorkspacePerm is the mode of every per-deployment scratch directory.
Variables ¶
var ( ErrInvalidURL = errors.New("git: invalid repository URL") ErrInvalidBaseDir = errors.New("git: invalid base directory") ErrInvalidBranch = errors.New("git: invalid branch name") ErrInvalidDockerfile = errors.New("git: invalid Dockerfile path") ErrInvalidDeploymentID = errors.New("git: invalid deployment id") ErrTooLarge = errors.New("git: checkout exceeds the size limit") ErrBaseDirEscapes = errors.New("git: base directory escapes the checkout") ErrBaseDirNotFound = errors.New("git: base directory does not exist in the checkout") ErrDockerfileEscapes = errors.New("git: Dockerfile escapes the build context") ErrDestNotEmpty = errors.New("git: destination exists and is not empty") ErrDestIsSymlink = errors.New("git: destination is a symlink") ErrNoSSHKey = errors.New("git: ssh repository URL requires a deploy key") ErrNoKnownHosts = errors.New("git: ssh known_hosts not configured and unknown hosts are not allowed") ErrWorkspaceExists = errors.New("git: workspace directory already exists") ErrWorkspaceRootInvalid = errors.New("git: workspace root is not a directory") // ErrRepositoryNotFound, ErrAuthenticationRequired and ErrAuthorizationFailed replace // go-git's transport errors, which embed the remote server's response body verbatim. ErrRepositoryNotFound = errors.New("git: repository not found") ErrAuthenticationRequired = errors.New("git: authentication required") ErrAuthorizationFailed = errors.New("git: authorization failed") ErrInvalidKnownHosts = errors.New("git: invalid known_hosts") )
Sentinel errors. Every error returned by this package wraps one of these or a go-git error.
var ErrBranchNotFound = errors.New("git: branch not found on remote")
ErrBranchNotFound is returned when the remote has no such branch.
Functions ¶
func CleanupWorkspace ¶
CleanupWorkspace removes every workspace directory under root except the keep newest (by modification time), and returns the number removed. Only direct children that are real directories named like a deployment id are considered: symlinks, files and foreign names are ignored and never followed.
func GenerateDeployKey ¶
GenerateDeployKey creates a fresh ed25519 key pair. It returns the private key as an unencrypted "OPENSSH PRIVATE KEY" PEM block (to be age-encrypted by the caller before it is stored), the public key in authorized_keys format with DeployKeyComment, and the SHA256 fingerprint. The private key is a secret: never log it.
func KnownHostsLine ¶
KnownHostsLine formats one known_hosts entry for host (host or [host]:port) and key, in the form LoadKnownHosts and Auth.SSHKnownHosts accept.
func LoadKnownHosts ¶
LoadKnownHosts reads a platform-owned known_hosts file (D-012: <data>/known_hosts) for Auth.SSHKnownHosts and verifies that every non-comment line parses, so a typo fails at configuration time rather than as an opaque host-key rejection at clone time. It refuses a file with no usable entries. The content is not a secret.
func NewWorkspaceDir ¶
NewWorkspaceDir creates root/<deploymentID> with mode 0700 and returns its path. The id must match ^[a-z0-9-]{8,64}$, root must be an existing absolute directory, and the target must not already exist.
func ResolveBranchHead ¶
ResolveBranchHead returns the commit hash at the tip of src.Branch on the remote without cloning (the pure-Go equivalent of `git ls-remote`). It is used by the polling fallback.
func SafeURL ¶
SafeURL returns u with any userinfo removed, for logs and audit events. Some users put a token in the username position, so the whole userinfo goes, not just the password. Input that does not parse as a URL (scp-like or garbage) keeps only what follows its last '@'.
func ValidateBaseDir ¶
ValidateBaseDir accepts "" or "." (repository root) or a relative, clean, slash-separated path with no ".." components. It rejects absolute paths, "~", backslashes, drive letters, NUL and control characters, and anything longer than 255 characters. A single trailing "/" is tolerated.
func ValidateBranch ¶
ValidateBranch applies git-check-ref-format rules to a short branch name: no "..", "@{", "//", leading "-", leading or trailing "/", trailing "." or ".lock", components starting with "." or ending in ".lock", no control characters, space, or any of ~ ^ : ? * [ \, and at most 255 characters.
func ValidateRepoURL ¶
ValidateRepoURL accepts https://host[:port]/path, ssh://[user@]host[:port]/path and scp-like user@host:path URLs, made of printable ASCII only. It rejects plaintext http://, git://, file:// (unless allowLocal), userinfo in https URLs (a token in the URL would leak into every log line), query strings, fragments, whitespace, control characters, leading dashes and anything else outside the grammar. allowLocal additionally permits file:///abs/path and bare absolute paths (tests and demos only). The URL itself is never included in the error.
func WebhookSecret ¶
WebhookSecret returns 32 cryptographically random bytes, hex-encoded, for use as a webhook HMAC key. The value is a secret: never log it.
Types ¶
type Auth ¶
type Auth struct {
// Token is an HTTPS personal-access / deploy token. It is sent as the basic-auth password
// with a provider-specific username ("x-access-token" for GitHub, "oauth2" for GitLab,
// "git" for Gitea and generic hosts).
Token string
// SSHPrivateKeyPEM is an unencrypted OpenSSH/PEM private key (ed25519 from
// GenerateDeployKey) used for ssh:// and scp-like URLs.
SSHPrivateKeyPEM []byte
// SSHKnownHosts holds known_hosts lines pinning the server host key(s). When set, an
// unknown or changed host key aborts the clone.
SSHKnownHosts string
// AllowUnknownHosts accepts any host key when SSHKnownHosts is empty, logging the accepted
// fingerprint at WARN level. Dev mode only; production must pin known hosts.
AllowUnknownHosts bool
}
Auth carries the credentials used to reach a repository. Values are secrets: never log them.
type Checkout ¶
type Checkout struct {
// Dir is the repository root (the dest passed to Clone).
Dir string
// ContextDir is Dir/BaseDir (cleaned), verified to lie inside Dir after resolving symlinks.
ContextDir string
// HasDockerfile reports whether Source.Dockerfile exists under ContextDir. When false the
// build package auto-generates one.
HasDockerfile bool
// DockerfilePath is the absolute Dockerfile path when HasDockerfile is true.
DockerfilePath string
CommitSHA string
CommitMessage string
Author string
// Bytes is the size of the working tree (regular files, .git excluded).
Bytes int64
}
Checkout is the result of a successful Clone.
type Source ¶
type Source struct {
// URL is the repository URL (https://, ssh://, scp-like git@host:path).
URL string
// Branch is the short branch name; empty clones the remote HEAD.
Branch string
// BaseDir is the monorepo build-context path relative to the repository root ("" or "."
// for the root).
BaseDir string
// Dockerfile is the Dockerfile path relative to BaseDir; empty means "Dockerfile".
Dockerfile string
// Auth holds the credentials, if any.
Auth Auth
// Provider selects the HTTPS token username (ProviderGitHub, …).
Provider string
// AllowLocal permits file:// URLs and absolute paths. Tests and demos only.
AllowLocal bool
}
Source describes what to clone.