diff --git a/cmd/devguard-cli/commands/vulndb.go b/cmd/devguard-cli/commands/vulndb.go
index 451d40578..6b5e020b6 100644
--- a/cmd/devguard-cli/commands/vulndb.go
+++ b/cmd/devguard-cli/commands/vulndb.go
@@ -83,6 +83,7 @@ func migrateDB() {
fx.Invoke(func(DependencyVulnRouter router.DependencyVulnRouter) {}),
fx.Invoke(func(FirstPartyVulnRouter router.FirstPartyVulnRouter) {}),
fx.Invoke(func(LicenseRiskRouter router.LicenseRiskRouter) {}),
+ fx.Invoke(func(ComplianceRiskRouter router.ComplianceRiskRouter) {}),
fx.Invoke(func(ShareRouter router.ShareRouter) {}),
fx.Invoke(func(VulnDBRouter router.VulnDBRouter) {}),
fx.Invoke(func(dependencyProxyRouter router.DependencyProxyRouter) {}),
diff --git a/cmd/devguard-scanner/commands/attestations.go b/cmd/devguard-scanner/commands/attestations.go
index 81704380f..af3e6b3fa 100644
--- a/cmd/devguard-scanner/commands/attestations.go
+++ b/cmd/devguard-scanner/commands/attestations.go
@@ -78,7 +78,7 @@ func attestationsCmd(cmd *cobra.Command, args []string) error {
defer os.Remove(policyPath)
}
- sarifResult, evals, err := scanner.EvaluatePolicyAgainstAttestations(image, policyPath, attestations)
+ sarifResult, evals, err := scanner.EvaluatePolicyAgainstAttestations(fmt.Sprintf("oci://%s", image), policyPath, attestations)
if err != nil {
return err
}
diff --git a/cmd/devguard-scanner/scanner/eval_policy.go b/cmd/devguard-scanner/scanner/eval_policy.go
index c1ee43527..5464e1e09 100644
--- a/cmd/devguard-scanner/scanner/eval_policy.go
+++ b/cmd/devguard-scanner/scanner/eval_policy.go
@@ -25,163 +25,40 @@ import (
"github.com/l3montree-dev/devguard/utils"
)
-func EvaluatePolicyAgainstAttestations(image string, policyPath string, attestations []map[string]any) (*sarif.SarifSchema210Json, []compliance.PolicyEvaluation, error) {
- policyContent, err := os.ReadFile(policyPath)
+func EvaluatePolicyAgainstAttestations(srcPath string, policyPath string, attestations []map[string]any) (*sarif.SarifSchema210Json, []compliance.PolicyEvaluation, error) {
+
+ content, err := os.ReadFile(policyPath)
if err != nil {
return nil, nil, fmt.Errorf("could not read policy file: %w", err)
}
- policy, err := compliance.NewPolicy(filepath.Base(policyPath), string(policyContent))
+ policy, err := compliance.GetPolicyFromFile(filepath.Base(policyPath), string(content))
if err != nil {
return nil, nil, fmt.Errorf("could not parse policy: %w", err)
}
- model := compliance.ConvertPolicyFsToModel(*policy)
-
- filtered := attestations
- if policy.PredicateType != "" {
- filtered = []map[string]any{}
- for _, attestation := range attestations {
- if predicateType, ok := attestation["predicateType"].(string); ok && predicateType == policy.PredicateType {
- filtered = append(filtered, attestation)
+ evaluations := make([]compliance.PolicyEvaluation, 0)
+
+ for _, attestation := range attestations {
+ var eval compliance.PolicyEvaluation
+ predicateType, _ := attestation["predicateType"].(string)
+ if predicateType != policy.PredicateType {
+ eval = compliance.Eval(policy, nil)
+ } else {
+ raw, err := json.Marshal(attestation)
+ if err != nil {
+ return nil, nil, fmt.Errorf("could not marshal attestation: %w", err)
}
+ input, err := utils.ExtractAttestationPayload(string(raw))
+ if err != nil {
+ return nil, nil, fmt.Errorf("could not extract attestation payload: %w", err)
+ }
+ eval = compliance.Eval(policy, input)
}
- if len(filtered) == 0 {
- return nil, nil, fmt.Errorf("no attestations found for predicate type %s", policy.PredicateType)
- }
- }
-
- var evaluations []compliance.PolicyEvaluation
- for _, attestation := range filtered {
- raw, err := json.Marshal(attestation)
- if err != nil {
- return nil, nil, fmt.Errorf("could not marshal attestation: %w", err)
- }
-
- input, err := utils.ExtractAttestationPayload(string(raw))
- if err != nil {
- return nil, nil, fmt.Errorf("could not extract attestation payload: %w", err)
- }
-
- evaluations = append(evaluations, compliance.Eval(model, input))
- }
-
- sarif := buildSarifFromPolicy(image, *policy, evaluations)
- return &sarif, evaluations, nil
-}
-
-func buildSarifFromPolicy(image string, policy compliance.PolicyFS, evaluations []compliance.PolicyEvaluation) sarif.SarifSchema210Json {
- ruleID := policy.Filename
- ruleName := policy.Title
-
- var helpURI *string
- if len(policy.RelatedResources) > 0 {
- helpURI = &policy.RelatedResources[0]
- }
-
- rule := sarif.ReportingDescriptor{
- ID: ruleID,
- Name: &ruleName,
- ShortDescription: &sarif.MultiformatMessageString{
- Text: policy.Title,
- },
- FullDescription: &sarif.MultiformatMessageString{
- Text: policy.Description,
- },
- Help: &sarif.MultiformatMessageString{
- Text: policy.Description,
- },
- HelpURI: helpURI,
- Properties: &sarif.PropertyBag{
- Tags: policy.Tags,
- AdditionalProperties: map[string]any{
- "priority": policy.Priority,
- "relatedResources": policy.RelatedResources,
- "complianceFrameworks": policy.ComplianceFrameworks,
- "predicateType": policy.PredicateType,
- },
- },
- }
-
- location := func(message string) sarif.Location {
- uri := fmt.Sprintf("oci://%s", image)
-
- return sarif.Location{
- PhysicalLocation: sarif.PhysicalLocation{
- ArtifactLocation: sarif.ArtifactLocation{
- URI: &uri,
- },
- },
- Message: sarif.Message{
- Text: message,
- },
- }
- }
-
- var results []sarif.Result
- seen := make(map[string]bool)
- addResult := func(r sarif.Result) {
- key := string(r.Kind) + "|" + r.Message.Text
- if !seen[key] {
- seen[key] = true
- results = append(results, r)
- }
- }
- for _, evaluation := range evaluations {
- if evaluation.Compliant != nil && *evaluation.Compliant {
- addResult(sarif.Result{
- Kind: sarif.ResultKindPass,
- RuleID: &ruleID,
- Message: sarif.Message{
- Text: "Policy compliant",
- },
- Locations: []sarif.Location{
- location("The attestation is compliant with the policy."),
- },
- Properties: &sarif.PropertyBag{
- Tags: policy.Tags,
- AdditionalProperties: map[string]any{
- "precision": "high",
- },
- },
- })
- continue
- }
- for _, violation := range evaluation.Violations {
- addResult(sarif.Result{
- Kind: sarif.ResultKindFail,
- RuleID: &ruleID,
- Message: sarif.Message{
- Text: violation,
- },
- Locations: []sarif.Location{
- location(violation),
- },
- Properties: &sarif.PropertyBag{
- Tags: policy.Tags,
- AdditionalProperties: map[string]any{
- "precision": "high",
- },
- },
- })
- }
- }
- driver := sarif.ToolComponent{
- Name: "devguard-attestations",
- Rules: []sarif.ReportingDescriptor{rule},
+ evaluations = append(evaluations, eval)
}
- return sarif.SarifSchema210Json{
- Version: sarif.SarifSchema210JsonVersionA210,
- Schema: utils.Ptr("https://json.schemastore.org/sarif-2.1.0.json"),
- Runs: []sarif.Run{
- {
- Tool: sarif.Tool{
- Driver: driver,
- },
- Results: results,
- },
- },
- }
+ sarifResult := compliance.BuildSarifFromPoliciesEvaluations(srcPath, evaluations)
+ return &sarifResult, evaluations, nil
}
diff --git a/cmd/devguard-scanner/scanner/eval_policy_test.go b/cmd/devguard-scanner/scanner/eval_policy_test.go
deleted file mode 100644
index cb69e7a71..000000000
--- a/cmd/devguard-scanner/scanner/eval_policy_test.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (C) 2025 l3montree GmbH
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-package scanner
-
-import (
- "testing"
-
- "github.com/l3montree-dev/devguard/compliance"
- "github.com/l3montree-dev/devguard/dtos/sarif"
- "github.com/l3montree-dev/devguard/utils"
-)
-
-func resultKey(r sarif.Result) string {
- kind := string(r.Kind)
- return kind + "|" + r.Message.Text
-}
-
-func hasDuplicateResults(results []sarif.Result) bool {
- seen := make(map[string]bool, len(results))
- for _, r := range results {
- k := resultKey(r)
- if seen[k] {
- return true
- }
- seen[k] = true
- }
- return false
-}
-
-func TestBuildSarifFromPolicy_NoDuplicateResults(t *testing.T) {
- policy := compliance.PolicyFS{
- PolicyMetadata: compliance.PolicyMetadata{
- Filename: "test-policy.rego",
- Title: "Test Policy",
- Description: "A test policy",
- Tags: []string{"test"},
- },
- }
-
- t.Run("duplicate violations across evaluations produce no duplicates", func(t *testing.T) {
- compliant := false
- evaluations := []compliance.PolicyEvaluation{
- {Compliant: &compliant, Violations: []string{"missing signature", "untrusted source"}},
- {Compliant: &compliant, Violations: []string{"missing signature", "untrusted source"}}, // same violations again
- }
-
- result := buildSarifFromPolicy("registry.example.com/image:latest", policy, evaluations)
- results := result.Runs[0].Results
-
- if hasDuplicateResults(results) {
- t.Errorf("buildSarifFromPolicy returned duplicate result entries: %v", results)
- }
- })
-
- t.Run("same violation repeated within one evaluation produces no duplicates", func(t *testing.T) {
- compliant := false
- evaluations := []compliance.PolicyEvaluation{
- {Compliant: &compliant, Violations: []string{"missing signature", "missing signature"}},
- }
-
- result := buildSarifFromPolicy("registry.example.com/image:latest", policy, evaluations)
- results := result.Runs[0].Results
-
- if hasDuplicateResults(results) {
- t.Errorf("buildSarifFromPolicy returned duplicate result entries: %v", results)
- }
- })
-
- t.Run("multiple compliant evaluations produce no duplicate pass results", func(t *testing.T) {
- compliant := true
- evaluations := []compliance.PolicyEvaluation{
- {Compliant: &compliant, Violations: nil},
- {Compliant: &compliant, Violations: nil},
- {Compliant: &compliant, Violations: nil},
- }
-
- result := buildSarifFromPolicy("registry.example.com/image:latest", policy, evaluations)
- results := result.Runs[0].Results
-
- if hasDuplicateResults(results) {
- t.Errorf("buildSarifFromPolicy returned duplicate pass result entries: %v", results)
- }
- })
-
- t.Run("mix of compliant and non-compliant evaluations with overlapping violations", func(t *testing.T) {
- compliant := true
- notCompliant := false
- evaluations := []compliance.PolicyEvaluation{
- {Compliant: &compliant, Violations: nil},
- {Compliant: ¬Compliant, Violations: []string{"missing signature"}},
- {Compliant: ¬Compliant, Violations: []string{"missing signature"}},
- {Compliant: &compliant, Violations: nil},
- }
-
- result := buildSarifFromPolicy("registry.example.com/image:latest", policy, evaluations)
- results := result.Runs[0].Results
-
- if hasDuplicateResults(results) {
- t.Errorf("buildSarifFromPolicy returned duplicate result entries: %v", results)
- }
- })
-
- t.Run("single evaluation with no violations produces no results", func(t *testing.T) {
- evaluations := []compliance.PolicyEvaluation{
- {Compliant: utils.Ptr(true), Violations: nil},
- }
-
- result := buildSarifFromPolicy("registry.example.com/image:latest", policy, evaluations)
- results := result.Runs[0].Results
-
- if hasDuplicateResults(results) {
- t.Errorf("buildSarifFromPolicy returned duplicate result entries: %v", results)
- }
- })
-}
diff --git a/cmd/devguard/main.go b/cmd/devguard/main.go
index eca079150..1b1029304 100644
--- a/cmd/devguard/main.go
+++ b/cmd/devguard/main.go
@@ -136,6 +136,7 @@ func main() {
fx.Invoke(func(DependencyVulnRouter router.DependencyVulnRouter) {}),
fx.Invoke(func(FirstPartyVulnRouter router.FirstPartyVulnRouter) {}),
fx.Invoke(func(LicenseRiskRouter router.LicenseRiskRouter) {}),
+ fx.Invoke(func(ComplianceRiskRouter router.ComplianceRiskRouter) {}),
fx.Invoke(func(ShareRouter router.ShareRouter) {}),
fx.Invoke(func(VulnDBRouter router.VulnDBRouter) {}),
fx.Invoke(func(dependencyProxyRouter router.DependencyProxyRouter) {}),
diff --git a/compliance/attestation-compliance-policies/policies/author_committer_email_is_from_org.rego b/compliance/attestation-compliance-policies/policies/author_committer_email_is_from_org.rego
index a1fc322cb..151635102 100644
--- a/compliance/attestation-compliance-policies/policies/author_committer_email_is_from_org.rego
+++ b/compliance/attestation-compliance-policies/policies/author_committer_email_is_from_org.rego
@@ -7,7 +7,7 @@
# relatedResources: []
# tags:
# - Legal
-# complianceFrameworks: []
+# policyFrameworks: []
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/branch_protection_enabled.rego b/compliance/attestation-compliance-policies/policies/branch_protection_enabled.rego
index af9a60628..12ad9bc9e 100644
--- a/compliance/attestation-compliance-policies/policies/branch_protection_enabled.rego
+++ b/compliance/attestation-compliance-policies/policies/branch_protection_enabled.rego
@@ -9,8 +9,10 @@
# tags:
# - ISO 27001
# - A.8.4 Access to source code
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.8.4
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/build_from_signed_source.rego b/compliance/attestation-compliance-policies/policies/build_from_signed_source.rego
index 7a452e727..29e4ff154 100644
--- a/compliance/attestation-compliance-policies/policies/build_from_signed_source.rego
+++ b/compliance/attestation-compliance-policies/policies/build_from_signed_source.rego
@@ -8,8 +8,10 @@
# tags:
# - ISO 27001
# - A.8 Access Control
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.8
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/ci_image_has_digest_set.rego b/compliance/attestation-compliance-policies/policies/ci_image_has_digest_set.rego
index 8ef158627..6d053bf30 100644
--- a/compliance/attestation-compliance-policies/policies/ci_image_has_digest_set.rego
+++ b/compliance/attestation-compliance-policies/policies/ci_image_has_digest_set.rego
@@ -8,7 +8,7 @@
# tags:
# - GitLab CI
# - Legal
-# complianceFrameworks: []
+# policyFrameworks: []
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/cia_requirements_set_for_asset.rego b/compliance/attestation-compliance-policies/policies/cia_requirements_set_for_asset.rego
index e8701f162..f660ecc65 100644
--- a/compliance/attestation-compliance-policies/policies/cia_requirements_set_for_asset.rego
+++ b/compliance/attestation-compliance-policies/policies/cia_requirements_set_for_asset.rego
@@ -9,8 +9,10 @@
# tags:
# - ISO 27001
# - A.5.12 Classification of Information
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.5.12
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/code_review_for_changes_on_default_branch.rego b/compliance/attestation-compliance-policies/policies/code_review_for_changes_on_default_branch.rego
index 409b034a7..1ba15c1bc 100644
--- a/compliance/attestation-compliance-policies/policies/code_review_for_changes_on_default_branch.rego
+++ b/compliance/attestation-compliance-policies/policies/code_review_for_changes_on_default_branch.rego
@@ -9,8 +9,10 @@
# tags:
# - ISO 27001
# - A.8.4 Access to source code
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.8.4
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/container_scanning_executed.rego b/compliance/attestation-compliance-policies/policies/container_scanning_executed.rego
index 29cad1ee0..aa2e644e2 100644
--- a/compliance/attestation-compliance-policies/policies/container_scanning_executed.rego
+++ b/compliance/attestation-compliance-policies/policies/container_scanning_executed.rego
@@ -9,8 +9,10 @@
# tags:
# - ISO 27001
# - A.5.7 Threat intelligence
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.5.7
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/current_sbom_is_present.rego b/compliance/attestation-compliance-policies/policies/current_sbom_is_present.rego
index a5a5d8aff..9dc027d23 100644
--- a/compliance/attestation-compliance-policies/policies/current_sbom_is_present.rego
+++ b/compliance/attestation-compliance-policies/policies/current_sbom_is_present.rego
@@ -10,8 +10,12 @@
# - A.5.7 Threat intelligence
# - A.5.9 Inventory of information and other associated assets
# - A.8.8 Management of technical vulnerabilities
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.5.7
+# - A.5.9
+# - A.8.8
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/notification_channel_for_new_vulnerabilities.rego b/compliance/attestation-compliance-policies/policies/notification_channel_for_new_vulnerabilities.rego
index 53852a086..935a6310a 100644
--- a/compliance/attestation-compliance-policies/policies/notification_channel_for_new_vulnerabilities.rego
+++ b/compliance/attestation-compliance-policies/policies/notification_channel_for_new_vulnerabilities.rego
@@ -9,8 +9,10 @@
# tags:
# - ISO 27001
# - A.8.8 Management of technical vulnerabilities
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.8.8
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/only_osi_approved_licenses.rego b/compliance/attestation-compliance-policies/policies/only_osi_approved_licenses.rego
index 3a4beb60c..9cc3884ce 100644
--- a/compliance/attestation-compliance-policies/policies/only_osi_approved_licenses.rego
+++ b/compliance/attestation-compliance-policies/policies/only_osi_approved_licenses.rego
@@ -9,8 +9,10 @@
# tags:
# - ISO 27001
# - A.5.32 Intellectual property rights
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.5.32
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/secret_scanning_executed.rego b/compliance/attestation-compliance-policies/policies/secret_scanning_executed.rego
index 8f1b51f08..1743cbe2e 100644
--- a/compliance/attestation-compliance-policies/policies/secret_scanning_executed.rego
+++ b/compliance/attestation-compliance-policies/policies/secret_scanning_executed.rego
@@ -9,8 +9,11 @@
# tags:
# - ISO 27001
# - A.5.7 Threat intelligence
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.5.7
+
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/security_policy_present_in_repo.rego b/compliance/attestation-compliance-policies/policies/security_policy_present_in_repo.rego
index 9febffac9..caa2965d2 100644
--- a/compliance/attestation-compliance-policies/policies/security_policy_present_in_repo.rego
+++ b/compliance/attestation-compliance-policies/policies/security_policy_present_in_repo.rego
@@ -8,9 +8,9 @@
# - https://github.com/ossf/scorecard/blob/main/docs/checks.md#security-policy
# tags:
# - Best Practices
-# complianceFrameworks:
-# - Best Practices
-# - OpenSSF Scorecard
+# policyFrameworks:
+# - framework: Best Practices
+# - framework: OpenSSF Scorecard
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/signed_off_commit.rego b/compliance/attestation-compliance-policies/policies/signed_off_commit.rego
index 18ca7587a..137562c94 100644
--- a/compliance/attestation-compliance-policies/policies/signed_off_commit.rego
+++ b/compliance/attestation-compliance-policies/policies/signed_off_commit.rego
@@ -7,7 +7,7 @@
# relatedResources: []
# tags:
# - Legal
-# complianceFrameworks: []
+# policyFrameworks: []
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/software_composition_analysis_executed.rego b/compliance/attestation-compliance-policies/policies/software_composition_analysis_executed.rego
index f1e917653..edbe1fed3 100644
--- a/compliance/attestation-compliance-policies/policies/software_composition_analysis_executed.rego
+++ b/compliance/attestation-compliance-policies/policies/software_composition_analysis_executed.rego
@@ -9,8 +9,10 @@
# tags:
# - ISO 27001
# - A.5.7 Threat intelligence
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.5.7
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/uses_sbom.rego b/compliance/attestation-compliance-policies/policies/uses_sbom.rego
index 24257b161..b9c697213 100644
--- a/compliance/attestation-compliance-policies/policies/uses_sbom.rego
+++ b/compliance/attestation-compliance-policies/policies/uses_sbom.rego
@@ -10,8 +10,12 @@
# - A.5.7 Threat intelligence
# - A.5.9 Inventory of information and other associated assets
# - A.8.8 Management of technical vulnerabilities
-# complianceFrameworks:
-# - ISO 27001
+# policyFrameworks:
+# - framework: ISO 27001
+# controls:
+# - A.5.7
+# - A.5.9
+# - A.8.8
package compliance
import rego.v1
diff --git a/compliance/attestation-compliance-policies/policies/vulnerability_fix_time_sla.rego b/compliance/attestation-compliance-policies/policies/vulnerability_fix_time_sla.rego
new file mode 100644
index 000000000..6523b3d47
--- /dev/null
+++ b/compliance/attestation-compliance-policies/policies/vulnerability_fix_time_sla.rego
@@ -0,0 +1,78 @@
+# METADATA
+# title: Vulnerability fix time SLA
+# custom:
+# description: Ensures that the average time to remediate vulnerabilities meets defined SLA thresholds — critical < 1 day, high < 3 days, medium < 14 days, low < 30 days.
+# priority: 1
+# predicateType: https://devguard.org/attestation/asset-metrics/v1
+# relatedResources: []
+# tags:
+# - Security
+# policyFrameworks:
+# - framework: L3montree Compliance
+# controls:
+# - Vulnerability Management
+
+package compliance
+
+import rego.v1
+
+default compliant := false
+
+# SLA thresholds in hours
+critical_max_hours := 24
+high_max_hours := 72
+medium_max_hours := 336
+low_max_hours := 720
+
+violations contains msg if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ input.meanTimeToRemediate.riskCriticalAvgHours == 0
+ msg := "Mean time to remediate for critical vulnerabilities is 0 — no data available"
+}
+
+violations contains msg if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ input.meanTimeToRemediate.riskHighAvgHours == 0
+ msg := "Mean time to remediate for high vulnerabilities is 0 — no data available"
+}
+
+violations contains msg if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ input.meanTimeToRemediate.riskMediumAvgHours == 0
+ msg := "Mean time to remediate for medium vulnerabilities is 0 — no data available"
+}
+
+violations contains msg if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ input.meanTimeToRemediate.riskLowAvgHours == 0
+ msg := "Mean time to remediate for low vulnerabilities is 0 — no data available"
+}
+
+violations contains msg if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ input.meanTimeToRemediate.riskCriticalAvgHours >= critical_max_hours
+ msg := sprintf("Mean time to remediate critical vulnerabilities (%d h) exceeds SLA of %d h", [input.meanTimeToRemediate.riskCriticalAvgHours, critical_max_hours])
+}
+
+violations contains msg if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ input.meanTimeToRemediate.riskHighAvgHours >= high_max_hours
+ msg := sprintf("Mean time to remediate high vulnerabilities (%d h) exceeds SLA of %d h", [input.meanTimeToRemediate.riskHighAvgHours, high_max_hours])
+}
+
+violations contains msg if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ input.meanTimeToRemediate.riskMediumAvgHours >= medium_max_hours
+ msg := sprintf("Mean time to remediate medium vulnerabilities (%d h) exceeds SLA of %d h", [input.meanTimeToRemediate.riskMediumAvgHours, medium_max_hours])
+}
+
+violations contains msg if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ input.meanTimeToRemediate.riskLowAvgHours >= low_max_hours
+ msg := sprintf("Mean time to remediate low vulnerabilities (%d h) exceeds SLA of %d h", [input.meanTimeToRemediate.riskLowAvgHours, low_max_hours])
+}
+
+compliant if {
+ input.type == "https://devguard.org/attestation/asset-metrics/v1"
+ count(violations) == 0
+}
diff --git a/compliance/rego.go b/compliance/rego.go
index cb54544c1..9cbd81a9b 100644
--- a/compliance/rego.go
+++ b/compliance/rego.go
@@ -10,6 +10,7 @@ import (
"strings"
"github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/dtos/sarif"
"github.com/l3montree-dev/devguard/utils"
"github.com/open-policy-agent/opa/v1/rego"
"gopkg.in/yaml.v2"
@@ -21,36 +22,45 @@ type yamlPolicy struct {
}
type customYaml struct {
- Description string `yaml:"description"`
- Priority int `yaml:"priority"`
- Tags []string
+ Description string `yaml:"description"`
+ Priority int `yaml:"priority"`
+ Tags []string `yaml:"tags"`
// used for mapping from policies to attestations
- PredicateType string `yaml:"predicateType"`
- RelatedResources []string `yaml:"relatedResources"`
- ComplianceFrameworks []string `yaml:"complianceFrameworks"`
+ PredicateType string `yaml:"predicateType"`
+ RelatedResources []string `yaml:"relatedResources"`
+ PolicyFrameworks []models.PolicyFrameworks `yaml:"policyFrameworks"`
}
type PolicyMetadata struct {
- Title string `yaml:"title" json:"title"`
- Description string `yaml:"description" json:"description"`
- Priority int `yaml:"priority" json:"priority"`
- Tags []string `yaml:"tags" json:"tags"`
- RelatedResources []string `yaml:"relatedResources" json:"relatedResources"`
- ComplianceFrameworks []string `yaml:"complianceFrameworks" json:"complianceFrameworks"`
- Filename string `json:"filename"`
- Content string `json:"content"`
- PredicateType string `yaml:"predicateType" json:"predicateType"`
+ Title string `yaml:"title" json:"title"`
+ Description string `yaml:"description" json:"description"`
+ Priority int `yaml:"priority" json:"priority"`
+ Tags []string `yaml:"tags" json:"tags"`
+ RelatedResources []string `yaml:"relatedResources" json:"relatedResources"`
+ PolicyFrameworks []models.PolicyFrameworks `yaml:"policyFrameworks" json:"policyFrameworks"`
+ ComplianceFrameworks []string `yaml:"complianceFrameworks" json:"complianceFrameworks"`
+ Filename string `json:"filename"`
+ Content string `json:"content"`
+ PredicateType string `yaml:"predicateType" json:"predicateType"`
}
-type PolicyFS struct {
+type Policy struct {
PolicyMetadata
Content string
}
type PolicyEvaluation struct {
- models.Policy
- Compliant *bool `json:"compliant"`
- Violations []string `json:"violations"`
- RawEvaluationResult map[string]any `json:"rawEvaluationResult"`
+ PolicyID string
+ PolicyTitle string
+ PolicyDescription string
+ PolicyRelatedResources []string
+ PolicyTags []string
+ PolicyPriority int
+ PolicyFrameworks []models.PolicyFrameworks
+ Compliant *bool
+ Violations []string
+ RawEvaluationResult map[string]any
+ EvidenceType string
+ EvidenceContent *string
}
var packageRegexp = regexp.MustCompile(`(?m)^package compliance`)
@@ -94,78 +104,54 @@ func parseMetadata(fileName string, content string) (PolicyMetadata, error) {
}
return PolicyMetadata{
- Title: metadata.Title,
- Description: metadata.Custom.Description,
- Priority: metadata.Custom.Priority,
- Tags: metadata.Custom.Tags,
- RelatedResources: metadata.Custom.RelatedResources,
- ComplianceFrameworks: metadata.Custom.ComplianceFrameworks,
- Filename: fileName,
- PredicateType: metadata.Custom.PredicateType,
- Content: content,
+ Title: metadata.Title,
+ Description: metadata.Custom.Description,
+ Priority: metadata.Custom.Priority,
+ Tags: metadata.Custom.Tags,
+ RelatedResources: metadata.Custom.RelatedResources,
+ PolicyFrameworks: metadata.Custom.PolicyFrameworks,
+ Filename: fileName,
+ PredicateType: metadata.Custom.PredicateType,
}, nil
}
-func ConvertPolicyFsToModel(policy PolicyFS) models.Policy {
- return models.Policy{
- Rego: policy.Content,
- Description: policy.Description,
- Title: policy.Title,
- PredicateType: policy.PredicateType,
- OpaqueID: &policy.Filename,
- OrganizationID: nil,
+func Eval(policy Policy, input any) PolicyEvaluation {
+ result := PolicyEvaluation{
+ PolicyID: policy.Filename,
+ PolicyTitle: policy.Title,
+ PolicyDescription: policy.Description,
+ PolicyRelatedResources: policy.RelatedResources,
+ PolicyTags: policy.Tags,
+ PolicyPriority: policy.Priority,
+ PolicyFrameworks: policy.PolicyFrameworks,
+ EvidenceType: "json",
+ EvidenceContent: &policy.Content,
}
-}
-
-func NewPolicy(filename string, content string) (*PolicyFS, error) {
- metadata, err := parseMetadata(filename, content)
- if err != nil {
- return nil, err
- }
-
- return &PolicyFS{
- PolicyMetadata: metadata,
- Content: content,
- }, nil
-}
-
-func Eval(p models.Policy, input any) PolicyEvaluation {
-
if input == nil {
- return PolicyEvaluation{
- Policy: p,
- Compliant: nil,
- }
+ return result
}
r := rego.New(
rego.Query("data.compliance"),
- rego.Module("", p.Rego),
+ rego.Module(policy.Filename, policy.Content),
)
ctx := context.TODO()
query, err := r.PrepareForEval(ctx)
if err != nil {
- return PolicyEvaluation{
- Policy: p,
- Compliant: nil,
- }
+ return result
}
- rs, err := query.Eval(context.TODO(), rego.EvalInput(input))
+ rs, err := query.Eval(ctx, rego.EvalInput(input))
if err != nil {
- return PolicyEvaluation{
- Policy: p,
- Compliant: nil,
- }
+ return result
}
- var violations = []string{}
+ var violations []string
var rawEvalResult map[string]any
var compliant *bool
if len(rs) > 0 {
value := rs[0].Expressions[0].Value
- // cast value to map
if v, ok := value.(map[string]any); ok {
rawEvalResult = v
if v["compliant"] != nil {
@@ -181,12 +167,11 @@ func Eval(p models.Policy, input any) PolicyEvaluation {
}
}
- return PolicyEvaluation{
- Policy: p,
- Compliant: compliant,
- Violations: violations,
- RawEvaluationResult: rawEvalResult,
- }
+ result.Compliant = compliant
+ result.Violations = violations
+ result.RawEvaluationResult = rawEvalResult
+
+ return result
}
// embed the policies in the binary
@@ -194,26 +179,31 @@ func Eval(p models.Policy, input any) PolicyEvaluation {
//go:embed attestation-compliance-policies/policies/*.rego
var policiesFs embed.FS
-func GetCommunityManagedPoliciesFromFS() []PolicyFS {
+func GetPoliciesFromFS(policyDir string) ([]Policy, error) {
// fetch all policies
- policyFiles, err := policiesFs.ReadDir("attestation-compliance-policies/policies")
+ policyFiles, err := policiesFs.ReadDir(policyDir)
if err != nil {
- return nil
+ return nil, err
}
- var policies []PolicyFS
+ var policies []Policy
for _, file := range policyFiles {
- content, err := policiesFs.ReadFile(filepath.Join("attestation-compliance-policies/policies", file.Name()))
+ content, err := policiesFs.ReadFile(filepath.Join(policyDir, file.Name()))
if err != nil {
continue
}
- policy, err := NewPolicy(file.Name(), string(content))
+ metadata, err := parseMetadata(file.Name(), string(content))
if err != nil {
- continue
+ return nil, err
+ }
+
+ policy := Policy{
+ PolicyMetadata: metadata,
+ Content: string(content),
}
- policies = append(policies, *policy)
+ policies = append(policies, policy)
}
// sort the policies by priority - use a stable sort
@@ -221,5 +211,126 @@ func GetCommunityManagedPoliciesFromFS() []PolicyFS {
return policies[i].Priority < policies[j].Priority
})
- return policies
+ return policies, nil
+}
+
+func GetPolicyFromFile(fileName, content string) (Policy, error) {
+ metadata, err := parseMetadata(fileName, content)
+ if err != nil {
+ return Policy{}, err
+ }
+ return Policy{PolicyMetadata: metadata, Content: content}, nil
+}
+
+func BuildSarifFromPoliciesEvaluations(srcPath string, evaluations []PolicyEvaluation) sarif.SarifSchema210Json {
+ rules := make([]sarif.ReportingDescriptor, 0)
+ results := make([]sarif.Result, 0, len(evaluations))
+ seenRules := make(map[string]bool)
+ addRule := func(r sarif.ReportingDescriptor) {
+ if !seenRules[r.ID] {
+ seenRules[r.ID] = true
+ rules = append(rules, r)
+ }
+ }
+
+ seenResults := make(map[string]bool)
+ addResult := func(r sarif.Result) {
+ if !seenResults[*r.RuleID] {
+ seenResults[*r.RuleID] = true
+ results = append(results, r)
+ }
+ }
+
+ for _, evaluation := range evaluations {
+ ruleID := evaluation.PolicyID
+ ruleName := evaluation.PolicyTitle
+
+ var helpURI *string
+ if len(evaluation.PolicyRelatedResources) > 0 {
+ helpURI = &evaluation.PolicyRelatedResources[0]
+ }
+
+ rule := sarif.ReportingDescriptor{
+ ID: ruleID,
+ Name: &ruleName,
+ ShortDescription: &sarif.MultiformatMessageString{
+ Text: evaluation.PolicyTitle,
+ },
+ FullDescription: &sarif.MultiformatMessageString{
+ Text: evaluation.PolicyDescription,
+ },
+ Help: &sarif.MultiformatMessageString{
+ Text: evaluation.PolicyDescription,
+ },
+ HelpURI: helpURI,
+ Properties: &sarif.PropertyBag{
+ Tags: evaluation.PolicyTags,
+ AdditionalProperties: map[string]any{
+ "priority": evaluation.PolicyPriority,
+ "relatedResources": evaluation.PolicyRelatedResources,
+ "policyFrameworks": evaluation.PolicyFrameworks,
+ },
+ },
+ }
+
+ addRule(rule)
+
+ artifactLocation := sarif.ArtifactLocation{URI: &srcPath}
+ additionalProps := map[string]any{
+ "precision": "high",
+ "evidenceType": evaluation.EvidenceType,
+ "violations": evaluation.Violations,
+ }
+ if evaluation.EvidenceContent != nil {
+ additionalProps["evidenceContent"] = *evaluation.EvidenceContent
+ }
+
+ props := &sarif.PropertyBag{
+ Tags: evaluation.PolicyTags,
+ AdditionalProperties: additionalProps,
+ }
+ var kind sarif.ResultKind
+ var message sarif.Message
+ var result sarif.Result
+ if evaluation.Compliant != nil && *evaluation.Compliant {
+ kind = sarif.ResultKindPass
+ message = sarif.Message{Text: "Policy compliant"}
+ } else if evaluation.Compliant != nil && !*evaluation.Compliant {
+ kind = sarif.ResultKindFail
+ message = sarif.Message{Text: "Policy not compliant"}
+ } else {
+ kind = sarif.ResultKindOpen
+ message = sarif.Message{Text: "No attestation found for policy — compliance could not be determined."}
+ }
+
+ result = sarif.Result{
+ Kind: kind,
+ RuleID: &ruleID,
+ Message: message,
+ Locations: []sarif.Location{
+ {PhysicalLocation: sarif.PhysicalLocation{ArtifactLocation: artifactLocation}},
+ },
+ Properties: props,
+ }
+
+ addResult(result)
+ }
+
+ driver := sarif.ToolComponent{
+ Name: "devguard-attestations",
+ Rules: rules,
+ }
+
+ return sarif.SarifSchema210Json{
+ Version: sarif.SarifSchema210JsonVersionA210,
+ Schema: utils.Ptr("https://json.schemastore.org/sarif-2.1.0.json"),
+ Runs: []sarif.Run{
+ {
+ Tool: sarif.Tool{
+ Driver: driver,
+ },
+ Results: results,
+ },
+ },
+ }
}
diff --git a/compliance/rego_test.go b/compliance/rego_test.go
index f4e9b275d..a8ddd4258 100644
--- a/compliance/rego_test.go
+++ b/compliance/rego_test.go
@@ -5,6 +5,7 @@ import (
"os"
"testing"
+ "github.com/l3montree-dev/devguard/dtos/sarif"
"github.com/l3montree-dev/devguard/utils"
"github.com/stretchr/testify/assert"
)
@@ -28,41 +29,19 @@ func TestEval(t *testing.T) {
t.Fatal(err)
}
- // create a new policy
- policy, err := NewPolicy("", string(policyContent))
+ metadata, err := parseMetadata("", string(policyContent))
if err != nil {
t.Fatal(err)
}
-
- model := ConvertPolicyFsToModel(*policy)
+ policy := Policy{PolicyMetadata: metadata, Content: string(policyContent)}
// evaluate the policy
- res := Eval(model, input)
+ res := Eval(policy, input)
if res.Compliant == nil || *res.Compliant != true {
t.Fatal(res)
}
}
-func TestNewPolicy(t *testing.T) {
- t.Run("should parse the metadata", func(t *testing.T) {
- // read the example-policy.rego file
- policyContent, err := os.ReadFile("testfiles/example-policy.rego")
- if err != nil {
- t.Fatal(err)
- }
-
- // create a new policy
- policy, err := NewPolicy("", string(policyContent))
- if err != nil {
- t.Fatal(err)
- }
-
- assert.Equal(t, "Build from signed source", policy.Title)
- assert.Equal(t, "This policy checks if the build was done from a signed commit.", policy.Description)
- assert.Equal(t, []string{"iso27001", "A.8 Access Control"}, policy.Tags)
- })
-}
-
func TestOnlyOsiApprovedLicensesPolicy(t *testing.T) {
sbomContent, err := os.ReadFile("./testfiles/sbom.json")
if err != nil {
@@ -74,10 +53,11 @@ func TestOnlyOsiApprovedLicensesPolicy(t *testing.T) {
t.Fatal(err)
}
- policy, err := NewPolicy("", string(policyContent))
+ metadata, err := parseMetadata("", string(policyContent))
if err != nil {
t.Fatal(err)
}
+ policy := Policy{PolicyMetadata: metadata, Content: string(policyContent)}
// parse the sbom
var input any
@@ -86,11 +66,9 @@ func TestOnlyOsiApprovedLicensesPolicy(t *testing.T) {
t.Fatal(err)
}
- model := ConvertPolicyFsToModel(*policy)
- result := Eval(model, input)
+ result := Eval(policy, input)
expectedResult := &PolicyEvaluation{
- Policy: model,
Compliant: utils.Ptr(false),
Violations: []string{
"Component \"github.com/cloudflare/circl\" uses non-OSI approved license \"non-standard\"",
@@ -129,3 +107,101 @@ func TestOnlyOsiApprovedLicensesPolicy(t *testing.T) {
assert.Subset(t, expectedResult.Violations, result.Violations)
assert.Subset(t, result.Violations, expectedResult.Violations)
}
+
+func resultKey(r sarif.Result) string {
+ return string(r.Kind) + "|" + r.Message.Text
+}
+
+func hasDuplicateResults(results []sarif.Result) bool {
+ seen := make(map[string]bool, len(results))
+ for _, r := range results {
+ k := resultKey(r)
+ if seen[k] {
+ return true
+ }
+ seen[k] = true
+ }
+ return false
+}
+
+func makeEvaluations(policy Policy, evals []PolicyEvaluation) []PolicyEvaluation {
+ for i := range evals {
+ evals[i].PolicyID = policy.Filename
+ evals[i].PolicyTitle = policy.Title
+ evals[i].PolicyDescription = policy.Description
+ evals[i].PolicyTags = policy.Tags
+ }
+ return evals
+}
+
+func TestBuildSarifFromPoliciesEvaluations_NoDuplicateResults(t *testing.T) {
+ policy := Policy{
+ PolicyMetadata: PolicyMetadata{
+ Filename: "test-policy.rego",
+ Title: "Test Policy",
+ Description: "A test policy",
+ Tags: []string{"test"},
+ },
+ }
+
+ t.Run("duplicate violations across evaluations produce no duplicates", func(t *testing.T) {
+ compliant := false
+ evaluations := makeEvaluations(policy, []PolicyEvaluation{
+ {Compliant: &compliant, Violations: []string{"missing signature", "untrusted source"}},
+ {Compliant: &compliant, Violations: []string{"missing signature", "untrusted source"}},
+ })
+ results := BuildSarifFromPoliciesEvaluations("registry.example.com/image:latest", evaluations).Runs[0].Results
+ if hasDuplicateResults(results) {
+ t.Errorf("BuildSarifFromPoliciesEvaluations returned duplicate result entries: %v", results)
+ }
+ })
+
+ t.Run("same violation repeated within one evaluation produces no duplicates", func(t *testing.T) {
+ compliant := false
+ evaluations := makeEvaluations(policy, []PolicyEvaluation{
+ {Compliant: &compliant, Violations: []string{"missing signature", "missing signature"}},
+ })
+ results := BuildSarifFromPoliciesEvaluations("registry.example.com/image:latest", evaluations).Runs[0].Results
+ if hasDuplicateResults(results) {
+ t.Errorf("BuildSarifFromPoliciesEvaluations returned duplicate result entries: %v", results)
+ }
+ })
+
+ t.Run("multiple compliant evaluations produce no duplicate pass results", func(t *testing.T) {
+ compliant := true
+ evaluations := makeEvaluations(policy, []PolicyEvaluation{
+ {Compliant: &compliant},
+ {Compliant: &compliant},
+ {Compliant: &compliant},
+ })
+ results := BuildSarifFromPoliciesEvaluations("registry.example.com/image:latest", evaluations).Runs[0].Results
+ if hasDuplicateResults(results) {
+ t.Errorf("BuildSarifFromPoliciesEvaluations returned duplicate pass result entries: %v", results)
+ }
+ })
+
+ t.Run("mix of compliant and non-compliant evaluations with overlapping violations", func(t *testing.T) {
+ compliant := true
+ notCompliant := false
+ evaluations := makeEvaluations(policy, []PolicyEvaluation{
+ {Compliant: &compliant},
+ {Compliant: ¬Compliant, Violations: []string{"missing signature"}},
+ {Compliant: ¬Compliant, Violations: []string{"missing signature"}},
+ {Compliant: &compliant},
+ })
+ results := BuildSarifFromPoliciesEvaluations("registry.example.com/image:latest", evaluations).Runs[0].Results
+ if hasDuplicateResults(results) {
+ t.Errorf("BuildSarifFromPoliciesEvaluations returned duplicate result entries: %v", results)
+ }
+ })
+
+ t.Run("single evaluation with no violations produces no results", func(t *testing.T) {
+ evaluations := makeEvaluations(policy, []PolicyEvaluation{
+ {Compliant: utils.Ptr(true)},
+ })
+ results := BuildSarifFromPoliciesEvaluations("registry.example.com/image:latest", evaluations).Runs[0].Results
+ if hasDuplicateResults(results) {
+ t.Errorf("BuildSarifFromPoliciesEvaluations returned duplicate result entries: %v", results)
+ }
+ })
+}
diff --git a/controllers/attestation_controller.go b/controllers/attestation_controller.go
index da07feba6..6c83e6bc8 100644
--- a/controllers/attestation_controller.go
+++ b/controllers/attestation_controller.go
@@ -12,14 +12,14 @@ import (
)
type AttestationController struct {
- attestationRepository shared.AttestationRepository
- artifactRepository shared.ArtifactRepository
+ attestationService shared.AttestationService
+ artifactRepository shared.ArtifactRepository
}
-func NewAttestationController(repository shared.AttestationRepository, artifactRepository shared.ArtifactRepository) *AttestationController {
+func NewAttestationController(attestationService shared.AttestationService, artifactRepository shared.ArtifactRepository) *AttestationController {
return &AttestationController{
- attestationRepository: repository,
- artifactRepository: artifactRepository,
+ attestationService: attestationService,
+ artifactRepository: artifactRepository,
}
}
@@ -38,7 +38,22 @@ func (a *AttestationController) List(ctx shared.Context) error {
asset := shared.GetAsset(ctx)
assetVersion := shared.GetAssetVersion(ctx)
- attestationList, err := a.attestationRepository.GetByAssetVersionAndAssetID(ctx.Request().Context(), nil, asset.GetID(), assetVersion.Name)
+ attestationList, err := a.attestationService.GetByAssetVersionAndAssetID(ctx.Request().Context(), nil, asset.GetID(), assetVersion.Name)
+ if err != nil {
+ return err
+ }
+
+ return ctx.JSON(200, attestationList)
+}
+
+func (a *AttestationController) ListByArtifact(ctx shared.Context) error {
+
+ asset := shared.GetAsset(ctx)
+ assetVersion := shared.GetAssetVersion(ctx)
+
+ artifact := shared.GetArtifact(ctx)
+
+ attestationList, err := a.attestationService.GetByArtifactAndAssetVersionAndAssetID(ctx.Request().Context(), nil, artifact.ArtifactName, assetVersion.Name, asset.GetID())
if err != nil {
return err
}
@@ -100,7 +115,7 @@ func (a *AttestationController) Create(ctx shared.Context) error {
return echo.NewHTTPError(400, fmt.Sprintf("could not validate request: %s", err.Error()))
}
attestation.Content = jsonContent
- err = a.attestationRepository.Create(ctx.Request().Context(), nil, &attestation)
+ err = a.attestationService.Create(ctx.Request().Context(), nil, &attestation)
if err != nil {
return err
}
diff --git a/controllers/attestation_test.go b/controllers/attestation_test.go
index 3ffeae3ee..625eba5dc 100644
--- a/controllers/attestation_test.go
+++ b/controllers/attestation_test.go
@@ -26,12 +26,12 @@ func TestList(t *testing.T) {
shared.SetAsset(ctx, asset)
shared.SetAssetVersion(ctx, assetVersion)
- attestationRepository := mocks.NewAttestationRepository(t)
- attestationRepository.On("GetByAssetVersionAndAssetID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]models.Attestation{
+ attestationService := mocks.NewAttestationService(t)
+ attestationService.On("GetByAssetVersionAndAssetID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]models.Attestation{
{PredicateType: "not ocol name"},
}, nil)
- attestationController := NewAttestationController(attestationRepository, mocks.NewArtifactRepository(t))
+ attestationController := NewAttestationController(attestationService, mocks.NewArtifactRepository(t))
result := attestationController.List(ctx)
if result != nil {
t.Fail()
@@ -49,9 +49,9 @@ func TestList(t *testing.T) {
shared.SetAsset(ctx, asset)
shared.SetAssetVersion(ctx, assetVersion)
- attestationRepository := mocks.NewAttestationRepository(t)
- attestationRepository.On("GetByAssetVersionAndAssetID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]models.Attestation{}, fmt.Errorf("Something went wrong"))
- attestationController := NewAttestationController(attestationRepository, mocks.NewArtifactRepository(t))
+ attestationService := mocks.NewAttestationService(t)
+ attestationService.On("GetByAssetVersionAndAssetID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]models.Attestation{}, fmt.Errorf("Something went wrong"))
+ attestationController := NewAttestationController(attestationService, mocks.NewArtifactRepository(t))
result := attestationController.List(ctx)
diff --git a/controllers/compliance_controller.go b/controllers/compliance_controller.go
deleted file mode 100644
index a4abaabaa..000000000
--- a/controllers/compliance_controller.go
+++ /dev/null
@@ -1,132 +0,0 @@
-package controllers
-
-import (
- "context"
- _ "embed"
-
- "github.com/google/uuid"
- "github.com/l3montree-dev/devguard/compliance"
- "github.com/l3montree-dev/devguard/database/models"
- "github.com/l3montree-dev/devguard/shared"
-)
-
-type ComplianceController struct {
- assetVersionRepository shared.AssetVersionRepository
- attestationRepository shared.AttestationRepository
- policyRepository shared.PolicyRepository
-}
-
-func NewComplianceController(assetVersionRepository shared.AssetVersionRepository, attestationRepository shared.AttestationRepository, policyRepository shared.PolicyRepository) *ComplianceController {
- return &ComplianceController{
- assetVersionRepository: assetVersionRepository,
- policyRepository: policyRepository,
- attestationRepository: attestationRepository,
- }
-}
-
-func (c *ComplianceController) getAssetVersionCompliance(ctx context.Context, projectID uuid.UUID, assetVersion models.AssetVersion) ([]compliance.PolicyEvaluation, error) {
- // get the attestation
- attestations, err := c.attestationRepository.GetByAssetVersionAndAssetID(ctx, nil, assetVersion.AssetID, assetVersion.Name)
- if err != nil {
- return nil, err
- }
-
- policies, err := c.policyRepository.FindByProjectID(ctx, nil, projectID)
- if err != nil {
- return nil, err
- }
-
- results := make([]compliance.PolicyEvaluation, 0, len(policies))
-foundMatch:
- for _, policy := range policies {
- // check if we find an attestation that matches
- for _, attestation := range attestations {
- if attestation.PredicateType != policy.PredicateType {
- continue
- }
- res := compliance.Eval(policy, attestation.Content)
- // this matches - lets add it
- results = append(results, res)
- continue foundMatch
- }
- // we did not find any attestation that matches - lets add the policy with a nil result
- results = append(results, compliance.Eval(policy, nil))
- }
-
- // compliance.Evaluate the policy
- return results, nil
-}
-
-func (c *ComplianceController) Details(ctx shared.Context) error {
- assetVersion := shared.GetAssetVersion(ctx)
-
- p := ctx.Param("policy")
- // parse the uuid
- policyID, err := uuid.Parse(p)
- if err != nil {
- return ctx.JSON(400, nil)
- }
- // get all policies
- policy, err := c.policyRepository.Read(ctx.Request().Context(), nil, policyID)
- if err != nil {
- return ctx.JSON(404, nil)
- }
-
- attestations, err := c.attestationRepository.GetByAssetVersionAndAssetID(ctx.Request().Context(), nil, assetVersion.AssetID, assetVersion.Name)
-
- if err != nil {
- return ctx.JSON(500, nil)
- }
-
- // look for the right attestations
- for _, attestation := range attestations {
- if attestation.PredicateType == policy.PredicateType {
- res := compliance.Eval(policy, attestation.Content)
- return ctx.JSON(200, res)
- }
- }
- // we did not find any attestation that matches - lets add the policy with a nil result
- return ctx.JSON(200, compliance.Eval(policy, nil))
-}
-
-func (c *ComplianceController) AssetCompliance(ctx shared.Context) error {
- asset := shared.GetAsset(ctx)
- assetVersion, err := shared.MaybeGetAssetVersion(ctx)
- if err != nil {
- // we need to get the default asset version
- assetVersion, err = c.assetVersionRepository.GetDefaultAssetVersion(ctx.Request().Context(), nil, asset.ID)
- if err != nil {
- return ctx.JSON(404, nil)
- }
- }
-
- project := shared.GetProject(ctx)
-
- results, err := c.getAssetVersionCompliance(ctx.Request().Context(), project.ID, assetVersion)
- if err != nil {
- return ctx.JSON(500, nil)
- }
-
- return ctx.JSON(200, results)
-}
-
-func (c *ComplianceController) ProjectCompliance(ctx shared.Context) error {
- // get all default asset version from the project
- project := shared.GetProject(ctx)
- assetVersions, err := c.assetVersionRepository.GetDefaultAssetVersionsByProjectID(ctx.Request().Context(), nil, project.ID)
-
- if err != nil {
- return ctx.JSON(500, nil)
- }
-
- results := make([][]compliance.PolicyEvaluation, 0, len(assetVersions))
- for _, assetVersion := range assetVersions {
- compliance, err := c.getAssetVersionCompliance(ctx.Request().Context(), project.ID, assetVersion)
- if err != nil {
- return ctx.JSON(500, nil)
- }
-
- results = append(results, compliance)
- }
- return ctx.JSON(200, results)
-}
diff --git a/controllers/compliance_risk_controller.go b/controllers/compliance_risk_controller.go
new file mode 100644
index 000000000..8171dd547
--- /dev/null
+++ b/controllers/compliance_risk_controller.go
@@ -0,0 +1,313 @@
+package controllers
+
+import (
+ "archive/zip"
+ "bytes"
+ "encoding/json"
+ "io"
+ "log/slog"
+
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/dtos"
+ "github.com/l3montree-dev/devguard/dtos/sarif"
+ "github.com/l3montree-dev/devguard/shared"
+ "github.com/l3montree-dev/devguard/transformer"
+ "github.com/l3montree-dev/devguard/utils"
+ "github.com/labstack/echo/v4"
+)
+
+type ComplianceRiskController struct {
+ complianceRiskRepository shared.ComplianceRiskRepository
+ complianceRiskService shared.ComplianceRiskService
+ complianceService shared.ComplianceService
+ attestationService shared.AttestationService
+ artifactRepository shared.ArtifactRepository
+}
+
+func NewComplianceRiskController(
+ repo shared.ComplianceRiskRepository,
+ svc shared.ComplianceRiskService,
+ complianceService shared.ComplianceService,
+ attestationService shared.AttestationService,
+ artifactRepository shared.ArtifactRepository,
+) *ComplianceRiskController {
+ return &ComplianceRiskController{
+ complianceRiskRepository: repo,
+ complianceRiskService: svc,
+ complianceService: complianceService,
+ attestationService: attestationService,
+ artifactRepository: artifactRepository,
+ }
+}
+
+type complianceRiskStatus struct {
+ StatusType string `json:"status"`
+ Justification string `json:"justification"`
+ MechanicalJustification dtos.MechanicalJustificationType `json:"mechanicalJustification"`
+}
+
+func convertComplianceRiskToDetailedDTO(r models.ComplianceRisk) dtos.DetailedComplianceRiskDTO {
+ return dtos.DetailedComplianceRiskDTO{
+ ComplianceRiskDTO: transformer.ComplianceRiskToDTO(r),
+ Events: utils.Map(r.Events, func(ev models.VulnEvent) dtos.VulnEventDTO {
+ return dtos.VulnEventDTO{
+ ID: ev.ID,
+ Type: ev.Type,
+ VulnID: ev.GetVulnID(),
+ UserID: ev.UserID,
+ Justification: ev.Justification,
+ MechanicalJustification: ev.MechanicalJustification,
+ OriginalAssetVersionName: ev.OriginalAssetVersionName,
+ VulnerabilityName: r.PolicyID,
+ ArbitraryJSONData: ev.GetArbitraryJSONData(),
+ CreatedAt: ev.CreatedAt,
+ CreatedByVexRule: ev.CreatedByVexRule,
+ }
+ }),
+ }
+}
+
+func (c *ComplianceRiskController) ListPaged(ctx shared.Context) error {
+ assetVersion := shared.GetAssetVersion(ctx)
+
+ pagedResp, err := c.complianceRiskRepository.GetAllComplianceRisksForAssetVersionPaged(
+ ctx.Request().Context(), nil,
+ assetVersion.AssetID,
+ assetVersion.Name,
+ shared.GetPageInfo(ctx),
+ ctx.QueryParam("search"),
+ shared.GetFilterQuery(ctx),
+ shared.GetSortQuery(ctx),
+ )
+ if err != nil {
+ return echo.NewHTTPError(500, "could not get compliance risks").WithInternal(err)
+ }
+
+ frameworks, err := c.complianceRiskRepository.GetDistinctFrameworksForAssetVersion(
+ ctx.Request().Context(), nil,
+ assetVersion.AssetID,
+ assetVersion.Name,
+ )
+ if err != nil {
+ return echo.NewHTTPError(500, "could not get frameworks").WithInternal(err)
+ }
+
+ return ctx.JSON(200, struct {
+ shared.Paged[any]
+ Frameworks []string `json:"frameworks"`
+ }{
+ Paged: pagedResp.Map(func(r models.ComplianceRisk) any { return convertComplianceRiskToDetailedDTO(r) }),
+ Frameworks: frameworks,
+ })
+}
+
+func (c *ComplianceRiskController) Read(ctx shared.Context) error {
+ riskID, _, err := shared.GetVulnID(ctx)
+ if err != nil {
+ return echo.NewHTTPError(400, "could not get compliance risk ID")
+ }
+ risk, err := c.complianceRiskRepository.Read(ctx.Request().Context(), nil, riskID)
+ if err != nil {
+ return echo.NewHTTPError(404, "could not find compliance risk")
+ }
+ return ctx.JSON(200, convertComplianceRiskToDetailedDTO(risk))
+}
+
+func (c *ComplianceRiskController) GetEvidence(ctx shared.Context) error {
+ riskID, _, err := shared.GetVulnID(ctx)
+ if err != nil {
+ return echo.NewHTTPError(400, "could not get compliance risk ID")
+ }
+ risk, err := c.complianceRiskRepository.Read(ctx.Request().Context(), nil, riskID)
+ if err != nil {
+ return echo.NewHTTPError(404, "could not find compliance risk")
+ }
+ if len(risk.EvidenceContent) == 0 {
+ return echo.NewHTTPError(404, "no evidence available")
+ }
+
+ contentType := risk.EvidenceType
+ if contentType == "" || contentType == "json" {
+ contentType = "application/json"
+ }
+
+ return ctx.Blob(200, contentType, risk.EvidenceContent)
+}
+
+func (c *ComplianceRiskController) CreateEvent(ctx shared.Context) error {
+ thirdPartyIntegration := shared.GetThirdPartyIntegration(ctx)
+ riskID, _, err := shared.GetVulnID(ctx)
+ if err != nil {
+ return echo.NewHTTPError(400, "invalid compliance risk id")
+ }
+
+ risk, err := c.complianceRiskRepository.Read(ctx.Request().Context(), nil, riskID)
+ if err != nil {
+ return echo.NewHTTPError(404, "could not find compliance risk")
+ }
+
+ var status complianceRiskStatus
+ if err := json.NewDecoder(ctx.Request().Body).Decode(&status); err != nil {
+ return echo.NewHTTPError(400, "invalid payload").WithInternal(err)
+ }
+ if err := models.CheckStatusType(status.StatusType); err != nil {
+ return echo.NewHTTPError(400, "invalid status type")
+ }
+
+ userID := shared.GetSession(ctx).GetUserID()
+ userAgent := ctx.Request().UserAgent()
+
+ event, err := c.complianceRiskService.UpdateComplianceRiskState(ctx.Request().Context(), nil, userID, &risk, status.StatusType, status.Justification, status.MechanicalJustification, &userAgent)
+ if err != nil {
+ return echo.NewHTTPError(500, "could not create compliance risk event").WithInternal(err)
+ }
+
+ if err := thirdPartyIntegration.HandleEvent(ctx.Request().Context(), shared.VulnEvent{
+ Ctx: ctx,
+ Event: event,
+ }, &userAgent); err != nil {
+ slog.Error("could not handle third-party event for compliance risk", "err", err)
+ return echo.NewHTTPError(500, "could not create compliance risk event").WithInternal(err)
+ }
+
+ return ctx.JSON(200, convertComplianceRiskToDetailedDTO(risk))
+}
+
+func (c *ComplianceRiskController) Mitigate(ctx shared.Context) error {
+ var justification struct {
+ Comment string `json:"comment"`
+ }
+ if err := ctx.Bind(&justification); err != nil {
+ return echo.NewHTTPError(500, "could not bind the request to a justification")
+ }
+
+ riskID, _, err := shared.GetVulnID(ctx)
+ if err != nil {
+ return echo.NewHTTPError(400, "invalid compliance risk id")
+ }
+
+ userAgent := ctx.Request().UserAgent()
+ thirdPartyIntegrations := shared.GetThirdPartyIntegration(ctx)
+
+ if err := thirdPartyIntegrations.HandleEvent(ctx.Request().Context(), shared.ManualMitigateEvent{
+ Ctx: ctx,
+ Justification: justification.Comment,
+ }, &userAgent); err != nil {
+ return echo.NewHTTPError(500, "could not mitigate compliance risk").WithInternal(err)
+ }
+
+ risk, err := c.complianceRiskRepository.Read(ctx.Request().Context(), nil, riskID)
+ if err != nil {
+ return echo.NewHTTPError(404, "could not find compliance risk")
+ }
+ return ctx.JSON(200, convertComplianceRiskToDetailedDTO(risk))
+}
+
+// RunAttestationEvaluation fetches evaluations via complianceService.EvaluateArtifactAttestations and recalculates risks.
+func (c *ComplianceRiskController) RunAttestationEvaluation(ctx shared.Context) error {
+ assetVersion := shared.GetAssetVersion(ctx)
+ artifact := shared.GetArtifact(ctx)
+ project := shared.GetProject(ctx)
+ userAgent := ctx.Request().UserAgent()
+ userID := shared.GetSession(ctx).GetUserID()
+
+ sarifDoc, err := c.complianceService.EvaluateArtifactAttestations(ctx.Request().Context(), project.ID, assetVersion, artifact)
+ if err != nil {
+ return echo.NewHTTPError(500, "could not evaluate artifact compliance").WithInternal(err)
+ }
+
+ if err := c.complianceRiskService.HandleArtifactCompliance(ctx.Request().Context(), nil, userID, &userAgent, assetVersion, artifact, sarifDoc); err != nil {
+ return echo.NewHTTPError(500, "could not handle artifact compliance risks").WithInternal(err)
+ }
+
+ return ctx.JSON(200, sarifDoc)
+}
+
+// UploadZip accepts a ZIP file containing attestation JSON files and a sarif.json.
+// It saves each attestation and then recalculates compliance risks based on the SARIF.
+func (c *ComplianceRiskController) UploadZip(ctx shared.Context) error {
+ assetVersion := shared.GetAssetVersion(ctx)
+ artifact := shared.GetArtifact(ctx)
+ userAgent := ctx.Request().UserAgent()
+ userID := shared.GetSession(ctx).GetUserID()
+
+ file, err := ctx.FormFile("file")
+ if err != nil {
+ return echo.NewHTTPError(400, "missing zip file").WithInternal(err)
+ }
+
+ src, err := file.Open()
+ if err != nil {
+ return echo.NewHTTPError(500, "could not open zip file").WithInternal(err)
+ }
+ defer src.Close()
+
+ data, err := io.ReadAll(src)
+ if err != nil {
+ return echo.NewHTTPError(500, "could not read zip file").WithInternal(err)
+ }
+
+ zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
+ if err != nil {
+ return echo.NewHTTPError(400, "invalid zip file").WithInternal(err)
+ }
+
+ var sarifDoc *sarif.SarifSchema210Json
+
+ for _, f := range zr.File {
+ rc, err := f.Open()
+ if err != nil {
+ slog.Warn("could not open file in zip", "name", f.Name, "err", err)
+ continue
+ }
+ content, err := io.ReadAll(rc)
+ rc.Close()
+ if err != nil {
+ slog.Warn("could not read file in zip", "name", f.Name, "err", err)
+ continue
+ }
+
+ if f.Name == "sarif.json" {
+ var doc sarif.SarifSchema210Json
+ if err := json.Unmarshal(content, &doc); err != nil {
+ return echo.NewHTTPError(400, "invalid sarif.json in zip").WithInternal(err)
+ }
+ sarifDoc = &doc
+ continue
+ }
+
+ // treat remaining files as attestations; predicateType is read from the JSON content
+ var contentMap map[string]any
+ if err := json.Unmarshal(content, &contentMap); err != nil {
+ slog.Warn("skipping non-JSON attestation file in zip", "name", f.Name, "err", err)
+ continue
+ }
+
+ predicateType, ok := contentMap["predicateType"].(string)
+ if !ok || predicateType == "" {
+ slog.Warn("attestation file missing predicateType field, skipping", "name", f.Name)
+ continue
+ }
+
+ attestation := models.Attestation{
+ AssetID: assetVersion.AssetID,
+ AssetVersionName: assetVersion.Name,
+ ArtifactName: artifact.ArtifactName,
+ PredicateType: predicateType,
+ Content: contentMap,
+ }
+ if err := c.attestationService.Create(ctx.Request().Context(), nil, &attestation); err != nil {
+ slog.Error("could not save attestation from zip", "name", f.Name, "err", err)
+ }
+ }
+
+ if sarifDoc == nil {
+ return echo.NewHTTPError(400, "sarif.json not found in zip")
+ }
+
+ if err := c.complianceRiskService.HandleArtifactCompliance(ctx.Request().Context(), nil, userID, &userAgent, assetVersion, artifact, *sarifDoc); err != nil {
+ return echo.NewHTTPError(500, "could not handle artifact compliance risks").WithInternal(err)
+ }
+
+ return ctx.JSON(200, sarifDoc)
+}
diff --git a/controllers/policy_controller.go b/controllers/policy_controller.go
deleted file mode 100644
index b580df62e..000000000
--- a/controllers/policy_controller.go
+++ /dev/null
@@ -1,265 +0,0 @@
-package controllers
-
-import (
- "context"
- "log/slog"
- "sync"
-
- "github.com/google/uuid"
- "github.com/l3montree-dev/devguard/compliance"
- "github.com/l3montree-dev/devguard/database/models"
- "github.com/l3montree-dev/devguard/dtos"
- "github.com/l3montree-dev/devguard/shared"
- "github.com/l3montree-dev/devguard/utils"
-)
-
-type PolicyController struct {
- policyRepository shared.PolicyRepository
- projectRepository shared.ProjectRepository
-}
-
-func NewPolicyController(policyRepository shared.PolicyRepository, projectRepository shared.ProjectRepository) *PolicyController {
- c := &PolicyController{
- policyRepository: policyRepository,
- projectRepository: projectRepository,
- }
-
- if err := c.migratePolicies(); err != nil {
- panic(err)
- }
- return c
-}
-
-func (c *PolicyController) migratePolicies() error {
- ctx := context.Background()
- // we need to migrate the policies from the old format to the new format
- // this is only needed for the first time we run the application
- // after that we can remove this function
- policies := compliance.GetCommunityManagedPoliciesFromFS()
- policyModels := make([]models.Policy, len(policies))
- for i, policy := range policies {
- policyModels[i] = compliance.ConvertPolicyFsToModel(policy)
- }
-
- // get all community managed policies from the database
- dbPolicies, err := c.policyRepository.FindCommunityManagedPolicies(ctx, nil)
- if err != nil {
- return err
- }
-
- // compare the policies
- comp := utils.CompareSlices(policyModels, dbPolicies, func(p models.Policy) string {
- return *p.OpaqueID
- })
-
- toCreate := comp.OnlyInA
- toUpdate := comp.InBothB // use the B elements - those are the new policies read from disk
- toDelete := comp.OnlyInB
-
- // set the id for the policies to update
- for i := range toUpdate {
- for j := range dbPolicies {
- if dbPolicies[j].OpaqueID == toUpdate[i].OpaqueID {
- toUpdate[i].ID = dbPolicies[j].ID
- break
- }
- }
- }
-
- // create the policies
- if len(toCreate) > 0 {
- if err := c.policyRepository.CreateBatch(ctx, nil, toCreate); err != nil {
- return err
- }
- }
-
- // update the policies
- if len(toUpdate) > 0 {
- if err := c.policyRepository.SaveBatch(ctx, nil, toUpdate); err != nil {
- return err
- }
- }
-
- // delete the policies
- if len(toDelete) > 0 {
- wg := sync.WaitGroup{}
- for _, policy := range toDelete {
- wg.Add(1)
- go func(p models.Policy) {
- defer wg.Done()
- err := c.policyRepository.GetDB(ctx, nil).Model(&p).Association("Projects").Clear()
- if err != nil {
- slog.Warn("failed to clear projects association for policy", "policyID", p.ID, "error", err)
- return
- }
- }(policy)
- }
- wg.Wait()
- if err := c.policyRepository.DeleteBatch(ctx, nil, toDelete); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (c *PolicyController) GetOrganizationPolicies(ctx shared.Context) error {
-
- org := shared.GetOrg(ctx)
- policies, err := c.policyRepository.FindByOrganizationID(ctx.Request().Context(), nil, org.ID)
-
- if err != nil {
- return err
- }
-
- // include the community managed policies
- communityPolicies, err := c.policyRepository.FindCommunityManagedPolicies(ctx.Request().Context(), nil)
- if err != nil {
- return err
- }
-
- return ctx.JSON(200, append(policies, communityPolicies...))
-}
-
-func (c *PolicyController) GetProjectPolicies(ctx shared.Context) error {
- project := shared.GetProject(ctx)
- policies, err := c.policyRepository.FindByProjectID(ctx.Request().Context(), nil, project.ID)
-
- if err != nil {
- return err
- }
-
- return ctx.JSON(200, policies)
-}
-
-func (c *PolicyController) GetPolicy(ctx shared.Context) error {
- policyID := ctx.Param("policyID")
-
- // parse the uuid
- policyUUID, err := uuid.Parse(policyID)
- if err != nil {
- return err
- }
-
- policy, err := c.policyRepository.Read(ctx.Request().Context(), nil, policyUUID)
-
- if err != nil {
- return err
- }
-
- return ctx.JSON(200, policy)
-}
-
-func (c *PolicyController) CreatePolicy(ctx shared.Context) error {
- policy := dtos.PolicyDTO{}
- if err := ctx.Bind(&policy); err != nil {
- return err
- }
-
- org := shared.GetOrg(ctx)
-
- // create a new policy model
- policyModel := models.Policy{
- Rego: policy.Rego,
- Description: policy.Description,
- Title: policy.Title,
- PredicateType: policy.PredicateType,
- OrganizationID: utils.Ptr(org.ID),
- OpaqueID: nil,
- }
-
- // create the policy
- if err := c.policyRepository.Create(ctx.Request().Context(), nil, &policyModel); err != nil {
- return err
- }
-
- return ctx.JSON(201, policy)
-}
-
-func (c *PolicyController) UpdatePolicy(ctx shared.Context) error {
- policyID := ctx.Param("policyID")
-
- // parse the uuid
- policyUUID, err := uuid.Parse(policyID)
- if err != nil {
- return err
- }
-
- policy := dtos.PolicyDTO{}
- if err := ctx.Bind(&policy); err != nil {
- return err
- }
-
- org := shared.GetOrg(ctx)
-
- // create a new policy model
- policyModel := models.Policy{
- ID: policyUUID,
- Rego: policy.Rego,
- Description: policy.Description,
- Title: policy.Title,
- PredicateType: policy.PredicateType,
- OrganizationID: utils.Ptr(org.ID),
- }
-
- if err := c.policyRepository.Save(ctx.Request().Context(), nil, &policyModel); err != nil {
- return err
- }
-
- return ctx.JSON(200, policyModel)
-}
-
-func (c *PolicyController) DeletePolicy(ctx shared.Context) error {
- policyID := ctx.Param("policyID")
-
- // parse the uuid
- policyUUID, err := uuid.Parse(policyID)
- if err != nil {
- return err
- }
-
- // delete the policy
- if err := c.policyRepository.Delete(ctx.Request().Context(), nil, policyUUID); err != nil {
- return err
- }
-
- return ctx.NoContent(204)
-}
-
-func (c *PolicyController) EnablePolicyForProject(ctx shared.Context) error {
- policyID := ctx.Param("policyID")
-
- project := shared.GetProject(ctx)
-
- // parse the uuid
- policyUUID, err := uuid.Parse(policyID)
- if err != nil {
- return err
- }
-
- // enable the policy for the project
- if err := c.projectRepository.EnablePolicyForProject(ctx.Request().Context(), nil, project.ID, policyUUID); err != nil {
- return err
- }
-
- return ctx.NoContent(204)
-}
-
-func (c *PolicyController) DisablePolicyForProject(ctx shared.Context) error {
- policyID := ctx.Param("policyID")
-
- // parse the uuid
- policyUUID, err := uuid.Parse(policyID)
- if err != nil {
- return err
- }
-
- project := shared.GetProject(ctx)
-
- // disable the policy for the project
- if err := c.projectRepository.DisablePolicyForProject(ctx.Request().Context(), nil, project.ID, policyUUID); err != nil {
- return err
- }
-
- return ctx.NoContent(204)
-}
diff --git a/controllers/providers.go b/controllers/providers.go
index 193f9c996..fb96666f9 100644
--- a/controllers/providers.go
+++ b/controllers/providers.go
@@ -90,10 +90,9 @@ var ControllerModule = fx.Options(
// Security & Compliance
fx.Provide(NewCSAFController),
- fx.Provide(NewComplianceController),
fx.Provide(NewAttestationController),
fx.Provide(NewInToToController),
- fx.Provide(NewPolicyController),
+ fx.Provide(NewComplianceRiskController),
// Integrations
fx.Provide(NewIntegrationController),
diff --git a/daemons/attestation_daemon.go b/daemons/attestation_daemon.go
new file mode 100644
index 000000000..4aa921bef
--- /dev/null
+++ b/daemons/attestation_daemon.go
@@ -0,0 +1,87 @@
+package daemons
+
+import (
+ "log/slog"
+
+ "github.com/l3montree-dev/devguard/monitoring"
+)
+
+func (runner *DaemonRunner) CheckArtifactCompliance(input <-chan assetWithProjectAndOrg, errChan chan<- pipelineError) <-chan assetWithProjectAndOrg {
+ out := make(chan assetWithProjectAndOrg)
+
+ go func() {
+ defer func() {
+ close(out)
+ monitoring.RecoverPanic("check artifact compliance panic")
+ }()
+
+ for assetWithDetails := range input {
+ stageCtx, span := daemonTracer.Start(assetWithDetails.ctx, "pipeline.check-artifact-compliance")
+
+ for _, assetVersion := range assetWithDetails.assetVersions {
+ for _, artifact := range assetVersion.Artifacts {
+ sarifDoc, err := runner.complianceService.EvaluateArtifactAttestations(stageCtx, assetWithDetails.project.ID, assetVersion, artifact)
+ if err != nil {
+ slog.Error("could not evaluate artifact compliance",
+ "assetID", assetWithDetails.asset.ID,
+ "assetVersion", assetVersion.Name,
+ "artifactName", artifact.ArtifactName,
+ "err", err,
+ )
+ continue
+ }
+ if err := runner.complianceRiskService.HandleArtifactCompliance(stageCtx, nil, "system", nil, assetVersion, artifact, sarifDoc); err != nil {
+ slog.Error("could not handle artifact compliance risks",
+ "assetID", assetWithDetails.asset.ID,
+ "assetVersion", assetVersion.Name,
+ "artifactName", artifact.ArtifactName,
+ "err", err,
+ )
+ }
+ }
+ }
+
+ span.End()
+ out <- assetWithDetails
+ }
+ }()
+
+ return out
+}
+
+// GenerateDevguardAttestations is a pipeline stage that computes the DevGuard asset
+// metrics attestation for every asset version and upserts it into the attestations table.
+// It runs after CollectStats so that risk data is already up to date.
+func (runner *DaemonRunner) GenerateDevguardAttestations(input <-chan assetWithProjectAndOrg, errChan chan<- pipelineError) <-chan assetWithProjectAndOrg {
+ out := make(chan assetWithProjectAndOrg)
+
+ go func() {
+ defer func() {
+ close(out)
+ monitoring.RecoverPanic("generate devguard attestations panic")
+ }()
+
+ for assetWithDetails := range input {
+ stageCtx, span := daemonTracer.Start(assetWithDetails.ctx, "pipeline.generate-devguard-attestations")
+
+ for _, assetVersion := range assetWithDetails.assetVersions {
+ for _, artifact := range assetVersion.Artifacts {
+ if err := runner.attestationService.GenerateAndStoreDevguardAttestation(stageCtx, assetVersion.AssetID, assetVersion.Name, artifact.ArtifactName); err != nil {
+ slog.Error("could not generate devguard attestation",
+ "assetID", assetWithDetails.asset.ID,
+ "assetVersion", assetVersion.Name,
+ "artifactName", artifact.ArtifactName,
+ "err", err,
+ )
+ // non-fatal: log and continue to next artifact
+ }
+ }
+ }
+
+ span.End()
+ out <- assetWithDetails
+ }
+ }()
+
+ return out
+}
diff --git a/daemons/daemon_asset_pipeline.go b/daemons/daemon_asset_pipeline.go
index 13833668b..6417c1256 100644
--- a/daemons/daemon_asset_pipeline.go
+++ b/daemons/daemon_asset_pipeline.go
@@ -61,6 +61,8 @@ func (runner *DaemonRunner) runPipeline(ctx context.Context, idsChan <-chan uuid
ch = runner.SyncTickets(ch, errChan)
ch = runner.ResolveDifferencesInTicketState(ch, errChan)
ch = runner.CollectStats(ch, errChan)
+ ch = runner.GenerateDevguardAttestations(ch, errChan)
+ ch = runner.CheckArtifactCompliance(ch, errChan)
utils.WaitForChannelDrain(ch)
// we can close the error channel now
// since it is a chan<-pipelineError we can be sure that all errors have been sent
diff --git a/daemons/providers.go b/daemons/providers.go
index d8870d294..c84f09b7e 100644
--- a/daemons/providers.go
+++ b/daemons/providers.go
@@ -62,6 +62,10 @@ type DaemonRunner struct {
maliciousPackageChecker shared.MaliciousPackageChecker
vulnDBImportService shared.VulnDBService
vexRuleService shared.VEXRuleService
+ attestationService shared.AttestationService
+ statisticsRepository shared.StatisticsRepository
+ complianceService shared.ComplianceService
+ complianceRiskService shared.ComplianceRiskService
debugOptions DebugOptions
fixedVersionResolver shared.FixedVersionResolver
@@ -106,6 +110,10 @@ func NewDaemonRunner(
vulnDBImportService shared.VulnDBService,
vexRuleService shared.VEXRuleService,
fixedVersionResolver shared.FixedVersionResolver,
+ attestationService shared.AttestationService,
+ statisticsRepository shared.StatisticsRepository,
+ complianceService shared.ComplianceService,
+ complianceRiskService shared.ComplianceRiskService,
) *DaemonRunner {
return &DaemonRunner{
db: db,
@@ -137,6 +145,10 @@ func NewDaemonRunner(
vulnDBImportService: vulnDBImportService,
vexRuleService: vexRuleService,
fixedVersionResolver: fixedVersionResolver,
+ attestationService: attestationService,
+ statisticsRepository: statisticsRepository,
+ complianceService: complianceService,
+ complianceRiskService: complianceRiskService,
}
}
diff --git a/database/migrations/20260602000000_add_compliance_risks_drop_policies.up.sql b/database/migrations/20260602000000_add_compliance_risks_drop_policies.up.sql
new file mode 100644
index 000000000..8e646f129
--- /dev/null
+++ b/database/migrations/20260602000000_add_compliance_risks_drop_policies.up.sql
@@ -0,0 +1,70 @@
+-- Drop policy tables (data is now embedded in compliance_risks)
+DROP TABLE IF EXISTS public.project_enabled_policies;
+DROP TABLE IF EXISTS public.policies;
+
+CREATE TABLE IF NOT EXISTS public.compliance_risks (
+ id uuid NOT NULL,
+ asset_version_name text NOT NULL,
+ asset_id uuid NOT NULL,
+ message text,
+ state text DEFAULT 'open' NOT NULL,
+ last_detected timestamp with time zone DEFAULT now() NOT NULL,
+ ticket_id text,
+ ticket_url text,
+ manual_ticket_creation boolean DEFAULT false,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ deleted_at timestamp with time zone,
+ policy_id text NOT NULL,
+ policy_title text NOT NULL DEFAULT '',
+ policy_description text,
+ evidence_type text NOT NULL DEFAULT '',
+ policy_related_resources jsonb DEFAULT '[]',
+ policy_tags jsonb DEFAULT '[]',
+ policy_priority integer,
+ "policyFrameworks" jsonb,
+ evidence_content bytea,
+ violations jsonb DEFAULT '[]',
+ CONSTRAINT compliance_risks_pkey PRIMARY KEY (id),
+ CONSTRAINT fk_compliance_risks_asset_versions FOREIGN KEY (asset_version_name, asset_id)
+ REFERENCES public.asset_versions (name, asset_id) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS public.artifact_compliance_risks (
+ artifact_artifact_name text NOT NULL,
+ artifact_asset_version_name text NOT NULL,
+ artifact_asset_id uuid NOT NULL,
+ compliance_risk_id uuid NOT NULL,
+ CONSTRAINT artifact_compliance_risks_pkey PRIMARY KEY (artifact_artifact_name, artifact_asset_version_name, artifact_asset_id, compliance_risk_id),
+ CONSTRAINT fk_artifact_compliance_risks_artifact FOREIGN KEY (artifact_artifact_name, artifact_asset_version_name, artifact_asset_id)
+ REFERENCES public.artifacts (artifact_name, asset_version_name, asset_id) ON DELETE CASCADE,
+ CONSTRAINT fk_artifact_compliance_risks_compliance_risk FOREIGN KEY (compliance_risk_id)
+ REFERENCES public.compliance_risks (id) ON DELETE CASCADE
+);
+
+-- Add compliance_risk_id column to vuln_events
+ALTER TABLE public.vuln_events
+ ADD COLUMN IF NOT EXISTS compliance_risk_id uuid;
+
+ALTER TABLE public.vuln_events
+ DROP CONSTRAINT IF EXISTS fk_vuln_events_compliance_risk;
+
+ALTER TABLE public.vuln_events
+ ADD CONSTRAINT fk_vuln_events_compliance_risk FOREIGN KEY (compliance_risk_id)
+ REFERENCES public.compliance_risks (id) ON DELETE CASCADE;
+
+-- Drop old one_vuln_parent check (only 3 columns) and replace with updated version including compliance_risk_id
+ALTER TABLE public.vuln_events DROP CONSTRAINT IF EXISTS one_vuln_parent;
+
+ALTER TABLE public.vuln_events ADD CONSTRAINT one_vuln_parent CHECK (
+ (dependency_vuln_id IS NOT NULL)::int +
+ (license_risk_id IS NOT NULL)::int +
+ (first_party_vuln_id IS NOT NULL)::int +
+ (compliance_risk_id IS NOT NULL)::int = 1
+);
+
+CREATE INDEX IF NOT EXISTS idx_compliance_risks_asset_version
+ ON public.compliance_risks (asset_version_name, asset_id);
+
+CREATE INDEX IF NOT EXISTS idx_artifact_compliance_risks_compliance_risk_id
+ ON public.artifact_compliance_risks (compliance_risk_id);
diff --git a/database/models/compliance_risk_model.go b/database/models/compliance_risk_model.go
new file mode 100644
index 000000000..f9b80442b
--- /dev/null
+++ b/database/models/compliance_risk_model.go
@@ -0,0 +1,98 @@
+// Copyright (C) 2026 l3montree GmbH
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+package models
+
+import (
+ "fmt"
+
+ "github.com/google/uuid"
+ "github.com/l3montree-dev/devguard/dtos"
+ "github.com/l3montree-dev/devguard/utils"
+ "gorm.io/gorm"
+)
+
+type PolicyFrameworks struct {
+ Framework string `yaml:"framework" json:"framework"`
+ Controls []string `yaml:"controls" json:"controls"`
+}
+type ComplianceRisk struct {
+ Vulnerability
+
+ PolicyID string `json:"policyId" gorm:"type:text;"`
+ PolicyTitle string `json:"policyTitle" gorm:"type:text;"`
+ PolicyDescription *string `json:"policyDescription" gorm:"type:text;"`
+ PolicyRelatedResources []string `json:"policyRelatedResources" gorm:"type:jsonb;serializer:json"`
+ PolicyTags []string `json:"policyTags" gorm:"type:jsonb;serializer:json"`
+ PolicyPriority int `json:"policyPriority"`
+ PolicyFrameworks []PolicyFrameworks `json:"policyFrameworks" gorm:"column:policyFrameworks;type:jsonb;serializer:json"`
+ EvidenceType string `json:"evidenceType" gorm:"type:text;"`
+ EvidenceContent []byte `json:"evidenceContent" gorm:"type:bytea;"`
+
+ Message string `json:"message" gorm:"type:text;"`
+
+ Violations []string `json:"violations" gorm:"type:jsonb;serializer:json"`
+
+ Events []VulnEvent `gorm:"foreignKey:ComplianceRiskID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;" json:"events"`
+
+ Artifacts []Artifact `json:"artifacts" gorm:"many2many:artifact_compliance_risks;constraint:OnDelete:CASCADE"`
+}
+
+func (complianceRisk ComplianceRisk) TableName() string {
+ return "compliance_risks"
+}
+
+func (complianceRisk ComplianceRisk) GetType() dtos.VulnType {
+ return dtos.VulnTypeComplianceRisk
+}
+
+func (complianceRisk *ComplianceRisk) CalculateHash() uuid.UUID {
+ return utils.HashToUUID(fmt.Sprintf("%s/%s/%s", complianceRisk.PolicyID, complianceRisk.AssetVersionName, complianceRisk.AssetID))
+}
+
+func (complianceRisk *ComplianceRisk) BeforeSave(tx *gorm.DB) error {
+ complianceRisk.ID = complianceRisk.CalculateHash()
+ return nil
+}
+
+func (complianceRisk ComplianceRisk) GetEvents() []VulnEvent {
+ return complianceRisk.Events
+}
+
+func (complianceRisk *ComplianceRisk) GetArtifacts() []Artifact {
+ return complianceRisk.Artifacts
+}
+
+func (complianceRisk ComplianceRisk) GetAssetVersionName() string {
+ return complianceRisk.AssetVersionName
+}
+
+func (complianceRisk ComplianceRisk) AssetVersionIndependentHash() string {
+ return utils.HashString(complianceRisk.PolicyID)
+}
+
+func (complianceRisk *ComplianceRisk) GetArtifactNames() string {
+ names := ""
+ for _, a := range complianceRisk.Artifacts {
+ if names != "" {
+ names += ", "
+ }
+ names += a.ArtifactName
+ }
+ return names
+}
+
+func (complianceRisk ComplianceRisk) Title() string {
+ return fmt.Sprintf("Compliance risk for policy %s", complianceRisk.PolicyID)
+}
diff --git a/database/models/policy_model.go b/database/models/policy_model.go
deleted file mode 100644
index 3c1966b64..000000000
--- a/database/models/policy_model.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package models
-
-import "github.com/google/uuid"
-
-type Policy struct {
- ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey;default:gen_random_uuid()"`
- Rego string `json:"rego"`
- Title string `json:"title"`
- PredicateType string `json:"predicateType"`
- Description string `json:"description"`
-
- OrganizationID *uuid.UUID `json:"organizationId"` // will be null for global policies
- Organization *Org `json:"organization" gorm:"foreignKey:OrganizationID;references:ID;constraint:OnDelete:CASCADE;"`
-
- OpaqueID *string `json:"opaqueId" gorm:"unique"` // only used by global policies maintained by the community and migrated by the system
- Projects []Project `json:"projects" gorm:"many2many:project_enabled_policies;constraint:OnDelete:CASCADE;"`
-}
-
-func (m Policy) TableName() string {
- return "policies"
-}
diff --git a/database/models/project_model.go b/database/models/project_model.go
index deec3e8dd..aa7450861 100644
--- a/database/models/project_model.go
+++ b/database/models/project_model.go
@@ -43,8 +43,6 @@ type Project struct {
ConfigFiles databasetypes.JSONB `json:"configFiles" gorm:"type:jsonb"`
- EnabledPolicies []Policy `json:"enabledPolicies" gorm:"many2many:project_enabled_policies;constraint:OnDelete:CASCADE;"`
-
ExternalEntityID *string `json:"externalEntityId" gorm:"uniqueIndex:unique_external_entity;"`
ExternalEntityProviderID *string `json:"externalEntityProviderId" gorm:"uniqueIndex:unique_external_entity;"`
ExternalEntityParentID *string `json:"externalEntityProviderParentId" gorm:"type:text;"`
diff --git a/database/models/vulnevent_model.go b/database/models/vulnevent_model.go
index 1e97aabd7..e614746ca 100644
--- a/database/models/vulnevent_model.go
+++ b/database/models/vulnevent_model.go
@@ -17,6 +17,7 @@ type VulnEvent struct {
DependencyVulnID *uuid.UUID `json:"dependencyVulnId" gorm:"type:uuid;column:dependency_vuln_id"`
LicenseRiskID *uuid.UUID `json:"licenseRiskId" gorm:"type:uuid;column:license_risk_id"`
FirstPartyVulnID *uuid.UUID `json:"firstPartyVulnId" gorm:"type:uuid;column:first_party_vuln_id"`
+ ComplianceRiskID *uuid.UUID `json:"complianceRiskId" gorm:"type:uuid;column:compliance_risk_id"`
UserID string `json:"userId"`
Justification *string `json:"justification" gorm:"type:text;"`
MechanicalJustification dtos.MechanicalJustificationType `json:"mechanicalJustification" gorm:"type:text;"`
@@ -45,6 +46,9 @@ func (event VulnEvent) GetVulnID() uuid.UUID {
if event.FirstPartyVulnID != nil {
return *event.FirstPartyVulnID
}
+ if event.ComplianceRiskID != nil {
+ return *event.ComplianceRiskID
+ }
return uuid.Nil
}
@@ -59,6 +63,9 @@ func (event VulnEvent) GetVulnType() dtos.VulnType {
if event.FirstPartyVulnID != nil {
return dtos.VulnTypeFirstPartyVuln
}
+ if event.ComplianceRiskID != nil {
+ return dtos.VulnTypeComplianceRisk
+ }
return ""
}
@@ -71,6 +78,8 @@ func SetVulnIDOnEvent(event *VulnEvent, vulnID uuid.UUID, vulnType dtos.VulnType
event.LicenseRiskID = &vulnID
case dtos.VulnTypeFirstPartyVuln:
event.FirstPartyVulnID = &vulnID
+ case dtos.VulnTypeComplianceRisk:
+ event.ComplianceRiskID = &vulnID
}
}
diff --git a/database/repositories/attestation_repository.go b/database/repositories/attestation_repository.go
index c3b6491ce..2085dad5d 100644
--- a/database/repositories/attestation_repository.go
+++ b/database/repositories/attestation_repository.go
@@ -43,6 +43,15 @@ func (a *attestationRepository) GetByAssetVersionAndAssetID(ctx context.Context,
return attestationList, nil
}
+func (a *attestationRepository) GetByArtifactAndAssetVersionAndAssetID(ctx context.Context, tx *gorm.DB, artifactName string, assetVersion string, assetID uuid.UUID) ([]models.Attestation, error) {
+ var attestationList []models.Attestation
+ err := a.GetDB(ctx, tx).Where("asset_id = ? AND asset_version_name = ? AND artifact_name = ?", assetID, assetVersion, artifactName).Find(&attestationList).Error
+ if err != nil {
+ return attestationList, err
+ }
+ return attestationList, nil
+}
+
func (a *attestationRepository) Create(ctx context.Context, tx *gorm.DB, attestation *models.Attestation) error {
return a.GetDB(ctx, tx).Clauses(clause.OnConflict{
Columns: []clause.Column{
diff --git a/database/repositories/compliance_risk_repository.go b/database/repositories/compliance_risk_repository.go
new file mode 100644
index 000000000..b5c345224
--- /dev/null
+++ b/database/repositories/compliance_risk_repository.go
@@ -0,0 +1,136 @@
+package repositories
+
+import (
+ "context"
+
+ "github.com/google/uuid"
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/shared"
+ "github.com/l3montree-dev/devguard/statemachine"
+ "github.com/l3montree-dev/devguard/utils"
+ "gorm.io/gorm"
+)
+
+type ComplianceRiskRepository struct {
+ utils.Repository[uuid.UUID, models.ComplianceRisk, *gorm.DB]
+ db *gorm.DB
+}
+
+func NewComplianceRiskRepository(db *gorm.DB) *ComplianceRiskRepository {
+ return &ComplianceRiskRepository{
+ db: db,
+ Repository: newGormRepository[uuid.UUID, models.ComplianceRisk](db),
+ }
+}
+
+func (r *ComplianceRiskRepository) GetAllComplianceRisksForAssetVersion(ctx context.Context, tx *gorm.DB, assetID uuid.UUID, assetVersionName string) ([]models.ComplianceRisk, error) {
+ var result []models.ComplianceRisk
+ err := r.GetDB(ctx, tx).Preload("Artifacts").Where("asset_id = ? AND asset_version_name = ?", assetID, assetVersionName).Find(&result).Error
+ return result, err
+}
+
+func (r *ComplianceRiskRepository) GetAllComplianceRisksForAssetVersionPaged(ctx context.Context, tx *gorm.DB, assetID uuid.UUID, assetVersionName string, pageInfo shared.PageInfo, search string, filter []shared.FilterQuery, sort []shared.SortQuery) (shared.Paged[models.ComplianceRisk], error) {
+ var count int64
+ var risks []models.ComplianceRisk
+
+ q := r.GetDB(ctx, tx).Model(&models.ComplianceRisk{}).
+ Preload("Artifacts").
+ Joins("LEFT JOIN artifact_compliance_risks ON artifact_compliance_risks.compliance_risk_id = compliance_risks.id").
+ Where("compliance_risks.asset_version_name = ?", assetVersionName).
+ Where("compliance_risks.asset_id = ?", assetID).
+ Distinct()
+
+ for _, f := range filter {
+ q = q.Where(f.SQL(), f.Value())
+ }
+
+ if len(search) > 2 {
+ q = q.Where("compliance_risks.policy_id ILIKE ?", "%"+search+"%")
+ }
+
+ if err := q.Session(&gorm.Session{}).Distinct("compliance_risks.id").Count(&count).Error; err != nil {
+ return shared.Paged[models.ComplianceRisk]{}, err
+ }
+
+ err := q.Limit(pageInfo.PageSize).Offset((pageInfo.Page - 1) * pageInfo.PageSize).Find(&risks).Error
+ if err != nil {
+ return shared.Paged[models.ComplianceRisk]{}, err
+ }
+ return shared.NewPaged(pageInfo, count, risks), nil
+}
+
+func (r *ComplianceRiskRepository) Read(ctx context.Context, tx *gorm.DB, id uuid.UUID) (models.ComplianceRisk, error) {
+ var risk models.ComplianceRisk
+ err := r.GetDB(ctx, tx).Where("id = ?", id).
+ Preload("Artifacts").
+ Preload("Events", func(db *gorm.DB) *gorm.DB {
+ return db.Order("created_at ASC")
+ }).
+ First(&risk).Error
+ return risk, err
+}
+
+func (r *ComplianceRiskRepository) ApplyAndSave(ctx context.Context, tx *gorm.DB, risk *models.ComplianceRisk, ev *models.VulnEvent) error {
+ if tx == nil {
+ return r.Transaction(ctx, func(d *gorm.DB) error {
+ return r.applyAndSave(ctx, d, risk, ev)
+ })
+ }
+ return r.applyAndSave(ctx, tx, risk, ev)
+}
+
+func (r *ComplianceRiskRepository) applyAndSave(ctx context.Context, tx *gorm.DB, risk *models.ComplianceRisk, ev *models.VulnEvent) error {
+ statemachine.Apply(risk, *ev)
+ if err := r.Save(ctx, tx, risk); err != nil {
+ return err
+ }
+ if err := r.GetDB(ctx, tx).Save(ev).Error; err != nil {
+ return err
+ }
+ risk.Events = append(risk.Events, *ev)
+ return nil
+}
+
+func (r *ComplianceRiskRepository) GetComplianceRisksByOtherAssetVersions(ctx context.Context, tx *gorm.DB, assetVersionName string, assetID uuid.UUID) ([]models.ComplianceRisk, error) {
+ var risks []models.ComplianceRisk
+ q := r.GetDB(ctx, tx).
+ Preload("Events", func(db *gorm.DB) *gorm.DB {
+ return db.Order("created_at ASC")
+ }).
+ Preload("Artifacts").
+ Where("compliance_risks.asset_version_name != ? AND compliance_risks.asset_id = ?", assetVersionName, assetID)
+ if err := q.Find(&risks).Error; err != nil {
+ return nil, err
+ }
+ return risks, nil
+}
+
+func (r *ComplianceRiskRepository) GetDistinctFrameworksForAssetVersion(ctx context.Context, tx *gorm.DB, assetID uuid.UUID, assetVersionName string) ([]string, error) {
+ type result struct {
+ Framework string
+ }
+ var rows []result
+ err := r.GetDB(ctx, tx).Raw(`
+ SELECT DISTINCT elem->>'framework' AS framework
+ FROM compliance_risks,
+ jsonb_array_elements("policyFrameworks") AS elem
+ WHERE asset_id = ? AND asset_version_name = ?
+ AND elem->>'framework' IS NOT NULL
+ ORDER BY framework
+ `, assetID, assetVersionName).Scan(&rows).Error
+ if err != nil {
+ return nil, err
+ }
+ frameworks := make([]string, len(rows))
+ for i, row := range rows {
+ frameworks[i] = row.Framework
+ }
+ return frameworks, nil
+}
+
+func (r *ComplianceRiskRepository) SaveBatch(ctx context.Context, tx *gorm.DB, risks []models.ComplianceRisk) error {
+ if len(risks) == 0 {
+ return nil
+ }
+ return r.GetDB(ctx, tx).Save(&risks).Error
+}
diff --git a/database/repositories/policy_repository.go b/database/repositories/policy_repository.go
deleted file mode 100644
index 717fba7a3..000000000
--- a/database/repositories/policy_repository.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package repositories
-
-import (
- "context"
-
- "github.com/google/uuid"
- "github.com/l3montree-dev/devguard/database/models"
- "github.com/l3montree-dev/devguard/utils"
- "gorm.io/gorm"
-)
-
-type policyRepository struct {
- db *gorm.DB
- utils.Repository[uuid.UUID, models.Policy, *gorm.DB]
-}
-
-func NewPolicyRepository(db *gorm.DB) *policyRepository {
- return &policyRepository{
- db: db,
- Repository: newGormRepository[uuid.UUID, models.Policy](db),
- }
-}
-
-func (r *policyRepository) FindByProjectID(ctx context.Context, tx *gorm.DB, projectID uuid.UUID) ([]models.Policy, error) {
- // we need to use the project_enabled_policies pivot table to get the policies for a project
- var policies []models.Policy
- if err := r.GetDB(ctx, tx).Joins("JOIN project_enabled_policies ON project_enabled_policies.policy_id = policies.id").
- Where("project_enabled_policies.project_id = ?", projectID).
- Find(&policies).Error; err != nil {
- return nil, err
- }
-
- return policies, nil
-}
-
-func (r *policyRepository) FindCommunityManagedPolicies(ctx context.Context, tx *gorm.DB) ([]models.Policy, error) {
- // where organization id is nil
- var policies []models.Policy
- if err := r.GetDB(ctx, tx).Where("organization_id IS NULL").Find(&policies).Error; err != nil {
- return nil, err
- }
- return policies, nil
-}
-
-func (r *policyRepository) FindByOrganizationID(ctx context.Context, tx *gorm.DB, organizationID uuid.UUID) ([]models.Policy, error) {
- var policies []models.Policy
- if err := r.GetDB(ctx, tx).Find(&policies, "organization_id = ?", organizationID).Error; err != nil {
- return nil, err
- }
- return policies, nil
-}
diff --git a/database/repositories/project_repository.go b/database/repositories/project_repository.go
index 9400464e1..b253d20cb 100644
--- a/database/repositories/project_repository.go
+++ b/database/repositories/project_repository.go
@@ -426,31 +426,6 @@ func (g *projectRepository) GetDirectChildProjects(ctx context.Context, tx *gorm
return projects, err
}
-func (g *projectRepository) EnablePolicyForProject(ctx context.Context, tx *gorm.DB, projectID uuid.UUID, policyID uuid.UUID) error {
- return g.GetDB(ctx, tx).Model(&models.Project{
- Model: models.Model{
- ID: projectID,
- },
- }).Association("EnabledPolicies").Append(&models.Policy{ID: policyID})
-}
-func (g *projectRepository) DisablePolicyForProject(ctx context.Context, tx *gorm.DB, projectID uuid.UUID, policyID uuid.UUID) error {
- return g.GetDB(ctx, tx).Model(&models.Project{
- Model: models.Model{
- ID: projectID,
- },
- }).Association("EnabledPolicies").Delete(&models.Policy{ID: policyID})
-}
-
-func (g *projectRepository) EnableCommunityManagedPolicies(ctx context.Context, tx *gorm.DB, projectID uuid.UUID) error {
- // community policies can be identified by their "organization_id" being nil
- return g.GetDB(ctx, tx).Exec(`
- INSERT INTO project_enabled_policies (project_id, policy_id)
- SELECT ?, id
- FROM policies
- WHERE organization_id IS NULL
- `, projectID).Error
-}
-
func (g *projectRepository) Create(ctx context.Context, tx *gorm.DB, project *models.Project) error {
// set the slug if not set
slug, err := g.firstFreeSlug(ctx, tx, project.OrganizationID, project.Slug)
diff --git a/database/repositories/providers.go b/database/repositories/providers.go
index 886db5816..0c57020f5 100644
--- a/database/repositories/providers.go
+++ b/database/repositories/providers.go
@@ -41,8 +41,8 @@ var Module = fx.Options(
fx.Provide(fx.Annotate(NewInTotoLinkRepository, fx.As(new(shared.InTotoLinkRepository)))),
fx.Provide(fx.Annotate(NewSupplyChainRepository, fx.As(new(shared.SupplyChainRepository)))),
fx.Provide(fx.Annotate(NewAttestationRepository, fx.As(new(shared.AttestationRepository)))),
- fx.Provide(fx.Annotate(NewPolicyRepository, fx.As(new(shared.PolicyRepository)))),
fx.Provide(fx.Annotate(NewLicenseRiskRepository, fx.As(new(shared.LicenseRiskRepository)))),
+ fx.Provide(fx.Annotate(NewComplianceRiskRepository, fx.As(new(shared.ComplianceRiskRepository)))),
fx.Provide(fx.Annotate(NewWebhookRepository, fx.As(new(shared.WebhookIntegrationRepository)))),
fx.Provide(fx.Annotate(NewArtifactRepository, fx.As(new(shared.ArtifactRepository)))),
fx.Provide(fx.Annotate(NewInvitationRepository, fx.As(new(shared.InvitationRepository)))),
diff --git a/dtos/compliance_risk_dto.go b/dtos/compliance_risk_dto.go
new file mode 100644
index 000000000..aa221045f
--- /dev/null
+++ b/dtos/compliance_risk_dto.go
@@ -0,0 +1,42 @@
+package dtos
+
+import (
+ "time"
+
+ "github.com/google/uuid"
+)
+
+type PolicyFrameworks struct {
+ Framework string `yaml:"framework" json:"framework"`
+ Controls []string `yaml:"controls" json:"controls"`
+}
+
+type ComplianceRiskDTO struct {
+ ID uuid.UUID `json:"id"`
+ AssetVersionName string `json:"assetVersionName"`
+ AssetID string `json:"assetId"`
+ Artifacts []ArtifactDTO `json:"artifacts,omitempty"`
+
+ PolicyID string `json:"policyId"`
+ PolicyTitle string `json:"policyTitle"`
+ PolicyDescription *string `json:"policyDescription"`
+ PolicyRelatedResources []string `json:"policyRelatedResources"`
+ PolicyTags []string `json:"policyTags"`
+ PolicyPriority int `json:"policyPriority"`
+ PolicyFrameworks []PolicyFrameworks `json:"policyFrameworks"`
+
+ State VulnState `json:"state"`
+ CreatedAt time.Time `json:"createdAt"`
+ TicketID *string `json:"ticketId"`
+ TicketURL *string `json:"ticketUrl"`
+ ManualTicketCreation bool `json:"manualTicketCreation"`
+
+ Message string `json:"message"`
+ EvidenceType string `json:"evidenceType"`
+ Violations []string `json:"violations"`
+}
+
+type DetailedComplianceRiskDTO struct {
+ ComplianceRiskDTO
+ Events []VulnEventDTO `json:"events"`
+}
diff --git a/dtos/devguard_asset_attestation_dto.go b/dtos/devguard_asset_attestation_dto.go
new file mode 100644
index 000000000..f29b607d9
--- /dev/null
+++ b/dtos/devguard_asset_attestation_dto.go
@@ -0,0 +1,34 @@
+package dtos
+
+import "time"
+
+// DevguardAssetAttestationPredicateType is the predicate type URI used when storing this attestation in the attestations table.
+const DevguardAssetAttestationPredicateType = "https://devguard.org/attestation/asset-metrics/v1"
+
+// DevguardAssetAttestationDTO represents a security attestation for an asset.
+// It captures measurable metrics about how quickly vulnerabilities are being addressed.
+type DevguardAssetAttestationDTO struct {
+ // Metadata
+ Type string `json:"type"`
+ GeneratedAt time.Time `json:"generatedAt"`
+ SchemaVersion string `json:"schemaVersion"`
+
+ // Average time (in hours) to close vulnerabilities, grouped by severity.
+ // Based on risk score classification.
+ MeanTimeToRemediate MeanTimeToRemediateDTO `json:"meanTimeToRemediate"`
+}
+
+// MeanTimeToRemediateDTO holds average remediation durations in hours, split by severity.
+type MeanTimeToRemediateDTO struct {
+ // Risk-based severity buckets (DevGuard risk score)
+ RiskLowAvgHours float64 `json:"riskLowAvgHours"`
+ RiskMediumAvgHours float64 `json:"riskMediumAvgHours"`
+ RiskHighAvgHours float64 `json:"riskHighAvgHours"`
+ RiskCriticalAvgHours float64 `json:"riskCriticalAvgHours"`
+
+ // CVSS-based severity buckets
+ CVSSLowAvgHours float64 `json:"cvssLowAvgHours"`
+ CVSSMediumAvgHours float64 `json:"cvsssMediumAvgHours"`
+ CVSSHighAvgHours float64 `json:"cvssHighAvgHours"`
+ CVSSCriticalAvgHours float64 `json:"cvssCriticalAvgHours"`
+}
diff --git a/dtos/devguard_asset_attestation_schema.json b/dtos/devguard_asset_attestation_schema.json
new file mode 100644
index 000000000..55df35f50
--- /dev/null
+++ b/dtos/devguard_asset_attestation_schema.json
@@ -0,0 +1,88 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://devguard.org/schemas/asset-attestation/v1",
+ "title": "DevguardAssetAttestation",
+ "description": "Security attestation for a DevGuard asset. Captures measurable metrics about how quickly vulnerabilities are being addressed.",
+ "type": "object",
+ "required": [
+ "type",
+ "generatedAt",
+ "schemaVersion",
+ "meanTimeToRemediate"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Predicate type URI identifying this attestation format.",
+ "const": "https://devguard.org/attestation/asset-metrics/v1"
+ },
+ "generatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "ISO 8601 timestamp when this attestation was generated."
+ },
+ "schemaVersion": {
+ "type": "string",
+ "description": "Version of the attestation schema (semver).",
+ "example": "1.0.0"
+ },
+ "meanTimeToRemediate": {
+ "type": "object",
+ "description": "Average time in hours to close (fix/accept/false-positive) vulnerabilities, grouped by severity.",
+ "required": [
+ "riskLowAvgHours",
+ "riskMediumAvgHours",
+ "riskHighAvgHours",
+ "riskCriticalAvgHours",
+ "cvssLowAvgHours",
+ "cvsssMediumAvgHours",
+ "cvssHighAvgHours",
+ "cvssCriticalAvgHours"
+ ],
+ "properties": {
+ "riskLowAvgHours": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Average hours to remediate low-risk vulnerabilities (DevGuard risk score)."
+ },
+ "riskMediumAvgHours": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Average hours to remediate medium-risk vulnerabilities (DevGuard risk score)."
+ },
+ "riskHighAvgHours": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Average hours to remediate high-risk vulnerabilities (DevGuard risk score)."
+ },
+ "riskCriticalAvgHours": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Average hours to remediate critical-risk vulnerabilities (DevGuard risk score)."
+ },
+ "cvssLowAvgHours": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Average hours to remediate low-CVSS vulnerabilities."
+ },
+ "cvssMediumAvgHours": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Average hours to remediate medium-CVSS vulnerabilities."
+ },
+ "cvssHighAvgHours": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Average hours to remediate high-CVSS vulnerabilities."
+ },
+ "cvssCriticalAvgHours": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Average hours to remediate critical-CVSS vulnerabilities."
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/dtos/policy_dto.go b/dtos/policy_dto.go
deleted file mode 100644
index 2a67d4981..000000000
--- a/dtos/policy_dto.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2025 l3montree UG (haftungsbeschraenkt)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-package dtos
-
-type PolicyDTO struct {
- Title string `json:"title"`
- Description string `json:"description"`
- Priority int `json:"priority"`
- PredicateType string `json:"predicateType"`
- Rego string `json:"rego"`
-}
diff --git a/dtos/vulnevent_dto.go b/dtos/vulnevent_dto.go
index 8ed1b7977..890fa79b4 100644
--- a/dtos/vulnevent_dto.go
+++ b/dtos/vulnevent_dto.go
@@ -14,6 +14,7 @@ const (
VulnTypeDependencyVuln VulnType = "dependencyVuln"
VulnTypeFirstPartyVuln VulnType = "firstPartyVuln"
VulnTypeLicenseRisk VulnType = "licenseRisk"
+ VulnTypeComplianceRisk VulnType = "complianceRisk"
)
const (
diff --git a/mocks/mock_AttestationRepository.go b/mocks/mock_AttestationRepository.go
index 6cd045a27..49cc07340 100644
--- a/mocks/mock_AttestationRepository.go
+++ b/mocks/mock_AttestationRepository.go
@@ -277,8 +277,8 @@ func (_c *AttestationRepository_CleanupOrphanedRecords_Call) RunAndReturn(run fu
}
// Create provides a mock function for the type AttestationRepository
-func (_mock *AttestationRepository) Create(ctx context.Context, tx shared.DB, t *models.Attestation) error {
- ret := _mock.Called(ctx, tx, t)
+func (_mock *AttestationRepository) Create(ctx context.Context, tx shared.DB, attestation *models.Attestation) error {
+ ret := _mock.Called(ctx, tx, attestation)
if len(ret) == 0 {
panic("no return value specified for Create")
@@ -286,7 +286,7 @@ func (_mock *AttestationRepository) Create(ctx context.Context, tx shared.DB, t
var r0 error
if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *models.Attestation) error); ok {
- r0 = returnFunc(ctx, tx, t)
+ r0 = returnFunc(ctx, tx, attestation)
} else {
r0 = ret.Error(0)
}
@@ -301,12 +301,12 @@ type AttestationRepository_Create_Call struct {
// Create is a helper method to define mock.On call
// - ctx context.Context
// - tx shared.DB
-// - t *models.Attestation
-func (_e *AttestationRepository_Expecter) Create(ctx interface{}, tx interface{}, t interface{}) *AttestationRepository_Create_Call {
- return &AttestationRepository_Create_Call{Call: _e.mock.On("Create", ctx, tx, t)}
+// - attestation *models.Attestation
+func (_e *AttestationRepository_Expecter) Create(ctx interface{}, tx interface{}, attestation interface{}) *AttestationRepository_Create_Call {
+ return &AttestationRepository_Create_Call{Call: _e.mock.On("Create", ctx, tx, attestation)}
}
-func (_c *AttestationRepository_Create_Call) Run(run func(ctx context.Context, tx shared.DB, t *models.Attestation)) *AttestationRepository_Create_Call {
+func (_c *AttestationRepository_Create_Call) Run(run func(ctx context.Context, tx shared.DB, attestation *models.Attestation)) *AttestationRepository_Create_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
@@ -334,7 +334,7 @@ func (_c *AttestationRepository_Create_Call) Return(err error) *AttestationRepos
return _c
}
-func (_c *AttestationRepository_Create_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, t *models.Attestation) error) *AttestationRepository_Create_Call {
+func (_c *AttestationRepository_Create_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, attestation *models.Attestation) error) *AttestationRepository_Create_Call {
_c.Call.Return(run)
return _c
}
@@ -528,6 +528,92 @@ func (_c *AttestationRepository_DeleteBatch_Call) RunAndReturn(run func(ctx cont
return _c
}
+// GetByArtifactAndAssetVersionAndAssetID provides a mock function for the type AttestationRepository
+func (_mock *AttestationRepository) GetByArtifactAndAssetVersionAndAssetID(ctx context.Context, tx shared.DB, artifactName string, assetVersion string, assetID uuid.UUID) ([]models.Attestation, error) {
+ ret := _mock.Called(ctx, tx, artifactName, assetVersion, assetID)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetByArtifactAndAssetVersionAndAssetID")
+ }
+
+ var r0 []models.Attestation
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, string, uuid.UUID) ([]models.Attestation, error)); ok {
+ return returnFunc(ctx, tx, artifactName, assetVersion, assetID)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, string, uuid.UUID) []models.Attestation); ok {
+ r0 = returnFunc(ctx, tx, artifactName, assetVersion, assetID)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]models.Attestation)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, string, string, uuid.UUID) error); ok {
+ r1 = returnFunc(ctx, tx, artifactName, assetVersion, assetID)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByArtifactAndAssetVersionAndAssetID'
+type AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call struct {
+ *mock.Call
+}
+
+// GetByArtifactAndAssetVersionAndAssetID is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - artifactName string
+// - assetVersion string
+// - assetID uuid.UUID
+func (_e *AttestationRepository_Expecter) GetByArtifactAndAssetVersionAndAssetID(ctx interface{}, tx interface{}, artifactName interface{}, assetVersion interface{}, assetID interface{}) *AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call {
+ return &AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call{Call: _e.mock.On("GetByArtifactAndAssetVersionAndAssetID", ctx, tx, artifactName, assetVersion, assetID)}
+}
+
+func (_c *AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call) Run(run func(ctx context.Context, tx shared.DB, artifactName string, assetVersion string, assetID uuid.UUID)) *AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 string
+ if args[2] != nil {
+ arg2 = args[2].(string)
+ }
+ var arg3 string
+ if args[3] != nil {
+ arg3 = args[3].(string)
+ }
+ var arg4 uuid.UUID
+ if args[4] != nil {
+ arg4 = args[4].(uuid.UUID)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ )
+ })
+ return _c
+}
+
+func (_c *AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call) Return(attestations []models.Attestation, err error) *AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call {
+ _c.Call.Return(attestations, err)
+ return _c
+}
+
+func (_c *AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, artifactName string, assetVersion string, assetID uuid.UUID) ([]models.Attestation, error)) *AttestationRepository_GetByArtifactAndAssetVersionAndAssetID_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// GetByAssetID provides a mock function for the type AttestationRepository
func (_mock *AttestationRepository) GetByAssetID(ctx context.Context, tx shared.DB, assetID uuid.UUID) ([]models.Attestation, error) {
ret := _mock.Called(ctx, tx, assetID)
diff --git a/mocks/mock_AttestationService.go b/mocks/mock_AttestationService.go
new file mode 100644
index 000000000..05b11ed52
--- /dev/null
+++ b/mocks/mock_AttestationService.go
@@ -0,0 +1,413 @@
+// Code generated by mockery; DO NOT EDIT.
+// github.com/vektra/mockery
+// template: testify
+
+package mocks
+
+import (
+ "context"
+
+ "github.com/google/uuid"
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/shared"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// NewAttestationService creates a new instance of AttestationService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewAttestationService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *AttestationService {
+ mock := &AttestationService{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
+
+// AttestationService is an autogenerated mock type for the AttestationService type
+type AttestationService struct {
+ mock.Mock
+}
+
+type AttestationService_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *AttestationService) EXPECT() *AttestationService_Expecter {
+ return &AttestationService_Expecter{mock: &_m.Mock}
+}
+
+// Create provides a mock function for the type AttestationService
+func (_mock *AttestationService) Create(ctx context.Context, tx shared.DB, attestation *models.Attestation) error {
+ ret := _mock.Called(ctx, tx, attestation)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Create")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *models.Attestation) error); ok {
+ r0 = returnFunc(ctx, tx, attestation)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// AttestationService_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create'
+type AttestationService_Create_Call struct {
+ *mock.Call
+}
+
+// Create is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - attestation *models.Attestation
+func (_e *AttestationService_Expecter) Create(ctx interface{}, tx interface{}, attestation interface{}) *AttestationService_Create_Call {
+ return &AttestationService_Create_Call{Call: _e.mock.On("Create", ctx, tx, attestation)}
+}
+
+func (_c *AttestationService_Create_Call) Run(run func(ctx context.Context, tx shared.DB, attestation *models.Attestation)) *AttestationService_Create_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 *models.Attestation
+ if args[2] != nil {
+ arg2 = args[2].(*models.Attestation)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *AttestationService_Create_Call) Return(err error) *AttestationService_Create_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *AttestationService_Create_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, attestation *models.Attestation) error) *AttestationService_Create_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GenerateAndStoreDevguardAttestation provides a mock function for the type AttestationService
+func (_mock *AttestationService) GenerateAndStoreDevguardAttestation(ctx context.Context, assetID uuid.UUID, assetVersionName string, artifactName string) error {
+ ret := _mock.Called(ctx, assetID, assetVersionName, artifactName)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GenerateAndStoreDevguardAttestation")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, string, string) error); ok {
+ r0 = returnFunc(ctx, assetID, assetVersionName, artifactName)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// AttestationService_GenerateAndStoreDevguardAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenerateAndStoreDevguardAttestation'
+type AttestationService_GenerateAndStoreDevguardAttestation_Call struct {
+ *mock.Call
+}
+
+// GenerateAndStoreDevguardAttestation is a helper method to define mock.On call
+// - ctx context.Context
+// - assetID uuid.UUID
+// - assetVersionName string
+// - artifactName string
+func (_e *AttestationService_Expecter) GenerateAndStoreDevguardAttestation(ctx interface{}, assetID interface{}, assetVersionName interface{}, artifactName interface{}) *AttestationService_GenerateAndStoreDevguardAttestation_Call {
+ return &AttestationService_GenerateAndStoreDevguardAttestation_Call{Call: _e.mock.On("GenerateAndStoreDevguardAttestation", ctx, assetID, assetVersionName, artifactName)}
+}
+
+func (_c *AttestationService_GenerateAndStoreDevguardAttestation_Call) Run(run func(ctx context.Context, assetID uuid.UUID, assetVersionName string, artifactName string)) *AttestationService_GenerateAndStoreDevguardAttestation_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 uuid.UUID
+ if args[1] != nil {
+ arg1 = args[1].(uuid.UUID)
+ }
+ var arg2 string
+ if args[2] != nil {
+ arg2 = args[2].(string)
+ }
+ var arg3 string
+ if args[3] != nil {
+ arg3 = args[3].(string)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ )
+ })
+ return _c
+}
+
+func (_c *AttestationService_GenerateAndStoreDevguardAttestation_Call) Return(err error) *AttestationService_GenerateAndStoreDevguardAttestation_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *AttestationService_GenerateAndStoreDevguardAttestation_Call) RunAndReturn(run func(ctx context.Context, assetID uuid.UUID, assetVersionName string, artifactName string) error) *AttestationService_GenerateAndStoreDevguardAttestation_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetByArtifactAndAssetVersionAndAssetID provides a mock function for the type AttestationService
+func (_mock *AttestationService) GetByArtifactAndAssetVersionAndAssetID(ctx context.Context, tx shared.DB, artifactName string, assetVersion string, assetID uuid.UUID) ([]models.Attestation, error) {
+ ret := _mock.Called(ctx, tx, artifactName, assetVersion, assetID)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetByArtifactAndAssetVersionAndAssetID")
+ }
+
+ var r0 []models.Attestation
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, string, uuid.UUID) ([]models.Attestation, error)); ok {
+ return returnFunc(ctx, tx, artifactName, assetVersion, assetID)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, string, uuid.UUID) []models.Attestation); ok {
+ r0 = returnFunc(ctx, tx, artifactName, assetVersion, assetID)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]models.Attestation)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, string, string, uuid.UUID) error); ok {
+ r1 = returnFunc(ctx, tx, artifactName, assetVersion, assetID)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByArtifactAndAssetVersionAndAssetID'
+type AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call struct {
+ *mock.Call
+}
+
+// GetByArtifactAndAssetVersionAndAssetID is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - artifactName string
+// - assetVersion string
+// - assetID uuid.UUID
+func (_e *AttestationService_Expecter) GetByArtifactAndAssetVersionAndAssetID(ctx interface{}, tx interface{}, artifactName interface{}, assetVersion interface{}, assetID interface{}) *AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call {
+ return &AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call{Call: _e.mock.On("GetByArtifactAndAssetVersionAndAssetID", ctx, tx, artifactName, assetVersion, assetID)}
+}
+
+func (_c *AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call) Run(run func(ctx context.Context, tx shared.DB, artifactName string, assetVersion string, assetID uuid.UUID)) *AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 string
+ if args[2] != nil {
+ arg2 = args[2].(string)
+ }
+ var arg3 string
+ if args[3] != nil {
+ arg3 = args[3].(string)
+ }
+ var arg4 uuid.UUID
+ if args[4] != nil {
+ arg4 = args[4].(uuid.UUID)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ )
+ })
+ return _c
+}
+
+func (_c *AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call) Return(attestations []models.Attestation, err error) *AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call {
+ _c.Call.Return(attestations, err)
+ return _c
+}
+
+func (_c *AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, artifactName string, assetVersion string, assetID uuid.UUID) ([]models.Attestation, error)) *AttestationService_GetByArtifactAndAssetVersionAndAssetID_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetByAssetID provides a mock function for the type AttestationService
+func (_mock *AttestationService) GetByAssetID(ctx context.Context, tx shared.DB, assetID uuid.UUID) ([]models.Attestation, error) {
+ ret := _mock.Called(ctx, tx, assetID)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetByAssetID")
+ }
+
+ var r0 []models.Attestation
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) ([]models.Attestation, error)); ok {
+ return returnFunc(ctx, tx, assetID)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) []models.Attestation); ok {
+ r0 = returnFunc(ctx, tx, assetID)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]models.Attestation)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID) error); ok {
+ r1 = returnFunc(ctx, tx, assetID)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// AttestationService_GetByAssetID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByAssetID'
+type AttestationService_GetByAssetID_Call struct {
+ *mock.Call
+}
+
+// GetByAssetID is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - assetID uuid.UUID
+func (_e *AttestationService_Expecter) GetByAssetID(ctx interface{}, tx interface{}, assetID interface{}) *AttestationService_GetByAssetID_Call {
+ return &AttestationService_GetByAssetID_Call{Call: _e.mock.On("GetByAssetID", ctx, tx, assetID)}
+}
+
+func (_c *AttestationService_GetByAssetID_Call) Run(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID)) *AttestationService_GetByAssetID_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].(uuid.UUID)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *AttestationService_GetByAssetID_Call) Return(attestations []models.Attestation, err error) *AttestationService_GetByAssetID_Call {
+ _c.Call.Return(attestations, err)
+ return _c
+}
+
+func (_c *AttestationService_GetByAssetID_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID) ([]models.Attestation, error)) *AttestationService_GetByAssetID_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetByAssetVersionAndAssetID provides a mock function for the type AttestationService
+func (_mock *AttestationService) GetByAssetVersionAndAssetID(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersion string) ([]models.Attestation, error) {
+ ret := _mock.Called(ctx, tx, assetID, assetVersion)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetByAssetVersionAndAssetID")
+ }
+
+ var r0 []models.Attestation
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, string) ([]models.Attestation, error)); ok {
+ return returnFunc(ctx, tx, assetID, assetVersion)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, string) []models.Attestation); ok {
+ r0 = returnFunc(ctx, tx, assetID, assetVersion)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]models.Attestation)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID, string) error); ok {
+ r1 = returnFunc(ctx, tx, assetID, assetVersion)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// AttestationService_GetByAssetVersionAndAssetID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByAssetVersionAndAssetID'
+type AttestationService_GetByAssetVersionAndAssetID_Call struct {
+ *mock.Call
+}
+
+// GetByAssetVersionAndAssetID is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - assetID uuid.UUID
+// - assetVersion string
+func (_e *AttestationService_Expecter) GetByAssetVersionAndAssetID(ctx interface{}, tx interface{}, assetID interface{}, assetVersion interface{}) *AttestationService_GetByAssetVersionAndAssetID_Call {
+ return &AttestationService_GetByAssetVersionAndAssetID_Call{Call: _e.mock.On("GetByAssetVersionAndAssetID", ctx, tx, assetID, assetVersion)}
+}
+
+func (_c *AttestationService_GetByAssetVersionAndAssetID_Call) Run(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersion string)) *AttestationService_GetByAssetVersionAndAssetID_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].(uuid.UUID)
+ }
+ var arg3 string
+ if args[3] != nil {
+ arg3 = args[3].(string)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ )
+ })
+ return _c
+}
+
+func (_c *AttestationService_GetByAssetVersionAndAssetID_Call) Return(attestations []models.Attestation, err error) *AttestationService_GetByAssetVersionAndAssetID_Call {
+ _c.Call.Return(attestations, err)
+ return _c
+}
+
+func (_c *AttestationService_GetByAssetVersionAndAssetID_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersion string) ([]models.Attestation, error)) *AttestationService_GetByAssetVersionAndAssetID_Call {
+ _c.Call.Return(run)
+ return _c
+}
diff --git a/mocks/mock_ComplianceRiskRepository.go b/mocks/mock_ComplianceRiskRepository.go
new file mode 100644
index 000000000..2c96a1284
--- /dev/null
+++ b/mocks/mock_ComplianceRiskRepository.go
@@ -0,0 +1,1466 @@
+// Code generated by mockery; DO NOT EDIT.
+// github.com/vektra/mockery
+// template: testify
+
+package mocks
+
+import (
+ "context"
+
+ "github.com/google/uuid"
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/shared"
+ mock "github.com/stretchr/testify/mock"
+ "gorm.io/gorm/clause"
+)
+
+// NewComplianceRiskRepository creates a new instance of ComplianceRiskRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewComplianceRiskRepository(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ComplianceRiskRepository {
+ mock := &ComplianceRiskRepository{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
+
+// ComplianceRiskRepository is an autogenerated mock type for the ComplianceRiskRepository type
+type ComplianceRiskRepository struct {
+ mock.Mock
+}
+
+type ComplianceRiskRepository_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ComplianceRiskRepository) EXPECT() *ComplianceRiskRepository_Expecter {
+ return &ComplianceRiskRepository_Expecter{mock: &_m.Mock}
+}
+
+// Activate provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) Activate(ctx context.Context, tx shared.DB, id uuid.UUID) error {
+ ret := _mock.Called(ctx, tx, id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Activate")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) error); ok {
+ r0 = returnFunc(ctx, tx, id)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_Activate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Activate'
+type ComplianceRiskRepository_Activate_Call struct {
+ *mock.Call
+}
+
+// Activate is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - id uuid.UUID
+func (_e *ComplianceRiskRepository_Expecter) Activate(ctx interface{}, tx interface{}, id interface{}) *ComplianceRiskRepository_Activate_Call {
+ return &ComplianceRiskRepository_Activate_Call{Call: _e.mock.On("Activate", ctx, tx, id)}
+}
+
+func (_c *ComplianceRiskRepository_Activate_Call) Run(run func(ctx context.Context, tx shared.DB, id uuid.UUID)) *ComplianceRiskRepository_Activate_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].(uuid.UUID)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Activate_Call) Return(err error) *ComplianceRiskRepository_Activate_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Activate_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, id uuid.UUID) error) *ComplianceRiskRepository_Activate_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// All provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) All(ctx context.Context, tx shared.DB) ([]models.ComplianceRisk, error) {
+ ret := _mock.Called(ctx, tx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for All")
+ }
+
+ var r0 []models.ComplianceRisk
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB) ([]models.ComplianceRisk, error)); ok {
+ return returnFunc(ctx, tx)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB) []models.ComplianceRisk); ok {
+ r0 = returnFunc(ctx, tx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]models.ComplianceRisk)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB) error); ok {
+ r1 = returnFunc(ctx, tx)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceRiskRepository_All_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'All'
+type ComplianceRiskRepository_All_Call struct {
+ *mock.Call
+}
+
+// All is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+func (_e *ComplianceRiskRepository_Expecter) All(ctx interface{}, tx interface{}) *ComplianceRiskRepository_All_Call {
+ return &ComplianceRiskRepository_All_Call{Call: _e.mock.On("All", ctx, tx)}
+}
+
+func (_c *ComplianceRiskRepository_All_Call) Run(run func(ctx context.Context, tx shared.DB)) *ComplianceRiskRepository_All_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ run(
+ arg0,
+ arg1,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_All_Call) Return(complianceRisks []models.ComplianceRisk, err error) *ComplianceRiskRepository_All_Call {
+ _c.Call.Return(complianceRisks, err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_All_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB) ([]models.ComplianceRisk, error)) *ComplianceRiskRepository_All_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ApplyAndSave provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) ApplyAndSave(ctx context.Context, tx shared.DB, risk *models.ComplianceRisk, ev *models.VulnEvent) error {
+ ret := _mock.Called(ctx, tx, risk, ev)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ApplyAndSave")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *models.ComplianceRisk, *models.VulnEvent) error); ok {
+ r0 = returnFunc(ctx, tx, risk, ev)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_ApplyAndSave_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyAndSave'
+type ComplianceRiskRepository_ApplyAndSave_Call struct {
+ *mock.Call
+}
+
+// ApplyAndSave is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - risk *models.ComplianceRisk
+// - ev *models.VulnEvent
+func (_e *ComplianceRiskRepository_Expecter) ApplyAndSave(ctx interface{}, tx interface{}, risk interface{}, ev interface{}) *ComplianceRiskRepository_ApplyAndSave_Call {
+ return &ComplianceRiskRepository_ApplyAndSave_Call{Call: _e.mock.On("ApplyAndSave", ctx, tx, risk, ev)}
+}
+
+func (_c *ComplianceRiskRepository_ApplyAndSave_Call) Run(run func(ctx context.Context, tx shared.DB, risk *models.ComplianceRisk, ev *models.VulnEvent)) *ComplianceRiskRepository_ApplyAndSave_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 *models.ComplianceRisk
+ if args[2] != nil {
+ arg2 = args[2].(*models.ComplianceRisk)
+ }
+ var arg3 *models.VulnEvent
+ if args[3] != nil {
+ arg3 = args[3].(*models.VulnEvent)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_ApplyAndSave_Call) Return(err error) *ComplianceRiskRepository_ApplyAndSave_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_ApplyAndSave_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, risk *models.ComplianceRisk, ev *models.VulnEvent) error) *ComplianceRiskRepository_ApplyAndSave_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Begin provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) Begin(ctx context.Context) shared.DB {
+ ret := _mock.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Begin")
+ }
+
+ var r0 shared.DB
+ if returnFunc, ok := ret.Get(0).(func(context.Context) shared.DB); ok {
+ r0 = returnFunc(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(shared.DB)
+ }
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_Begin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Begin'
+type ComplianceRiskRepository_Begin_Call struct {
+ *mock.Call
+}
+
+// Begin is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *ComplianceRiskRepository_Expecter) Begin(ctx interface{}) *ComplianceRiskRepository_Begin_Call {
+ return &ComplianceRiskRepository_Begin_Call{Call: _e.mock.On("Begin", ctx)}
+}
+
+func (_c *ComplianceRiskRepository_Begin_Call) Run(run func(ctx context.Context)) *ComplianceRiskRepository_Begin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ run(
+ arg0,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Begin_Call) Return(v shared.DB) *ComplianceRiskRepository_Begin_Call {
+ _c.Call.Return(v)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Begin_Call) RunAndReturn(run func(ctx context.Context) shared.DB) *ComplianceRiskRepository_Begin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CleanupOrphanedRecords provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) CleanupOrphanedRecords(ctx context.Context) error {
+ ret := _mock.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CleanupOrphanedRecords")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = returnFunc(ctx)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_CleanupOrphanedRecords_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CleanupOrphanedRecords'
+type ComplianceRiskRepository_CleanupOrphanedRecords_Call struct {
+ *mock.Call
+}
+
+// CleanupOrphanedRecords is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *ComplianceRiskRepository_Expecter) CleanupOrphanedRecords(ctx interface{}) *ComplianceRiskRepository_CleanupOrphanedRecords_Call {
+ return &ComplianceRiskRepository_CleanupOrphanedRecords_Call{Call: _e.mock.On("CleanupOrphanedRecords", ctx)}
+}
+
+func (_c *ComplianceRiskRepository_CleanupOrphanedRecords_Call) Run(run func(ctx context.Context)) *ComplianceRiskRepository_CleanupOrphanedRecords_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ run(
+ arg0,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_CleanupOrphanedRecords_Call) Return(err error) *ComplianceRiskRepository_CleanupOrphanedRecords_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_CleanupOrphanedRecords_Call) RunAndReturn(run func(ctx context.Context) error) *ComplianceRiskRepository_CleanupOrphanedRecords_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Create provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) Create(ctx context.Context, tx shared.DB, t *models.ComplianceRisk) error {
+ ret := _mock.Called(ctx, tx, t)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Create")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *models.ComplianceRisk) error); ok {
+ r0 = returnFunc(ctx, tx, t)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create'
+type ComplianceRiskRepository_Create_Call struct {
+ *mock.Call
+}
+
+// Create is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - t *models.ComplianceRisk
+func (_e *ComplianceRiskRepository_Expecter) Create(ctx interface{}, tx interface{}, t interface{}) *ComplianceRiskRepository_Create_Call {
+ return &ComplianceRiskRepository_Create_Call{Call: _e.mock.On("Create", ctx, tx, t)}
+}
+
+func (_c *ComplianceRiskRepository_Create_Call) Run(run func(ctx context.Context, tx shared.DB, t *models.ComplianceRisk)) *ComplianceRiskRepository_Create_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 *models.ComplianceRisk
+ if args[2] != nil {
+ arg2 = args[2].(*models.ComplianceRisk)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Create_Call) Return(err error) *ComplianceRiskRepository_Create_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Create_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, t *models.ComplianceRisk) error) *ComplianceRiskRepository_Create_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CreateBatch provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) CreateBatch(ctx context.Context, tx shared.DB, ts []models.ComplianceRisk) error {
+ ret := _mock.Called(ctx, tx, ts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CreateBatch")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []models.ComplianceRisk) error); ok {
+ r0 = returnFunc(ctx, tx, ts)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_CreateBatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateBatch'
+type ComplianceRiskRepository_CreateBatch_Call struct {
+ *mock.Call
+}
+
+// CreateBatch is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - ts []models.ComplianceRisk
+func (_e *ComplianceRiskRepository_Expecter) CreateBatch(ctx interface{}, tx interface{}, ts interface{}) *ComplianceRiskRepository_CreateBatch_Call {
+ return &ComplianceRiskRepository_CreateBatch_Call{Call: _e.mock.On("CreateBatch", ctx, tx, ts)}
+}
+
+func (_c *ComplianceRiskRepository_CreateBatch_Call) Run(run func(ctx context.Context, tx shared.DB, ts []models.ComplianceRisk)) *ComplianceRiskRepository_CreateBatch_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 []models.ComplianceRisk
+ if args[2] != nil {
+ arg2 = args[2].([]models.ComplianceRisk)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_CreateBatch_Call) Return(err error) *ComplianceRiskRepository_CreateBatch_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_CreateBatch_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ts []models.ComplianceRisk) error) *ComplianceRiskRepository_CreateBatch_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Delete provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) Delete(ctx context.Context, tx shared.DB, id uuid.UUID) error {
+ ret := _mock.Called(ctx, tx, id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Delete")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) error); ok {
+ r0 = returnFunc(ctx, tx, id)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
+type ComplianceRiskRepository_Delete_Call struct {
+ *mock.Call
+}
+
+// Delete is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - id uuid.UUID
+func (_e *ComplianceRiskRepository_Expecter) Delete(ctx interface{}, tx interface{}, id interface{}) *ComplianceRiskRepository_Delete_Call {
+ return &ComplianceRiskRepository_Delete_Call{Call: _e.mock.On("Delete", ctx, tx, id)}
+}
+
+func (_c *ComplianceRiskRepository_Delete_Call) Run(run func(ctx context.Context, tx shared.DB, id uuid.UUID)) *ComplianceRiskRepository_Delete_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].(uuid.UUID)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Delete_Call) Return(err error) *ComplianceRiskRepository_Delete_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Delete_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, id uuid.UUID) error) *ComplianceRiskRepository_Delete_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// DeleteBatch provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) DeleteBatch(ctx context.Context, tx shared.DB, ids []models.ComplianceRisk) error {
+ ret := _mock.Called(ctx, tx, ids)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DeleteBatch")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []models.ComplianceRisk) error); ok {
+ r0 = returnFunc(ctx, tx, ids)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_DeleteBatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteBatch'
+type ComplianceRiskRepository_DeleteBatch_Call struct {
+ *mock.Call
+}
+
+// DeleteBatch is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - ids []models.ComplianceRisk
+func (_e *ComplianceRiskRepository_Expecter) DeleteBatch(ctx interface{}, tx interface{}, ids interface{}) *ComplianceRiskRepository_DeleteBatch_Call {
+ return &ComplianceRiskRepository_DeleteBatch_Call{Call: _e.mock.On("DeleteBatch", ctx, tx, ids)}
+}
+
+func (_c *ComplianceRiskRepository_DeleteBatch_Call) Run(run func(ctx context.Context, tx shared.DB, ids []models.ComplianceRisk)) *ComplianceRiskRepository_DeleteBatch_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 []models.ComplianceRisk
+ if args[2] != nil {
+ arg2 = args[2].([]models.ComplianceRisk)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_DeleteBatch_Call) Return(err error) *ComplianceRiskRepository_DeleteBatch_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_DeleteBatch_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ids []models.ComplianceRisk) error) *ComplianceRiskRepository_DeleteBatch_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetAllComplianceRisksForAssetVersion provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) GetAllComplianceRisksForAssetVersion(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string) ([]models.ComplianceRisk, error) {
+ ret := _mock.Called(ctx, tx, assetID, assetVersionName)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetAllComplianceRisksForAssetVersion")
+ }
+
+ var r0 []models.ComplianceRisk
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, string) ([]models.ComplianceRisk, error)); ok {
+ return returnFunc(ctx, tx, assetID, assetVersionName)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, string) []models.ComplianceRisk); ok {
+ r0 = returnFunc(ctx, tx, assetID, assetVersionName)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]models.ComplianceRisk)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID, string) error); ok {
+ r1 = returnFunc(ctx, tx, assetID, assetVersionName)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllComplianceRisksForAssetVersion'
+type ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call struct {
+ *mock.Call
+}
+
+// GetAllComplianceRisksForAssetVersion is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - assetID uuid.UUID
+// - assetVersionName string
+func (_e *ComplianceRiskRepository_Expecter) GetAllComplianceRisksForAssetVersion(ctx interface{}, tx interface{}, assetID interface{}, assetVersionName interface{}) *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call {
+ return &ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call{Call: _e.mock.On("GetAllComplianceRisksForAssetVersion", ctx, tx, assetID, assetVersionName)}
+}
+
+func (_c *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call) Run(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string)) *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].(uuid.UUID)
+ }
+ var arg3 string
+ if args[3] != nil {
+ arg3 = args[3].(string)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call) Return(complianceRisks []models.ComplianceRisk, err error) *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call {
+ _c.Call.Return(complianceRisks, err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string) ([]models.ComplianceRisk, error)) *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetAllComplianceRisksForAssetVersionPaged provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) GetAllComplianceRisksForAssetVersionPaged(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string, pageInfo shared.PageInfo, search string, filter []shared.FilterQuery, sort []shared.SortQuery) (shared.Paged[models.ComplianceRisk], error) {
+ ret := _mock.Called(ctx, tx, assetID, assetVersionName, pageInfo, search, filter, sort)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetAllComplianceRisksForAssetVersionPaged")
+ }
+
+ var r0 shared.Paged[models.ComplianceRisk]
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, string, shared.PageInfo, string, []shared.FilterQuery, []shared.SortQuery) (shared.Paged[models.ComplianceRisk], error)); ok {
+ return returnFunc(ctx, tx, assetID, assetVersionName, pageInfo, search, filter, sort)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, string, shared.PageInfo, string, []shared.FilterQuery, []shared.SortQuery) shared.Paged[models.ComplianceRisk]); ok {
+ r0 = returnFunc(ctx, tx, assetID, assetVersionName, pageInfo, search, filter, sort)
+ } else {
+ r0 = ret.Get(0).(shared.Paged[models.ComplianceRisk])
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID, string, shared.PageInfo, string, []shared.FilterQuery, []shared.SortQuery) error); ok {
+ r1 = returnFunc(ctx, tx, assetID, assetVersionName, pageInfo, search, filter, sort)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllComplianceRisksForAssetVersionPaged'
+type ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call struct {
+ *mock.Call
+}
+
+// GetAllComplianceRisksForAssetVersionPaged is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - assetID uuid.UUID
+// - assetVersionName string
+// - pageInfo shared.PageInfo
+// - search string
+// - filter []shared.FilterQuery
+// - sort []shared.SortQuery
+func (_e *ComplianceRiskRepository_Expecter) GetAllComplianceRisksForAssetVersionPaged(ctx interface{}, tx interface{}, assetID interface{}, assetVersionName interface{}, pageInfo interface{}, search interface{}, filter interface{}, sort interface{}) *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call {
+ return &ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call{Call: _e.mock.On("GetAllComplianceRisksForAssetVersionPaged", ctx, tx, assetID, assetVersionName, pageInfo, search, filter, sort)}
+}
+
+func (_c *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call) Run(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string, pageInfo shared.PageInfo, search string, filter []shared.FilterQuery, sort []shared.SortQuery)) *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].(uuid.UUID)
+ }
+ var arg3 string
+ if args[3] != nil {
+ arg3 = args[3].(string)
+ }
+ var arg4 shared.PageInfo
+ if args[4] != nil {
+ arg4 = args[4].(shared.PageInfo)
+ }
+ var arg5 string
+ if args[5] != nil {
+ arg5 = args[5].(string)
+ }
+ var arg6 []shared.FilterQuery
+ if args[6] != nil {
+ arg6 = args[6].([]shared.FilterQuery)
+ }
+ var arg7 []shared.SortQuery
+ if args[7] != nil {
+ arg7 = args[7].([]shared.SortQuery)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ arg5,
+ arg6,
+ arg7,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call) Return(paged shared.Paged[models.ComplianceRisk], err error) *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call {
+ _c.Call.Return(paged, err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string, pageInfo shared.PageInfo, search string, filter []shared.FilterQuery, sort []shared.SortQuery) (shared.Paged[models.ComplianceRisk], error)) *ComplianceRiskRepository_GetAllComplianceRisksForAssetVersionPaged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetComplianceRisksByOtherAssetVersions provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) GetComplianceRisksByOtherAssetVersions(ctx context.Context, tx shared.DB, assetVersionName string, assetID uuid.UUID) ([]models.ComplianceRisk, error) {
+ ret := _mock.Called(ctx, tx, assetVersionName, assetID)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetComplianceRisksByOtherAssetVersions")
+ }
+
+ var r0 []models.ComplianceRisk
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, uuid.UUID) ([]models.ComplianceRisk, error)); ok {
+ return returnFunc(ctx, tx, assetVersionName, assetID)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, uuid.UUID) []models.ComplianceRisk); ok {
+ r0 = returnFunc(ctx, tx, assetVersionName, assetID)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]models.ComplianceRisk)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, string, uuid.UUID) error); ok {
+ r1 = returnFunc(ctx, tx, assetVersionName, assetID)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetComplianceRisksByOtherAssetVersions'
+type ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call struct {
+ *mock.Call
+}
+
+// GetComplianceRisksByOtherAssetVersions is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - assetVersionName string
+// - assetID uuid.UUID
+func (_e *ComplianceRiskRepository_Expecter) GetComplianceRisksByOtherAssetVersions(ctx interface{}, tx interface{}, assetVersionName interface{}, assetID interface{}) *ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call {
+ return &ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call{Call: _e.mock.On("GetComplianceRisksByOtherAssetVersions", ctx, tx, assetVersionName, assetID)}
+}
+
+func (_c *ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call) Run(run func(ctx context.Context, tx shared.DB, assetVersionName string, assetID uuid.UUID)) *ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 string
+ if args[2] != nil {
+ arg2 = args[2].(string)
+ }
+ var arg3 uuid.UUID
+ if args[3] != nil {
+ arg3 = args[3].(uuid.UUID)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call) Return(complianceRisks []models.ComplianceRisk, err error) *ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call {
+ _c.Call.Return(complianceRisks, err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, assetVersionName string, assetID uuid.UUID) ([]models.ComplianceRisk, error)) *ComplianceRiskRepository_GetComplianceRisksByOtherAssetVersions_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDB provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) GetDB(ctx context.Context, tx shared.DB) shared.DB {
+ ret := _mock.Called(ctx, tx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDB")
+ }
+
+ var r0 shared.DB
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB) shared.DB); ok {
+ r0 = returnFunc(ctx, tx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(shared.DB)
+ }
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_GetDB_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDB'
+type ComplianceRiskRepository_GetDB_Call struct {
+ *mock.Call
+}
+
+// GetDB is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+func (_e *ComplianceRiskRepository_Expecter) GetDB(ctx interface{}, tx interface{}) *ComplianceRiskRepository_GetDB_Call {
+ return &ComplianceRiskRepository_GetDB_Call{Call: _e.mock.On("GetDB", ctx, tx)}
+}
+
+func (_c *ComplianceRiskRepository_GetDB_Call) Run(run func(ctx context.Context, tx shared.DB)) *ComplianceRiskRepository_GetDB_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ run(
+ arg0,
+ arg1,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetDB_Call) Return(v shared.DB) *ComplianceRiskRepository_GetDB_Call {
+ _c.Call.Return(v)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetDB_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB) shared.DB) *ComplianceRiskRepository_GetDB_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDistinctFrameworksForAssetVersion provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) GetDistinctFrameworksForAssetVersion(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string) ([]string, error) {
+ ret := _mock.Called(ctx, tx, assetID, assetVersionName)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDistinctFrameworksForAssetVersion")
+ }
+
+ var r0 []string
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, string) ([]string, error)); ok {
+ return returnFunc(ctx, tx, assetID, assetVersionName)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, string) []string); ok {
+ r0 = returnFunc(ctx, tx, assetID, assetVersionName)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]string)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID, string) error); ok {
+ r1 = returnFunc(ctx, tx, assetID, assetVersionName)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDistinctFrameworksForAssetVersion'
+type ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call struct {
+ *mock.Call
+}
+
+// GetDistinctFrameworksForAssetVersion is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - assetID uuid.UUID
+// - assetVersionName string
+func (_e *ComplianceRiskRepository_Expecter) GetDistinctFrameworksForAssetVersion(ctx interface{}, tx interface{}, assetID interface{}, assetVersionName interface{}) *ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call {
+ return &ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call{Call: _e.mock.On("GetDistinctFrameworksForAssetVersion", ctx, tx, assetID, assetVersionName)}
+}
+
+func (_c *ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call) Run(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string)) *ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].(uuid.UUID)
+ }
+ var arg3 string
+ if args[3] != nil {
+ arg3 = args[3].(string)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call) Return(strings []string, err error) *ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call {
+ _c.Call.Return(strings, err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersionName string) ([]string, error)) *ComplianceRiskRepository_GetDistinctFrameworksForAssetVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// List provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) List(ctx context.Context, tx shared.DB, ids []uuid.UUID) ([]models.ComplianceRisk, error) {
+ ret := _mock.Called(ctx, tx, ids)
+
+ if len(ret) == 0 {
+ panic("no return value specified for List")
+ }
+
+ var r0 []models.ComplianceRisk
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []uuid.UUID) ([]models.ComplianceRisk, error)); ok {
+ return returnFunc(ctx, tx, ids)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []uuid.UUID) []models.ComplianceRisk); ok {
+ r0 = returnFunc(ctx, tx, ids)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]models.ComplianceRisk)
+ }
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, []uuid.UUID) error); ok {
+ r1 = returnFunc(ctx, tx, ids)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceRiskRepository_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List'
+type ComplianceRiskRepository_List_Call struct {
+ *mock.Call
+}
+
+// List is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - ids []uuid.UUID
+func (_e *ComplianceRiskRepository_Expecter) List(ctx interface{}, tx interface{}, ids interface{}) *ComplianceRiskRepository_List_Call {
+ return &ComplianceRiskRepository_List_Call{Call: _e.mock.On("List", ctx, tx, ids)}
+}
+
+func (_c *ComplianceRiskRepository_List_Call) Run(run func(ctx context.Context, tx shared.DB, ids []uuid.UUID)) *ComplianceRiskRepository_List_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 []uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].([]uuid.UUID)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_List_Call) Return(complianceRisks []models.ComplianceRisk, err error) *ComplianceRiskRepository_List_Call {
+ _c.Call.Return(complianceRisks, err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_List_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ids []uuid.UUID) ([]models.ComplianceRisk, error)) *ComplianceRiskRepository_List_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Read provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) Read(ctx context.Context, tx shared.DB, id uuid.UUID) (models.ComplianceRisk, error) {
+ ret := _mock.Called(ctx, tx, id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Read")
+ }
+
+ var r0 models.ComplianceRisk
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) (models.ComplianceRisk, error)); ok {
+ return returnFunc(ctx, tx, id)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) models.ComplianceRisk); ok {
+ r0 = returnFunc(ctx, tx, id)
+ } else {
+ r0 = ret.Get(0).(models.ComplianceRisk)
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID) error); ok {
+ r1 = returnFunc(ctx, tx, id)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceRiskRepository_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read'
+type ComplianceRiskRepository_Read_Call struct {
+ *mock.Call
+}
+
+// Read is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - id uuid.UUID
+func (_e *ComplianceRiskRepository_Expecter) Read(ctx interface{}, tx interface{}, id interface{}) *ComplianceRiskRepository_Read_Call {
+ return &ComplianceRiskRepository_Read_Call{Call: _e.mock.On("Read", ctx, tx, id)}
+}
+
+func (_c *ComplianceRiskRepository_Read_Call) Run(run func(ctx context.Context, tx shared.DB, id uuid.UUID)) *ComplianceRiskRepository_Read_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 uuid.UUID
+ if args[2] != nil {
+ arg2 = args[2].(uuid.UUID)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Read_Call) Return(complianceRisk models.ComplianceRisk, err error) *ComplianceRiskRepository_Read_Call {
+ _c.Call.Return(complianceRisk, err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Read_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, id uuid.UUID) (models.ComplianceRisk, error)) *ComplianceRiskRepository_Read_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Save provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) Save(ctx context.Context, tx shared.DB, t *models.ComplianceRisk) error {
+ ret := _mock.Called(ctx, tx, t)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Save")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *models.ComplianceRisk) error); ok {
+ r0 = returnFunc(ctx, tx, t)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_Save_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Save'
+type ComplianceRiskRepository_Save_Call struct {
+ *mock.Call
+}
+
+// Save is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - t *models.ComplianceRisk
+func (_e *ComplianceRiskRepository_Expecter) Save(ctx interface{}, tx interface{}, t interface{}) *ComplianceRiskRepository_Save_Call {
+ return &ComplianceRiskRepository_Save_Call{Call: _e.mock.On("Save", ctx, tx, t)}
+}
+
+func (_c *ComplianceRiskRepository_Save_Call) Run(run func(ctx context.Context, tx shared.DB, t *models.ComplianceRisk)) *ComplianceRiskRepository_Save_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 *models.ComplianceRisk
+ if args[2] != nil {
+ arg2 = args[2].(*models.ComplianceRisk)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Save_Call) Return(err error) *ComplianceRiskRepository_Save_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Save_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, t *models.ComplianceRisk) error) *ComplianceRiskRepository_Save_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SaveBatch provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) SaveBatch(ctx context.Context, tx shared.DB, risks []models.ComplianceRisk) error {
+ ret := _mock.Called(ctx, tx, risks)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SaveBatch")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []models.ComplianceRisk) error); ok {
+ r0 = returnFunc(ctx, tx, risks)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_SaveBatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveBatch'
+type ComplianceRiskRepository_SaveBatch_Call struct {
+ *mock.Call
+}
+
+// SaveBatch is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - risks []models.ComplianceRisk
+func (_e *ComplianceRiskRepository_Expecter) SaveBatch(ctx interface{}, tx interface{}, risks interface{}) *ComplianceRiskRepository_SaveBatch_Call {
+ return &ComplianceRiskRepository_SaveBatch_Call{Call: _e.mock.On("SaveBatch", ctx, tx, risks)}
+}
+
+func (_c *ComplianceRiskRepository_SaveBatch_Call) Run(run func(ctx context.Context, tx shared.DB, risks []models.ComplianceRisk)) *ComplianceRiskRepository_SaveBatch_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 []models.ComplianceRisk
+ if args[2] != nil {
+ arg2 = args[2].([]models.ComplianceRisk)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_SaveBatch_Call) Return(err error) *ComplianceRiskRepository_SaveBatch_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_SaveBatch_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, risks []models.ComplianceRisk) error) *ComplianceRiskRepository_SaveBatch_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SaveBatchBestEffort provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) SaveBatchBestEffort(ctx context.Context, tx shared.DB, ts []models.ComplianceRisk) error {
+ ret := _mock.Called(ctx, tx, ts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SaveBatchBestEffort")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []models.ComplianceRisk) error); ok {
+ r0 = returnFunc(ctx, tx, ts)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_SaveBatchBestEffort_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveBatchBestEffort'
+type ComplianceRiskRepository_SaveBatchBestEffort_Call struct {
+ *mock.Call
+}
+
+// SaveBatchBestEffort is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - ts []models.ComplianceRisk
+func (_e *ComplianceRiskRepository_Expecter) SaveBatchBestEffort(ctx interface{}, tx interface{}, ts interface{}) *ComplianceRiskRepository_SaveBatchBestEffort_Call {
+ return &ComplianceRiskRepository_SaveBatchBestEffort_Call{Call: _e.mock.On("SaveBatchBestEffort", ctx, tx, ts)}
+}
+
+func (_c *ComplianceRiskRepository_SaveBatchBestEffort_Call) Run(run func(ctx context.Context, tx shared.DB, ts []models.ComplianceRisk)) *ComplianceRiskRepository_SaveBatchBestEffort_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 []models.ComplianceRisk
+ if args[2] != nil {
+ arg2 = args[2].([]models.ComplianceRisk)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_SaveBatchBestEffort_Call) Return(err error) *ComplianceRiskRepository_SaveBatchBestEffort_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_SaveBatchBestEffort_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ts []models.ComplianceRisk) error) *ComplianceRiskRepository_SaveBatchBestEffort_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Transaction provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) Transaction(ctx context.Context, fn func(tx shared.DB) error) error {
+ ret := _mock.Called(ctx, fn)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Transaction")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, func(tx shared.DB) error) error); ok {
+ r0 = returnFunc(ctx, fn)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_Transaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Transaction'
+type ComplianceRiskRepository_Transaction_Call struct {
+ *mock.Call
+}
+
+// Transaction is a helper method to define mock.On call
+// - ctx context.Context
+// - fn func(tx shared.DB) error
+func (_e *ComplianceRiskRepository_Expecter) Transaction(ctx interface{}, fn interface{}) *ComplianceRiskRepository_Transaction_Call {
+ return &ComplianceRiskRepository_Transaction_Call{Call: _e.mock.On("Transaction", ctx, fn)}
+}
+
+func (_c *ComplianceRiskRepository_Transaction_Call) Run(run func(ctx context.Context, fn func(tx shared.DB) error)) *ComplianceRiskRepository_Transaction_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 func(tx shared.DB) error
+ if args[1] != nil {
+ arg1 = args[1].(func(tx shared.DB) error)
+ }
+ run(
+ arg0,
+ arg1,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Transaction_Call) Return(err error) *ComplianceRiskRepository_Transaction_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Transaction_Call) RunAndReturn(run func(ctx context.Context, fn func(tx shared.DB) error) error) *ComplianceRiskRepository_Transaction_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Upsert provides a mock function for the type ComplianceRiskRepository
+func (_mock *ComplianceRiskRepository) Upsert(ctx context.Context, tx shared.DB, t *[]*models.ComplianceRisk, conflictingColumns []clause.Column, updateOnly []string) error {
+ ret := _mock.Called(ctx, tx, t, conflictingColumns, updateOnly)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Upsert")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *[]*models.ComplianceRisk, []clause.Column, []string) error); ok {
+ r0 = returnFunc(ctx, tx, t, conflictingColumns, updateOnly)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskRepository_Upsert_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Upsert'
+type ComplianceRiskRepository_Upsert_Call struct {
+ *mock.Call
+}
+
+// Upsert is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - t *[]*models.ComplianceRisk
+// - conflictingColumns []clause.Column
+// - updateOnly []string
+func (_e *ComplianceRiskRepository_Expecter) Upsert(ctx interface{}, tx interface{}, t interface{}, conflictingColumns interface{}, updateOnly interface{}) *ComplianceRiskRepository_Upsert_Call {
+ return &ComplianceRiskRepository_Upsert_Call{Call: _e.mock.On("Upsert", ctx, tx, t, conflictingColumns, updateOnly)}
+}
+
+func (_c *ComplianceRiskRepository_Upsert_Call) Run(run func(ctx context.Context, tx shared.DB, t *[]*models.ComplianceRisk, conflictingColumns []clause.Column, updateOnly []string)) *ComplianceRiskRepository_Upsert_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 *[]*models.ComplianceRisk
+ if args[2] != nil {
+ arg2 = args[2].(*[]*models.ComplianceRisk)
+ }
+ var arg3 []clause.Column
+ if args[3] != nil {
+ arg3 = args[3].([]clause.Column)
+ }
+ var arg4 []string
+ if args[4] != nil {
+ arg4 = args[4].([]string)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Upsert_Call) Return(err error) *ComplianceRiskRepository_Upsert_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskRepository_Upsert_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, t *[]*models.ComplianceRisk, conflictingColumns []clause.Column, updateOnly []string) error) *ComplianceRiskRepository_Upsert_Call {
+ _c.Call.Return(run)
+ return _c
+}
diff --git a/mocks/mock_ComplianceRiskService.go b/mocks/mock_ComplianceRiskService.go
new file mode 100644
index 000000000..8080ba3d0
--- /dev/null
+++ b/mocks/mock_ComplianceRiskService.go
@@ -0,0 +1,231 @@
+// Code generated by mockery; DO NOT EDIT.
+// github.com/vektra/mockery
+// template: testify
+
+package mocks
+
+import (
+ "context"
+
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/dtos"
+ "github.com/l3montree-dev/devguard/dtos/sarif"
+ "github.com/l3montree-dev/devguard/shared"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// NewComplianceRiskService creates a new instance of ComplianceRiskService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewComplianceRiskService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ComplianceRiskService {
+ mock := &ComplianceRiskService{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
+
+// ComplianceRiskService is an autogenerated mock type for the ComplianceRiskService type
+type ComplianceRiskService struct {
+ mock.Mock
+}
+
+type ComplianceRiskService_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ComplianceRiskService) EXPECT() *ComplianceRiskService_Expecter {
+ return &ComplianceRiskService_Expecter{mock: &_m.Mock}
+}
+
+// HandleArtifactCompliance provides a mock function for the type ComplianceRiskService
+func (_mock *ComplianceRiskService) HandleArtifactCompliance(ctx context.Context, tx shared.DB, userID string, userAgent *string, assetVersion models.AssetVersion, artifact models.Artifact, sarifDoc sarif.SarifSchema210Json) error {
+ ret := _mock.Called(ctx, tx, userID, userAgent, assetVersion, artifact, sarifDoc)
+
+ if len(ret) == 0 {
+ panic("no return value specified for HandleArtifactCompliance")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, *string, models.AssetVersion, models.Artifact, sarif.SarifSchema210Json) error); ok {
+ r0 = returnFunc(ctx, tx, userID, userAgent, assetVersion, artifact, sarifDoc)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// ComplianceRiskService_HandleArtifactCompliance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HandleArtifactCompliance'
+type ComplianceRiskService_HandleArtifactCompliance_Call struct {
+ *mock.Call
+}
+
+// HandleArtifactCompliance is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - userID string
+// - userAgent *string
+// - assetVersion models.AssetVersion
+// - artifact models.Artifact
+// - sarifDoc sarif.SarifSchema210Json
+func (_e *ComplianceRiskService_Expecter) HandleArtifactCompliance(ctx interface{}, tx interface{}, userID interface{}, userAgent interface{}, assetVersion interface{}, artifact interface{}, sarifDoc interface{}) *ComplianceRiskService_HandleArtifactCompliance_Call {
+ return &ComplianceRiskService_HandleArtifactCompliance_Call{Call: _e.mock.On("HandleArtifactCompliance", ctx, tx, userID, userAgent, assetVersion, artifact, sarifDoc)}
+}
+
+func (_c *ComplianceRiskService_HandleArtifactCompliance_Call) Run(run func(ctx context.Context, tx shared.DB, userID string, userAgent *string, assetVersion models.AssetVersion, artifact models.Artifact, sarifDoc sarif.SarifSchema210Json)) *ComplianceRiskService_HandleArtifactCompliance_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 string
+ if args[2] != nil {
+ arg2 = args[2].(string)
+ }
+ var arg3 *string
+ if args[3] != nil {
+ arg3 = args[3].(*string)
+ }
+ var arg4 models.AssetVersion
+ if args[4] != nil {
+ arg4 = args[4].(models.AssetVersion)
+ }
+ var arg5 models.Artifact
+ if args[5] != nil {
+ arg5 = args[5].(models.Artifact)
+ }
+ var arg6 sarif.SarifSchema210Json
+ if args[6] != nil {
+ arg6 = args[6].(sarif.SarifSchema210Json)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ arg5,
+ arg6,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskService_HandleArtifactCompliance_Call) Return(err error) *ComplianceRiskService_HandleArtifactCompliance_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *ComplianceRiskService_HandleArtifactCompliance_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, userID string, userAgent *string, assetVersion models.AssetVersion, artifact models.Artifact, sarifDoc sarif.SarifSchema210Json) error) *ComplianceRiskService_HandleArtifactCompliance_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// UpdateComplianceRiskState provides a mock function for the type ComplianceRiskService
+func (_mock *ComplianceRiskService) UpdateComplianceRiskState(ctx context.Context, tx shared.DB, userID string, risk *models.ComplianceRisk, statusType string, justification string, mechanicalJustification dtos.MechanicalJustificationType, userAgent *string) (models.VulnEvent, error) {
+ ret := _mock.Called(ctx, tx, userID, risk, statusType, justification, mechanicalJustification, userAgent)
+
+ if len(ret) == 0 {
+ panic("no return value specified for UpdateComplianceRiskState")
+ }
+
+ var r0 models.VulnEvent
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, *models.ComplianceRisk, string, string, dtos.MechanicalJustificationType, *string) (models.VulnEvent, error)); ok {
+ return returnFunc(ctx, tx, userID, risk, statusType, justification, mechanicalJustification, userAgent)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, string, *models.ComplianceRisk, string, string, dtos.MechanicalJustificationType, *string) models.VulnEvent); ok {
+ r0 = returnFunc(ctx, tx, userID, risk, statusType, justification, mechanicalJustification, userAgent)
+ } else {
+ r0 = ret.Get(0).(models.VulnEvent)
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, string, *models.ComplianceRisk, string, string, dtos.MechanicalJustificationType, *string) error); ok {
+ r1 = returnFunc(ctx, tx, userID, risk, statusType, justification, mechanicalJustification, userAgent)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceRiskService_UpdateComplianceRiskState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateComplianceRiskState'
+type ComplianceRiskService_UpdateComplianceRiskState_Call struct {
+ *mock.Call
+}
+
+// UpdateComplianceRiskState is a helper method to define mock.On call
+// - ctx context.Context
+// - tx shared.DB
+// - userID string
+// - risk *models.ComplianceRisk
+// - statusType string
+// - justification string
+// - mechanicalJustification dtos.MechanicalJustificationType
+// - userAgent *string
+func (_e *ComplianceRiskService_Expecter) UpdateComplianceRiskState(ctx interface{}, tx interface{}, userID interface{}, risk interface{}, statusType interface{}, justification interface{}, mechanicalJustification interface{}, userAgent interface{}) *ComplianceRiskService_UpdateComplianceRiskState_Call {
+ return &ComplianceRiskService_UpdateComplianceRiskState_Call{Call: _e.mock.On("UpdateComplianceRiskState", ctx, tx, userID, risk, statusType, justification, mechanicalJustification, userAgent)}
+}
+
+func (_c *ComplianceRiskService_UpdateComplianceRiskState_Call) Run(run func(ctx context.Context, tx shared.DB, userID string, risk *models.ComplianceRisk, statusType string, justification string, mechanicalJustification dtos.MechanicalJustificationType, userAgent *string)) *ComplianceRiskService_UpdateComplianceRiskState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 shared.DB
+ if args[1] != nil {
+ arg1 = args[1].(shared.DB)
+ }
+ var arg2 string
+ if args[2] != nil {
+ arg2 = args[2].(string)
+ }
+ var arg3 *models.ComplianceRisk
+ if args[3] != nil {
+ arg3 = args[3].(*models.ComplianceRisk)
+ }
+ var arg4 string
+ if args[4] != nil {
+ arg4 = args[4].(string)
+ }
+ var arg5 string
+ if args[5] != nil {
+ arg5 = args[5].(string)
+ }
+ var arg6 dtos.MechanicalJustificationType
+ if args[6] != nil {
+ arg6 = args[6].(dtos.MechanicalJustificationType)
+ }
+ var arg7 *string
+ if args[7] != nil {
+ arg7 = args[7].(*string)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ arg5,
+ arg6,
+ arg7,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceRiskService_UpdateComplianceRiskState_Call) Return(vulnEvent models.VulnEvent, err error) *ComplianceRiskService_UpdateComplianceRiskState_Call {
+ _c.Call.Return(vulnEvent, err)
+ return _c
+}
+
+func (_c *ComplianceRiskService_UpdateComplianceRiskState_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, userID string, risk *models.ComplianceRisk, statusType string, justification string, mechanicalJustification dtos.MechanicalJustificationType, userAgent *string) (models.VulnEvent, error)) *ComplianceRiskService_UpdateComplianceRiskState_Call {
+ _c.Call.Return(run)
+ return _c
+}
diff --git a/mocks/mock_ComplianceService.go b/mocks/mock_ComplianceService.go
new file mode 100644
index 000000000..f674a5778
--- /dev/null
+++ b/mocks/mock_ComplianceService.go
@@ -0,0 +1,119 @@
+// Code generated by mockery; DO NOT EDIT.
+// github.com/vektra/mockery
+// template: testify
+
+package mocks
+
+import (
+ "context"
+
+ "github.com/google/uuid"
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/dtos/sarif"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// NewComplianceService creates a new instance of ComplianceService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewComplianceService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ComplianceService {
+ mock := &ComplianceService{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
+
+// ComplianceService is an autogenerated mock type for the ComplianceService type
+type ComplianceService struct {
+ mock.Mock
+}
+
+type ComplianceService_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ComplianceService) EXPECT() *ComplianceService_Expecter {
+ return &ComplianceService_Expecter{mock: &_m.Mock}
+}
+
+// EvaluateArtifactAttestations provides a mock function for the type ComplianceService
+func (_mock *ComplianceService) EvaluateArtifactAttestations(ctx context.Context, projectID uuid.UUID, assetVersion models.AssetVersion, artifact models.Artifact) (sarif.SarifSchema210Json, error) {
+ ret := _mock.Called(ctx, projectID, assetVersion, artifact)
+
+ if len(ret) == 0 {
+ panic("no return value specified for EvaluateArtifactAttestations")
+ }
+
+ var r0 sarif.SarifSchema210Json
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, models.AssetVersion, models.Artifact) (sarif.SarifSchema210Json, error)); ok {
+ return returnFunc(ctx, projectID, assetVersion, artifact)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, uuid.UUID, models.AssetVersion, models.Artifact) sarif.SarifSchema210Json); ok {
+ r0 = returnFunc(ctx, projectID, assetVersion, artifact)
+ } else {
+ r0 = ret.Get(0).(sarif.SarifSchema210Json)
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, uuid.UUID, models.AssetVersion, models.Artifact) error); ok {
+ r1 = returnFunc(ctx, projectID, assetVersion, artifact)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// ComplianceService_EvaluateArtifactAttestations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EvaluateArtifactAttestations'
+type ComplianceService_EvaluateArtifactAttestations_Call struct {
+ *mock.Call
+}
+
+// EvaluateArtifactAttestations is a helper method to define mock.On call
+// - ctx context.Context
+// - projectID uuid.UUID
+// - assetVersion models.AssetVersion
+// - artifact models.Artifact
+func (_e *ComplianceService_Expecter) EvaluateArtifactAttestations(ctx interface{}, projectID interface{}, assetVersion interface{}, artifact interface{}) *ComplianceService_EvaluateArtifactAttestations_Call {
+ return &ComplianceService_EvaluateArtifactAttestations_Call{Call: _e.mock.On("EvaluateArtifactAttestations", ctx, projectID, assetVersion, artifact)}
+}
+
+func (_c *ComplianceService_EvaluateArtifactAttestations_Call) Run(run func(ctx context.Context, projectID uuid.UUID, assetVersion models.AssetVersion, artifact models.Artifact)) *ComplianceService_EvaluateArtifactAttestations_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ var arg0 context.Context
+ if args[0] != nil {
+ arg0 = args[0].(context.Context)
+ }
+ var arg1 uuid.UUID
+ if args[1] != nil {
+ arg1 = args[1].(uuid.UUID)
+ }
+ var arg2 models.AssetVersion
+ if args[2] != nil {
+ arg2 = args[2].(models.AssetVersion)
+ }
+ var arg3 models.Artifact
+ if args[3] != nil {
+ arg3 = args[3].(models.Artifact)
+ }
+ run(
+ arg0,
+ arg1,
+ arg2,
+ arg3,
+ )
+ })
+ return _c
+}
+
+func (_c *ComplianceService_EvaluateArtifactAttestations_Call) Return(sarifSchema210Json sarif.SarifSchema210Json, err error) *ComplianceService_EvaluateArtifactAttestations_Call {
+ _c.Call.Return(sarifSchema210Json, err)
+ return _c
+}
+
+func (_c *ComplianceService_EvaluateArtifactAttestations_Call) RunAndReturn(run func(ctx context.Context, projectID uuid.UUID, assetVersion models.AssetVersion, artifact models.Artifact) (sarif.SarifSchema210Json, error)) *ComplianceService_EvaluateArtifactAttestations_Call {
+ _c.Call.Return(run)
+ return _c
+}
diff --git a/mocks/mock_ExternalPropertyFileReference.go b/mocks/mock_ExternalPropertyFileReference.go
deleted file mode 100644
index a2163049d..000000000
--- a/mocks/mock_ExternalPropertyFileReference.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Code generated by mockery; DO NOT EDIT.
-// github.com/vektra/mockery
-// template: testify
-
-package mocks
-
-import (
- mock "github.com/stretchr/testify/mock"
-)
-
-// NewExternalPropertyFileReference creates a new instance of ExternalPropertyFileReference. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewExternalPropertyFileReference(t interface {
- mock.TestingT
- Cleanup(func())
-}) *ExternalPropertyFileReference {
- mock := &ExternalPropertyFileReference{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
-
-// ExternalPropertyFileReference is an autogenerated mock type for the ExternalPropertyFileReference type
-type ExternalPropertyFileReference struct {
- mock.Mock
-}
-
-type ExternalPropertyFileReference_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *ExternalPropertyFileReference) EXPECT() *ExternalPropertyFileReference_Expecter {
- return &ExternalPropertyFileReference_Expecter{mock: &_m.Mock}
-}
diff --git a/mocks/mock_PolicyRepository.go b/mocks/mock_PolicyRepository.go
deleted file mode 100644
index 0f5fee02e..000000000
--- a/mocks/mock_PolicyRepository.go
+++ /dev/null
@@ -1,1271 +0,0 @@
-// Code generated by mockery; DO NOT EDIT.
-// github.com/vektra/mockery
-// template: testify
-
-package mocks
-
-import (
- "context"
-
- "github.com/google/uuid"
- "github.com/l3montree-dev/devguard/database/models"
- "github.com/l3montree-dev/devguard/shared"
- mock "github.com/stretchr/testify/mock"
- "gorm.io/gorm/clause"
-)
-
-// NewPolicyRepository creates a new instance of PolicyRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewPolicyRepository(t interface {
- mock.TestingT
- Cleanup(func())
-}) *PolicyRepository {
- mock := &PolicyRepository{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
-
-// PolicyRepository is an autogenerated mock type for the PolicyRepository type
-type PolicyRepository struct {
- mock.Mock
-}
-
-type PolicyRepository_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *PolicyRepository) EXPECT() *PolicyRepository_Expecter {
- return &PolicyRepository_Expecter{mock: &_m.Mock}
-}
-
-// Activate provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) Activate(ctx context.Context, tx shared.DB, id uuid.UUID) error {
- ret := _mock.Called(ctx, tx, id)
-
- if len(ret) == 0 {
- panic("no return value specified for Activate")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) error); ok {
- r0 = returnFunc(ctx, tx, id)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_Activate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Activate'
-type PolicyRepository_Activate_Call struct {
- *mock.Call
-}
-
-// Activate is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - id uuid.UUID
-func (_e *PolicyRepository_Expecter) Activate(ctx interface{}, tx interface{}, id interface{}) *PolicyRepository_Activate_Call {
- return &PolicyRepository_Activate_Call{Call: _e.mock.On("Activate", ctx, tx, id)}
-}
-
-func (_c *PolicyRepository_Activate_Call) Run(run func(ctx context.Context, tx shared.DB, id uuid.UUID)) *PolicyRepository_Activate_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 uuid.UUID
- if args[2] != nil {
- arg2 = args[2].(uuid.UUID)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_Activate_Call) Return(err error) *PolicyRepository_Activate_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_Activate_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, id uuid.UUID) error) *PolicyRepository_Activate_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// All provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) All(ctx context.Context, tx shared.DB) ([]models.Policy, error) {
- ret := _mock.Called(ctx, tx)
-
- if len(ret) == 0 {
- panic("no return value specified for All")
- }
-
- var r0 []models.Policy
- var r1 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB) ([]models.Policy, error)); ok {
- return returnFunc(ctx, tx)
- }
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB) []models.Policy); ok {
- r0 = returnFunc(ctx, tx)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]models.Policy)
- }
- }
- if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB) error); ok {
- r1 = returnFunc(ctx, tx)
- } else {
- r1 = ret.Error(1)
- }
- return r0, r1
-}
-
-// PolicyRepository_All_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'All'
-type PolicyRepository_All_Call struct {
- *mock.Call
-}
-
-// All is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-func (_e *PolicyRepository_Expecter) All(ctx interface{}, tx interface{}) *PolicyRepository_All_Call {
- return &PolicyRepository_All_Call{Call: _e.mock.On("All", ctx, tx)}
-}
-
-func (_c *PolicyRepository_All_Call) Run(run func(ctx context.Context, tx shared.DB)) *PolicyRepository_All_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- run(
- arg0,
- arg1,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_All_Call) Return(policys []models.Policy, err error) *PolicyRepository_All_Call {
- _c.Call.Return(policys, err)
- return _c
-}
-
-func (_c *PolicyRepository_All_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB) ([]models.Policy, error)) *PolicyRepository_All_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Begin provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) Begin(ctx context.Context) shared.DB {
- ret := _mock.Called(ctx)
-
- if len(ret) == 0 {
- panic("no return value specified for Begin")
- }
-
- var r0 shared.DB
- if returnFunc, ok := ret.Get(0).(func(context.Context) shared.DB); ok {
- r0 = returnFunc(ctx)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(shared.DB)
- }
- }
- return r0
-}
-
-// PolicyRepository_Begin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Begin'
-type PolicyRepository_Begin_Call struct {
- *mock.Call
-}
-
-// Begin is a helper method to define mock.On call
-// - ctx context.Context
-func (_e *PolicyRepository_Expecter) Begin(ctx interface{}) *PolicyRepository_Begin_Call {
- return &PolicyRepository_Begin_Call{Call: _e.mock.On("Begin", ctx)}
-}
-
-func (_c *PolicyRepository_Begin_Call) Run(run func(ctx context.Context)) *PolicyRepository_Begin_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- run(
- arg0,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_Begin_Call) Return(v shared.DB) *PolicyRepository_Begin_Call {
- _c.Call.Return(v)
- return _c
-}
-
-func (_c *PolicyRepository_Begin_Call) RunAndReturn(run func(ctx context.Context) shared.DB) *PolicyRepository_Begin_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CleanupOrphanedRecords provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) CleanupOrphanedRecords(ctx context.Context) error {
- ret := _mock.Called(ctx)
-
- if len(ret) == 0 {
- panic("no return value specified for CleanupOrphanedRecords")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context) error); ok {
- r0 = returnFunc(ctx)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_CleanupOrphanedRecords_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CleanupOrphanedRecords'
-type PolicyRepository_CleanupOrphanedRecords_Call struct {
- *mock.Call
-}
-
-// CleanupOrphanedRecords is a helper method to define mock.On call
-// - ctx context.Context
-func (_e *PolicyRepository_Expecter) CleanupOrphanedRecords(ctx interface{}) *PolicyRepository_CleanupOrphanedRecords_Call {
- return &PolicyRepository_CleanupOrphanedRecords_Call{Call: _e.mock.On("CleanupOrphanedRecords", ctx)}
-}
-
-func (_c *PolicyRepository_CleanupOrphanedRecords_Call) Run(run func(ctx context.Context)) *PolicyRepository_CleanupOrphanedRecords_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- run(
- arg0,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_CleanupOrphanedRecords_Call) Return(err error) *PolicyRepository_CleanupOrphanedRecords_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_CleanupOrphanedRecords_Call) RunAndReturn(run func(ctx context.Context) error) *PolicyRepository_CleanupOrphanedRecords_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Create provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) Create(ctx context.Context, tx shared.DB, t *models.Policy) error {
- ret := _mock.Called(ctx, tx, t)
-
- if len(ret) == 0 {
- panic("no return value specified for Create")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *models.Policy) error); ok {
- r0 = returnFunc(ctx, tx, t)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create'
-type PolicyRepository_Create_Call struct {
- *mock.Call
-}
-
-// Create is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - t *models.Policy
-func (_e *PolicyRepository_Expecter) Create(ctx interface{}, tx interface{}, t interface{}) *PolicyRepository_Create_Call {
- return &PolicyRepository_Create_Call{Call: _e.mock.On("Create", ctx, tx, t)}
-}
-
-func (_c *PolicyRepository_Create_Call) Run(run func(ctx context.Context, tx shared.DB, t *models.Policy)) *PolicyRepository_Create_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 *models.Policy
- if args[2] != nil {
- arg2 = args[2].(*models.Policy)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_Create_Call) Return(err error) *PolicyRepository_Create_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_Create_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, t *models.Policy) error) *PolicyRepository_Create_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CreateBatch provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) CreateBatch(ctx context.Context, tx shared.DB, ts []models.Policy) error {
- ret := _mock.Called(ctx, tx, ts)
-
- if len(ret) == 0 {
- panic("no return value specified for CreateBatch")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []models.Policy) error); ok {
- r0 = returnFunc(ctx, tx, ts)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_CreateBatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateBatch'
-type PolicyRepository_CreateBatch_Call struct {
- *mock.Call
-}
-
-// CreateBatch is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - ts []models.Policy
-func (_e *PolicyRepository_Expecter) CreateBatch(ctx interface{}, tx interface{}, ts interface{}) *PolicyRepository_CreateBatch_Call {
- return &PolicyRepository_CreateBatch_Call{Call: _e.mock.On("CreateBatch", ctx, tx, ts)}
-}
-
-func (_c *PolicyRepository_CreateBatch_Call) Run(run func(ctx context.Context, tx shared.DB, ts []models.Policy)) *PolicyRepository_CreateBatch_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 []models.Policy
- if args[2] != nil {
- arg2 = args[2].([]models.Policy)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_CreateBatch_Call) Return(err error) *PolicyRepository_CreateBatch_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_CreateBatch_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ts []models.Policy) error) *PolicyRepository_CreateBatch_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Delete provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) Delete(ctx context.Context, tx shared.DB, id uuid.UUID) error {
- ret := _mock.Called(ctx, tx, id)
-
- if len(ret) == 0 {
- panic("no return value specified for Delete")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) error); ok {
- r0 = returnFunc(ctx, tx, id)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
-type PolicyRepository_Delete_Call struct {
- *mock.Call
-}
-
-// Delete is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - id uuid.UUID
-func (_e *PolicyRepository_Expecter) Delete(ctx interface{}, tx interface{}, id interface{}) *PolicyRepository_Delete_Call {
- return &PolicyRepository_Delete_Call{Call: _e.mock.On("Delete", ctx, tx, id)}
-}
-
-func (_c *PolicyRepository_Delete_Call) Run(run func(ctx context.Context, tx shared.DB, id uuid.UUID)) *PolicyRepository_Delete_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 uuid.UUID
- if args[2] != nil {
- arg2 = args[2].(uuid.UUID)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_Delete_Call) Return(err error) *PolicyRepository_Delete_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_Delete_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, id uuid.UUID) error) *PolicyRepository_Delete_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// DeleteBatch provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) DeleteBatch(ctx context.Context, tx shared.DB, ids []models.Policy) error {
- ret := _mock.Called(ctx, tx, ids)
-
- if len(ret) == 0 {
- panic("no return value specified for DeleteBatch")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []models.Policy) error); ok {
- r0 = returnFunc(ctx, tx, ids)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_DeleteBatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteBatch'
-type PolicyRepository_DeleteBatch_Call struct {
- *mock.Call
-}
-
-// DeleteBatch is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - ids []models.Policy
-func (_e *PolicyRepository_Expecter) DeleteBatch(ctx interface{}, tx interface{}, ids interface{}) *PolicyRepository_DeleteBatch_Call {
- return &PolicyRepository_DeleteBatch_Call{Call: _e.mock.On("DeleteBatch", ctx, tx, ids)}
-}
-
-func (_c *PolicyRepository_DeleteBatch_Call) Run(run func(ctx context.Context, tx shared.DB, ids []models.Policy)) *PolicyRepository_DeleteBatch_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 []models.Policy
- if args[2] != nil {
- arg2 = args[2].([]models.Policy)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_DeleteBatch_Call) Return(err error) *PolicyRepository_DeleteBatch_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_DeleteBatch_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ids []models.Policy) error) *PolicyRepository_DeleteBatch_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// FindByOrganizationID provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) FindByOrganizationID(ctx context.Context, tx shared.DB, organizationID uuid.UUID) ([]models.Policy, error) {
- ret := _mock.Called(ctx, tx, organizationID)
-
- if len(ret) == 0 {
- panic("no return value specified for FindByOrganizationID")
- }
-
- var r0 []models.Policy
- var r1 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) ([]models.Policy, error)); ok {
- return returnFunc(ctx, tx, organizationID)
- }
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) []models.Policy); ok {
- r0 = returnFunc(ctx, tx, organizationID)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]models.Policy)
- }
- }
- if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID) error); ok {
- r1 = returnFunc(ctx, tx, organizationID)
- } else {
- r1 = ret.Error(1)
- }
- return r0, r1
-}
-
-// PolicyRepository_FindByOrganizationID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindByOrganizationID'
-type PolicyRepository_FindByOrganizationID_Call struct {
- *mock.Call
-}
-
-// FindByOrganizationID is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - organizationID uuid.UUID
-func (_e *PolicyRepository_Expecter) FindByOrganizationID(ctx interface{}, tx interface{}, organizationID interface{}) *PolicyRepository_FindByOrganizationID_Call {
- return &PolicyRepository_FindByOrganizationID_Call{Call: _e.mock.On("FindByOrganizationID", ctx, tx, organizationID)}
-}
-
-func (_c *PolicyRepository_FindByOrganizationID_Call) Run(run func(ctx context.Context, tx shared.DB, organizationID uuid.UUID)) *PolicyRepository_FindByOrganizationID_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 uuid.UUID
- if args[2] != nil {
- arg2 = args[2].(uuid.UUID)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_FindByOrganizationID_Call) Return(policys []models.Policy, err error) *PolicyRepository_FindByOrganizationID_Call {
- _c.Call.Return(policys, err)
- return _c
-}
-
-func (_c *PolicyRepository_FindByOrganizationID_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, organizationID uuid.UUID) ([]models.Policy, error)) *PolicyRepository_FindByOrganizationID_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// FindByProjectID provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) FindByProjectID(ctx context.Context, tx shared.DB, projectID uuid.UUID) ([]models.Policy, error) {
- ret := _mock.Called(ctx, tx, projectID)
-
- if len(ret) == 0 {
- panic("no return value specified for FindByProjectID")
- }
-
- var r0 []models.Policy
- var r1 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) ([]models.Policy, error)); ok {
- return returnFunc(ctx, tx, projectID)
- }
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) []models.Policy); ok {
- r0 = returnFunc(ctx, tx, projectID)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]models.Policy)
- }
- }
- if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID) error); ok {
- r1 = returnFunc(ctx, tx, projectID)
- } else {
- r1 = ret.Error(1)
- }
- return r0, r1
-}
-
-// PolicyRepository_FindByProjectID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindByProjectID'
-type PolicyRepository_FindByProjectID_Call struct {
- *mock.Call
-}
-
-// FindByProjectID is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - projectID uuid.UUID
-func (_e *PolicyRepository_Expecter) FindByProjectID(ctx interface{}, tx interface{}, projectID interface{}) *PolicyRepository_FindByProjectID_Call {
- return &PolicyRepository_FindByProjectID_Call{Call: _e.mock.On("FindByProjectID", ctx, tx, projectID)}
-}
-
-func (_c *PolicyRepository_FindByProjectID_Call) Run(run func(ctx context.Context, tx shared.DB, projectID uuid.UUID)) *PolicyRepository_FindByProjectID_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 uuid.UUID
- if args[2] != nil {
- arg2 = args[2].(uuid.UUID)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_FindByProjectID_Call) Return(policys []models.Policy, err error) *PolicyRepository_FindByProjectID_Call {
- _c.Call.Return(policys, err)
- return _c
-}
-
-func (_c *PolicyRepository_FindByProjectID_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, projectID uuid.UUID) ([]models.Policy, error)) *PolicyRepository_FindByProjectID_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// FindCommunityManagedPolicies provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) FindCommunityManagedPolicies(ctx context.Context, tx shared.DB) ([]models.Policy, error) {
- ret := _mock.Called(ctx, tx)
-
- if len(ret) == 0 {
- panic("no return value specified for FindCommunityManagedPolicies")
- }
-
- var r0 []models.Policy
- var r1 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB) ([]models.Policy, error)); ok {
- return returnFunc(ctx, tx)
- }
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB) []models.Policy); ok {
- r0 = returnFunc(ctx, tx)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]models.Policy)
- }
- }
- if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB) error); ok {
- r1 = returnFunc(ctx, tx)
- } else {
- r1 = ret.Error(1)
- }
- return r0, r1
-}
-
-// PolicyRepository_FindCommunityManagedPolicies_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindCommunityManagedPolicies'
-type PolicyRepository_FindCommunityManagedPolicies_Call struct {
- *mock.Call
-}
-
-// FindCommunityManagedPolicies is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-func (_e *PolicyRepository_Expecter) FindCommunityManagedPolicies(ctx interface{}, tx interface{}) *PolicyRepository_FindCommunityManagedPolicies_Call {
- return &PolicyRepository_FindCommunityManagedPolicies_Call{Call: _e.mock.On("FindCommunityManagedPolicies", ctx, tx)}
-}
-
-func (_c *PolicyRepository_FindCommunityManagedPolicies_Call) Run(run func(ctx context.Context, tx shared.DB)) *PolicyRepository_FindCommunityManagedPolicies_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- run(
- arg0,
- arg1,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_FindCommunityManagedPolicies_Call) Return(policys []models.Policy, err error) *PolicyRepository_FindCommunityManagedPolicies_Call {
- _c.Call.Return(policys, err)
- return _c
-}
-
-func (_c *PolicyRepository_FindCommunityManagedPolicies_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB) ([]models.Policy, error)) *PolicyRepository_FindCommunityManagedPolicies_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetDB provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) GetDB(ctx context.Context, tx shared.DB) shared.DB {
- ret := _mock.Called(ctx, tx)
-
- if len(ret) == 0 {
- panic("no return value specified for GetDB")
- }
-
- var r0 shared.DB
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB) shared.DB); ok {
- r0 = returnFunc(ctx, tx)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(shared.DB)
- }
- }
- return r0
-}
-
-// PolicyRepository_GetDB_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDB'
-type PolicyRepository_GetDB_Call struct {
- *mock.Call
-}
-
-// GetDB is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-func (_e *PolicyRepository_Expecter) GetDB(ctx interface{}, tx interface{}) *PolicyRepository_GetDB_Call {
- return &PolicyRepository_GetDB_Call{Call: _e.mock.On("GetDB", ctx, tx)}
-}
-
-func (_c *PolicyRepository_GetDB_Call) Run(run func(ctx context.Context, tx shared.DB)) *PolicyRepository_GetDB_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- run(
- arg0,
- arg1,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_GetDB_Call) Return(v shared.DB) *PolicyRepository_GetDB_Call {
- _c.Call.Return(v)
- return _c
-}
-
-func (_c *PolicyRepository_GetDB_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB) shared.DB) *PolicyRepository_GetDB_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// List provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) List(ctx context.Context, tx shared.DB, ids []uuid.UUID) ([]models.Policy, error) {
- ret := _mock.Called(ctx, tx, ids)
-
- if len(ret) == 0 {
- panic("no return value specified for List")
- }
-
- var r0 []models.Policy
- var r1 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []uuid.UUID) ([]models.Policy, error)); ok {
- return returnFunc(ctx, tx, ids)
- }
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []uuid.UUID) []models.Policy); ok {
- r0 = returnFunc(ctx, tx, ids)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]models.Policy)
- }
- }
- if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, []uuid.UUID) error); ok {
- r1 = returnFunc(ctx, tx, ids)
- } else {
- r1 = ret.Error(1)
- }
- return r0, r1
-}
-
-// PolicyRepository_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List'
-type PolicyRepository_List_Call struct {
- *mock.Call
-}
-
-// List is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - ids []uuid.UUID
-func (_e *PolicyRepository_Expecter) List(ctx interface{}, tx interface{}, ids interface{}) *PolicyRepository_List_Call {
- return &PolicyRepository_List_Call{Call: _e.mock.On("List", ctx, tx, ids)}
-}
-
-func (_c *PolicyRepository_List_Call) Run(run func(ctx context.Context, tx shared.DB, ids []uuid.UUID)) *PolicyRepository_List_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 []uuid.UUID
- if args[2] != nil {
- arg2 = args[2].([]uuid.UUID)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_List_Call) Return(policys []models.Policy, err error) *PolicyRepository_List_Call {
- _c.Call.Return(policys, err)
- return _c
-}
-
-func (_c *PolicyRepository_List_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ids []uuid.UUID) ([]models.Policy, error)) *PolicyRepository_List_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Read provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) Read(ctx context.Context, tx shared.DB, id uuid.UUID) (models.Policy, error) {
- ret := _mock.Called(ctx, tx, id)
-
- if len(ret) == 0 {
- panic("no return value specified for Read")
- }
-
- var r0 models.Policy
- var r1 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) (models.Policy, error)); ok {
- return returnFunc(ctx, tx, id)
- }
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID) models.Policy); ok {
- r0 = returnFunc(ctx, tx, id)
- } else {
- r0 = ret.Get(0).(models.Policy)
- }
- if returnFunc, ok := ret.Get(1).(func(context.Context, shared.DB, uuid.UUID) error); ok {
- r1 = returnFunc(ctx, tx, id)
- } else {
- r1 = ret.Error(1)
- }
- return r0, r1
-}
-
-// PolicyRepository_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read'
-type PolicyRepository_Read_Call struct {
- *mock.Call
-}
-
-// Read is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - id uuid.UUID
-func (_e *PolicyRepository_Expecter) Read(ctx interface{}, tx interface{}, id interface{}) *PolicyRepository_Read_Call {
- return &PolicyRepository_Read_Call{Call: _e.mock.On("Read", ctx, tx, id)}
-}
-
-func (_c *PolicyRepository_Read_Call) Run(run func(ctx context.Context, tx shared.DB, id uuid.UUID)) *PolicyRepository_Read_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 uuid.UUID
- if args[2] != nil {
- arg2 = args[2].(uuid.UUID)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_Read_Call) Return(policy models.Policy, err error) *PolicyRepository_Read_Call {
- _c.Call.Return(policy, err)
- return _c
-}
-
-func (_c *PolicyRepository_Read_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, id uuid.UUID) (models.Policy, error)) *PolicyRepository_Read_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Save provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) Save(ctx context.Context, tx shared.DB, t *models.Policy) error {
- ret := _mock.Called(ctx, tx, t)
-
- if len(ret) == 0 {
- panic("no return value specified for Save")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *models.Policy) error); ok {
- r0 = returnFunc(ctx, tx, t)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_Save_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Save'
-type PolicyRepository_Save_Call struct {
- *mock.Call
-}
-
-// Save is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - t *models.Policy
-func (_e *PolicyRepository_Expecter) Save(ctx interface{}, tx interface{}, t interface{}) *PolicyRepository_Save_Call {
- return &PolicyRepository_Save_Call{Call: _e.mock.On("Save", ctx, tx, t)}
-}
-
-func (_c *PolicyRepository_Save_Call) Run(run func(ctx context.Context, tx shared.DB, t *models.Policy)) *PolicyRepository_Save_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 *models.Policy
- if args[2] != nil {
- arg2 = args[2].(*models.Policy)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_Save_Call) Return(err error) *PolicyRepository_Save_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_Save_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, t *models.Policy) error) *PolicyRepository_Save_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SaveBatch provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) SaveBatch(ctx context.Context, tx shared.DB, ts []models.Policy) error {
- ret := _mock.Called(ctx, tx, ts)
-
- if len(ret) == 0 {
- panic("no return value specified for SaveBatch")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []models.Policy) error); ok {
- r0 = returnFunc(ctx, tx, ts)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_SaveBatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveBatch'
-type PolicyRepository_SaveBatch_Call struct {
- *mock.Call
-}
-
-// SaveBatch is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - ts []models.Policy
-func (_e *PolicyRepository_Expecter) SaveBatch(ctx interface{}, tx interface{}, ts interface{}) *PolicyRepository_SaveBatch_Call {
- return &PolicyRepository_SaveBatch_Call{Call: _e.mock.On("SaveBatch", ctx, tx, ts)}
-}
-
-func (_c *PolicyRepository_SaveBatch_Call) Run(run func(ctx context.Context, tx shared.DB, ts []models.Policy)) *PolicyRepository_SaveBatch_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 []models.Policy
- if args[2] != nil {
- arg2 = args[2].([]models.Policy)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_SaveBatch_Call) Return(err error) *PolicyRepository_SaveBatch_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_SaveBatch_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ts []models.Policy) error) *PolicyRepository_SaveBatch_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SaveBatchBestEffort provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) SaveBatchBestEffort(ctx context.Context, tx shared.DB, ts []models.Policy) error {
- ret := _mock.Called(ctx, tx, ts)
-
- if len(ret) == 0 {
- panic("no return value specified for SaveBatchBestEffort")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, []models.Policy) error); ok {
- r0 = returnFunc(ctx, tx, ts)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_SaveBatchBestEffort_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveBatchBestEffort'
-type PolicyRepository_SaveBatchBestEffort_Call struct {
- *mock.Call
-}
-
-// SaveBatchBestEffort is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - ts []models.Policy
-func (_e *PolicyRepository_Expecter) SaveBatchBestEffort(ctx interface{}, tx interface{}, ts interface{}) *PolicyRepository_SaveBatchBestEffort_Call {
- return &PolicyRepository_SaveBatchBestEffort_Call{Call: _e.mock.On("SaveBatchBestEffort", ctx, tx, ts)}
-}
-
-func (_c *PolicyRepository_SaveBatchBestEffort_Call) Run(run func(ctx context.Context, tx shared.DB, ts []models.Policy)) *PolicyRepository_SaveBatchBestEffort_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 []models.Policy
- if args[2] != nil {
- arg2 = args[2].([]models.Policy)
- }
- run(
- arg0,
- arg1,
- arg2,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_SaveBatchBestEffort_Call) Return(err error) *PolicyRepository_SaveBatchBestEffort_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_SaveBatchBestEffort_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, ts []models.Policy) error) *PolicyRepository_SaveBatchBestEffort_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Transaction provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) Transaction(ctx context.Context, fn func(tx shared.DB) error) error {
- ret := _mock.Called(ctx, fn)
-
- if len(ret) == 0 {
- panic("no return value specified for Transaction")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, func(tx shared.DB) error) error); ok {
- r0 = returnFunc(ctx, fn)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_Transaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Transaction'
-type PolicyRepository_Transaction_Call struct {
- *mock.Call
-}
-
-// Transaction is a helper method to define mock.On call
-// - ctx context.Context
-// - fn func(tx shared.DB) error
-func (_e *PolicyRepository_Expecter) Transaction(ctx interface{}, fn interface{}) *PolicyRepository_Transaction_Call {
- return &PolicyRepository_Transaction_Call{Call: _e.mock.On("Transaction", ctx, fn)}
-}
-
-func (_c *PolicyRepository_Transaction_Call) Run(run func(ctx context.Context, fn func(tx shared.DB) error)) *PolicyRepository_Transaction_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 func(tx shared.DB) error
- if args[1] != nil {
- arg1 = args[1].(func(tx shared.DB) error)
- }
- run(
- arg0,
- arg1,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_Transaction_Call) Return(err error) *PolicyRepository_Transaction_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_Transaction_Call) RunAndReturn(run func(ctx context.Context, fn func(tx shared.DB) error) error) *PolicyRepository_Transaction_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Upsert provides a mock function for the type PolicyRepository
-func (_mock *PolicyRepository) Upsert(ctx context.Context, tx shared.DB, t *[]*models.Policy, conflictingColumns []clause.Column, updateOnly []string) error {
- ret := _mock.Called(ctx, tx, t, conflictingColumns, updateOnly)
-
- if len(ret) == 0 {
- panic("no return value specified for Upsert")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, *[]*models.Policy, []clause.Column, []string) error); ok {
- r0 = returnFunc(ctx, tx, t, conflictingColumns, updateOnly)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// PolicyRepository_Upsert_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Upsert'
-type PolicyRepository_Upsert_Call struct {
- *mock.Call
-}
-
-// Upsert is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - t *[]*models.Policy
-// - conflictingColumns []clause.Column
-// - updateOnly []string
-func (_e *PolicyRepository_Expecter) Upsert(ctx interface{}, tx interface{}, t interface{}, conflictingColumns interface{}, updateOnly interface{}) *PolicyRepository_Upsert_Call {
- return &PolicyRepository_Upsert_Call{Call: _e.mock.On("Upsert", ctx, tx, t, conflictingColumns, updateOnly)}
-}
-
-func (_c *PolicyRepository_Upsert_Call) Run(run func(ctx context.Context, tx shared.DB, t *[]*models.Policy, conflictingColumns []clause.Column, updateOnly []string)) *PolicyRepository_Upsert_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 *[]*models.Policy
- if args[2] != nil {
- arg2 = args[2].(*[]*models.Policy)
- }
- var arg3 []clause.Column
- if args[3] != nil {
- arg3 = args[3].([]clause.Column)
- }
- var arg4 []string
- if args[4] != nil {
- arg4 = args[4].([]string)
- }
- run(
- arg0,
- arg1,
- arg2,
- arg3,
- arg4,
- )
- })
- return _c
-}
-
-func (_c *PolicyRepository_Upsert_Call) Return(err error) *PolicyRepository_Upsert_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *PolicyRepository_Upsert_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, t *[]*models.Policy, conflictingColumns []clause.Column, updateOnly []string) error) *PolicyRepository_Upsert_Call {
- _c.Call.Return(run)
- return _c
-}
diff --git a/mocks/mock_ProjectRepository.go b/mocks/mock_ProjectRepository.go
index 73ccd679f..131aa4d3f 100644
--- a/mocks/mock_ProjectRepository.go
+++ b/mocks/mock_ProjectRepository.go
@@ -299,75 +299,6 @@ func (_c *ProjectRepository_Delete_Call) RunAndReturn(run func(ctx context.Conte
return _c
}
-// DisablePolicyForProject provides a mock function for the type ProjectRepository
-func (_mock *ProjectRepository) DisablePolicyForProject(ctx context.Context, tx shared.DB, projectID uuid.UUID, policyID uuid.UUID) error {
- ret := _mock.Called(ctx, tx, projectID, policyID)
-
- if len(ret) == 0 {
- panic("no return value specified for DisablePolicyForProject")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, uuid.UUID) error); ok {
- r0 = returnFunc(ctx, tx, projectID, policyID)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// ProjectRepository_DisablePolicyForProject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisablePolicyForProject'
-type ProjectRepository_DisablePolicyForProject_Call struct {
- *mock.Call
-}
-
-// DisablePolicyForProject is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - projectID uuid.UUID
-// - policyID uuid.UUID
-func (_e *ProjectRepository_Expecter) DisablePolicyForProject(ctx interface{}, tx interface{}, projectID interface{}, policyID interface{}) *ProjectRepository_DisablePolicyForProject_Call {
- return &ProjectRepository_DisablePolicyForProject_Call{Call: _e.mock.On("DisablePolicyForProject", ctx, tx, projectID, policyID)}
-}
-
-func (_c *ProjectRepository_DisablePolicyForProject_Call) Run(run func(ctx context.Context, tx shared.DB, projectID uuid.UUID, policyID uuid.UUID)) *ProjectRepository_DisablePolicyForProject_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 uuid.UUID
- if args[2] != nil {
- arg2 = args[2].(uuid.UUID)
- }
- var arg3 uuid.UUID
- if args[3] != nil {
- arg3 = args[3].(uuid.UUID)
- }
- run(
- arg0,
- arg1,
- arg2,
- arg3,
- )
- })
- return _c
-}
-
-func (_c *ProjectRepository_DisablePolicyForProject_Call) Return(err error) *ProjectRepository_DisablePolicyForProject_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *ProjectRepository_DisablePolicyForProject_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, projectID uuid.UUID, policyID uuid.UUID) error) *ProjectRepository_DisablePolicyForProject_Call {
- _c.Call.Return(run)
- return _c
-}
-
// EnableCommunityManagedPolicies provides a mock function for the type ProjectRepository
func (_mock *ProjectRepository) EnableCommunityManagedPolicies(ctx context.Context, tx shared.DB, projectID uuid.UUID) error {
ret := _mock.Called(ctx, tx, projectID)
@@ -431,75 +362,6 @@ func (_c *ProjectRepository_EnableCommunityManagedPolicies_Call) RunAndReturn(ru
return _c
}
-// EnablePolicyForProject provides a mock function for the type ProjectRepository
-func (_mock *ProjectRepository) EnablePolicyForProject(ctx context.Context, tx shared.DB, projectID uuid.UUID, policyID uuid.UUID) error {
- ret := _mock.Called(ctx, tx, projectID, policyID)
-
- if len(ret) == 0 {
- panic("no return value specified for EnablePolicyForProject")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, shared.DB, uuid.UUID, uuid.UUID) error); ok {
- r0 = returnFunc(ctx, tx, projectID, policyID)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// ProjectRepository_EnablePolicyForProject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnablePolicyForProject'
-type ProjectRepository_EnablePolicyForProject_Call struct {
- *mock.Call
-}
-
-// EnablePolicyForProject is a helper method to define mock.On call
-// - ctx context.Context
-// - tx shared.DB
-// - projectID uuid.UUID
-// - policyID uuid.UUID
-func (_e *ProjectRepository_Expecter) EnablePolicyForProject(ctx interface{}, tx interface{}, projectID interface{}, policyID interface{}) *ProjectRepository_EnablePolicyForProject_Call {
- return &ProjectRepository_EnablePolicyForProject_Call{Call: _e.mock.On("EnablePolicyForProject", ctx, tx, projectID, policyID)}
-}
-
-func (_c *ProjectRepository_EnablePolicyForProject_Call) Run(run func(ctx context.Context, tx shared.DB, projectID uuid.UUID, policyID uuid.UUID)) *ProjectRepository_EnablePolicyForProject_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 shared.DB
- if args[1] != nil {
- arg1 = args[1].(shared.DB)
- }
- var arg2 uuid.UUID
- if args[2] != nil {
- arg2 = args[2].(uuid.UUID)
- }
- var arg3 uuid.UUID
- if args[3] != nil {
- arg3 = args[3].(uuid.UUID)
- }
- run(
- arg0,
- arg1,
- arg2,
- arg3,
- )
- })
- return _c
-}
-
-func (_c *ProjectRepository_EnablePolicyForProject_Call) Return(err error) *ProjectRepository_EnablePolicyForProject_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *ProjectRepository_EnablePolicyForProject_Call) RunAndReturn(run func(ctx context.Context, tx shared.DB, projectID uuid.UUID, policyID uuid.UUID) error) *ProjectRepository_EnablePolicyForProject_Call {
- _c.Call.Return(run)
- return _c
-}
-
// GetByOrgID provides a mock function for the type ProjectRepository
func (_mock *ProjectRepository) GetByOrgID(ctx context.Context, tx shared.DB, organizationID uuid.UUID) ([]models.Project, error) {
ret := _mock.Called(ctx, tx, organizationID)
diff --git a/mocks/mock_ReportingDescriptorReference.go b/mocks/mock_ReportingDescriptorReference.go
deleted file mode 100644
index e38e0efb6..000000000
--- a/mocks/mock_ReportingDescriptorReference.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Code generated by mockery; DO NOT EDIT.
-// github.com/vektra/mockery
-// template: testify
-
-package mocks
-
-import (
- mock "github.com/stretchr/testify/mock"
-)
-
-// NewReportingDescriptorReference creates a new instance of ReportingDescriptorReference. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewReportingDescriptorReference(t interface {
- mock.TestingT
- Cleanup(func())
-}) *ReportingDescriptorReference {
- mock := &ReportingDescriptorReference{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
-
-// ReportingDescriptorReference is an autogenerated mock type for the ReportingDescriptorReference type
-type ReportingDescriptorReference struct {
- mock.Mock
-}
-
-type ReportingDescriptorReference_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *ReportingDescriptorReference) EXPECT() *ReportingDescriptorReference_Expecter {
- return &ReportingDescriptorReference_Expecter{mock: &_m.Mock}
-}
diff --git a/mocks/mock_VulnDBImportService.go b/mocks/mock_VulnDBImportService.go
deleted file mode 100644
index fbc5bbcf9..000000000
--- a/mocks/mock_VulnDBImportService.go
+++ /dev/null
@@ -1,260 +0,0 @@
-// Code generated by mockery; DO NOT EDIT.
-// github.com/vektra/mockery
-// template: testify
-
-package mocks
-
-import (
- "context"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// NewVulnDBImportService creates a new instance of VulnDBImportService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewVulnDBImportService(t interface {
- mock.TestingT
- Cleanup(func())
-}) *VulnDBImportService {
- mock := &VulnDBImportService{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
-
-// VulnDBImportService is an autogenerated mock type for the VulnDBImportService type
-type VulnDBImportService struct {
- mock.Mock
-}
-
-type VulnDBImportService_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *VulnDBImportService) EXPECT() *VulnDBImportService_Expecter {
- return &VulnDBImportService_Expecter{mock: &_m.Mock}
-}
-
-// CleanupOrphanedTables provides a mock function for the type VulnDBImportService
-func (_mock *VulnDBImportService) CleanupOrphanedTables(ctx context.Context) error {
- ret := _mock.Called(ctx)
-
- if len(ret) == 0 {
- panic("no return value specified for CleanupOrphanedTables")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context) error); ok {
- r0 = returnFunc(ctx)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// VulnDBImportService_CleanupOrphanedTables_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CleanupOrphanedTables'
-type VulnDBImportService_CleanupOrphanedTables_Call struct {
- *mock.Call
-}
-
-// CleanupOrphanedTables is a helper method to define mock.On call
-// - ctx context.Context
-func (_e *VulnDBImportService_Expecter) CleanupOrphanedTables(ctx interface{}) *VulnDBImportService_CleanupOrphanedTables_Call {
- return &VulnDBImportService_CleanupOrphanedTables_Call{Call: _e.mock.On("CleanupOrphanedTables", ctx)}
-}
-
-func (_c *VulnDBImportService_CleanupOrphanedTables_Call) Run(run func(ctx context.Context)) *VulnDBImportService_CleanupOrphanedTables_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- run(
- arg0,
- )
- })
- return _c
-}
-
-func (_c *VulnDBImportService_CleanupOrphanedTables_Call) Return(err error) *VulnDBImportService_CleanupOrphanedTables_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *VulnDBImportService_CleanupOrphanedTables_Call) RunAndReturn(run func(ctx context.Context) error) *VulnDBImportService_CleanupOrphanedTables_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CreateTablesWithSuffix provides a mock function for the type VulnDBImportService
-func (_mock *VulnDBImportService) CreateTablesWithSuffix(ctx context.Context, suffix string) error {
- ret := _mock.Called(ctx, suffix)
-
- if len(ret) == 0 {
- panic("no return value specified for CreateTablesWithSuffix")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, string) error); ok {
- r0 = returnFunc(ctx, suffix)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// VulnDBImportService_CreateTablesWithSuffix_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateTablesWithSuffix'
-type VulnDBImportService_CreateTablesWithSuffix_Call struct {
- *mock.Call
-}
-
-// CreateTablesWithSuffix is a helper method to define mock.On call
-// - ctx context.Context
-// - suffix string
-func (_e *VulnDBImportService_Expecter) CreateTablesWithSuffix(ctx interface{}, suffix interface{}) *VulnDBImportService_CreateTablesWithSuffix_Call {
- return &VulnDBImportService_CreateTablesWithSuffix_Call{Call: _e.mock.On("CreateTablesWithSuffix", ctx, suffix)}
-}
-
-func (_c *VulnDBImportService_CreateTablesWithSuffix_Call) Run(run func(ctx context.Context, suffix string)) *VulnDBImportService_CreateTablesWithSuffix_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 string
- if args[1] != nil {
- arg1 = args[1].(string)
- }
- run(
- arg0,
- arg1,
- )
- })
- return _c
-}
-
-func (_c *VulnDBImportService_CreateTablesWithSuffix_Call) Return(err error) *VulnDBImportService_CreateTablesWithSuffix_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *VulnDBImportService_CreateTablesWithSuffix_Call) RunAndReturn(run func(ctx context.Context, suffix string) error) *VulnDBImportService_CreateTablesWithSuffix_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ExportDiffs provides a mock function for the type VulnDBImportService
-func (_mock *VulnDBImportService) ExportDiffs(ctx context.Context, extraTableNameSuffix string) error {
- ret := _mock.Called(ctx, extraTableNameSuffix)
-
- if len(ret) == 0 {
- panic("no return value specified for ExportDiffs")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, string) error); ok {
- r0 = returnFunc(ctx, extraTableNameSuffix)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// VulnDBImportService_ExportDiffs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExportDiffs'
-type VulnDBImportService_ExportDiffs_Call struct {
- *mock.Call
-}
-
-// ExportDiffs is a helper method to define mock.On call
-// - ctx context.Context
-// - extraTableNameSuffix string
-func (_e *VulnDBImportService_Expecter) ExportDiffs(ctx interface{}, extraTableNameSuffix interface{}) *VulnDBImportService_ExportDiffs_Call {
- return &VulnDBImportService_ExportDiffs_Call{Call: _e.mock.On("ExportDiffs", ctx, extraTableNameSuffix)}
-}
-
-func (_c *VulnDBImportService_ExportDiffs_Call) Run(run func(ctx context.Context, extraTableNameSuffix string)) *VulnDBImportService_ExportDiffs_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 string
- if args[1] != nil {
- arg1 = args[1].(string)
- }
- run(
- arg0,
- arg1,
- )
- })
- return _c
-}
-
-func (_c *VulnDBImportService_ExportDiffs_Call) Return(err error) *VulnDBImportService_ExportDiffs_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *VulnDBImportService_ExportDiffs_Call) RunAndReturn(run func(ctx context.Context, extraTableNameSuffix string) error) *VulnDBImportService_ExportDiffs_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ImportFromDiff provides a mock function for the type VulnDBImportService
-func (_mock *VulnDBImportService) ImportFromDiff(ctx context.Context, extraTableNameSuffix *string) error {
- ret := _mock.Called(ctx, extraTableNameSuffix)
-
- if len(ret) == 0 {
- panic("no return value specified for ImportFromDiff")
- }
-
- var r0 error
- if returnFunc, ok := ret.Get(0).(func(context.Context, *string) error); ok {
- r0 = returnFunc(ctx, extraTableNameSuffix)
- } else {
- r0 = ret.Error(0)
- }
- return r0
-}
-
-// VulnDBImportService_ImportFromDiff_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ImportFromDiff'
-type VulnDBImportService_ImportFromDiff_Call struct {
- *mock.Call
-}
-
-// ImportFromDiff is a helper method to define mock.On call
-// - ctx context.Context
-// - extraTableNameSuffix *string
-func (_e *VulnDBImportService_Expecter) ImportFromDiff(ctx interface{}, extraTableNameSuffix interface{}) *VulnDBImportService_ImportFromDiff_Call {
- return &VulnDBImportService_ImportFromDiff_Call{Call: _e.mock.On("ImportFromDiff", ctx, extraTableNameSuffix)}
-}
-
-func (_c *VulnDBImportService_ImportFromDiff_Call) Run(run func(ctx context.Context, extraTableNameSuffix *string)) *VulnDBImportService_ImportFromDiff_Call {
- _c.Call.Run(func(args mock.Arguments) {
- var arg0 context.Context
- if args[0] != nil {
- arg0 = args[0].(context.Context)
- }
- var arg1 *string
- if args[1] != nil {
- arg1 = args[1].(*string)
- }
- run(
- arg0,
- arg1,
- )
- })
- return _c
-}
-
-func (_c *VulnDBImportService_ImportFromDiff_Call) Return(err error) *VulnDBImportService_ImportFromDiff_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *VulnDBImportService_ImportFromDiff_Call) RunAndReturn(run func(ctx context.Context, extraTableNameSuffix *string) error) *VulnDBImportService_ImportFromDiff_Call {
- _c.Call.Return(run)
- return _c
-}
diff --git a/router/artifact_router.go b/router/artifact_router.go
index 3b94c3246..05e08afcc 100644
--- a/router/artifact_router.go
+++ b/router/artifact_router.go
@@ -30,6 +30,7 @@ func NewArtifactRouter(
assetVersionGroup AssetVersionRouter,
artifactController *controllers.ArtifactController,
externalReferenceController *controllers.ExternalReferenceController,
+ attestationController *controllers.AttestationController,
artifactRepository shared.ArtifactRepository,
assetRepository shared.AssetRepository,
) ArtifactRouter {
@@ -43,6 +44,7 @@ func NewArtifactRouter(
artifactRouter.GET("/vex.xml/", artifactController.VEXXML)
artifactRouter.GET("/sbom.pdf/", artifactController.BuildPDFFromSBOM)
artifactRouter.GET("/vulnerability-report.pdf/", artifactController.BuildVulnerabilityReportPDF)
+ artifactRouter.GET("/attestations/", attestationController.ListByArtifact)
artifactRouter.DELETE("/", artifactController.DeleteArtifact, middlewares.NeededScope([]string{"manage"}), assetScopedRBAC(shared.ObjectAsset, shared.ActionUpdate))
artifactRouter.PUT("/", artifactController.UpdateArtifact, middlewares.NeededScope([]string{"manage"}), assetScopedRBAC(shared.ObjectAsset, shared.ActionUpdate))
diff --git a/router/asset_router.go b/router/asset_router.go
index b44b918c3..42b513337 100644
--- a/router/asset_router.go
+++ b/router/asset_router.go
@@ -32,7 +32,6 @@ func NewAssetRouter(
assetController *controllers.AssetController,
dependencyProxyController *dependencyfirewall.DependencyProxyController,
assetVersionController *controllers.AssetVersionController,
- complianceController *controllers.ComplianceController,
statisticsController *controllers.StatisticsController,
componentController *controllers.ComponentController,
intotoController *controllers.InToToController,
@@ -49,8 +48,6 @@ func NewAssetRouter(
assetRouter := projectGroup.Group.Group("/assets/:assetSlug", assetScopedRBAC(shared.ObjectAsset, shared.ActionRead))
assetRouter.GET("/", assetController.Read)
- assetRouter.GET("/compliance/", complianceController.AssetCompliance)
- assetRouter.GET("/compliance/:policy/", complianceController.Details)
assetRouter.GET("/number-of-exploits/", statisticsController.GetCVESWithKnownExploits)
assetRouter.GET("/components/licenses/", componentController.LicenseDistribution)
assetRouter.GET("/config-files/:config-file/", assetController.GetConfigFile)
diff --git a/router/asset_version_router.go b/router/asset_version_router.go
index 6a026ecd8..9abd26a76 100644
--- a/router/asset_version_router.go
+++ b/router/asset_version_router.go
@@ -30,7 +30,6 @@ func NewAssetVersionRouter(
assetGroup AssetRouter,
assetVersionController *controllers.AssetVersionController,
firstPartyVulnController *controllers.FirstPartyVulnController,
- complianceController *controllers.ComplianceController,
componentController *controllers.ComponentController,
statisticsController *controllers.StatisticsController,
attestationController *controllers.AttestationController,
@@ -50,8 +49,7 @@ func NewAssetVersionRouter(
assetVersionRouter.GET("/vex.json/", assetVersionController.VEXJSON)
assetVersionRouter.GET("/sbom.json/", assetVersionController.SBOMJSON)
assetVersionRouter.GET("/", assetVersionController.Read)
- assetVersionRouter.GET("/compliance/", complianceController.AssetCompliance)
- assetVersionRouter.GET("/compliance/:policy/", complianceController.Details)
+
assetVersionRouter.GET("/metrics/", assetVersionController.Metrics)
assetVersionRouter.GET("/components/licenses/", componentController.LicenseDistribution)
assetVersionRouter.GET("/affected-components/", assetVersionController.AffectedComponents)
diff --git a/router/compliance_risk_router.go b/router/compliance_risk_router.go
new file mode 100644
index 000000000..27177e34c
--- /dev/null
+++ b/router/compliance_risk_router.go
@@ -0,0 +1,28 @@
+package router
+
+import (
+ "github.com/l3montree-dev/devguard/controllers"
+ "github.com/l3montree-dev/devguard/middlewares"
+ "github.com/labstack/echo/v4"
+)
+
+type ComplianceRiskRouter struct {
+ *echo.Group
+}
+
+func NewComplianceRiskRouter(
+ assetVersionGroup AssetVersionRouter,
+ controller *controllers.ComplianceRiskController,
+) ComplianceRiskRouter {
+ complianceRisksRouter := assetVersionGroup.Group.Group("/compliance-risks")
+ complianceRisksRouter.GET("/", controller.ListPaged)
+ complianceRisksRouter.GET("/:complianceRiskID/", controller.Read)
+ complianceRisksRouter.GET("/:complianceRiskID/evidence/", controller.GetEvidence)
+ complianceRisksRouter.POST("/:complianceRiskID/", controller.CreateEvent, middlewares.NeededScope([]string{"manage"}), middlewares.DisallowPublicRequests)
+ complianceRisksRouter.POST("/:complianceRiskID/mitigate/", controller.Mitigate, middlewares.NeededScope([]string{"manage"}), middlewares.DisallowPublicRequests)
+
+ complianceRisksRouter.POST("/evaluate/", controller.RunAttestationEvaluation, middlewares.NeededScope([]string{"manage"}), middlewares.DisallowPublicRequests)
+ complianceRisksRouter.POST("/upload-zip/", controller.UploadZip, middlewares.NeededScope([]string{"manage"}), middlewares.DisallowPublicRequests)
+
+ return ComplianceRiskRouter{Group: complianceRisksRouter}
+}
diff --git a/router/org_router.go b/router/org_router.go
index eccc375e0..fb2871913 100644
--- a/router/org_router.go
+++ b/router/org_router.go
@@ -36,7 +36,6 @@ func NewOrgRouter(
dependencyProxyController *dependencyfirewall.DependencyProxyController,
dependencyVulnController *controllers.DependencyVulnController,
firstPartyVulnController *controllers.FirstPartyVulnController,
- policyController *controllers.PolicyController,
integrationController *controllers.IntegrationController,
webhookIntegration *controllers.WebhookController,
externalEntityProviderService shared.ExternalEntityProviderService,
@@ -75,8 +74,6 @@ func NewOrgRouter(
organizationRouter.GET("/content-tree/", orgController.ContentTree)
organizationRouter.GET("/dependency-vulns/", dependencyVulnController.ListByOrgPaged)
organizationRouter.GET("/first-party-vulns/", firstPartyVulnController.ListByOrgPaged)
- organizationRouter.GET("/policies/", policyController.GetOrganizationPolicies)
- organizationRouter.GET("/policies/:policyID/", policyController.GetPolicy)
organizationRouter.GET("/members/", orgController.Members)
organizationRouter.GET("/integrations/finish-installation/", integrationController.FinishInstallation)
organizationRouter.GET("/projects/", projectController.List)
@@ -89,18 +86,14 @@ func NewOrgRouter(
organizationUpdateAccessControlRequired.POST("/integrations/jira/test-and-save/", integrationController.TestAndSaveJiraIntegration)
organizationUpdateAccessControlRequired.POST("/integrations/webhook/test-and-save/", webhookIntegration.Save)
organizationUpdateAccessControlRequired.POST("/integrations/webhook/test/", webhookIntegration.Test)
- organizationUpdateAccessControlRequired.POST("/policies/", policyController.CreatePolicy)
- organizationUpdateAccessControlRequired.POST("/integrations/gitlab/test-and-save/", integrationController.TestAndSaveGitlabIntegration)
organizationUpdateAccessControlRequired.POST("/projects/", projectController.Create)
- organizationUpdateAccessControlRequired.DELETE("/policies/:policyID/", policyController.DeletePolicy)
organizationUpdateAccessControlRequired.DELETE("/integrations/gitlab/:gitlab_integration_id/", integrationController.DeleteGitLabAccessToken)
organizationUpdateAccessControlRequired.DELETE("/members/:userID/", orgController.RemoveMember)
organizationUpdateAccessControlRequired.DELETE("/integrations/jira/:jira_integration_id/", integrationController.DeleteJiraAccessToken)
organizationUpdateAccessControlRequired.DELETE("/integrations/webhook/:id/", webhookIntegration.Delete)
organizationUpdateAccessControlRequired.PATCH("/", orgController.Update)
- organizationUpdateAccessControlRequired.PUT("/policies/:policyID/", policyController.UpdatePolicy)
organizationUpdateAccessControlRequired.PUT("/members/:userID/", orgController.ChangeRole)
organizationUpdateAccessControlRequired.PUT("/integrations/webhook/:id/", webhookIntegration.Update)
diff --git a/router/project_router.go b/router/project_router.go
index d3f6ba6b8..86cda60e7 100644
--- a/router/project_router.go
+++ b/router/project_router.go
@@ -33,7 +33,6 @@ func NewProjectRouter(
assetController *controllers.AssetController,
dependencyProxyController *dependencyfirewall.DependencyProxyController,
dependencyVulnController *controllers.DependencyVulnController,
- policyController *controllers.PolicyController,
releaseController *controllers.ReleaseController,
statisticsController *controllers.StatisticsController,
webhookIntegration *controllers.WebhookController,
@@ -49,7 +48,6 @@ func NewProjectRouter(
projectRouter := organizationGroup.Group.Group("/projects/:projectSlug", projectScopedRBAC(shared.ObjectProject, shared.ActionRead))
projectRouter.GET("/", projectController.Read)
projectRouter.GET("/resources/", projectController.ListSubProjectsAndAssets)
- projectRouter.GET("/policies/", policyController.GetProjectPolicies)
projectRouter.GET("/dependency-vulns/", dependencyVulnController.ListByProjectPaged)
projectRouter.GET("/assets/", assetController.List)
projectRouter.GET("/members/", projectController.Members)
@@ -79,14 +77,12 @@ func NewProjectRouter(
projectUpdateAccessControlRequired.POST("/releases/:releaseID/items/", releaseController.AddItem)
projectUpdateAccessControlRequired.DELETE("/integrations/webhook/:id/", webhookIntegration.Delete)
- projectUpdateAccessControlRequired.DELETE("/policies/:policyID/", policyController.DisablePolicyForProject)
projectUpdateAccessControlRequired.DELETE("/", projectController.Delete)
projectUpdateAccessControlRequired.DELETE("/members/:userID/", projectController.RemoveMember)
projectUpdateAccessControlRequired.DELETE("/releases/:releaseID/", releaseController.Delete)
projectUpdateAccessControlRequired.DELETE("/releases/:releaseID/items/:itemID/", releaseController.RemoveItem)
projectUpdateAccessControlRequired.PUT("/integrations/webhook/:id/", webhookIntegration.Update)
- projectUpdateAccessControlRequired.PUT("/policies/:policyID/", policyController.EnablePolicyForProject)
projectUpdateAccessControlRequired.PATCH("/", projectController.Update)
projectUpdateAccessControlRequired.PUT("/members/:userID/", projectController.ChangeRole)
projectUpdateAccessControlRequired.PATCH("/releases/:releaseID/", releaseController.Update)
diff --git a/router/providers.go b/router/providers.go
index f2f799529..3a45d6ba5 100644
--- a/router/providers.go
+++ b/router/providers.go
@@ -10,6 +10,7 @@ var RouterModule = fx.Options(
fx.Provide(NewDependencyVulnRouter),
fx.Provide(NewFirstPartyVulnRouter),
fx.Provide(NewLicenseRiskRouter),
+ fx.Provide(NewComplianceRiskRouter),
fx.Provide(NewOrgRouter),
fx.Provide(NewProjectRouter),
fx.Provide(NewSessionRouter),
diff --git a/router/router_test.go b/router/router_test.go
index 7b7251bba..c9356c32e 100644
--- a/router/router_test.go
+++ b/router/router_test.go
@@ -84,15 +84,15 @@ var intentionallyPublicPaths = map[string]bool{
// Key format: "METHOD /full/echo/path/template/"
var memberOnlyPaths = map[string]bool{
// Vuln triage actions — any member who can read the asset version may triage findings.
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/dependency-vulns/sync/": true,
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/dependency-vulns/batch/": true,
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/dependency-vulns/:dependencyVulnID/": true,
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/dependency-vulns/:dependencyVulnID/mitigate/": true,
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/first-party-vulns/:firstPartyVulnID/": true,
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/first-party-vulns/:firstPartyVulnID/mitigate/": true,
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/license-risks/": true,
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/license-risks/:licenseRiskID/": true,
- "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/license-risks/:licenseRiskID/mitigate/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/dependency-vulns/sync/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/dependency-vulns/batch/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/dependency-vulns/:dependencyVulnID/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/dependency-vulns/:dependencyVulnID/mitigate/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/first-party-vulns/:firstPartyVulnID/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/first-party-vulns/:firstPartyVulnID/mitigate/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/license-risks/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/license-risks/:licenseRiskID/": true,
+ "POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/license-risks/:licenseRiskID/mitigate/": true,
"POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/license-risks/:licenseRiskID/final-license-decision/": true,
// VEX rules — any member may create/edit/delete VEX rules (membership = passed read RBAC).
"POST /api/v1/organizations/:organization/projects/:project/assets/:assetSlug/refs/:assetVersionSlug/vex-rules/": true,
@@ -219,7 +219,6 @@ func buildSecurityTestServer(t *testing.T, ac *mocks.AccessControl) *echo.Echo {
new(dependencyfirewall.DependencyProxyController),
new(controllers.DependencyVulnController),
new(controllers.FirstPartyVulnController),
- new(controllers.PolicyController),
new(controllers.IntegrationController),
new(controllers.WebhookController),
extEntityService,
@@ -235,7 +234,6 @@ func buildSecurityTestServer(t *testing.T, ac *mocks.AccessControl) *echo.Echo {
new(controllers.AssetController),
new(dependencyfirewall.DependencyProxyController),
new(controllers.DependencyVulnController),
- new(controllers.PolicyController),
new(controllers.ReleaseController),
new(controllers.StatisticsController),
new(controllers.WebhookController),
@@ -248,7 +246,6 @@ func buildSecurityTestServer(t *testing.T, ac *mocks.AccessControl) *echo.Echo {
new(controllers.AssetController),
new(dependencyfirewall.DependencyProxyController),
new(controllers.AssetVersionController),
- new(controllers.ComplianceController),
new(controllers.StatisticsController),
new(controllers.ComponentController),
new(controllers.InToToController),
@@ -261,7 +258,6 @@ func buildSecurityTestServer(t *testing.T, ac *mocks.AccessControl) *echo.Echo {
assetRouter,
new(controllers.AssetVersionController),
new(controllers.FirstPartyVulnController),
- new(controllers.ComplianceController),
new(controllers.ComponentController),
new(controllers.StatisticsController),
new(controllers.AttestationController),
@@ -280,7 +276,7 @@ func buildSecurityTestServer(t *testing.T, ac *mocks.AccessControl) *echo.Echo {
NewFirstPartyVulnRouter(assetVersionRouter, new(controllers.FirstPartyVulnController), new(controllers.VulnEventController))
NewLicenseRiskRouter(assetVersionRouter, new(controllers.LicenseRiskController))
NewVEXRuleRouter(assetVersionRouter, new(controllers.VEXRuleController))
- NewArtifactRouter(assetVersionRouter, new(controllers.ArtifactController), new(controllers.ExternalReferenceController), artifactRepo, assetRepo)
+ NewArtifactRouter(assetVersionRouter, new(controllers.ArtifactController), new(controllers.ExternalReferenceController), new(controllers.AttestationController), artifactRepo, assetRepo)
NewExternalReferenceRouter(assetVersionRouter, new(controllers.ExternalReferenceController), assetRepo)
return e
diff --git a/services/attestation_service.go b/services/attestation_service.go
new file mode 100644
index 000000000..213a972c7
--- /dev/null
+++ b/services/attestation_service.go
@@ -0,0 +1,102 @@
+// Copyright (C) 2026 l3montree GmbH
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package services
+
+import (
+ "context"
+ "encoding/json"
+ "time"
+
+ "github.com/google/uuid"
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/dtos"
+ "github.com/l3montree-dev/devguard/shared"
+)
+
+const secondsPerHour = 3600.0
+
+type AttestationService struct {
+ attestationRepository shared.AttestationRepository
+ statisticsRepository shared.StatisticsRepository
+}
+
+var _ shared.AttestationService = (*AttestationService)(nil)
+
+func NewAttestationService(attestationRepository shared.AttestationRepository, statisticsRepository shared.StatisticsRepository) *AttestationService {
+ return &AttestationService{
+ attestationRepository: attestationRepository,
+ statisticsRepository: statisticsRepository,
+ }
+}
+
+func (s *AttestationService) GetByAssetID(ctx context.Context, tx shared.DB, assetID uuid.UUID) ([]models.Attestation, error) {
+ return s.attestationRepository.GetByAssetID(ctx, tx, assetID)
+}
+
+func (s *AttestationService) GetByAssetVersionAndAssetID(ctx context.Context, tx shared.DB, assetID uuid.UUID, assetVersion string) ([]models.Attestation, error) {
+ return s.attestationRepository.GetByAssetVersionAndAssetID(ctx, tx, assetID, assetVersion)
+}
+
+func (s *AttestationService) GetByArtifactAndAssetVersionAndAssetID(ctx context.Context, tx shared.DB, artifactName string, assetVersion string, assetID uuid.UUID) ([]models.Attestation, error) {
+ return s.attestationRepository.GetByArtifactAndAssetVersionAndAssetID(ctx, tx, artifactName, assetVersion, assetID)
+}
+
+func (s *AttestationService) Create(ctx context.Context, tx shared.DB, attestation *models.Attestation) error {
+ return s.attestationRepository.Create(ctx, tx, attestation)
+}
+
+func (s *AttestationService) GenerateAndStoreDevguardAttestation(ctx context.Context, assetID uuid.UUID, assetVersionName string, artifactName string) error {
+ averages, err := s.statisticsRepository.AverageFixingTimes(ctx, nil, assetVersionName, assetID)
+ if err != nil {
+ return err
+ }
+
+ attestationDTO := dtos.DevguardAssetAttestationDTO{
+ Type: dtos.DevguardAssetAttestationPredicateType,
+ GeneratedAt: time.Now().UTC(),
+ SchemaVersion: "1.0.0",
+ MeanTimeToRemediate: dtos.MeanTimeToRemediateDTO{
+ RiskLowAvgHours: averages.RiskAvgLow / secondsPerHour,
+ RiskMediumAvgHours: averages.RiskAvgMedium / secondsPerHour,
+ RiskHighAvgHours: averages.RiskAvgHigh / secondsPerHour,
+ RiskCriticalAvgHours: averages.RiskAvgCritical / secondsPerHour,
+ CVSSLowAvgHours: averages.CVSSAvgLow / secondsPerHour,
+ CVSSMediumAvgHours: averages.CVSSAvgMedium / secondsPerHour,
+ CVSSHighAvgHours: averages.CVSSAvgHigh / secondsPerHour,
+ CVSSCriticalAvgHours: averages.CVSSAvgCritical / secondsPerHour,
+ },
+ }
+
+ content, err := json.Marshal(attestationDTO)
+ if err != nil {
+ return err
+ }
+
+ var contentMap map[string]any
+ if err := json.Unmarshal(content, &contentMap); err != nil {
+ return err
+ }
+
+ attestation := models.Attestation{
+ AssetID: assetID,
+ AssetVersionName: assetVersionName,
+ ArtifactName: artifactName,
+ PredicateType: dtos.DevguardAssetAttestationPredicateType,
+ Content: contentMap,
+ }
+
+ return s.attestationRepository.Create(ctx, nil, &attestation)
+}
diff --git a/services/compliance_risk_service.go b/services/compliance_risk_service.go
new file mode 100644
index 000000000..be2ea9288
--- /dev/null
+++ b/services/compliance_risk_service.go
@@ -0,0 +1,428 @@
+package services
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+ "time"
+
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/dtos"
+ "github.com/l3montree-dev/devguard/dtos/sarif"
+ "github.com/l3montree-dev/devguard/shared"
+ "github.com/l3montree-dev/devguard/statemachine"
+ "github.com/l3montree-dev/devguard/utils"
+)
+
+type ComplianceRiskService struct {
+ complianceRiskRepository shared.ComplianceRiskRepository
+ vulnEventRepository shared.VulnEventRepository
+}
+
+var _ shared.ComplianceRiskService = (*ComplianceRiskService)(nil)
+
+func NewComplianceRiskService(complianceRiskRepository shared.ComplianceRiskRepository, vulnEventRepository shared.VulnEventRepository) *ComplianceRiskService {
+ return &ComplianceRiskService{
+ complianceRiskRepository: complianceRiskRepository,
+ vulnEventRepository: vulnEventRepository,
+ }
+}
+
+// HandleArtifactCompliance processes a SARIF compliance report for an artifact and manages the
+// lifecycle of compliance risks: new detections, branch-diffing, artifact association, and fixes.
+func (s *ComplianceRiskService) HandleArtifactCompliance(ctx context.Context, tx shared.DB, userID string, userAgent *string, assetVersion models.AssetVersion, artifact models.Artifact, sarifDoc sarif.SarifSchema210Json) error {
+ // fetch all existing compliance risks for this asset version (across all artifacts)
+ existingRisks, err := s.complianceRiskRepository.GetAllComplianceRisksForAssetVersion(ctx, tx, assetVersion.AssetID, assetVersion.Name)
+ if err != nil {
+ return err
+ }
+
+ foundRisks := sarifToComplianceRisks(sarifDoc, assetVersion)
+
+ // compare found risks with existing ones using hash-based identity
+ comparison := utils.CompareSlices(foundRisks, existingRisks, func(r models.ComplianceRisk) string {
+ return r.CalculateHash().String()
+ })
+
+ newRisks := comparison.OnlyInA
+ fixedRisks := comparison.OnlyInB
+ inBoth := comparison.InBoth
+
+ // get risks from other branches for branch-diffing of new detections
+ existingRisksOnOtherBranch, err := s.complianceRiskRepository.GetComplianceRisksByOtherAssetVersions(ctx, tx, assetVersion.Name, assetVersion.AssetID)
+ if err != nil {
+ slog.Error("could not get existing compliance risks on other branches", "err", err)
+ return err
+ }
+ existingRisksOnOtherBranch = utils.Filter(existingRisksOnOtherBranch, func(r models.ComplianceRisk) bool {
+ return r.State != dtos.VulnStateFixed
+ })
+
+ // branch-diff new risks
+ branchDiff := statemachine.DiffVulnsBetweenBranches(
+ utils.Map(newRisks, utils.Ptr),
+ utils.Map(existingRisksOnOtherBranch, utils.Ptr),
+ )
+
+ // determine which "fixed" risks are truly fixed everywhere vs just removed from this artifact
+ existingNeedsAssoc := make([]models.ComplianceRisk, 0)
+ for _, r := range inBoth {
+ alreadyAssoc := utils.Any(r.Artifacts, func(a models.Artifact) bool {
+ return a.ArtifactName == artifact.ArtifactName
+ })
+ if !alreadyAssoc {
+ existingNeedsAssoc = append(existingNeedsAssoc, r)
+ }
+ }
+
+ existingNeedsDissoc := make([]models.ComplianceRisk, 0)
+ finallyFixed := make([]models.ComplianceRisk, 0)
+ for _, r := range fixedRisks {
+ if len(r.Artifacts) > 1 {
+ existingNeedsDissoc = append(existingNeedsDissoc, r)
+ } else if len(r.Artifacts) == 1 && r.Artifacts[0].ArtifactName != artifact.ArtifactName {
+ existingNeedsDissoc = append(existingNeedsDissoc, r)
+ } else {
+ finallyFixed = append(finallyFixed, r)
+ }
+ }
+
+ return s.complianceRiskRepository.Transaction(ctx, func(db shared.DB) error {
+ // update policy/evidence metadata
+ if err := s.complianceRiskRepository.SaveBatch(ctx, db, inBoth); err != nil {
+ return err
+ }
+
+ // risks that exist on other branches: copy event history
+ if err := s.UserDetectedExistingComplianceRiskOnDifferentBranch(ctx, db, artifact.ArtifactName, branchDiff.ExistingOnOtherBranches, assetVersion); err != nil {
+ slog.Error("error processing existing compliance risk on different branch", "err", err)
+ return err
+ }
+
+ // brand-new risks never seen before
+ newToAllBranches := utils.Map(utils.DereferenceSlice(branchDiff.NewToAllBranches), func(r models.ComplianceRisk) models.ComplianceRisk { return r })
+ if err := s.UserDetectedComplianceRisks(ctx, db, userID, userAgent, assetVersion.Name, artifact.ArtifactName, newToAllBranches); err != nil {
+ return err
+ }
+
+ // risks now fixed everywhere
+ if err := s.UserFixedComplianceRisks(ctx, db, userID, userAgent, finallyFixed); err != nil {
+ return err
+ }
+
+ // risks seen in this artifact for the first time (already exist in other artifacts)
+ if err := s.UserDetectedComplianceRiskInAnotherArtifact(ctx, db, existingNeedsAssoc, artifact.ArtifactName); err != nil {
+ return err
+ }
+
+ // risks no longer seen in this artifact (still exists in others)
+ if err := s.UserDidNotDetectComplianceRiskInArtifactAnymore(ctx, db, existingNeedsDissoc, artifact.ArtifactName); err != nil {
+ return err
+ }
+
+ return nil
+ })
+}
+
+func (s *ComplianceRiskService) UserDetectedExistingComplianceRiskOnDifferentBranch(ctx context.Context, tx shared.DB, artifactName string, matches []statemachine.BranchVulnMatch[*models.ComplianceRisk], assetVersion models.AssetVersion) error {
+ if len(matches) == 0 {
+ return nil
+ }
+
+ risks := utils.Map(matches, func(m statemachine.BranchVulnMatch[*models.ComplianceRisk]) models.ComplianceRisk {
+ r := *m.CurrentBranchVuln
+ r.Artifacts = append(r.Artifacts, models.Artifact{
+ ArtifactName: artifactName,
+ AssetVersionName: assetVersion.Name,
+ AssetID: assetVersion.AssetID,
+ })
+ return r
+ })
+ events := utils.Map(matches, func(m statemachine.BranchVulnMatch[*models.ComplianceRisk]) []models.VulnEvent {
+ return m.EventsToCopy
+ })
+
+ if err := s.complianceRiskRepository.SaveBatch(ctx, tx, risks); err != nil {
+ return err
+ }
+ return s.vulnEventRepository.SaveBatch(ctx, tx, utils.Flat(events))
+}
+
+func (s *ComplianceRiskService) UserDetectedComplianceRisks(ctx context.Context, tx shared.DB, userID string, userAgent *string, assetVersionName, artifactName string, risks []models.ComplianceRisk) error {
+ if len(risks) == 0 {
+ return nil
+ }
+ events := make([]models.VulnEvent, len(risks))
+ for i := range risks {
+ risks[i].Artifacts = append(risks[i].Artifacts, models.Artifact{
+ ArtifactName: artifactName,
+ AssetVersionName: assetVersionName,
+ AssetID: risks[i].AssetID,
+ })
+ ev := models.NewDetectedEvent(risks[i].CalculateHash(), dtos.VulnTypeComplianceRisk, userID, dtos.RiskCalculationReport{}, artifactName, false, userAgent)
+ statemachine.Apply(&risks[i], ev)
+ events[i] = ev
+ }
+ if err := s.complianceRiskRepository.SaveBatch(ctx, tx, risks); err != nil {
+ return err
+ }
+ return s.vulnEventRepository.SaveBatch(ctx, tx, events)
+}
+
+func (s *ComplianceRiskService) UserFixedComplianceRisks(ctx context.Context, tx shared.DB, userID string, userAgent *string, risks []models.ComplianceRisk) error {
+ if len(risks) == 0 {
+ return nil
+ }
+ events := make([]models.VulnEvent, len(risks))
+ for i := range risks {
+ ev := models.NewFixedEvent(risks[i].CalculateHash(), dtos.VulnTypeComplianceRisk, userID, "", false, userAgent)
+ statemachine.Apply(&risks[i], ev)
+ events[i] = ev
+ }
+ if err := s.complianceRiskRepository.SaveBatch(ctx, tx, risks); err != nil {
+ return err
+ }
+ return s.vulnEventRepository.SaveBatch(ctx, tx, events)
+}
+
+func (s *ComplianceRiskService) UserDetectedComplianceRiskInAnotherArtifact(ctx context.Context, tx shared.DB, risks []models.ComplianceRisk, artifactName string) error {
+ if len(risks) == 0 {
+ return nil
+ }
+ for i := range risks {
+ if err := tx.Exec(
+ "INSERT INTO artifact_compliance_risks (artifact_artifact_name, artifact_asset_version_name, artifact_asset_id, compliance_risk_id) VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING",
+ artifactName, risks[i].AssetVersionName, risks[i].AssetID, risks[i].CalculateHash(),
+ ).Error; err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (s *ComplianceRiskService) UserDidNotDetectComplianceRiskInArtifactAnymore(ctx context.Context, tx shared.DB, risks []models.ComplianceRisk, artifactName string) error {
+ if len(risks) == 0 {
+ return nil
+ }
+ for i := range risks {
+ if err := tx.Exec(
+ "DELETE FROM artifact_compliance_risks WHERE artifact_artifact_name = ? AND artifact_asset_version_name = ? AND artifact_asset_id = ? AND compliance_risk_id = ?",
+ artifactName, risks[i].AssetVersionName, risks[i].AssetID, risks[i].ID,
+ ).Error; err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (s *ComplianceRiskService) UpdateComplianceRiskState(ctx context.Context, tx shared.DB, userID string, risk *models.ComplianceRisk, statusType string, justification string, mechanicalJustification dtos.MechanicalJustificationType, userAgent *string) (models.VulnEvent, error) {
+ if tx == nil {
+ var ev models.VulnEvent
+ var err error
+ err = s.complianceRiskRepository.Transaction(ctx, func(d shared.DB) error {
+ ev, err = s.updateComplianceRiskState(ctx, d, userID, risk, statusType, justification, mechanicalJustification, userAgent)
+ return err
+ })
+ return ev, err
+ }
+ return s.updateComplianceRiskState(ctx, tx, userID, risk, statusType, justification, mechanicalJustification, userAgent)
+}
+
+func (s *ComplianceRiskService) updateComplianceRiskState(ctx context.Context, tx shared.DB, userID string, risk *models.ComplianceRisk, statusType string, justification string, mechanicalJustification dtos.MechanicalJustificationType, userAgent *string) (models.VulnEvent, error) {
+ var ev models.VulnEvent
+ switch dtos.VulnEventType(statusType) {
+ case dtos.EventTypeAccepted:
+ ev = models.NewAcceptedEvent(risk.CalculateHash(), dtos.VulnTypeComplianceRisk, userID, justification, false, userAgent)
+ case dtos.EventTypeFalsePositive:
+ ev = models.NewFalsePositiveEvent(risk.CalculateHash(), dtos.VulnTypeComplianceRisk, userID, justification, mechanicalJustification, risk.GetArtifactNames(), false, userAgent)
+ case dtos.EventTypeReopened:
+ ev = models.NewReopenedEvent(risk.CalculateHash(), dtos.VulnTypeComplianceRisk, userID, justification, false, userAgent)
+ case dtos.EventTypeComment:
+ ev = models.NewCommentEvent(risk.CalculateHash(), dtos.VulnTypeComplianceRisk, userID, justification, false, userAgent)
+ default:
+ return models.VulnEvent{}, fmt.Errorf("unsupported event type: %s", statusType)
+ }
+ err := s.complianceRiskRepository.ApplyAndSave(ctx, tx, risk, &ev)
+ return ev, err
+}
+
+// sarifToComplianceRisks converts a SARIF document into ComplianceRisk models for the given asset version.
+// Each SARIF rule becomes one risk; its state is derived from the result kinds (pass/fail/open).
+func sarifToComplianceRisks(sarifDoc sarif.SarifSchema210Json, assetVersion models.AssetVersion) []models.ComplianceRisk {
+ if len(sarifDoc.Runs) == 0 {
+ return nil
+ }
+
+ risks := make([]models.ComplianceRisk, 0)
+ for _, run := range sarifDoc.Runs {
+
+ type ruleInfo struct {
+ title string
+ description *string
+ relatedResources []string
+ tags []string
+ priority int
+ policyFrameworks []models.PolicyFrameworks
+ }
+ ruleMap := make(map[string]ruleInfo, len(run.Tool.Driver.Rules))
+ for _, rule := range run.Tool.Driver.Rules {
+ var desc *string
+ if rule.FullDescription != nil && rule.FullDescription.Text != "" {
+ d := rule.FullDescription.Text
+ desc = &d
+ }
+
+ title := rule.ID
+ if rule.ShortDescription != nil {
+ title = rule.ShortDescription.Text
+ }
+
+ var tags []string
+ if rule.Properties != nil {
+ tags = rule.Properties.Tags
+ }
+
+ relatedResources := make([]string, 0)
+ if rule.Properties != nil {
+ if rr, ok := rule.Properties.AdditionalProperties["relatedResources"].([]string); ok {
+ relatedResources = rr
+ } else if rr, ok := rule.Properties.AdditionalProperties["relatedResources"].([]any); ok {
+ for _, r := range rr {
+ if s, ok := r.(string); ok {
+ relatedResources = append(relatedResources, s)
+ }
+ }
+ }
+ }
+
+ var policyFrameworks []models.PolicyFrameworks
+ if rule.Properties != nil {
+ if direct, ok := rule.Properties.AdditionalProperties["policyFrameworks"].([]models.PolicyFrameworks); ok {
+ policyFrameworks = direct
+ } else if cf, ok := rule.Properties.AdditionalProperties["policyFrameworks"].([]any); ok {
+ for _, c := range cf {
+ if cMap, ok := c.(map[string]any); ok {
+ pc := models.PolicyFrameworks{}
+ if fw, ok := cMap["framework"].(string); ok {
+ pc.Framework = fw
+ }
+ if ctls, ok := cMap["controls"].([]any); ok {
+ for _, ctl := range ctls {
+ if s, ok := ctl.(string); ok {
+ pc.Controls = append(pc.Controls, s)
+ }
+ }
+ }
+ policyFrameworks = append(policyFrameworks, pc)
+ }
+ }
+ }
+ }
+
+ var priority int
+ if rule.Properties != nil {
+ if p, ok := rule.Properties.AdditionalProperties["priority"].(int); ok {
+ priority = p
+ } else if pFloat, ok := rule.Properties.AdditionalProperties["priority"].(float64); ok {
+ priority = int(pFloat)
+ }
+ }
+
+ ruleMap[rule.ID] = ruleInfo{title: title, description: desc, relatedResources: relatedResources, tags: tags, priority: priority, policyFrameworks: policyFrameworks}
+ }
+
+ type policyResult struct {
+ kind sarif.ResultKind
+ message sarif.Message
+ violations []string
+ evidenceContent []byte
+ evidenceType string
+ }
+ resultMap := make(map[string]*policyResult, len(ruleMap))
+
+ for _, result := range run.Results {
+ if result.RuleID == nil {
+ continue
+ }
+ ruleID := *result.RuleID
+ pr := resultMap[ruleID]
+ if pr == nil {
+ pr = &policyResult{}
+ resultMap[ruleID] = pr
+ }
+
+ pr.message = result.Message
+
+ if result.Properties != nil {
+ if ac, ok := result.Properties.AdditionalProperties["evidenceContent"].(string); ok && pr.evidenceContent == nil {
+ pr.evidenceContent = []byte(ac)
+ }
+ if et, ok := result.Properties.AdditionalProperties["evidenceType"].(string); ok {
+ pr.evidenceType = et
+ }
+ if v, ok := result.Properties.AdditionalProperties["violations"].([]string); ok {
+ pr.violations = v
+ }
+ }
+
+ switch result.Kind {
+ case sarif.ResultKindFail:
+ pr.kind = sarif.ResultKindFail
+ case sarif.ResultKindOpen:
+ if pr.kind != sarif.ResultKindFail {
+ pr.kind = sarif.ResultKindOpen
+ }
+ case sarif.ResultKindPass:
+ if pr.kind == "" {
+ pr.kind = sarif.ResultKindPass
+ }
+ }
+
+ }
+
+ for ruleID, info := range ruleMap {
+ state := dtos.VulnStateOpen
+ var violations []string
+ var evidenceContent []byte
+ var evidenceType string
+ var message string
+
+ if pr := resultMap[ruleID]; pr != nil {
+ evidenceContent = pr.evidenceContent
+ switch pr.kind {
+ case sarif.ResultKindPass:
+ state = dtos.VulnStateFixed
+ case sarif.ResultKindFail:
+ state = dtos.VulnStateOpen
+ violations = pr.violations
+ }
+ evidenceType = pr.evidenceType
+ message = pr.message.Text
+
+ }
+
+ risks = append(risks, models.ComplianceRisk{
+ Vulnerability: models.Vulnerability{
+ AssetVersionName: assetVersion.Name,
+ AssetID: assetVersion.AssetID,
+ AssetVersion: assetVersion,
+ State: state,
+ LastDetected: time.Now(),
+ },
+ PolicyID: ruleID,
+ PolicyTitle: info.title,
+ PolicyDescription: info.description,
+ PolicyRelatedResources: info.relatedResources,
+ PolicyTags: info.tags,
+ PolicyPriority: info.priority,
+ PolicyFrameworks: info.policyFrameworks,
+ EvidenceType: evidenceType,
+ Violations: violations,
+ EvidenceContent: evidenceContent,
+ Message: message,
+ })
+ }
+ }
+
+ return risks
+}
diff --git a/services/compliance_service.go b/services/compliance_service.go
new file mode 100644
index 000000000..41f4cbe86
--- /dev/null
+++ b/services/compliance_service.go
@@ -0,0 +1,63 @@
+// Copyright (C) 2025 l3montree GmbH
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+package services
+
+import (
+ "context"
+
+ "github.com/google/uuid"
+ "github.com/l3montree-dev/devguard/compliance"
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/dtos/sarif"
+ "github.com/l3montree-dev/devguard/shared"
+)
+
+type ComplianceService struct {
+ attestationRepository shared.AttestationRepository
+}
+
+func NewComplianceService(attestationRepository shared.AttestationRepository) *ComplianceService {
+ return &ComplianceService{
+ attestationRepository: attestationRepository,
+ }
+}
+
+func (s *ComplianceService) EvaluateArtifactAttestations(ctx context.Context, projectID uuid.UUID, assetVersion models.AssetVersion, artifact models.Artifact) (sarif.SarifSchema210Json, error) {
+ attestations, err := s.attestationRepository.GetByArtifactAndAssetVersionAndAssetID(ctx, nil, artifact.ArtifactName, assetVersion.Name, assetVersion.AssetID)
+ if err != nil {
+ return sarif.SarifSchema210Json{}, err
+ }
+
+ policies, err := compliance.GetPoliciesFromFS("attestation-compliance-policies/policies")
+ if err != nil {
+ return sarif.SarifSchema210Json{}, err
+ }
+
+ evals := make([]compliance.PolicyEvaluation, 0, len(policies))
+foundMatch:
+ for _, policy := range policies {
+ for _, attestation := range attestations {
+ if attestation.PredicateType != policy.PredicateType {
+ continue
+ }
+ eval := compliance.Eval(policy, attestation.Content)
+ evals = append(evals, eval)
+ continue foundMatch
+ }
+ evals = append(evals, compliance.Eval(policy, nil))
+ }
+
+ return compliance.BuildSarifFromPoliciesEvaluations("", evals), nil
+}
diff --git a/services/dependency_vuln_service.go b/services/dependency_vuln_service.go
index af679e783..9caf35de2 100644
--- a/services/dependency_vuln_service.go
+++ b/services/dependency_vuln_service.go
@@ -340,6 +340,8 @@ func (s *DependencyVulnService) createVulnEventAndApply(ctx context.Context, tx
ev = models.NewCommentEvent(dependencyVuln.CalculateHash(), dtos.VulnTypeDependencyVuln, userID, justification, false, userAgent)
case dtos.EventTypeFixed:
ev = models.NewFixedEvent(dependencyVuln.CalculateHash(), dtos.VulnTypeDependencyVuln, userID, dependencyVuln.GetScannerIDsOrArtifactNames(), false, userAgent)
+ default:
+ return models.VulnEvent{}, fmt.Errorf("unsupported event type: %s", vulnEventType)
}
// Apply the event to the original vuln
diff --git a/services/external_entity_provider_service.go b/services/external_entity_provider_service.go
index 986dc98f8..aff440b0a 100644
--- a/services/external_entity_provider_service.go
+++ b/services/external_entity_provider_service.go
@@ -136,10 +136,6 @@ func (s externalEntityProviderService) RefreshExternalEntityProviderProjects(ctx
return nil, err
}
- if err := s.enableCommunityPoliciesForNewProjects(ctx.Request().Context(), created); err != nil {
- return nil, err
- }
-
projectsMap := s.createProjectsMap(ctx.Request().Context(), created, updated)
assets, err := s.syncProjectsAndAssets(ctx, domainRBAC, user, projects, roles, append(created, updated...))
@@ -199,16 +195,6 @@ func (s externalEntityProviderService) upsertProjects(ctx context.Context, org m
return created, updated, nil
}
-func (s externalEntityProviderService) enableCommunityPoliciesForNewProjects(ctx context.Context, created []models.Project) error {
- for _, project := range created {
- if err := s.projectRepository.EnableCommunityManagedPolicies(ctx, nil, project.ID); err != nil {
- return fmt.Errorf("could not enable community managed policies for project %s: %w", project.Slug, err)
- }
- slog.Info("enabled community managed policies for project", "projectSlug", project.Slug, "projectID", project.ID)
- }
- return nil
-}
-
func (s externalEntityProviderService) createProjectsMap(ctx context.Context, created, updated []models.Project) map[string]struct{} {
projectsMap := make(map[string]struct{}, len(created)+len(updated))
for _, project := range append(created, updated...) {
diff --git a/services/external_entity_provider_service_test.go b/services/external_entity_provider_service_test.go
index 0d21b65d4..e2a48d83b 100644
--- a/services/external_entity_provider_service_test.go
+++ b/services/external_entity_provider_service_test.go
@@ -191,41 +191,6 @@ func TestUpsertProjects(t *testing.T) {
})
}
-func TestEnableCommunityPoliciesForNewProjects(t *testing.T) {
- t.Run("successful enable", func(t *testing.T) {
- projectRepo := mocks.NewProjectRepository(t)
- service := createTestServiceWithRepo(t, projectRepo)
-
- projects := []models.Project{
- {Model: models.Model{ID: uuid.New()}, Slug: "project1"},
- {Model: models.Model{ID: uuid.New()}, Slug: "project2"},
- }
-
- for _, project := range projects {
- projectRepo.On("EnableCommunityManagedPolicies", mock.Anything, mock.Anything, project.ID).Return(nil)
- }
-
- err := service.enableCommunityPoliciesForNewProjects(context.Background(), projects)
-
- assert.NoError(t, err)
- projectRepo.AssertExpectations(t)
- })
-
- t.Run("repository error", func(t *testing.T) {
- projectRepo := mocks.NewProjectRepository(t)
- service := createTestServiceWithRepo(t, projectRepo)
-
- projects := []models.Project{{Model: models.Model{ID: uuid.New()}, Slug: "project1"}}
-
- projectRepo.On("EnableCommunityManagedPolicies", mock.Anything, mock.Anything, projects[0].ID).Return(errors.New("policy error"))
-
- err := service.enableCommunityPoliciesForNewProjects(context.Background(), projects)
-
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "could not enable community managed policies for project project1")
- })
-}
-
func TestSyncOrgs(t *testing.T) {
t.Run("successful sync with new organizations", func(t *testing.T) {
ctx := createTestContext()
diff --git a/services/first_party_vuln_service.go b/services/first_party_vuln_service.go
index 6d4ac7c32..8138abe24 100644
--- a/services/first_party_vuln_service.go
+++ b/services/first_party_vuln_service.go
@@ -120,6 +120,8 @@ func (s *firstPartyVulnService) updateFirstPartyVulnState(ctx context.Context, t
ev = models.NewReopenedEvent(firstPartyVuln.CalculateHash(), dtos.VulnTypeFirstPartyVuln, userID, justification, false, userAgent)
case dtos.EventTypeComment:
ev = models.NewCommentEvent(firstPartyVuln.CalculateHash(), dtos.VulnTypeFirstPartyVuln, userID, justification, false, userAgent)
+ default:
+ return models.VulnEvent{}, fmt.Errorf("unsupported event type: %s", statusType)
}
return s.applyAndSave(ctx, tx, firstPartyVuln, &ev)
diff --git a/services/license_risk_service.go b/services/license_risk_service.go
index a8435b008..98fa98710 100644
--- a/services/license_risk_service.go
+++ b/services/license_risk_service.go
@@ -2,6 +2,7 @@ package services
import (
"context"
+ "fmt"
"log/slog"
"slices"
"strings"
@@ -403,6 +404,8 @@ func (s *LicenseRiskService) updateLicenseRiskState(ctx context.Context, tx shar
ev = models.NewReopenedEvent(licenseRisk.CalculateHash(), dtos.VulnTypeLicenseRisk, userID, justification, false, userAgent)
case dtos.EventTypeComment:
ev = models.NewCommentEvent(licenseRisk.CalculateHash(), dtos.VulnTypeLicenseRisk, userID, justification, false, userAgent)
+ default:
+ return models.VulnEvent{}, fmt.Errorf("unsupported event type: %s", statusType)
}
err := s.licenseRiskRepository.ApplyAndSave(ctx, tx, licenseRisk, &ev)
diff --git a/services/project_service.go b/services/project_service.go
index be2575273..4fbfbc4bf 100644
--- a/services/project_service.go
+++ b/services/project_service.go
@@ -61,9 +61,7 @@ func (s *projectService) CreateProject(ctx shared.Context, project *models.Proje
return echo.NewHTTPError(500, "could not create project").WithInternal(err)
}
}
-
- // enable the default community policies
- return s.projectRepository.EnableCommunityManagedPolicies(ctx.Request().Context(), tx, newProject.ID)
+ return nil
})
if err != nil {
slog.Error("could not create project", "err", err, "projectSlug", project.Slug, "projectID", project.ID)
diff --git a/services/providers.go b/services/providers.go
index 479d5824e..79117efb5 100644
--- a/services/providers.go
+++ b/services/providers.go
@@ -18,6 +18,8 @@ var ServiceModule = fx.Options(
fx.Provide(fx.Annotate(NewConfigService, fx.As(new(shared.ConfigService)))),
fx.Provide(fx.Annotate(NewFirstPartyVulnService, fx.As(new(shared.FirstPartyVulnService)))),
fx.Provide(fx.Annotate(NewLicenseRiskService, fx.As(new(shared.LicenseRiskService)))),
+ fx.Provide(fx.Annotate(NewComplianceService, fx.As(new(shared.ComplianceService)))),
+ fx.Provide(fx.Annotate(NewComplianceRiskService, fx.As(new(shared.ComplianceRiskService)))),
fx.Provide(fx.Annotate(NewProjectService, fx.As(new(shared.ProjectService)))),
fx.Provide(fx.Annotate(NewAssetService, fx.As(new(shared.AssetService)))),
fx.Provide(fx.Annotate(NewComponentService, fx.As(new(shared.ComponentService)))),
@@ -25,6 +27,7 @@ var ServiceModule = fx.Options(
fx.Provide(func() http.Client { return utils.EgressClient }),
fx.Provide(fx.Annotate(NewCSAFService, fx.As(new(shared.CSAFService)))),
fx.Provide(fx.Annotate(NewArtifactService, fx.As(new(shared.ArtifactService)))),
+ fx.Provide(fx.Annotate(NewAttestationService, fx.As(new(shared.AttestationService)))),
fx.Provide(fx.Annotate(NewStatisticsService, fx.As(new(shared.StatisticsService)))),
fx.Provide(fx.Annotate(NewInTotoService, fx.As(new(shared.InTotoVerifierService)))),
fx.Provide(fx.Annotate(NewOrgService, fx.As(new(shared.OrgService)))),
diff --git a/shared/common_interfaces.go b/shared/common_interfaces.go
index 72a531708..53b16c601 100644
--- a/shared/common_interfaces.go
+++ b/shared/common_interfaces.go
@@ -44,7 +44,6 @@ type DaemonRunner interface {
UpdateFixedVersions(ctx context.Context) error
UpdateVulnDB(ctx context.Context) error
UpdateOpenSourceInsightInformation(ctx context.Context) error
-
Start(ctx context.Context)
}
@@ -98,10 +97,7 @@ type ProjectRepository interface {
GetByProjectIDs(ctx context.Context, tx DB, projectIDs []uuid.UUID) ([]models.Project, error)
List(ctx context.Context, tx DB, idSlice []uuid.UUID, parentID *uuid.UUID, organizationID uuid.UUID) ([]models.Project, error)
ListPaged(ctx context.Context, tx DB, projectIDs []uuid.UUID, parentID *uuid.UUID, orgID uuid.UUID, pageInfo PageInfo, search string, filter []FilterQuery, sort []SortQuery) (Paged[models.Project], error)
- EnablePolicyForProject(ctx context.Context, tx DB, projectID uuid.UUID, policyID uuid.UUID) error
- DisablePolicyForProject(ctx context.Context, tx DB, projectID uuid.UUID, policyID uuid.UUID) error
Upsert(ctx context.Context, tx DB, projects *[]*models.Project, conflictingColumns []clause.Column, toUpdate []string) error
- EnableCommunityManagedPolicies(ctx context.Context, tx DB, projectID uuid.UUID) error
UpsertSplit(ctx context.Context, tx DB, externalProviderID string, projects []*models.Project) ([]*models.Project, []*models.Project, error)
ListSubProjectsAndAssets(ctx context.Context, tx DB, allowedAssetIDs []string, allowedProjectIDs []uuid.UUID, parentID *uuid.UUID, orgID uuid.UUID, pageInfo PageInfo, search string, filter []FilterQuery, sort []SortQuery) (Paged[dtos.ProjectAssetDTO], error)
SearchProjectsWithSubProjectsAndAssetsPaged(ctx context.Context, tx DB, allowedAssetIDs []string, allowedProjectIDs []string, parentID *uuid.UUID, orgID uuid.UUID, pageInfo PageInfo, search string, filter []FilterQuery, sort []SortQuery) (Paged[dtos.ProjectDTO], error)
@@ -112,13 +108,6 @@ type Verifier interface {
VerifyRequestSignature(ctx context.Context, req *http.Request) (string, string, error)
}
-type PolicyRepository interface {
- utils.Repository[uuid.UUID, models.Policy, DB]
- FindByProjectID(ctx context.Context, tx DB, projectID uuid.UUID) ([]models.Policy, error)
- FindByOrganizationID(ctx context.Context, tx DB, organizationID uuid.UUID) ([]models.Policy, error)
- FindCommunityManagedPolicies(ctx context.Context, tx DB) ([]models.Policy, error)
-}
-
type DependencyProxySecretRepository interface {
utils.Repository[uuid.UUID, models.DependencyProxySecret, DB]
GetOrCreateByOrgID(ctx context.Context, tx DB, orgID uuid.UUID) (models.DependencyProxySecret, error)
@@ -157,6 +146,16 @@ type AttestationRepository interface {
utils.Repository[string, models.Attestation, DB]
GetByAssetID(ctx context.Context, tx DB, assetID uuid.UUID) ([]models.Attestation, error)
GetByAssetVersionAndAssetID(ctx context.Context, tx DB, assetID uuid.UUID, assetVersion string) ([]models.Attestation, error)
+ GetByArtifactAndAssetVersionAndAssetID(ctx context.Context, tx DB, artifactName string, assetVersion string, assetID uuid.UUID) ([]models.Attestation, error)
+ Create(ctx context.Context, tx DB, attestation *models.Attestation) error
+}
+
+type AttestationService interface {
+ GetByAssetID(ctx context.Context, tx DB, assetID uuid.UUID) ([]models.Attestation, error)
+ GetByAssetVersionAndAssetID(ctx context.Context, tx DB, assetID uuid.UUID, assetVersion string) ([]models.Attestation, error)
+ GetByArtifactAndAssetVersionAndAssetID(ctx context.Context, tx DB, artifactName string, assetVersion string, assetID uuid.UUID) ([]models.Attestation, error)
+ Create(ctx context.Context, tx DB, attestation *models.Attestation) error
+ GenerateAndStoreDevguardAttestation(ctx context.Context, assetID uuid.UUID, assetVersionName string, artifactName string) error
}
type ArtifactRepository interface {
@@ -169,6 +168,10 @@ type ArtifactRepository interface {
CleanupOrphanedRecords(ctx context.Context) error
}
+type ComplianceService interface {
+ EvaluateArtifactAttestations(ctx context.Context, projectID uuid.UUID, assetVersion models.AssetVersion, artifact models.Artifact) (sarif.SarifSchema210Json, error)
+}
+
type ReleaseRepository interface {
utils.Repository[uuid.UUID, models.Release, DB]
GetByProjectID(ctx context.Context, tx DB, projectID uuid.UUID) ([]models.Release, error)
@@ -284,6 +287,22 @@ type LicenseRiskRepository interface {
ApplyAndSave(ctx context.Context, tx DB, licenseRisk *models.LicenseRisk, vulnEvent *models.VulnEvent) error
}
+type ComplianceRiskRepository interface {
+ utils.Repository[uuid.UUID, models.ComplianceRisk, DB]
+ GetAllComplianceRisksForAssetVersion(ctx context.Context, tx DB, assetID uuid.UUID, assetVersionName string) ([]models.ComplianceRisk, error)
+ GetAllComplianceRisksForAssetVersionPaged(ctx context.Context, tx DB, assetID uuid.UUID, assetVersionName string, pageInfo PageInfo, search string, filter []FilterQuery, sort []SortQuery) (Paged[models.ComplianceRisk], error)
+ GetComplianceRisksByOtherAssetVersions(ctx context.Context, tx DB, assetVersionName string, assetID uuid.UUID) ([]models.ComplianceRisk, error)
+ Read(ctx context.Context, tx DB, id uuid.UUID) (models.ComplianceRisk, error)
+ ApplyAndSave(ctx context.Context, tx DB, risk *models.ComplianceRisk, ev *models.VulnEvent) error
+ GetDistinctFrameworksForAssetVersion(ctx context.Context, tx DB, assetID uuid.UUID, assetVersionName string) ([]string, error)
+ SaveBatch(ctx context.Context, tx DB, risks []models.ComplianceRisk) error
+}
+
+type ComplianceRiskService interface {
+ HandleArtifactCompliance(ctx context.Context, tx DB, userID string, userAgent *string, assetVersion models.AssetVersion, artifact models.Artifact, sarifDoc sarif.SarifSchema210Json) error
+ UpdateComplianceRiskState(ctx context.Context, tx DB, userID string, risk *models.ComplianceRisk, statusType string, justification string, mechanicalJustification dtos.MechanicalJustificationType, userAgent *string) (models.VulnEvent, error)
+}
+
type InTotoLinkRepository interface {
utils.Repository[uuid.UUID, models.InTotoLink, DB]
FindByAssetAndSupplyChainID(ctx context.Context, tx DB, assetID uuid.UUID, supplyChainID string) ([]models.InTotoLink, error)
diff --git a/shared/context_utils.go b/shared/context_utils.go
index fc4807de5..72ce65560 100644
--- a/shared/context_utils.go
+++ b/shared/context_utils.go
@@ -168,6 +168,23 @@ func GetVulnID(ctx Context) (uuid.UUID, dtos.VulnType, error) {
return id, dtos.VulnTypeLicenseRisk, nil
}
+ ComplianceRiskID := ctx.Param("complianceRiskID")
+ if ComplianceRiskID != "" {
+ id, err := uuid.Parse(ComplianceRiskID)
+ if err != nil {
+ return uuid.Nil, "", fmt.Errorf("invalid compliance risk id: %w", err)
+ }
+ return id, dtos.VulnTypeComplianceRisk, nil
+ }
+ ComplianceRiskIDFromGet, ok := ctx.Get("complianceRiskID").(string)
+ if ok && ComplianceRiskIDFromGet != "" {
+ id, err := uuid.Parse(ComplianceRiskIDFromGet)
+ if err != nil {
+ return uuid.Nil, "", fmt.Errorf("invalid compliance risk id: %w", err)
+ }
+ return id, dtos.VulnTypeComplianceRisk, nil
+ }
+
return uuid.Nil, "", fmt.Errorf("could not get vuln id")
}
@@ -557,6 +574,11 @@ func (f FilterQuery) SQL() string {
return field + " ILIKE ?"
case "any":
return "? = ANY(string_to_array(" + field + ", ' '))"
+ case "frameworkContains":
+ // Matches a JSONB array-of-objects column (e.g. policyFrameworks) where any
+ // element's "framework" key equals the value. Used by the compliance-risks
+ // framework filter.
+ return "EXISTS (SELECT 1 FROM jsonb_array_elements(" + field + ") AS e WHERE e->>'framework' = ?)"
default:
// default do an equals
return field + " = ?"
diff --git a/tests/fx_test_app.go b/tests/fx_test_app.go
index 3dbceda13..f2e1054b1 100644
--- a/tests/fx_test_app.go
+++ b/tests/fx_test_app.go
@@ -96,6 +96,11 @@ type TestApp struct {
VulnEventRepository shared.VulnEventRepository
ComponentProjectRepository shared.ComponentProjectRepository
StatisticsRepository shared.StatisticsRepository
+ AttestationRepository shared.AttestationRepository
+ AttestationService shared.AttestationService
+ ComplianceService shared.ComplianceService
+ ComplianceRiskService shared.ComplianceRiskService
+ ComplianceRiskRepository shared.ComplianceRiskRepository
LicenseRiskRepository shared.LicenseRiskRepository
GitLabOauth2TokenRepository shared.GitLabOauth2TokenRepository
GitlabIntegrationRepository shared.GitlabIntegrationRepository
diff --git a/tests/fx_test_helpers.go b/tests/fx_test_helpers.go
index 5f8e4d2ed..074c6ba94 100644
--- a/tests/fx_test_helpers.go
+++ b/tests/fx_test_helpers.go
@@ -180,6 +180,10 @@ func (f *TestFixture) CreateDaemonRunner() *daemons.DaemonRunner {
f.App.VulnDBService,
f.App.VexRuleService,
f.App.FixedVersionResolver,
+ f.App.AttestationService,
+ f.App.StatisticsRepository,
+ f.App.ComplianceService,
+ f.App.ComplianceRiskService,
)
}
diff --git a/tests/project_controller_test.go b/tests/project_controller_test.go
index cc4355fc0..74e47fe5a 100644
--- a/tests/project_controller_test.go
+++ b/tests/project_controller_test.go
@@ -22,68 +22,6 @@ func TestProjectCreation(t *testing.T) {
WithTestApp(t, "../initdb.sql", func(f *TestFixture) {
org, project, _, _ := f.CreateOrgProjectAssetAndVersion()
- t.Run("should enable all community policies by default", func(t *testing.T) {
- e := echo.New()
- rec := httptest.NewRecorder()
- // create a community policy
- communityPolicy := models.Policy{
- Title: "Community Policy 1",
- Description: "This is a community policy",
- OrganizationID: nil, // nil means it's a community policy
- }
-
- assert.Nil(t, f.DB.Create(&communityPolicy).Error)
-
- requestBody := map[string]string{
- "name": "new-project",
- "description": "This is a new project",
- }
-
- b, err := json.Marshal(requestBody)
- assert.Nil(t, err)
-
- req := httptest.NewRequest("POST", "/projects", bytes.NewBuffer(b))
- req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
- ctx := e.NewContext(req, rec)
- shared.SetOrg(ctx, org)
- session := mocks.NewAuthSession(t)
- shared.SetSession(ctx, session)
- rbac := mocks.NewAccessControl(t)
- rbac.On("LinkDomainAndProjectRole", mock.Anything, shared.RoleAdmin, shared.RoleAdmin, mock.Anything).Return(nil)
- rbac.On("InheritProjectRole", mock.Anything, shared.RoleAdmin, shared.RoleMember, mock.Anything).Return(nil)
- rbac.On("AllowRoleInProject", mock.Anything, mock.Anything, shared.RoleAdmin, shared.ObjectUser, []shared.Action{
- shared.ActionCreate,
- shared.ActionDelete,
- shared.ActionUpdate,
- }).Return(nil)
- rbac.On("AllowRoleInProject", mock.Anything, mock.Anything, shared.RoleAdmin, shared.ObjectAsset, []shared.Action{
- shared.ActionCreate,
- shared.ActionDelete,
- shared.ActionUpdate,
- }).Return(nil)
- rbac.On("AllowRoleInProject", mock.Anything, mock.Anything, shared.RoleAdmin, shared.ObjectProject, []shared.Action{
- shared.ActionDelete,
- shared.ActionUpdate,
- }).Return(nil)
- rbac.On("AllowRoleInProject", mock.Anything, mock.Anything, shared.RoleMember, shared.ObjectProject, []shared.Action{
- shared.ActionRead,
- }).Return(nil)
- rbac.On("AllowRoleInProject", mock.Anything, mock.Anything, shared.RoleMember, shared.ObjectAsset, []shared.Action{
- shared.ActionRead,
- }).Return(nil)
-
- shared.SetRBAC(ctx, rbac)
-
- err = f.App.ProjectController.Create(ctx)
- assert.Nil(t, err)
-
- var createdProject models.Project
- err = f.DB.Preload("EnabledPolicies").First(&createdProject, "slug = ?", requestBody["name"]).Error
-
- assert.Nil(t, err)
- assert.Len(t, createdProject.EnabledPolicies, 1)
- })
-
t.Run("should generate a unique slug", func(t *testing.T) {
// create a new project with the same name and slug as the existing project
e := echo.New()
diff --git a/transformer/compliance_risk_transformer.go b/transformer/compliance_risk_transformer.go
new file mode 100644
index 000000000..c8b1f59a0
--- /dev/null
+++ b/transformer/compliance_risk_transformer.go
@@ -0,0 +1,47 @@
+package transformer
+
+import (
+ "github.com/l3montree-dev/devguard/database/models"
+ "github.com/l3montree-dev/devguard/dtos"
+)
+
+func ComplianceRiskToDTO(r models.ComplianceRisk) dtos.ComplianceRiskDTO {
+ artifacts := make([]dtos.ArtifactDTO, len(r.Artifacts))
+ for i, a := range r.Artifacts {
+ artifacts[i] = dtos.ArtifactDTO{
+ ArtifactName: a.ArtifactName,
+ AssetVersionName: a.AssetVersionName,
+ AssetID: a.AssetID,
+ }
+ }
+
+ policyFrameworks := make([]dtos.PolicyFrameworks, len(r.PolicyFrameworks))
+ for i, pf := range r.PolicyFrameworks {
+ policyFrameworks[i] = dtos.PolicyFrameworks{
+ Framework: pf.Framework,
+ Controls: pf.Controls,
+ }
+ }
+
+ return dtos.ComplianceRiskDTO{
+ ID: r.ID,
+ AssetVersionName: r.AssetVersionName,
+ AssetID: r.AssetID.String(),
+ State: r.State,
+ CreatedAt: r.CreatedAt,
+ TicketID: r.TicketID,
+ TicketURL: r.TicketURL,
+ ManualTicketCreation: r.ManualTicketCreation,
+ PolicyID: r.PolicyID,
+ PolicyTitle: r.PolicyTitle,
+ PolicyDescription: r.PolicyDescription,
+ PolicyRelatedResources: r.PolicyRelatedResources,
+ PolicyTags: r.PolicyTags,
+ PolicyPriority: r.PolicyPriority,
+ PolicyFrameworks: policyFrameworks,
+ EvidenceType: r.EvidenceType,
+ Violations: r.Violations,
+ Artifacts: artifacts,
+ Message: r.Message,
+ }
+}