Skip to content

Commit

Permalink
Add datadog certifier
Browse files Browse the repository at this point in the history
Signed-off-by: robert-cronin <robert.owen.cronin@gmail.com>
  • Loading branch information
robert-cronin committed Dec 16, 2024
1 parent fc2976b commit d2f86e2
Show file tree
Hide file tree
Showing 4 changed files with 731 additions and 0 deletions.
169 changes: 169 additions & 0 deletions cmd/guacone/cmd/datadog_malware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//
// Copyright 2024 The GUAC Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
"context"
"fmt"
"net/http"
"os"
"time"

"github.com/Khan/genqlient/graphql"
"github.com/guacsec/guac/pkg/assembler/clients/generated"
"github.com/guacsec/guac/pkg/certifier"
"github.com/guacsec/guac/pkg/certifier/certify"
"github.com/guacsec/guac/pkg/certifier/components/root_package"
"github.com/guacsec/guac/pkg/certifier/datadog_malware"
"github.com/guacsec/guac/pkg/cli"
"github.com/guacsec/guac/pkg/handler/processor"
"github.com/guacsec/guac/pkg/ingestor"
"github.com/guacsec/guac/pkg/logging"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type datadogMalwareOptions struct {
graphqlEndpoint string
headerFile string
poll bool
interval time.Duration
addedLatency *time.Duration
batchSize int
lastScan *int
}

var datadogMalwareCmd = &cobra.Command{
Use: "datadog-malware [flags]",
Short: "Runs the Datadog malicious package certifier",
Run: func(cmd *cobra.Command, args []string) {
opts, err := validateDatadogMalwareFlags(
viper.GetString("gql-addr"),
viper.GetString("header-file"),
viper.GetString("interval"),
viper.GetString("certifier-latency"),
viper.GetInt("certifier-batch-size"),
viper.GetInt("last-scan"),
viper.GetBool("poll"),
)
if err != nil {
fmt.Printf("unable to validate flags: %v\n", err)
_ = cmd.Help()
os.Exit(1)
}

ctx := logging.WithLogger(context.Background())
logger := logging.FromContext(ctx)
transport := cli.HTTPHeaderTransport(ctx, opts.headerFile, http.DefaultTransport)

assemblerFunc := ingestor.GetAssembler(ctx, logger, opts.graphqlEndpoint, transport)
ddCertifier, err := datadog_malware.NewDatadogMalwareCertifier(ctx, assemblerFunc)
if err != nil {
logger.Fatalf("unable to create datadog certifier: %v", err)
}

if err := certify.RegisterCertifier(func() certifier.Certifier { return ddCertifier }, certifier.CertifierDatadogMalware); err != nil {
logger.Fatalf("unable to register datadog certifier: %v", err)
}

httpClient := http.Client{Transport: transport}
gqlclient := graphql.NewClient(opts.graphqlEndpoint, &httpClient)

packageQuery := root_package.NewPackageQuery(gqlclient, generated.QueryTypeVulnerability, opts.batchSize, 1000, opts.addedLatency, opts.lastScan)

totalNum := 0
emit := func(d *processor.Document) error {
// data dog certifier does not need to emit anything but just for the sake of completeness
if _, err := ingestor.Ingest(ctx, d, opts.graphqlEndpoint, transport, nil, false, false, false, false); err != nil {
return fmt.Errorf("unable to ingest document: %v", err)
}
totalNum += 1
return nil
}

errHandler := func(err error) bool {
if err == nil {
logger.Info("certifier ended gracefully")
return true
}
logger.Errorf("certifier ended with error: %v", err)
return true
}

if err := certify.Certify(ctx, packageQuery, emit, errHandler, opts.poll, opts.interval); err != nil {
logger.Fatal(err)
}

logger.Infof("completed certifying %d packages", totalNum)
},
}

func validateDatadogMalwareFlags(
graphqlEndpoint,
headerFile,
interval,
certifierLatencyStr string,
batchSize int, lastScan int,
poll bool,
) (datadogMalwareOptions, error) {
var opts datadogMalwareOptions
opts.graphqlEndpoint = graphqlEndpoint
opts.headerFile = headerFile

i, err := time.ParseDuration(interval)
if err != nil {
return opts, err
}
opts.interval = i
if certifierLatencyStr != "" {
addedLatency, err := time.ParseDuration(certifierLatencyStr)
if err != nil {
return opts, fmt.Errorf("failed to parse duration with error: %w", err)
}
opts.addedLatency = &addedLatency
} else {
opts.addedLatency = nil
}

opts.batchSize = batchSize
if lastScan != 0 {
opts.lastScan = &lastScan
}
opts.poll = poll
return opts, nil
}

func init() {
set, err := cli.BuildFlags([]string{
"interval",
"header-file",
"certifier-latency",
"certifier-batch-size",
"last-scan",
"poll",
})
if err != nil {
fmt.Fprintf(os.Stderr, "failed to setup flag: %v", err)
os.Exit(1)
}
datadogMalwareCmd.PersistentFlags().AddFlagSet(set)
if err := viper.BindPFlags(datadogMalwareCmd.PersistentFlags()); err != nil {
fmt.Fprintf(os.Stderr, "failed to bind flags: %v", err)
os.Exit(1)
}

certifierCmd.AddCommand(datadogMalwareCmd)
}
1 change: 1 addition & 0 deletions pkg/certifier/certifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ const (
CertifierClearlyDefined CertifierType = "CD"
CertifierScorecard CertifierType = "scorecard"
CertifierEOL CertifierType = "EOL"
CertifierDatadogMalware CertifierType = "DATADOG_MALWARE"
)
Loading

0 comments on commit d2f86e2

Please sign in to comment.