regscale-cli 6.26.0.0__py3-none-any.whl → 6.27.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of regscale-cli might be problematic. Click here for more details.
- regscale/_version.py +1 -1
- regscale/core/app/application.py +1 -1
- regscale/core/app/internal/evidence.py +419 -2
- regscale/dev/code_gen.py +24 -20
- regscale/integrations/commercial/__init__.py +0 -1
- regscale/integrations/commercial/jira.py +367 -126
- regscale/integrations/commercial/qualys/__init__.py +7 -8
- regscale/integrations/commercial/qualys/scanner.py +8 -3
- regscale/integrations/commercial/synqly/assets.py +17 -0
- regscale/integrations/commercial/synqly/vulnerabilities.py +45 -28
- regscale/integrations/commercial/tenablev2/cis_parsers.py +453 -0
- regscale/integrations/commercial/tenablev2/cis_scanner.py +447 -0
- regscale/integrations/commercial/tenablev2/commands.py +142 -1
- regscale/integrations/commercial/tenablev2/scanner.py +0 -1
- regscale/integrations/commercial/tenablev2/stig_parsers.py +113 -57
- regscale/integrations/commercial/wizv2/WizDataMixin.py +1 -1
- regscale/integrations/commercial/wizv2/click.py +44 -59
- regscale/integrations/commercial/wizv2/compliance/__init__.py +15 -0
- regscale/integrations/commercial/wizv2/{policy_compliance_helpers.py → compliance/helpers.py} +78 -60
- regscale/integrations/commercial/wizv2/compliance_report.py +10 -9
- regscale/integrations/commercial/wizv2/core/__init__.py +133 -0
- regscale/integrations/commercial/wizv2/{async_client.py → core/client.py} +3 -3
- regscale/integrations/commercial/wizv2/{constants.py → core/constants.py} +1 -17
- regscale/integrations/commercial/wizv2/core/file_operations.py +237 -0
- regscale/integrations/commercial/wizv2/fetchers/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{data_fetcher.py → fetchers/policy_assessment.py} +5 -9
- regscale/integrations/commercial/wizv2/issue.py +1 -1
- regscale/integrations/commercial/wizv2/models/__init__.py +0 -0
- regscale/integrations/commercial/wizv2/parsers/__init__.py +34 -0
- regscale/integrations/commercial/wizv2/{parsers.py → parsers/main.py} +1 -1
- regscale/integrations/commercial/wizv2/processors/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{finding_processor.py → processors/finding.py} +1 -1
- regscale/integrations/commercial/wizv2/reports.py +1 -1
- regscale/integrations/commercial/wizv2/sbom.py +1 -1
- regscale/integrations/commercial/wizv2/scanner.py +40 -100
- regscale/integrations/commercial/wizv2/utils/__init__.py +48 -0
- regscale/integrations/commercial/wizv2/{utils.py → utils/main.py} +116 -61
- regscale/integrations/commercial/wizv2/variables.py +89 -3
- regscale/integrations/compliance_integration.py +0 -46
- regscale/integrations/control_matcher.py +22 -3
- regscale/integrations/due_date_handler.py +14 -8
- regscale/integrations/public/fedramp/docx_parser.py +10 -1
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +393 -340
- regscale/integrations/public/fedramp/fedramp_five.py +1 -1
- regscale/integrations/scanner_integration.py +127 -57
- regscale/models/integration_models/cisa_kev_data.json +132 -9
- regscale/models/integration_models/qualys.py +3 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +24 -7
- regscale/models/integration_models/synqly_models/synqly_model.py +8 -1
- regscale/models/regscale_models/control_implementation.py +1 -1
- regscale/models/regscale_models/issue.py +0 -1
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/METADATA +1 -17
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/RECORD +94 -61
- tests/regscale/integrations/commercial/test_jira.py +481 -91
- tests/regscale/integrations/commercial/test_wiz.py +96 -200
- tests/regscale/integrations/commercial/wizv2/__init__.py +1 -1
- tests/regscale/integrations/commercial/wizv2/compliance/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/compliance/test_helpers.py +903 -0
- tests/regscale/integrations/commercial/wizv2/core/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/core/test_auth.py +701 -0
- tests/regscale/integrations/commercial/wizv2/core/test_client.py +1037 -0
- tests/regscale/integrations/commercial/wizv2/core/test_file_operations.py +989 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/test_policy_assessment.py +805 -0
- tests/regscale/integrations/commercial/wizv2/parsers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/parsers/test_main.py +1153 -0
- tests/regscale/integrations/commercial/wizv2/processors/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/processors/test_finding.py +671 -0
- tests/regscale/integrations/commercial/wizv2/test_WizDataMixin.py +537 -0
- tests/regscale/integrations/commercial/wizv2/test_click_comprehensive.py +851 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_comprehensive.py +910 -0
- tests/regscale/integrations/commercial/wizv2/test_file_cleanup.py +283 -0
- tests/regscale/integrations/commercial/wizv2/test_file_operations.py +260 -0
- tests/regscale/integrations/commercial/wizv2/test_issue.py +1 -1
- tests/regscale/integrations/commercial/wizv2/test_issue_comprehensive.py +1203 -0
- tests/regscale/integrations/commercial/wizv2/test_reports.py +497 -0
- tests/regscale/integrations/commercial/wizv2/test_sbom.py +643 -0
- tests/regscale/integrations/commercial/wizv2/test_scanner_comprehensive.py +805 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_click_client_id.py +1 -1
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +72 -29
- tests/regscale/integrations/commercial/wizv2/test_wiz_findings_comprehensive.py +364 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_inventory_comprehensive.py +644 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py +946 -78
- tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +97 -202
- tests/regscale/integrations/commercial/wizv2/utils/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/utils/test_main.py +1523 -0
- tests/regscale/integrations/public/test_fedramp.py +301 -0
- tests/regscale/integrations/test_control_matcher.py +83 -0
- regscale/integrations/commercial/wizv2/policy_compliance.py +0 -3543
- tests/regscale/integrations/commercial/wizv2/test_wiz_policy_compliance.py +0 -750
- /regscale/integrations/commercial/wizv2/{wiz_auth.py → core/auth.py} +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/LICENSE +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/WHEEL +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/top_level.txt +0 -0
|
@@ -31,7 +31,6 @@ from regscale.integrations.commercial.jira import (
|
|
|
31
31
|
sync_regscale_objects_to_jira,
|
|
32
32
|
sync_regscale_to_jira,
|
|
33
33
|
task_and_attachments_sync,
|
|
34
|
-
update_regscale_issues,
|
|
35
34
|
create_regscale_task_from_jira,
|
|
36
35
|
create_and_update_regscale_tasks,
|
|
37
36
|
process_tasks_for_sync,
|
|
@@ -39,7 +38,7 @@ from regscale.integrations.commercial.jira import (
|
|
|
39
38
|
upload_files_to_regscale,
|
|
40
39
|
validate_issue_type,
|
|
41
40
|
)
|
|
42
|
-
from regscale.models import File, Issue
|
|
41
|
+
from regscale.models import File, Issue
|
|
43
42
|
from regscale.models.regscale_models.task import Task
|
|
44
43
|
from tests import CLITestFixture
|
|
45
44
|
|
|
@@ -184,6 +183,7 @@ class TestJira(CLITestFixture):
|
|
|
184
183
|
parentId=self.PARENT_ID,
|
|
185
184
|
parentModule=self.PARENT_MODULE,
|
|
186
185
|
dueDate=get_current_datetime(),
|
|
186
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
187
187
|
status="Open",
|
|
188
188
|
).create()
|
|
189
189
|
if fetch_attachments:
|
|
@@ -287,6 +287,8 @@ class TestJira(CLITestFixture):
|
|
|
287
287
|
def test_sync_regscale_and_jira(self, mock_check_license, fetch_attachments):
|
|
288
288
|
"""Test the entire Jira & RegScale sync process"""
|
|
289
289
|
mock_check_license.return_value.config = self.config
|
|
290
|
+
# Add thread_manager to the mock Application
|
|
291
|
+
mock_check_license.return_value.thread_manager = MagicMock()
|
|
290
292
|
try:
|
|
291
293
|
sync_regscale_and_jira(
|
|
292
294
|
parent_id=self.PARENT_ID,
|
|
@@ -302,6 +304,8 @@ class TestJira(CLITestFixture):
|
|
|
302
304
|
def test_sync_regscale_and_jira_tasks(self, mock_check_license, fetch_attachments):
|
|
303
305
|
"""Test the entire Jira & RegScale task sync process"""
|
|
304
306
|
mock_check_license.return_value.config = self.config
|
|
307
|
+
# Add thread_manager to the mock Application
|
|
308
|
+
mock_check_license.return_value.thread_manager = MagicMock()
|
|
305
309
|
try:
|
|
306
310
|
sync_regscale_and_jira(
|
|
307
311
|
parent_id=self.PARENT_ID,
|
|
@@ -358,7 +362,7 @@ class TestJira(CLITestFixture):
|
|
|
358
362
|
mock_fetch_jira_objects.assert_called_once_with(
|
|
359
363
|
jira_client=mock_jira_client,
|
|
360
364
|
jira_project=self.JIRA_PROJECT,
|
|
361
|
-
jql_str="project = SNES",
|
|
365
|
+
jql_str="project = 'SNES'",
|
|
362
366
|
jira_issue_type="Bug",
|
|
363
367
|
sync_tasks_only=False,
|
|
364
368
|
)
|
|
@@ -390,6 +394,11 @@ class TestJira(CLITestFixture):
|
|
|
390
394
|
mock_jira_client = MagicMock()
|
|
391
395
|
mock_create_jira_client.return_value = mock_jira_client
|
|
392
396
|
|
|
397
|
+
# Setup mock config with jiraCustomFields returning empty dict
|
|
398
|
+
mock_config = MagicMock()
|
|
399
|
+
mock_config.get.return_value = {}
|
|
400
|
+
mock_check_license.return_value.config = mock_config
|
|
401
|
+
|
|
393
402
|
# mock these so that we can control what objects were returned to check later
|
|
394
403
|
mock_fetch_jira_objects.return_value = MagicMock()
|
|
395
404
|
mock_get_regscale_data_and_attachments.return_value = (MagicMock(), MagicMock())
|
|
@@ -415,7 +424,7 @@ class TestJira(CLITestFixture):
|
|
|
415
424
|
mock_fetch_jira_objects.assert_called_once_with(
|
|
416
425
|
jira_client=mock_jira_client,
|
|
417
426
|
jira_project=self.JIRA_PROJECT,
|
|
418
|
-
jql_str="project = SNES",
|
|
427
|
+
jql_str="project = 'SNES'",
|
|
419
428
|
jira_issue_type="Bug",
|
|
420
429
|
sync_tasks_only=False,
|
|
421
430
|
)
|
|
@@ -429,6 +438,7 @@ class TestJira(CLITestFixture):
|
|
|
429
438
|
api=mock_api.return_value,
|
|
430
439
|
sync_attachments=fetch_attachments,
|
|
431
440
|
attachments=mock_get_regscale_data_and_attachments.return_value[1],
|
|
441
|
+
custom_fields={},
|
|
432
442
|
)
|
|
433
443
|
mock_sync_regscale_objects_to_jira.assert_called_once_with(
|
|
434
444
|
mock_fetch_jira_objects.return_value,
|
|
@@ -438,6 +448,7 @@ class TestJira(CLITestFixture):
|
|
|
438
448
|
self.PARENT_ID,
|
|
439
449
|
self.PARENT_MODULE,
|
|
440
450
|
False,
|
|
451
|
+
False,
|
|
441
452
|
)
|
|
442
453
|
|
|
443
454
|
@patch(f"{PATH}.sync_regscale_objects_to_jira")
|
|
@@ -606,14 +617,12 @@ class TestJira(CLITestFixture):
|
|
|
606
617
|
mock_create_and_update_regscale_issues.assert_not_called()
|
|
607
618
|
|
|
608
619
|
@patch(f"{PATH}.create_jira_client")
|
|
609
|
-
@patch(f"{PATH}.create_threads")
|
|
610
620
|
@patch(f"{PATH}.create_and_update_regscale_tasks")
|
|
611
621
|
@patch(f"{PATH}.check_license", return_value=MagicMock(spec=Application))
|
|
612
622
|
def test_sync_regscale_objects_to_jira_all(
|
|
613
623
|
self,
|
|
614
624
|
mock_check_license,
|
|
615
625
|
mock_create_and_update_regscale_tasks,
|
|
616
|
-
mock_create_threads,
|
|
617
626
|
mock_create_jira_client,
|
|
618
627
|
fetch_attachments,
|
|
619
628
|
):
|
|
@@ -622,18 +631,29 @@ class TestJira(CLITestFixture):
|
|
|
622
631
|
mock_jira_client = MagicMock()
|
|
623
632
|
mock_create_jira_client.return_value = mock_jira_client
|
|
624
633
|
|
|
634
|
+
# Create mock application with ThreadManager
|
|
635
|
+
mock_app = MagicMock(spec=Application)
|
|
636
|
+
mock_app.config = self.config
|
|
637
|
+
mock_thread_manager = MagicMock()
|
|
638
|
+
mock_app.thread_manager = mock_thread_manager
|
|
639
|
+
|
|
640
|
+
# Mock Jira issues
|
|
641
|
+
mock_jira_issues = [MagicMock(), MagicMock()]
|
|
642
|
+
|
|
625
643
|
sync_regscale_objects_to_jira(
|
|
626
|
-
|
|
644
|
+
mock_jira_issues,
|
|
627
645
|
MagicMock(),
|
|
628
646
|
fetch_attachments,
|
|
629
|
-
|
|
647
|
+
mock_app,
|
|
630
648
|
self.PARENT_ID,
|
|
631
649
|
self.PARENT_MODULE,
|
|
632
650
|
False,
|
|
633
651
|
)
|
|
634
652
|
|
|
635
653
|
mock_create_and_update_regscale_tasks.assert_not_called()
|
|
636
|
-
|
|
654
|
+
# Verify ThreadManager methods were called
|
|
655
|
+
mock_thread_manager.submit_tasks_from_list.assert_called_once()
|
|
656
|
+
mock_thread_manager.execute_and_verify.assert_called_once()
|
|
637
657
|
|
|
638
658
|
@patch(f"{PATH}.JIRA")
|
|
639
659
|
def test_create_jira_client_basic(self, mock_jira):
|
|
@@ -1159,14 +1179,14 @@ class TestJira(CLITestFixture):
|
|
|
1159
1179
|
mock_compare_files_for_dupes_and_upload.assert_called_once()
|
|
1160
1180
|
|
|
1161
1181
|
@patch(f"{PATH}.compare_files_for_dupes_and_upload")
|
|
1162
|
-
@patch(f"{PATH}.
|
|
1163
|
-
@patch(f"{PATH}.Issue.
|
|
1182
|
+
@patch(f"{PATH}.map_jira_to_regscale_issue")
|
|
1183
|
+
@patch(f"{PATH}.Issue.save")
|
|
1164
1184
|
@patch(f"{PATH}.job_progress", return_value=MagicMock(spec=Progress))
|
|
1165
1185
|
def test_create_and_update_regscale_issues(
|
|
1166
1186
|
self,
|
|
1167
1187
|
mock_job_progress_object,
|
|
1168
1188
|
mock_update_issue,
|
|
1169
|
-
|
|
1189
|
+
mock_map_jira_to_regscale_issue,
|
|
1170
1190
|
mock_compare_files_for_dupes_and_upload,
|
|
1171
1191
|
fetch_attachments,
|
|
1172
1192
|
):
|
|
@@ -1190,60 +1210,58 @@ class TestJira(CLITestFixture):
|
|
|
1190
1210
|
lowest_priority.name = "lowest"
|
|
1191
1211
|
|
|
1192
1212
|
# Create mock Jira issues
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
attachment=MagicMock(),
|
|
1204
|
-
),
|
|
1213
|
+
jira_issue_1 = MagicMock( # should be updated (existing issue)
|
|
1214
|
+
key="JIRA-1",
|
|
1215
|
+
fields=MagicMock(
|
|
1216
|
+
summary="Skipped issue",
|
|
1217
|
+
description="Skipped issue description",
|
|
1218
|
+
status=open_status,
|
|
1219
|
+
duedate=None,
|
|
1220
|
+
priority=highest_priority,
|
|
1221
|
+
statuscategorychangedate="2025-06-12T12:46:34.755961+0000",
|
|
1222
|
+
attachment=[MagicMock()], # Has attachments
|
|
1205
1223
|
),
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1224
|
+
)
|
|
1225
|
+
jira_issue_2 = MagicMock( # should be inserted (issue in jira but not regscale)
|
|
1226
|
+
key="JIRA-2",
|
|
1227
|
+
fields=MagicMock(
|
|
1228
|
+
summary="New issue",
|
|
1229
|
+
description="New issue description",
|
|
1230
|
+
status=open_status,
|
|
1231
|
+
duedate=None,
|
|
1232
|
+
priority=medium_priority,
|
|
1233
|
+
statuscategorychangedate="2025-06-12T12:46:34.755961+0000",
|
|
1234
|
+
attachment=None,
|
|
1217
1235
|
),
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1236
|
+
)
|
|
1237
|
+
jira_issue_3 = MagicMock( # should be updated (issue in both but out of sync)
|
|
1238
|
+
key="JIRA-3",
|
|
1239
|
+
fields=MagicMock(
|
|
1240
|
+
summary="Existing issue",
|
|
1241
|
+
description="Existing issue description",
|
|
1242
|
+
status=in_progress_status,
|
|
1243
|
+
duedate=None,
|
|
1244
|
+
priority=low_priority,
|
|
1245
|
+
statuscategorychangedate="2025-06-12T12:46:34.755961+0000",
|
|
1246
|
+
attachment=None, # No attachments
|
|
1229
1247
|
),
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1248
|
+
)
|
|
1249
|
+
jira_issue_4 = MagicMock( # should be closed - counts as updated
|
|
1250
|
+
key="JIRA-4",
|
|
1251
|
+
fields=MagicMock(
|
|
1252
|
+
summary="Existing issue",
|
|
1253
|
+
description="Existing issue description",
|
|
1254
|
+
status=closed_status,
|
|
1255
|
+
duedate=None,
|
|
1256
|
+
priority=lowest_priority,
|
|
1257
|
+
statuscategorychangedate="2025-06-12T12:46:34.755961+0000",
|
|
1258
|
+
attachment=None, # No attachments
|
|
1241
1259
|
),
|
|
1242
|
-
|
|
1260
|
+
)
|
|
1243
1261
|
|
|
1244
1262
|
# Create RegScale issues
|
|
1245
1263
|
regscale_issues = [
|
|
1246
|
-
Issue( # matches JIRA-1 (should be
|
|
1264
|
+
Issue( # matches JIRA-1 (should be updated)
|
|
1247
1265
|
id=1,
|
|
1248
1266
|
title="Skipped issue",
|
|
1249
1267
|
status="Open",
|
|
@@ -1252,6 +1270,7 @@ class TestJira(CLITestFixture):
|
|
|
1252
1270
|
parentId=self.PARENT_ID,
|
|
1253
1271
|
parentModule=self.PARENT_MODULE,
|
|
1254
1272
|
dueDate=get_current_datetime(),
|
|
1273
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1255
1274
|
),
|
|
1256
1275
|
Issue( # matches JIRA-3 (should be updated - issue in both but out of sync)
|
|
1257
1276
|
id=3,
|
|
@@ -1262,6 +1281,7 @@ class TestJira(CLITestFixture):
|
|
|
1262
1281
|
parentId=self.PARENT_ID,
|
|
1263
1282
|
parentModule=self.PARENT_MODULE,
|
|
1264
1283
|
dueDate=get_current_datetime(),
|
|
1284
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1265
1285
|
),
|
|
1266
1286
|
Issue( # matches JIRA-4 (should be closed - jira closed but regscale open)
|
|
1267
1287
|
id=4,
|
|
@@ -1272,32 +1292,41 @@ class TestJira(CLITestFixture):
|
|
|
1272
1292
|
parentId=self.PARENT_ID,
|
|
1273
1293
|
parentModule=self.PARENT_MODULE,
|
|
1274
1294
|
dueDate=get_current_datetime(),
|
|
1295
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1275
1296
|
),
|
|
1276
1297
|
]
|
|
1277
1298
|
|
|
1278
1299
|
# Create mock config with priority mappings from init.yaml
|
|
1279
1300
|
config = {
|
|
1280
1301
|
"issues": {"jira": {"highest": 7, "high": 30, "medium": 90, "low": 180, "lowest": 365, "status": "Open"}},
|
|
1281
|
-
"maxThreads": 4,
|
|
1282
|
-
"userId": "123e4567-e89b-12d3-a456-426614174000",
|
|
1302
|
+
"maxThreads": 4,
|
|
1303
|
+
"userId": "123e4567-e89b-12d3-a456-426614174000",
|
|
1283
1304
|
}
|
|
1284
1305
|
app = MagicMock()
|
|
1285
1306
|
app.config = config
|
|
1286
1307
|
|
|
1287
1308
|
# Setup mock return values
|
|
1288
1309
|
mock_update_issue.return_value = MagicMock()
|
|
1289
|
-
|
|
1310
|
+
|
|
1311
|
+
# Mock the creation of a new issue
|
|
1312
|
+
created_issue_mock = MagicMock()
|
|
1313
|
+
created_issue_mock.id = 2
|
|
1314
|
+
created_issue_mock.create.return_value = created_issue_mock
|
|
1315
|
+
mock_map_jira_to_regscale_issue.return_value = created_issue_mock
|
|
1290
1316
|
|
|
1291
1317
|
with mock_job_progress_object as job_progress:
|
|
1292
1318
|
test_task = job_progress.add_task(
|
|
1293
1319
|
description="Processing issues",
|
|
1294
|
-
total=
|
|
1320
|
+
total=4,
|
|
1295
1321
|
visible=False,
|
|
1296
1322
|
)
|
|
1297
1323
|
|
|
1298
|
-
|
|
1299
|
-
|
|
1324
|
+
# Test the function with each Jira issue individually (as ThreadManager would call it)
|
|
1325
|
+
# JIRA-1: existing issue with matching jiraId and attachments
|
|
1326
|
+
create_and_update_regscale_issues(
|
|
1327
|
+
jira_issue_1,
|
|
1300
1328
|
regscale_issues,
|
|
1329
|
+
False,
|
|
1301
1330
|
fetch_attachments,
|
|
1302
1331
|
MagicMock(),
|
|
1303
1332
|
app,
|
|
@@ -1307,17 +1336,56 @@ class TestJira(CLITestFixture):
|
|
|
1307
1336
|
job_progress,
|
|
1308
1337
|
)
|
|
1309
1338
|
|
|
1310
|
-
#
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1339
|
+
# JIRA-2: new issue (not in regscale_issues)
|
|
1340
|
+
create_and_update_regscale_issues(
|
|
1341
|
+
jira_issue_2,
|
|
1342
|
+
regscale_issues,
|
|
1343
|
+
False,
|
|
1344
|
+
fetch_attachments,
|
|
1345
|
+
MagicMock(),
|
|
1346
|
+
app,
|
|
1347
|
+
self.PARENT_ID,
|
|
1348
|
+
self.PARENT_MODULE,
|
|
1349
|
+
test_task,
|
|
1350
|
+
job_progress,
|
|
1351
|
+
)
|
|
1316
1352
|
|
|
1317
|
-
|
|
1318
|
-
|
|
1353
|
+
# JIRA-3: existing issue to be updated
|
|
1354
|
+
create_and_update_regscale_issues(
|
|
1355
|
+
jira_issue_3,
|
|
1356
|
+
regscale_issues,
|
|
1357
|
+
False,
|
|
1358
|
+
fetch_attachments,
|
|
1359
|
+
MagicMock(),
|
|
1360
|
+
app,
|
|
1361
|
+
self.PARENT_ID,
|
|
1362
|
+
self.PARENT_MODULE,
|
|
1363
|
+
test_task,
|
|
1364
|
+
job_progress,
|
|
1365
|
+
)
|
|
1366
|
+
|
|
1367
|
+
# JIRA-4: existing issue to be closed
|
|
1368
|
+
create_and_update_regscale_issues(
|
|
1369
|
+
jira_issue_4,
|
|
1370
|
+
regscale_issues,
|
|
1371
|
+
False,
|
|
1372
|
+
fetch_attachments,
|
|
1373
|
+
MagicMock(),
|
|
1374
|
+
app,
|
|
1375
|
+
self.PARENT_ID,
|
|
1376
|
+
self.PARENT_MODULE,
|
|
1377
|
+
test_task,
|
|
1378
|
+
job_progress,
|
|
1379
|
+
)
|
|
1380
|
+
|
|
1381
|
+
# Verify update_issue was called 3 times (JIRA-1, JIRA-3, JIRA-4)
|
|
1382
|
+
assert mock_update_issue.call_count == 3
|
|
1383
|
+
# Verify map_jira_to_regscale_issue was called once for JIRA-2 (new issue)
|
|
1384
|
+
assert mock_map_jira_to_regscale_issue.call_count == 1
|
|
1385
|
+
# Verify attachment handling
|
|
1319
1386
|
if fetch_attachments:
|
|
1320
|
-
|
|
1387
|
+
# Only JIRA-1 has attachments in fields.attachment
|
|
1388
|
+
assert mock_compare_files_for_dupes_and_upload.call_count == 1
|
|
1321
1389
|
else:
|
|
1322
1390
|
assert mock_compare_files_for_dupes_and_upload.call_count == 0
|
|
1323
1391
|
|
|
@@ -1335,6 +1403,7 @@ class TestJira(CLITestFixture):
|
|
|
1335
1403
|
dueDate=get_current_datetime(),
|
|
1336
1404
|
parentId=self.PARENT_ID,
|
|
1337
1405
|
parentModule=self.PARENT_MODULE,
|
|
1406
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1338
1407
|
),
|
|
1339
1408
|
Issue(
|
|
1340
1409
|
id=3,
|
|
@@ -1345,6 +1414,7 @@ class TestJira(CLITestFixture):
|
|
|
1345
1414
|
parentId=self.PARENT_ID,
|
|
1346
1415
|
parentModule=self.PARENT_MODULE,
|
|
1347
1416
|
jiraId="JIRA-3",
|
|
1417
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1348
1418
|
),
|
|
1349
1419
|
]
|
|
1350
1420
|
|
|
@@ -1459,6 +1529,7 @@ class TestJira(CLITestFixture):
|
|
|
1459
1529
|
jiraId="JIRA-123",
|
|
1460
1530
|
severityLevel="High",
|
|
1461
1531
|
dueDate="2023-12-31",
|
|
1532
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1462
1533
|
)
|
|
1463
1534
|
|
|
1464
1535
|
comment = _generate_jira_comment(issue)
|
|
@@ -1493,6 +1564,7 @@ class TestJira(CLITestFixture):
|
|
|
1493
1564
|
otherIdentifier="JIRA-123",
|
|
1494
1565
|
percentComplete=50,
|
|
1495
1566
|
dueDate="2023-12-31",
|
|
1567
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1496
1568
|
)
|
|
1497
1569
|
|
|
1498
1570
|
comment = _generate_jira_comment(task)
|
|
@@ -1596,6 +1668,7 @@ class TestJira(CLITestFixture):
|
|
|
1596
1668
|
description="Test Description",
|
|
1597
1669
|
parentId=self.PARENT_ID,
|
|
1598
1670
|
parentModule=self.PARENT_MODULE,
|
|
1671
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1599
1672
|
)
|
|
1600
1673
|
|
|
1601
1674
|
# setup file hashes for upload
|
|
@@ -1671,6 +1744,7 @@ class TestJira(CLITestFixture):
|
|
|
1671
1744
|
parentModule=self.PARENT_MODULE,
|
|
1672
1745
|
dueDate=get_current_datetime(),
|
|
1673
1746
|
status="Open",
|
|
1747
|
+
identification=f"{self.title_prefix} Jira Issue Integration Test",
|
|
1674
1748
|
)
|
|
1675
1749
|
reg_issue = tmp.create()
|
|
1676
1750
|
|
|
@@ -1782,29 +1856,345 @@ class TestJira(CLITestFixture):
|
|
|
1782
1856
|
)
|
|
1783
1857
|
assert os.path.exists(tmpdir) is True
|
|
1784
1858
|
|
|
1859
|
+
@patch(f"{PATH}.sync_regscale_objects_to_jira")
|
|
1860
|
+
@patch(f"{PATH}.sync_regscale_to_jira", return_value=[])
|
|
1861
|
+
@patch(f"{PATH}.create_jira_client")
|
|
1862
|
+
@patch(f"{PATH}.fetch_jira_objects")
|
|
1863
|
+
@patch(f"{PATH}.get_regscale_data_and_attachments")
|
|
1864
|
+
@patch(f"{PATH}.Api", return_value=MagicMock(spec=Api))
|
|
1865
|
+
@patch(f"{PATH}.check_license", return_value=MagicMock(spec=Application))
|
|
1866
|
+
def test_sync_regscale_and_jira_with_poams_true(
|
|
1867
|
+
self,
|
|
1868
|
+
mock_check_license,
|
|
1869
|
+
mock_api,
|
|
1870
|
+
mock_get_regscale_data_and_attachments,
|
|
1871
|
+
mock_fetch_jira_objects,
|
|
1872
|
+
mock_create_jira_client,
|
|
1873
|
+
mock_sync_regscale_to_jira,
|
|
1874
|
+
mock_sync_regscale_objects_to_jira,
|
|
1875
|
+
fetch_attachments,
|
|
1876
|
+
):
|
|
1877
|
+
"""Test sync_regscale_and_jira with use_poams=True"""
|
|
1878
|
+
# Setup mocks
|
|
1879
|
+
mock_jira_client = MagicMock()
|
|
1880
|
+
mock_create_jira_client.return_value = mock_jira_client
|
|
1881
|
+
mock_fetch_jira_objects.return_value = [MagicMock()]
|
|
1882
|
+
mock_get_regscale_data_and_attachments.return_value = ([MagicMock()], MagicMock())
|
|
1883
|
+
|
|
1884
|
+
# Call function with use_poams=True
|
|
1885
|
+
sync_regscale_and_jira(
|
|
1886
|
+
parent_id=self.PARENT_ID,
|
|
1887
|
+
parent_module=self.PARENT_MODULE,
|
|
1888
|
+
jira_project=self.JIRA_PROJECT,
|
|
1889
|
+
jira_issue_type="Bug",
|
|
1890
|
+
sync_attachments=fetch_attachments,
|
|
1891
|
+
use_poams=True,
|
|
1892
|
+
)
|
|
1893
|
+
|
|
1894
|
+
# Verify sync_regscale_objects_to_jira was called with use_poams=True
|
|
1895
|
+
mock_sync_regscale_objects_to_jira.assert_called_once()
|
|
1896
|
+
call_args = mock_sync_regscale_objects_to_jira.call_args
|
|
1897
|
+
assert call_args[0][7] is True # use_poams is the 8th positional argument
|
|
1898
|
+
|
|
1899
|
+
@patch(f"{PATH}.sync_regscale_objects_to_jira")
|
|
1900
|
+
@patch(f"{PATH}.sync_regscale_to_jira", return_value=[])
|
|
1901
|
+
@patch(f"{PATH}.create_jira_client")
|
|
1902
|
+
@patch(f"{PATH}.fetch_jira_objects")
|
|
1903
|
+
@patch(f"{PATH}.get_regscale_data_and_attachments")
|
|
1904
|
+
@patch(f"{PATH}.Api", return_value=MagicMock(spec=Api))
|
|
1905
|
+
@patch(f"{PATH}.check_license", return_value=MagicMock(spec=Application))
|
|
1906
|
+
def test_sync_regscale_and_jira_with_poams_false(
|
|
1907
|
+
self,
|
|
1908
|
+
mock_check_license,
|
|
1909
|
+
mock_api,
|
|
1910
|
+
mock_get_regscale_data_and_attachments,
|
|
1911
|
+
mock_fetch_jira_objects,
|
|
1912
|
+
mock_create_jira_client,
|
|
1913
|
+
mock_sync_regscale_to_jira,
|
|
1914
|
+
mock_sync_regscale_objects_to_jira,
|
|
1915
|
+
fetch_attachments,
|
|
1916
|
+
):
|
|
1917
|
+
"""Test sync_regscale_and_jira with use_poams=False (default)"""
|
|
1918
|
+
# Setup mocks
|
|
1919
|
+
mock_jira_client = MagicMock()
|
|
1920
|
+
mock_create_jira_client.return_value = mock_jira_client
|
|
1921
|
+
mock_fetch_jira_objects.return_value = [MagicMock()]
|
|
1922
|
+
mock_get_regscale_data_and_attachments.return_value = ([MagicMock()], MagicMock())
|
|
1923
|
+
|
|
1924
|
+
# Call function with use_poams=False (default)
|
|
1925
|
+
sync_regscale_and_jira(
|
|
1926
|
+
parent_id=self.PARENT_ID,
|
|
1927
|
+
parent_module=self.PARENT_MODULE,
|
|
1928
|
+
jira_project=self.JIRA_PROJECT,
|
|
1929
|
+
jira_issue_type="Bug",
|
|
1930
|
+
sync_attachments=fetch_attachments,
|
|
1931
|
+
use_poams=False,
|
|
1932
|
+
)
|
|
1933
|
+
|
|
1934
|
+
# Verify sync_regscale_objects_to_jira was called with use_poams=False
|
|
1935
|
+
mock_sync_regscale_objects_to_jira.assert_called_once()
|
|
1936
|
+
call_args = mock_sync_regscale_objects_to_jira.call_args
|
|
1937
|
+
assert call_args[0][7] is False # use_poams is the 8th positional argument
|
|
1938
|
+
|
|
1939
|
+
@patch(f"{PATH}.create_jira_client")
|
|
1940
|
+
@patch(f"{PATH}.create_and_update_regscale_issues")
|
|
1941
|
+
@patch(f"{PATH}.check_license", return_value=MagicMock(spec=Application))
|
|
1942
|
+
def test_sync_regscale_objects_to_jira_with_poams(
|
|
1943
|
+
self,
|
|
1944
|
+
mock_check_license,
|
|
1945
|
+
mock_create_and_update_regscale_issues,
|
|
1946
|
+
mock_create_jira_client,
|
|
1947
|
+
fetch_attachments,
|
|
1948
|
+
):
|
|
1949
|
+
"""Test sync_regscale_objects_to_jira passes use_poams to create_and_update_regscale_issues"""
|
|
1950
|
+
mock_check_license.return_value.config = self.config
|
|
1951
|
+
mock_jira_client = MagicMock()
|
|
1952
|
+
mock_create_jira_client.return_value = mock_jira_client
|
|
1953
|
+
|
|
1954
|
+
# Create mock application with ThreadManager
|
|
1955
|
+
mock_app = MagicMock(spec=Application)
|
|
1956
|
+
mock_app.config = self.config
|
|
1957
|
+
mock_thread_manager = MagicMock()
|
|
1958
|
+
mock_app.thread_manager = mock_thread_manager
|
|
1959
|
+
|
|
1960
|
+
# Mock Jira issues
|
|
1961
|
+
mock_jira_issues = [MagicMock(), MagicMock()]
|
|
1962
|
+
mock_regscale_objects = [MagicMock()]
|
|
1963
|
+
|
|
1964
|
+
# Test with use_poams=True
|
|
1965
|
+
sync_regscale_objects_to_jira(
|
|
1966
|
+
mock_jira_issues,
|
|
1967
|
+
mock_regscale_objects,
|
|
1968
|
+
fetch_attachments,
|
|
1969
|
+
mock_app,
|
|
1970
|
+
self.PARENT_ID,
|
|
1971
|
+
self.PARENT_MODULE,
|
|
1972
|
+
False, # sync_tasks_only
|
|
1973
|
+
True, # use_poams
|
|
1974
|
+
)
|
|
1975
|
+
|
|
1976
|
+
# Verify ThreadManager was called with correct parameters
|
|
1977
|
+
mock_thread_manager.submit_tasks_from_list.assert_called_once()
|
|
1978
|
+
call_args = mock_thread_manager.submit_tasks_from_list.call_args[0]
|
|
1979
|
+
# use_poams is the 4th argument (index 3) after function, jira_issues, and regscale_objects
|
|
1980
|
+
assert call_args[3] is True
|
|
1981
|
+
|
|
1982
|
+
@patch(f"{PATH}.map_jira_to_regscale_issue")
|
|
1983
|
+
def test_map_jira_to_regscale_issue_with_poam_true(self, mock_map_jira_to_regscale_issue):
|
|
1984
|
+
"""Test map_jira_to_regscale_issue sets isPoam=True when is_poam=True"""
|
|
1985
|
+
# Create mock Jira issue
|
|
1986
|
+
mock_issue = MagicMock()
|
|
1987
|
+
mock_issue.fields.summary = "Test Issue"
|
|
1988
|
+
mock_issue.fields.description = "Test Description"
|
|
1989
|
+
mock_issue.fields.status.name = "Open"
|
|
1990
|
+
mock_issue.fields.priority.name = "High"
|
|
1991
|
+
mock_issue.fields.duedate = None
|
|
1992
|
+
mock_issue.key = "TEST-123"
|
|
1993
|
+
|
|
1994
|
+
# Create mock config
|
|
1995
|
+
mock_config = {
|
|
1996
|
+
"userId": "1",
|
|
1997
|
+
"issues": {"jira": {"status": "Open", "high": 7, "medium": 14, "low": 30}},
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
# Call the actual function with is_poam=True
|
|
2001
|
+
result = map_jira_to_regscale_issue(
|
|
2002
|
+
jira_issue=mock_issue,
|
|
2003
|
+
config=mock_config,
|
|
2004
|
+
parent_id=self.PARENT_ID,
|
|
2005
|
+
parent_module=self.PARENT_MODULE,
|
|
2006
|
+
is_poam=True,
|
|
2007
|
+
)
|
|
2008
|
+
|
|
2009
|
+
# Verify the Issue object was created with isPoam=True
|
|
2010
|
+
assert isinstance(result, Issue)
|
|
2011
|
+
assert result.isPoam is True
|
|
2012
|
+
assert result.title == "Test Issue"
|
|
2013
|
+
assert result.jiraId == "TEST-123"
|
|
2014
|
+
|
|
2015
|
+
@patch(f"{PATH}.map_jira_to_regscale_issue")
|
|
2016
|
+
def test_map_jira_to_regscale_issue_with_poam_false(self, mock_map_jira_to_regscale_issue):
|
|
2017
|
+
"""Test map_jira_to_regscale_issue sets isPoam=False when is_poam=False"""
|
|
2018
|
+
# Create mock Jira issue
|
|
2019
|
+
mock_issue = MagicMock()
|
|
2020
|
+
mock_issue.fields.summary = "Test Issue"
|
|
2021
|
+
mock_issue.fields.description = "Test Description"
|
|
2022
|
+
mock_issue.fields.status.name = "Open"
|
|
2023
|
+
mock_issue.fields.priority.name = "High"
|
|
2024
|
+
mock_issue.fields.duedate = None
|
|
2025
|
+
mock_issue.key = "TEST-123"
|
|
2026
|
+
|
|
2027
|
+
# Create mock config
|
|
2028
|
+
mock_config = {
|
|
2029
|
+
"userId": "1",
|
|
2030
|
+
"issues": {"jira": {"status": "Open", "high": 7, "medium": 14, "low": 30}},
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
# Call the actual function with is_poam=False
|
|
2034
|
+
result = map_jira_to_regscale_issue(
|
|
2035
|
+
jira_issue=mock_issue,
|
|
2036
|
+
config=mock_config,
|
|
2037
|
+
parent_id=self.PARENT_ID,
|
|
2038
|
+
parent_module=self.PARENT_MODULE,
|
|
2039
|
+
is_poam=False,
|
|
2040
|
+
)
|
|
2041
|
+
|
|
2042
|
+
# Verify the Issue object was created with isPoam=False
|
|
2043
|
+
assert isinstance(result, Issue)
|
|
2044
|
+
assert result.isPoam is False
|
|
2045
|
+
assert result.title == "Test Issue"
|
|
2046
|
+
assert result.jiraId == "TEST-123"
|
|
2047
|
+
|
|
2048
|
+
@patch(f"{PATH}.compare_files_for_dupes_and_upload")
|
|
2049
|
+
@patch(f"{PATH}.map_jira_to_regscale_issue")
|
|
2050
|
+
@patch(f"{PATH}.Issue.update_issue")
|
|
2051
|
+
@patch(f"{PATH}.job_progress", return_value=MagicMock(spec=Progress))
|
|
2052
|
+
def test_create_and_update_regscale_issues_sets_ispoam_on_new_issue(
|
|
2053
|
+
self,
|
|
2054
|
+
mock_job_progress_object,
|
|
2055
|
+
mock_update_issue,
|
|
2056
|
+
mock_map_jira_to_regscale_issue,
|
|
2057
|
+
mock_compare_files_for_dupes_and_upload,
|
|
2058
|
+
):
|
|
2059
|
+
"""Test that create_and_update_regscale_issues sets isPoam on newly created issues"""
|
|
2060
|
+
# Create mock Jira issue
|
|
2061
|
+
open_status = MagicMock()
|
|
2062
|
+
open_status.name = "open"
|
|
2063
|
+
high_priority = MagicMock()
|
|
2064
|
+
high_priority.name = "high"
|
|
2065
|
+
|
|
2066
|
+
jira_issue = MagicMock(
|
|
2067
|
+
key="JIRA-NEW",
|
|
2068
|
+
fields=MagicMock(
|
|
2069
|
+
summary="New Issue",
|
|
2070
|
+
description="New issue description",
|
|
2071
|
+
status=open_status,
|
|
2072
|
+
duedate=None,
|
|
2073
|
+
priority=high_priority,
|
|
2074
|
+
statuscategorychangedate="2025-06-12T12:46:34.755961+0000",
|
|
2075
|
+
attachment=None,
|
|
2076
|
+
),
|
|
2077
|
+
)
|
|
2078
|
+
|
|
2079
|
+
# Create empty RegScale issues list (no existing issues)
|
|
2080
|
+
regscale_issues = []
|
|
2081
|
+
|
|
2082
|
+
# Create mock config
|
|
2083
|
+
config = {
|
|
2084
|
+
"issues": {"jira": {"highest": 7, "high": 30, "medium": 90, "low": 180, "lowest": 365, "status": "Open"}},
|
|
2085
|
+
"maxThreads": 4,
|
|
2086
|
+
"userId": "123e4567-e89b-12d3-a456-426614174000",
|
|
2087
|
+
}
|
|
2088
|
+
app = MagicMock()
|
|
2089
|
+
app.config = config
|
|
2090
|
+
|
|
2091
|
+
# Mock the creation of a new issue
|
|
2092
|
+
created_issue_mock = MagicMock()
|
|
2093
|
+
created_issue_mock.id = 999
|
|
2094
|
+
created_issue_mock.create.return_value = created_issue_mock
|
|
2095
|
+
mock_map_jira_to_regscale_issue.return_value = created_issue_mock
|
|
2096
|
+
|
|
2097
|
+
with mock_job_progress_object as job_progress:
|
|
2098
|
+
test_task = job_progress.add_task(
|
|
2099
|
+
description="Processing issues",
|
|
2100
|
+
total=1,
|
|
2101
|
+
visible=False,
|
|
2102
|
+
)
|
|
2103
|
+
|
|
2104
|
+
# Call with use_poams=True
|
|
2105
|
+
create_and_update_regscale_issues(
|
|
2106
|
+
jira_issue,
|
|
2107
|
+
regscale_issues,
|
|
2108
|
+
True, # use_poams
|
|
2109
|
+
False, # add_attachments
|
|
2110
|
+
MagicMock(),
|
|
2111
|
+
app,
|
|
2112
|
+
self.PARENT_ID,
|
|
2113
|
+
self.PARENT_MODULE,
|
|
2114
|
+
test_task,
|
|
2115
|
+
job_progress,
|
|
2116
|
+
)
|
|
2117
|
+
|
|
2118
|
+
# Verify map_jira_to_regscale_issue was called with is_poam=True
|
|
2119
|
+
mock_map_jira_to_regscale_issue.assert_called_once()
|
|
2120
|
+
call_kwargs = mock_map_jira_to_regscale_issue.call_args[1]
|
|
2121
|
+
assert call_kwargs["is_poam"] is True
|
|
2122
|
+
|
|
2123
|
+
@patch(f"{PATH}.compare_files_for_dupes_and_upload")
|
|
2124
|
+
@patch(f"{PATH}.map_jira_to_regscale_issue")
|
|
2125
|
+
@patch(f"{PATH}.Issue.save")
|
|
1785
2126
|
@patch(f"{PATH}.job_progress", return_value=MagicMock(spec=Progress))
|
|
1786
|
-
def
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
2127
|
+
def test_create_and_update_regscale_issues_sets_ispoam_on_existing_issue(
|
|
2128
|
+
self,
|
|
2129
|
+
mock_job_progress_object,
|
|
2130
|
+
mock_save,
|
|
2131
|
+
mock_map_jira_to_regscale_issue,
|
|
2132
|
+
mock_compare_files_for_dupes_and_upload,
|
|
2133
|
+
):
|
|
2134
|
+
"""Test that create_and_update_regscale_issues sets isPoam on existing issues"""
|
|
2135
|
+
# Create mock Jira issue
|
|
2136
|
+
open_status = MagicMock()
|
|
2137
|
+
open_status.name = "open"
|
|
2138
|
+
high_priority = MagicMock()
|
|
2139
|
+
high_priority.name = "high"
|
|
2140
|
+
|
|
2141
|
+
jira_issue = MagicMock(
|
|
2142
|
+
key="JIRA-1",
|
|
2143
|
+
fields=MagicMock(
|
|
2144
|
+
summary="Existing Issue",
|
|
2145
|
+
description="Existing issue description",
|
|
2146
|
+
status=open_status,
|
|
2147
|
+
duedate=None,
|
|
2148
|
+
priority=high_priority,
|
|
2149
|
+
statuscategorychangedate="2025-06-12T12:46:34.755961+0000",
|
|
2150
|
+
attachment=None,
|
|
2151
|
+
),
|
|
2152
|
+
)
|
|
2153
|
+
|
|
2154
|
+
# Create existing RegScale issue (using MagicMock to avoid actual creation)
|
|
2155
|
+
existing_issue = MagicMock(spec=Issue)
|
|
2156
|
+
existing_issue.jiraId = "JIRA-1"
|
|
2157
|
+
existing_issue.isPoam = False # Initially not a POAM
|
|
2158
|
+
existing_issue.id = 1
|
|
2159
|
+
existing_issue.title = "Existing Issue"
|
|
2160
|
+
regscale_issues = [existing_issue]
|
|
2161
|
+
|
|
2162
|
+
# Create mock config
|
|
2163
|
+
config = {
|
|
2164
|
+
"issues": {"jira": {"highest": 7, "high": 30, "medium": 90, "low": 180, "lowest": 365, "status": "Open"}},
|
|
2165
|
+
"maxThreads": 4,
|
|
2166
|
+
"userId": "123e4567-e89b-12d3-a456-426614174000",
|
|
2167
|
+
"jiraCustomFields": {},
|
|
2168
|
+
}
|
|
2169
|
+
app = MagicMock()
|
|
2170
|
+
app.config = config
|
|
2171
|
+
|
|
2172
|
+
# Setup mock return values
|
|
2173
|
+
mock_save.return_value = MagicMock()
|
|
2174
|
+
|
|
1792
2175
|
with mock_job_progress_object as job_progress:
|
|
1793
2176
|
test_task = job_progress.add_task(
|
|
1794
|
-
description="
|
|
1795
|
-
total=
|
|
2177
|
+
description="Processing issues",
|
|
2178
|
+
total=1,
|
|
1796
2179
|
visible=False,
|
|
1797
2180
|
)
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
2181
|
+
|
|
2182
|
+
# Call with use_poams=True
|
|
2183
|
+
create_and_update_regscale_issues(
|
|
2184
|
+
jira_issue,
|
|
2185
|
+
regscale_issues,
|
|
2186
|
+
True, # use_poams
|
|
2187
|
+
False, # add_attachments
|
|
2188
|
+
MagicMock(),
|
|
2189
|
+
app,
|
|
2190
|
+
self.PARENT_ID,
|
|
2191
|
+
self.PARENT_MODULE,
|
|
2192
|
+
test_task,
|
|
2193
|
+
job_progress,
|
|
1801
2194
|
)
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
updated_issue = Issue.fetch_issue_by_id(app=self.app, issue_id=test_issue.id)
|
|
1806
|
-
assert updated_issue.assetIdentifier == test_issue.assetIdentifier
|
|
1807
|
-
assert updated_issue.lastUpdatedById == test_issue.lastUpdatedById
|
|
2195
|
+
|
|
2196
|
+
# Verify the existing issue had isPoam set to True
|
|
2197
|
+
assert existing_issue.isPoam is True
|
|
1808
2198
|
|
|
1809
2199
|
@staticmethod
|
|
1810
2200
|
def teardown_class(cls):
|