executor

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package executor runs a runner's command somewhere (ADR-007). Contained executors (docker) are required for unattended lanes; process is for interactive steps and shadow mode only. Every run gets its own worktree, run folder and tool caches.

Index

Constants

View Source
const (
	WorkDir  = "/work"
	RunDir   = "/run/ynf"
	SpoolDir = spool.ContainerPath
)

Container paths: what a contained command sees.

Variables

View Source
var ErrEgress = errors.New("this lane allows egress, which needs the egress proxy: a linux ynf binary (make build, or YNF_LINUX_BINARY)")

ErrEgress means the lane allows hosts but the egress proxy cannot be started. A containment control that cannot be applied is an error, never a warning (ADR-007).

Functions

func ResolveUser

func ResolveUser(spec string, lookup func(name string) (uint32, error)) (uint32, error)

ResolveUser is the uid an image's user setting names: empty is root, a number is itself, and a name is looked up. A group after a colon is not needed.

Types

type Docker

type Docker struct {
	Bin         string
	ProxyBinary string // a static linux ynf, run as the egress proxy
	ProxyImage  string // the image the proxy runs in; default alpine:3.20
}

Docker runs the command in a container: no network at all when the lane allows no hosts, and otherwise an internal network whose only way out is ynf's allow-list proxy (ADR-007).

func (Docker) Args

func (d Docker) Args(j Job, name, network string) ([]string, error)

Args builds the job's docker command line for a container name and network; it is separate from Run so it can be tested.

func (Docker) Contained

func (Docker) Contained() bool

Contained implements Executor.

func (Docker) Name

func (Docker) Name() string

Name implements Executor.

func (Docker) Paths

func (Docker) Paths(Job) (string, string)

Paths implements Executor.

func (Docker) ProxyArgs

func (d Docker) ProxyArgs(j Job, name string) []string

ProxyArgs builds the egress proxy container's command line.

func (Docker) Run

func (d Docker) Run(ctx context.Context, j Job) (Output, error)

Run implements Executor.

func (Docker) RunUID

func (d Docker) RunUID(ctx context.Context, j Job) (uint32, bool, error)

RunUID implements RunUser: a run that keeps its image's own user writes as the user the image names, found in the image's configuration, and in the image's /etc/passwd when it names the user rather than numbering it. Any other docker run is ynf's own user (--user).

func (Docker) SpoolVolume

func (Docker) SpoolVolume() bool

SpoolVolume implements SpoolVolumes. Docker Desktop for Mac cannot bind-mount a host folder that is a mount of its own: the daemon fails with "error while creating mount source path ... file exists", so a run there keeps a plain folder and the quota watcher. A docker daemon on Linux binds one like any folder.

type Executor

type Executor interface {
	Name() string
	// Contained reports whether the executor confines the run (ADR-007).
	Contained() bool
	// Paths returns the worktree and run folder as the command sees them.
	Paths(j Job) (worktree, runDir string)
	Run(ctx context.Context, j Job) (Output, error)
}

Executor runs jobs.

func For

func For(name string) (Executor, error)

For returns the executor a lane names.

type Inline

type Inline struct {
	// User is the user runs run as; default ynh, the user an agent image is built for.
	User string
	// Chown changes a path's owner; nil is os.Lchown. For tests.
	Chown func(path string, uid, gid int) error
	// Credential sets the user a command runs as; nil runs it as that user. For tests.
	Credential func(c *exec.Cmd, uid, gid uint32)
}

Inline runs the runner as a process inside the container ynf itself runs in: the factory image, as a job (ADR-007, ADR-009). The job runner provides the containment (the network policy, the dropped capabilities); ynf keeps its credentials from the run by running it as another user.

ynf runs as root in the container with only SETUID, SETGID and CHOWN. Before a run it hands the run's folders to the run user; it starts the run as that user with only the run's own environment; afterwards it takes the folders back. The run cannot read ynf's environment or memory (another user, no SYS_PTRACE) or its token.

func (Inline) Contained

func (Inline) Contained() bool

Contained implements Executor: the operator declared the containment (ADR-007).

func (Inline) Name

func (Inline) Name() string

Name implements Executor.

func (Inline) Paths

func (Inline) Paths(j Job) (string, string)

Paths implements Executor.

func (Inline) Run

func (in Inline) Run(ctx context.Context, j Job) (Output, error)

Run implements Executor.

func (Inline) RunUID

func (in Inline) RunUID(_ context.Context, _ Job) (uint32, bool, error)

RunUID implements RunUser: the run user, which is not ynf's own (Run refuses it when it is).

type Job

type Job struct {
	Argv     []string
	Env      map[string]string
	Worktree string // host path, real (no symlinks)
	RunDir   string // host path for the run's files and caches
	Image    string
	Egress   []string
	Timeout  time.Duration
	// ImageUser keeps the image's own user and home: an agent image built by ynh keeps its
	// harness and vendor configuration under its user's home.
	ImageUser bool
	// Secrets reach the run by name only: docker reads each value from its own environment, so a
	// secret never appears in a command line or a process listing.
	Secrets map[string]string
	// Share are folders the run needs beside its own, if any; the inline executor hands them to the run user too.
	Share []string
	// Spool is the run's own spool folder on the host, when it has one (ynr ADR-004): the run
	// writes its telemetry there, as YNR_SPOOL. A docker run has this folder mounted at SpoolDir,
	// and nothing else of the spool; the inline executor hands it to the run user.
	Spool string
	// NoOTLP starts the run without the operator's OTEL_EXPORTER_OTLP_*: the collector is on, and
	// ynr serve ships to the operator's endpoint instead.
	NoOTLP bool
}

Job is one run.

type Output

type Output struct {
	Exit   int
	Stdout []byte
	Stderr []byte
	Denied []string // hosts the egress proxy refused
}

Output is how the command ended.

type Process

type Process struct{}

Process runs the command directly on the host. It is not contained, so ynf only allows it for interactive steps and shadow mode (ADR-007).

func (Process) Contained

func (Process) Contained() bool

Contained implements Executor.

func (Process) Name

func (Process) Name() string

Name implements Executor.

func (Process) Paths

func (Process) Paths(j Job) (string, string)

Paths implements Executor.

func (Process) Run

func (Process) Run(ctx context.Context, j Job) (Output, error)

Run implements Executor.

type RunUser

type RunUser interface {
	// RunUID returns the user the run writes as and whether it is another than ynf's own, the
	// owner of the run's spool folder. An error means it could not be found out.
	RunUID(ctx context.Context, j Job) (uid uint32, other bool, err error)
}

RunUser is implemented by an executor whose run can write as a user other than ynf's own, so the run's spool manifest can name that user (ynr ADR-003). The answer comes from the image's own configuration or the executor's own setting, which the run cannot reach or change.

type SpoolVolumes

type SpoolVolumes interface {
	SpoolVolume() bool
}

SpoolVolumes is implemented by an executor that may not be able to use a run's spool folder when it is a volume of its own, in which case the folder stays a plain one.

Jump to

Keyboard shortcuts

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