Help us shape the future of Go! Take the 2026 Go Developer Survey

source

package
v0.17.2 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: AGPL-3.0 Imports: 37 Imported by: 0

Documentation

Overview

Package source fetches an app's source and exposes it read-only.

R-020: the source tree is strictly read-only input. Pando looks at it and never asks it for permission — there is no pando.yaml, and nothing in a repo can change how Pando behaves.

Index

Constants

View Source
const DefaultUploadDir = "/var/lib/pando/uploads"

DefaultUploadDir is where uploaded sources were kept before they moved into the database, and where a file not yet moved is still found.

Variables

This section is empty.

Functions

func AllowLocalRepositories added in v0.8.0

func AllowLocalRepositories()

AllowLocalRepositories lets a repository on this machine's disk be fetched, for tests that build one in a temporary directory. Pando never calls it: a local path is not a source a person can give.

func AppFrom

func AppFrom(ctx context.Context) string

AppFrom is the app ForApp recorded, or empty.

func ForApp

func ForApp(ctx context.Context, appID string) context.Context

ForApp records which app a fetch is for, so a source connection's use is audited against it.

func GuardTransport added in v0.14.0

func GuardTransport(t *http.Transport) *http.Transport

GuardTransport is t with every connection it opens checked against the same guard as a repository fetch: on the address dialed, redirects included, and through a proxy on the destination's host as well. For other reads made at an address a person gave — an image's registry — so that one reaches what a repository may (a registry on the LAN or this machine) and is refused what a repository is (link-local addresses, where a cloud's metadata service answers, and Pando's own port and database).

func RefusedAddress added in v0.14.0

func RefusedAddress(err error) bool

RefusedAddress reports whether err is the guard refusing a connection, however a client wrapped it.

func SetGuard added in v0.8.0

func SetGuard(g Guard)

SetGuard installs the endpoints Pando's own fetches must not reach. Called once at startup; until then only the fixed classes are refused.

Types

type Access

type Access struct {
	Credential api.GitCredential

	// Connection names the source connection it came from, for messages:
	// "the source connection 'GitHub (acme)'".
	Connection string
}

Access is what a repository is read with.

type Checkout

type Checkout struct {
	// Dir is the root of the working tree.
	Dir string

	// Commit is the resolved SHA. R-120: Ref is what the user asked for, Commit
	// is what runs, and it is written back into the spec so a redeploy of the
	// same revision builds the same code.
	Commit string

	// Digest names an uploaded source, which has no commit: the SHA-256 of the
	// archive it was unpacked from, as "sha256:<hex>". Never written into the
	// spec as a commit (R-120) — it is how a scan knows the same archive when
	// it sees it again (R-312).
	Digest string
	// contains filtered or unexported fields
}

Checkout is a fetched source tree on disk.

func (*Checkout) Close

func (c *Checkout) Close()

Close removes the checkout.

func (*Checkout) Identity

func (c *Checkout) Identity() string

Identity is what names this exact source: the commit, or for an upload the archive's digest. Empty when neither is known.

func (*Checkout) View

func (c *Checkout) View(subdir string) api.SourceView

View returns a read-only view rooted at the source, honoring Subdir.

type Credentials

type Credentials interface {
	Access(ctx context.Context, src spec.Source, purpose Purpose) (*Access, error)
}

Credentials finds what a repository is read with. Nil Access with no error means read it anonymously.

type Guard added in v0.8.0

type Guard struct {
	// OwnPorts are the ports Pando listens on. Refused on loopback and on
	// every address of this machine's interfaces.
	OwnPorts []uint16

	// Database is where Pando's state store is, as host and port. A host
	// name is resolved when a dial is checked, since it may be a Compose
	// service name whose address changes.
	Database []HostPort

	// Resolve looks a database host up. net.DefaultResolver when nil.
	Resolve func(ctx context.Context, host string) ([]netip.Addr, error)

	// LocalAddrs lists this machine's interface addresses.
	// net.InterfaceAddrs when nil.
	LocalAddrs func() ([]netip.Addr, error)
}

Guard is the endpoints a fetch must not reach beyond the fixed classes.

type HostPort added in v0.8.0

type HostPort struct {
	Host string
	Port uint16
}

HostPort is a host and the port on it.

type Purpose

type Purpose int

Purpose is why a repository is being read, so a use that matters — a clone whose code will run — can be audited and a poll for new commits is not.

const (
	// PurposeClone fetches the code.
	PurposeClone Purpose = iota

	// PurposeCheck only asks the repository what it has: whether it can be
	// read, or what a branch points at.
	PurposeCheck
)

type Sources

type Sources struct {
	// Uploads keeps uploaded sources in the database, where every control
	// host reads them (R-417). Nil keeps them as files under UploadDir.
	Uploads UploadStore

	// UploadDir is where uploaded sources were kept as files. With Uploads
	// set, a file found here is moved into the database when it is read.
	UploadDir string

	// WorkDir is where a clone or an unpacked upload is made while a deploy or
	// a detection reads it: server.work_dir, beside Pando's other working
	// files, rather than the system temporary directory, which is often a
	// small tmpfs that a few concurrent clones fill (issue #72). Empty means
	// the system temporary directory, for tests and embeddings.
	WorkDir string

	// Credentials finds what a repository is read with, from the install's
	// source connections (R-091, issue #127). Nil reads every repository
	// anonymously, which is what a public one needs.
	Credentials Credentials
}

Sources fetches an app's source, and keeps the sources that were uploaded rather than cloned (R-262).

A value handed to each caller rather than a package variable: the upload directory used to be one, and two servers in one process — which is what a parallel test run is — wrote their uploads into each other's (issue #31).

The zero value fetches git and image sources. An upload needs Uploads or UploadDir.

func (Sources) DiscardUpload

func (s Sources) DiscardUpload(ctx context.Context, appID string) error

DiscardUpload removes a deleted app's stored upload.

The archive is kept for the app's next deploy, and a deleted app has none: a restore goes to an app created again, with an upload of its own (R-206). It had been kept forever (issue #55). A missing archive is not an error — an app built from git never had one.

func (Sources) Fetch

func (s Sources) Fetch(ctx context.Context, src spec.Source) (*Checkout, error)

Fetch clones an app's source.

The caller must have checked the source allowlist first (R-092) — by the time this runs, disk has been written to, which is exactly why that check belongs before it and not inside it.

func (Sources) MigrateUploads added in v0.17.0

func (s Sources) MigrateUploads(ctx context.Context) (int, error)

MigrateUploads moves every archive file under UploadDir that the database has no upload for into it (R-417), and returns how many it moved. Every file is tried; the first error is returned after the rest.

func (Sources) Probe

func (s Sources) Probe(ctx context.Context, src spec.Source) error

Probe checks that src can be read, with the credential its connection gives or anonymously, without cloning it. It is how creating an app from a private repository fails at once, saying why, rather than at detection.

The caller has checked the source allowlist first (R-092).

func (Sources) ResolveRef

func (s Sources) ResolveRef(ctx context.Context, src spec.Source) (string, error)

ResolveRef returns the commit a ref currently points at, without cloning.

Auto-deploy runs this every five minutes for every app tracking a branch, and the answer is usually "the same as last time". Cloning to find that out would make Pando's largest source of network traffic a question it almost never needs to act on.

func (Sources) ResolveTracked

func (s Sources) ResolveTracked(ctx context.Context, src spec.Source, ad spec.AutoDeploy) (Tracked, error)

ResolveTracked answers "what would auto-deploy deploy now" for an app's source and its auto-deploy settings (R-141), without cloning.

The branch trigger follows AutoDeploy.Branch, or the ref the app was deployed from when that is empty. The release trigger follows the newest tag that counts as a release (NewestRelease).

With the credential the app's source connection gives, as every other read of the repository is (issue #127), so a private repository auto-deploys.

func (Sources) StoreUpload

func (s Sources) StoreUpload(ctx context.Context, appID string, r io.Reader) error

StoreUpload keeps an uploaded archive for an app.

type Tracked

type Tracked struct {
	// Ref is fully qualified: refs/heads/main or refs/tags/v1.2.0. It goes in
	// the revision's Source.Ref, so the revision says what it was cut from.
	Ref    string
	Commit string
}

Tracked is what an auto-deploy trigger currently points at: the ref it found and the commit under it. Both empty when there is nothing to deploy.

func NewestRelease

func NewestRelease(refs []*plumbing.Reference, pattern string) Tracked

NewestRelease picks the newest release tag from a remote's refs.

With no pattern, a release is a stable semantic version tag. With one, it is any tag whose name matches the pattern as a glob (path.Match: `release-*`, `v*`), because plenty of projects tag releases without following semver (issue #40).

Newest is by version order, not by date: a remote's ref list carries no dates, and reading them would mean cloning. Names are compared a run of digits at a time as numbers, so release-10 is newer than release-9 and 2026.10.1 is newer than 2026.9.30.

type UploadStore added in v0.17.0

type UploadStore interface {
	PutUpload(ctx context.Context, appID string, r io.Reader) error
	// AddUpload stores r only if the app has none, and reports whether it
	// did. An app that no longer exists is errs.NotFound.
	AddUpload(ctx context.Context, appID string, r io.Reader) (bool, error)
	// OpenUpload answers ok false when the app has no upload stored.
	OpenUpload(ctx context.Context, appID string) (io.ReadCloser, bool, error)
	DeleteUpload(ctx context.Context, appID string) error
}

UploadStore keeps uploaded archives (state.Uploads).

Jump to

Keyboard shortcuts

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