package store import "encoding/json" // HostOOBRow is the latest operator-access (OOB) state per host (TASK H1), parsed from the newest // host_report. Present is false when the agent sent no oob stanza (pre-H1 / feature off) → never // alerted. type HostOOBRow struct { HostID string CustomerID string Present bool FelhomSshdActive bool FelhomSshdPort int Reachable bool ConfigInvalid bool OperatorPeerConfigured bool } // GetHostOOBStates returns the latest oob stanza per host (mirrors GetHostMgmtPlaneStates). A report // without the stanza yields Present=false; malformed JSON degrades to zero values, never an error. func (s *Store) GetHostOOBStates() ([]HostOOBRow, error) { rows, err := s.db.Query(` SELECT hr.host_id, hr.customer_id, hr.report_json FROM host_reports hr JOIN (SELECT host_id, MAX(id) AS mx FROM host_reports GROUP BY host_id) latest ON hr.id = latest.mx`) if err != nil { return nil, err } defer rows.Close() var out []HostOOBRow for rows.Next() { var r HostOOBRow var reportJSON string if err := rows.Scan(&r.HostID, &r.CustomerID, &reportJSON); err != nil { return nil, err } var body struct { OOB *struct { FelhomSshdActive bool `json:"felhom_sshd_active"` FelhomSshdPort int `json:"felhom_sshd_port"` Reachable bool `json:"reachable"` ConfigInvalid bool `json:"config_invalid"` OperatorPeerConfigured bool `json:"operator_peer_configured"` } `json:"oob"` } _ = json.Unmarshal([]byte(reportJSON), &body) if body.OOB != nil { r.Present = true r.FelhomSshdActive = body.OOB.FelhomSshdActive r.FelhomSshdPort = body.OOB.FelhomSshdPort r.Reachable = body.OOB.Reachable r.ConfigInvalid = body.OOB.ConfigInvalid r.OperatorPeerConfigured = body.OOB.OperatorPeerConfigured } out = append(out, r) } return out, rows.Err() }