Skip to content

Commit

Permalink
Merge pull request #545 from armosec/feature/multipule_jira
Browse files Browse the repository at this point in the history
change the apis to support the multi jira
  • Loading branch information
jnathangreeg authored Dec 30, 2024
2 parents 64d7192 + 60e1b6c commit 15eb4d5
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 17 deletions.
1 change: 1 addition & 0 deletions configurations/integrations/issueTmpl.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"collaborationGUID": "",
"issueType": "clusterControl",
"fields": {
"summary": "armo system test",
Expand Down
31 changes: 24 additions & 7 deletions infrastructure/backend_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2879,19 +2879,36 @@ def get_runtime_policies_uniquevalues(self, body):
return r

def get_integration_status(self, provider: str):
url = API_INTEGRATIONS + "/connection/status"
url = API_INTEGRATIONS + "/connectionV2/status"
r = self.get(url, params={"customerGUID": self.selected_tenant_id, "provider": provider})
assert 200 <= r.status_code < 300, f"{inspect.currentframe().f_code.co_name}, url: '{url}', customer: '{self.customer}' code: {r.status_code}, message: '{r.text}'"
return r.json()

def get_jira_config(self):
url = API_INTEGRATIONS + "/jira/config"
url = API_INTEGRATIONS + "/jira/configV2"
r = self.get(url, params={"customerGUID": self.selected_tenant_id})
assert 200 <= r.status_code < 300, f"{inspect.currentframe().f_code.co_name}, url: '{url}', customer: '{self.customer}' code: {r.status_code}, message: '{r.text}'"
return r.json()

def get_jira_collaboration_guid_by_site_name(self, site_name: str):
config = self.get_jira_config()
jira_connections = config.get("jiraConnections", [])
if not jira_connections:
raise Exception("No Jira connections found in the response")

for connection in jira_connections:
selected_site = connection.get("selectedSite", {})
if selected_site.get("name") == site_name:
collabGUID = connection.get("jiraCollabGUID", "")
if collabGUID:
return collabGUID
else:
raise Exception(f"Jira collaboration GUID is empty or missing for site '{site_name}'")

raise Exception(f"No Jira collaboration found for site '{site_name}'")

def update_jira_config(self, body: dict):
url = API_INTEGRATIONS + "/jira/config"
url = API_INTEGRATIONS + "/jira/configV2"
r = self.post(url,
params={"customerGUID": self.selected_tenant_id},
json=body)
Expand All @@ -2901,7 +2918,7 @@ def update_jira_config(self, body: dict):
self.customer, r.status_code, r.text))

def search_jira_projects(self, body: dict):
url = API_INTEGRATIONS + "/jira/projects/search"
url = API_INTEGRATIONS + "/jira/projectsV2/search"
r = self.post(url, params={"customerGUID": self.customer_guid},
json=body)
if not 200 <= r.status_code < 300:
Expand All @@ -2911,7 +2928,7 @@ def search_jira_projects(self, body: dict):
return r.json()

def search_jira_issue_types(self, body: dict):
url = API_INTEGRATIONS + "/jira/issueTypes/search"
url = API_INTEGRATIONS + "/jira/issueTypesV2/search"
r = self.post(url, params={"customerGUID": self.customer_guid},
json=body)
if not 200 <= r.status_code < 300:
Expand All @@ -2921,7 +2938,7 @@ def search_jira_issue_types(self, body: dict):
return r.json()

def search_jira_schema(self, body: dict):
url = API_INTEGRATIONS + "/jira/issueTypes/schema/search"
url = API_INTEGRATIONS + "/jira/issueTypesV2/schema/search"
r = self.post(url, params={"customerGUID": self.customer_guid},
json=body)
if not 200 <= r.status_code < 300:
Expand All @@ -2941,7 +2958,7 @@ def search_jira_issue_field(self, body: dict):
return r.json()

def create_jira_issue(self, body: dict):
url = API_INTEGRATIONS + "/jira/issue"
url = API_INTEGRATIONS + "/jira/issueV2"
r = self.post(url, params={"customerGUID": self.customer_guid},
json=body)
if not 200 <= r.status_code < 300:
Expand Down
27 changes: 21 additions & 6 deletions tests_scripts/helm/jira_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(
self.helm_kwargs.update(test_helm_kwargs)

self.wait_for_agg_to_end = False
self.site_name = "cyberarmor-io"

def cleanup(self, **kwargs):
super().cleanup(**kwargs)
Expand Down Expand Up @@ -64,15 +65,16 @@ def setup_jira_config(self):
jiraStatus = next((status for status in connectionStatus if status['provider'] == 'jira'), None)
assert jiraStatus, "Jira is missing form connection status"
assert jiraStatus['status'] == "connected", "Jira is not connected"
jiraCollaborationGUID = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name)

Logger.logger.info('get cyberarmor-io site')
projectsResp = self.backend.search_jira_projects({})
projectsResp = self.backend.search_jira_projects(body={'innerFilters': [{'jiraCollabGUID': jiraCollaborationGUID}]})
assert projectsResp, "Jira projects response is empty"
site = next((site for site in projectsResp['availableSites'] if site['name'] == 'cyberarmor-io'), None)
assert site, "cyberarmor-io is missing from available sites"

Logger.logger.info('get Jira System Tests project')
projectsResp = projectsResp = self.backend.search_jira_projects({'innerFilters': [{'siteId': site['id'], 'name': 'Jira System Tests'}]})
projectsResp = projectsResp = self.backend.search_jira_projects({'innerFilters': [{'jiraCollabGUID': jiraCollaborationGUID, 'siteId': site['id'], 'name': 'Jira System Tests'}]})
assert projectsResp, "Jira projects response is empty"
project = next((project for project in projectsResp['projects'] if project['name'] == 'Jira System Tests'), None)
assert project, "Jira System Tests is missing from projects"
Expand All @@ -83,18 +85,24 @@ def setup_jira_config(self):
Logger.logger.info('verify Jira configuration')
config = self.backend.get_jira_config()
assert config, "Jira configuration is empty"
assert config['selectedSite']['name'] == 'cyberarmor-io', "Jira site is not cyberarmor-io"
assert config['projects'][0]['name'] == 'Jira System Tests', "Jira project is not Jira System Tests"
assert 'jiraConnections' in config and isinstance(config['jiraConnections'], list) and config['jiraConnections'], "No Jira connections found in the configuration"
connection = next(
(conn for conn in config['jiraConnections'] if conn.get('selectedSite', {}).get('name') == 'cyberarmor-io'),
None
)
assert connection, "No Jira connection found for site 'cyberarmor-io'"
assert 'projects' in connection and isinstance(connection['projects'], list) and connection['projects'][0]['name'] == 'Jira System Tests', "Jira project is not Jira System Tests"



Logger.logger.info('get jira test issue type')
issueTypesRes = self.backend.search_jira_issue_types({'innerFilters': [{'siteId': site['id'], 'projectId': project['id'], 'name': 'System Test Issue Type'}]})
issueTypesRes = self.backend.search_jira_issue_types({'innerFilters': [{'jiraCollabGUID': jiraCollaborationGUID, 'siteId': site['id'], 'projectId': project['id'], 'name': 'System Test Issue Type'}]})
assert issueTypesRes, "Jira issue types response is empty"
issueType = next((issueType for issueType in issueTypesRes['response'] if issueType['name'] == 'System Test Issue Type'), None)
assert issueType, "System Test Issue Type is missing from issue types"

Logger.logger.info('verify issue type schema')
schema = self.backend.search_jira_schema({'innerFilters': [{
schema = self.backend.search_jira_schema({'innerFilters': [{'jiraCollabGUID': jiraCollaborationGUID,
'siteId': site['id'], 'projectId': project['id'], 'issueTypeId': issueType['id'],
'includeFields': 'summary,description,reporter,labels,assignee,users,user'}]})
assert schema, "Jira schema response is empty"
Expand All @@ -110,6 +118,7 @@ def setup_jira_config(self):
self.project = project
self.issueType = issueType


def setup_cluster_and_run_posture_scan(self):
cluster, namespace = self.setup(apply_services=False)
print("Debug: cluster: ", cluster)
Expand Down Expand Up @@ -145,6 +154,7 @@ def create_jira_issue_for_posture(self):

Logger.logger.info(f"Create Jira issue for resource {resourceHash} and control {controlId}")
issue = self.test_obj["issueTemplate"].copy()
issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name)
issue['siteId'] = self.site['id']
issue['projectId'] = self.project['id']
issue['issueTypeId'] = self.issueType['id']
Expand Down Expand Up @@ -188,6 +198,7 @@ def create_jira_issue_for_security_risks(self):

Logger.logger.info(f"Create Jira issue for resource {resourceHash} and security_risk_id {security_risk_id}")
issue = self.test_obj["issueTemplate"].copy()
issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name)
issue['issueType'] = "securityIssue"
issue['siteId'] = self.site['id']
issue['projectId'] = self.project['id']
Expand Down Expand Up @@ -278,6 +289,7 @@ def wait_for_vuln_results(self):
def create_vuln_tickets(self):
Logger.logger.info('create global ticket for CVE')
issue = self.test_obj["issueTemplate"].copy()
issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name)
issue['issueType'] = "vulnerability"
issue['siteId'] = self.site['id']
issue['projectId'] = self.project['id']
Expand All @@ -288,6 +300,7 @@ def create_vuln_tickets(self):
assert globalCVEicket, "Jira ticket is empty"

Logger.logger.info('create ticket for workload CVE')
issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name)
issue['owner'] = {"cluster": self.vulnWL['cluster'], "namespace": self.vulnWL['namespace'], "kind": self.vulnWL['kind'], "name": self.vulnWL['name']}
issue['fields']['summary'] = f"Jira System Test CVE Issue for workload cluster:{self.cluster} namespace:{self.namespace} image:{self.vulnImage['repository']}"
workloadCVEicket = self.backend.create_jira_issue(issue)
Expand All @@ -298,13 +311,15 @@ def create_vuln_tickets(self):

Logger.logger.info('create global ticket for image')
del issue['owner']
issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name)
issue['issueType'] = "image"
issue['subjects'] = [{"imageRepository": self.vulnImage['repository']}]
issue['fields']['summary'] = f"Jira System Test global Issue image:{self.vulnImage['repository']}"
globalImageTicket = self.backend.create_jira_issue(issue)
assert globalImageTicket, "Jira ticket is empty"

Logger.logger.info('create ticket for image in workload')
issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name)
issue['owner'] = {"cluster": self.vulnWL['cluster'], "namespace": self.vulnWL['namespace'], "kind": self.vulnWL['kind'], "name": self.vulnWL['name']}
issue['fields']['summary'] = f"Jira System Test image Issue for workload cluster:{self.cluster} namespace:{self.namespace} image:{self.vulnImage['repository']}"
workloadImageTicket = self.backend.create_jira_issue(issue)
Expand Down
10 changes: 6 additions & 4 deletions tests_scripts/workflows/jira_workflows.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from tests_scripts.workflows.workflows import Workflows
from tests_scripts.workflows.utils import (
get_env,
NOTIFICATIONS_SVC_DELAY_FIRST_SCAN,
EXPECTED_CREATE_RESPONSE,
JIRA_PROVIDER_NAME,
SECURITY_RISKS,
SECURITY_RISKS_ID,
VULNERABILITIES,
SEVERITIES_CRITICAL,
SEVERITIES_HIGH,
SEVERITIES_MEDIUM,
VULNERABILITIES_WORKFLOW_NAME_JIRA,
Expand All @@ -30,6 +28,7 @@ def __init__(self, test_obj=None, backend=None, kubernetes_obj=None, test_driver
self.fw_name = None
self.cluster = None
self.wait_for_agg_to_end = False
self.site_name = "cyberarmor-io"


def start(self):
Expand All @@ -47,11 +46,13 @@ def start(self):
assert self.backend is not None, f'the test {self.test_driver.test_name} must run with backend'
self.cluster, self.namespace = self.setup(apply_services=False)



Logger.logger.info("Stage 1: Create new workflows")
workflow_body = self.build_securityRisk_workflow_body(name=SECURITY_RISKS_WORKFLOW_NAME_JIRA + self.cluster, severities=SEVERITIES_MEDIUM, jiraCollaborationGUID=get_env("JIRA_COLLABORATION_GUID"), siteId=get_env("JIRA_SITE_ID"), projectId=get_env("JIRA_PROJECT_ID"), cluster=self.cluster, namespace=self.namespace, category=SECURITY_RISKS, securityRiskIDs=SECURITY_RISKS_ID, issueTypeId=get_env("JIRA_ISSUE_TYPE_ID"))
jiraCollaborationGUID = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name)
workflow_body = self.build_securityRisk_workflow_body(name=SECURITY_RISKS_WORKFLOW_NAME_JIRA + self.cluster, severities=SEVERITIES_MEDIUM, jiraCollaborationGUID=jiraCollaborationGUID, siteId=get_env("JIRA_SITE_ID"), projectId=get_env("JIRA_PROJECT_ID"), cluster=self.cluster, namespace=self.namespace, category=SECURITY_RISKS, securityRiskIDs=SECURITY_RISKS_ID, issueTypeId=get_env("JIRA_ISSUE_TYPE_ID"))
self.create_and_assert_workflow(workflow_body, EXPECTED_CREATE_RESPONSE, update=False)
workflow_body = self.build_vulnerabilities_workflow_body(name=VULNERABILITIES_WORKFLOW_NAME_JIRA + self.cluster, severities=SEVERITIES_HIGH, jiraCollaborationGUID=get_env("JIRA_COLLABORATION_GUID"), siteId=get_env("JIRA_SITE_ID"), projectId=get_env("JIRA_PROJECT_ID"), cluster=self.cluster, namespace=self.namespace, category=VULNERABILITIES, cvss=6, issueTypeId=get_env("JIRA_ISSUE_TYPE_ID"))
workflow_body = self.build_vulnerabilities_workflow_body(name=VULNERABILITIES_WORKFLOW_NAME_JIRA + self.cluster, severities=SEVERITIES_HIGH, jiraCollaborationGUID=jiraCollaborationGUID, siteId=get_env("JIRA_SITE_ID"), projectId=get_env("JIRA_PROJECT_ID"), cluster=self.cluster, namespace=self.namespace, category=VULNERABILITIES, cvss=6, issueTypeId=get_env("JIRA_ISSUE_TYPE_ID"))
self.create_and_assert_workflow(workflow_body, EXPECTED_CREATE_RESPONSE, update=False)
before_test_message_ts = time.time()

Expand Down Expand Up @@ -82,6 +83,7 @@ def cleanup(self, **kwargs):
self.delete_and_assert_workflow(self.return_workflow_guid(VULNERABILITIES_WORKFLOW_NAME_JIRA + self.cluster))
return super().cleanup(**kwargs)


def assert_jira_tickets_was_created(self, begin_time, cluster_name, attempts=20, sleep_time=20):

vuln_body = {
Expand Down

0 comments on commit 15eb4d5

Please sign in to comment.