Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
37d5d78
feat: add asset attestation daemon and DTOs
refoo0 May 29, 2026
8e37608
feat: add compliance service and artifact-scoped attestation lookup
refoo0 Jun 2, 2026
26bfbda
add compliance risk tracking
refoo0 Jun 3, 2026
1601dd2
add zip upload and recalculate endpoints for compliance risks
refoo0 Jun 3, 2026
8519317
add attestation service
refoo0 Jun 3, 2026
b9ae1a6
add predicate type and attestation timestamp to compliance risks
refoo0 Jun 3, 2026
4d2c767
add artifact-scoped attestation list endpoint
refoo0 Jun 3, 2026
188c2ba
add policy name to compliance risk DTO and reuse ArtifactDTO
refoo0 Jun 5, 2026
e60117a
Merge remote-tracking branch 'origin/main' into feat/attestation-and-…
refoo0 Jun 5, 2026
d64e8d2
refine compliance risk model, DTOs and add policy transformer
refoo0 Jun 5, 2026
fd08e6d
move attestation logic from daemon to service
refoo0 Jun 5, 2026
5af001e
fix mocks
refoo0 Jun 5, 2026
9094f16
remove standalone policy layer, consolidate into compliance risk
refoo0 Jun 9, 2026
eb6af0e
fix mocks
refoo0 Jun 9, 2026
90783b9
remove policy layer mocks and update compliance risk migration
refoo0 Jun 9, 2026
0f01c54
refactor compliance risk and attestation evaluation logic
refoo0 Jun 9, 2026
906f3a6
update compliance risk model, service, and evaluation logic
refoo0 Jun 9, 2026
589979a
fix lint
refoo0 Jun 9, 2026
b79729a
add policy frameworks logic
refoo0 Jun 9, 2026
5aec45e
feat: update compliance risk evaluation and rego policies
refoo0 Jun 10, 2026
fa40329
feat: refine compliance risk and attestation evaluation logic
refoo0 Jun 10, 2026
5642008
add metadata update
refoo0 Jun 10, 2026
045bc35
update compliance rego evaluation logic
refoo0 Jun 10, 2026
79673da
update compliance risk DTO
refoo0 Jun 10, 2026
b322977
remove unused external entity provider logic and cleanup interfaces
refoo0 Jun 11, 2026
947aeb7
add frameworkContains filter and sort open compliance risks first
Konstantin-Zhukov Jun 16, 2026
1596ad9
remove compliance risks sorting
Konstantin-Zhukov Jun 16, 2026
e0c608a
Merge pull request #2148 from l3montree-dev/feat/attestation-and-comp…
Konstantin-Zhukov Jun 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/devguard-cli/commands/vulndb.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}),
Expand Down
2 changes: 1 addition & 1 deletion cmd/devguard-scanner/commands/attestations.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
169 changes: 23 additions & 146 deletions cmd/devguard-scanner/scanner/eval_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Comment thread
refoo0 marked this conversation as resolved.

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
}
128 changes: 0 additions & 128 deletions cmd/devguard-scanner/scanner/eval_policy_test.go

This file was deleted.

1 change: 1 addition & 0 deletions cmd/devguard/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# relatedResources: []
# tags:
# - Legal
# complianceFrameworks: []
# policyFrameworks: []
package compliance

import rego.v1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# tags:
# - GitLab CI
# - Legal
# complianceFrameworks: []
# policyFrameworks: []
package compliance

import rego.v1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading