From 352e77e5e1c7a695f33af95d5392e5d048258df3 Mon Sep 17 00:00:00 2001 From: Blaize M Kaye Date: Fri, 9 Feb 2024 11:48:51 +1300 Subject: [PATCH] Separates out fact gathering to fact writing --- internal/handler/main.go | 67 +++++++++++++++++++++++------------ internal/handler/messaging.go | 17 +++++++-- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/internal/handler/main.go b/internal/handler/main.go index d7528f8..f20fabf 100644 --- a/internal/handler/main.go +++ b/internal/handler/main.go @@ -284,25 +284,22 @@ func (t *authedTransport) RoundTrip(req *http.Request) (*http.Response, error) { type LagoonSourceFactMap map[string][]LagoonFact // Incoming payload may contain facts or problems, so we need to handle these differently -func (h *Messaging) sendToLagoonAPI(incoming *InsightsMessage, resource ResourceDestination, insights InsightsData) (err error) { +func (h *Messaging) gatherFactsFromInsightData(incoming *InsightsMessage, resource ResourceDestination, insights InsightsData) ([]LagoonSourceFactMap, error) { apiClient := h.getApiClient() + // Here we collect all source fact maps before writing them _once_ + lagoonSourceFactMapCollection := []LagoonSourceFactMap{} if resource.Project == "" && resource.Environment == "" { - return fmt.Errorf("no resource definition labels could be found in payload (i.e. lagoon.sh/project or lagoon.sh/environment)") + return lagoonSourceFactMapCollection, fmt.Errorf("no resource definition labels could be found in payload (i.e. lagoon.sh/project or lagoon.sh/environment)") } if insights.InputPayload == Payload && insights.LagoonType == Facts { for _, p := range incoming.Payload { lagoonSourceFactMap, err := parserFilterLoopForPayloads(insights, p, h, apiClient, resource) if err != nil { - return err - } - for sourceName, facts := range lagoonSourceFactMap { - err = sendResultsetToLagoon(facts, err, h, apiClient, resource, sourceName) - if err != nil { - return err - } + return lagoonSourceFactMapCollection, err } + lagoonSourceFactMapCollection = append(lagoonSourceFactMapCollection, lagoonSourceFactMap) } } @@ -310,18 +307,13 @@ func (h *Messaging) sendToLagoonAPI(incoming *InsightsMessage, resource Resource for _, p := range incoming.BinaryPayload { lagoonSourceFactMap, err := parserFilterLoopForBinaryPayloads(insights, p, h, apiClient, resource) if err != nil { - return err - } - for sourceName, facts := range lagoonSourceFactMap { - err = sendResultsetToLagoon(facts, err, h, apiClient, resource, sourceName) - if err != nil { - return err - } + return lagoonSourceFactMapCollection, err } + lagoonSourceFactMapCollection = append(lagoonSourceFactMapCollection, lagoonSourceFactMap) } } - return nil + return lagoonSourceFactMapCollection, nil } func parserFilterLoopForBinaryPayloads(insights InsightsData, p string, h *Messaging, apiClient graphql.Client, resource ResourceDestination) (LagoonSourceFactMap, error) { @@ -360,8 +352,39 @@ func parserFilterLoopForPayloads(insights InsightsData, p PayloadInput, h *Messa return lagoonSourceFactMap, nil } +func trivySBOMProcessing(apiClient graphql.Client, trivyServerEndpoint string, resource ResourceDestination, payload string) error { + + bom, err := getBOMfromPayload(payload) + if err != nil { + return err + } + + // Determine lagoon resource destination + _, environment, apiErr := determineResourceFromLagoonAPI(apiClient, resource) + if apiErr != nil { + return apiErr + } + + // we process the SBOM here + // TODO: This should actually live in its own function somewhere else. + isAlive, err := IsTrivyServerIsAlive(trivyServerEndpoint) + if err != nil { + return fmt.Errorf("trivy server not alive: %v", err.Error()) + } else { + slog.Debug("Trivy is reachable") + } + if isAlive { + err = SbomToProblems(apiClient, trivyServerEndpoint, "/tmp/", environment.Id, resource.Service, *bom) + } + if err != nil { + return err + } + return nil +} + // sendResultsetToLagoon will send results as facts to the lagoon api after processing via a parser filter -func sendResultsetToLagoon(result []LagoonFact, err error, h *Messaging, apiClient graphql.Client, resource ResourceDestination, source string) error { +func (h *Messaging) SendResultsetToLagoon(result []LagoonFact, resource ResourceDestination, source string) error { + apiClient := h.getApiClient() project, environment, apiErr := determineResourceFromLagoonAPI(apiClient, resource) if apiErr != nil { slog.Error(apiErr.Error()) @@ -376,10 +399,10 @@ func sendResultsetToLagoon(result []LagoonFact, err error, h *Messaging, apiClie return apiErr } - err = h.sendFactsToLagoonAPI(result, apiClient, resource, source) - if err != nil { - slog.Error("Error sending facts to Lagoon API", "error", err.Error()) - return err + e := h.sendFactsToLagoonAPI(result, apiClient, resource, source) + if e != nil { + slog.Error("Error sending facts to Lagoon API", "error", e.Error()) + return e } return nil diff --git a/internal/handler/messaging.go b/internal/handler/messaging.go index 8e8a3d6..d56b649 100644 --- a/internal/handler/messaging.go +++ b/internal/handler/messaging.go @@ -135,13 +135,26 @@ func (h *Messaging) processMessageQueue(message mq.Message) { insights.InsightsType != Direct { slog.Error("only 'sbom', 'direct', 'raw', and 'image' types are currently supported for api processing") } else { - err := h.sendToLagoonAPI(incoming, resource, insights) + lagoonSourceFactMapCollection, err := h.gatherFactsFromInsightData(incoming, resource, insights) if err != nil { - slog.Error("Unable to send to the API", "Error", err.Error()) + slog.Error("Unable to gather facts from incoming data", "Error", err.Error()) rejectMessage(false) return } + + // Here we actually go ahead and write all the facts with their source + for _, lsfm := range lagoonSourceFactMapCollection { + for sourceName, facts := range lsfm { + err := h.SendResultsetToLagoon(facts, resource, sourceName) + if err != nil { + slog.Error("Unable to write facts to api", "Error", err.Error()) + rejectMessage(false) + return + } + } + } + } } acknowledgeMessage()