Documentation
¶
Index ¶
- Constants
- func CheckSystemResources() error
- func CloseAllActiveFtpWorkers()
- func CloseAllActiveTunnels()
- func CloseTunnel(sessionID string) error
- func CommitAsync(session *scheduler.Session, commissioned bool, ...)
- func CommitSystemInfo()
- func IsValidSessionID(sessionID string) bool
- func RegisterCommandPID(pid int, commandID, username string) func()
- func RegisterFtpWorker(sessionID string, cmd *exec.Cmd) chan struct{}
- func RegisterTunnel(sessionID string, tc *TunnelClient) bool
- func RunTunnelDaemon(socketPath string)
- func SyncSystemInfo(session *scheduler.Session, keys []string)
- func UnregisterFtpWorker(sessionID string, cmd *exec.Cmd)
- type AccessPolicy
- type Address
- type AuthManager
- func (am *AuthManager) AddPIDCommandMapping(pid int, commandID, username string)
- func (am *AuthManager) AddPIDSessionMapping(pid int, session *SessionInfo)
- func (am *AuthManager) HandleSudoApprovalResponse(response SudoApprovalResponse) error
- func (am *AuthManager) LookupPID(pid int) (TrackerEntry, bool)
- func (am *AuthManager) RemovePIDCommandMapping(pid int, commandID string)
- func (am *AuthManager) RemovePIDSessionMapping(pid int)
- func (am *AuthManager) Start(ctx context.Context)
- func (am *AuthManager) Stop()
- func (am *AuthManager) UpdateBlockLocalSudo(value bool)
- type BaseRequest
- type CodeServerConfig
- func (c *CodeServerConfig) ToArgs(port int, userDataDir string) []string
- func (c *CodeServerConfig) ToConfigYAML() string
- func (c *CodeServerConfig) ToEnv(homeDir string, includeXDG bool) []string
- func (c *CodeServerConfig) ToExtensionGalleryEnv() string
- func (c *CodeServerConfig) ToSettingsJSON() ([]byte, error)
- type CodeServerManager
- type CodeServerStatus
- type CommandDispatcher
- type CommandResult
- type CommandRunner
- type ComparableData
- type ControlClient
- func (cc *ControlClient) Close()
- func (cc *ControlClient) CloseAndReconnect(ctx context.Context)
- func (cc *ControlClient) Connect()
- func (cc *ControlClient) GetWSPath() string
- func (cc *ControlClient) HandleMessage(message []byte)
- func (cc *ControlClient) IsConnected() bool
- func (cc *ControlClient) RunForever(ctx context.Context)
- func (cc *ControlClient) WriteJSON(data interface{}) error
- type ControlMessage
- type Disk
- type FtpClient
- type FtpCommand
- type FtpConfigData
- type FtpContent
- type FtpData
- type FtpResult
- type GroupData
- type Interface
- type IsAlpconRequest
- type IsAlpconResponse
- type MFAResponse
- type OSData
- type Partition
- type PtyClient
- type ServerData
- type SessionInfo
- type SudoApprovalRequest
- type SudoApprovalResponse
- type SudoRequest
- type SyncHashes
- type Syncer
- type SystemData
- type TerminalManager
- func (m *TerminalManager) Get(sessionID string) *PtyClient
- func (m *TerminalManager) Refresh(sessionID string) error
- func (m *TerminalManager) Register(sessionID string, client *PtyClient)
- func (m *TerminalManager) Remove(sessionID string)
- func (m *TerminalManager) Resize(sessionID string, rows, cols uint16) error
- type TimeData
- type TrackerEntry
- type TunnelClient
- type UserData
- type WebsocketClient
- func (wc *WebsocketClient) Close()
- func (wc *WebsocketClient) CloseAndReconnect(ctx context.Context)
- func (wc *WebsocketClient) CommandRequestHandler(message []byte)
- func (wc *WebsocketClient) Connect()
- func (wc *WebsocketClient) ReadMessage() (messageType int, message []byte, err error)
- func (wc *WebsocketClient) Restart()
- func (wc *WebsocketClient) RestartCollector()
- func (wc *WebsocketClient) RunForever(ctx context.Context)
- func (wc *WebsocketClient) SendPingQuery() error
- func (wc *WebsocketClient) SendPongResponse() error
- func (wc *WebsocketClient) SetDispatcher(dispatcher CommandDispatcher)
- func (wc *WebsocketClient) SetOnAuthenticated(fn func())
- func (wc *WebsocketClient) ShutDown()
- func (wc *WebsocketClient) WriteJSON(data interface{}) error
Constants ¶
const ( // TrackerKindWebsh marks an interactive Websh PTY session. TrackerKindWebsh = "websh" // TrackerKindCommand marks a non-interactive deploy shell Command execution. TrackerKindCommand = "command" )
Kinds of tracked processes that may issue sudo through alpamon-pam.
const ( IFF_UP = 1 << 0 // Interface is up IFF_LOOPBACK = 1 << 3 // Loopback interface IFF_POINTOPOINT = 1 << 4 // Point-to-point link IFF_RUNNING = 1 << 6 // Interface is running )
const ( ErrPermissionDenied = "permission denied" ErrOperationNotPermitted = "operation not permitted" ErrTooLargeDepth = "depth has reached its limit. please try a lower depth" ErrInvalidArgument = "invalid argument" ErrNoSuchFileOrDirectory = "no such file or directory" ErrFileExists = "file exists" ErrDirectoryNotEmpty = "directory not empty" ErrInfiniteRecursion = "causing infinite recursion" ErrNotSupported = "not supported on this platform" )
const ( // Client type constants for tunnel connections. ClientTypeCLI = "cli" ClientTypeWeb = "web" ClientTypeEditor = "editor" )
const (
ConnectionReadTimeout = 35 * time.Minute
)
Variables ¶
This section is empty.
Functions ¶
func CheckSystemResources ¶
func CheckSystemResources() error
CheckSystemResources verifies that system resources are within acceptable limits for creating a new tunnel session. Returns an error if CPU or memory usage exceeds thresholds. Uses fail-open policy: if resource metrics cannot be retrieved, the session is allowed.
func CloseAllActiveFtpWorkers ¶ added in v2.2.4
func CloseAllActiveFtpWorkers()
CloseAllActiveFtpWorkers terminates all tracked WebFTP worker processes. Called during graceful shutdown so the agent reaps its own helper processes instead of relying on the systemd cgroup kill.
func CloseAllActiveTunnels ¶
func CloseAllActiveTunnels()
CloseAllActiveTunnels closes all active tunnel connections. Called during graceful shutdown to ensure code-server and daemon processes are cleaned up.
func CloseTunnel ¶
CloseTunnel closes an active tunnel by session ID.
func CommitAsync ¶
func CommitAsync(session *scheduler.Session, commissioned bool, ctxManager *agent.ContextManager)
CommitAsync commits system information asynchronously Uses ContextManager for coordinated lifecycle management
func CommitSystemInfo ¶
func CommitSystemInfo()
func IsValidSessionID ¶
IsValidSessionID reports whether sessionID is safe to use in paths and map keys.
func RegisterCommandPID ¶
RegisterCommandPID is a package-level helper that registers a deploy shell Command root pid on the singleton AuthManager (if initialized) and returns an unregister closure. The closure captures the exact (pid, commandID) pair so callers cannot accidentally unregister the wrong entry, making the Register/Unregister pair leak-proof by construction. The returned closure is always safe to call — it is a no-op when the AuthManager has not been wired up yet (tests, early boot) or when the arguments would be rejected by AddPIDCommandMapping (non-positive pid, empty commandID).
func RegisterFtpWorker ¶ added in v2.2.4
RegisterFtpWorker records a started worker process and returns a channel the caller must close once the worker exits on its own. The caller still owns the single exec.Cmd.Wait call.
func RegisterTunnel ¶
func RegisterTunnel(sessionID string, tc *TunnelClient) bool
RegisterTunnel atomically checks for an existing tunnel and registers a new one. Returns false if a tunnel with the same session ID already exists.
func RunTunnelDaemon ¶
func RunTunnelDaemon(socketPath string)
RunTunnelDaemon runs the tunnel daemon subprocess. It listens on a Unix domain socket and relays connections to local TCP services. This function is called by the tunnel-daemon subcommand and runs with demoted user credentials.
func SyncSystemInfo ¶
func UnregisterFtpWorker ¶ added in v2.2.4
UnregisterFtpWorker drops the worker for sessionID, but only if it still maps to the same command, so a worker that exits after a same-session worker has replaced it does not delete the newer entry.
Types ¶
type AccessPolicy ¶
type AccessPolicy struct {
BlockLocalSudo bool `json:"block_local_sudo"`
}
type Address ¶
type Address struct {
ID string `json:"id,omitempty"`
Address string `json:"address"`
Broadcast string `json:"broadcast"`
InterfaceName string `json:"interface_name,omitempty"`
Mask string `json:"mask"`
}
func (Address) GetComparableData ¶
func (a Address) GetComparableData() ComparableData
func (Address) GetData ¶
func (a Address) GetData() ComparableData
type AuthManager ¶
type AuthManager struct {
// contains filtered or unexported fields
}
func GetAuthManager ¶
func GetAuthManager(controlClient *ControlClient, session *scheduler.Session) *AuthManager
func NewEmptyAuthManager ¶
func NewEmptyAuthManager() *AuthManager
NewEmptyAuthManager returns an AuthManager populated just enough to exercise the PID tracker without starting the socket listener. It has no dependency on the testing package, so it is safe to keep in the shipped package; the actual test-only glue that swaps the singleton lives in the internal/runnertest package, which is firewalled by the Go compiler's internal rule and only imported from *_test.go files.
func SwapAuthManager ¶
func SwapAuthManager(am *AuthManager) *AuthManager
SwapAuthManager installs am as the package-level singleton and returns the previously installed one so callers can restore it. It is intended to be used from internal/runnertest (which adds *testing.T cleanup); direct use in production code is not supported.
func (*AuthManager) AddPIDCommandMapping ¶
func (am *AuthManager) AddPIDCommandMapping(pid int, commandID, username string)
AddPIDCommandMapping registers the root pid of a deploy shell Command execution so alpamon-pam can attribute a sudo call made inside the Command (or any descendant) to the originating Command.ID. It must be called before the child process can exec sudo to avoid a race where sudo arrives at the PAM module before the tracker knows about the pid.
Concurrency: multiple Commands run in parallel with distinct root pids, so entries never collide. Safe to call from any goroutine.
func (*AuthManager) AddPIDSessionMapping ¶
func (am *AuthManager) AddPIDSessionMapping(pid int, session *SessionInfo)
AddPIDSessionMapping registers an entry for a Websh PTY session. Kind and StartedAt are filled in when unset so callers don't have to remember to populate them; CommandID is always cleared to keep the websh/command fields mutually exclusive per entry.
func (*AuthManager) HandleSudoApprovalResponse ¶
func (am *AuthManager) HandleSudoApprovalResponse(response SudoApprovalResponse) error
HandleSudoApprovalResponse is used to handle the sudo_approval response from the alpacon-server
func (*AuthManager) LookupPID ¶
func (am *AuthManager) LookupPID(pid int) (TrackerEntry, bool)
LookupPID returns a snapshot of the tracker entry for pid (if any). The second return value reports whether an entry was found.
func (*AuthManager) RemovePIDCommandMapping ¶
func (am *AuthManager) RemovePIDCommandMapping(pid int, commandID string)
RemovePIDCommandMapping deletes the tracker entry for a deploy shell Command's root pid. It only removes the entry when it still has the matching command_id; callers must pass a non-empty commandID so that a pid reused by an unrelated entry (e.g. a legacy leftover from a crash) cannot be dropped accidentally.
func (*AuthManager) RemovePIDSessionMapping ¶
func (am *AuthManager) RemovePIDSessionMapping(pid int)
func (*AuthManager) Start ¶
func (am *AuthManager) Start(ctx context.Context)
func (*AuthManager) Stop ¶
func (am *AuthManager) Stop()
func (*AuthManager) UpdateBlockLocalSudo ¶
func (am *AuthManager) UpdateBlockLocalSudo(value bool)
type BaseRequest ¶
type BaseRequest struct {
Type string `json:"type"`
}
type CodeServerConfig ¶
type CodeServerConfig struct {
// Timeouts
InstallTimeout time.Duration
StartupTimeout time.Duration
IdleTimeout time.Duration
// Paths
UserDataDirName string
InstallScriptURL string
// Daemon settings (config.yaml)
Auth string
DisableTelemetry bool
DisableUpdateCheck bool
// Editor settings (settings.json)
ColorTheme string
WindowTitle string
TelemetryLevel string
StartupEditor string
RestoreWindows string
UpdateMode string
DisableWorkspaceTrust bool
DisableWelcomeWalkthrough bool
// Extension gallery
ExtensionGalleryServiceURL string
ExtensionGalleryItemURL string
}
CodeServerConfig holds all code-server configuration in one place.
func GetCodeServerConfig ¶
func GetCodeServerConfig() *CodeServerConfig
GetCodeServerConfig returns the code-server configuration. On the first call, it applies the editor idle timeout from alpamon.conf.
func (*CodeServerConfig) ToArgs ¶
func (c *CodeServerConfig) ToArgs(port int, userDataDir string) []string
ToArgs generates command line arguments for code-server.
func (*CodeServerConfig) ToConfigYAML ¶
func (c *CodeServerConfig) ToConfigYAML() string
ToConfigYAML generates config.yaml content for code-server daemon.
func (*CodeServerConfig) ToEnv ¶
func (c *CodeServerConfig) ToEnv(homeDir string, includeXDG bool) []string
ToEnv generates environment variables for code-server process.
func (*CodeServerConfig) ToExtensionGalleryEnv ¶
func (c *CodeServerConfig) ToExtensionGalleryEnv() string
ToExtensionGalleryEnv generates the EXTENSIONS_GALLERY environment variable value.
func (*CodeServerConfig) ToSettingsJSON ¶
func (c *CodeServerConfig) ToSettingsJSON() ([]byte, error)
ToSettingsJSON generates settings.json content for VS Code editor.
type CodeServerManager ¶
type CodeServerManager struct {
// contains filtered or unexported fields
}
CodeServerManager manages a code-server process for editor tunneling.
func NewCodeServerManager ¶
func NewCodeServerManager(parentCtx context.Context, username, groupname string) (*CodeServerManager, error)
func (*CodeServerManager) IsRunning ¶
func (m *CodeServerManager) IsRunning() bool
IsRunning checks if code-server is currently running.
func (*CodeServerManager) Port ¶
func (m *CodeServerManager) Port() int
Port returns the port code-server is running on.
func (*CodeServerManager) Start ¶
func (m *CodeServerManager) Start() error
Start installs (if needed) and starts code-server on an available port. Lock is held only for short field updates to avoid blocking Status()/Stop() during long-running install/startup operations.
func (*CodeServerManager) StartAsync ¶
func (m *CodeServerManager) StartAsync()
StartAsync starts code-server installation/startup in background. Returns immediately. Use Status() to check progress.
func (*CodeServerManager) Status ¶
func (m *CodeServerManager) Status() (CodeServerStatus, string)
Status returns the current status and last error message.
func (*CodeServerManager) Stop ¶
func (m *CodeServerManager) Stop() error
Stop gracefully terminates the code-server process.
type CodeServerStatus ¶
type CodeServerStatus string
CodeServerStatus represents the current state of code-server.
const ( CodeServerStatusIdle CodeServerStatus = "idle" CodeServerStatusInstalling CodeServerStatus = "installing" CodeServerStatusStarting CodeServerStatus = "starting" CodeServerStatusReady CodeServerStatus = "ready" CodeServerStatusError CodeServerStatus = "error" )
type CommandDispatcher ¶
type CommandDispatcher interface {
Execute(ctx context.Context, command string, args *common.CommandArgs) (int, string, error)
HasHandler(command string) bool
}
CommandDispatcher interface to avoid circular import with executor package
type CommandResult ¶
type CommandResult struct {
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Path string `json:"path,omitempty"`
Dst string `json:"dst,omitempty"`
Code int `json:"code,omitempty"`
Size int64 `json:"size,omitempty"`
Children []CommandResult `json:"children,omitempty"`
ModTime *time.Time `json:"mod_time,omitempty"`
Message string `json:"message,omitempty"`
PermissionString string `json:"permission_str,omitempty"`
PermissionOctal string `json:"permission_octal,omitempty"`
Owner string `json:"owner,omitempty"`
Group string `json:"group,omitempty"`
Target string `json:"target,omitempty"` // Symlink target path
}
func GetFtpErrorCode ¶
func GetFtpErrorCode(command FtpCommand, result CommandResult) (CommandResult, int)
type CommandRunner ¶
type CommandRunner struct {
// contains filtered or unexported fields
}
CommandRunner executes commands received from the server
func NewCommandRunner ¶
func NewCommandRunner(wsClient *WebsocketClient, apiSession *scheduler.Session, command protocol.Command, data protocol.CommandData, dispatcher CommandDispatcher) *CommandRunner
type ComparableData ¶
type ComparableData interface {
GetID() string
GetKey() interface{}
GetData() ComparableData // For transmission (includes all raw data)
GetComparableData() ComparableData // For comparison (excludes fields not stored by server)
}
Defines the ComparableData interface for comparing different types. Ensures data retrieval for each key, excluding the ID field, while minimizing the use of reflection for better performance.
type ControlClient ¶
ControlClient handles WebSocket connection for control messages (sudo_approval, etc.)
func NewControlClient ¶
func NewControlClient() *ControlClient
NewControlClient creates a new ControlClient
func (*ControlClient) Close ¶
func (cc *ControlClient) Close()
Close cleanly closes the WebSocket connection
func (*ControlClient) CloseAndReconnect ¶
func (cc *ControlClient) CloseAndReconnect(ctx context.Context)
CloseAndReconnect closes current connection and reconnects
func (*ControlClient) Connect ¶
func (cc *ControlClient) Connect()
Connect establishes WebSocket connection to control endpoint
func (*ControlClient) GetWSPath ¶
func (cc *ControlClient) GetWSPath() string
GetWSPath returns the WebSocket URL for control endpoint
func (*ControlClient) HandleMessage ¶
func (cc *ControlClient) HandleMessage(message []byte)
HandleMessage processes incoming control messages
func (*ControlClient) IsConnected ¶
func (cc *ControlClient) IsConnected() bool
IsConnected returns whether the client is connected
func (*ControlClient) RunForever ¶
func (cc *ControlClient) RunForever(ctx context.Context)
RunForever maintains the control WebSocket connection and handles messages
func (*ControlClient) WriteJSON ¶
func (cc *ControlClient) WriteJSON(data interface{}) error
WriteJSON sends JSON data through the WebSocket connection
type ControlMessage ¶
type ControlMessage struct {
Query string `json:"query"`
Data json.RawMessage `json:"data"`
}
ControlMessage represents the wrapper message from alpacon-server via Redis
type Disk ¶
type Disk struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
SerialNumber string `json:"serial_number"`
Label string `json:"label"`
}
func (Disk) GetComparableData ¶
func (d Disk) GetComparableData() ComparableData
func (Disk) GetData ¶
func (d Disk) GetData() ComparableData
type FtpClient ¶
type FtpClient struct {
// contains filtered or unexported fields
}
func NewFtpClient ¶
func NewFtpClient(data FtpConfigData) *FtpClient
func (*FtpClient) RunFtpBackground ¶
func (fc *FtpClient) RunFtpBackground()
type FtpCommand ¶
type FtpCommand string
const ( List FtpCommand = "list" Mkd FtpCommand = "mkd" Cwd FtpCommand = "cwd" Pwd FtpCommand = "pwd" Dele FtpCommand = "dele" Rmd FtpCommand = "rmd" Mv FtpCommand = "mv" Cp FtpCommand = "cp" Chmod FtpCommand = "chmod" Chown FtpCommand = "chown" )
type FtpConfigData ¶
type FtpContent ¶
type FtpContent struct {
Command FtpCommand `json:"command"`
Data FtpData `json:"data"`
}
type FtpData ¶
type FtpData struct {
Path string `json:"path,omitempty"`
Depth int `json:"depth,omitempty"`
Recursive bool `json:"recursive,omitempty"`
ShowHidden bool `json:"show_hidden,omitempty"`
AllowOverwrite bool `json:"allow_overwrite,omitempty"`
Src string `json:"src,omitempty"`
Dst string `json:"dst,omitempty"`
Mode string `json:"mode,omitempty"`
Username string `json:"username,omitempty"`
Groupname string `json:"groupname,omitempty"`
}
type FtpResult ¶
type FtpResult struct {
Command FtpCommand `json:"command"`
Success bool `json:"success"`
Code int `json:"code,omitempty"`
Data CommandResult `json:"data,omitempty"`
}
type GroupData ¶
type GroupData struct {
ID string `json:"id,omitempty"`
GID int `json:"gid"`
GroupName string `json:"groupname"`
}
func (GroupData) GetComparableData ¶
func (g GroupData) GetComparableData() ComparableData
func (GroupData) GetData ¶
func (g GroupData) GetData() ComparableData
type Interface ¶
type Interface struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Mac string `json:"mac"`
Type int `json:"type"`
Flags int `json:"flags"`
MTU int `json:"mtu"`
LinkSpeed int `json:"link_speed"`
}
func (Interface) GetComparableData ¶
func (i Interface) GetComparableData() ComparableData
func (Interface) GetData ¶
func (i Interface) GetData() ComparableData
type IsAlpconRequest ¶
type IsAlpconResponse ¶
type MFAResponse ¶
type OSData ¶
type OSData struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Version string `json:"version"`
Major int `json:"major"`
Minor int `json:"minor"`
Patch int `json:"patch"`
Platform string `json:"platform"`
PlatformLike string `json:"platform_like"`
}
func (OSData) GetComparableData ¶
func (o OSData) GetComparableData() ComparableData
func (OSData) GetData ¶
func (o OSData) GetData() ComparableData
type Partition ¶
type Partition struct {
ID string `json:"id,omitempty"`
MountPoints []string `json:"mount_points"`
Name string `json:"name"`
DiskName string `json:"disk_name"`
Fstype string `json:"fs_type"`
IsVirtual bool `json:"is_virtual"`
}
func (Partition) GetComparableData ¶
func (p Partition) GetComparableData() ComparableData
func (Partition) GetData ¶
func (p Partition) GetData() ComparableData
type PtyClient ¶
type PtyClient struct {
// contains filtered or unexported fields
}
func NewPtyClient ¶
func NewPtyClient(data protocol.CommandData, apiSession *scheduler.Session, manager *TerminalManager) *PtyClient
func (*PtyClient) Refresh ¶
Refresh sends SIGWINCH to the PTY foreground process group to force a terminal redraw without changing the terminal size. It uses TIOCGPGRP to look up the foreground process group from the PTY fd, ensuring that full-screen programs (vim, less, top, etc.) also receive the signal.
func (*PtyClient) RunPtyBackground ¶
func (pc *PtyClient) RunPtyBackground()
type ServerData ¶
type SessionInfo ¶
type SessionInfo struct {
Kind string
SessionID string
CommandID string
Username string
PID int
StartedAt time.Time
PtyClient *PtyClient
Requests map[string]*SudoRequest
}
SessionInfo tracks a process (Websh PTY or deploy shell Command) that alpamon-pam may later encounter by walking the ppid chain. The same map holds both kinds of entries so the PAM lookup logic stays single-path.
Exactly one of SessionID or CommandID is populated, determined by Kind:
- Kind == TrackerKindWebsh: SessionID set, CommandID empty.
- Kind == TrackerKindCommand: CommandID set, SessionID empty.
Legacy entries created before the Kind field was introduced are treated as websh entries for backward compatibility (see effectiveKind).
type SudoApprovalRequest ¶
type SudoApprovalRequest struct {
RequestID string `json:"request_id"`
Type string `json:"type"`
Username string `json:"username"`
Groupname string `json:"groupname"`
PID int `json:"pid"`
PPID int `json:"ppid"`
Command string `json:"command"`
IsAlpconUser bool `json:"is_alpacon_user"`
SessionID string `json:"session_id,omitempty"`
CommandID string `json:"command_id,omitempty"`
}
type SudoApprovalResponse ¶
type SudoApprovalResponse struct {
RequestID string `json:"request_id"`
Type string `json:"type"`
Username string `json:"username"`
Groupname string `json:"groupname"`
PID int `json:"pid"`
PPID int `json:"ppid"`
Command string `json:"command"`
IsAlpconUser bool `json:"is_alpacon_user"`
SessionID string `json:"session_id,omitempty"`
CommandID string `json:"command_id,omitempty"`
Approved bool `json:"approved"`
Reason string `json:"reason"`
// ErrorCode is an optional machine-readable denial code (e.g.
// SUDO_NO_WORKSESSION_POLICY) from alpacon-server. Its value is forwarded
// unchanged to the auth socket so the PAM module / approval plugin can show
// a specific reason. omitempty omits the key when the server doesn't send
// it, keeping older socket clients unaffected.
ErrorCode string `json:"error_code,omitempty"`
}
type SudoRequest ¶
type SyncHashes ¶
SyncHashes maps sync category keys to their SHA-256 content hashes.
type Syncer ¶
type Syncer interface {
Key() string
Collect() (any, error)
Def() commitDef
ComputeHash(data any) string
}
Syncer encapsulates per-category sync logic.
type SystemData ¶
type SystemData struct {
ID string `json:"id,omitempty"`
UUID string `json:"uuid"`
CPUType string `json:"cpu_type"`
CPUBrand string `json:"cpu_brand"`
CPUPhysicalCores int `json:"cpu_physical_cores"`
CPULogicalCores int `json:"cpu_logical_cores"`
PhysicalMemory uint64 `json:"physical_memory"`
HardwareVendor string `json:"hardware_vendor"`
HardwareModel string `json:"hardware_model"`
HardwareSerial string `json:"hardware_serial"`
ComputerName string `json:"computer_name"`
Hostname string `json:"hostname"`
LocalHostname string `json:"local_hostname"`
}
func (SystemData) GetComparableData ¶
func (s SystemData) GetComparableData() ComparableData
func (SystemData) GetData ¶
func (s SystemData) GetData() ComparableData
func (SystemData) GetID ¶
func (s SystemData) GetID() string
func (SystemData) GetKey ¶
func (s SystemData) GetKey() interface{}
type TerminalManager ¶
type TerminalManager struct {
// contains filtered or unexported fields
}
TerminalManager manages PTY session lifecycle in a single place.
func NewTerminalManager ¶
func NewTerminalManager() *TerminalManager
NewTerminalManager creates a new TerminalManager.
func (*TerminalManager) Get ¶
func (m *TerminalManager) Get(sessionID string) *PtyClient
Get returns the PtyClient for the given session ID, or nil if not found.
func (*TerminalManager) Refresh ¶
func (m *TerminalManager) Refresh(sessionID string) error
Refresh sends SIGWINCH to the terminal for the given session ID. It holds a read lock for the duration of the signal syscall so that a concurrent close/Remove cannot tear down the PTY mid-operation.
func (*TerminalManager) Register ¶
func (m *TerminalManager) Register(sessionID string, client *PtyClient)
Register adds a PtyClient to the manager.
func (*TerminalManager) Remove ¶
func (m *TerminalManager) Remove(sessionID string)
Remove deletes a PtyClient from the manager.
type TimeData ¶
type TimeData struct {
ID string `json:"id,omitempty"`
Datetime string `json:"datetime"`
BootTime uint64 `json:"boot_time"`
Timezone string `json:"timezone"`
Uptime uint64 `json:"uptime"`
}
func (TimeData) GetComparableData ¶
func (t TimeData) GetComparableData() ComparableData
func (TimeData) GetData ¶
func (t TimeData) GetData() ComparableData
type TrackerEntry ¶
type TrackerEntry struct {
Kind string
SessionID string
CommandID string
Username string
PID int
StartedAt time.Time
}
TrackerEntry is a read-only snapshot of a tracker entry, returned by LookupPID for callers (e.g. tests) that need to inspect state without taking the AuthManager's lock themselves.
type TunnelClient ¶
type TunnelClient struct {
// contains filtered or unexported fields
}
TunnelClient manages the smux-multiplexed tunnel connection to the proxy server. It accepts streams from the server and relays them to local services.
func GetActiveTunnel ¶
func GetActiveTunnel(sessionID string) (*TunnelClient, bool)
GetActiveTunnel returns an active tunnel by session ID.
func NewTunnelClient ¶
func NewTunnelClient(sessionID, clientType string, targetPort int, username, groupname, url string) *TunnelClient
NewTunnelClient creates a new tunnel client for the given WebSocket URL.
func (*TunnelClient) Close ¶
func (tc *TunnelClient) Close()
Close cleanly shuts down the tunnel connection. Safe to call multiple times; only the first call performs cleanup.
func (*TunnelClient) RunTunnelBackground ¶
func (tc *TunnelClient) RunTunnelBackground()
RunTunnelBackground starts the tunnel connection in a goroutine. The caller must register the tunnel via RegisterTunnel before calling this method.
type UserData ¶
type UserData struct {
ID string `json:"id,omitempty"`
UID int `json:"uid"`
GID int `json:"gid"`
Username string `json:"username"`
Description string `json:"description"`
Directory string `json:"directory"`
Shell string `json:"shell"`
ShadowExpireDate *int64 `json:"shadow_expire_date,omitempty"` // /etc/shadow: raw expiration date (days since epoch)
ValidShells []string `json:"valid_shells,omitempty"` // /etc/shells: full list of valid login shells
}
func (UserData) GetComparableData ¶
func (u UserData) GetComparableData() ComparableData
GetComparableData returns data for comparison, excluding fields not stored by server. ValidShells is excluded because the server doesn't store it (system-wide, rarely changes). ShadowExpireDate is included because the server stores it for real-time expiration checks.
func (UserData) GetData ¶
func (u UserData) GetData() ComparableData
type WebsocketClient ¶
type WebsocketClient struct {
Conn *websocket.Conn
RestartChan chan struct{}
ShutDownChan chan struct{}
CollectorRestartChan chan struct{}
// contains filtered or unexported fields
}
func NewWebsocketClient ¶
func NewWebsocketClient(session *scheduler.Session, ctxManager *agent.ContextManager, workerPool *pool.Pool) *WebsocketClient
func (*WebsocketClient) Close ¶
func (wc *WebsocketClient) Close()
Cleanly close the websocket connection by sending a close message Do not close quitChan, as the purpose here is to disconnect the WebSocket, not to terminate RunForever.
func (*WebsocketClient) CloseAndReconnect ¶
func (wc *WebsocketClient) CloseAndReconnect(ctx context.Context)
func (*WebsocketClient) CommandRequestHandler ¶
func (wc *WebsocketClient) CommandRequestHandler(message []byte)
func (*WebsocketClient) Connect ¶
func (wc *WebsocketClient) Connect()
func (*WebsocketClient) ReadMessage ¶
func (wc *WebsocketClient) ReadMessage() (messageType int, message []byte, err error)
func (*WebsocketClient) Restart ¶
func (wc *WebsocketClient) Restart()
func (*WebsocketClient) RestartCollector ¶
func (wc *WebsocketClient) RestartCollector()
func (*WebsocketClient) RunForever ¶
func (wc *WebsocketClient) RunForever(ctx context.Context)
func (*WebsocketClient) SendPingQuery ¶
func (wc *WebsocketClient) SendPingQuery() error
func (*WebsocketClient) SendPongResponse ¶
func (wc *WebsocketClient) SendPongResponse() error
func (*WebsocketClient) SetDispatcher ¶
func (wc *WebsocketClient) SetDispatcher(dispatcher CommandDispatcher)
SetDispatcher sets the dispatcher for handling commands with dispatcher
func (*WebsocketClient) SetOnAuthenticated ¶
func (wc *WebsocketClient) SetOnAuthenticated(fn func())
SetOnAuthenticated registers a callback invoked from RunForever after the first successful ReadMessage of each connection. Firing here rather than at dial-time gives the migration watchdog a strong "the new workspace really did accept us" signal: an upgrade-then-immediate-close scenario (auth rejected by a downstream proxy, rate-limit, etc.) never produces a ReadMessage and so never confirms.
The callback must be idempotent — it fires on every reconnect, not only the first one. Passing nil clears it. Safe to call from any goroutine.
func (*WebsocketClient) ShutDown ¶
func (wc *WebsocketClient) ShutDown()
func (*WebsocketClient) WriteJSON ¶
func (wc *WebsocketClient) WriteJSON(data interface{}) error
Source Files
¶
- auth_manager.go
- auth_manager_testing.go
- client.go
- command.go
- commit.go
- commit_linux.go
- commit_types.go
- control_client.go
- editor.go
- env.go
- ftp.go
- ftp_types.go
- ftp_worker.go
- process_unix.go
- pty.go
- pty_unix.go
- session_unix.go
- signing.go
- syncer.go
- terminal_manager.go
- tunnel_client.go
- tunnel_daemon.go
- tunnel_linux.go
- ws_url.go