Skip to content

Commit

Permalink
New Build 1.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
DanMolz committed Nov 18, 2024
1 parent 78c7aaa commit 56ed1ff
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 160 deletions.
117 changes: 107 additions & 10 deletions internal/scheduler/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ import (
"log"
"math/rand"
"os"
"strings"
"time"

"github.com/DanMolz/wiz-semgrep-connector/config"
"github.com/DanMolz/wiz-semgrep-connector/internal/semgrep"
"github.com/DanMolz/wiz-semgrep-connector/internal/utils"
"github.com/DanMolz/wiz-semgrep-connector/internal/wiz"
)

const wizFileName = "wiz_findings.json"
const semgrepFileName = "semgrep_findings.json"
const integrationID = "55c176cc-d155-43a2-98ed-aa56873a1ca1"

func StartScheduler(ctx context.Context, cfg config.Config) {
// Wait for the random delay before starting the scheduler
Expand Down Expand Up @@ -73,33 +75,45 @@ func fetchAndProcessFindings(ctx context.Context, cfg config.Config, phase strin
}

func runFindingsCollection(ctx context.Context, cfg config.Config) error {
// Fetch the cloud resources from Wiz
wizCloudResources, err := wiz.PullCloudResources(ctx, cfg)
if err != nil {
return logAndReturnError("Error fetching Wiz repositories", err)
}
// Write the cloud resources to a JSON file
if err := utils.WriteToFile(wizCloudResources, "wiz_cloud_resources.json"); err != nil {
return logAndReturnError("Error writing Wiz Cloud Resources to file", err)
}
log.Println("Wiz Cloud Resources written to file successfully")

// Fetch the findings from Semgrep
semgrepFindings, err := semgrep.FetchFindings(cfg)
if err != nil {
return logAndReturnError("Error fetching findings", err)
}

// Write the findings to a JSON file
if err := semgrep.WriteFindingsToFile(semgrepFindings, semgrepFileName); err != nil {
return logAndReturnError("Error writing findings to file", err)
if err := utils.WriteToFile(semgrepFindings, "semgrep_findings.json"); err != nil {
return logAndReturnError("Error writing Semgrep Findings to file", err)
}
log.Println("Semgrep Findings written to file successfully")

// Log the number of findings fetched
// Log the number of repositories and findings fetched
repoCount := len(wizCloudResources.VersionControlResources.Nodes)
log.Printf("Wiz Cloud Resources fetched: %d\n", repoCount)
findingsCount := len(semgrepFindings.Findings)
log.Printf("Findings fetched: %d\n", findingsCount)
log.Printf("Semgrep Findings fetched: %d\n", findingsCount)

// Transform the findings
wizFindings, err := semgrep.TransformFindings(semgrepFindings)
wizFindings, err := transformFindings(wizCloudResources, semgrepFindings)
if err != nil {
return logAndReturnError("Error transforming findings", err)
}

// Write the findings to a JSON file
if err := semgrep.WriteFindingsToFile(wizFindings, wizFileName); err != nil {
return logAndReturnError("Error writing findings to file", err)
if err := utils.WriteToFile(wizFindings, wizFileName); err != nil {
return logAndReturnError("Error writing Wiz Findings to file", err)
}
log.Println("Wiz Findings written to file successfully")
log.Println("WiZ Findings written to file successfully")

// Request an upload slot from the Wiz API
resp, err := wiz.RequestUploadSlot(ctx, cfg)
Expand Down Expand Up @@ -129,3 +143,86 @@ func logAndReturnError(message string, err error) error {
log.Printf("%s: %v\n", message, err)
return fmt.Errorf("%s: %w", message, err)
}

func transformFindings(wizCloudResources wiz.WizCloudResources, semgrepFindings semgrep.SemgrepFindings) (wiz.WizFindingsSchema, error) {
var wizFindings wiz.WizFindingsSchema
wizFindings.IntegrationID = integrationID

// Create a map of repositories from Wiz Cloud Resources
wizRepoMap := make(map[string]struct{})
for _, node := range wizCloudResources.VersionControlResources.Nodes {
wizRepoMap[node.ProviderID] = struct{}{}
}

// Iterate over the findings and transform them
for _, finding := range semgrepFindings.Findings {
// Get the cloud platform and provider ID
cloudPlatform, providerId := getCloudPlatformAndProviderId(finding)

// Skip findings for repositories not present in Wiz Cloud Resources
if _, exists := wizRepoMap[providerId]; !exists {
log.Printf("Skipping, Repository reference not found in Wiz Cloud Resources: %s, %s\n", finding.Repository.Name, finding.Ref)
continue
}

// Create the Wiz Findings data structure
wizFindingDataSources := wiz.DataSources{
ID: finding.Repository.Name,
AnalysisDate: finding.CreatedAt,
Assets: []wiz.Assets{
{
AssetIdentifier: wiz.AssetIdentifier{
CloudPlatform: cloudPlatform,
ProviderID: providerId,
},
WebAppVulnerabilityFindings: []wiz.WebAppVulnerabilityFindings{
{
SastFinding: wiz.SastFinding{
CommitHash: "",
Filename: finding.Location.FilePath,
LineNumbers: fmt.Sprintf("%d-%d", finding.Location.Line, finding.Location.Column),
},
ID: fmt.Sprint(finding.ID),
Name: strings.Split(finding.Rule.CWE[0], ":")[0],
DetailedName: splitRuleName(finding.RuleName),
Severity: utils.CapitalizeFirstChar(finding.Severity),
ExternalFindingLink: finding.LineOfCodeURL,
Source: "Semgrep",
Remediation: "N/A",
Description: fmt.Sprintf("Rule Confidence: %s. Description: %s", utils.CapitalizeFirstChar(finding.Confidence), finding.Rule.Message),
},
},
},
},
}

// Append the Wiz Findings data structure to the list
wizFindings.DataSources = append(wizFindings.DataSources, wizFindingDataSources)
}

// Log the number of data sources
log.Printf("WiZ Data Sources: %d will be uploaded.", len(wizFindings.DataSources))

return wizFindings, nil
}

func getCloudPlatformAndProviderId(finding semgrep.Finding) (string, string) {
var cloudPlatform, providerId string

if strings.Contains(finding.Repository.URL, "github.com") {
cloudPlatform = "GitHub"
providerId = fmt.Sprintf("github.com##%s##%s", finding.Repository.Name, strings.Split(finding.Ref, "refs/heads/")[1])
} else {
cloudPlatform = "GitLab"
providerId = fmt.Sprintf("gitlab.com##%s##%s", finding.Repository.Name, strings.Split(finding.Ref, "refs/heads/")[1])
}

return cloudPlatform, providerId
}

func splitRuleName(input string) string {
if lastDotIndex := strings.LastIndex(input, "."); lastDotIndex != -1 {
return input[:lastDotIndex]
}
return input
}
149 changes: 20 additions & 129 deletions internal/semgrep/semgrep_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,33 @@ import (
"io"
"net/http"
"os"
"strings"

"github.com/DanMolz/wiz-semgrep-connector/config"
"github.com/DanMolz/wiz-semgrep-connector/internal/utils"
)

const (
semgrepAPIURLTemplate = "https://semgrep.dev/api/v1/deployments/%s/findings?issue_type=sast&page_size=3000"
integrationID = "55c176cc-d155-43a2-98ed-aa56873a1ca1"
)

type WizFindingsSchema struct {
IntegrationID string `json:"integrationId"`
DataSources []DataSources `json:"dataSources"`
}

type DataSources struct {
ID string `json:"id"`
AnalysisDate string `json:"analysisDate"`
Assets []Assets `json:"assets"`
}

type Assets struct {
AssetIdentifier AssetIdentifier `json:"assetIdentifier"`
WebAppVulnerabilityFindings []WebAppVulnerabilityFindings `json:"webAppVulnerabilityFindings"`
}

type AssetIdentifier struct {
CloudPlatform string `json:"cloudPlatform"`
ProviderID string `json:"providerId"`
}
const semgrepAPIURLTemplate = "https://semgrep.dev/api/v1/deployments/%s/findings?issue_type=sast&page_size=3000"

type WebAppVulnerabilityFindings struct {
SastFinding SastFinding `json:"sastFinding"`
ID string `json:"id"`
Name string `json:"name"`
DetailedName string `json:"detailedName"`
Severity string `json:"severity"`
ExternalFindingLink string `json:"externalFindingLink"`
Source string `json:"source"`
Remediation string `json:"remediation"`
Description string `json:"description"`
type SemgrepFindings struct {
Findings []Finding `json:"findings"`
}

type SastFinding struct {
CommitHash string `json:"commitHash"`
Filename string `json:"filename"`
LineNumbers string `json:"lineNumbers"`
type Finding struct {
ID int `json:"id"`
Ref string `json:"ref"`
Repository Repository `json:"repository"`
LineOfCodeURL string `json:"line_of_code_url"`
State string `json:"state"`
TriageState string `json:"triage_state"`
Status string `json:"status"`
Confidence string `json:"confidence"`
CreatedAt string `json:"created_at"`
RelevantSince string `json:"relevant_since"`
RuleName string `json:"rule_name"`
RuleMessage string `json:"rule_message"`
Location Location `json:"location"`
Severity string `json:"severity"`
Categories []string `json:"categories"`
Rule Rule `json:"rule"`
}

type Repository struct {
Expand All @@ -80,29 +59,6 @@ type Rule struct {
OWASP []string `json:"owasp_names"`
}

type SemgrepFindings struct {
Findings []Finding `json:"findings"`
}

type Finding struct {
ID int `json:"id"`
Ref string `json:"ref"`
Repository Repository `json:"repository"`
LineOfCodeURL string `json:"line_of_code_url"`
State string `json:"state"`
TriageState string `json:"triage_state"`
Status string `json:"status"`
Confidence string `json:"confidence"`
CreatedAt string `json:"created_at"`
RelevantSince string `json:"relevant_since"`
RuleName string `json:"rule_name"`
RuleMessage string `json:"rule_message"`
Location Location `json:"location"`
Severity string `json:"severity"`
Categories []string `json:"categories"`
Rule Rule `json:"rule"`
}

func FetchFindings(cfg config.Config) (SemgrepFindings, error) {
client := &http.Client{}
semgrepURL := fmt.Sprintf(semgrepAPIURLTemplate, cfg.SEMGREP_DEPLOYMENT)
Expand Down Expand Up @@ -144,68 +100,3 @@ func WriteFindingsToFile(findings interface{}, filePath string) error {

return nil
}

func TransformFindings(findings SemgrepFindings) (WizFindingsSchema, error) {
var wizFindings WizFindingsSchema
wizFindings.IntegrationID = integrationID

for _, finding := range findings.Findings {
cloudPlatform, providerId := getCloudPlatformAndProviderId(finding)
findingDescription := fmt.Sprintf("Rule Confidence: %s. Description: %s", utils.CapitalizeFirstChar(finding.Confidence), finding.Rule.Message)

wizFindingDataSources := DataSources{
ID: finding.Repository.Name,
AnalysisDate: finding.CreatedAt,
Assets: []Assets{
{
AssetIdentifier: AssetIdentifier{
CloudPlatform: cloudPlatform,
ProviderID: providerId,
},
WebAppVulnerabilityFindings: []WebAppVulnerabilityFindings{
{
SastFinding: SastFinding{
CommitHash: "",
Filename: finding.Location.FilePath,
LineNumbers: fmt.Sprintf("%d-%d", finding.Location.Line, finding.Location.Column),
},
ID: fmt.Sprint(finding.ID),
Name: strings.Split(finding.Rule.CWE[0], ":")[0],
DetailedName: splitRuleName(finding.RuleName),
Severity: utils.CapitalizeFirstChar(finding.Severity),
ExternalFindingLink: finding.LineOfCodeURL,
Source: "Semgrep",
Remediation: "N/A",
Description: findingDescription,
},
},
},
},
}

wizFindings.DataSources = append(wizFindings.DataSources, wizFindingDataSources)
}

return wizFindings, nil
}

func getCloudPlatformAndProviderId(finding Finding) (string, string) {
var cloudPlatform, providerId string

if strings.Contains(finding.Repository.URL, "github.com") {
cloudPlatform = "GitHub"
providerId = fmt.Sprintf("github.com##%s##%s", finding.Repository.Name, strings.Split(finding.Ref, "refs/heads/")[1])
} else {
cloudPlatform = "GitLab"
providerId = fmt.Sprintf("gitlab.com##%s##%s", finding.Repository.Name, strings.Split(finding.Ref, "refs/heads/")[1])
}

return cloudPlatform, providerId
}

func splitRuleName(input string) string {
if lastDotIndex := strings.LastIndex(input, "."); lastDotIndex != -1 {
return input[:lastDotIndex]
}
return input
}
20 changes: 19 additions & 1 deletion internal/utils/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package utils

import "strings"
import (
"encoding/json"
"fmt"
"os"
"strings"
)

// CapitalizeFirstChar capitalizes the first character of a string
func CapitalizeFirstChar(s string) string {
Expand All @@ -9,3 +14,16 @@ func CapitalizeFirstChar(s string) string {
}
return strings.ToUpper(string(s[0])) + s[1:]
}

func WriteToFile(input interface{}, filePath string) error {
data, err := json.MarshalIndent(input, "", " ")
if err != nil {
return fmt.Errorf("marshaling data: %w", err)
}

if err := os.WriteFile(filePath, data, 0644); err != nil {
return fmt.Errorf("writing file: %w", err)
}

return nil
}
Loading

0 comments on commit 56ed1ff

Please sign in to comment.