// Package managementaccess owns the narrow runtime boundary used to make // staged management-service settings real on the target. package managementaccess import ( "context" "errors" "fmt" "strings" "tera-clone/services/tera-api/internal/domain" ) const DefaultSocketPath = "/run/tera-accessd/control.sock" type Controller interface { Apply(context.Context, domain.ManagementAccessSettings) error } type NoopController struct{} func (NoopController) Apply(context.Context, domain.ManagementAccessSettings) error { return nil } type UnavailableError struct{ Reason string } func (e *UnavailableError) Error() string { reason := strings.TrimSpace(e.Reason) if reason == "" { reason = "tera-accessd is unavailable" } return reason } func IsUnavailable(err error) bool { var target *UnavailableError return errors.As(err, &target) } func Validate(settings domain.ManagementAccessSettings) error { if settings.IdleTimeoutMinutes < 1 || settings.IdleTimeoutMinutes > 120 { return errors.New("idle_timeout_minutes must be between 1 and 120") } if settings.SSHEnabled || settings.TelnetEnabled { return errors.New("management access SSH and Telnet are excluded; use per-channel SSH or Telnet access") } if settings.LoginDetectionMinutes < 0 || settings.LoginDetectionMinutes > 1440 { return errors.New("login_detection_minutes must be between 0 and 1440") } if settings.LoginSecurityHitCount < 0 || settings.LoginSecurityHitCount > 100 { return errors.New("login_security_hit_count must be between 0 and 100") } if !settings.HTTPSEnabled && !settings.SerialConsoleEnabled { return errors.New("management access must keep HTTPS or serial console enabled") } ports := []struct { name string port int enabled bool }{ {"http", settings.HTTPPort, settings.HTTPEnabled}, {"https", settings.HTTPSPort, settings.HTTPSEnabled}, } active := make(map[int]string) for _, item := range ports { if item.port < 1 || item.port > 65535 { return fmt.Errorf("management access %s port must be between 1 and 65535", item.name) } if !item.enabled { continue } if item.port == 8080 { return fmt.Errorf("management access %s port 8080 is reserved for the recovery-safe web endpoint", item.name) } if previous, exists := active[item.port]; exists { return fmt.Errorf("management access services %s and %s cannot share port %d", previous, item.name, item.port) } active[item.port] = item.name } return nil }