Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(webapp): add go controller for cves endpoint #1193

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions deploy/clowdapp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ objects:
value: ${NEWER_RELEASEVER_REPOS}
- name: NEWER_RELEASEVER_CSAF
value: ${NEWER_RELEASEVER_CSAF}
- name: ENABLE_GO_CVES
value: ${ENABLE_GO_CVES}
resources:
limits:
cpu: ${CPU_LIMIT_WEBAPP_GO}
Expand Down Expand Up @@ -494,3 +496,6 @@ parameters:
value: "true"
- name: DB_DUMP_BUCKET
value: insights-vmaas-dump-storage
- name: ENABLE_GO_CVES
description: Enable go implementation of the cves endpoint
value: "false"
2 changes: 2 additions & 0 deletions vmaas-go/base/utils/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type Config struct {
LogStyle string
CacheRefreshInterval time.Duration
EnableProfiler bool
EnableGoCves bool

// lib
UnfixedEvalEnabled bool
Expand Down Expand Up @@ -134,6 +135,7 @@ func initEnv() {
Cfg.VmaasLibMaxGoroutines = GetIntEnvOrDefault("VMAAS_LIB_MAX_GOROUTINES", 20)
Cfg.NewerReleaseverRepos = GetBoolEnvOrDefault("NEWER_RELEASEVER_REPOS", true)
Cfg.NewerReleaseverCsaf = GetBoolEnvOrDefault("NEWER_RELEASEVER_CSAF", true)
Cfg.EnableGoCves = GetBoolEnvOrDefault("ENABLE_GO_CVES", false)
}

func (e *Endpoint) BuildURL(scheme string) string {
Expand Down
21 changes: 21 additions & 0 deletions vmaas-go/base/utils/gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"strconv"
"strings"
"time"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -105,6 +106,25 @@ func respStatusError(c *gin.Context, code int, err error) {
})
}

func processBadRequestErrMessage(err error) error {
errMessage := err.Error()
if strings.HasPrefix(errMessage, "parsing time") {
parts := strings.Split(errMessage, `"`)
if len(parts) < 2 {
return errors.New("Wrong date format (not ISO format with timezone)")
}
return errors.New("Wrong date format (not ISO format with timezone): " + parts[1])
Comment on lines +112 to +116
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the purpose of splitting the error message? When it has only 1 " then the error will be Wrong date format (not ISO format with timezone and when there are more " then the second part is wrapped by the new message and other parts are discarded?
If the point is to only wrap the current error, you can use errors.Wrap from github.com/pkg/errors which is already used in this module or https://pkg.go.dev/errors#Join

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose is to get the original timestamp being parsed, the error message without one is just a fallback.

}
if strings.HasSuffix(errMessage, "looking for beginning of value") {
parts := strings.Split(errMessage, ` `)
if len(parts) < 3 {
return errors.New("malformed input")
}
return errors.New("malformed input: invalid character " + parts[2])
}
return err
}

Comment on lines +109 to +127
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parsing errors based on error message and then changing the error message is not optimal. I'd prefer wrapping original error.
Error for wrong date can be for example handled when UnmarshalJSON for time fails (it would require custom type for time so UnmarshalJSON can be defined, something like https://github.com/RedHatInsights/patchman-engine/blob/master/base/types/timestamp.go). Anyways, timestamp is parsed only by bindValidateJSON so at least move the current logic to that function.

looking for beginning of value is returned by regex error? In that case you can wrap the error in vmaas-lib before returning regex error or return some custom error type and then change the message after checking the error type with errors.Is

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original error parsing time "2017-01-01T00:00:00" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "Z07:00" is clunky and requires some go-specific knowledge to understand. That's why I opted to replace it rather than to just wrap it.

invalid character 'N' looking for beginning of value also occurs during JSON parsing, for example, when there is NaN instead of a number.

I will move the logic. Should I also wrap the errors instead?

func LogAndRespError(c *gin.Context, err error) {
if errors.Is(err, vmaas.ErrProcessingInput) {
// if error is from processing the request, we should return 400
Expand All @@ -116,6 +136,7 @@ func LogAndRespError(c *gin.Context, err error) {
}

func LogAndRespBadRequest(c *gin.Context, err error) {
err = processBadRequestErrMessage(err)
LogWarn("err", err.Error())
respStatusError(c, http.StatusBadRequest, err)
}
Expand Down
2 changes: 1 addition & 1 deletion vmaas-go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/prometheus/client_golang v1.20.5
github.com/redhatinsights/app-common-go v1.6.8
github.com/redhatinsights/platform-go-middlewares v1.0.0
github.com/redhatinsights/vmaas-lib v1.14.5
github.com/redhatinsights/vmaas-lib v1.14.6
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
github.com/zsais/go-gin-prometheus v0.1.0
Expand Down
4 changes: 2 additions & 2 deletions vmaas-go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ github.com/redhatinsights/app-common-go v1.6.8 h1:hyExMp6WHprlGkHKElQvSFF2ZPX8XT
github.com/redhatinsights/app-common-go v1.6.8/go.mod h1:KW0BK+bnhp3kXU8BFwebQXqCqjdkcRewZsDlXCSNMyo=
github.com/redhatinsights/platform-go-middlewares v1.0.0 h1:OxyiYt+VmNo+UucK/ey0b6UDFnpCni6JoGPeisGmmNI=
github.com/redhatinsights/platform-go-middlewares v1.0.0/go.mod h1:dRH6XOjiZDbw8STvk6NNC7mMwqhTaV7X+1tn1oXOs24=
github.com/redhatinsights/vmaas-lib v1.14.5 h1:5n2Rq0gzCZzsz/yU4pcaZLTZ9uKSDdpqu18Du6v7KtA=
github.com/redhatinsights/vmaas-lib v1.14.5/go.mod h1:fCpKKAkaxgxSSLTgJYPgA4xi3qizDiUiboeDWst1j2Q=
github.com/redhatinsights/vmaas-lib v1.14.6 h1:w3hqNztwA0ArliwySlqDYws4fzs0bbNcK2qp1AQsOdQ=
github.com/redhatinsights/vmaas-lib v1.14.6/go.mod h1:fCpKKAkaxgxSSLTgJYPgA4xi3qizDiUiboeDWst1j2Q=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
Expand Down
44 changes: 44 additions & 0 deletions vmaas-go/webapp/controllers/cves.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package controllers

import (
"net/http"

"github.com/gin-gonic/gin"
"github.com/redhatinsights/vmaas-lib/vmaas"
"github.com/redhatinsights/vmaas/base/core"
"github.com/redhatinsights/vmaas/base/utils"
)

func CvesHandler(c *gin.Context) {
if !isCacheLoaded(c) {
return
}
cve := c.Param("cve")
req := vmaas.CvesRequest{Cves: []string{cve}}

res, err := core.VmaasAPI.Cves(&req)
if err != nil {
utils.LogAndRespError(c, err)
return
}
c.JSON(http.StatusOK, res)
}

func CvesPostHandler(c *gin.Context) {
if !isCacheLoaded(c) {
return
}
req := vmaas.CvesRequest{}
err := bindValidateJSON(c, &req)
if err != nil {
utils.LogAndRespBadRequest(c, err)
return
}

cves, err := core.VmaasAPI.Cves(&req)
if err != nil {
utils.LogAndRespError(c, err)
return
}
c.JSON(http.StatusOK, cves)
}
18 changes: 10 additions & 8 deletions vmaas-go/webapp/controllers/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,22 @@ import (
"github.com/redhatinsights/vmaas/base/utils"
)

func bindValidateJSON(c *gin.Context, request *vmaas.Request) error {
func bindValidateJSON(c *gin.Context, request interface{}) error {
if request == nil {
return fmt.Errorf("nil vmaas request")
}
if err := c.BindJSON(request); err != nil {
return err
}
// validate module name:stream
for i, m := range request.Modules {
if m.Module == nil {
return fmt.Errorf("'module_name' is a required property - 'modules_list.%d'", i)
}
if m.Stream == nil {
return fmt.Errorf("'module_stream' is a required property - 'modules_list.%d'", i)

if reqest, ok := (request).(*vmaas.Request); ok {
for i, m := range reqest.Modules {
if m.Module == nil {
return fmt.Errorf("'module_name' is a required property - 'modules_list.%d'", i)
}
if m.Stream == nil {
return fmt.Errorf("'module_stream' is a required property - 'modules_list.%d'", i)
}
}
}
return nil
Expand Down
6 changes: 6 additions & 0 deletions vmaas-go/webapp/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package routes
import (
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
"github.com/redhatinsights/vmaas/base/utils"
"github.com/redhatinsights/vmaas/webapp/controllers"
)

Expand All @@ -12,4 +13,9 @@ func InitAPI(api *gin.RouterGroup) {
api.POST("/updates", controllers.UpdatesPostHandler)
api.GET("/vulnerabilities/:package", controllers.VulnerabilitiesHandler)
api.POST("/vulnerabilities", controllers.VulnerabilitiesPostHandler)

if utils.Cfg.EnableGoCves {
api.GET("/cves/:cve", controllers.CvesHandler)
api.POST("/cves", controllers.CvesPostHandler)
}
}
Loading