native

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Index

Constants

View Source
const ServiceGroupName = "_ephemerd"

ServiceGroupName is a dedicated primary group for the service user. Using a dedicated group instead of staff (gid 20 — the default group for every normal macOS account) keeps the runner process from inheriting group access to the many files on a typical Mac that are staff-group owned. Falls back to staff if the group can't be created.

View Source
const ServiceUserName = "_ephemerd"

ServiceUserName is the hidden macOS service account that native runner jobs execute as when no [runner.macos] user is configured. It is created lazily on first use and persists like other service accounts (_www, ...). Per-job user deletion is deliberately avoided: dscl/sysadminctl user deletion wedges opendirectoryd on modern macOS.

Variables

This section is empty.

Functions

func GenerateSandboxProfile

func GenerateSandboxProfile(jobDir, dataDir, pemPath string, opts SandboxOptions) string

GenerateSandboxProfile returns a macOS sandbox profile that restricts the runner process. Paths are templated with the job-specific directories.

pemPath is the configured GitHub App private_key_path (may be empty). When set it is denied explicitly as a belt-and-suspenders measure on top of the broad /Users content deny below.

Two postures:

  • opts.Strict == false (default): allow-by-default with an explicit deny-list. This is the previously-smoke-tested behavior and is emitted byte-for-byte as before when strict is off.
  • opts.Strict == true (opt-in): deny-by-default with an explicit allow-list for the paths/services a GHA runner + toolchain needs, with the same tier-1/tier-2 denies layered on top. Much stronger, but not guaranteed complete for every toolchain — must be live-tested.

Types

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner executes a GitHub Actions runner directly on the macOS host inside a per-job sandbox. Each job gets its own workspace, HOME, TMPDIR, keychain, and Homebrew prefix.

func New

func New(dataDir, jobID, jitConfig, runnerSrc, pemPath string, log *slog.Logger) (*Runner, error)

New creates a native macOS runner for a single job. It prepares the workspace directory structure but does not start the runner process.

pemPath is the configured GitHub App private_key_path (empty for PAT auth). It is threaded into the sandbox profile so the runner is denied read access to the operator's App private key even though the daemon runs as root with no HOME — see GenerateSandboxProfile.

func (*Runner) SetMaxProcesses

func (r *Runner) SetMaxProcesses(n int)

SetMaxProcesses sets the ulimit -u process cap applied before the runner is exec'd. 0 disables the cap (unlimited).

func (*Runner) SetRunAsUser

func (r *Runner) SetRunAsUser(username string)

SetRunAsUser configures a non-root user to run the runner process as. The daemon (running as root) drops privileges via setuid/setgid when launching the runner. Strongly recommended when the daemon runs as root: without it, CI job steps execute as root on the host.

func (*Runner) SetSandboxStrict

func (r *Runner) SetSandboxStrict(strict bool)

SetSandboxStrict enables the deny-by-default sandbox profile. Opt-in: the strict allow-list is not guaranteed to cover every toolchain and must be live-smoke-tested before it is turned on for a host.

func (*Runner) Start

func (r *Runner) Start(ctx context.Context) error

Start copies the runner binary, sets up the sandbox and environment, and launches the runner process.

func (*Runner) Stop

func (r *Runner) Stop()

Stop forcefully terminates the runner and all its children, cleans up the keychain, and removes the job workspace.

func (*Runner) Wait

func (r *Runner) Wait() (int, error)

Wait blocks until the runner process exits and returns its exit code.

type SandboxOptions

type SandboxOptions struct {
	// Strict switches from allow-by-default (deny-list) to deny-by-default
	// (allow-list). Opt-in; default false keeps today's already-smoke-tested
	// allow-by-default profile byte-for-byte identical.
	Strict bool
	// HomebrewPrefix is the host Homebrew prefix (e.g. /opt/homebrew) the
	// runner uses read-only. Needed in the strict allow-list.
	HomebrewPrefix string
	// DeveloperDir is the resolved active Xcode / CLT path (xcode-select -p).
	// Needed in the strict allow-list so clang/git shims work. May be empty.
	DeveloperDir string
}

SandboxOptions carries the knobs GenerateSandboxProfile needs beyond the job/data/pem paths.

Jump to

Keyboard shortcuts

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