From 7b03ea173f8aea69e3a208c1c24f4d247acf4a56 Mon Sep 17 00:00:00 2001 From: Tim Purschke Date: Mon, 3 Nov 2025 20:23:24 +0100 Subject: [PATCH 1/5] sonar fixes - starting with db and some csharp issues --- .../creation/fworch-create-constraints.sql | 1 + .../files/sql/idempotent/fworch-api-funcs.sql | 65 ++++--- .../sql/idempotent/fworch-encryption.sql | 85 +++++---- roles/database/files/upgrade/9.0.sql | 156 ++++++++++------ .../files/FWO.Api.Client/Queries/Queries.cs | 1 - .../files/FWO.Compliance/ComplianceCheck.cs | 166 +++++++++++------- roles/lib/files/FWO.Data/ApiCrudHelper.cs | 7 +- roles/lib/files/FWO.Data/DisplayBase.cs | 24 +-- .../FWO.Report/Display/RuleDisplayHtml.cs | 2 +- .../lib/files/FWO.Report/ReportDevicesBase.cs | 6 +- .../files/FWO.Test/ReportComplianceTest.cs | 10 +- 11 files changed, 322 insertions(+), 201 deletions(-) diff --git a/roles/database/files/sql/creation/fworch-create-constraints.sql b/roles/database/files/sql/creation/fworch-create-constraints.sql index 74fffb3ba6..e6125bc31d 100755 --- a/roles/database/files/sql/creation/fworch-create-constraints.sql +++ b/roles/database/files/sql/creation/fworch-create-constraints.sql @@ -14,6 +14,7 @@ Alter Table "changelog_service" add Constraint "alt_key_changelog_service" UNIQU Alter Table "changelog_user" add Constraint "alt_key_changelog_user" UNIQUE ("abs_change_id"); Alter Table "import_changelog" add Constraint "Alter_Key14" UNIQUE ("import_changelog_nr","control_id"); Alter Table "import_control" add Constraint "control_id_stop_time_unique" UNIQUE ("stop_time","control_id"); +ALTER TABLE ldap_connection ADD CONSTRAINT ldap_connection_server_unique UNIQUE (ldap_server, ldap_port, active); Alter Table "object" add Constraint "obj_altkey" UNIQUE ("mgm_id","zone_id","obj_uid","obj_create"); ALTER TABLE object ADD CONSTRAINT object_obj_ip_is_host CHECK (is_single_ip(obj_ip)); ALTER TABLE object ADD CONSTRAINT object_obj_ip_end_is_host CHECK (is_single_ip(obj_ip_end)); diff --git a/roles/database/files/sql/idempotent/fworch-api-funcs.sql b/roles/database/files/sql/idempotent/fworch-api-funcs.sql index 3ae33e4f8f..9d739a3e46 100644 --- a/roles/database/files/sql/idempotent/fworch-api-funcs.sql +++ b/roles/database/files/sql/idempotent/fworch-api-funcs.sql @@ -608,27 +608,44 @@ $$ LANGUAGE 'plpgsql' STABLE; CREATE OR REPLACE FUNCTION public.get_rulebase_for_owner(rulebase_row rulebase, ownerid integer) - RETURNS SETOF rule - LANGUAGE plpgsql - STABLE -AS $function$ - BEGIN - RETURN QUERY - SELECT r.* FROM rule r - LEFT JOIN rule_from rf ON (r.rule_id=rf.rule_id) - LEFT JOIN objgrp_flat rf_of ON (rf.obj_id=rf_of.objgrp_flat_id) - LEFT JOIN object rf_o ON (rf_of.objgrp_flat_member_id=rf_o.obj_id) - LEFT JOIN owner_network ON - (ip_ranges_overlap(rf_o.obj_ip, rf_o.obj_ip_end, ip, ip_end, rf.negated != r.rule_src_neg)) - WHERE r.rulebase_id = rulebase_row.id AND owner_id = ownerid AND rule_head_text IS NULL - UNION - SELECT r.* FROM rule r - LEFT JOIN rule_to rt ON (r.rule_id=rt.rule_id) - LEFT JOIN objgrp_flat rt_of ON (rt.obj_id=rt_of.objgrp_flat_id) - LEFT JOIN object rt_o ON (rt_of.objgrp_flat_member_id=rt_o.obj_id) - LEFT JOIN owner_network ON - (ip_ranges_overlap(rt_o.obj_ip, rt_o.obj_ip_end, ip, ip_end, rt.negated != r.rule_dst_neg)) - WHERE r.rulebase_id = rulebase_row.id AND owner_id = ownerid AND rule_head_text IS NULL - ORDER BY rule_name; - END; -$function$ +RETURNS SETOF rule +LANGUAGE sql +STABLE +AS $$ + SELECT r.* + FROM rule r + WHERE r.rulebase_id = rulebase_row.id + AND r.rule_head_text IS NULL + AND ( + r.rule_id IN ( + SELECT rf.rule_id + FROM rule_from rf + JOIN objgrp_flat of1 ON of1.objgrp_flat_id = rf.obj_id + JOIN object o1 ON o1.obj_id = of1.objgrp_flat_member_id + JOIN owner_network onet1 ON onet1.owner_id = ownerid + WHERE rf.rule_id = r.rule_id + AND ip_ranges_overlap( + o1.obj_ip, o1.obj_ip_end, + onet1.ip, onet1.ip_end, + rf.negated <> r.rule_src_neg + ) + ) + OR + r.rule_id IN ( + SELECT rt.rule_id + FROM rule_to rt + JOIN objgrp_flat of2 ON of2.objgrp_flat_id = rt.obj_id + JOIN object o2 ON o2.obj_id = of2.objgrp_flat_member_id + JOIN owner_network onet2 ON onet2.owner_id = ownerid + WHERE rt.rule_id = r.rule_id + AND ip_ranges_overlap( + o2.obj_ip, o2.obj_ip_end, + onet2.ip, onet2.ip_end, + rt.negated <> r.rule_dst_neg + ) + ) + ) + ORDER BY r.rule_name; +$$; + + diff --git a/roles/database/files/sql/idempotent/fworch-encryption.sql b/roles/database/files/sql/idempotent/fworch-encryption.sql index cd1e82d88f..6d0e75f034 100644 --- a/roles/database/files/sql/idempotent/fworch-encryption.sql +++ b/roles/database/files/sql/idempotent/fworch-encryption.sql @@ -130,34 +130,59 @@ $$ LANGUAGE plpgsql; SELECT * FROM encryptPasswords (getMainKey()); -- function for adding local ldap data with encrypted pwds into ldap_connection + +-- assumes ldap_connection(active boolean NOT NULL [DEFAULT true]) + CREATE OR REPLACE FUNCTION insertLocalLdapWithEncryptedPasswords( - serverName TEXT, - port INTEGER, - userSearchPath TEXT, - roleSearchPath TEXT, - groupSearchPath TEXT, - groupWritePath TEXT, - tenantLevel INTEGER, - searchUser TEXT, - searchUserPwd TEXT, - writeUser TEXT, - writeUserPwd TEXT, - ldapType INTEGER -) RETURNS VOID AS $$ -DECLARE - t_key TEXT; - t_encryptedReadPwd TEXT; - t_encryptedWritePwd TEXT; -BEGIN - IF NOT EXISTS (SELECT * FROM ldap_connection WHERE ldap_server = serverName) - THEN - SELECT INTO t_key * FROM getMainKey(); - SELECT INTO t_encryptedReadPwd * FROM encryptText(searchUserPwd, t_key); - SELECT INTO t_encryptedWritePwd * FROM encryptText(writeUserPwd, t_key); - INSERT INTO ldap_connection - (ldap_server, ldap_port, ldap_searchpath_for_users, ldap_searchpath_for_roles, ldap_searchpath_for_groups, ldap_writepath_for_groups, - ldap_tenant_level, ldap_search_user, ldap_search_user_pwd, ldap_write_user, ldap_write_user_pwd, ldap_type) - VALUES (serverName, port, userSearchPath, roleSearchPath, groupSearchPath, groupWritePath, tenantLevel, searchUser, t_encryptedReadPwd, writeUser, t_encryptedWritePwd, ldapType); - END IF; -END; -$$ LANGUAGE plpgsql; + serverName text, + port integer, + userSearchPath text, + roleSearchPath text, + groupSearchPath text, + groupWritePath text, + tenantLevel integer, + searchUser text, + searchUserPwd text, + writeUser text, + writeUserPwd text, + ldapType integer, + activeFlag boolean DEFAULT true -- ← include active explicitly +) RETURNS void +LANGUAGE sql +VOLATILE +SECURITY DEFINER +SET search_path = public +AS $$ +WITH k AS (SELECT getMainKey() AS mk) +INSERT INTO ldap_connection ( + ldap_server, + ldap_port, + ldap_searchpath_for_users, + ldap_searchpath_for_roles, + ldap_searchpath_for_groups, + ldap_writepath_for_groups, + ldap_tenant_level, + ldap_search_user, + ldap_search_user_pwd, + ldap_write_user, + ldap_write_user_pwd, + ldap_type, + active +) +SELECT + serverName, + port, + userSearchPath, + roleSearchPath, + groupSearchPath, + groupWritePath, + tenantLevel, + searchUser, + encryptText(searchUserPwd, k.mk), + writeUser, + encryptText(writeUserPwd, k.mk), + ldapType, + activeFlag +FROM k +ON CONFLICT (ldap_server, ldap_port, active) DO NOTHING; +$$; diff --git a/roles/database/files/upgrade/9.0.sql b/roles/database/files/upgrade/9.0.sql index dabfdafc41..bd65d06eff 100644 --- a/roles/database/files/upgrade/9.0.sql +++ b/roles/database/files/upgrade/9.0.sql @@ -49,37 +49,66 @@ $$ LANGUAGE plpgsql VOLATILE; Alter table "ldap_connection" ADD COLUMN IF NOT EXISTS "ldap_writepath_for_groups" Varchar; +ALTER TABLE ldap_connection ADD CONSTRAINT ldap_connection_server_unique UNIQUE (ldap_server, ldap_port, active); + +-- assumes ldap_connection(active boolean NOT NULL [DEFAULT true]) + +-- assumes ldap_connection(active boolean NOT NULL [DEFAULT true]) + CREATE OR REPLACE FUNCTION insertLocalLdapWithEncryptedPasswords( - serverName TEXT, - port INTEGER, - userSearchPath TEXT, - roleSearchPath TEXT, - groupSearchPath TEXT, - groupWritePath TEXT, - tenantLevel INTEGER, - searchUser TEXT, - searchUserPwd TEXT, - writeUser TEXT, - writeUserPwd TEXT, - ldapType INTEGER -) RETURNS VOID AS $$ -DECLARE - t_key TEXT; - t_encryptedReadPwd TEXT; - t_encryptedWritePwd TEXT; -BEGIN - IF NOT EXISTS (SELECT * FROM ldap_connection WHERE ldap_server = serverName) - THEN - SELECT INTO t_key * FROM getMainKey(); - SELECT INTO t_encryptedReadPwd * FROM encryptText(searchUserPwd, t_key); - SELECT INTO t_encryptedWritePwd * FROM encryptText(writeUserPwd, t_key); - INSERT INTO ldap_connection - (ldap_server, ldap_port, ldap_searchpath_for_users, ldap_searchpath_for_roles, ldap_searchpath_for_groups, ldap_writepath_for_groups, - ldap_tenant_level, ldap_search_user, ldap_search_user_pwd, ldap_write_user, ldap_write_user_pwd, ldap_type) - VALUES (serverName, port, userSearchPath, roleSearchPath, groupSearchPath, groupWritePath, tenantLevel, searchUser, t_encryptedReadPwd, writeUser, t_encryptedWritePwd, ldapType); - END IF; -END; -$$ LANGUAGE plpgsql; + serverName text, + port integer, + userSearchPath text, + roleSearchPath text, + groupSearchPath text, + groupWritePath text, + tenantLevel integer, + searchUser text, + searchUserPwd text, + writeUser text, + writeUserPwd text, + ldapType integer, + activeFlag boolean DEFAULT true -- ← include active explicitly +) RETURNS void +LANGUAGE sql +VOLATILE +SECURITY DEFINER +SET search_path = public +AS $$ +WITH k AS (SELECT getMainKey() AS mk) +INSERT INTO ldap_connection ( + ldap_server, + ldap_port, + ldap_searchpath_for_users, + ldap_searchpath_for_roles, + ldap_searchpath_for_groups, + ldap_writepath_for_groups, + ldap_tenant_level, + ldap_search_user, + ldap_search_user_pwd, + ldap_write_user, + ldap_write_user_pwd, + ldap_type, + active +) +SELECT + serverName, + port, + userSearchPath, + roleSearchPath, + groupSearchPath, + groupWritePath, + tenantLevel, + searchUser, + encryptText(searchUserPwd, k.mk), + writeUser, + encryptText(writeUserPwd, k.mk), + ldapType, + activeFlag +FROM k +ON CONFLICT (ldap_server, ldap_port, active) DO NOTHING; +$$; + -- 8.7.2 @@ -444,8 +473,6 @@ Create table IF NOT EXISTS "rulebase" "removed" BIGINT ); --- ALTER TABLE "rulebase" ADD COLUMN IF NOT EXISTS "uid" Varchar NOT NULL; - ALTER TABLE "rulebase" DROP CONSTRAINT IF EXISTS "fk_rulebase_mgm_id" CASCADE; Alter table "rulebase" add CONSTRAINT fk_rulebase_mgm_id foreign key ("mgm_id") references "management" ("mgm_id") on update restrict on delete cascade; @@ -1015,31 +1042,46 @@ Alter Table "rule" ADD Constraint "rule_unique_mgm_id_rule_uid_rule_create_xlate -- rewrite get_rulebase_for_owner to work with rulebase instead of device CREATE OR REPLACE FUNCTION public.get_rulebase_for_owner(rulebase_row rulebase, ownerid integer) - RETURNS SETOF rule - LANGUAGE plpgsql - STABLE -AS -$function$ - BEGIN - RETURN QUERY - SELECT r.* FROM rule r - LEFT JOIN rule_from rf ON (r.rule_id=rf.rule_id) - LEFT JOIN objgrp_flat rf_of ON (rf.obj_id=rf_of.objgrp_flat_id) - LEFT JOIN object rf_o ON (rf_of.objgrp_flat_member_id=rf_o.obj_id) - LEFT JOIN owner_network ON - (ip_ranges_overlap(rf_o.obj_ip, rf_o.obj_ip_end, ip, ip_end, rf.negated != r.rule_src_neg)) - WHERE r.rulebase_id = rulebase_row.id AND owner_id = ownerid AND rule_head_text IS NULL - UNION - SELECT r.* FROM rule r - LEFT JOIN rule_to rt ON (r.rule_id=rt.rule_id) - LEFT JOIN objgrp_flat rt_of ON (rt.obj_id=rt_of.objgrp_flat_id) - LEFT JOIN object rt_o ON (rt_of.objgrp_flat_member_id=rt_o.obj_id) - LEFT JOIN owner_network ON - (ip_ranges_overlap(rt_o.obj_ip, rt_o.obj_ip_end, ip, ip_end, rt.negated != r.rule_dst_neg)) - WHERE r.rulebase_id = rulebase_row.id AND owner_id = ownerid AND rule_head_text IS NULL - ORDER BY rule_name; - END; -$function$; +RETURNS SETOF rule +LANGUAGE sql +STABLE +AS $$ + SELECT r.* + FROM rule r + WHERE r.rulebase_id = rulebase_row.id + AND r.rule_head_text IS NULL + AND ( + r.rule_id IN ( + SELECT rf.rule_id + FROM rule_from rf + JOIN objgrp_flat of1 ON of1.objgrp_flat_id = rf.obj_id + JOIN object o1 ON o1.obj_id = of1.objgrp_flat_member_id + JOIN owner_network onet1 ON onet1.owner_id = ownerid + WHERE rf.rule_id = r.rule_id + AND ip_ranges_overlap( + o1.obj_ip, o1.obj_ip_end, + onet1.ip, onet1.ip_end, + rf.negated <> r.rule_src_neg + ) + ) + OR + r.rule_id IN ( + SELECT rt.rule_id + FROM rule_to rt + JOIN objgrp_flat of2 ON of2.objgrp_flat_id = rt.obj_id + JOIN object o2 ON o2.obj_id = of2.objgrp_flat_member_id + JOIN owner_network onet2 ON onet2.owner_id = ownerid + WHERE rt.rule_id = r.rule_id + AND ip_ranges_overlap( + o2.obj_ip, o2.obj_ip_end, + onet2.ip, onet2.ip_end, + rt.negated <> r.rule_dst_neg + ) + ) + ) + ORDER BY r.rule_name; +$$; + -- drop only after migration diff --git a/roles/lib/files/FWO.Api.Client/Queries/Queries.cs b/roles/lib/files/FWO.Api.Client/Queries/Queries.cs index a9b6ebac6b..20e307aef6 100644 --- a/roles/lib/files/FWO.Api.Client/Queries/Queries.cs +++ b/roles/lib/files/FWO.Api.Client/Queries/Queries.cs @@ -6,7 +6,6 @@ namespace FWO.Api.Client.Queries { public class Queries { - // protected static readonly string QueryPath = AppDomain.CurrentDomain.BaseDirectory + "../../../../../../common/files/fwo-api-calls/"; protected static readonly string QueryPath = GlobalConst.kFwoBaseDir + "/fwo-api-calls/"; protected static string GetQueryText(string relativeQueryFileName) diff --git a/roles/lib/files/FWO.Compliance/ComplianceCheck.cs b/roles/lib/files/FWO.Compliance/ComplianceCheck.cs index 6f07760f8c..21a1c6e3bd 100644 --- a/roles/lib/files/FWO.Compliance/ComplianceCheck.cs +++ b/roles/lib/files/FWO.Compliance/ComplianceCheck.cs @@ -22,12 +22,12 @@ public class ComplianceCheck private ReportFilters _reportFilters = new(); private CompliancePolicy? _policy = null; private List _networkZones = []; - + private readonly UserConfig _userConfig; private readonly ApiConnection _apiConnection; private readonly DebugConfig _debugConfig; - private List _relevanteManagementIDs = new(); + private readonly List _relevantManagementIDs = new(); /// /// Constructor for compliance check @@ -54,7 +54,7 @@ public ComplianceCheck(UserConfig userConfig, ApiConnection apiConnection) { try { - _relevanteManagementIDs = userConfig.GlobalConfig.ComplianceCheckRelevantManagements + _relevantManagementIDs = userConfig.GlobalConfig.ComplianceCheckRelevantManagements .Split(',', StringSplitOptions.RemoveEmptyEntries) .Select(s => int.Parse(s.Trim())) .ToList(); @@ -120,13 +120,13 @@ public async Task CheckAll() else { Log.WriteError("Compliance Check", "Could not generate compliance report."); - } + } } catch (System.Exception e) { Log.WriteError("Compliance Check", "Error while checking for compliance violations.", e); } - + } /// @@ -305,7 +305,7 @@ private string CreateUniqueViolationKey(ComplianceViolation violation) catch (Exception e) { Log.WriteError("Compliance Check", "Error creating unique violation key", Error: e); - + } return key; @@ -330,7 +330,7 @@ private Task> GetViolationsForRemove(List existin return Task.FromResult(violationsForUpdate); } - + private async Task CheckRuleComplianceForAllRules() { int nonCompliantRules = 0; @@ -387,62 +387,124 @@ private async Task CheckAgainstMatrix(Rule rule) return ruleIsCompliant; } + private bool CheckMatrixCompliance(List source, List destination, out List<(ComplianceNetworkZone, ComplianceNetworkZone)> forbiddenCommunication) + { + // Determine all matching source zones + List sourceZones = DetermineZones(source); + + // Determine all macthing destination zones + List destinationZones = DetermineZones(destination); + + forbiddenCommunication = []; + + foreach (ComplianceNetworkZone sourceZone in sourceZones) + { + foreach (ComplianceNetworkZone destinationZone in destinationZones.Where(d => !sourceZone.CommunicationAllowedTo(d))) + { + forbiddenCommunication.Add((sourceZone, destinationZone)); + } + } + + return forbiddenCommunication.Count == 0; + } + private bool CheckMatrixCompliance(Rule rule, List<(NetworkObject networkObject, List ipRanges)> source, List<(NetworkObject networkObject, List ipRanges)> destination) { bool ruleIsCompliant = true; List<(NetworkObject networkObject, List? networkZones)> sourceZones = MapZonesToNetworkObjects(source); List<(NetworkObject networkObject, List? networkZones)> destinationZones = MapZonesToNetworkObjects(destination); - List objectsWithoutZone = []; + ComplianceCriterion? matrixCriterion = _policy?.Criteria.FirstOrDefault(c => c.Content.CriterionType == CriterionType.Matrix.ToString())?.Content; + + if (!HandleUnresolvedZones(rule, sourceZones, true)) + { + ruleIsCompliant = false; + } + + if (!HandleUnresolvedZones(rule, destinationZones, false)) + { + ruleIsCompliant = false; + } foreach ((NetworkObject networkObject, List? networkZones) sourceZone in sourceZones) { if (sourceZone.networkZones == null) { - CreateUnresolvableZoneViolation(rule, sourceZone.networkObject, true); - ruleIsCompliant = false; continue; } - foreach (ComplianceNetworkZone sourceNetworkZone in sourceZone.networkZones ?? []) + foreach ((NetworkObject networkObject, List? networkZones) destinationZone in destinationZones) { - foreach ((NetworkObject networkObject, List? networkZones) destinationZone in destinationZones) + if (destinationZone.networkZones == null) { + continue; + } - if (sourceZone.networkZones == null) - { - CreateUnresolvableZoneViolation(rule, destinationZone.networkObject, false); - ruleIsCompliant = false; - continue; - } + if (!CheckZonePairCompliance(rule, matrixCriterion, sourceZone, destinationZone)) + { + ruleIsCompliant = false; + } + } + } - foreach (ComplianceNetworkZone destinationNetworkZone in destinationZone.networkZones ?? []) - { - if (!sourceNetworkZone.CommunicationAllowedTo(destinationNetworkZone)) - { - ComplianceCheckResult complianceCheckResult = new(rule, ComplianceViolationType.MatrixViolation) - { - Criterion = _policy?.Criteria.FirstOrDefault(c => c.Content.CriterionType == CriterionType.Matrix.ToString())?.Content, - Source = sourceZone.networkObject, - SourceZone = sourceNetworkZone, - Destination = destinationZone.networkObject, - DestinationZone = destinationNetworkZone - }; + return ruleIsCompliant; + } + + private bool HandleUnresolvedZones(Rule rule, IEnumerable<(NetworkObject networkObject, List? networkZones)> zones, bool isSource) + { + bool zonesResolvable = true; - ComplianceViolation? violation = TryCreateViolation(ComplianceViolationType.MatrixViolation, rule, complianceCheckResult); + foreach ((NetworkObject networkObject, List? networkZones) zone in zones) + { + if (zone.networkZones != null) + { + continue; + } + CreateUnresolvableZoneViolation(rule, zone.networkObject, isSource); + zonesResolvable = false; + } + return zonesResolvable; + } - ComplianceReport!.Violations.Add(violation!); + private bool CheckZonePairCompliance(Rule rule, ComplianceCriterion? matrixCriterion, (NetworkObject networkObject, List? networkZones) sourceZone, (NetworkObject networkObject, List? networkZones) destinationZone) + { + bool zonesCompliant = true; - ruleIsCompliant = false; - } - } + foreach (ComplianceNetworkZone sourceNetworkZone in sourceZone.networkZones!) + { + foreach (ComplianceNetworkZone destinationNetworkZone in destinationZone.networkZones!) + { + if (sourceNetworkZone.CommunicationAllowedTo(destinationNetworkZone)) + { + continue; } + + AddMatrixViolation(rule, matrixCriterion, sourceZone.networkObject, sourceNetworkZone, destinationZone.networkObject, destinationNetworkZone); + zonesCompliant = false; } } - return ruleIsCompliant; + return zonesCompliant; + } + + private void AddMatrixViolation(Rule rule, ComplianceCriterion? matrixCriterion, NetworkObject source, ComplianceNetworkZone sourceZone, NetworkObject destination, ComplianceNetworkZone destinationZone) + { + ComplianceCheckResult complianceCheckResult = new(rule, ComplianceViolationType.MatrixViolation) + { + Criterion = matrixCriterion, + Source = source, + SourceZone = sourceZone, + Destination = destination, + DestinationZone = destinationZone + }; + + ComplianceViolation? violation = TryCreateViolation(ComplianceViolationType.MatrixViolation, rule, complianceCheckResult); + + + + ComplianceReport!.Violations.Add(violation!); } private void CreateUnresolvableZoneViolation(Rule rule, NetworkObject networkObject, bool isSource) @@ -487,7 +549,7 @@ private void CreateUnresolvableZoneViolation(Rule rule, NetworkObject networkObj violation.CriterionId = _policy?.Criteria .FirstOrDefault(criterionWrapper => criterionWrapper.Content.CriterionType == "Matrix")? .Content.Id ?? 0; - + if (complianceCheckResult.Source is NetworkObject s && complianceCheckResult.Destination is NetworkObject d) { string sourceString = GetNwObjectString(s); @@ -506,7 +568,8 @@ private void CreateUnresolvableZoneViolation(Rule rule, NetworkObject networkObj } else { - violation.Details = $"Matrix violation: Failed to resolve network objects."; } + violation.Details = $"Matrix violation: Failed to resolve network objects."; + } } break; @@ -543,27 +606,6 @@ private string GetNwObjectString(NetworkObject networkObject) return networkObjectString; } - private bool CheckMatrixCompliance(List source, List destination, out List<(ComplianceNetworkZone, ComplianceNetworkZone)> forbiddenCommunication) - { - // Determine all matching source zones - List sourceZones = DetermineZones(source); - - // Determine all macthing destination zones - List destinationZones = DetermineZones(destination); - - forbiddenCommunication = []; - - foreach (ComplianceNetworkZone sourceZone in sourceZones) - { - foreach (ComplianceNetworkZone destinationZone in destinationZones.Where(d => !sourceZone.CommunicationAllowedTo(d))) - { - forbiddenCommunication.Add((sourceZone, destinationZone)); - } - } - - return forbiddenCommunication.Count == 0; - } - private async Task SetUpReportFilters() { Log.TryWriteLog(LogType.Info, "Compliance Check", "Setting up report filters for compliance check", _debugConfig.ExtendedLogComplianceCheck); @@ -608,14 +650,14 @@ private bool CheckForForbiddenService(Rule rule, ComplianceCriterion criterion) { ComplianceReport!.Violations.Add(violation); } - + ruleIsCompliant = false; } } return ruleIsCompliant; } - + private static Task ipRanges)>> GetNetworkObjectsWithIpRanges(List networkObjects) { List<(NetworkObject networkObject, List ipRanges)> networkObjectsWithIpRange = []; @@ -670,7 +712,7 @@ private static List ParseIpRange(NetworkObject networkObject) { networkZones = DetermineZones(dataItem.ipRanges); } - + map.Add((dataItem.networkObject, networkZones)); } diff --git a/roles/lib/files/FWO.Data/ApiCrudHelper.cs b/roles/lib/files/FWO.Data/ApiCrudHelper.cs index de64bc61a5..a6e5f3c478 100644 --- a/roles/lib/files/FWO.Data/ApiCrudHelper.cs +++ b/roles/lib/files/FWO.Data/ApiCrudHelper.cs @@ -47,11 +47,6 @@ public class ReturnIdWrapper } public class AggregateCountLastHit - // { - // [JsonProperty("device"), JsonPropertyName("device")] - // public List Devices {get; set;} = []; - // } - // public class DeviceLastHit { [JsonProperty("rulebase_link"), JsonPropertyName("rulebase_link")] public List RulebasesOnGateway { get; set; } = []; @@ -62,7 +57,7 @@ public class RulebaseOnGatewaysLastHit [JsonProperty("rulebase"), JsonPropertyName("rulebase")] public RulebaseLastHit Rulebase { get; set; } = new RulebaseLastHit(); } - + public class RulebaseLastHit { [JsonProperty("rulesWithHits"), JsonPropertyName("rulesWithHits")] diff --git a/roles/lib/files/FWO.Data/DisplayBase.cs b/roles/lib/files/FWO.Data/DisplayBase.cs index 2d95c64663..815ebf91aa 100644 --- a/roles/lib/files/FWO.Data/DisplayBase.cs +++ b/roles/lib/files/FWO.Data/DisplayBase.cs @@ -10,14 +10,13 @@ public static class DisplayBase { public static StringBuilder DisplayGateway(Device gateway, bool isTechReport, string? gatewayName = null) { - StringBuilder result = new (); - // result.Append($"

{gateway.Name}

"); + StringBuilder result = new(); result.Append($" {gateway.Name}"); return result; - } + } public static StringBuilder DisplayService(NetworkService service, bool isTechReport, string? serviceName = null) { - StringBuilder result = new (); + StringBuilder result = new(); string ports = service.DestinationPortEnd == null || service.DestinationPortEnd == 0 || service.DestinationPort == service.DestinationPortEnd ? $"{service.DestinationPort}" : $"{service.DestinationPort}-{service.DestinationPortEnd}"; bool displayPorts = service.Protocol != null && service.Protocol.HasPorts() && service.DestinationPort != null; @@ -63,24 +62,24 @@ public static List CustomSortProtocols(List ListIn) { List ListOut = []; IpProtocol? tcp = ListIn.Find(x => x.Name.ToLower() == "tcp"); - if(tcp != null) + if (tcp != null) { ListOut.Add(tcp); ListIn.Remove(tcp); } IpProtocol? udp = ListIn.Find(x => x.Name.ToLower() == "udp"); - if(udp != null) + if (udp != null) { ListOut.Add(udp); ListIn.Remove(udp); } IpProtocol? icmp = ListIn.Find(x => x.Name.ToLower() == "icmp"); - if(icmp != null) + if (icmp != null) { ListOut.Add(icmp); ListIn.Remove(icmp); } - foreach(var proto in ListIn.Where(p => p.Name.ToLower() != "unassigned").OrderBy(x => x.Name).ToList()) + foreach (var proto in ListIn.Where(p => p.Name.ToLower() != "unassigned").OrderBy(x => x.Name).ToList()) { ListOut.Add(proto); } @@ -89,7 +88,7 @@ public static List CustomSortProtocols(List ListIn) public static string DisplayIpWithName(NetworkObject elem) { - if(elem.Name != null && elem.Name != "") + if (elem.Name != null && elem.Name != "") { return elem.Name + DisplayIp(elem.IP, elem.IpEnd, true); } @@ -111,7 +110,7 @@ public static string DisplayIp(string ip1, string ip2, bool inBrackets = false) string nwObjType = IpOperations.GetObjectType(ip1, ip2); return DisplayIp(ip1, ip2, nwObjType, inBrackets); } - catch(Exception exc) + catch (Exception exc) { Log.WriteError("Ip displaying", $"Exception thrown: {exc.Message}"); return ""; @@ -132,7 +131,8 @@ public static string DisplayIp(string ip1, string ip2, string nwObjType, bool in if (string.IsNullOrEmpty(ip1)) { Log.WriteDebug("Ip displaying", $"Nessessary parameter {nameof(ip1)} is empty."); - }else if (!ip1.IsV4Address() && !ip1.IsV6Address()) + } + else if (!ip1.IsV4Address() && !ip1.IsV6Address()) { Log.WriteError("Ip displaying", $"Found undefined IP family: {ip1} - {ip2}"); } @@ -141,7 +141,7 @@ public static string DisplayIp(string ip1, string ip2, string nwObjType, bool in Log.WriteError("Ip displaying", $"Found mixed IP family: {ip1} - {ip2}"); } else - { + { string IpStart = ip1.StripOffUnnecessaryNetmask(); string IpEnd = ip2.StripOffUnnecessaryNetmask(); diff --git a/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs b/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs index 0850dd07d6..205aa1ba94 100644 --- a/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs +++ b/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs @@ -126,7 +126,7 @@ protected static string EnforcingGatewayToHtml(Device gateway, int mgmtId, int c string gwLink = ReportDevicesBase.GetReportDevicesLinkAddress(location, mgmtId, ObjCatString.NwObj, chapterNumber, gateway.Id, reportType); return DisplayGateway(gateway, reportType, reportType.IsResolvedReport() ? null : - ReportBase.ConstructLink(ReportBase.GetIconClass(ObjCategory.nsrv, "Gateway"), gateway.Name, style, gwLink)).ToString(); + ReportBase.ConstructLink(ReportBase.GetIconClass(ObjCategory.nsrv, "Gateway"), gateway.Name ?? "", style, gwLink)).ToString(); } private string DisplaySourceOrDestination(Rule rule, int chapterNumber, OutputLocation location, ReportType reportType, string style, bool isSource) diff --git a/roles/lib/files/FWO.Report/ReportDevicesBase.cs b/roles/lib/files/FWO.Report/ReportDevicesBase.cs index ae049428e0..d01c0eb16e 100644 --- a/roles/lib/files/FWO.Report/ReportDevicesBase.cs +++ b/roles/lib/files/FWO.Report/ReportDevicesBase.cs @@ -121,9 +121,9 @@ private static async Task UsageDataAvailable(ApiConnection apiConnection, try { // TODO: the following only deals with first rulebase of a gateway: - // return (await apiConnection.SendQueryAsync>(ReportQueries.getUsageDataCount, new { devId }) - // )[0].RulebasesOnGateway[0].Rulebase.RulesWithHits.Aggregate.Count > 0; - return false; // TODO: implement + var result = await apiConnection.SendQueryAsync>(ReportQueries.getUsageDataCount, new { devId }); + return result?.FirstOrDefault()?.RulebasesOnGateway?.FirstOrDefault()?.ToRulebase?.Rules?.Length > 0; + } catch (Exception) { diff --git a/roles/tests-unit/files/FWO.Test/ReportComplianceTest.cs b/roles/tests-unit/files/FWO.Test/ReportComplianceTest.cs index 9817ca9c5d..c54734efef 100644 --- a/roles/tests-unit/files/FWO.Test/ReportComplianceTest.cs +++ b/roles/tests-unit/files/FWO.Test/ReportComplianceTest.cs @@ -7,11 +7,11 @@ namespace FWO.Test [TestFixture] internal class ReportComplianceTest { - private MockReportCompliance _complianceReport => new(new(""), new(), Basics.ReportType.Compliance); + private static MockReportCompliance _complianceReport => new(new(""), new(), Basics.ReportType.Compliance); private MockReportCompliance _testReport = default!; - private MockReportComplianceDiff _complianceDiffReport => new(new(""), new(), Basics.ReportType.ComplianceDiff); + private static MockReportComplianceDiff _complianceDiffReport => new(new(""), new(), Basics.ReportType.ComplianceDiff); private MockReportComplianceDiff _testDiffReport = default!; - + [SetUp] public void SetUpTest() @@ -129,7 +129,7 @@ public async Task ProcessChunksParallelized_MinimalTestData_CreatesCorrectDiffs( // ASSERT Assert.That(testResults.First(r => r.Id == rule1.Id).ViolationDetails == controlRule1, message: $"{testResults.First(r => r.Id == rule1.Id).ViolationDetails} VS. {controlRule1}"); - Assert.That(testResults.First(r => r.Id == rule2.Id).ViolationDetails == controlRule2 , message: $"{testResults.First(r => r.Id == rule2.Id).ViolationDetails} VS. {controlRule2}"); + Assert.That(testResults.First(r => r.Id == rule2.Id).ViolationDetails == controlRule2, message: $"{testResults.First(r => r.Id == rule2.Id).ViolationDetails} VS. {controlRule2}"); } private List[] BuildFixedRuleChunksParallel(int numberOfChunks, int numberOfRulesPerChunk, int startRuleId = 1, int? maxDegreeOfParallelism = null) @@ -159,4 +159,4 @@ private List[] BuildFixedRuleChunksParallel(int numberOfChunks, int number } } -} \ No newline at end of file +} From 8c1ca2c26743604971b54f35dee5f3879eb249ce Mon Sep 17 00:00:00 2001 From: Tim Purschke Date: Mon, 3 Nov 2025 20:24:09 +0100 Subject: [PATCH 2/5] fixing variance report --- .../Modelling/ModellingVarianceResult.cs | 263 ++++++++++++++++-- 1 file changed, 244 insertions(+), 19 deletions(-) diff --git a/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs b/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs index da8c872f67..ee955881d5 100644 --- a/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs +++ b/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs @@ -1,3 +1,6 @@ +using System; +using System.Collections.Generic; +using System.Linq; using FWO.Data.Report; namespace FWO.Data.Modelling @@ -37,7 +40,7 @@ public void AddDifference(ModellingConnection conn, Rule rule) ModProdDifference? diff = RuleDifferences.FirstOrDefault(d => d.ModelledConnection.Id == conn.Id); if (diff == null) { - RuleDifferences.Add(new(){ModelledConnection = conn, ImplementedRules = [rule]}); + RuleDifferences.Add(new() { ModelledConnection = conn, ImplementedRules = [rule] }); } else { @@ -50,7 +53,7 @@ public void AddOkRule(ModellingConnection conn, Rule rule) ModProdDifference? diff = OkRules.FirstOrDefault(d => d.ModelledConnection.Id == conn.Id); if (diff == null) { - OkRules.Add(new(){ModelledConnection = conn, ImplementedRules = [rule]}); + OkRules.Add(new() { ModelledConnection = conn, ImplementedRules = [rule] }); } else { @@ -81,29 +84,251 @@ public List DeletedConnRuleDataToReport() private List MgtDataToReport(Dictionary> rulesToReport) { List managementReports = []; - foreach (var mgtId in rulesToReport.Keys.Where(m => rulesToReport[m].Count > 0)) + + foreach ((int managementId, List rulesPerManagement) in rulesToReport.Where(entry => entry.Value.Count > 0)) { - Management? mgt = Managements.FirstOrDefault(m => m.Id == mgtId); - ManagementReport managementReport = new() { Id = mgtId, Name = mgt?.Name ?? "" }; - List deviceReports = []; - foreach (var rule in rulesToReport[mgtId]) + Management? management = Managements.FirstOrDefault(m => m.Id == managementId); + Dictionary deviceMap = management?.Devices?.ToDictionary(d => d.Id) ?? []; + Dictionary deviceNameMap = management?.Devices? + .Where(d => !string.IsNullOrEmpty(d.Name)) + .GroupBy(d => d.Name!, StringComparer.OrdinalIgnoreCase) + .ToDictionary(group => group.Key, group => group.First(), StringComparer.OrdinalIgnoreCase) ?? []; + + ManagementReport managementReport = new() + { + Id = managementId, + Name = management?.Name ?? "", + Uid = management?.Uid ?? "" + }; + + Dictionary rulebaseReports = []; + Dictionary> rulebaseRules = []; + + Dictionary deviceAggregations = []; + Dictionary pseudoRulebaseIds = []; + int nextPseudoRulebaseId = -1; + + foreach (Rule rule in rulesPerManagement) + { + int deviceId = ResolveDeviceId(rule, management, deviceNameMap); + int rulebaseId = ResolveRulebaseId(rule, pseudoRulebaseIds, ref nextPseudoRulebaseId); + + RulebaseReport rulebaseReport = GetOrCreateRulebaseReport(rulebaseReports, rulebaseId, rule); + if (!rulebaseRules.TryGetValue(rulebaseId, out List? rulesForRulebase)) + { + rulesForRulebase = []; + rulebaseRules.Add(rulebaseId, rulesForRulebase); + } + + rulesForRulebase.Add(rule); + + DeviceAggregation deviceAggregation = GetOrCreateDeviceAggregation(deviceAggregations, deviceId, rule, management, deviceMap, deviceNameMap); + + EnsureRulebaseLink(deviceAggregation, deviceId, rulebaseReport.Id); + + deviceAggregation.RuleCount++; + } + + foreach ((int rulebaseId, List ruleList) in rulebaseRules) { - // TODO: Migrate - // DeviceReport? existingDev = deviceReports.FirstOrDefault(d => d.Id == rule.DeviceId); - // if (existingDev != null) - // { - // existingDev.Rules = existingDev.Rules?.Append(rule).ToArray(); - // } - // else - // { - // string devName = mgt == null ? "" : mgt.Devices.FirstOrDefault(d => d.Id == rule.DeviceId)?.Name ?? ""; - // deviceReports.Add(new() { Id = rule.DeviceId, Name = devName, Rules = [rule] }); - // } + RulebaseReport report = rulebaseReports[rulebaseId]; + report.Rules = ruleList.ToArray(); + report.RuleStatistics.ObjectAggregate.ObjectCount = report.Rules.Length; } - managementReport.Devices = [.. deviceReports]; + + managementReport.Rulebases = rulebaseReports.Values.OrderBy(rb => rb.Id).ToArray(); + + managementReport.Devices = deviceAggregations + .OrderBy(pair => pair.Key) + .Select(pair => CreateDeviceReport(pair.Key, pair.Value)) + .ToArray(); + managementReports.Add(managementReport); } + return managementReports; } + + private static int ResolveRulebaseId(Rule rule, Dictionary pseudoRulebaseIds, ref int nextPseudoRulebaseId) + { + if (rule.RulebaseId != 0) + { + return rule.RulebaseId; + } + + if (rule.Rulebase?.Id > 0) + { + return Convert.ToInt32(rule.Rulebase.Id); + } + + long fallbackKey = rule.Id; + if (!pseudoRulebaseIds.TryGetValue(fallbackKey, out int pseudoId)) + { + pseudoId = nextPseudoRulebaseId--; + pseudoRulebaseIds.Add(fallbackKey, pseudoId); + } + + return pseudoId; + } + + private static RulebaseReport GetOrCreateRulebaseReport(Dictionary rulebaseReports, int rulebaseId, Rule rule) + { + if (rulebaseReports.TryGetValue(rulebaseId, out RulebaseReport? existing)) + { + return existing; + } + + string? rulebaseName = rule.Rulebase?.Name; + if (string.IsNullOrEmpty(rulebaseName)) + { + rulebaseName = rule.RulebaseName; + } + + RulebaseReport newReport = new() + { + Id = rulebaseId, + Name = rulebaseName + }; + + rulebaseReports.Add(rulebaseId, newReport); + + return newReport; + } + + private static int ResolveDeviceId(Rule rule, Management? management, Dictionary deviceNameMap) + { + if (rule.Metadata?.DeviceId > 0) + { + return rule.Metadata.DeviceId; + } + + if (rule.EnforcingGateways?.Length > 0) + { + Device? enforcingDevice = rule.EnforcingGateways + .Select(wrapper => wrapper.Content) + .FirstOrDefault(device => device?.Id > 0); + if (enforcingDevice?.Id > 0) + { + return enforcingDevice.Id; + } + } + + if (!string.IsNullOrWhiteSpace(rule.DeviceName) && deviceNameMap.TryGetValue(rule.DeviceName, out Device? deviceByName) && deviceByName.Id > 0) + { + return deviceByName.Id; + } + + if (management?.Devices?.Length == 1) + { + return management.Devices[0].Id; + } + + return 0; + } + + private static DeviceAggregation GetOrCreateDeviceAggregation(Dictionary deviceAggregations, int deviceId, Rule rule, Management? management, Dictionary deviceMap, Dictionary deviceNameMap) + { + if (!deviceAggregations.TryGetValue(deviceId, out DeviceAggregation? aggregation)) + { + (string deviceName, string deviceUid) = ResolveDeviceMetadata(deviceId, rule, management, deviceMap, deviceNameMap); + + aggregation = new DeviceAggregation + { + Name = deviceName, + Uid = deviceUid + }; + + deviceAggregations.Add(deviceId, aggregation); + } + else + { + RefreshDeviceAggregationMetadata(aggregation, deviceId, rule, management, deviceMap, deviceNameMap); + } + + return aggregation; + } + + private static (string deviceName, string deviceUid) ResolveDeviceMetadata(int deviceId, Rule rule, Management? management, Dictionary deviceMap, Dictionary deviceNameMap) + { + if (deviceId > 0 && deviceMap.TryGetValue(deviceId, out Device? deviceFromManagement)) + { + return (deviceFromManagement.Name ?? "", deviceFromManagement.Uid ?? ""); + } + + if (!string.IsNullOrWhiteSpace(rule.DeviceName) && deviceNameMap.TryGetValue(rule.DeviceName, out Device? deviceByName)) + { + return (deviceByName.Name ?? "", deviceByName.Uid ?? ""); + } + + if (!string.IsNullOrWhiteSpace(rule.DeviceName)) + { + return (rule.DeviceName, ""); + } + + return (deviceId > 0 ? $"Device {deviceId}" : "Unknown Device", ""); + } + + private static void RefreshDeviceAggregationMetadata(DeviceAggregation aggregation, int deviceId, Rule rule, Management? management, Dictionary deviceMap, Dictionary deviceNameMap) + { + (string candidateName, string candidateUid) = ResolveDeviceMetadata(deviceId, rule, management, deviceMap, deviceNameMap); + + bool hasMeaningfulName = !string.IsNullOrWhiteSpace(candidateName); + bool shouldReplaceName = string.IsNullOrWhiteSpace(aggregation.Name) + || aggregation.Name.StartsWith("Unknown", StringComparison.OrdinalIgnoreCase); + + if (hasMeaningfulName && shouldReplaceName) + { + aggregation.Name = candidateName; + } + + if (!string.IsNullOrEmpty(candidateUid)) + { + aggregation.Uid = candidateUid; + } + } + + private static void EnsureRulebaseLink(DeviceAggregation deviceAggregation, int deviceId, int rulebaseId) + { + if (deviceAggregation.RulebaseLinks.Any(link => link.NextRulebaseId == rulebaseId)) + { + return; + } + + int? initialRulebaseId = deviceAggregation.RulebaseLinks.FirstOrDefault()?.NextRulebaseId; + + RulebaseLink newLink = new() + { + GatewayId = deviceId, + NextRulebaseId = rulebaseId, + IsInitial = deviceAggregation.RulebaseLinks.Count == 0, + FromRulebaseId = deviceAggregation.RulebaseLinks.Count == 0 ? null : initialRulebaseId, + Removed = null + }; + + deviceAggregation.RulebaseLinks.Add(newLink); + } + + private static DeviceReport CreateDeviceReport(int deviceId, DeviceAggregation aggregation) + { + DeviceReport deviceReport = new() + { + Id = deviceId, + Name = aggregation.Name, + Uid = aggregation.Uid, + RulebaseLinks = aggregation.RulebaseLinks.ToArray() + }; + + deviceReport.RuleStatistics.ObjectAggregate.ObjectCount = aggregation.RuleCount; + + return deviceReport; + } + + private sealed class DeviceAggregation + { + public string Name { get; set; } = ""; + public string Uid { get; set; } = ""; + public List RulebaseLinks { get; } = []; + public int RuleCount { get; set; } + } } } From c3202ca6285e5c105d0640e7aff8b04eb01a9d72 Mon Sep 17 00:00:00 2001 From: Tim Purschke Date: Wed, 12 Nov 2025 08:28:45 +0100 Subject: [PATCH 3/5] sonar fixes --- roles/database/files/sql/idempotent/fworch-api-funcs.sql | 2 +- roles/database/files/upgrade/9.0.sql | 2 +- .../lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/roles/database/files/sql/idempotent/fworch-api-funcs.sql b/roles/database/files/sql/idempotent/fworch-api-funcs.sql index 9d739a3e46..c9c89fa308 100644 --- a/roles/database/files/sql/idempotent/fworch-api-funcs.sql +++ b/roles/database/files/sql/idempotent/fworch-api-funcs.sql @@ -645,7 +645,7 @@ AS $$ ) ) ) - ORDER BY r.rule_name; + ORDER BY r.rule_name ASC; $$; diff --git a/roles/database/files/upgrade/9.0.sql b/roles/database/files/upgrade/9.0.sql index bd65d06eff..c2882d0744 100644 --- a/roles/database/files/upgrade/9.0.sql +++ b/roles/database/files/upgrade/9.0.sql @@ -1079,7 +1079,7 @@ AS $$ ) ) ) - ORDER BY r.rule_name; + ORDER BY r.rule_name ASC; $$; diff --git a/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs b/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs index ee955881d5..91a8a6fe59 100644 --- a/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs +++ b/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs @@ -230,7 +230,7 @@ private static DeviceAggregation GetOrCreateDeviceAggregation(Dictionary deviceMap, Dictionary deviceNameMap) + private static (string deviceName, string deviceUid) ResolveDeviceMetadata(int deviceId, Rule rule, Dictionary deviceMap, Dictionary deviceNameMap) { if (deviceId > 0 && deviceMap.TryGetValue(deviceId, out Device? deviceFromManagement)) { @@ -270,7 +270,7 @@ private static (string deviceName, string deviceUid) ResolveDeviceMetadata(int d private static void RefreshDeviceAggregationMetadata(DeviceAggregation aggregation, int deviceId, Rule rule, Management? management, Dictionary deviceMap, Dictionary deviceNameMap) { - (string candidateName, string candidateUid) = ResolveDeviceMetadata(deviceId, rule, management, deviceMap, deviceNameMap); + (string candidateName, string candidateUid) = ResolveDeviceMetadata(deviceId, rule, deviceMap, deviceNameMap); bool hasMeaningfulName = !string.IsNullOrWhiteSpace(candidateName); bool shouldReplaceName = string.IsNullOrWhiteSpace(aggregation.Name) From b1ab695efcba5ff885f9ea0aa4c999e572c254e0 Mon Sep 17 00:00:00 2001 From: Tim Purschke Date: Wed, 12 Nov 2025 08:42:49 +0100 Subject: [PATCH 4/5] sonar remove unused field --- .../lib/files/FWO.Compliance/ComplianceCheck.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/roles/lib/files/FWO.Compliance/ComplianceCheck.cs b/roles/lib/files/FWO.Compliance/ComplianceCheck.cs index 21a1c6e3bd..31f1be1d11 100644 --- a/roles/lib/files/FWO.Compliance/ComplianceCheck.cs +++ b/roles/lib/files/FWO.Compliance/ComplianceCheck.cs @@ -27,8 +27,6 @@ public class ComplianceCheck private readonly ApiConnection _apiConnection; private readonly DebugConfig _debugConfig; - private readonly List _relevantManagementIDs = new(); - /// /// Constructor for compliance check /// @@ -50,21 +48,6 @@ public ComplianceCheck(UserConfig userConfig, ApiConnection apiConnection) _debugConfig = new(); } - if (userConfig.GlobalConfig is GlobalConfig globalConfig && !string.IsNullOrEmpty(globalConfig.DebugConfig)) - { - try - { - _relevantManagementIDs = userConfig.GlobalConfig.ComplianceCheckRelevantManagements - .Split(',', StringSplitOptions.RemoveEmptyEntries) - .Select(s => int.Parse(s.Trim())) - .ToList(); - } - catch (System.Exception e) - { - Log.TryWriteLog(LogType.Error, "Compliance Check", $"Error while parsing relevant mangement IDs: {e.Message}", _debugConfig.ExtendedLogComplianceCheck); - } - } - } /// From 75840baf0142580d045ffda00f096fd111440c67 Mon Sep 17 00:00:00 2001 From: Tim Purschke Date: Wed, 12 Nov 2025 11:41:04 +0100 Subject: [PATCH 5/5] no mgm --- roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs b/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs index 91a8a6fe59..75d7910d58 100644 --- a/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs +++ b/roles/lib/files/FWO.Data/Modelling/ModellingVarianceResult.cs @@ -242,7 +242,7 @@ private static DeviceAggregation GetOrCreateDeviceAggregation(Dictionary 0 ? $"Device {deviceId}" : "Unknown Device", ""); } - private static void RefreshDeviceAggregationMetadata(DeviceAggregation aggregation, int deviceId, Rule rule, Management? management, Dictionary deviceMap, Dictionary deviceNameMap) + private static void RefreshDeviceAggregationMetadata(DeviceAggregation aggregation, int deviceId, Rule rule, Dictionary deviceMap, Dictionary deviceNameMap) { (string candidateName, string candidateUid) = ResolveDeviceMetadata(deviceId, rule, deviceMap, deviceNameMap);