Skip to content

Commit

Permalink
Add support for specifying timeout and check interval in SBOM uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
takumakume committed Dec 5, 2023
1 parent 48fece4 commit 8e3a957
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 40 deletions.
9 changes: 9 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ Dependency-Track APK key permissions required:
viper.GetString("project-name"),
viper.GetString("project-version"),
viper.GetStringSlice("project-tags"),
viper.GetFloat64("dtrack-client-timeout"),
viper.GetFloat64("sbom-upload-timeout-sec"),
viper.GetFloat64("sbom-upload-check-interval-sec"),
)
if err := c.Validate(); err != nil {
return err
Expand Down Expand Up @@ -100,12 +103,18 @@ func init() {
flags.StringP("project-name", "", "[[.sbomReport.report.artifact.repository]]", "Project name template (env: DT_PROJECT_NAME)")
flags.StringP("project-version", "", "[[.sbomReport.report.artifact.tag]]", "Project version template (env: DT_PROJECT_VERSION)")
flags.StringSliceP("project-tags", "t", []string{}, "Project tags template (env: DT_PROJECT_TAGS (comma separated))")
flags.Float64P("dtrack-client-timeout", "", 10, "Dependency Track client timeout seconds")
flags.Float64P("sbom-upload-timeout-sec", "", 30, "Seconds to timeout waiting for completion of SBOM upload of Dependency Track")
flags.Float64P("sbom-upload-check-interval-sec", "", 1, "Interval seconds to check for completion of SBOM upload of Dependency Track")

viper.BindPFlag("base-url", flags.Lookup("base-url"))
viper.BindPFlag("api-key", flags.Lookup("api-key"))
viper.BindPFlag("project-name", flags.Lookup("project-name"))
viper.BindPFlag("project-version", flags.Lookup("project-version"))
viper.BindPFlag("project-tags", flags.Lookup("project-tags"))
viper.BindPFlag("dtrack-client-timeout", flags.Lookup("dtrack-client-timeout"))
viper.BindPFlag("sbom-upload-timeout-sec", flags.Lookup("sbom-upload-timeout-sec"))
viper.BindPFlag("sbom-upload-check-interval-sec", flags.Lookup("sbom-upload-check-interval-sec"))
}

func Execute() error {
Expand Down
3 changes: 3 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ var serverCmd = &cobra.Command{
viper.GetString("project-name"),
viper.GetString("project-version"),
viper.GetStringSlice("project-tags"),
viper.GetFloat64("dtrack-client-timeout-sec"),
viper.GetFloat64("sbom-upload-timeout-sec"),
viper.GetFloat64("sbom-upload-check-interval-sec"),
)
if err := c.Validate(); err != nil {
return err
Expand Down
20 changes: 14 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"errors"
"strings"
"time"
)

type Config struct {
Expand All @@ -12,21 +13,28 @@ type Config struct {
ProjectName string
ProjectVersion string
ProjectTags []string

DtrackClientTimeout time.Duration
SBOMUploadTimeout time.Duration
SBOMUploadCheckInterval time.Duration
}

var ErrAPIKeyIsRequired = errors.New("api-key is required")

func New(baseURL, apiKey, projectName, projectVersion string, projectTags []string) *Config {
func New(baseURL, apiKey, projectName, projectVersion string, projectTags []string, dtrackClientTimeoutSec, sbomUploadTimeoutSec, sbomUploadCheckIntervalSec float64) *Config {
if len(projectTags) == 1 && strings.Contains(projectTags[0], ",") {
projectTags = strings.Split(projectTags[0], ",")
}

return &Config{
BaseURL: baseURL,
APIKey: apiKey,
ProjectName: projectName,
ProjectVersion: projectVersion,
ProjectTags: projectTags,
BaseURL: baseURL,
APIKey: apiKey,
ProjectName: projectName,
ProjectVersion: projectVersion,
ProjectTags: projectTags,
DtrackClientTimeout: time.Duration(dtrackClientTimeoutSec) * time.Second,
SBOMUploadTimeout: time.Duration(sbomUploadTimeoutSec) * time.Second,
SBOMUploadCheckInterval: time.Duration(sbomUploadCheckIntervalSec) * time.Second,
}
}

Expand Down
68 changes: 42 additions & 26 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ package config
import (
"reflect"
"testing"
"time"
)

func TestNew(t *testing.T) {
type args struct {
baseURL string
apiKey string
projectName string
projectVersion string
projectTags []string
baseURL string
apiKey string
projectName string
projectVersion string
projectTags []string
dtrackClientTimeoutSec float64
sbomUploadTimeoutSec float64
sbomUploadCheckIntervalSec float64
}
tests := []struct {
name string
Expand All @@ -21,41 +25,53 @@ func TestNew(t *testing.T) {
{
name: "success",
args: args{
baseURL: "https://example.com",
apiKey: "12345",
projectName: "test-project",
projectVersion: "1.0.0",
projectTags: []string{"tag1", "tag2"},
baseURL: "https://example.com",
apiKey: "12345",
projectName: "test-project",
projectVersion: "1.0.0",
projectTags: []string{"tag1", "tag2"},
dtrackClientTimeoutSec: 10,
sbomUploadTimeoutSec: 30,
sbomUploadCheckIntervalSec: 1,
},
want: &Config{
BaseURL: "https://example.com",
APIKey: "12345",
ProjectName: "test-project",
ProjectVersion: "1.0.0",
ProjectTags: []string{"tag1", "tag2"},
BaseURL: "https://example.com",
APIKey: "12345",
ProjectName: "test-project",
ProjectVersion: "1.0.0",
ProjectTags: []string{"tag1", "tag2"},
DtrackClientTimeout: time.Duration(10) * time.Second,
SBOMUploadTimeout: time.Duration(30) * time.Second,
SBOMUploadCheckInterval: time.Duration(1) * time.Second,
},
},
{
name: "success tag separator is comma",
args: args{
baseURL: "https://example.com",
apiKey: "12345",
projectName: "test-project",
projectVersion: "1.0.0",
projectTags: []string{"tag1,tag2"},
baseURL: "https://example.com",
apiKey: "12345",
projectName: "test-project",
projectVersion: "1.0.0",
projectTags: []string{"tag1,tag2"},
dtrackClientTimeoutSec: 10,
sbomUploadTimeoutSec: 30,
sbomUploadCheckIntervalSec: 1,
},
want: &Config{
BaseURL: "https://example.com",
APIKey: "12345",
ProjectName: "test-project",
ProjectVersion: "1.0.0",
ProjectTags: []string{"tag1", "tag2"},
BaseURL: "https://example.com",
APIKey: "12345",
ProjectName: "test-project",
ProjectVersion: "1.0.0",
ProjectTags: []string{"tag1", "tag2"},
DtrackClientTimeout: time.Duration(10) * time.Second,
SBOMUploadTimeout: time.Duration(30) * time.Second,
SBOMUploadCheckInterval: time.Duration(1) * time.Second,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := New(tt.args.baseURL, tt.args.apiKey, tt.args.projectName, tt.args.projectVersion, tt.args.projectTags); !reflect.DeepEqual(got, tt.want) {
if got := New(tt.args.baseURL, tt.args.apiKey, tt.args.projectName, tt.args.projectVersion, tt.args.projectTags, tt.args.dtrackClientTimeoutSec, tt.args.sbomUploadTimeoutSec, tt.args.sbomUploadCheckIntervalSec); !reflect.DeepEqual(got, tt.want) {
t.Errorf("New() = %v, want %v", got, tt.want)
}
})
Expand Down
17 changes: 13 additions & 4 deletions dependencytrack/dependencytrack.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dependencytrack
import (
"context"
"encoding/base64"
"fmt"
"log"
"time"

Expand All @@ -16,16 +17,21 @@ type DependencyTrackClient interface {

type DependencyTrack struct {
Client *dtrack.Client

SBOMUploadTimeout time.Duration
SBOMUploadCheckInterval time.Duration
}

func New(baseURL, apiKey string, timeout time.Duration) (*DependencyTrack, error) {
client, err := dtrack.NewClient(baseURL, dtrack.WithAPIKey(apiKey), dtrack.WithTimeout(timeout))
func New(baseURL, apiKey string, dtrackClientTimeout, sbomUploadTimeout, sbomUploadCheckInterval time.Duration) (*DependencyTrack, error) {
client, err := dtrack.NewClient(baseURL, dtrack.WithAPIKey(apiKey), dtrack.WithTimeout(dtrackClientTimeout))
if err != nil {
return nil, err
}

return &DependencyTrack{
Client: client,
Client: client,
SBOMUploadTimeout: sbomUploadTimeout,
SBOMUploadCheckInterval: sbomUploadCheckInterval,
}, nil
}

Expand Down Expand Up @@ -53,7 +59,7 @@ func (dt *DependencyTrack) UploadBOM(ctx context.Context, projectName, projectVe
close(errChan)
}()

ticker := time.NewTicker(1 * time.Second)
ticker := time.NewTicker(dt.SBOMUploadCheckInterval)
defer ticker.Stop()

for {
Expand All @@ -68,6 +74,9 @@ func (dt *DependencyTrack) UploadBOM(ctx context.Context, projectName, projectVe
doneChan <- struct{}{}
return
}
case <-time.After(dt.SBOMUploadTimeout):
errChan <- fmt.Errorf("timeout exceeded")
return
case <-ctx.Done():
errChan <- ctx.Err()
return
Expand Down
5 changes: 1 addition & 4 deletions uploader/uploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@ import (
"context"
"errors"
"log"
"time"

"github.com/takumakume/sbomreport-to-dependencytrack/config"
"github.com/takumakume/sbomreport-to-dependencytrack/dependencytrack"
"github.com/takumakume/sbomreport-to-dependencytrack/sbomreport"
tmpl "github.com/takumakume/sbomreport-to-dependencytrack/template"
)

const TIMEOUT = 10

type Uploader interface {
Run(ctx context.Context, input []byte) error
}
Expand All @@ -24,7 +21,7 @@ type Upload struct {
}

func New(c *config.Config) (*Upload, error) {
dtrack, err := dependencytrack.New(c.BaseURL, c.APIKey, time.Duration(TIMEOUT)*time.Second)
dtrack, err := dependencytrack.New(c.BaseURL, c.APIKey, c.DtrackClientTimeout, c.SBOMUploadTimeout, c.SBOMUploadCheckInterval)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 8e3a957

Please sign in to comment.