procidentity

package
v0.5.0 Latest Latest
Warning

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

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

Documentation

Overview

Package procidentity observes OS process birth identity for PID-reuse protection.

A PID alone is not durable identity: after exit the number may be reassigned. Callers that later signal or attribute a process must re-observe the birth token recorded at claim time and refuse on mismatch or when identity cannot be proven on the host platform.

Index

Constants

View Source
const TokenVersionV1 = 1

TokenVersionV1 is the versioned native birth-token schema.

Variables

View Source
var (
	// ErrIdentityLost means the live process no longer matches the bound birth
	// token (exit + PID reuse, or observation failure).
	ErrIdentityLost = errors.New("process birth identity no longer matches")
	// ErrNotBound means the target was closed or never opened.
	ErrNotBound = errors.New("process target is not bound")
	// ErrUnsupportedPlatform means Bind cannot authorize destructive recovery
	// (no instance-stable signaling primitive — e.g. Darwin stalled-recovery path).
	ErrUnsupportedPlatform = errors.New("platform does not support instance-stable destructive recovery")
	// ErrAlreadyGone means the bound instance was already dead before a signal
	// could be delivered (e.g. pidfd ESRCH). Not a successful signal delivery.
	ErrAlreadyGone = errors.New("process instance already gone before signal delivery")
)

Functions

func CheckDestructiveRecoverySupported

func CheckDestructiveRecoverySupported() error

CheckDestructiveRecoverySupported reports whether this GOOS can perform instance-stable destructive recovery (Bind + signal). Darwin and other unsupported platforms refuse before any registry fence (D-R11-04).

func FileDevIno

func FileDevIno(path string) (dev, ino uint64)

FileDevIno returns device and inode for path when available.

func FileIdentityRequired

func FileIdentityRequired() bool

FileIdentityRequired reports whether reclaim receipts must include file IDs.

func Format

func Format(id Identity) string

Format returns a short diagnostic form for logs and plan output.

func Match

func Match(expected, observed Identity) bool

Match reports whether observed is the same process instance as expected. Both sides must be proven; a missing birth token never matches. TokenVersion 1 compares native fields. Legacy expected (version 0) may match via start_ms for plan/heartbeat, but Bind refuses legacy for destructive recovery.

Types

type Identity

type Identity struct {
	PID               int
	StartTimeUnixMS   uint64 // display/legacy; non-authoritative when TokenVersion>=1
	BootID            string
	TokenVersion      int    // 1 = native authority
	StartTicks        uint64 // Linux
	StartSec          int64  // Darwin
	StartUsec         int64  // Darwin
	Filetime          uint64 // Windows FILETIME 100ns
	Proven            bool
	UnavailableReason string
}

Identity is a platform-defined birth token for one process instance.

TokenVersion 1 uses platform-native fields as authority (Linux start ticks + boot ID; Darwin sec/usec; Windows FILETIME). StartTimeUnixMS remains a display/legacy convenience and is not sole authority for v1 Match.

func FromRecord

func FromRecord(pid int, startTimeUnixMS *uint64, bootID string) Identity

FromRecord reconstructs the identity persisted on a job record.

func FromRecordFull

func FromRecordFull(pid int, startTimeUnixMS *uint64, bootID string, tokenVersion int, startTicks uint64, startSec, startUsec int64, filetime uint64) Identity

FromRecordFull includes versioned native fields.

func Observe

func Observe(pid int) Identity

Observe returns the current birth identity for pid.

When the platform cannot prove identity, Proven is false and UnavailableReason names why. Callers must treat that as indeterminate for any stop authority — never as "same process".

type Liveness

type Liveness int

Liveness is a four-way observation of a recorded process instance. All platforms share this contract (E-R7 / D-R7).

const (
	// LiveMatching: live process matches the recorded birth identity.
	LiveMatching Liveness = iota
	// LiveMismatched: a live PID exists but birth identity does not match
	// (original instance is gone via reuse). This is identity-loss, not
	// death-side authority for pre-bind takeover (entarch E-R7-02).
	LiveMismatched
	// Gone: instance is proven dead (ESRCH, zombie/terminal, pidfd ESRCH, exit code).
	Gone
	// Indeterminate: observation failed (permission, unknown); never death.
	Indeterminate
)

func Classify

func Classify(expected Identity) Liveness

Classify reports liveness of the recorded instance. Implemented per-platform.

type Target

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

Target is an identity-bound handle for signalling one process instance.

On Linux it prefers a pidfd (kernel-bound to the process). On other platforms it re-validates the birth token immediately before every signal so a recycled PID cannot be targeted. Neither form is a raw "signal this number" API.

func Bind

func Bind(expected Identity) (*Target, error)

Bind opens an identity-bound target for the expected process instance. It fails closed when identity cannot be proven or the live process does not match.

func (*Target) Close

func (t *Target) Close() error

Close releases platform resources. It is safe to call more than once.

func (*Target) Expected

func (t *Target) Expected() Identity

Expected returns the birth identity this target was bound to.

func (*Target) HardStopOnly

func (t *Target) HardStopOnly() bool

HardStopOnly reports whether this platform's stop primitive is a hard stop (e.g. Windows TerminateProcess) with no portable graceful TERM for arbitrary processes. Callers must report ForcedKill / hard-stop semantics and must not invent a TERM→grace→KILL story.

func (*Target) SignalKill

func (t *Target) SignalKill() error

SignalKill delivers an uncatchable kill to the bound instance.

func (*Target) SignalTerm

func (t *Target) SignalTerm() error

SignalTerm delivers a graceful termination request to the bound instance.

func (*Target) Terminated

func (t *Target) Terminated() (bool, error)

Terminated reports whether the bound process instance is gone.

func (*Target) WaitTerminated

func (t *Target) WaitTerminated(timeout, poll time.Duration) (bool, error)

WaitTerminated polls until the bound instance is gone or the timeout elapses. timeout == 0 means already expired (immediate return, no wait). timeout < 0 uses the 30s default. Callers sharing a monotonic deadline must pass remain() which may be 0 at expiry (D-R11-03).

Jump to

Keyboard shortcuts

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