hostctx

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package hostctx describes observed facts about a system, so that findings can be upgraded from possible to confirmed.

The interface exists from the start even though the live implementation lands later, because rules must be written against it and must behave sensibly when nothing is known. Unknown is the zero implementation: every question returns "not known", so a rule needs no nil checks and the no-context path is the one exercised by default.

Live implementations read files only, never subprocesses: `/sys/fs/selinux/ enforce`, `/proc/self/mountinfo`, `/etc/subuid`, `/etc/subgid`. That is the spec's guidance, and it is also what makes a captured context replayable, since a directory of files can be serialised but a subprocess cannot.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Capture

func Capture(dir string) error

Capture writes the live context to a directory, so it can be replayed elsewhere. Capture on the machine where something is wrong, lint on your own.

The files keep their original paths under the directory, so replay is the same code reading the same layout, which is what keeps live and replay from diverging.

func Describe

func Describe(c Context) []string

Describe summarises a context for `quaddoc doctor`.

Types

type Context

type Context interface {
	// SELinux reports the SELinux mode, or SELinuxUnknown.
	SELinux() SELinuxMode

	// MountFor returns the mount entry whose mount point is the longest
	// prefix of the given path: the filesystem that path actually lives on.
	MountFor(path string) (Mount, bool)

	// SubUIDRanges and SubGIDRanges return the calling user's subordinate ID
	// allocations.
	SubUIDRanges() ([]IDRange, bool)
	SubGIDRanges() ([]IDRange, bool)

	// UnprivilegedPortStart returns net.ipv4.ip_unprivileged_port_start.
	// QD031 must read this rather than assume 1024: administrators commonly
	// lower it to 80.
	UnprivilegedPortStart() (int, bool)

	// ExistingUnitNames returns the names of units already installed in the
	// Quadlet search path, for collision detection.
	ExistingUnitNames() ([]string, bool)

	// Rootless reports whether Podman is running rootless.
	Rootless() (bool, bool)
}

Context is what rules may consult about the host.

Every method reports whether the fact is known, so that a rule can distinguish "the host says no" from "we did not look". Conflating the two is how a linter starts asserting things it has not checked.

type IDRange

type IDRange struct {
	Start int
	Count int
}

IDRange is a subordinate UID or GID allocation from /etc/subuid or /etc/subgid.

func (IDRange) Contains

func (r IDRange) Contains(id int) bool

Contains reports whether an ID falls within the range.

type Live

type Live struct {
	// Root is prefixed to every path read, which is what lets the same code
	// serve both the live system (Root = "") and a captured directory.
	Root string
	// contains filtered or unexported fields
}

Live reads facts from the running system.

Everything here comes from files, never subprocesses. That is the spec's guidance, and it is also what makes a captured context replayable: a directory of files can be serialised and read back, whereas a subprocess cannot. It also means quaddoc works with no podman binary present.

func NewLive

func NewLive() *Live

NewLive returns a context reading the running system.

func NewReplay

func NewReplay(dir string) *Live

NewReplay returns a context reading a previously captured directory. The findings it produces are identical to those from the machine it was captured on, which is the whole point: capture on the broken machine, lint anywhere.

func (*Live) ExistingUnitNames

func (l *Live) ExistingUnitNames() ([]string, bool)

ExistingUnitNames lists units already installed in the Quadlet search path.

func (*Live) MountFor

func (l *Live) MountFor(path string) (Mount, bool)

MountFor returns the filesystem a path is on: the mount whose mount point is the longest prefix of the path.

func (*Live) Mounts

func (l *Live) Mounts() []Mount

Mounts returns the whole mount table, for capture.

func (*Live) Rootless

func (l *Live) Rootless() (bool, bool)

Rootless reports whether Podman would run rootless, which is simply whether the effective user is root.

func (*Live) SELinux

func (l *Live) SELinux() SELinuxMode

SELinux reads the enforcement mode.

The file is absent on a kernel without SELinux, which is how "disabled" is distinguished from "permissive": permissive has policy loaded and the file present containing 0.

func (*Live) SubGIDRanges

func (l *Live) SubGIDRanges() ([]IDRange, bool)

SubGIDRanges returns the calling user's subordinate GID allocations.

func (*Live) SubUIDRanges

func (l *Live) SubUIDRanges() ([]IDRange, bool)

SubUIDRanges returns the calling user's subordinate UID allocations.

func (*Live) UnprivilegedPortStart

func (l *Live) UnprivilegedPortStart() (int, bool)

UnprivilegedPortStart reads net.ipv4.ip_unprivileged_port_start from procfs rather than invoking sysctl, so there is no subprocess and the value can be captured.

type Mount

type Mount struct {
	// MountPoint is where the filesystem is mounted.
	MountPoint string
	// FSType is the filesystem type, e.g. `ext4`, `nfs4`, `fuse.sshfs`.
	// QD003 decides from this, not from a path pattern.
	FSType string
	// Options are the mount options, which may include a `context=` setting
	// that makes relabelling unnecessary or wrong.
	Options string
}

Mount is one entry from the mount table.

type SELinuxMode

type SELinuxMode int

SELinuxMode is the state of SELinux on a system.

const (
	// SELinuxUnknown means no host context was gathered.
	SELinuxUnknown SELinuxMode = iota
	// SELinuxDisabled means SELinux is absent from the kernel.
	SELinuxDisabled
	// SELinuxPermissive means policy is loaded but violations are logged
	// rather than denied.
	SELinuxPermissive
	// SELinuxEnforcing means policy is loaded and enforced.
	SELinuxEnforcing
)

func (SELinuxMode) String

func (m SELinuxMode) String() string

type Static

type Static struct {
	SELinuxMode    SELinuxMode
	Mounts         []Mount
	SubUID         []IDRange
	SubGID         []IDRange
	PortStart      int
	PortStartKnown bool
	UnitNames      []string
	UnitNamesKnown bool
	IsRootless     bool
	RootlessKnown  bool
}

Static is a Context with fixed answers, for tests and for replaying a captured context.

func (Static) ExistingUnitNames

func (s Static) ExistingUnitNames() ([]string, bool)

func (Static) MountFor

func (s Static) MountFor(path string) (Mount, bool)

MountFor returns the longest mount point that prefixes path, which is the filesystem the path is actually on. A shorter match like `/` would otherwise shadow the specific mount the caller cares about.

func (Static) Rootless

func (s Static) Rootless() (bool, bool)

func (Static) SELinux

func (s Static) SELinux() SELinuxMode

func (Static) SubGIDRanges

func (s Static) SubGIDRanges() ([]IDRange, bool)

func (Static) SubUIDRanges

func (s Static) SubUIDRanges() ([]IDRange, bool)

func (Static) UnprivilegedPortStart

func (s Static) UnprivilegedPortStart() (int, bool)

type Unknown

type Unknown struct{}

Unknown is a Context that knows nothing. It is the default, so that the no-host-context path is the one exercised unless the user opts in.

func (Unknown) ExistingUnitNames

func (Unknown) ExistingUnitNames() ([]string, bool)

func (Unknown) MountFor

func (Unknown) MountFor(string) (Mount, bool)

func (Unknown) Rootless

func (Unknown) Rootless() (bool, bool)

func (Unknown) SELinux

func (Unknown) SELinux() SELinuxMode

func (Unknown) SubGIDRanges

func (Unknown) SubGIDRanges() ([]IDRange, bool)

func (Unknown) SubUIDRanges

func (Unknown) SubUIDRanges() ([]IDRange, bool)

func (Unknown) UnprivilegedPortStart

func (Unknown) UnprivilegedPortStart() (int, bool)

Jump to

Keyboard shortcuts

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