@@ -15,30 +15,83 @@ class BaseRule:
1515 rule_type = None
1616 label = None
1717 description = None
18+ parameters_schema = {}
1819
1920 def count_violations (self , policy_rule , product ):
2021 """Count objects violating the rule for the given product."""
2122 raise NotImplementedError
2223
2324
24- class ComplianceAlertRule (BaseRule ):
25- rule_type = "compliance_alert"
26- label = "Compliance Alert"
25+ class PackageBaseRule (BaseRule ):
26+ """Base for rules that count packages matching a fixed filter within a product."""
27+
28+ package_filter = {}
29+
30+ def count_violations (self , policy_rule , product ):
31+ Package = apps .get_model ("component_catalog" , "package" )
32+
33+ count = Package .objects .filter (
34+ productpackages__product = product ,
35+ ** self .package_filter ,
36+ ).count ()
37+
38+ return count if count > policy_rule .threshold else 0
39+
40+
41+ class LicensePolicyErrorRule (PackageBaseRule ):
42+ rule_type = "license_policy_error"
43+ label = "License Policy Error"
2744 description = (
2845 "Detects packages assigned a usage policy with a compliance alert level of 'error'."
2946 )
47+ package_filter = {"usage_policy__compliance_alert" : "error" }
48+
49+
50+ class LicensePolicyWarningRule (PackageBaseRule ):
51+ rule_type = "license_policy_warning"
52+ label = "License Policy Warning"
53+ description = (
54+ "Detects packages assigned a usage policy with a compliance alert level of 'warning'."
55+ )
56+ package_filter = {"usage_policy__compliance_alert" : "warning" }
57+
58+
59+ class LicenseCoverageGapRule (PackageBaseRule ):
60+ rule_type = "license_coverage_gap"
61+ label = "License Coverage Gap"
62+ description = (
63+ "Detects packages with no license expression, indicating a gap in license coverage."
64+ )
65+ package_filter = {"license_expression" : "" }
66+
67+
68+ class VulnerabilityDetectedRule (BaseRule ):
69+ rule_type = "vulnerability_detected"
70+ label = "Vulnerability Detected"
71+ description = "Detects packages with at least one known vulnerability (non-null risk score)."
72+ parameters_schema = {
73+ "min_risk_score" : "Minimum risk score (0.0-10.0). Default: any vulnerability." ,
74+ }
3075
3176 def count_violations (self , policy_rule , product ):
3277 Package = apps .get_model ("component_catalog" , "package" )
3378
34- count = Package .objects .filter (
79+ packages = Package .objects .filter (
3580 productpackages__product = product ,
36- usage_policy__compliance_alert = "error" ,
37- ).count ()
81+ risk_score__isnull = False ,
82+ )
83+
84+ min_risk_score = policy_rule .parameters .get ("min_risk_score" )
85+ if min_risk_score is not None :
86+ packages = packages .filter (risk_score__gte = min_risk_score )
3887
88+ count = packages .count ()
3989 return count if count > policy_rule .threshold else 0
4090
4191
4292RULE_REGISTRY = {
43- ComplianceAlertRule .rule_type : ComplianceAlertRule (),
93+ LicensePolicyErrorRule .rule_type : LicensePolicyErrorRule (),
94+ LicensePolicyWarningRule .rule_type : LicensePolicyWarningRule (),
95+ LicenseCoverageGapRule .rule_type : LicenseCoverageGapRule (),
96+ VulnerabilityDetectedRule .rule_type : VulnerabilityDetectedRule (),
4497}
0 commit comments