Merge pull request #221 from dwertent/master

Checking latest version
This commit is contained in:
David Wertenteil
2021-11-09 17:09:01 +02:00
committed by GitHub
8 changed files with 147 additions and 89 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ def main():
# Set some variables
packageName = getPackageName()
buildUrl = "github.com/armosec/kubescape/clihandler/cmd.BuildNumber"
buildUrl = "github.com/armosec/kubescape/cautils.BuildNumber"
releaseVersion = os.getenv("RELEASE")
ArmoBEServer = os.getenv("ArmoBEServer")
ArmoERServer = os.getenv("ArmoERServer")
+20 -2
View File
@@ -1,6 +1,7 @@
package getter
import (
"bytes"
"encoding/json"
"fmt"
"io"
@@ -87,7 +88,24 @@ func HttpGetter(httpClient *http.Client, fullURL string) (string, error) {
if err != nil {
return "", err
}
respStr, err := httpRespToString(resp)
respStr, err := HttpRespToString(resp)
if err != nil {
return "", err
}
return respStr, nil
}
func HttpPost(httpClient *http.Client, fullURL string, body []byte) (string, error) {
req, err := http.NewRequest("POST", fullURL, bytes.NewReader(body))
if err != nil {
return "", err
}
resp, err := httpClient.Do(req)
if err != nil {
return "", err
}
respStr, err := HttpRespToString(resp)
if err != nil {
return "", err
}
@@ -95,7 +113,7 @@ func HttpGetter(httpClient *http.Client, fullURL string) (string, error) {
}
// HTTPRespToString parses the body as string and checks the HTTP status code, it closes the body reader at the end
func httpRespToString(resp *http.Response) (string, error) {
func HttpRespToString(resp *http.Response) (string, error) {
if resp == nil || resp.Body == nil {
return "", nil
}
+112
View File
@@ -0,0 +1,112 @@
package cautils
import (
"encoding/json"
"fmt"
"net/http"
"os"
"github.com/armosec/kubescape/cautils/getter"
pkgutils "github.com/armosec/utils-go/utils"
)
const SKIP_VERSION_CHECK = "KUBESCAPE_SKIP_UPDATE_CHECK"
var BuildNumber string
type IVersionCheckHandler interface {
CheckLatestVersion(*VersionCheckRequest) error
}
func NewIVersionCheckHandler() IVersionCheckHandler {
if v, ok := os.LookupEnv(SKIP_VERSION_CHECK); ok && pkgutils.StringToBool(v) {
return NewVersionCheckHandlerMock()
}
return NewVersionCheckHandler()
}
type VersionCheckHandlerMock struct {
}
func NewVersionCheckHandlerMock() *VersionCheckHandlerMock {
return &VersionCheckHandlerMock{}
}
type VersionCheckHandler struct {
versionURL string
}
type VersionCheckRequest struct {
Client string `json:"client"` // kubescape
ClientVersion string `json:"clientVersion"` // kubescape version
Framework string `json:"framework"` // framework name
FrameworkVersion string `json:"frameworkVersion"` // framework version
ScanningTarget string `json:"target"` // scanning target- cluster/yaml
}
type VersionCheckResponse struct {
Client string `json:"client"` // kubescape
ClientUpdate string `json:"clientUpdate"` // kubescape latest version
Framework string `json:"framework"` // framework name
FrameworkUpdate string `json:"frameworkUpdate"` // framework latest version
Message string `json:"message"` // alert message
}
func NewVersionCheckHandler() *VersionCheckHandler {
return &VersionCheckHandler{
versionURL: "https://us-central1-elated-pottery-310110.cloudfunctions.net/ksgf1v1",
}
}
func NewVersionCheckRequest(buildNumber, frameworkName, frameworkVersion, scanningTarget string) *VersionCheckRequest {
return &VersionCheckRequest{
Client: "kubescape",
ClientVersion: buildNumber,
Framework: frameworkName,
FrameworkVersion: frameworkVersion,
ScanningTarget: scanningTarget,
}
}
func (v *VersionCheckHandlerMock) CheckLatestVersion(versionData *VersionCheckRequest) error {
fmt.Println("Skipping version check")
return nil
}
func (v *VersionCheckHandler) CheckLatestVersion(versionData *VersionCheckRequest) error {
latestVersion, err := v.getLatestVersion(versionData)
if err != nil || latestVersion == nil {
return fmt.Errorf("failed to get latest version: %v", err)
}
if latestVersion.ClientUpdate != "" {
fmt.Println(warningMessage(latestVersion.Client, latestVersion.ClientUpdate))
}
if latestVersion.FrameworkUpdate != "" {
fmt.Println(warningMessage(latestVersion.Framework, latestVersion.FrameworkUpdate))
}
return nil
}
func (v *VersionCheckHandler) getLatestVersion(versionData *VersionCheckRequest) (*VersionCheckResponse, error) {
reqBody, err := json.Marshal(versionData)
if err != nil {
return nil, fmt.Errorf("in 'CheckLatestVersion' failed to json.Marshal, reason: %v", err)
}
resp, err := getter.HttpPost(http.DefaultClient, v.versionURL, reqBody)
if err != nil {
return nil, err
}
vResp := &VersionCheckResponse{}
if err = getter.JSONDecoder(resp).Decode(vResp); err != nil {
return nil, err
}
return vResp, nil
}
func warningMessage(kind, release string) string {
return fmt.Sprintf("Warning: '%s' is not updated to the latest release: '%s'", kind, release)
}
+4 -29
View File
@@ -1,49 +1,24 @@
package cmd
import (
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/armosec/kubescape/cautils"
"github.com/spf13/cobra"
)
var BuildNumber string
var versionCmd = &cobra.Command{
Use: "version",
Short: "Get current version",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println("Your current version is: " + BuildNumber)
v := cautils.NewIVersionCheckHandler()
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, "", "", ""))
fmt.Println("Your current version is: " + cautils.BuildNumber)
return nil
},
}
func GetLatestVersion() (string, error) {
latestVersion := "https://api.github.com/repos/armosec/kubescape/releases/latest"
resp, err := http.Get(latestVersion)
if err != nil {
return "unknown", fmt.Errorf("failed to get latest releases from '%s', reason: %s", latestVersion, err.Error())
}
defer resp.Body.Close()
if resp.StatusCode < 200 || 301 < resp.StatusCode {
return "unknown", nil
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "unknown", fmt.Errorf("failed to read response body from '%s', reason: %s", latestVersion, err.Error())
}
var data map[string]interface{}
err = json.Unmarshal(body, &data)
if err != nil {
return "unknown", fmt.Errorf("failed to unmarshal response body from '%s', reason: %s", latestVersion, err.Error())
}
return fmt.Sprintf("%v", data["tag_name"]), nil
}
func init() {
rootCmd.AddCommand(versionCmd)
}
+6
View File
@@ -54,6 +54,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
var resourceHandler resourcehandler.IResourceHandler
var clusterConfig cautils.IClusterConfig
var reportHandler reporter.IReport
var scanningTarget string
if !scanInfo.ScanRunningCluster() {
k8sinterface.ConnectedToCluster = false
@@ -64,6 +65,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
// set mock report (do not send report)
reportHandler = reporter.NewReportMock()
scanningTarget = "yaml"
} else {
k8s := k8sinterface.NewKubernetesApi()
resourceHandler = resourcehandler.NewK8sResourceHandler(k8s, getFieldSelector(scanInfo))
@@ -71,8 +73,12 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
// setup reporter
reportHandler = getReporter(scanInfo)
scanningTarget = "cluster"
}
v := cautils.NewIVersionCheckHandler()
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, "", "", scanningTarget))
// setup printer
printerHandler := printer.GetPrinter(scanInfo.Format)
printerHandler.SetWriter(scanInfo.Output)
-20
View File
@@ -1,29 +1,9 @@
package main
import (
"fmt"
"os"
"github.com/armosec/kubescape/clihandler/cmd"
pkgutils "github.com/armosec/utils-go/utils"
)
const SKIP_VERSION_CHECK = "KUBESCAPE_SKIP_UPDATE_CHECK"
func main() {
CheckLatestVersion()
cmd.Execute()
}
func CheckLatestVersion() {
if v, ok := os.LookupEnv(SKIP_VERSION_CHECK); ok && pkgutils.StringToBool(v) {
return
}
latest, err := cmd.GetLatestVersion()
if err != nil || latest == "unknown" {
return
}
if latest != cmd.BuildNumber {
fmt.Println("Warning: You are not updated to the latest release: " + latest)
}
}
@@ -1,12 +1,12 @@
package reporter
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/opa-utils/reporthandling"
)
@@ -17,14 +17,14 @@ type IReport interface {
}
type ReportEventReceiver struct {
httpClient http.Client
httpClient *http.Client
clusterName string
customerGUID string
}
func NewReportEventReceiver(customerGUID, clusterName string) *ReportEventReceiver {
return &ReportEventReceiver{
httpClient: http.Client{},
httpClient: &http.Client{},
clusterName: clusterName,
customerGUID: customerGUID,
}
@@ -58,15 +58,7 @@ func (report *ReportEventReceiver) send(postureReport *reporthandling.PostureRep
}
host := hostToString(report.initEventReceiverURL(), postureReport.ReportID)
req, err := http.NewRequest("POST", host, bytes.NewReader(reqBody))
if err != nil {
return fmt.Errorf("in 'Send', http.NewRequest failed, host: %s, reason: %v", host, err)
}
res, err := report.httpClient.Do(req)
if err != nil {
return fmt.Errorf("httpClient.Do failed: %v", err)
}
msg, err := httpRespToString(res)
msg, err := getter.HttpPost(report.httpClient, host, reqBody)
if err != nil {
return fmt.Errorf("%s, %v:%s", host, err, msg)
}
@@ -1,37 +1,12 @@
package reporter
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"github.com/armosec/kubescape/cautils/getter"
"github.com/gofrs/uuid"
)
// HTTPRespToString parses the body as string and checks the HTTP status code, it closes the body reader at the end
func httpRespToString(resp *http.Response) (string, error) {
if resp == nil || resp.Body == nil {
return "", nil
}
strBuilder := strings.Builder{}
defer resp.Body.Close()
if resp.ContentLength > 0 {
strBuilder.Grow(int(resp.ContentLength))
}
_, err := io.Copy(&strBuilder, resp.Body)
if err != nil {
return strBuilder.String(), err
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
err = fmt.Errorf("response status: %d. Content: %s", resp.StatusCode, strBuilder.String())
}
return strBuilder.String(), err
}
func (report *ReportEventReceiver) initEventReceiverURL() *url.URL {
urlObj := url.URL{}