cnc

package module
v0.0.0-...-188fab0 Latest Latest
Warning

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

Go to latest
Published: Mar 18, 2026 License: MIT Imports: 0 Imported by: 0

README

CNC

A generic device management protocol.

Goals

  • Abstraction for server management, CI agent, AI agent
  • Allows different channels to run inside the same protocol
  • Serializable with JSON and CBOR

Documentation

Index

Constants

View Source
const (
	SessionTemplateShell        = "std.shell"
	SessionTemplateFileTransfer = "std.file-transfer"
	SessionTemplateDesktop      = "std.desktop"
	SessionTemplateCI           = "std.ci"
	SessionTemplateAgentTool    = "std.agent-tool"
)

Well-known session template names. Agents may also advertise custom names.

Variables

This section is empty.

Functions

This section is empty.

Types

type AgentConfig

type AgentConfig struct {
	HeartbeatInterval int `json:"heartbeat_interval"` // seconds
}

type CapabilityReport

type CapabilityReport struct {
	ProtocolVersion ProtocolVersion   `json:"protocol_version"`
	Hostname        string            `json:"hostname"`       // non-unique, untrusted
	Tags            KV                `json:"tags,omitempty"` // agent-reported, untrusted
	Capabilities    []SessionTemplate `json:"capabilities"`
	Extensions      Extensions        `json:"extensions,omitempty"`
}

CapabilityReport is sent by the agent; entirely untrusted by the central.

type Channel

type Channel struct {
	ChannelSpec

	ID        string `json:"id"` // UUID
	SessionID string `json:"session_id"`
}

type ChannelDirection

type ChannelDirection string
const (
	ChannelBidirectional ChannelDirection = "BIDI"
	ChannelAgentToServer ChannelDirection = "MISO"
	ChannelServerToAgent ChannelDirection = "MOSI"
)

type ChannelDisposition

type ChannelDisposition string

ChannelDisposition controls whether the agent forwards or drops this channel.

const (
	ChannelForward ChannelDisposition = "fwd"
	ChannelDiscard ChannelDisposition = "dsc"
)

type ChannelSpec

type ChannelSpec struct {
	Name           string             `json:"name"` // type-specific name, e.g. stdin/stdout/stderr
	Type           ChannelType        `json:"type"`
	Direction      ChannelDirection   `json:"direction"`
	Disposition    ChannelDisposition `json:"disposition"`
	BufferSizeHint int                `json:"buffer_size_hint,omitempty"` // bytes; 0 = default
	Extensions     Extensions         `json:"extensions,omitempty"`
}

ChannelSpec describes a channel in a SessionTemplate (no ID or SessionID).

type ChannelType

type ChannelType string
const (
	ChannelControl ChannelType = "std.control"
	ChannelTTY     ChannelType = "std.tty"
)

type ChannelUpdate

type ChannelUpdate struct {
	ChannelID   string              `json:"channel_id"`
	Disposition *ChannelDisposition `json:"disposition,omitempty"`
	Extensions  Extensions          `json:"extensions,omitempty"`
}

ChannelUpdate reconfigures a live channel. Nil pointer fields = no change.

type Codec

type Codec interface {
	Marshal(v any) ([]byte, error)
	Unmarshal(data []byte, v any) error
}

Codec marshals and unmarshals extension values.

type Command

type Command struct {
	ID        string      `json:"id"` // UUID
	SessionID string      `json:"session_id"`
	Type      CommandType `json:"type"`
	// Payload is the encoded ExecPayload/SignalPayload/ResizePayload,
	// using the same codec as the outer envelope.
	Payload []byte `json:"payload"`
	// nil = use session default channels
	ChannelOverrides []Channel  `json:"channel_overrides,omitempty"`
	Extensions       Extensions `json:"extensions,omitempty"`
}

Command carries a typed payload pre-serialized with the same codec as the outer envelope. The receiver decodes the outer struct first, reads Type, then decodes Payload into the appropriate payload struct. This avoids interface{} while keeping the outer envelope decodable without type knowledge.

type CommandState

type CommandState string
const (
	CommandPending  CommandState = "pending"
	CommandRunning  CommandState = "running"
	CommandExited   CommandState = "exited"
	CommandKilled   CommandState = "killed"
	CommandTimedOut CommandState = "timed-out"
)

type CommandStatus

type CommandStatus struct {
	CommandID  string       `json:"command_id"`
	State      CommandState `json:"state"`
	ExitCode   *int         `json:"exit_code,omitempty"`   // nil until exited
	SignalName *string      `json:"signal_name,omitempty"` // nil unless killed by signal
	Extensions Extensions   `json:"extensions,omitempty"`
}

type CommandType

type CommandType string
const (
	CommandExec   CommandType = "exec"   // run to completion
	CommandSpawn  CommandType = "spawn"  // persistent process
	CommandSignal CommandType = "signal" // send signal to running process
	CommandResize CommandType = "resize" // resize PTY
)

type ExecPayload

type ExecPayload struct {
	Argv    []string          `json:"argv"`
	Env     map[string]string `json:"env,omitempty"`
	Cwd     string            `json:"cwd,omitempty"`
	Timeout int               `json:"timeout,omitempty"` // seconds; 0 = none
	PTY     *PTYConfig        `json:"pty,omitempty"`
}

ExecPayload is used by CommandExec and CommandSpawn.

type Extension

type Extension struct {
	ID       string `json:"id"`
	Critical bool   `json:"critical"`
	Value    []byte `json:"value"` // opaque; decoded by registered handler
}

Extension is an ASN.1-inspired pluggable field. If Critical is true and the receiver has no registered handler for ID, it must abort processing of the enclosing message. If Critical is false, unknown extensions are silently ignored.

type Extensions

type Extensions []Extension

type KV

type KV map[string]string

type PTYConfig

type PTYConfig struct {
	Cols int    `json:"cols"`
	Rows int    `json:"rows"`
	Term string `json:"term,omitempty"` // e.g. "xterm-256color"
}

type ProtocolVersion

type ProtocolVersion string
const ProtocolV1 ProtocolVersion = "cnc/1"

type RegisterRequest

type RegisterRequest struct {
	AgentID    string           `json:"agent_id,omitempty"`
	Capability CapabilityReport `json:"capability"`
	Extensions Extensions       `json:"extensions,omitempty"`
}

RegisterRequest is sent by the agent on startup. AgentID is empty on first registration; the central assigns a UUID. On reconnect, carry the previously assigned UUID. Auth is via Extensions.

type RegisterResponse

type RegisterResponse struct {
	AgentID     string      `json:"agent_id"`               // confirmed or newly assigned UUID
	TrustedTags KV          `json:"trusted_tags,omitempty"` // central-assigned, authoritative
	Config      AgentConfig `json:"config"`
	Extensions  Extensions  `json:"extensions,omitempty"`
}

type ResizePayload

type ResizePayload struct {
	Cols int `json:"cols"`
	Rows int `json:"rows"`
}

type Session

type Session struct {
	ID              string       `json:"id"`       // UUID
	Template        string       `json:"template"` // template name used
	AgentID         string       `json:"agent_id"`
	State           SessionState `json:"state"`
	CreatedAt       int64        `json:"created_at"` // Unix seconds
	DefaultChannels []Channel    `json:"default_channels,omitempty"`
	Extensions      Extensions   `json:"extensions,omitempty"`
}

Session is the central-authoritative record; distributed to both central and agent.

type SessionPolicy

type SessionPolicy struct {
	Concurrent int `json:"concurrent,omitempty"` // max concurrent sessions; 0 = unlimited
}

type SessionRequest

type SessionRequest struct {
	Template      string     `json:"template"` // template name
	TargetAgentID *string    `json:"target_agent_id,omitempty"`
	Labels        KV         `json:"labels,omitempty"`
	Extensions    Extensions `json:"extensions,omitempty"`
}

SessionRequest is sent central → agent. TargetAgentID nil = fleet-routed (central picks agent). Non-nil = pinned to that agent UUID (e.g. CI resume on same machine).

type SessionState

type SessionState string
const (
	SessionPending SessionState = "pending"
	SessionActive  SessionState = "active"
	SessionClosing SessionState = "closing"
	SessionClosed  SessionState = "closed"
)

type SessionTemplate

type SessionTemplate struct {
	Name            string        `json:"name"`
	Policy          SessionPolicy `json:"policy,omitempty"`
	InitialChannels []ChannelSpec `json:"initial_channels,omitempty"` // opened automatically on session start
	AllowedChannels []ChannelSpec `json:"allowed_channels,omitempty"` // may be requested by central after start
	Extensions      Extensions    `json:"extensions,omitempty"`
}

SessionTemplate describes a session type an agent can host. Name may be a well-known constant or a custom string. The central sends the template name in SessionRequest; the agent looks up the matching SessionTemplate from its CapabilityReport.

type SignalPayload

type SignalPayload struct {
	Signal string `json:"signal"` // e.g. "SIGTERM"
}

Directories

Path Synopsis
extensions
qos
serdes

Jump to

Keyboard shortcuts

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