Actually, it's more complexe than expected. If the rule has 0 reports (which is likely if it has only one directive which is overrided), then we don't reach the point where we look for overrides. And so we don't even get a chance to see them:
// the method called to display rule compliance
// class RuleCompliance (rule : Rule, rootRuleCategory: RuleCategory) {
// ...
def refreshCompliance() : JsCmd = {
( for {
reports <- reportingService.findDirectiveRuleStatusReportsByRule(rule.id)
allRules <- roRuleRepository.getAll()
groups <- getGroups()
updatedRule <- Box(allRules.find(_.id == rule.id))
directiveLib <- getFullDirectiveLib()
allNodeInfos <- getAllNodeInfos()
globalMode <- configService.rudder_global_policy_mode()
} yield {
val directiveData = ComplianceData.getRuleByDirectivesComplianceDetails(reports, updatedRule, allNodeInfos, directiveLib, groups, allRules, globalMode).json.toJsCmd
...
// here "reports" is empty, so in getRuleByDirectivesComplianceDetails:
And:
def getRuleByDirectivesComplianceDetails (
report : RuleStatusReport
, rule : Rule
, ...
) : JsTableData[DirectiveComplianceLine] = {
val overrides = getOverridenDirectiveDetails(report.overrides, directiveLib, allRules)
// restrict mode calcul to node really targetted by that rule
val appliedNodes = groupLib.getNodeIds(rule.targets, allNodeInfos)
val nodeModes = appliedNodes.flatMap(id => allNodeInfos.get(id).map(_.policyMode))
val lines = getDirectivesComplianceDetails(report.report.directives.values.toSet, directiveLib, globalMode, ComputePolicyMode.directiveModeOnRule(nodeModes, globalMode))
// here, overrides will be empty because there's node report.
So to correct that bug, we will need a significative change were we start by collecting expected reports containing that rule (either in expected or in override).
It may be good to do that in all cases, because it would rely on correct data, not received/calculated one based on received.
Or perhaps we could do that only when we are in the case with 0 reports.