socket

package
v0.23.0 Latest Latest
Warning

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

Go to latest
Published: Jun 12, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package socket owns the daemon's Unix-domain-socket listener, the per-OS peer-credential capture, and the length-prefix message framing.

ADR-0010 specifies SOCK_SEQPACKET, but macOS does not support SEQPACKET on AF_UNIX (only SOCK_STREAM and SOCK_DGRAM). Phase 1 uses SOCK_STREAM uniformly on Linux and macOS with a 4-byte big-endian length prefix per frame. Peer credentials are still reliably retrievable on stream sockets via SO_PEERCRED (Linux) / LOCAL_PEERCRED + LOCAL_PEEREPID (macOS), so the transport simplification does not affect the trust model. A follow-up issue should amend ADR-0010 to record the per-OS transport types.

Index

Constants

View Source
const MaxFrameSize = 1 << 20

MaxFrameSize caps a single emitter frame at 1 MiB. Larger frames are rejected outright so a misbehaving emitter cannot exhaust the daemon's memory by claiming an arbitrary length prefix.

Variables

This section is empty.

Functions

func WriteFrame

func WriteFrame(w io.Writer, payload []byte) error

WriteFrame writes one length-prefixed frame to w. Exposed so the daemon's own integration tests (which dial the listener as if they were emitters) don't reimplement the wire encoding. This package is daemon-internal, so Phase 2 emitter SDKs in other modules cannot import it directly — they reimplement the same encoding (4-byte big-endian length prefix, MaxFrameSize cap), which is documented in daemon/README.md so the wire form stays canonical across implementations.

io.Writer's contract permits short writes with a nil error. A short write would corrupt framing for the receiver, so writes are looped until all bytes are sent or an error is returned.

Types

type Frame

type Frame struct {
	Payload []byte
	Peer    PeerCred
}

Frame pairs the JSON payload an emitter sent with the OS-attested peer cred captured at accept time. Handler receives one Frame per emitter message.

type Handler

type Handler func(ctx context.Context, f Frame) error

Handler processes a single frame. Implementations MUST be safe for concurrent use (the listener invokes Handler from many connection goroutines). A returned error is logged via the listener's ErrorLog but is otherwise non-fatal — the connection stays open for subsequent frames.

type Listener

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

Listener wraps a net.UnixListener with peer-cred capture and length-prefix framing. Construct via Listen, drive via Serve, stop via Close.

func Listen

func Listen(opts Options) (*Listener, error)

Listen binds a SOCK_STREAM Unix-domain listener at opts.Path and returns it ready to Serve. The caller must call Close to release the socket file.

func (*Listener) Close

func (l *Listener) Close() error

Close stops accepting new connections, closes any in-flight connections to unblock their read loops, removes the socket file, and waits for handlers to finish. Idempotent.

func (*Listener) Path

func (l *Listener) Path() string

Path returns the socket file path.

func (*Listener) Serve

func (l *Listener) Serve(ctx context.Context) error

Serve accepts connections until ctx is cancelled or Close is called. Each accepted connection is handled in its own goroutine; Serve returns nil on graceful shutdown.

type Options

type Options struct {
	// Path is the socket path. Required. The parent directory is created with
	// 0750 if missing. Any pre-existing socket file at Path is removed first
	// (a stale socket from a previous run is the common case).
	Path string

	// Handler is called for each received frame. Required.
	Handler Handler

	// ErrorLog logs non-fatal errors (handler errors, malformed frames). When
	// nil, errors are silently discarded.
	ErrorLog func(format string, args ...any)
}

Options configure a Listener.

type PeerCred

type PeerCred struct {
	// Platform discriminates which fields are populated. One of
	// "linux", "darwin". A future Windows port will introduce additional
	// values and fields (user_sid, integrity_level).
	Platform string

	// PID is the connecting process's process id. Signed because POSIX pid_t
	// is signed (and -1 is a valid sentinel).
	PID int32

	// UID, GID are POSIX credentials. uid_t and gid_t are unsigned 32-bit on
	// every platform we support, so widen-and-format via uint64 to preserve
	// the full range — narrowing into int32 here would wrap UIDs above
	// 2^31 to negative values and corrupt the recorded peer.
	UID uint32
	GID uint32

	// ExePath is the absolute path to the connecting process's executable,
	// or "" when the daemon could not resolve it. On Linux this is read from
	// /proc/<pid>/exe; on macOS via the SYS_PROC_INFO(PROC_PIDPATHINFO)
	// syscall (the call libproc's proc_pidpath() wraps). Failure is
	// non-fatal — the daemon still records pid/uid/gid.
	ExePath string
}

PeerCred is the OS-attested identity of a connecting emitter, captured at accept() time before any frame is read. The agent's self-asserted identity in the frame body is untrusted; this is what makes the audit meaningful.

Jump to

Keyboard shortcuts

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