Skip to content

Commit

Permalink
create base enricher and make it follow conventions
Browse files Browse the repository at this point in the history
  • Loading branch information
northdpole committed Jun 5, 2024
1 parent a3df9eb commit 1d3908b
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 274 deletions.
47 changes: 21 additions & 26 deletions components/enrichers/aggregator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import (
"flag"
"fmt"
"log"
"os"
"path/filepath"

"golang.org/x/crypto/nacl/sign"

apiv1 "github.com/ocurity/dracon/api/proto/v1"
v1 "github.com/ocurity/dracon/api/proto/v1"
"github.com/ocurity/dracon/components/enrichers"
"github.com/ocurity/dracon/pkg/putil"
)

Expand All @@ -24,17 +25,10 @@ var (
keyBytes []byte
)

func lookupEnvOrString(key string, defaultVal string) string {
if val, ok := os.LookupEnv(key); ok {
return val
}
return defaultVal
}

// Aggregation Rules:
// all k,v annotations get merged
// if there's a key conflict keep the value of the one you saw first.
func aggregateIssue(i *v1.EnrichedIssue, issues map[string]*v1.EnrichedIssue) map[string]*v1.EnrichedIssue {
func aggregateIssue(i *apiv1.EnrichedIssue, issues map[string]*apiv1.EnrichedIssue) map[string]*apiv1.EnrichedIssue {
if _, ok := issues[i.RawIssue.Uuid]; ok { // do we already know about this Uuid?
for k, v := range i.Annotations { // if yes, merge known Uuid annotations with new annotations
if val, found := issues[i.RawIssue.Uuid].Annotations[k]; found {
Expand Down Expand Up @@ -74,13 +68,13 @@ func aggregateIssue(i *v1.EnrichedIssue, issues map[string]*v1.EnrichedIssue) ma
}

// signMessage uses Nacl.Sign to append a Base64 encoded signature of the whole message to the annotation named: "JSON-Message-Signature".
func signMessage(i *v1.EnrichedIssue) (*v1.EnrichedIssue, error) {
func signMessage(i *apiv1.EnrichedIssue) (*apiv1.EnrichedIssue, error) {
// if you have been instructed to sign results, then add the signature annotation
log.Println("signing message " + i.RawIssue.Title)
msg, err := json.Marshal(i)
if err != nil {
log.Printf("Error: could not serialise the message for signing")
return &v1.EnrichedIssue{}, nil
return &apiv1.EnrichedIssue{}, nil

}
if i.Annotations == nil {
Expand All @@ -90,33 +84,33 @@ func signMessage(i *v1.EnrichedIssue) (*v1.EnrichedIssue, error) {
return i, nil
}

func aggregateToolResponse(response *v1.EnrichedLaunchToolResponse, issues map[string]*v1.EnrichedIssue) map[string]*v1.EnrichedIssue {
func aggregateToolResponse(response *apiv1.EnrichedLaunchToolResponse, issues map[string]*apiv1.EnrichedIssue) map[string]*apiv1.EnrichedIssue {
for _, i := range response.GetIssues() {
issues = aggregateIssue(i, issues)
}
return issues
}

func run() {
func run() error {
results, err := putil.LoadEnrichedNonAggregatedToolResponse(readPath)
if err != nil {
log.Fatalf("could not load tool response from path %s , error:%v", readPath, err)
return fmt.Errorf("could not load tool response from path %s , error:%v", readPath, err)
}

if len(signKey) > 0 {
keyBytes, err = base64.StdEncoding.DecodeString(signKey)
if err != nil {
log.Fatalf("could not decode private key for signing")
return fmt.Errorf("could not decode private key for signing")
}
}
log.Printf("loaded %d, enriched but not aggregated tool responses\n", len(results))
issues := make(map[string]map[string]*v1.EnrichedIssue)
originalResponses := make(map[string]*v1.LaunchToolResponse)
issues := make(map[string]map[string]*apiv1.EnrichedIssue)
originalResponses := make(map[string]*apiv1.LaunchToolResponse)
for _, r := range results {
toolName := r.GetOriginalResults().GetToolName()
originalResponses[toolName] = r.GetOriginalResults()
if _, ok := issues[toolName]; !ok {
issues[toolName] = make(map[string]*v1.EnrichedIssue)
issues[toolName] = make(map[string]*apiv1.EnrichedIssue)
}
issues[toolName] = aggregateToolResponse(r, issues[toolName])
}
Expand All @@ -136,17 +130,18 @@ func run() {
if err := putil.WriteEnrichedResults(originalResponses[toolName], result,
filepath.Join(writePath, fmt.Sprintf("%s.enriched.aggregated.pb", toolName)),
); err != nil {
log.Fatal(err)
return err
}
}
return nil
}

func main() {
flag.StringVar(&readPath, "read_path", lookupEnvOrString("READ_PATH", ""), "where to find producer results")
flag.StringVar(&writePath, "write_path", lookupEnvOrString("WRITE_PATH", ""), "where to put tagged results")

flag.StringVar(&signKey, "signature_key", lookupEnvOrString("B64_SIGNATURE_KEY", ""), "where to put tagged results")

flag.Parse()
run()
flag.StringVar(&signKey, "signature_key", enrichers.LookupEnvOrString("B64_SIGNATURE_KEY", ""), "where to put tagged results")
if err := enrichers.ParseFlags(); err != nil {
log.Fatal(err)
}
if err := run(); err != nil {
log.Fatal(err)
}
}
73 changes: 22 additions & 51 deletions components/enrichers/codeowners/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,25 @@ import (
"flag"
"fmt"
"log"
"os"
"log/slog"
"path/filepath"
"strings"
"time"

owners "github.com/hairyhenderson/go-codeowners"

v1 "github.com/ocurity/dracon/api/proto/v1"
"github.com/ocurity/dracon/pkg/putil"
apiv1 "github.com/ocurity/dracon/api/proto/v1"
"github.com/ocurity/dracon/components/enrichers"
)

const defaultAnnotation = "Owner"

var (
readPath string
writePath string
repoBasePath string
annotation string
)

func lookupEnvOrString(key string, defaultVal string) string {
if val, ok := os.LookupEnv(key); ok {
return val
}
return defaultVal
}

func enrichIssue(i *v1.Issue) (*v1.EnrichedIssue, error) {
enrichedIssue := v1.EnrichedIssue{}
func enrichIssue(i *apiv1.Issue) (*apiv1.EnrichedIssue, error) {
enrichedIssue := apiv1.EnrichedIssue{}
annotations := map[string]string{}
targets := []string{}
if i.GetCycloneDXSBOM() != "" {
Expand All @@ -64,64 +54,45 @@ func enrichIssue(i *v1.Issue) (*v1.EnrichedIssue, error) {
annotations[fmt.Sprintf("Owner-%d", len(annotations))] = owner
}
}

enrichedIssue = v1.EnrichedIssue{
enrichedIssue = apiv1.EnrichedIssue{
RawIssue: i,
Annotations: annotations,
}
enrichedIssue.Annotations = annotations
return &enrichedIssue, nil
}

func run() {
res, err := putil.LoadTaggedToolResponse(readPath)
func run() error {
res, err := enrichers.LoadData()
if err != nil {
log.Fatalf("could not load tool response from path %s , error:%v", readPath, err)
return err
}
if annotation == "" {
annotation = defaultAnnotation
}
for _, r := range res {
enrichedIssues := []*v1.EnrichedIssue{}
enrichedIssues := []*apiv1.EnrichedIssue{}
for _, i := range r.GetIssues() {
eI, err := enrichIssue(i)
if err != nil {
log.Println(err)
slog.Error(err.Error())
continue
}
enrichedIssues = append(enrichedIssues, eI)
}
if len(enrichedIssues) > 0 {
if err := putil.WriteEnrichedResults(r, enrichedIssues,
filepath.Join(writePath, fmt.Sprintf("%s.depsdev.enriched.pb", r.GetToolName())),
); err != nil {
log.Fatal(err)
}
} else {
log.Println("no enriched issues were created for", r.GetToolName())
}
if len(r.GetIssues()) > 0 {
scanStartTime := r.GetScanInfo().GetScanStartTime().AsTime()
if err := putil.WriteResults(
r.GetToolName(),
r.GetIssues(),
filepath.Join(writePath, fmt.Sprintf("%s.raw.pb", r.GetToolName())),
r.GetScanInfo().GetScanUuid(),
scanStartTime.Format(time.RFC3339),
r.GetScanInfo().GetScanTags(),
); err != nil {
log.Fatalf("could not write results: %s", err)
}
}

return enrichers.WriteData(enrichedIssues, r, "codeowners")
}
return nil
}

func main() {
flag.StringVar(&readPath, "read_path", lookupEnvOrString("READ_PATH", ""), "where to find producer results")
flag.StringVar(&writePath, "write_path", lookupEnvOrString("WRITE_PATH", ""), "where to put enriched results")
flag.StringVar(&annotation, "annotation", lookupEnvOrString("ANNOTATION", defaultAnnotation), "what is the annotation this enricher will add to the issues, by default `Enriched Licenses`")
flag.StringVar(&repoBasePath, "repoBasePath", lookupEnvOrString("REPO_BASE_PATH", ""), `the base path of the repository, this is most likely an internally set variable`)
flag.Parse()
run()
flag.StringVar(&annotation, "annotation", enrichers.LookupEnvOrString("ANNOTATION", defaultAnnotation), "what is the annotation this enricher will add to the issues, by default `Enriched Licenses`")
flag.StringVar(&repoBasePath, "repoBasePath", enrichers.LookupEnvOrString("REPO_BASE_PATH", ""), `the base path of the repository, this is most likely an internally set variable`)

if err := enrichers.ParseFlags(); err != nil {
log.Fatal(err)
}
if err := run(); err != nil {
log.Fatal(err)
}
}
123 changes: 37 additions & 86 deletions components/enrichers/deduplication/main.go
Original file line number Diff line number Diff line change
@@ -1,108 +1,59 @@
package main

import (
"flag"
"fmt"
"log"
"path/filepath"
"time"
"log/slog"

v1 "github.com/ocurity/dracon/api/proto/v1"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/ocurity/dracon/components/enrichers"

"github.com/ocurity/dracon/pkg/db"
"github.com/ocurity/dracon/pkg/enrichment"
"github.com/ocurity/dracon/pkg/putil"
)

var (
connStr string
readPath string
writePath string
connStr string
)

var rootCmd = &cobra.Command{
Use: "enricher",
Short: "enricher",
Long: "tool to enrich issues against a database",
RunE: func(cmd *cobra.Command, args []string) error {
connStr = viper.GetString("db_connection")
dbUrl, err := db.ParseConnectionStr(connStr)
if err != nil {
return err
}

conn, err := dbUrl.Connect()
if err != nil {
return err
}

readPath = viper.GetString("read_path")
res, err := putil.LoadTaggedToolResponse(readPath)
if err != nil {
log.Fatal(err)
}

log.Printf("Loaded %d tagged tool responses\n", len(res))
writePath = viper.GetString("write_path")
for _, r := range res {
enrichedIssues := []*v1.EnrichedIssue{}
log.Printf("enriching %d issues", len(r.GetIssues()))
for _, i := range r.GetIssues() {
eI, err := enrichment.EnrichIssue(conn, i)
if err != nil {
log.Printf("error enriching issue %s, err: %#v\n", i.Uuid, err)
continue
}
enrichedIssues = append(enrichedIssues, eI)
log.Printf("enriched issue '%s'", eI.GetRawIssue().GetUuid())
}
if len(enrichedIssues) > 0 {
if err := putil.WriteEnrichedResults(r, enrichedIssues,
filepath.Join(writePath, fmt.Sprintf("%s.enriched.pb", r.GetToolName())),
); err != nil {
return err
}
}
if len(r.GetIssues()) > 0 {
scanStartTime := r.GetScanInfo().GetScanStartTime().AsTime()
if err := putil.WriteResults(
r.GetToolName(),
r.GetIssues(),
filepath.Join(writePath, fmt.Sprintf("%s.raw.pb", r.GetToolName())),
r.GetScanInfo().GetScanUuid(),
scanStartTime.Format(time.RFC3339),
r.GetScanInfo().GetScanTags(),
); err != nil {
log.Fatalf("could not write results: %s", err)
}
}
}

return nil
},
func main() {
flag.StringVar(&connStr, "db_connection", enrichers.LookupEnvOrString("ENRICHER_DB_CONNECTION", ""), "the database connection DSN")
if err := enrichers.ParseFlags(); err != nil {
log.Fatal(err)
}
if err := run(); err != nil {
log.Fatal(err)
}
}

func init() {
rootCmd.Flags().StringVar(&connStr, "db_connection", "", "the database connection DSN")
rootCmd.Flags().StringVar(&readPath, "read_path", "", "the path to read LaunchToolResponses from")
rootCmd.Flags().StringVar(&writePath, "write_path", "", "the path to write enriched results to")
if err := viper.BindPFlag("db_connection", rootCmd.Flags().Lookup("db_connection")); err != nil {
log.Fatalf("could not bind db_connection flag: %s", err)
func run() error {
dbURL, err := db.ParseConnectionStr(connStr)
if err != nil {
return err
}
if err := viper.BindPFlag("read_path", rootCmd.Flags().Lookup("read_path")); err != nil {
log.Fatalf("could not bind read_path flag: %s", err)
conn, err := dbURL.Connect()
if err != nil {
return err
}
if err := viper.BindPFlag("write_path", rootCmd.Flags().Lookup("write_path")); err != nil {
log.Fatalf("could not bind write_path flag: %s", err)
res, err := enrichers.LoadData()
if err != nil {
return err
}
viper.SetEnvPrefix("enricher")
viper.AutomaticEnv()
}

func main() {
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
log.Printf("Loaded %d tagged tool responses\n", len(res))
for _, r := range res {
enrichedIssues := []*v1.EnrichedIssue{}
log.Printf("enriching %d issues", len(r.GetIssues()))
for _, i := range r.GetIssues() {
eI, err := enrichment.EnrichIssue(conn, i)
if err != nil {
slog.Error(fmt.Sprintf("error enriching issue %s, err: %#v\n", i.Uuid, err))
continue
}
enrichedIssues = append(enrichedIssues, eI)
log.Printf("enriched issue '%s'", eI.GetRawIssue().GetUuid())
}
return enrichers.WriteData(enrichedIssues, r, "deduplication")
}
return nil
}
Loading

0 comments on commit 1d3908b

Please sign in to comment.