Skip to content

Commit 5608809

Browse files
Merge branch 'CactuseSecurity:develop' into develop
2 parents cf48892 + 194710c commit 5608809

12 files changed

Lines changed: 189 additions & 6 deletions

File tree

roles/common/files/fwo-api-calls/rule/fragments/ruleDetails.graphql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ fragment ruleDetails on rule {
2929
rule_name
3030
rule_installon
3131
rule_custom_fields
32+
rule_time
33+
rule_times{
34+
rule_time_id
35+
rule_id
36+
time_obj_id
37+
created
38+
removed
39+
time_object {
40+
time_obj_id
41+
time_obj_name
42+
time_obj_uid
43+
start_time
44+
end_time
45+
created
46+
}
47+
}
3248
access_rule
3349
nat_rule
3450
xlate_rule

roles/common/files/fwo-api-calls/rule/fragments/ruleDetailsForReport.graphql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@
3535
rule_name
3636
rule_installon
3737
rule_custom_fields
38+
rule_time
39+
rule_times {
40+
rule_time_id
41+
rule_id
42+
time_obj_id
43+
created
44+
removed
45+
time_object {
46+
time_obj_id
47+
time_obj_name
48+
time_obj_uid
49+
start_time
50+
end_time
51+
created
52+
}
53+
}
3854
access_rule
3955
nat_rule
4056
xlate_rule

roles/common/files/fwo-api-calls/rule/fragments/ruleOverview.graphql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,22 @@ fragment ruleOverview on rule {
3232
rule_name
3333
rule_custom_fields
3434
rule_installon
35+
rule_time
36+
rule_times {
37+
rule_time_id
38+
rule_id
39+
time_obj_id
40+
created
41+
removed
42+
time_object {
43+
time_obj_id
44+
time_obj_name
45+
time_obj_uid
46+
start_time
47+
end_time
48+
created
49+
}
50+
}
3551
access_rule
3652
nat_rule
3753
xlate_rule

roles/lib/files/FWO.Data/Rule.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ public class Rule
132132
[JsonProperty("rule_time"), JsonPropertyName("rule_time")]
133133
public string? Time { get; set; }
134134

135+
[JsonProperty("rule_times"), JsonPropertyName("rule_times")]
136+
public List<RuleTime> RuleTimes { get; set; } = [];
137+
135138
[JsonProperty("violations"), JsonPropertyName("violations")]
136139
public List<ComplianceViolation> Violations { get; set; } = [];
137140

@@ -208,6 +211,7 @@ public Rule(Rule rule)
208211
EnforcingGateways = rule.EnforcingGateways;
209212
InstallOn = rule.InstallOn;
210213
Time = rule.Time;
214+
RuleTimes = rule.RuleTimes;
211215
Violations = rule.Violations;
212216
Rulebase = rule.Rulebase;
213217
LastChangeAdmin = rule.LastChangeAdmin;

roles/lib/files/FWO.Data/RuleTime.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ public class RuleTime
1414
[JsonProperty("time_obj_id"), JsonPropertyName("time_obj_id")]
1515
public long TimeObjId { get; set; }
1616

17+
[JsonProperty("created"), JsonPropertyName("created")]
18+
public long Created { get; set; }
19+
1720
[JsonProperty("removed"), JsonPropertyName("removed")]
18-
public int Removed { get; set; } = 0;
21+
public long? Removed { get; set; }
22+
23+
[JsonProperty("time_object"), JsonPropertyName("time_object")]
24+
public TimeObject? TimeObj { get; set; }
1925
}
2026
}

roles/lib/files/FWO.Report/Data/ViewData/RuleViewData.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class RuleViewData : IRuleViewData
3030
public string RulebaseId { get; set; } = "";
3131
public string RulebaseName { get; set; } = "";
3232
public string Enabled { get; set; } = "";
33+
public string RuleTime { get; set; } = "";
3334

3435
public Rule? DataObject { get; set; }
3536
public bool Show { get; set; } = true;
@@ -63,6 +64,7 @@ public RuleViewData(Rule rule, NatRuleDisplayHtml natRuleDisplayHtml, OutputLoca
6364
AdoITID = SafeCall(rule, "AdoITID", () => GetFromCustomField(rule, ["field-3", "AdoIT"]));
6465
Comment = SafeCall(rule, "Comment", () => rule.Comment ?? "");
6566
LastModified = SafeCall(rule, "LastModified", () => RuleDisplayBase.DisplayLastModified(rule));
67+
RuleTime = SafeCall(rule, "RuleTime", () => natRuleDisplayHtml.DisplayRuleTime(rule));
6668
RulebaseId = SafeCall(rule, "RulebaseId", () => rule.RulebaseId.ToString());
6769
RulebaseName = SafeCall(rule, "RulebaseName", () => rule.Rulebase?.Name ?? "");
6870
Enabled = SafeCall(rule, "Enabled", () => RuleDisplayBase.DisplayEnabled(rule, outputLocation));

roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ namespace FWO.Ui.Display
88
{
99
public class RuleDisplayHtml(UserConfig userConfig) : RuleDisplayBase(userConfig)
1010
{
11+
public string DisplayRuleTime(Rule rule)
12+
{
13+
// Quick implementation to satisfy current requirements: use only the first time object with an EndTime.
14+
DateTime? firstEndTime = rule.RuleTimes.FirstOrDefault(ruleTime => ruleTime.TimeObj?.EndTime != null)?.TimeObj?.EndTime;
15+
return firstEndTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "";
16+
}
17+
1118
public string DisplaySource(Rule rule, OutputLocation location, ReportType reportType, int chapterNumber = 0, string style = "", bool overwriteIsResolvedReport = false)
1219
{
1320
return DisplaySourceOrDestination(rule, chapterNumber, location, reportType, style, true, overwriteIsResolvedReport);

roles/tests-unit/files/FWO.Test/ExportTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ public void RulesGenerateJson()
482482
"\"rule_action\": \"accept\",\"rule_track\": \"none\",\"section_header\": \"\"," +
483483
"\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"created_import\": null,\"removed\": null,\"removed_import\": null,\"rule_first_hit\": null,\"rule_last_hit\": \"2022-04-19T00:00:00\",\"recertification\": [],\"recert_history\": [],\"rule_uid\": \"\",\"rules\": [],\"Recert\": false}," +
484484
"\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," +
485-
"\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"rule_custom_fields\": \"\",\"rule_implied\": false,\"nat_rule\": false,\"rulebase_id\": 0,\"rule_num\": 0,\"rule_enforced_on_gateways\": [],\"rule_installon\": null,\"rule_time\": null,\"violations\": [],\"rulebase\": {\"id\": 0,\"name\": \"\",\"uid\": \"\",\"mgm_id\": 0,\"is_global\": false,\"created\": 0,\"removed\": 0,\"rules\": []},\"uiuser\": null,\"rule\": null,\"ChangeID\": \"\",\"AdoITID\": \"\",\"Compliance\": 0,\"ViolationDetails\": \"\",\"DisplayOrderNumberString\": \"1\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\",\"RulebaseName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": [],\"DisregardedServices\": [],\"ShowDisregarded\": false}," +
485+
"\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"rule_custom_fields\": \"\",\"rule_implied\": false,\"nat_rule\": false,\"rulebase_id\": 0,\"rule_num\": 0,\"rule_enforced_on_gateways\": [],\"rule_installon\": null,\"rule_time\": null,\"rule_times\": [],\"violations\": [],\"rulebase\": {\"id\": 0,\"name\": \"\",\"uid\": \"\",\"mgm_id\": 0,\"is_global\": false,\"created\": 0,\"removed\": 0,\"rules\": []},\"uiuser\": null,\"rule\": null,\"ChangeID\": \"\",\"AdoITID\": \"\",\"Compliance\": 0,\"ViolationDetails\": \"\",\"DisplayOrderNumberString\": \"1\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\",\"RulebaseName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": [],\"DisregardedServices\": [],\"ShowDisregarded\": false}," +
486486
"{\"rule_id\": 0,\"rule_uid\": \"uid2:123\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule2\",\"rule_comment\": \"comment2\",\"rule_disabled\": false," +
487487
"\"rule_services\": [{\"service\": {\"svc_id\": 2,\"svc_name\": \"TestService2\",\"svc_uid\": \"\",\"svc_port\": 6666,\"svc_port_end\": 7777,\"svc_source_port\": null,\"svc_source_port_end\": null,\"svc_code\": \"\",\"svc_timeout\": null,\"svc_typ_id\": null,\"active\": false,\"svc_create\": 0,\"svc_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"svc_last_seen\": 0,\"service_type\": {\"name\": \"\"},\"svc_comment\": \"\",\"svc_color_id\": null,\"stm_color\": null,\"ip_proto_id\": null,\"protocol_name\": {\"id\": 17,\"name\": \"UDP\"},\"svc_member_names\": \"\",\"svc_member_refs\": \"\",\"svcgrps\": [],\"svcgrp_flats\": [],\"svc_rpcnr\": null}}]," +
488488
"\"rule_svc_neg\": true,\"rule_svc\": \"\",\"rule_svc_refs\": \"\",\"rule_src_neg\": true,\"rule_src\": \"\",\"rule_src_refs\": \"\",\"rule_from_zones\": []," +
@@ -495,7 +495,7 @@ public void RulesGenerateJson()
495495
"\"rule_action\": \"deny\",\"rule_track\": \"none\",\"section_header\": \"\"," +
496496
"\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"created_import\": null,\"removed\": null,\"removed_import\": null,\"rule_first_hit\": null,\"rule_last_hit\": null,\"recertification\": [],\"recert_history\": [],\"rule_uid\": \"\",\"rules\": [],\"Recert\": false}," +
497497
"\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," +
498-
"\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"rule_custom_fields\": \"\",\"rule_implied\": false,\"nat_rule\": false,\"rulebase_id\": 0,\"rule_num\": 0,\"rule_enforced_on_gateways\": [],\"rule_installon\": null,\"rule_time\": null,\"violations\": [],\"rulebase\": {\"id\": 0,\"name\": \"\",\"uid\": \"\",\"mgm_id\": 0,\"is_global\": false,\"created\": 0,\"removed\": 0,\"rules\": []},\"uiuser\": null,\"rule\": null,\"ChangeID\": \"\",\"AdoITID\": \"\",\"Compliance\": 0,\"ViolationDetails\": \"\",\"DisplayOrderNumberString\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\",\"RulebaseName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": [],\"DisregardedServices\": [],\"ShowDisregarded\": false}]}]," +
498+
"\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"rule_custom_fields\": \"\",\"rule_implied\": false,\"nat_rule\": false,\"rulebase_id\": 0,\"rule_num\": 0,\"rule_enforced_on_gateways\": [],\"rule_installon\": null,\"rule_time\": null,\"rule_times\": [],\"violations\": [],\"rulebase\": {\"id\": 0,\"name\": \"\",\"uid\": \"\",\"mgm_id\": 0,\"is_global\": false,\"created\": 0,\"removed\": 0,\"rules\": []},\"uiuser\": null,\"rule\": null,\"ChangeID\": \"\",\"AdoITID\": \"\",\"Compliance\": 0,\"ViolationDetails\": \"\",\"DisplayOrderNumberString\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\",\"RulebaseName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": [],\"DisregardedServices\": [],\"ShowDisregarded\": false}]}]," +
499499
"\"changelog_rules\": null,\"changelog_objects\": null,\"changelog_services\": null,\"changelog_users\": null,\"import\": {\"aggregate\": {\"max\": {\"id\": null}}},\"import_controls\": [],\"RelevantImportId\": null,\"is_super_manager\": false,\"multi_device_manager_id\": null,\"management\": null,\"managementByMultiDeviceManagerId\": [],\"networkObjects\": [],\"serviceObjects\": [],\"userObjects\": [],\"zoneObjects\": []," +
500500
"\"reportNetworkObjects\": [{\"obj_id\": 1,\"obj_name\": \"TestIp1\",\"obj_ip\": \"1.2.3.4/32\",\"obj_ip_end\": \"1.2.3.4/32\",\"obj_uid\": \"\",\"zone\": null,\"active\": false,\"obj_create\": 0," +
501501
"\"obj_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"obj_last_seen\": 0,\"type\": {\"id\": 0,\"name\": \"network\"},\"obj_color\": null,\"obj_comment\": \"\",\"obj_member_names\": \"\",\"obj_member_refs\": \"\"," +
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using FWO.Data;
2+
using Newtonsoft.Json;
3+
using NUnit.Framework;
4+
5+
namespace FWO.Test
6+
{
7+
[TestFixture]
8+
public class RuleDataTest
9+
{
10+
[Test]
11+
public void RuleTimes_AreDeserialized_WhenRemovedIsNull()
12+
{
13+
const string serializedRule = """
14+
{
15+
"rule_id": 1001,
16+
"rule_times": [
17+
{
18+
"rule_time_id": 10,
19+
"rule_id": 1001,
20+
"time_obj_id": 55,
21+
"created": 200,
22+
"removed": null,
23+
"time_object": {
24+
"time_obj_id": 55,
25+
"time_obj_name": "Office Hours",
26+
"time_obj_uid": "uid-55",
27+
"start_time": "2025-01-01T08:00:00Z",
28+
"end_time": "2025-01-01T17:00:00Z",
29+
"created": 200
30+
}
31+
}
32+
]
33+
}
34+
""";
35+
36+
Rule? deserializedRule = JsonConvert.DeserializeObject<Rule>(serializedRule);
37+
38+
Assert.That(deserializedRule, Is.Not.Null);
39+
Assert.That(deserializedRule!.RuleTimes.Count, Is.EqualTo(1));
40+
Assert.That(deserializedRule.RuleTimes[0].Id, Is.EqualTo(10));
41+
Assert.That(deserializedRule.RuleTimes[0].RuleId, Is.EqualTo(1001));
42+
Assert.That(deserializedRule.RuleTimes[0].TimeObjId, Is.EqualTo(55));
43+
Assert.That(deserializedRule.RuleTimes[0].Created, Is.EqualTo(200));
44+
Assert.That(deserializedRule.RuleTimes[0].Removed, Is.Null);
45+
Assert.That(deserializedRule.RuleTimes[0].TimeObj, Is.Not.Null);
46+
TimeObject timeObject = deserializedRule.RuleTimes[0].TimeObj!;
47+
Assert.That(timeObject.Id, Is.EqualTo(55));
48+
Assert.That(timeObject.Name, Is.EqualTo("Office Hours"));
49+
}
50+
}
51+
}

roles/tests-unit/files/FWO.Test/RuleViewDataTest.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,60 @@ public void RuleViewData_LastModified_UsesCreatedWhenNoLastSeen()
9292
Assert.That(viewData.LastModified, Is.EqualTo("2023-01-10"));
9393
}
9494

95+
[Test]
96+
public void DisplayRuleTime_UsesFirstTimeObjectWithEndTime()
97+
{
98+
Rule rule = new Rule
99+
{
100+
RuleTimes =
101+
[
102+
new RuleTime { TimeObj = new TimeObject { EndTime = null } },
103+
new RuleTime { TimeObj = new TimeObject { EndTime = new DateTime(2026, 01, 02, 03, 04, 05) } },
104+
new RuleTime { TimeObj = new TimeObject { EndTime = new DateTime(2030, 06, 07, 08, 09, 10) } }
105+
]
106+
};
107+
108+
UserConfig userConfig = new UserConfig();
109+
RuleDisplayHtml ruleDisplay = new RuleDisplayHtml(userConfig);
110+
111+
Assert.That(ruleDisplay.DisplayRuleTime(rule), Is.EqualTo("2026-01-02 03:04:05"));
112+
}
113+
114+
[Test]
115+
public void DisplayRuleTime_ReturnsEmpty_WhenNoTimeObjectHasEndTime()
116+
{
117+
Rule rule = new Rule
118+
{
119+
RuleTimes =
120+
[
121+
new RuleTime { TimeObj = null },
122+
new RuleTime { TimeObj = new TimeObject { EndTime = null } }
123+
]
124+
};
125+
126+
UserConfig userConfig = new UserConfig();
127+
RuleDisplayHtml ruleDisplay = new RuleDisplayHtml(userConfig);
128+
129+
Assert.That(ruleDisplay.DisplayRuleTime(rule), Is.EqualTo(""));
130+
}
131+
132+
[Test]
133+
public void RuleViewData_SetsRuleTime_FromDisplayRuleTime()
134+
{
135+
Rule rule = new Rule
136+
{
137+
RuleTimes =
138+
[
139+
new RuleTime { TimeObj = new TimeObject { EndTime = new DateTime(2026, 12, 24, 11, 22, 33) } }
140+
]
141+
};
142+
143+
UserConfig userConfig = new UserConfig();
144+
NatRuleDisplayHtml ruleDisplay = new NatRuleDisplayHtml(userConfig);
145+
RuleViewData viewData = new RuleViewData(rule, ruleDisplay, OutputLocation.report, true);
146+
147+
Assert.That(viewData.RuleTime, Is.EqualTo("2026-12-24 11:22:33"));
148+
}
149+
95150
}
96151
}

0 commit comments

Comments
 (0)