diff --git a/client.go b/client.go index 4a75d7b..d1a31bd 100644 --- a/client.go +++ b/client.go @@ -46,6 +46,7 @@ type Client struct { Health HealthService LDAP LDAPService License LicenseService + LicenseGroup LicenseGroupService Metrics MetricsService OIDC OIDCService Permission PermissionService @@ -99,6 +100,7 @@ func NewClient(baseURL string, options ...ClientOption) (*Client, error) { client.Health = HealthService{client: &client} client.LDAP = LDAPService{client: &client} client.License = LicenseService{client: &client} + client.LicenseGroup = LicenseGroupService{client: &client} client.Metrics = MetricsService{client: &client} client.OIDC = OIDCService{client: &client} client.Permission = PermissionService{client: &client} diff --git a/license.go b/license.go index 9309dca..656a138 100644 --- a/license.go +++ b/license.go @@ -2,6 +2,7 @@ package dtrack import ( "context" + "fmt" "net/http" "github.com/google/uuid" @@ -25,13 +26,18 @@ type LicenseService struct { client *Client } -func (l LicenseService) GetAll(ctx context.Context, po PageOptions) (p Page[License], err error) { - req, err := l.client.newRequest(ctx, http.MethodGet, "api/v1/license", withPageOptions(po)) +func (ls LicenseService) GetAll(ctx context.Context, po PageOptions) (p Page[License], err error) { + err = ls.client.assertServerVersionAtLeast("3.0.0") if err != nil { return } - res, err := l.client.doRequest(req, &p.Items) + req, err := ls.client.newRequest(ctx, http.MethodGet, "api/v1/license", withPageOptions(po)) + if err != nil { + return + } + + res, err := ls.client.doRequest(req, &p.Items) if err != nil { return } @@ -39,3 +45,63 @@ func (l LicenseService) GetAll(ctx context.Context, po PageOptions) (p Page[Lice p.TotalCount = res.TotalCount return } + +func (ls LicenseService) Get(ctx context.Context, licenseSPDX string) (l License, err error) { + err = ls.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("api/v1/license/%s", licenseSPDX)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, &l) + return +} + +func (ls LicenseService) Create(ctx context.Context, license License) (l License, err error) { + err = ls.client.assertServerVersionAtLeast("4.7.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodPut, "api/v1/license", withBody(license)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, &l) + return +} + +func (ls LicenseService) Delete(ctx context.Context, licenseSPDX string) (err error) { + err = ls.client.assertServerVersionAtLeast("4.7.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/license/%s", licenseSPDX)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, nil) + return +} + +func (ls LicenseService) GetConcise(ctx context.Context) (licenses []License, err error) { + err = ls.client.assertServerVersionAtLeast("3.4.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodGet, "api/v1/license/concise") + if err != nil { + return + } + + _, err = ls.client.doRequest(req, &licenses) + return +} diff --git a/license_group.go b/license_group.go new file mode 100644 index 0000000..7e6157e --- /dev/null +++ b/license_group.go @@ -0,0 +1,129 @@ +package dtrack + +import ( + "context" + "fmt" + "net/http" + + "github.com/google/uuid" +) + +type LicenseGroup struct { + UUID uuid.UUID `json:"uuid"` + Name string `json:"name"` + Licenses []License `json:"licenses,omitempty"` + RiskWeight int32 `json:"riskWeight,omitempty"` +} + +type LicenseGroupService struct { + client *Client +} + +func (ls LicenseGroupService) AddLicense(ctx context.Context, groupUUID, licenseUUID uuid.UUID) (lg LicenseGroup, err error) { + err = ls.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodPost, fmt.Sprintf("api/v1/licenseGroup/%s/license/%s", groupUUID, licenseUUID)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, &lg) + return +} + +func (ls LicenseGroupService) RemoveLicense(ctx context.Context, groupUUID, licenseUUID uuid.UUID) (lg LicenseGroup, err error) { + err = ls.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/licenseGroup/%s/license/%s", groupUUID, licenseUUID)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, &lg) + return +} + +func (ls LicenseGroupService) GetAll(ctx context.Context, po PageOptions, so SortOptions) (p Page[LicenseGroup], err error) { + err = ls.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodGet, "api/v1/licenseGroup") + if err != nil { + return + } + + res, err := ls.client.doRequest(req, &p.Items) + if err != nil { + return + } + p.TotalCount = res.TotalCount + return +} + +func (ls LicenseGroupService) Create(ctx context.Context, group LicenseGroup) (lg LicenseGroup, err error) { + err = ls.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodPut, "api/v1/licenseGroup", withBody(group)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, &lg) + return +} + +func (ls LicenseGroupService) Update(ctx context.Context, group LicenseGroup) (lg LicenseGroup, err error) { + err = ls.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodPost, "api/v1/licenseGroup", withBody(group)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, &lg) + return +} + +func (ls LicenseGroupService) Get(ctx context.Context, groupUUID uuid.UUID) (lg LicenseGroup, err error) { + err = ls.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("api/v1/licenseGroup/%s", groupUUID)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, &lg) + return +} + +func (ls LicenseGroupService) Delete(ctx context.Context, groupUUID uuid.UUID) (err error) { + err = ls.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := ls.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/licenseGroup/%s", groupUUID)) + if err != nil { + return + } + + _, err = ls.client.doRequest(req, nil) + return +} diff --git a/license_group_test.go b/license_group_test.go new file mode 100644 index 0000000..3525bb3 --- /dev/null +++ b/license_group_test.go @@ -0,0 +1,154 @@ +package dtrack + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestLicenseGroupGetAll(t *testing.T) { + po := PageOptions{ + // DepedencyTrack is preloaded with 4 license groups. This need only be <= the number preloaded in DT. + PageSize: 4, + PageNumber: 1, + } + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionPolicyManagement, + }, + }) + + groups, err := client.LicenseGroup.GetAll(context.Background(), po, SortOptions{}) + require.NoError(t, err) + require.Equal(t, len(groups.Items), po.PageSize) + require.NotZero(t, groups.TotalCount) + for _, group := range groups.Items { + require.NotZero(t, group.UUID) + require.NotEmpty(t, group.Name) + require.NotEmpty(t, group.Licenses) + } +} + +func TestLicenseGroupLifecycle(t *testing.T) { + po := PageOptions{ + PageNumber: 1, + PageSize: 10, + } + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionPolicyManagement, + }, + }) + // Check absence + { + groups, err := client.LicenseGroup.GetAll(context.Background(), po, SortOptions{}) + require.NoError(t, err) + for _, group := range groups.Items { + require.NotEqual(t, group.Name, "TestLicenseGroupLifecycle") + } + } + // Create + group, err := client.LicenseGroup.Create(context.Background(), LicenseGroup{ + Name: "TestLicenseGroupLifecycle", + }) + { + require.NoError(t, err) + require.NotZero(t, group.UUID) + require.Equal(t, group.Name, "TestLicenseGroupLifecycle") + } + // Check presence + { + newGroup, err := client.LicenseGroup.Get(context.Background(), group.UUID) + require.NoError(t, err) + require.Equal(t, newGroup, group) + } + // Update + { + copyGroup := group + copyGroup.Name = "UpdatedName" + require.NotEqual(t, copyGroup.Name, group.Name) + + newGroup, err := client.LicenseGroup.Update(context.Background(), copyGroup) + require.NoError(t, err) + require.Equal(t, newGroup, copyGroup) + } + // Check update + { + newGroup, err := client.LicenseGroup.Get(context.Background(), group.UUID) + require.NoError(t, err) + require.Equal(t, newGroup.Name, "UpdatedName") + newGroup.Name = group.Name + require.Equal(t, newGroup, group) + } + // Delete + { + err := client.LicenseGroup.Delete(context.Background(), group.UUID) + require.NoError(t, err) + } + // Check absence + { + groups, err := client.LicenseGroup.GetAll(context.Background(), po, SortOptions{}) + require.NoError(t, err) + for _, check := range groups.Items { + require.NotEqual(t, check.UUID, group.UUID) + } + } +} + +func TestLicenseGroupLicense(t *testing.T) { + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionSystemConfiguration, + PermissionPolicyManagement, + }, + }) + // Create License, License Group + group, err := client.LicenseGroup.Create(context.Background(), LicenseGroup{ + Name: "TestLicenseGroup", + }) + require.NoError(t, err) + license, err := client.License.Create(context.Background(), License{ + Name: "TestLicense", + LicenseID: "TestLicenseID", + }) + require.NoError(t, err) + // Add license + { + newGroup, err := client.LicenseGroup.AddLicense(context.Background(), group.UUID, license.UUID) + require.NoError(t, err) + require.Equal(t, newGroup.Licenses, []License{license}) + newGroup.Licenses = []License{} + require.Equal(t, newGroup, group) + } + // Check presence in group + { + newGroup, err := client.LicenseGroup.Get(context.Background(), group.UUID) + require.NoError(t, err) + require.Equal(t, newGroup.Licenses, []License{license}) + newGroup.Licenses = []License{} + require.Equal(t, newGroup, group) + } + // Remove license + { + newGroup, err := client.LicenseGroup.RemoveLicense(context.Background(), group.UUID, license.UUID) + require.NoError(t, err) + require.Empty(t, newGroup.Licenses) + require.Equal(t, newGroup, group) + } + // Check empty group + { + newGroup, err := client.LicenseGroup.Get(context.Background(), group.UUID) + require.NoError(t, err) + require.Empty(t, newGroup.Licenses) + require.Equal(t, newGroup, group) + } + // Cleanup + { + err := client.License.Delete(context.Background(), "TestLicenseID") + require.NoError(t, err) + + err = client.LicenseGroup.Delete(context.Background(), group.UUID) + require.NoError(t, err) + } +} diff --git a/license_test.go b/license_test.go new file mode 100644 index 0000000..ce698e2 --- /dev/null +++ b/license_test.go @@ -0,0 +1,81 @@ +package dtrack + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestLicenseGetAll(t *testing.T) { + po := PageOptions{ + PageSize: 10, + PageNumber: 1, + } + client := setUpContainer(t, testContainerOptions{}) + + licenses, err := client.License.GetAll(context.Background(), po) + require.NoError(t, err) + require.Equal(t, len(licenses.Items), po.PageSize) + require.NotZero(t, licenses.TotalCount) + for _, license := range licenses.Items { + require.NotZero(t, license.UUID) + require.NotEmpty(t, license.Name) + require.NotEmpty(t, license.LicenseID) + } +} + +func TestLicenseLifecycle(t *testing.T) { + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionSystemConfiguration, + }, + }) + licenseSPDX := "DependencyTrack-ClientGo" + // Check absence + { + l, err := client.License.Get(context.Background(), licenseSPDX) + require.Error(t, err) + require.Zero(t, l) + } + // Create + license, err := client.License.Create(context.Background(), License{ + Name: "Client Go Test License", + LicenseID: licenseSPDX, + }) + { + require.NoError(t, err) + require.NotZero(t, license.UUID) + require.Equal(t, license.LicenseID, licenseSPDX) + require.Equal(t, license.Name, "Client Go Test License") + } + // Check presence + { + l, err := client.License.Get(context.Background(), licenseSPDX) + require.NoError(t, err) + require.Equal(t, l, license) + } + // Delete + { + err := client.License.Delete(context.Background(), licenseSPDX) + require.NoError(t, err) + } + // Check absence + { + l, err := client.License.Get(context.Background(), licenseSPDX) + require.Error(t, err) + require.Zero(t, l) + } +} + +func TestLicenseGetConcise(t *testing.T) { + client := setUpContainer(t, testContainerOptions{}) + licenses, err := client.License.GetConcise(context.Background()) + require.NoError(t, err) + require.NotEmpty(t, licenses) + for _, license := range licenses { + require.NotZero(t, license.UUID) + require.NotEmpty(t, license.Name) + require.NotEmpty(t, license.LicenseID) + } +}