CI Test Suite / Run Component Tests & Pipeline Verification (push) Failing after 1m56s
126 lines
4.8 KiB
Python
126 lines
4.8 KiB
Python
"""
|
|
LOGAR Best Practice Analyzer & Security Baseline Engine
|
|
Provides a modular, extensible framework for verifying server configuration baselines,
|
|
role-specific best practices, and security hardening across enrolled fleet nodes.
|
|
Gated by the 'best_practices' enterprise license capability.
|
|
Rule definitions are maintained separately in best_practice_rules.py.
|
|
"""
|
|
|
|
import json
|
|
from datetime import datetime, timezone
|
|
from typing import Dict, Any, List, Optional, Callable
|
|
|
|
try:
|
|
from src.hub.best_practice_rules import BestPracticeRule, get_baseline_rules
|
|
except ImportError:
|
|
try:
|
|
from best_practice_rules import BestPracticeRule, get_baseline_rules
|
|
except ImportError:
|
|
from .best_practice_rules import BestPracticeRule, get_baseline_rules
|
|
|
|
|
|
class BestPracticeEngine:
|
|
"""Evaluates rules across enrolled server nodes and collects compliance telemetry."""
|
|
|
|
def __init__(self):
|
|
self._rules: Dict[str, BestPracticeRule] = {}
|
|
self._load_baseline_rules()
|
|
|
|
def register_rule(self, rule: BestPracticeRule):
|
|
"""Registers a custom Best Practice check. Enables users to define rules later on."""
|
|
self._rules[rule.rule_id] = rule
|
|
|
|
def unregister_rule(self, rule_id: str):
|
|
"""Removes a rule by its identifier."""
|
|
self._rules.pop(rule_id, None)
|
|
|
|
def get_rules(self) -> List[Dict[str, Any]]:
|
|
return [r.to_dict() for r in self._rules.values()]
|
|
|
|
def _load_baseline_rules(self):
|
|
"""Loads baseline checks defined in the separate best_practice_rules.py module."""
|
|
for rule in get_baseline_rules():
|
|
self.register_rule(rule)
|
|
|
|
def evaluate_node(self, node: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
"""Evaluates all applicable rules against a single server/node record."""
|
|
results = []
|
|
for rule in self._rules.values():
|
|
# Check target OS constraint
|
|
if rule.target_os and str(node.get("os_type", "")).lower() != rule.target_os.lower():
|
|
continue
|
|
|
|
# Check target role constraint
|
|
if rule.target_role:
|
|
roles = node.get("server_roles") or []
|
|
if isinstance(roles, str):
|
|
try:
|
|
roles = json.loads(roles)
|
|
except Exception:
|
|
roles = [r.strip() for r in roles.split(",") if r.strip()]
|
|
roles_str = " ".join(str(r) for r in roles).lower()
|
|
if rule.target_role.lower() not in roles_str:
|
|
continue
|
|
|
|
eval_res = {"status": "PASS", "message": "Check passed baseline standards."}
|
|
if rule.eval_fn:
|
|
try:
|
|
eval_res = rule.eval_fn(node)
|
|
except Exception as ex:
|
|
eval_res = {"status": "ERROR", "message": f"Evaluation error: {str(ex)}"}
|
|
|
|
results.append({
|
|
"rule_id": rule.rule_id,
|
|
"category": rule.category,
|
|
"title": rule.title,
|
|
"severity": rule.severity,
|
|
"recommendation": rule.recommendation,
|
|
"status": eval_res.get("status", "PASS"),
|
|
"message": eval_res.get("message", "")
|
|
})
|
|
return results
|
|
|
|
def evaluate_fleet(self, nodes: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
"""Evaluates all registered rules across all fleet nodes and returns aggregated summary."""
|
|
fleet_results = {}
|
|
pass_count = 0
|
|
warn_count = 0
|
|
fail_count = 0
|
|
|
|
for node in nodes:
|
|
cid = node.get("client_id") or node.get("hostname") or "unknown"
|
|
node_checks = self.evaluate_node(node)
|
|
fleet_results[cid] = {
|
|
"hostname": node.get("hostname", cid),
|
|
"os_type": node.get("os_type", "unknown"),
|
|
"os_name": node.get("os_name", ""),
|
|
"is_server": bool(node.get("is_server")),
|
|
"checks": node_checks
|
|
}
|
|
for chk in node_checks:
|
|
st = chk.get("status")
|
|
if st == "PASS":
|
|
pass_count += 1
|
|
elif st == "WARN":
|
|
warn_count += 1
|
|
elif st == "FAIL":
|
|
fail_count += 1
|
|
|
|
total_evaluated = pass_count + warn_count + fail_count
|
|
score = int((pass_count / total_evaluated * 100)) if total_evaluated > 0 else 100
|
|
|
|
return {
|
|
"score": score,
|
|
"pass_count": pass_count,
|
|
"warn_count": warn_count,
|
|
"fail_count": fail_count,
|
|
"total_evaluated": total_evaluated,
|
|
"evaluated_nodes_count": len(nodes),
|
|
"fleet_results": fleet_results,
|
|
"rules_count": len(self._rules)
|
|
}
|
|
|
|
|
|
# Global singleton instance
|
|
BEST_PRACTICES_ENGINE = BestPracticeEngine()
|