regscale-cli 6.20.1.1__py3-none-any.whl → 6.20.3.0__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/__init__.py +1 -1
- regscale/core/app/utils/variables.py +5 -3
- regscale/integrations/commercial/__init__.py +15 -0
- regscale/integrations/commercial/axonius/__init__.py +0 -0
- regscale/integrations/commercial/axonius/axonius_integration.py +70 -0
- regscale/integrations/commercial/burp.py +14 -0
- regscale/integrations/commercial/grype/commands.py +8 -1
- regscale/integrations/commercial/grype/scanner.py +2 -1
- regscale/integrations/commercial/jira.py +288 -137
- regscale/integrations/commercial/opentext/commands.py +14 -5
- regscale/integrations/commercial/opentext/scanner.py +3 -2
- regscale/integrations/commercial/qualys/__init__.py +3 -3
- regscale/integrations/commercial/stigv2/click_commands.py +6 -37
- regscale/integrations/commercial/synqly/assets.py +10 -0
- regscale/integrations/commercial/tenablev2/commands.py +12 -4
- regscale/integrations/commercial/tenablev2/sc_scanner.py +21 -1
- regscale/integrations/commercial/tenablev2/sync_compliance.py +3 -0
- regscale/integrations/commercial/trivy/commands.py +11 -4
- regscale/integrations/commercial/trivy/scanner.py +2 -1
- regscale/integrations/commercial/wizv2/constants.py +4 -0
- regscale/integrations/commercial/wizv2/scanner.py +67 -14
- regscale/integrations/commercial/wizv2/utils.py +24 -10
- regscale/integrations/commercial/wizv2/variables.py +7 -0
- regscale/integrations/jsonl_scanner_integration.py +8 -1
- regscale/integrations/public/cisa.py +58 -63
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +153 -104
- regscale/integrations/scanner_integration.py +30 -8
- regscale/integrations/variables.py +1 -0
- regscale/models/app_models/click.py +49 -1
- regscale/models/app_models/import_validater.py +3 -1
- regscale/models/integration_models/axonius_models/__init__.py +0 -0
- regscale/models/integration_models/axonius_models/connectors/__init__.py +3 -0
- regscale/models/integration_models/axonius_models/connectors/assets.py +111 -0
- regscale/models/integration_models/burp.py +11 -8
- regscale/models/integration_models/cisa_kev_data.json +204 -23
- regscale/models/integration_models/flat_file_importer/__init__.py +36 -176
- regscale/models/integration_models/jira_task_sync.py +27 -0
- regscale/models/integration_models/qualys.py +6 -7
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/regscale_models/__init__.py +2 -1
- regscale/models/regscale_models/control_implementation.py +39 -2
- regscale/models/regscale_models/issue.py +1 -0
- regscale/models/regscale_models/regscale_model.py +49 -1
- regscale/models/regscale_models/risk_issue_mapping.py +61 -0
- regscale/models/regscale_models/task.py +1 -0
- regscale/regscale.py +1 -4
- regscale/utils/graphql_client.py +4 -4
- regscale/utils/string.py +13 -0
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/RECORD +54 -48
- regscale/integrations/commercial/synqly_jira.py +0 -840
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/top_level.txt +0 -0
|
@@ -1,840 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Synqly Python SDK Ticketing Example
|
|
3
|
-
|
|
4
|
-
This example demonstrates how to use the Synqly Python SDK to create a
|
|
5
|
-
Ticketing Integration for a tenant.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
# Standard imports
|
|
9
|
-
import base64
|
|
10
|
-
import os
|
|
11
|
-
import tempfile
|
|
12
|
-
from datetime import datetime
|
|
13
|
-
from typing import Tuple, Optional
|
|
14
|
-
|
|
15
|
-
import click
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
from synqly import engine, management as mgmt
|
|
18
|
-
from synqly.engine import CreateTicketRequest
|
|
19
|
-
from synqly.engine.resources.ticketing.types.priority import Priority
|
|
20
|
-
from synqly.engine.resources.ticketing.types.ticket import Ticket
|
|
21
|
-
|
|
22
|
-
import regscale.utils.synqly_utils as utils
|
|
23
|
-
from regscale.core.app.api import Api
|
|
24
|
-
from regscale.core.app.application import Application
|
|
25
|
-
from regscale.core.app.utils.app_utils import (
|
|
26
|
-
create_progress_object,
|
|
27
|
-
create_logger,
|
|
28
|
-
get_current_datetime,
|
|
29
|
-
convert_datetime_to_regscale_string,
|
|
30
|
-
error_and_exit,
|
|
31
|
-
check_file_path,
|
|
32
|
-
compute_hashes_in_directory,
|
|
33
|
-
)
|
|
34
|
-
from regscale.utils.threading.threadhandler import create_threads, thread_assignment
|
|
35
|
-
from regscale.models import regscale_id, regscale_module, File
|
|
36
|
-
from regscale.models.regscale_models.issue import Issue
|
|
37
|
-
|
|
38
|
-
job_progress = create_progress_object()
|
|
39
|
-
logger = create_logger()
|
|
40
|
-
update_issues = []
|
|
41
|
-
new_regscale_issues = []
|
|
42
|
-
updated_regscale_issues = []
|
|
43
|
-
update_counter = []
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@click.group()
|
|
47
|
-
def synqly():
|
|
48
|
-
"""
|
|
49
|
-
Sync RegScale issues with Jira issues using Synqly
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def jira_provider_config(jira_url: str, jira_username: str, jira_token: str) -> mgmt.ProviderConfig_TicketingJira:
|
|
54
|
-
"""
|
|
55
|
-
Helper method to construct a JIRA ProviderConfig object.
|
|
56
|
-
|
|
57
|
-
:param str jira_url: JIRA URL
|
|
58
|
-
:param str jira_username: JIRA username
|
|
59
|
-
:param str jira_token: JIRA token
|
|
60
|
-
:return: JIRA ProviderConfig object
|
|
61
|
-
:rtype: mgmt.ProviderConfig_TicketingJira
|
|
62
|
-
"""
|
|
63
|
-
return mgmt.ProviderConfig_TicketingJira(
|
|
64
|
-
type="ticketing_jira",
|
|
65
|
-
url=jira_url,
|
|
66
|
-
credential=mgmt.JiraCredential_Basic(
|
|
67
|
-
type="basic",
|
|
68
|
-
username=jira_username,
|
|
69
|
-
secret=jira_token,
|
|
70
|
-
),
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def download_issue_attachments_to_directory(
|
|
75
|
-
directory: str,
|
|
76
|
-
synqly_issue: Ticket,
|
|
77
|
-
regscale_issue: Issue,
|
|
78
|
-
api: Api,
|
|
79
|
-
synqly_client: utils.Tenant,
|
|
80
|
-
) -> tuple[str, str]:
|
|
81
|
-
"""
|
|
82
|
-
Function to download attachments from Jira and RegScale issues to a directory
|
|
83
|
-
|
|
84
|
-
:param str directory: Directory to store the files in
|
|
85
|
-
:param Ticket synqly_issue: Synqly issue to download the attachments for
|
|
86
|
-
:param Issue regscale_issue: RegScale issue to download the attachments for
|
|
87
|
-
:param Api api: Api object to use for interacting with RegScale
|
|
88
|
-
:param utils.Tenant synqly_client: Synqly client to use for uploading attachments
|
|
89
|
-
:return: Tuple of strings containing the Jira and RegScale directories
|
|
90
|
-
:rtype: tuple[str, str]
|
|
91
|
-
"""
|
|
92
|
-
# determine which attachments need to be uploaded to prevent duplicates by checking hashes
|
|
93
|
-
jira_dir = os.path.join(directory, "jira")
|
|
94
|
-
check_file_path(jira_dir, False)
|
|
95
|
-
# download all attachments from Jira to the jira directory in temp_dir
|
|
96
|
-
download_synqly_attachments(tenant=synqly_client, ticket_id=synqly_issue.id, download_dir=jira_dir)
|
|
97
|
-
# get the regscale issue attachments
|
|
98
|
-
regscale_issue_attachments = File.get_files_for_parent_from_regscale(
|
|
99
|
-
api=api,
|
|
100
|
-
parent_id=regscale_issue.id,
|
|
101
|
-
parent_module="issues",
|
|
102
|
-
)
|
|
103
|
-
# create a directory for the regscale attachments
|
|
104
|
-
regscale_dir = os.path.join(directory, "regscale")
|
|
105
|
-
check_file_path(regscale_dir, False)
|
|
106
|
-
# download regscale attachments to the directory
|
|
107
|
-
for attachment in regscale_issue_attachments:
|
|
108
|
-
with open(os.path.join(regscale_dir, attachment.trustedDisplayName), "wb") as file:
|
|
109
|
-
file.write(
|
|
110
|
-
File.download_file_from_regscale_to_memory(
|
|
111
|
-
api=api,
|
|
112
|
-
record_id=regscale_issue.id,
|
|
113
|
-
module="issues",
|
|
114
|
-
stored_name=attachment.trustedStorageName,
|
|
115
|
-
file_hash=(attachment.fileHash if attachment.fileHash else attachment.shaHash),
|
|
116
|
-
)
|
|
117
|
-
)
|
|
118
|
-
return jira_dir, regscale_dir
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def compare_files_for_dupes_and_upload(
|
|
122
|
-
synqly_issue: Ticket, regscale_issue: Issue, synqly_client: utils.Tenant, api: Api
|
|
123
|
-
) -> None:
|
|
124
|
-
"""
|
|
125
|
-
Compare attachments for provided Jira and RegScale issues via hash to prevent duplicates
|
|
126
|
-
|
|
127
|
-
:param Ticket synqly_issue: Synqly issue object to compare attachments from
|
|
128
|
-
:param Issue regscale_issue: RegScale issue object to compare attachments from
|
|
129
|
-
:param utils.Tenant synqly_client: Jira client to use for uploading attachments
|
|
130
|
-
:param Api api: RegScale API object to use for interacting with RegScale
|
|
131
|
-
:rtype: None
|
|
132
|
-
"""
|
|
133
|
-
jira_uploaded_attachments = []
|
|
134
|
-
regscale_uploaded_attachments = []
|
|
135
|
-
# create a temporary directory to store the downloaded attachments from Jira and RegScale
|
|
136
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
|
137
|
-
# write attachments to the temporary directory
|
|
138
|
-
jira_dir, regscale_dir = download_issue_attachments_to_directory(
|
|
139
|
-
directory=temp_dir,
|
|
140
|
-
synqly_issue=synqly_issue,
|
|
141
|
-
regscale_issue=regscale_issue,
|
|
142
|
-
api=api,
|
|
143
|
-
synqly_client=synqly_client,
|
|
144
|
-
)
|
|
145
|
-
# get the hashes for the attachments in the regscale and jira directories
|
|
146
|
-
# iterate all files in the jira directory and compute their hashes
|
|
147
|
-
jira_attachment_hashes = compute_hashes_in_directory(jira_dir)
|
|
148
|
-
regscale_attachment_hashes = compute_hashes_in_directory(regscale_dir)
|
|
149
|
-
|
|
150
|
-
# check where the files need to be uploaded to before uploading
|
|
151
|
-
for file_hash, file in regscale_attachment_hashes.items():
|
|
152
|
-
if file_hash not in jira_attachment_hashes:
|
|
153
|
-
try:
|
|
154
|
-
upload_synqly_attachments(
|
|
155
|
-
tenant=synqly_client,
|
|
156
|
-
ticket_id=synqly_issue.id,
|
|
157
|
-
file_path=Path(file),
|
|
158
|
-
)
|
|
159
|
-
jira_uploaded_attachments.append(file)
|
|
160
|
-
except TypeError as ex:
|
|
161
|
-
logger.error(
|
|
162
|
-
"Unable to upload %s to Jira issue %s.\nError: %s",
|
|
163
|
-
Path(file).name,
|
|
164
|
-
synqly_issue.id,
|
|
165
|
-
ex,
|
|
166
|
-
)
|
|
167
|
-
for file_hash, file in jira_attachment_hashes.items():
|
|
168
|
-
if file_hash not in regscale_attachment_hashes:
|
|
169
|
-
with open(file, "rb") as in_file:
|
|
170
|
-
if File.upload_file_to_regscale(
|
|
171
|
-
file_name=f"Jira_attachment_{Path(file).name}",
|
|
172
|
-
parent_id=regscale_issue.id,
|
|
173
|
-
parent_module="issues",
|
|
174
|
-
api=api,
|
|
175
|
-
file_data=in_file.read(),
|
|
176
|
-
):
|
|
177
|
-
regscale_uploaded_attachments.append(file)
|
|
178
|
-
logger.debug(
|
|
179
|
-
"Uploaded %s to RegScale issue #%i.",
|
|
180
|
-
Path(file).name,
|
|
181
|
-
regscale_issue.id,
|
|
182
|
-
)
|
|
183
|
-
else:
|
|
184
|
-
logger.warning(
|
|
185
|
-
"Unable to upload %s to RegScale issue #%i.",
|
|
186
|
-
Path(file).name,
|
|
187
|
-
regscale_issue.id,
|
|
188
|
-
)
|
|
189
|
-
log_upload_results(regscale_uploaded_attachments, jira_uploaded_attachments, regscale_issue, synqly_issue)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def log_upload_results(
|
|
193
|
-
regscale_uploaded_attachments: list, jira_uploaded_attachments: list, regscale_issue: Issue, synqly_issue: Ticket
|
|
194
|
-
) -> None:
|
|
195
|
-
"""
|
|
196
|
-
Log the results of the upload process
|
|
197
|
-
|
|
198
|
-
:param list regscale_uploaded_attachments: List of RegScale attachments that were uploaded
|
|
199
|
-
:param list jira_uploaded_attachments: List of Jira attachments that were uploaded
|
|
200
|
-
:param Issue regscale_issue: RegScale issue that the attachments were uploaded to
|
|
201
|
-
:param Ticket synqly_issue: Jira issue that the attachments were uploaded to
|
|
202
|
-
:rtype: None
|
|
203
|
-
:return: None
|
|
204
|
-
"""
|
|
205
|
-
if regscale_uploaded_attachments and jira_uploaded_attachments:
|
|
206
|
-
logger.info(
|
|
207
|
-
"%i file(s) uploaded to RegScale issue #%i and %i file(s) uploaded to Jira issue %s.",
|
|
208
|
-
len(regscale_uploaded_attachments),
|
|
209
|
-
regscale_issue.id,
|
|
210
|
-
len(jira_uploaded_attachments),
|
|
211
|
-
synqly_issue.id,
|
|
212
|
-
)
|
|
213
|
-
elif jira_uploaded_attachments:
|
|
214
|
-
logger.info(
|
|
215
|
-
"%i file(s) uploaded to Jira issue %s.",
|
|
216
|
-
len(jira_uploaded_attachments),
|
|
217
|
-
synqly_issue.id,
|
|
218
|
-
)
|
|
219
|
-
elif regscale_uploaded_attachments:
|
|
220
|
-
logger.info(
|
|
221
|
-
"%i file(s) uploaded to RegScale issue #%i.",
|
|
222
|
-
len(regscale_uploaded_attachments),
|
|
223
|
-
regscale_issue.id,
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
def download_synqly_attachments(tenant: utils.Tenant, ticket_id: str, download_dir: str) -> int:
|
|
228
|
-
"""
|
|
229
|
-
Downloads attachments from a ticket via Synqly
|
|
230
|
-
|
|
231
|
-
:param utils.Tenant tenant: Synqly Tenant object
|
|
232
|
-
:param str ticket_id: Ticket ID to download attachments from
|
|
233
|
-
:param str download_dir: Directory to download attachments to
|
|
234
|
-
:return: # of Synqly attachments downloaded
|
|
235
|
-
:rtype: int
|
|
236
|
-
"""
|
|
237
|
-
attachments = tenant.synqly_engine_client.ticketing.list_attachments_metadata(ticket_id)
|
|
238
|
-
logger.debug("Found %i attachments for ticket %s", len(attachments.result), ticket_id)
|
|
239
|
-
for attachment in attachments.result:
|
|
240
|
-
download_response = tenant.synqly_engine_client.ticketing.download_attachment(
|
|
241
|
-
ticket_id=ticket_id, attachment_id=attachment.id
|
|
242
|
-
)
|
|
243
|
-
output_path = os.path.join(download_dir, attachment.file_name)
|
|
244
|
-
with open(output_path, "wb") as f:
|
|
245
|
-
f.write(base64.b64decode(download_response.result.content))
|
|
246
|
-
logger.debug(
|
|
247
|
-
"Downloaded attachment: %s and wrote its contents to %s",
|
|
248
|
-
download_response.result.file_name,
|
|
249
|
-
attachment.file_name,
|
|
250
|
-
)
|
|
251
|
-
return len(attachments.result)
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
def upload_synqly_attachments(tenant: utils.Tenant, ticket_id: str, file_path: Path) -> None:
|
|
255
|
-
"""
|
|
256
|
-
Uploads an attachment to a ticket via Synqly
|
|
257
|
-
|
|
258
|
-
:param utils.Tenant tenant: Synqly Tenant object
|
|
259
|
-
:param str ticket_id: Ticket ID to attach the file to
|
|
260
|
-
:param Path file_path: Path to the file to attach
|
|
261
|
-
:rtype: None
|
|
262
|
-
"""
|
|
263
|
-
with open(file_path, "rb") as file:
|
|
264
|
-
content = base64.b64encode(file.read())
|
|
265
|
-
logger.debug("Creating attachment for ticket %s", ticket_id)
|
|
266
|
-
tenant.synqly_engine_client.ticketing.create_attachment(
|
|
267
|
-
ticket_id=ticket_id,
|
|
268
|
-
request=engine.CreateAttachmentRequest(
|
|
269
|
-
file_name=file_path.name,
|
|
270
|
-
content=content,
|
|
271
|
-
),
|
|
272
|
-
)
|
|
273
|
-
logger.info("Added an attachment to ticket %s", ticket_id)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def map_jira_issue_to_regscale_issue(synqly_issue: Ticket, parent_id: int, parent_module: str, config: dict) -> Issue:
|
|
277
|
-
"""
|
|
278
|
-
Maps a JIRA issue to a RegScale issue
|
|
279
|
-
|
|
280
|
-
:param Ticket synqly_issue: Synqly Ticket object
|
|
281
|
-
:param int parent_id: Parent ID of the issue
|
|
282
|
-
:param str parent_module: Parent module of the issue
|
|
283
|
-
:param dict config: Configuration object
|
|
284
|
-
:return: RegScale issue object
|
|
285
|
-
:rtype: Issue
|
|
286
|
-
"""
|
|
287
|
-
due_date = convert_datetime_to_regscale_string(synqly_issue.due_date)
|
|
288
|
-
return Issue(
|
|
289
|
-
title=synqly_issue.summary,
|
|
290
|
-
severityLevel=Issue.assign_severity(synqly_issue.priority),
|
|
291
|
-
issueOwnerId=config["userId"],
|
|
292
|
-
dueDate=due_date,
|
|
293
|
-
description=(f"Description {synqly_issue.description}\nStatus: {synqly_issue.status}\nDue Date: {due_date}"),
|
|
294
|
-
status=("Closed" if synqly_issue.status.lower() == "done" else config["issues"]["jira"]["status"]),
|
|
295
|
-
jiraId=synqly_issue.id,
|
|
296
|
-
parentId=parent_id,
|
|
297
|
-
parentModule=parent_module,
|
|
298
|
-
dateCreated=get_current_datetime(),
|
|
299
|
-
dateCompleted=(
|
|
300
|
-
convert_datetime_to_regscale_string(synqly_issue.completion_date)
|
|
301
|
-
if synqly_issue.status.lower() == "done"
|
|
302
|
-
else None
|
|
303
|
-
),
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def map_regscale_issue_to_jira_issue(
|
|
308
|
-
regscale_issue: Issue, jira_project_key: str, jira_username: str, issue_type: str
|
|
309
|
-
) -> CreateTicketRequest:
|
|
310
|
-
"""
|
|
311
|
-
Maps a RegScale issue to a JIRA issue
|
|
312
|
-
|
|
313
|
-
:param Issue regscale_issue: RegScale issue object
|
|
314
|
-
:param str jira_project_key: Jira project key
|
|
315
|
-
:param str jira_username: Username to use for creating issues in Jira
|
|
316
|
-
:param str issue_type: Type of issue to create in Jira
|
|
317
|
-
:return: Synqly CreateTicketRequest object
|
|
318
|
-
:rtype: CreateTicketRequest
|
|
319
|
-
"""
|
|
320
|
-
return engine.CreateTicketRequest(
|
|
321
|
-
id=regscale_issue.title,
|
|
322
|
-
name=regscale_issue.title,
|
|
323
|
-
summary=f"{regscale_issue.description}\n\n{regscale_issue_fields_to_markdown(regscale_issue)}",
|
|
324
|
-
project=jira_project_key,
|
|
325
|
-
creator=jira_username,
|
|
326
|
-
issue_type=issue_type,
|
|
327
|
-
priority=map_regscale_severity_to_jira_priority(regscale_issue.severityLevel.lower()),
|
|
328
|
-
status="To Do",
|
|
329
|
-
due_date=datetime.strptime(regscale_issue.dueDate, "%Y-%m-%dT%H:%M:%S"), # convert string to datetime
|
|
330
|
-
)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
def regscale_issue_fields_to_markdown(regscale_issue: Issue) -> str:
|
|
334
|
-
"""
|
|
335
|
-
Converts a RegScale issue's fields to a Markdown string
|
|
336
|
-
|
|
337
|
-
:param Issue regscale_issue: RegScale issue object
|
|
338
|
-
:return: Markdown string of RegScale issue fields
|
|
339
|
-
:rtype: str
|
|
340
|
-
"""
|
|
341
|
-
regscale_issue_dict = regscale_issue.dict()
|
|
342
|
-
markdown_table = "| RegScale Field | Value |\n| --- | --- |\n"
|
|
343
|
-
for key in regscale_issue_dict:
|
|
344
|
-
markdown_table += f"| {key} | {regscale_issue_dict[key]} |\n"
|
|
345
|
-
return markdown_table
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
def map_regscale_severity_to_jira_priority(regscale_severity: str) -> Priority:
|
|
349
|
-
"""
|
|
350
|
-
Map RegScale severity to OCSF priority
|
|
351
|
-
|
|
352
|
-
:param str regscale_severity: RegScale severity
|
|
353
|
-
:return: Jira priority
|
|
354
|
-
:rtype: Priority
|
|
355
|
-
"""
|
|
356
|
-
if "high" in regscale_severity.lower():
|
|
357
|
-
return Priority.HIGH
|
|
358
|
-
elif "moderate" in regscale_severity.lower():
|
|
359
|
-
return Priority.MEDIUM
|
|
360
|
-
else:
|
|
361
|
-
return Priority.LOW
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
def background_job(
|
|
365
|
-
synqly_app: utils.App,
|
|
366
|
-
jira_project_key: str,
|
|
367
|
-
jira_username: str,
|
|
368
|
-
jira_issue_type: str,
|
|
369
|
-
regscale_id: int,
|
|
370
|
-
regscale_module: str,
|
|
371
|
-
sync_attachments: bool = True,
|
|
372
|
-
) -> None:
|
|
373
|
-
"""
|
|
374
|
-
Simulates a background process performing work on behalf of tenants.
|
|
375
|
-
Iterates through all tenants and, for any tenant with a Synqly Engine
|
|
376
|
-
Client defined, creates a new ticket. After a short delay,
|
|
377
|
-
background_job will update the ticket's status to "Done".
|
|
378
|
-
|
|
379
|
-
:param utils.App synqly_app: Synqly Application object
|
|
380
|
-
:param str jira_project_key: Jira project key
|
|
381
|
-
:param str jira_username: Username to use for creating issues in Jira
|
|
382
|
-
:param str jira_issue_type: Type of issue to create in Jira
|
|
383
|
-
:param int regscale_id: RegScale record ID Number to sync issues to
|
|
384
|
-
:param str regscale_module: RegScale module to sync issues to
|
|
385
|
-
:param bool sync_attachments: Flag to determine if attachments should be synced, defaults to True
|
|
386
|
-
:rtype: None
|
|
387
|
-
"""
|
|
388
|
-
# Iterate through each tenant and send an event to their Event Logger
|
|
389
|
-
for tenant in synqly_app.tenants.values():
|
|
390
|
-
# Skip tenants that don't have a Synqly Engine Client initialized
|
|
391
|
-
if tenant.synqly_engine_client is None:
|
|
392
|
-
continue
|
|
393
|
-
|
|
394
|
-
regscale_issues = Issue.get_all_by_parent(regscale_id, regscale_module)
|
|
395
|
-
logger.info("Found {} issues in RegScale".format(len(regscale_issues)))
|
|
396
|
-
jira_issues: list[Issue] = []
|
|
397
|
-
fetch_res = tenant.synqly_engine_client.ticketing.query_tickets(
|
|
398
|
-
filter=f"project[eq]{jira_project_key}",
|
|
399
|
-
limit=100,
|
|
400
|
-
)
|
|
401
|
-
jira_issues.extend(fetch_res.result)
|
|
402
|
-
# check and handle pagination
|
|
403
|
-
while int(fetch_res.cursor) == len(jira_issues):
|
|
404
|
-
fetch_res = tenant.synqly_engine_client.ticketing.query_tickets(
|
|
405
|
-
filter=f"project[eq]{jira_project_key}",
|
|
406
|
-
limit=100,
|
|
407
|
-
cursor=fetch_res.cursor,
|
|
408
|
-
)
|
|
409
|
-
jira_issues.extend(fetch_res.result)
|
|
410
|
-
logger.info("Found {} issues in JIRA".format(len(jira_issues)))
|
|
411
|
-
regscale_cli = Application()
|
|
412
|
-
api = Api()
|
|
413
|
-
(
|
|
414
|
-
regscale_issues,
|
|
415
|
-
regscale_attachments,
|
|
416
|
-
) = Issue.fetch_issues_and_attachments_by_parent(
|
|
417
|
-
app=regscale_cli,
|
|
418
|
-
parent_id=regscale_id,
|
|
419
|
-
parent_module=regscale_module,
|
|
420
|
-
fetch_attachments=sync_attachments,
|
|
421
|
-
)
|
|
422
|
-
|
|
423
|
-
if regscale_issues:
|
|
424
|
-
# sync RegScale issues to Jira
|
|
425
|
-
if issues_to_update := sync_regscale_to_jira(
|
|
426
|
-
regscale_issues=regscale_issues,
|
|
427
|
-
jira_client=tenant,
|
|
428
|
-
jira_project=jira_project_key,
|
|
429
|
-
jira_issue_type=jira_issue_type,
|
|
430
|
-
jira_username=jira_username,
|
|
431
|
-
sync_attachments=sync_attachments,
|
|
432
|
-
attachments=regscale_attachments,
|
|
433
|
-
):
|
|
434
|
-
with job_progress:
|
|
435
|
-
# create task to update RegScale issues
|
|
436
|
-
updating_issues = job_progress.add_task(
|
|
437
|
-
f"[#f8b737]Updating {len(issues_to_update)} RegScale issue(s) from Jira...",
|
|
438
|
-
total=len(issues_to_update),
|
|
439
|
-
)
|
|
440
|
-
# create threads to analyze Jira issues and RegScale issues
|
|
441
|
-
create_threads(
|
|
442
|
-
process=update_regscale_issues,
|
|
443
|
-
args=(
|
|
444
|
-
issues_to_update,
|
|
445
|
-
api,
|
|
446
|
-
updating_issues,
|
|
447
|
-
),
|
|
448
|
-
thread_count=len(issues_to_update),
|
|
449
|
-
)
|
|
450
|
-
# output the final result
|
|
451
|
-
logger.info(
|
|
452
|
-
"%i/%i issue(s) updated in RegScale.",
|
|
453
|
-
len(issues_to_update),
|
|
454
|
-
len(update_counter),
|
|
455
|
-
)
|
|
456
|
-
else:
|
|
457
|
-
logger.info("No issues need to be updated in RegScale.")
|
|
458
|
-
|
|
459
|
-
if jira_issues:
|
|
460
|
-
# sync Jira issues to RegScale
|
|
461
|
-
with job_progress:
|
|
462
|
-
# create task to create RegScale issues
|
|
463
|
-
creating_issues = job_progress.add_task(
|
|
464
|
-
f"[#f8b737]Analyzing {len(jira_issues)} Jira issue(s)"
|
|
465
|
-
f" and {len(regscale_issues)} RegScale issue(s)...",
|
|
466
|
-
total=len(jira_issues),
|
|
467
|
-
)
|
|
468
|
-
# create threads to analyze Jira issues and RegScale issues
|
|
469
|
-
create_threads(
|
|
470
|
-
process=create_and_update_regscale_issues,
|
|
471
|
-
args=(
|
|
472
|
-
jira_issues,
|
|
473
|
-
regscale_issues,
|
|
474
|
-
sync_attachments,
|
|
475
|
-
regscale_cli,
|
|
476
|
-
regscale_id,
|
|
477
|
-
regscale_module,
|
|
478
|
-
tenant,
|
|
479
|
-
creating_issues,
|
|
480
|
-
),
|
|
481
|
-
thread_count=len(jira_issues),
|
|
482
|
-
)
|
|
483
|
-
# output the final result
|
|
484
|
-
logger.info(
|
|
485
|
-
"Analyzed %i Jira issue(s), created %i issue(s) and updated %i issue(s) in RegScale.",
|
|
486
|
-
len(jira_issues),
|
|
487
|
-
len(new_regscale_issues),
|
|
488
|
-
len(updated_regscale_issues),
|
|
489
|
-
)
|
|
490
|
-
else:
|
|
491
|
-
logger.info("No issues need to be analyzed from Jira.")
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
def update_regscale_issues(args: Tuple, thread: int) -> None:
|
|
495
|
-
"""
|
|
496
|
-
Function to compare Jira issues and RegScale issues
|
|
497
|
-
|
|
498
|
-
:param Tuple args: Tuple of args to use during the process
|
|
499
|
-
:param int thread: Thread number of current thread
|
|
500
|
-
:rtype: None
|
|
501
|
-
"""
|
|
502
|
-
# set up local variables from the passed args
|
|
503
|
-
(
|
|
504
|
-
regscale_issues,
|
|
505
|
-
regscale_cli,
|
|
506
|
-
task,
|
|
507
|
-
) = args
|
|
508
|
-
# find which records should be executed by the current thread
|
|
509
|
-
threads = thread_assignment(thread=thread, total_items=len(regscale_issues))
|
|
510
|
-
# iterate through the thread assignment items and process them
|
|
511
|
-
for i in range(len(threads)):
|
|
512
|
-
# set the issue for the thread for later use in the function
|
|
513
|
-
issue = regscale_issues[threads[i]]
|
|
514
|
-
# update the issue in RegScale
|
|
515
|
-
Issue.update_issue(app=regscale_cli, issue=issue)
|
|
516
|
-
logger.info(
|
|
517
|
-
"RegScale Issue %i was updated with the Jira link.",
|
|
518
|
-
issue.id,
|
|
519
|
-
)
|
|
520
|
-
update_counter.append(issue)
|
|
521
|
-
# update progress bar
|
|
522
|
-
job_progress.update(task, advance=1)
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
def get_synqly_attachment_count(tenant: utils.Tenant, ticket_id: str) -> int:
|
|
526
|
-
"""
|
|
527
|
-
Get the number of attachments for a ticket in Synqly
|
|
528
|
-
|
|
529
|
-
:param utils.Tenant tenant: Synqly Tenant object
|
|
530
|
-
:param str ticket_id: Ticket ID to get the attachments for
|
|
531
|
-
:return: Number of attachments for the ticket
|
|
532
|
-
:rtype: int
|
|
533
|
-
"""
|
|
534
|
-
try:
|
|
535
|
-
attachments = tenant.synqly_engine_client.ticketing.list_attachments_metadata(ticket_id)
|
|
536
|
-
return len(attachments.result)
|
|
537
|
-
except Exception as ex:
|
|
538
|
-
logger.error(f"Unable to get attachments for ticket {ticket_id}.\nError: {ex}")
|
|
539
|
-
return 0
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
def create_and_update_regscale_issues(args: Tuple, thread: int) -> None:
|
|
543
|
-
"""
|
|
544
|
-
Function to create or update issues in RegScale from Jira
|
|
545
|
-
|
|
546
|
-
:param Tuple args: Tuple of args to use during the process
|
|
547
|
-
:param int thread: Thread number of current thread
|
|
548
|
-
:rtype: None
|
|
549
|
-
"""
|
|
550
|
-
# set up local variables from the passed args
|
|
551
|
-
(
|
|
552
|
-
jira_issues,
|
|
553
|
-
regscale_issues,
|
|
554
|
-
add_attachments,
|
|
555
|
-
regscale_cli,
|
|
556
|
-
parent_id,
|
|
557
|
-
parent_module,
|
|
558
|
-
jira_client,
|
|
559
|
-
task,
|
|
560
|
-
) = args
|
|
561
|
-
# find which records should be executed by the current thread
|
|
562
|
-
threads = thread_assignment(thread=thread, total_items=len(jira_issues))
|
|
563
|
-
|
|
564
|
-
# iterate through the thread assignment items and process them
|
|
565
|
-
for i in range(len(threads)):
|
|
566
|
-
jira_issue: Ticket = jira_issues[threads[i]]
|
|
567
|
-
regscale_issue: Optional[Issue] = next(
|
|
568
|
-
(issue for issue in regscale_issues if issue.jiraId == jira_issue.id), None
|
|
569
|
-
)
|
|
570
|
-
# see if the Jira issue needs to be created in RegScale
|
|
571
|
-
if jira_issue.status.lower() == "done" and regscale_issue:
|
|
572
|
-
# update the status and date completed of the RegScale issue
|
|
573
|
-
regscale_issue.status = "Closed"
|
|
574
|
-
regscale_issue.dateCompleted = get_current_datetime()
|
|
575
|
-
# update the issue in RegScale
|
|
576
|
-
updated_regscale_issues.append(Issue.update_issue(app=regscale_cli, issue=regscale_issue))
|
|
577
|
-
elif regscale_issue:
|
|
578
|
-
# update the issue in RegScale
|
|
579
|
-
updated_regscale_issues.append(Issue.update_issue(app=regscale_cli, issue=regscale_issue))
|
|
580
|
-
else:
|
|
581
|
-
# map the jira issue to a RegScale issue object
|
|
582
|
-
issue = map_jira_issue_to_regscale_issue(
|
|
583
|
-
synqly_issue=jira_issue,
|
|
584
|
-
config=regscale_cli.config,
|
|
585
|
-
parent_id=parent_id,
|
|
586
|
-
parent_module=parent_module,
|
|
587
|
-
)
|
|
588
|
-
# create the issue in RegScale
|
|
589
|
-
if regscale_issue := Issue.insert_issue(
|
|
590
|
-
app=regscale_cli,
|
|
591
|
-
issue=issue,
|
|
592
|
-
):
|
|
593
|
-
if regscale_issue.id:
|
|
594
|
-
logger.debug(
|
|
595
|
-
"Created issue #%i-%s in RegScale.",
|
|
596
|
-
regscale_issue.id,
|
|
597
|
-
regscale_issue.title,
|
|
598
|
-
)
|
|
599
|
-
else:
|
|
600
|
-
logger.warning("Unable to create issue in RegScale.\nIssue: %s", issue.dict())
|
|
601
|
-
new_regscale_issues.append(regscale_issue)
|
|
602
|
-
handle_attachments(
|
|
603
|
-
add_attachments=add_attachments,
|
|
604
|
-
regscale_issue=regscale_issue,
|
|
605
|
-
jira_client=jira_client,
|
|
606
|
-
jira_issue=jira_issue,
|
|
607
|
-
)
|
|
608
|
-
# update progress bar
|
|
609
|
-
job_progress.update(task, advance=1)
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
def handle_attachments(
|
|
613
|
-
add_attachments: bool, regscale_issue: Issue, jira_client: utils.Tenant, jira_issue: Ticket
|
|
614
|
-
) -> None:
|
|
615
|
-
"""
|
|
616
|
-
Handle attachments for Jira and RegScale issues
|
|
617
|
-
|
|
618
|
-
:param bool add_attachments: Flag to determine if attachments should be added to the issue
|
|
619
|
-
:param Issue regscale_issue: RegScale issue object
|
|
620
|
-
:param utils.Tenant jira_client: Jira client to use for issue creation in Jira
|
|
621
|
-
:param Ticket jira_issue: Jira issue object
|
|
622
|
-
:rtype: None
|
|
623
|
-
"""
|
|
624
|
-
if add_attachments and regscale_issue:
|
|
625
|
-
# check if the jira issue has attachments
|
|
626
|
-
attachment_count = get_synqly_attachment_count(jira_client, jira_issue.id)
|
|
627
|
-
if attachment_count > 0:
|
|
628
|
-
# determine which attachments need to be uploaded to prevent duplicates by
|
|
629
|
-
# getting the hashes of all Jira & RegScale attachments
|
|
630
|
-
compare_files_for_dupes_and_upload(
|
|
631
|
-
synqly_issue=jira_issue,
|
|
632
|
-
regscale_issue=regscale_issue,
|
|
633
|
-
synqly_client=jira_client,
|
|
634
|
-
api=Api(),
|
|
635
|
-
)
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
def sync_regscale_to_jira(
|
|
639
|
-
regscale_issues: list[Issue],
|
|
640
|
-
jira_client: utils.Tenant,
|
|
641
|
-
jira_project: str,
|
|
642
|
-
jira_issue_type: str,
|
|
643
|
-
jira_username: str,
|
|
644
|
-
sync_attachments: bool = True,
|
|
645
|
-
attachments: Optional[dict] = None,
|
|
646
|
-
) -> list[Issue]:
|
|
647
|
-
"""
|
|
648
|
-
Sync issues from RegScale to Jira
|
|
649
|
-
|
|
650
|
-
:param list[Issue] regscale_issues: list of RegScale issues to sync to Jira
|
|
651
|
-
:param utils.Tenant jira_client: Jira client to use for issue creation in Jira
|
|
652
|
-
:param str jira_project: Jira Project to create the issues in
|
|
653
|
-
:param str jira_issue_type: Type of issue to create in Jira
|
|
654
|
-
:param str jira_username: Username to use for creating issues in Jira
|
|
655
|
-
:param bool sync_attachments: Flag to determine if attachments should be synced, defaults to True
|
|
656
|
-
:param Optional[dict] attachments: Dictionary of attachments to sync, defaults to None
|
|
657
|
-
:return: list of RegScale issues that need to be updated
|
|
658
|
-
:rtype: list[Issue]
|
|
659
|
-
"""
|
|
660
|
-
new_issue_counter = 0
|
|
661
|
-
issuess_to_update = []
|
|
662
|
-
for issue in regscale_issues:
|
|
663
|
-
# see if Jira issue already exists
|
|
664
|
-
if not issue.jiraId or issue.jiraId == "":
|
|
665
|
-
new_issue = create_issue_in_jira(
|
|
666
|
-
issue=issue,
|
|
667
|
-
jira_client=jira_client,
|
|
668
|
-
jira_project=jira_project,
|
|
669
|
-
issue_type=jira_issue_type,
|
|
670
|
-
jira_username=jira_username,
|
|
671
|
-
add_attachments=sync_attachments,
|
|
672
|
-
attachments=attachments,
|
|
673
|
-
)
|
|
674
|
-
if not new_issue:
|
|
675
|
-
continue
|
|
676
|
-
# log progress
|
|
677
|
-
new_issue_counter += 1
|
|
678
|
-
# get the Jira ID
|
|
679
|
-
jira_id = new_issue.id
|
|
680
|
-
# update the RegScale issue for the Jira link
|
|
681
|
-
issue.jiraId = jira_id
|
|
682
|
-
# add the issue to the update_issues global list
|
|
683
|
-
issuess_to_update.append(issue)
|
|
684
|
-
# output the final result
|
|
685
|
-
logger.info("%i new issue(s) opened in Jira.", new_issue_counter)
|
|
686
|
-
return issuess_to_update
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
def create_issue_in_jira(
|
|
690
|
-
issue: Issue,
|
|
691
|
-
jira_client: utils.Tenant,
|
|
692
|
-
jira_project: str,
|
|
693
|
-
issue_type: str,
|
|
694
|
-
jira_username: str,
|
|
695
|
-
add_attachments: Optional[bool] = False,
|
|
696
|
-
attachments: list[File] = None,
|
|
697
|
-
api: Optional[Api] = None,
|
|
698
|
-
) -> Optional[Ticket]:
|
|
699
|
-
"""
|
|
700
|
-
Create a new issue in Jira
|
|
701
|
-
|
|
702
|
-
:param Issue issue: RegScale issue object
|
|
703
|
-
:param utils.Tenant jira_client: Jira client to use for issue creation in Jira
|
|
704
|
-
:param str jira_project: Project name in Jira to create the issue in
|
|
705
|
-
:param str issue_type: The type of issue to create in Jira
|
|
706
|
-
:param str jira_username: Username to use for creating issues in Jira
|
|
707
|
-
:param Optional[bool] add_attachments: Flag to determine if attachments should be added to the issue
|
|
708
|
-
:param list[File] attachments: List of attachments to add to the issue
|
|
709
|
-
:param Optional[Api] api: RegScale API object to use for interacting with RegScale
|
|
710
|
-
:return: Newly created issue in Jira
|
|
711
|
-
:rtype: Optional[Ticket]
|
|
712
|
-
"""
|
|
713
|
-
try:
|
|
714
|
-
new_issue = map_regscale_issue_to_jira_issue(issue, jira_project, jira_username, issue_type)
|
|
715
|
-
create_response = jira_client.synqly_engine_client.ticketing.create_ticket(request=new_issue)
|
|
716
|
-
except Exception as ex:
|
|
717
|
-
logger.error(f"Unable to create Jira issue.\nError: {ex}")
|
|
718
|
-
return None
|
|
719
|
-
# error_and_exit(f"Unable to create Jira issue.\nError: {ex}")
|
|
720
|
-
if add_attachments and attachments:
|
|
721
|
-
if not api:
|
|
722
|
-
api = Api()
|
|
723
|
-
compare_files_for_dupes_and_upload(
|
|
724
|
-
synqly_issue=create_response.result.Ticket,
|
|
725
|
-
regscale_issue=issue,
|
|
726
|
-
synqly_client=jira_client,
|
|
727
|
-
api=Api(),
|
|
728
|
-
)
|
|
729
|
-
logger.info("Created ticket: {}".format(create_response.result.name))
|
|
730
|
-
return create_response.result
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
@synqly.command(name="sync_jira")
|
|
734
|
-
@regscale_id()
|
|
735
|
-
@regscale_module()
|
|
736
|
-
@click.option(
|
|
737
|
-
"--jira_project",
|
|
738
|
-
type=click.STRING,
|
|
739
|
-
help="RegScale will sync the issues for the record to the Jira project.",
|
|
740
|
-
prompt="Enter the name of the project in Jira",
|
|
741
|
-
required=True,
|
|
742
|
-
)
|
|
743
|
-
@click.option(
|
|
744
|
-
"--jira_issue_type",
|
|
745
|
-
type=click.STRING,
|
|
746
|
-
help="Enter the Jira issue type to use when creating new issues from RegScale. (CASE SENSITIVE)",
|
|
747
|
-
prompt="Enter the Jira issue type",
|
|
748
|
-
required=True,
|
|
749
|
-
)
|
|
750
|
-
@click.option(
|
|
751
|
-
"--sync_attachments",
|
|
752
|
-
type=click.BOOL,
|
|
753
|
-
help=(
|
|
754
|
-
"Whether RegScale will sync the attachments for the issue "
|
|
755
|
-
"in the provided Jira project and vice versa. Defaults to True."
|
|
756
|
-
),
|
|
757
|
-
required=False,
|
|
758
|
-
default=True,
|
|
759
|
-
)
|
|
760
|
-
def sync_jira(
|
|
761
|
-
regscale_id: int, regscale_module: str, jira_project: str, jira_issue_type: str, sync_attachments: bool = True
|
|
762
|
-
):
|
|
763
|
-
"""
|
|
764
|
-
Parses command line arguments for this example.
|
|
765
|
-
"""
|
|
766
|
-
sync_with_jira(
|
|
767
|
-
regscale_id,
|
|
768
|
-
regscale_module,
|
|
769
|
-
jira_project,
|
|
770
|
-
jira_issue_type,
|
|
771
|
-
sync_attachments,
|
|
772
|
-
)
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
def sync_with_jira(
|
|
776
|
-
regscale_id: int, regscale_module: str, jira_project_key: str, jira_issue_type: str, sync_attachments: bool = True
|
|
777
|
-
) -> None:
|
|
778
|
-
"""
|
|
779
|
-
Syncs RegScale issues with Jira issues using Synqly
|
|
780
|
-
|
|
781
|
-
:param int regscale_id: RegScale record ID Number to sync issues to
|
|
782
|
-
:param str regscale_module: RegScale module to sync issues to
|
|
783
|
-
:param str jira_project_key: Jira project key
|
|
784
|
-
:param str jira_issue_type: Type of issue to create in Jira
|
|
785
|
-
:param bool sync_attachments: Flag to determine if attachments should be synced, defaults to True
|
|
786
|
-
:raises Exception: If an error occurs during the sync process
|
|
787
|
-
:rtype: None
|
|
788
|
-
"""
|
|
789
|
-
# Initialize an empty application to store our simulated tenants
|
|
790
|
-
synqly = utils.App("ticketing")
|
|
791
|
-
app = Application()
|
|
792
|
-
synqly_access_token = os.getenv("SYNQLY_ACCESS_TOKEN") or app.config["synqlyAccessToken"]
|
|
793
|
-
jira_url = os.getenv("JIRA_URL") or app.config["jiraUrl"]
|
|
794
|
-
jira_username = os.getenv("JIRA_USERNAME") or app.config["jiraUserName"]
|
|
795
|
-
jira_token = os.getenv("JIRA_API_TOKEN") or app.config["jiraApiToken"]
|
|
796
|
-
if (
|
|
797
|
-
not jira_url
|
|
798
|
-
or not jira_username
|
|
799
|
-
or not jira_token
|
|
800
|
-
or not synqly_access_token
|
|
801
|
-
or synqly_access_token == app.template["synqlyAccessToken"]
|
|
802
|
-
or jira_url == app.template["jiraUrl"]
|
|
803
|
-
or jira_username == app.template["jiraUserName"]
|
|
804
|
-
or jira_token == app.template["jiraApiToken"]
|
|
805
|
-
):
|
|
806
|
-
error_and_exit(
|
|
807
|
-
"jiraUrl, jiraUserName, and jiraApiToken are required. Please provide them in the environment or init.yaml."
|
|
808
|
-
)
|
|
809
|
-
# Initialize tenants within our Application
|
|
810
|
-
try:
|
|
811
|
-
synqly.new_tenant(synqly_access_token, "RegScale-CLI")
|
|
812
|
-
app.logger.debug("RegScale-CLI created")
|
|
813
|
-
except Exception as e:
|
|
814
|
-
app.logger.error("Error creating Tenant RegScale-CLI:" + str(e))
|
|
815
|
-
synqly._cleanup_handler()
|
|
816
|
-
raise e
|
|
817
|
-
|
|
818
|
-
# Configure a ticketing integration based on the configuration. If no jira credentials
|
|
819
|
-
# are provided, then mock ticket provider is used
|
|
820
|
-
provider_config: mgmt.ProviderConfig = jira_provider_config(jira_url, jira_username, jira_token)
|
|
821
|
-
|
|
822
|
-
# Configure a mock integration for tenant ABC and a JIRA Integration for Tenant XYZ
|
|
823
|
-
try:
|
|
824
|
-
synqly.configure_integration("RegScale-CLI", provider_config)
|
|
825
|
-
except Exception as e:
|
|
826
|
-
print("Error configuring provider integration for Tenant RegScale-CLI: " + str(e))
|
|
827
|
-
synqly._cleanup_handler()
|
|
828
|
-
raise e
|
|
829
|
-
|
|
830
|
-
# Start a background job to generate data
|
|
831
|
-
try:
|
|
832
|
-
background_job(
|
|
833
|
-
synqly, jira_project_key, jira_username, jira_issue_type, regscale_id, regscale_module, sync_attachments
|
|
834
|
-
)
|
|
835
|
-
except Exception as e:
|
|
836
|
-
print("Error running background job: " + str(e))
|
|
837
|
-
synqly._cleanup_handler()
|
|
838
|
-
raise e
|
|
839
|
-
|
|
840
|
-
synqly._cleanup_handler()
|