procguard

package
v1.0.4 Latest Latest
Warning

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

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

Documentation

Overview

Package procguard keeps forge from signalling the processes it is running inside.

forge stops processes it started: `forge env down <env>`, `forge env down --all`, the `forge env up` pre-flight that replaces a running stack, host-infra shutdown and `forge debug stop`. Each selects its targets by forge's ownership markers, and those markers are ENVIRONMENT VARIABLES — inherited by every descendant of a process forge started. A forge-started server that itself runs work (an agent server hosting sessions, a shell, an IDE task runner) therefore hands the markers to everything it spawns, including a `forge env down` typed inside it. That command used to select the very server hosting it, SIGTERM the tree, and end its own session along with every sibling session running in it.

The rule here is structural, not a heuristic: a forge command never signals its own LINEAGE — itself and every ancestor up to init. Lineage is read from the kernel's parent links, so no environment variable, process name or configuration can widen or narrow it, and the same process table always produces the same decision.

Index

Constants

This section is empty.

Variables

View Source
var ErrLineage = errors.New("process is in this command's own lineage")

ErrLineage is wrapped by every refusal to signal a member of this command's own lineage. Callers test for it with errors.Is.

Functions

This section is empty.

Types

type Entry

type Entry struct {
	// PPID is the parent pid. 0 means "no trustworthy parent" and ends the
	// walk (on Windows a recorded parent that is dead or younger than its
	// child is reported as 0 — see trustedParent).
	PPID int
	// PGID is the process-group id, or 0 on a platform whose process groups
	// a signal cannot target (Windows).
	PGID int
}

Entry is what a lineage walk reads about one process.

type Lineage

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

Lineage is one process and every ancestor above it, nearest first.

func Self

func Self() Lineage

Self returns this process's lineage, read from the operating system.

It is read fresh on every call rather than cached: forge also runs embedded in long-lived servers, and a process whose parent dies is re-parented, so a cached chain could go on protecting a pid the OS has since recycled. A walk is a handful of syscalls.

func Walk

func Walk(self int, lookup Lookup) Lineage

Walk builds the lineage of self from lookup. self is always a member, even when lookup knows nothing about it. The walk ends at a pid <= 0, a process that is its own parent, a pid already seen (a cycle), or a pid lookup cannot answer for. Pure: the decision is a function of the table it is handed.

func (Lineage) Contains

func (l Lineage) Contains(pid int) bool

Contains reports whether pid is this process or one of its ancestors.

func (Lineage) ContainsGroup

func (l Lineage) ContainsGroup(pgid int) bool

ContainsGroup reports whether any member of the lineage belongs to process group pgid — so a group-wide signal to it would reach this command.

func (Lineage) PIDs

func (l Lineage) PIDs() []int

PIDs returns the lineage nearest first: this process, its parent, and so on.

func (Lineage) Self

func (l Lineage) Self(pid int) bool

Self reports whether pid is the process the lineage was walked from.

type LineageError

type LineageError struct {
	PID int
	// Command names the process for the reader ("" when unreadable).
	Command string
}

LineageError is the refusal for one pid.

func (*LineageError) Error

func (e *LineageError) Error() string

func (*LineageError) Unwrap

func (e *LineageError) Unwrap() error

type Lookup

type Lookup func(pid int) (Entry, bool)

Lookup reports the table entry for pid; ok is false when pid is unknown (exited, or unreadable).

Jump to

Keyboard shortcuts

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