config

package
v0.2.16 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultRunnerGroupID int64 = 1

DefaultRunnerGroupID is GitHub's "Default" runner group; used when Org.RunnerGroupID is unset (zero).

View Source
const SchemaVersion = "1"

SchemaVersion is the only config schema accepted by this binary. Bump when making backwards-incompatible config changes.

Variables

This section is empty.

Functions

func AddOrg

func AddOrg(path string, o Org) error

AddOrg appends o to the orgs list in the agent config at path.

func AddRepo

func AddRepo(path string, r RepoTarget) error

AddRepo appends r to the repos list in the agent config at path.

func CheckBaseURL added in v0.2.11

func CheckBaseURL(base string) error

CheckBaseURL accepts an empty base URL or the root of a GHES instance. The API and App URLs are derived from it, so it must carry no path, and github.com is spelled by leaving it empty.

func CredentialsPath

func CredentialsPath(agentConfigPath string) string

CredentialsPath is credentials.yaml in the same directory as the agent config.

func WriteCredentials

func WriteCredentials(path string, c Credentials) error

WriteCredentials writes c to path with 0600 perms (it holds a bearer token).

Types

type Agent

type Agent struct {
	Version       string       `yaml:"version"`
	ControllerURL string       `yaml:"controller_url"`
	Token         string       `yaml:"token"`
	Name          string       `yaml:"name"`
	Labels        []string     `yaml:"labels"`
	Driver        DriverConfig `yaml:"driver"`
	// The agent holds the GitHub App keys, polls GitHub, and mints JIT configs,
	// so the orgs it serves and its poll source are configured here.
	Orgs []Org `yaml:"orgs"`
	// Repos serves individual repositories (personal-account / per-repo runners).
	Repos  []RepoTarget `yaml:"repos"`
	Source SourceConfig `yaml:"source"`
	// MetricsListen serves Prometheus metrics at /metrics on this address, with
	// no auth. Empty (the default) serves nothing.
	MetricsListen string `yaml:"metrics_listen"`
}

func LoadAgent

func LoadAgent(path string) (*Agent, error)

type Aging

type Aging struct {
	BoostPerMinute int `yaml:"boost_per_minute"`
}

type Controller

type Controller struct {
	Version string `yaml:"version"`
	Listen  string `yaml:"listen"`
	Token   string `yaml:"token"`
	// Orgs is read only by the local `ushr cost` report, which queries GitHub
	// directly; the keyless control plane schedules on agent-reported metadata
	// and needs no org config of its own.
	Orgs    []Org         `yaml:"orgs"`
	Policy  Policy        `yaml:"policy"`
	Webhook WebhookConfig `yaml:"webhook"`
	// DispatchDSN, when set, backs the dispatch ledger with Postgres (Neon) for
	// the hosted control plane instead of the local JSONL WAL. Empty = JSONL.
	DispatchDSN string `yaml:"dispatch_dsn"`
	// DispatchLedgerPath overrides where the controller persists in-flight
	// dispatch state across restarts. Empty means dispatch.DefaultPath().
	DispatchLedgerPath string `yaml:"dispatch_ledger_path"`
}

func LoadController

func LoadController(path string) (*Controller, error)

type Credentials

type Credentials struct {
	ControllerURL string   `yaml:"controller_url"`
	Token         string   `yaml:"token"`
	Name          string   `yaml:"name"`
	Orgs          []string `yaml:"orgs"`
}

Credentials are the login-managed connection secrets, written by `ushr login` to credentials.yaml alongside the agent config and overlaid by LoadAgent.

type DriverConfig

type DriverConfig struct {
	Type     DriverType `yaml:"type"`
	Image    string     `yaml:"image"`
	Capacity int        `yaml:"capacity"`

	// Runtime pins the container CLI for the docker driver ("docker" or
	// "podman"). Empty autodetects (docker, then podman). Ignored by other drivers.
	Runtime string `yaml:"runtime"`

	// MinFreeGB is the free-space floor on the driver's image store (tart's
	// home, the container data root). Under it the agent stops accepting
	// dispatches, so the work stays schedulable on a host that can run it rather
	// than failing on a full disk here. Zero takes the driver's default;
	// negative disables the gate but leaves reclaim working to the same mark.
	MinFreeGB int `yaml:"min_free_gb"`

	// ExclusiveDaemon declares that nothing but ushr's runners uses this host's
	// container daemon. Jobs mount the host docker socket, so what they leave
	// behind carries none of our labels and can only be collected by pruning
	// unowned objects — safe exactly when there is no other user. Docker driver
	// only; off by default.
	ExclusiveDaemon bool `yaml:"exclusive_daemon"`

	// Docker-driver-specific, ignored by other drivers. The load-bearing ones:
	// Volumes mounts the host docker socket for buildx, GroupAdd carries the
	// host docker GID so the runner user can use it, and Memory (e.g. "4g")
	// caps each runner container so a heavy build OOM-kills its own job rather
	// than the host.
	Network    string   `yaml:"network"`
	Volumes    []string `yaml:"volumes"`
	ExtraHosts []string `yaml:"extra_hosts"`
	GroupAdd   []string `yaml:"group_add"`
	Memory     string   `yaml:"memory"`
	Entrypoint string   `yaml:"entrypoint"`

	// BuildCache gives each repo its own persistent buildx builder, so image
	// layers and RUN --mount=type=cache survive between that repo's jobs in a
	// cache store separate from other repos'. This is cache isolation, not a
	// trust boundary (jobs share the host docker socket), and within a repo a
	// fork-PR build shares the warm cache with protected builds — keep the usual
	// "no untrusted PRs on self-hosted runners" rule. Docker driver only, on by
	// default (unset = enabled; needs the host buildx plugin, and each dispatch
	// degrades to uncached when buildx is unavailable). BuildkitImage overrides
	// the buildkit image; BuildCacheGB caps each repo's cache before a prune
	// (default 20). StateDir holds the per-repo buildx configs (default
	// ~/.local/share/ushr).
	BuildCache        *bool  `yaml:"build_cache"`
	BuildkitImage     string `yaml:"buildkit_image"`
	BuildCacheGB      int    `yaml:"build_cache_gb"`
	BuildCacheIdleHrs int    `yaml:"build_cache_idle_hours"` // reap a repo's builder after this idle (default 168 = 7d)
	StateDir          string `yaml:"state_dir"`
}

type DriverType

type DriverType string
const (
	DriverTypeTart   DriverType = "tart"
	DriverTypeLume   DriverType = "lume"
	DriverTypeDocker DriverType = "docker"
	DriverTypeK8s    DriverType = "k8s"
)

type Org

type Org struct {
	Name           string `yaml:"name"`
	AppID          int64  `yaml:"app_id"`
	PrivateKeyPath string `yaml:"private_key_path"`
	Priority       int    `yaml:"priority,omitempty"`
	// BaseURL is the GitHub Enterprise Server root (e.g.
	// https://ghe.example.com). Empty means github.com.
	BaseURL string `yaml:"base_url,omitempty"`
	// RunnerGroupID is the GitHub runner group to register JIT runners into.
	// Falls back to DefaultRunnerGroupID if zero.
	RunnerGroupID int64 `yaml:"runner_group_id,omitempty"`
	// Repos optionally restricts polling to these repo names within the org.
	// Empty means poll every repo the App installation can access — which blows
	// the API rate limit on a large installation. Set it to the handful that
	// actually use the runner; this also skips the list-installation-repos call.
	// Poll source only.
	Repos []string `yaml:"repos,omitempty"`
	// ScaleSets lists the runner scale sets to serve in this org. Scaleset
	// source only; repo scoping is enforced GitHub-side by the runner group.
	ScaleSets []ScaleSet `yaml:"scale_sets,omitempty"`
}

type Policy

type Policy struct {
	Type  PolicyType `yaml:"type"`
	Aging Aging      `yaml:"aging"`
	// Priorities sets the priority per scope (an org login or "owner/repo").
	// A listed scope overrides the priority its agents report; an unlisted
	// scope keeps the agent-reported value.
	Priorities map[string]int `yaml:"priorities"`
}

type PolicyType

type PolicyType string
const PolicyTypePriority PolicyType = "priority"

type RepoTarget

type RepoTarget struct {
	Owner          string `yaml:"owner"`
	Repo           string `yaml:"repo"`
	AppID          int64  `yaml:"app_id"`
	PrivateKeyPath string `yaml:"private_key_path"`
	Priority       int    `yaml:"priority,omitempty"`
	// BaseURL is the GitHub Enterprise Server root; empty means github.com.
	BaseURL string `yaml:"base_url,omitempty"`
	// ScaleSets lists the repo-level runner scale sets to serve. Scaleset
	// source only; a repo scale set serves only this repo.
	ScaleSets []ScaleSet `yaml:"scale_sets,omitempty"`
}

RepoTarget serves a single repository's runners (the personal-account path: user accounts have no org-level runner pool, so runners are per-repo). The App must have repository "Administration: write" on the repo.

func (RepoTarget) Scope

func (r RepoTarget) Scope() string

Scope is the tenant scope ("owner/repo") this target serves; matches the enrollment-token grant and domain.Job.Org.

type ScaleSet

type ScaleSet struct {
	Name string `yaml:"name"`
	// MaxRunners caps outstanding runners for this set. Size it to the
	// capacity of the agent(s) labelled to serve it: it is what the controller
	// reports to GitHub as the set's max capacity when polling for messages.
	MaxRunners int `yaml:"max_runners"`
}

ScaleSet is one runner scale set. Its name doubles as the runs-on label workflows target.

type SourceConfig

type SourceConfig struct {
	Type     SourceType    `yaml:"type"`
	Interval time.Duration `yaml:"interval"`
}

type SourceType

type SourceType string
const (
	SourceTypePoll     SourceType = "poll"
	SourceTypeScaleSet SourceType = "scaleset"
)

type WebhookConfig

type WebhookConfig struct {
	Secret     string `yaml:"secret"`
	LedgerPath string `yaml:"ledger_path"`
}

WebhookConfig enables the workflow_job receiver that feeds the job ledger. Empty Secret disables it. LedgerPath defaults to ledger.DefaultPath().

Jump to

Keyboard shortcuts

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