mirror of
https://github.com/SAP/jenkins-library.git
synced 2026-06-19 22:58:55 +02:00
detectExecuteScan: count violations only for license policy rules (#5778)
This commit is contained in:
@@ -1004,7 +1004,10 @@ func writeIpPolicyJson(config detectExecuteScanOptions, utils detectUtils, paths
|
||||
return fmt.Errorf("failed to get License Policy Violations: %w", err), 0
|
||||
}
|
||||
|
||||
violationCount := getActivePolicyViolations(components)
|
||||
violationCount, err := countComponentsActiveLicensePolicyViolations(sys, components)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get License Policy Violations: %w", err), 0
|
||||
}
|
||||
violations := struct {
|
||||
PolicyViolations int `json:"policyViolations"`
|
||||
Reports []string `json:"reports"`
|
||||
@@ -1034,21 +1037,44 @@ func writeIpPolicyJson(config detectExecuteScanOptions, utils detectUtils, paths
|
||||
return nil, violationCount
|
||||
}
|
||||
|
||||
func getActivePolicyViolations(components *bd.Components) int {
|
||||
func countComponentsActiveLicensePolicyViolations(sys *blackduckSystem, components *bd.Components) (int, error) {
|
||||
if components.TotalCount == 0 {
|
||||
return 0
|
||||
return 0, nil
|
||||
}
|
||||
activeViolations := 0
|
||||
for _, component := range components.Items {
|
||||
if isActivePolicyViolation(component.PolicyStatus) {
|
||||
hasActiveViolations, err := hasActiveLicensePolicyViolations(sys, component)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if hasActiveViolations {
|
||||
activeViolations++
|
||||
}
|
||||
}
|
||||
return activeViolations
|
||||
return activeViolations, nil
|
||||
}
|
||||
|
||||
func isActivePolicyViolation(status string) bool {
|
||||
return status == "IN_VIOLATION"
|
||||
func hasActiveLicensePolicyViolations(sys *blackduckSystem, component bd.Component) (bool, error) {
|
||||
if component.PolicyStatus != "IN_VIOLATION" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
policyRules, err := sys.Client.GetComponentPolicyRules(component)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, policyRule := range policyRules {
|
||||
policyRuleDetails, err := sys.Client.GetPolicyRuleDetails(policyRule)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if policyRuleDetails.Category == "LICENSE" && policyRule.PolicyApprovalStatus == "IN_VIOLATION" {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// create toolrecord file for detectExecute
|
||||
|
||||
@@ -99,6 +99,10 @@ func newBlackduckMockSystem(config detectExecuteScanOptions) blackduckSystem {
|
||||
"https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/policy-status": policyStatusContent,
|
||||
"https://my.blackduck.system/api/projects?q=name%3ARapid_scan_on_PRs": projectContentRapidScan,
|
||||
"https://my.blackduck.system/api/projects/654ggfdgf-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContentRapid,
|
||||
"https://my.blackduck.system/api/projects/33716152-0d8a-42b4-a08e-433043f1069f/versions/519053ed-e753-4962-b396-f6e263337ddc/components/2e03fc5f-55b8-43b8-80cd-b3f2cee4bd41/versions/f19941ef-4421-4f08-9675-a905ed076e6e/policy-rules": componentPolicyRules,
|
||||
"https://my.blackduck.system/api/policy-rules/f3e0eb8f-3af2-4656-827e-97769211e19a": policyRuleLicense,
|
||||
"https://my.blackduck.system/api/policy-rules/112ba222-3bc0-4341-89c3-1b1053760722": policyRuleOperational,
|
||||
"https://my.blackduck.system/api/policy-rules/212ba222-3bc0-4341-89c3-1b1053760722": policyRuleLicense,
|
||||
},
|
||||
header: map[string]http.Header{},
|
||||
}
|
||||
@@ -161,15 +165,41 @@ const (
|
||||
{
|
||||
"componentName": "Spring Framework",
|
||||
"componentVersionName": "5.3.9",
|
||||
"policyStatus": "IN_VIOLATION"
|
||||
}, {
|
||||
"policyStatus": "IN_VIOLATION",
|
||||
"_meta": {
|
||||
"links": [
|
||||
{
|
||||
"rel": "policy-rules",
|
||||
"href": "https://my.blackduck.system/api/projects/33716152-0d8a-42b4-a08e-433043f1069f/versions/519053ed-e753-4962-b396-f6e263337ddc/components/2e03fc5f-55b8-43b8-80cd-b3f2cee4bd41/versions/f19941ef-4421-4f08-9675-a905ed076e6e/policy-rules"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Apache Tomcat",
|
||||
"componentVersionName": "9.0.52",
|
||||
"policyStatus": "IN_VIOLATION"
|
||||
}, {
|
||||
"policyStatus": "IN_VIOLATION",
|
||||
"_meta": {
|
||||
"links": [
|
||||
{
|
||||
"rel": "policy-rules",
|
||||
"href": "https://my.blackduck.system/api/projects/33716152-0d8a-42b4-a08e-433043f1069f/versions/519053ed-e753-4962-b396-f6e263337ddc/components/2e03fc5f-55b8-43b8-80cd-b3f2cee4bd41/versions/f19941ef-4421-4f08-9675-a905ed076e6e/policy-rules"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Apache Log4j",
|
||||
"componentVersionName": "4.5.16",
|
||||
"policyStatus": "UNKNOWN"
|
||||
"policyStatus": "UNKNOWN",
|
||||
"_meta": {
|
||||
"links": [
|
||||
{
|
||||
"rel": "policy-rules",
|
||||
"href": "https://my.blackduck.system/api/projects/33716152-0d8a-42b4-a08e-433043f1069f/versions/519053ed-e753-4962-b396-f6e263337ddc/components/3e03fc5f-55b8-43b8-80cd-b3f2cee4bd41/versions/f19941ef-4421-4f08-9675-a905ed076e6e/policy-rules"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}`
|
||||
@@ -261,6 +291,61 @@ const (
|
||||
}
|
||||
]
|
||||
}`
|
||||
componentPolicyRules = `{
|
||||
"totalCount": 2,
|
||||
"items": [
|
||||
{
|
||||
"name": "license policy rule overridden",
|
||||
"enabled": true,
|
||||
"policyApprovalStatus": "IN_VIOLATION_OVERRIDDEN",
|
||||
"_meta": {
|
||||
"allow": [
|
||||
"DELETE",
|
||||
"GET",
|
||||
"PUT"
|
||||
],
|
||||
"href": "https://my.blackduck.system/api/policy-rules/f3e0eb8f-3af2-4656-827e-97769211e19a",
|
||||
"links": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "operational policy rule",
|
||||
"enabled": true,
|
||||
"policyApprovalStatus": "IN_VIOLATION",
|
||||
"_meta": {
|
||||
"allow": [
|
||||
"DELETE",
|
||||
"GET",
|
||||
"PUT"
|
||||
],
|
||||
"href": "https://my.blackduck.system/api/policy-rules/112ba222-3bc0-4341-89c3-1b1053760722",
|
||||
"links": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "license policy rule violated",
|
||||
"enabled": true,
|
||||
"policyApprovalStatus": "IN_VIOLATION",
|
||||
"_meta": {
|
||||
"allow": [
|
||||
"DELETE",
|
||||
"GET",
|
||||
"PUT"
|
||||
],
|
||||
"href": "https://my.blackduck.system/api/policy-rules/212ba222-3bc0-4341-89c3-1b1053760722",
|
||||
"links": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}`
|
||||
policyRuleLicense = `{
|
||||
"name": "license policy rule",
|
||||
"category": "LICENSE"
|
||||
}`
|
||||
policyRuleOperational = `{
|
||||
"name": "operational policy rule",
|
||||
"category": "OPERATIONAL"
|
||||
}`
|
||||
)
|
||||
|
||||
func (c *detectTestUtilsBundle) RunExecutable(string, ...string) error {
|
||||
@@ -885,26 +970,20 @@ func TestIsActiveVulnerability(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsActivePolicyViolation(t *testing.T) {
|
||||
func TestCountComponentsActiveLicensePolicyViolations(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Case true", func(t *testing.T) {
|
||||
assert.True(t, isActivePolicyViolation("IN_VIOLATION"))
|
||||
})
|
||||
t.Run("Case False", func(t *testing.T) {
|
||||
assert.False(t, isActivePolicyViolation("NOT_IN_VIOLATION"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetActivePolicyViolations(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Case true", func(t *testing.T) {
|
||||
t.Run("components with active license policy violations", func(t *testing.T) {
|
||||
config := detectExecuteScanOptions{Token: "token", ServerURL: "https://my.blackduck.system", ProjectName: "SHC-PiperTest", Version: "", CustomScanVersion: "1.0"}
|
||||
sys := newBlackduckMockSystem(config)
|
||||
|
||||
components, err := sys.Client.GetComponents("SHC-PiperTest", "1.0")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, getActivePolicyViolations(components))
|
||||
require.NoError(t, err)
|
||||
|
||||
violationCount, err := countComponentsActiveLicensePolicyViolations(&sys, components)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, violationCount)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestGetVulnerabilitiesWithComponents(t *testing.T) {
|
||||
|
||||
+67
-11
@@ -23,6 +23,8 @@ const (
|
||||
HEADER_PROJECT_DETAILS_V4 = "application/vnd.blackducksoftware.project-detail-4+json"
|
||||
HEADER_USER_V4 = "application/vnd.blackducksoftware.user-4+json"
|
||||
HEADER_BOM_V6 = "application/vnd.blackducksoftware.bill-of-materials-6+json"
|
||||
HEADER_BOM_V7 = "application/vnd.blackducksoftware.bill-of-materials-7+json"
|
||||
HEADER_POLICY_DETAILS_V5 = "application/vnd.blackducksoftware.policy-5+json"
|
||||
)
|
||||
|
||||
// Projects defines the response to a BlackDuck project API request
|
||||
@@ -82,6 +84,21 @@ type ComponentOrigin struct {
|
||||
ExternalID string `json:"externalId,omitempty"`
|
||||
}
|
||||
|
||||
type PaginatedResponse[T any] struct {
|
||||
TotalCount int `json:"totalCount,omitempty"`
|
||||
Items []T `json:"items,omitempty"`
|
||||
}
|
||||
|
||||
type ComponentPolicyRule struct {
|
||||
Metadata `json:"_meta,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
PolicyApprovalStatus string `json:"policyApprovalStatus,omitempty"`
|
||||
}
|
||||
|
||||
type PolicyRule struct {
|
||||
Category string `json:"category,omitempty"`
|
||||
}
|
||||
|
||||
// ToPackageUrl creates the package URL for the component
|
||||
func (c *Component) ToPackageUrl() *packageurl.PackageURL {
|
||||
purlParts := transformComponentOriginToPurlParts(c)
|
||||
@@ -433,19 +450,58 @@ func (b *Client) GetComponentsWithLicensePolicyRule(projectName, versionName str
|
||||
return &components, nil
|
||||
}
|
||||
|
||||
// func (b *Client) GetComponentPolicyStatus(component Component) (ComponentPolicyStatus, error) {
|
||||
// var policyStatusUrl string
|
||||
// for _, link := range component.Links {
|
||||
// if link.Rel == "policy-status" {
|
||||
// policyStatusUrl = urlPath(link.Href)
|
||||
// }
|
||||
// }
|
||||
func (b *Client) GetComponentPolicyRules(component Component) ([]ComponentPolicyRule, error) {
|
||||
var policyRulesUrl string
|
||||
for _, link := range component.Links {
|
||||
if link.Rel == "policy-rules" {
|
||||
policyRulesUrl = urlPath(link.Href)
|
||||
break
|
||||
}
|
||||
}
|
||||
if policyRulesUrl == "" {
|
||||
return nil, fmt.Errorf("no Policy Rules found for component '%v'", component.Name)
|
||||
}
|
||||
|
||||
// headers := http.Header{}
|
||||
// headers.Add("Accept", HEADER_BOM_V6)
|
||||
headers := http.Header{}
|
||||
headers.Add("Accept", HEADER_BOM_V7)
|
||||
|
||||
// respBody, err := b.sendRequest("GET", policyStatusUrl, map[string]string{}, nil, headers)
|
||||
// }
|
||||
respBody, err := b.sendRequest(http.MethodGet, policyRulesUrl, map[string]string{}, nil, headers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get policy rules for component '%v': %w", component.Name, err)
|
||||
}
|
||||
|
||||
response := PaginatedResponse[ComponentPolicyRule]{}
|
||||
|
||||
err = json.Unmarshal(respBody, &response)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal component policy rules for component '%v': %w", component.Name, err)
|
||||
}
|
||||
|
||||
return response.Items, nil
|
||||
}
|
||||
|
||||
func (b *Client) GetPolicyRuleDetails(policyRule ComponentPolicyRule) (PolicyRule, error) {
|
||||
var policyRuleDetails PolicyRule
|
||||
policyRuleDetailsUrl := urlPath(policyRule.Href)
|
||||
if policyRuleDetailsUrl == "" {
|
||||
return policyRuleDetails, fmt.Errorf("no policy rule details URL found for policy '%v'", policyRule.Name)
|
||||
}
|
||||
|
||||
headers := http.Header{}
|
||||
headers.Add("Accept", HEADER_POLICY_DETAILS_V5)
|
||||
|
||||
respBody, err := b.sendRequest(http.MethodGet, policyRuleDetailsUrl, map[string]string{}, nil, headers)
|
||||
if err != nil {
|
||||
return policyRuleDetails, fmt.Errorf("failed to get policy rule details for policy '%v': %w", policyRule.Name, err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(respBody, &policyRuleDetails)
|
||||
if err != nil {
|
||||
return policyRuleDetails, fmt.Errorf("failed to unmarshal policy rule details for policy '%v': %w", policyRule.Name, err)
|
||||
}
|
||||
|
||||
return policyRuleDetails, nil
|
||||
}
|
||||
|
||||
func (b *Client) GetVulnerabilities(projectName, versionName string) (*Vulnerabilities, error) {
|
||||
projectVersion, err := b.GetProjectVersion(projectName, versionName)
|
||||
|
||||
Reference in New Issue
Block a user