Documentation
¶
Overview ¶
Package agentproto defines the CBOR wire protocol shared by local runners and mproxy-agent. It receives command, stream, file-operation, logging, and recording state from remoteexec and the agent, and feeds broker, remote backends, workspacefs, pathstub, and cmd/mproxy-agent with stable frame and RPC types.
Index ¶
- type AgentConfig
- type CommandEnd
- type CommandStart
- type Decoder
- type Direction
- type Encoder
- type ExecMsg
- type FileDirEntry
- type FileOp
- type FileOpReq
- type FileOpResp
- type FileOpServer
- type FileStat
- type FileStatfs
- type Frame
- type FrameType
- type LogEntry
- type Mux
- func (m *Mux) DecodeOne() (*Frame, error)
- func (m *Mux) FileOp(ctx context.Context, req *FileOpReq) (*FileOpResp, error)
- func (m *Mux) OnFileOp(fn func(*FileOpReq) *FileOpResp)
- func (m *Mux) OnLog(fn func(*LogEntry))
- func (m *Mux) OnSignal(fn func(int))
- func (m *Mux) ReadLoop(ctx context.Context) (exitCode int, err error)
- func (m *Mux) RegisterStream(id uint32, h StreamHandler)
- func (m *Mux) Send(f *Frame) error
- func (m *Mux) SendData(stream uint32, data []byte) error
- func (m *Mux) SendEOF(stream uint32) error
- func (m *Mux) SetRecorder(rec *Recorder, seq uint32)
- type MuxLogHandler
- type PathInfo
- type PathInfoEntry
- type PathQuery
- type Record
- type RecordType
- type RecordedFrame
- type Recorder
- func (r *Recorder) Close() error
- func (r *Recorder) WriteCommandEnd(seq uint32, exitCode int) error
- func (r *Recorder) WriteCommandStart(exec *ExecMsg) (uint32, error)
- func (r *Recorder) WriteFrame(seq uint32, dir Direction, f *Frame) error
- func (r *Recorder) WriteSessionFooter() error
- func (r *Recorder) WriteSessionHeader(h *SessionHeader) error
- type SessionFooter
- type SessionHeader
- type StreamHandler
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AgentConfig ¶
type AgentConfig struct {
EnvKeep []string `cbor:"env_keep"`
EnvRemove []string `cbor:"env_remove"`
}
AgentConfig carries the agent's runtime configuration, sent via FrameConfig before any FrameExec. Patterns are globs or /regex/ delimited strings.
type CommandEnd ¶
type CommandEnd struct {
SeqNum uint32 `cbor:"seq"`
EndTime int64 `cbor:"end_time"`
ExitCode int `cbor:"exit_code"`
}
CommandEnd marks the end of a command execution.
type CommandStart ¶
type CommandStart struct {
SeqNum uint32 `cbor:"seq"`
StartTime int64 `cbor:"start_time"`
Exec ExecMsg `cbor:"exec"`
}
CommandStart marks the beginning of a command execution.
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
Decoder reads CBOR-encoded frames.
func NewDecoder ¶
NewDecoder returns a Decoder that reads from r.
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder writes CBOR-encoded frames. It is safe for concurrent use.
func NewEncoder ¶
NewEncoder returns an Encoder that writes to w.
type ExecMsg ¶
type ExecMsg struct {
Path string `cbor:"path"`
Argv []string `cbor:"argv"`
Env []string `cbor:"env"`
Cwd string `cbor:"cwd"`
ExtraFDs []uint32 `cbor:"fds,omitempty"`
}
ExecMsg carries the command details in a FrameExec.
type FileDirEntry ¶ added in v1.2.0
type FileDirEntry struct {
Stat FileStat `cbor:"st"`
}
FileDirEntry is one entry in a FileOpReadDir response.
type FileOp ¶ added in v1.2.0
type FileOp uint8
FileOp identifies a remote file operation. Operations are RPC-style: the caller assigns a unique ReqID and expects exactly one FileOpResp back with the same ReqID. File handles are agent-side state; the client treats them as opaque uint32 tokens returned by Open/Create.
const ( FileOpOpen FileOp = 1 // input: Path, Flags → output: Handle FileOpCreate FileOp = 2 // input: Path → output: Handle (O_WRONLY|O_CREATE|O_TRUNC) FileOpOpenFile FileOp = 3 // input: Path, Flags → output: Handle FileOpClose FileOp = 4 // input: Handle FileOpReadAt FileOp = 5 // input: Handle, Offset, Size → output: Data, EOF FileOpWriteAt FileOp = 6 // input: Handle, Offset, Data → output: Size (bytes written) FileOpStat FileOp = 7 // input: Path → output: Stat FileOpLstat FileOp = 8 // input: Path → output: Stat, does not follow symlinks FileOpReadDir FileOp = 9 // input: Path → output: Entries FileOpMkdir FileOp = 10 // input: Path FileOpMkdirAll FileOp = 11 // input: Path FileOpRemove FileOp = 12 // input: Path FileOpRename FileOp = 13 // input: Path, NewPath FileOpChmod FileOp = 14 // input: Path, Mode FileOpTruncate FileOp = 15 // input: Path, Size FileOpGetwd FileOp = 16 // → output: Path FileOpFsync FileOp = 17 // input: Handle FileOpReadlink FileOp = 18 // input: Path → output: Path FileOpSymlink FileOp = 19 // input: Path target, NewPath linkpath FileOpLink FileOp = 20 // input: Path old, NewPath new FileOpChown FileOp = 21 // input: Path, UID, GID FileOpChtimes FileOp = 22 // input: Path, AtimeNanos, MTimeNanos FileOpStatfs FileOp = 23 // input: Path → output: Statfs FileOpFstat FileOp = 24 // input: Handle → output: Stat FileOpFtruncate FileOp = 25 // input: Handle, Size )
type FileOpReq ¶ added in v1.2.0
type FileOpReq struct {
ReqID uint32 `cbor:"id"`
Op FileOp `cbor:"op"`
Path string `cbor:"p,omitempty"`
NewPath string `cbor:"np,omitempty"`
Flags int32 `cbor:"fl,omitempty"`
Mode uint32 `cbor:"mo,omitempty"`
UID uint32 `cbor:"uid,omitempty"`
GID uint32 `cbor:"gid,omitempty"`
Handle uint32 `cbor:"h,omitempty"`
Offset int64 `cbor:"of,omitempty"`
Size int64 `cbor:"sz,omitempty"`
AtimeNanos int64 `cbor:"at,omitempty"`
MTimeNanos int64 `cbor:"mt,omitempty"`
Data []byte `cbor:"d,omitempty"`
}
FileOpReq is the request half of a file-op RPC. Only fields relevant to the chosen Op should be set.
type FileOpResp ¶ added in v1.2.0
type FileOpResp struct {
ReqID uint32 `cbor:"id"`
Errno uint32 `cbor:"er,omitempty"`
ErrMsg string `cbor:"em,omitempty"`
Handle uint32 `cbor:"h,omitempty"`
Data []byte `cbor:"d,omitempty"`
N int64 `cbor:"n,omitempty"` // bytes read/written
EOF bool `cbor:"eof,omitempty"` // for ReadAt
Path string `cbor:"p,omitempty"` // for Getwd
Stat *FileStat `cbor:"st,omitempty"`
Statfs *FileStatfs `cbor:"sf,omitempty"`
Entries []FileDirEntry `cbor:"en,omitempty"`
}
FileOpResp is the response half. Errno (when nonzero) is a POSIX errno value the client maps back to an os.Err* sentinel; ErrMsg is a human-readable description for logs.
type FileOpServer ¶ added in v1.2.0
type FileOpServer struct {
// contains filtered or unexported fields
}
FileOpServer is the agent-side implementation of file ops. It is stateful: Open/Create return uint32 handles that subsequent ReadAt/ WriteAt/Close requests reference. Handles are local to the server.
func NewFileOpServer ¶ added in v1.2.0
func NewFileOpServer() *FileOpServer
NewFileOpServer constructs an empty server.
func (*FileOpServer) CloseAll ¶ added in v1.2.0
func (s *FileOpServer) CloseAll()
CloseAll releases all open handles. Call this when the file-op service loop exits so the agent doesn't leak fds.
func (*FileOpServer) Handle ¶ added in v1.2.0
func (s *FileOpServer) Handle(req *FileOpReq) *FileOpResp
Handle dispatches a request to the matching os.* primitive and returns a response. Errors are surfaced through Resp.Errno + ErrMsg so the client can map them back to os.Err* sentinels.
type FileStat ¶ added in v1.2.0
type FileStat struct {
Name string `cbor:"n"`
Size int64 `cbor:"s"`
Mode uint32 `cbor:"m"`
MTimeNanos int64 `cbor:"t,omitempty"`
ATimeNanos int64 `cbor:"at,omitempty"`
CTimeNanos int64 `cbor:"ct,omitempty"`
UID uint32 `cbor:"uid,omitempty"`
GID uint32 `cbor:"gid,omitempty"`
Nlink uint32 `cbor:"nl,omitempty"`
Rdev uint32 `cbor:"rd,omitempty"`
Blocks uint64 `cbor:"bl,omitempty"`
Blksize uint32 `cbor:"bs,omitempty"`
Ino uint64 `cbor:"ino,omitempty"`
IsDir bool `cbor:"d,omitempty"`
}
FileStat is a backend-agnostic snapshot of os.FileInfo fields.
type FileStatfs ¶ added in v1.3.0
type FileStatfs struct {
Blocks uint64 `cbor:"b,omitempty"`
Bfree uint64 `cbor:"bf,omitempty"`
Bavail uint64 `cbor:"ba,omitempty"`
Files uint64 `cbor:"f,omitempty"`
Ffree uint64 `cbor:"ff,omitempty"`
Bsize uint32 `cbor:"bs,omitempty"`
Frsize uint32 `cbor:"fr,omitempty"`
NameLen uint32 `cbor:"nl,omitempty"`
}
FileStatfs is a backend-agnostic statfs/statvfs snapshot.
type Frame ¶
type Frame struct {
Type FrameType `cbor:"t"`
Stream uint32 `cbor:"s,omitempty"` // 0=stdin, 1=stdout, 2=stderr, 3+=extra fds
Data []byte `cbor:"d,omitempty"`
Signal int `cbor:"sig,omitempty"`
Code int `cbor:"c,omitempty"`
Error string `cbor:"e,omitempty"`
Exec *ExecMsg `cbor:"x,omitempty"`
Log *LogEntry `cbor:"l,omitempty"`
Config *AgentConfig `cbor:"cfg,omitempty"`
Query *PathQuery `cbor:"q,omitempty"`
Info *PathInfo `cbor:"i,omitempty"`
FileOp *FileOpReq `cbor:"fop,omitempty"`
FileResp *FileOpResp `cbor:"frp,omitempty"`
}
Frame is a single message on the CBOR mux. Fields are omitted when zero-valued so only the relevant subset appears on the wire.
type FrameType ¶
type FrameType uint8
FrameType identifies the kind of message on the CBOR mux.
const ( FrameExec FrameType = 1 // local → agent: start command FrameData FrameType = 2 // bidirectional: data for a stream FrameEOF FrameType = 3 // sender closes a stream FrameSignal FrameType = 4 // local → agent: deliver signal to child pgid FrameExit FrameType = 5 // agent → local: child exited (terminal frame) FrameError FrameType = 6 // agent → local: internal error FrameLog FrameType = 7 // agent → local: log message FrameConfig FrameType = 8 // local → agent: serialized config FramePathQuery FrameType = 9 // local → agent: enumerate PATH executables FramePathInfo FrameType = 10 // agent → local: PATH enumeration result FrameFileOp FrameType = 11 // local → agent: file-op request FrameFileResp FrameType = 12 // agent → local: file-op response )
type LogEntry ¶
type LogEntry struct {
Level int `cbor:"lvl"` // slog.Level value
Msg string `cbor:"msg"`
Attrs []string `cbor:"a,omitempty"` // key=value pairs
}
LogEntry carries a structured log record from the agent.
type Mux ¶
type Mux struct {
// contains filtered or unexported fields
}
Mux multiplexes CBOR frames over a reader/writer pair. Incoming frames are dispatched to registered handlers; Send serialises outgoing frames.
func NewMux ¶
NewMux creates a mux over the given reader (incoming frames) and writer (outgoing frames). Typically r and w are the two ends of an SSH session's stdio.
func (*Mux) DecodeOne ¶
DecodeOne reads a single frame from the underlying reader without dispatching it. Useful for reading the initial FrameExec before the read loop starts.
func (*Mux) FileOp ¶ added in v1.2.0
FileOp performs a client-side file-op RPC: encodes req with a fresh ReqID, sends it, and waits for the matching FileOpResp. Multiple FileOp calls are safe concurrently.
func (*Mux) OnFileOp ¶ added in v1.2.0
func (m *Mux) OnFileOp(fn func(*FileOpReq) *FileOpResp)
OnFileOp registers the agent-side handler that services file-op requests. The handler receives the request and must return a fully populated FileOpResp (ReqID is propagated automatically).
func (*Mux) ReadLoop ¶
ReadLoop reads and dispatches frames until the context is cancelled, a FrameExit is received, or the underlying reader returns an error. It returns the exit code from a FrameExit, or -1 if the loop ended without one.
func (*Mux) RegisterStream ¶
func (m *Mux) RegisterStream(id uint32, h StreamHandler)
RegisterStream adds a handler for the given stream ID.
func (*Mux) SetRecorder ¶
SetRecorder enables recording of all frames passing through this mux. seq is the command sequence number assigned by the Recorder.
type MuxLogHandler ¶
type MuxLogHandler struct {
// contains filtered or unexported fields
}
MuxLogHandler is a slog.Handler that sends log records over the CBOR mux as FrameLog frames. This lets agent-side logs appear on the machineproxy process where the operator can see them.
func NewMuxLogHandler ¶
func NewMuxLogHandler(mux *Mux, level slog.Level) *MuxLogHandler
NewMuxLogHandler creates a handler that forwards log records through mux.
type PathInfo ¶ added in v1.1.0
type PathInfo struct {
Entries []PathInfoEntry `cbor:"entries"`
}
PathInfo carries the agent's enumeration result. Entries are deduped by Name (first-found wins per PATH precedence) and listed in the same order as the input Paths.
type PathInfoEntry ¶ added in v1.1.0
type PathInfoEntry struct {
Name string `cbor:"name"`
RemotePath string `cbor:"path"`
Mode uint32 `cbor:"mode"`
Size int64 `cbor:"size"`
MTimeNanos int64 `cbor:"mtime,omitempty"`
}
PathInfoEntry describes one stub entry returned by FramePathInfo.
type PathQuery ¶ added in v1.1.0
type PathQuery struct {
Paths []string `cbor:"paths,omitempty"`
}
PathQuery requests enumeration of executable files reachable through the listed PATH-style directories. An empty Paths slice tells the agent to use its own $PATH at the time of the request.
type Record ¶
type Record struct {
Type RecordType `cbor:"type"`
Header *SessionHeader `cbor:"header,omitempty"`
CmdStart *CommandStart `cbor:"cmd_start,omitempty"`
Frame *RecordedFrame `cbor:"frame,omitempty"`
CmdEnd *CommandEnd `cbor:"cmd_end,omitempty"`
}
Record is the top-level envelope written to a recording file. Exactly one of the optional fields is set per record.
type RecordType ¶
type RecordType uint8
RecordType tags each record in a recording file.
const ( RecordSessionHeader RecordType = 1 RecordCommandStart RecordType = 2 RecordFrame RecordType = 3 RecordCommandEnd RecordType = 4 )
type RecordedFrame ¶
type RecordedFrame struct {
SeqNum uint32 `cbor:"seq"`
Timestamp int64 `cbor:"ts"`
Direction Direction `cbor:"dir"`
Frame Frame `cbor:"frame"`
}
RecordedFrame wraps an agentproto Frame with recording metadata.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder writes session recording data. Safe for concurrent use.
func NewRecorder ¶
NewRecorder creates a Recorder that writes to path. The file is created (or truncated) immediately.
func NewRecorderWriter ¶
NewRecorderWriter creates a Recorder that writes to w. The caller is responsible for closing w.
func (*Recorder) WriteCommandEnd ¶
WriteCommandEnd marks the completion of a command.
func (*Recorder) WriteCommandStart ¶
WriteCommandStart marks the beginning of a new command and returns its sequence number.
func (*Recorder) WriteFrame ¶
WriteFrame records a single agentproto frame with direction metadata.
func (*Recorder) WriteSessionFooter ¶
WriteSessionFooter writes the session-level summary. Call once before closing the recorder.
func (*Recorder) WriteSessionHeader ¶
func (r *Recorder) WriteSessionHeader(h *SessionHeader) error
WriteSessionHeader writes the session-level metadata. Call once at the start of a recording.
type SessionFooter ¶
type SessionFooter struct {
}
SessionFooter is written once at the end of a recording file.
type SessionHeader ¶
type SessionHeader struct {
Version string `cbor:"version"`
StartTime int64 `cbor:"start_time"` // unix nanos
LocalUser string `cbor:"local_user"`
LocalPID int `cbor:"local_pid"`
BackendType string `cbor:"backend_type,omitempty"`
BackendAddr string `cbor:"backend_addr,omitempty"`
AgentPath string `cbor:"agent_path"`
}
SessionHeader is written once at the start of a recording file.
type StreamHandler ¶
StreamHandler receives data and EOF events for a single stream ID.
func WriterHandler ¶
func WriterHandler(w io.WriteCloser) StreamHandler
WriterHandler returns a StreamHandler that writes to w and closes it on EOF.