This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
local_imports/
|
||||||
ENV
|
ENV
|
||||||
defs/
|
defs/
|
||||||
*/.venv/
|
*/.venv/
|
||||||
|
12
go.mod
Normal file
12
go.mod
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module dtrack-defectdojo-automatio-go/sbom-dd-dt
|
||||||
|
|
||||||
|
go 1.24.4
|
||||||
|
|
||||||
|
replace local_imports/defectdojo-client-go => ./local_imports/defectdojo-client-go
|
||||||
|
|
||||||
|
replace local_imports/dependencytrack-client-go => ./local_imports/dependencytrack-client-go
|
||||||
|
|
||||||
|
require (
|
||||||
|
local_imports/defectdojo-client-go v0.0.0-00010101000000-000000000000
|
||||||
|
local_imports/dependencytrack-client-go v0.0.0-00010101000000-000000000000
|
||||||
|
)
|
178
src/sbom-dd-dt/main.go
Normal file
178
src/sbom-dd-dt/main.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
defectdojo_api "local_imports/defectdojo-client-go"
|
||||||
|
dependencytrack_api "local_imports/dependencytrack-client-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
var verbose bool
|
||||||
|
|
||||||
|
func mustEnv(key string) string {
|
||||||
|
val, ok := os.LookupEnv(key)
|
||||||
|
if !ok {
|
||||||
|
log.Fatalf("Missing required env variable: %s", key)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSBOM(target, name, version string) ([]byte, error) {
|
||||||
|
cmd := exec.Command("syft", "scan", target, "-o", "cyclonedx-json", "--source-name", name, "--source-version", version)
|
||||||
|
var out, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &out
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("SBOM generation failed:", stderr.String())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Load env
|
||||||
|
dtrackURL := mustEnv("DTRACK_API_URL")
|
||||||
|
dtrackToken := mustEnv("DTRACK_TOKEN")
|
||||||
|
defectdojoURL := mustEnv("DEFECTDOJO_URL")
|
||||||
|
defectdojoToken := mustEnv("DEFECTDOJO_TOKEN")
|
||||||
|
|
||||||
|
// Flags
|
||||||
|
projectName := os.Args[1] // Simplified args
|
||||||
|
projectVersion := os.Args[2]
|
||||||
|
projectDescription := os.Args[3]
|
||||||
|
productType, _ := strconv.Atoi(os.Args[4])
|
||||||
|
projectClassifier := os.Args[5]
|
||||||
|
sbomFile := os.Args[6] // optional
|
||||||
|
|
||||||
|
// Get SBOM
|
||||||
|
var sbom []byte
|
||||||
|
var err error
|
||||||
|
if sbomFile != "" {
|
||||||
|
sbom, err = os.ReadFile(sbomFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not read SBOM file: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sbom, err = generateSBOM(".", projectName, projectVersion)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to generate SBOM: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefectDojo client
|
||||||
|
ddConfig := defectdojo_api.NewConfiguration()
|
||||||
|
ddConfig.Servers = defectdojo_api.ServerConfigurations{
|
||||||
|
{URL: defectdojoURL},
|
||||||
|
}
|
||||||
|
ddConfig.AddDefaultHeader("Authorization", "Token "+defectdojoToken)
|
||||||
|
|
||||||
|
ddClient := defectdojo_api.NewAPIClient(ddConfig)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// Create product
|
||||||
|
prodReq := defectdojo_api.ProductRequest{
|
||||||
|
Name: projectName + ":" + projectVersion,
|
||||||
|
Description: projectDescription,
|
||||||
|
ProdType: int32(productType),
|
||||||
|
}
|
||||||
|
prodResp, _, err := ddClient.ProductsAPI.ProductsCreate(ctx).ProductRequest(prodReq).Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create product: %v", err)
|
||||||
|
}
|
||||||
|
log.Println("Created product:", prodResp.Id)
|
||||||
|
|
||||||
|
// Create engagement
|
||||||
|
now := time.Now()
|
||||||
|
end := now.AddDate(10, 0, 0)
|
||||||
|
engagementReq := defectdojo_api.EngagementRequest{
|
||||||
|
Name: projectName + " DTrack Link",
|
||||||
|
TargetStart: now.Format("2006-01-02"),
|
||||||
|
TargetEnd: end.Format("2006-01-02"),
|
||||||
|
Status: "In Progress",
|
||||||
|
Product: prodResp.Id,
|
||||||
|
}
|
||||||
|
engagementResp, _, err := ddClient.EngagementsAPI.EngagementsCreate(ctx).EngagementRequest(engagementReq).Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create engagement: %v", err)
|
||||||
|
}
|
||||||
|
log.Println("Created engagement:", engagementResp.Id)
|
||||||
|
|
||||||
|
// DependencyTrack client
|
||||||
|
dtConfig := dependencytrack_api.NewConfiguration()
|
||||||
|
dtConfig.Servers = dependencytrack_api.ServerConfigurations{
|
||||||
|
{URL: dtrackURL + "/api"},
|
||||||
|
}
|
||||||
|
dtConfig.AddDefaultHeader("X-Api-Key", dtrackToken)
|
||||||
|
|
||||||
|
dtClient := dependencytrack_api.NewAPIClient(dtConfig)
|
||||||
|
|
||||||
|
// Create project
|
||||||
|
projectReq := dependencytrack_api.Project{
|
||||||
|
Name: &projectName,
|
||||||
|
Version: &projectVersion,
|
||||||
|
Classifier: &projectClassifier,
|
||||||
|
}
|
||||||
|
projectResp, _, err := dtClient.ProjectApi.CreateProject(ctx).Project(projectReq).Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create DTrack project: %v", err)
|
||||||
|
}
|
||||||
|
log.Println("Created DTrack project UUID:", *projectResp.Uuid)
|
||||||
|
|
||||||
|
// Set properties
|
||||||
|
properties := []dependencytrack_api.ProjectProperty{
|
||||||
|
{
|
||||||
|
GroupName: ptr("integrations"),
|
||||||
|
PropertyName: ptr("defectdojo.engagementId"),
|
||||||
|
PropertyValue: ptr(fmt.Sprintf("%d", *engagementResp.Id)),
|
||||||
|
PropertyType: ptr("STRING"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupName: ptr("integrations"),
|
||||||
|
PropertyName: ptr("defectdojo.doNotReactivate"),
|
||||||
|
PropertyValue: ptr("true"),
|
||||||
|
PropertyType: ptr("BOOLEAN"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupName: ptr("integrations"),
|
||||||
|
PropertyName: ptr("defectdojo.reimport"),
|
||||||
|
PropertyValue: ptr("true"),
|
||||||
|
PropertyType: ptr("BOOLEAN"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range properties {
|
||||||
|
_, err := dtClient.ProjectPropertyApi.CreateProperty1(ctx, *projectResp.Uuid).ProjectProperty(p).Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create property: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload SBOM
|
||||||
|
_, err = dtClient.BomApi.UploadBom(ctx).
|
||||||
|
ProjectName(projectName).
|
||||||
|
ProjectVersion(projectVersion).
|
||||||
|
AutoCreate(true).
|
||||||
|
Bom(string(sbom)).
|
||||||
|
Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to upload SBOM: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("SBOM uploaded successfully")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptr[T any](v T) *T {
|
||||||
|
return &v
|
||||||
|
}
|
Reference in New Issue
Block a user