diff --git a/Integrations/IriusRisk Github Issue Tracker Integration/GHSetup.py b/Integrations/IriusRisk Github Issue Tracker Integration/GHSetup.py new file mode 100644 index 0000000..e171bbd --- /dev/null +++ b/Integrations/IriusRisk Github Issue Tracker Integration/GHSetup.py @@ -0,0 +1,27 @@ +import requests + +class GithubIssueTracker: + def __init__(self, owner, repo, personal_access_token): + self.owner = owner + self.repo = repo + self.token = personal_access_token + self.base_url = f"https://api.github.com/repos/{owner}/{repo}/issues" + self.headers = { + "Authorization": f"Bearer {self.token}", + "Accept": "application/vnd.github+json" + } + + def create_issue(self, title, body, assignees=None, milestone=None, labels=None): + data = { + "title": title, + "body": body + } + if assignees: + data["assignees"] = assignees + if milestone: + data["milestone"] = milestone + if labels: + data["labels"] = labels + + response = requests.post(self.base_url, headers=self.headers, json=data) + return response diff --git a/Integrations/IriusRisk Github Issue Tracker Integration/GH_POST.py b/Integrations/IriusRisk Github Issue Tracker Integration/GH_POST.py new file mode 100644 index 0000000..399c764 --- /dev/null +++ b/Integrations/IriusRisk Github Issue Tracker Integration/GH_POST.py @@ -0,0 +1,91 @@ +import requests +import config +import GHSetup + +def main(): + # Initialize the GitHub issue tracker + issue_tracker = GHSetup.GithubIssueTracker(config.owner, config.repo, config.personal_access_token) + + response = requests.get(config.domain + config.sub_url_api_v2, headers={'api-token': config.apitoken}) + + #print(response.json()) + + + if response.status_code == 200: + projects = response.json() + for project in projects['_embedded']['items']: + + #check project CF value + for cf in project['customFields']: + if cf['customField']['name'] == "IssueTrackerType": + if cf['value'] == "Github": + + project_id = project['id'] + project_url = f"{config.domain}/api/v2/projects/{project_id}/countermeasures" + + # Fetch detailed project data + response = requests.get(project_url, headers={'api-token': config.apitoken}) + if response.status_code == 200: + countermeasures = response.json() + for countermeasure in countermeasures['_embedded']['items']: + if countermeasure['state'] == 'required': + countermeasure_id = countermeasure['id'] + url = f"{config.domain}/api/v2/projects/countermeasures/{countermeasure_id}/references" + + # Fetch detailed reference data for the countermeasure + response = requests.get(url, headers={'api-token': config.apitoken}) + references = response.json() + + reference_found = False # Flag to track if 'Github Issue Link' is found + if response.status_code == 200: + for reference in references['_embedded']['items']: + if reference['name'] == "Github Issue Link": + reference_found = True + break + + if not reference_found: + # Perform the logic to create the link since it doesn't exist + title = f"Countermeasure ref: {countermeasure['referenceId']}" + body = f"Description: {countermeasure['description']}\nState: {countermeasure['state']}" + labels = ["bug"] + + response = issue_tracker.create_issue(title, body, None, None, labels) + if response.status_code == 201: + GH_response = response.json() + new_issue_link = GH_response['html_url'] + new_issue_link_api = GH_response['url'] + + # PUT new data + sub_url = '/api/v2/projects/countermeasures/references' + url = config.domain + sub_url + + # JSON Body to pass to PUT request + myobjs = [ + { + "countermeasure": { + "id": countermeasure_id + }, + "name": "Github Issue Link", + "url": new_issue_link + }, + {"countermeasure": { + "id": countermeasure_id + }, + "name": "Github Issue Link - API", + "url": new_issue_link_api + } + ] + for myobj in myobjs: + # Send PUT request + response = requests.post(url, headers={'api-token': config.apitoken}, json=myobj) + if response.status_code == 201: + print('Successful post') + else: + print(response.text) + else: + print(f"Failed to create issue. Status Code: {response.status_code}") + else: + print(f"Failed to retrieve projects. Status Code: {response.status_code}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Integrations/IriusRisk Github Issue Tracker Integration/GH_sync.py b/Integrations/IriusRisk Github Issue Tracker Integration/GH_sync.py new file mode 100644 index 0000000..cba100a --- /dev/null +++ b/Integrations/IriusRisk Github Issue Tracker Integration/GH_sync.py @@ -0,0 +1,71 @@ +import requests +import config + +def extract_core_message(comment): + """Strip any user context and return the core message.""" + parts = comment.split(' commented: ') + if len(parts) > 1: + return parts[1].strip() + return parts[0].strip() + +def sync_comments(): + # Get projects from IriusRisk + projects_response = requests.get(config.domain + config.sub_url_api_v2, headers={'api-token': config.apitoken}) + if projects_response.status_code == 200: + projects = projects_response.json() + for project in projects['_embedded']['items']: + for cf in project['customFields']: + if cf['customField']['name'] == "IssueTrackerType" and cf['value'] == "Github": + project_id = project['id'] + # Get countermeasures for the project + countermeasures_response = requests.get(f"{config.domain}/api/v2/projects/{project_id}/countermeasures", headers={'api-token': config.apitoken}) + if countermeasures_response.status_code == 200: + countermeasures = countermeasures_response.json() + for countermeasure in countermeasures['_embedded']['items']: + if countermeasure['state'] == 'required': + countermeasure_id = countermeasure['id'] + # Get references to find Github API URL + references_response = requests.get(f"{config.domain}/api/v2/projects/countermeasures/{countermeasure_id}/references", headers={'api-token': config.apitoken}) + references = references_response.json() + for reference in references['_embedded']['items']: + if reference['name'] == "Github Issue Link - API": + GH_API_url = reference['url'] + + # Fetch comments from Github + GH_comments_response = requests.get(GH_API_url + '/comments', headers=config.GH_head) + GH_comments = GH_comments_response.json() + + # Fetch comments from IriusRisk + IR_comments_response = requests.get(f"{config.domain}/api/v2/projects/countermeasures/{countermeasure_id}/comments", headers={'api-token': config.apitoken}) + IR_comments = IR_comments_response.json() + + # Prepare comments for sync + GH_comments_dict = {extract_core_message(comm['body']): f"{comm['user']['login']} commented: {comm['body']}" for comm in GH_comments} + IR_comments_dict = {extract_core_message(comm['comment']): f"{comm['user']['username']} commented: {comm['comment']}" for comm in IR_comments['_embedded']['items']} + + # Sync from Github to IriusRisk + for core_message, full_message in GH_comments_dict.items(): + if core_message not in IR_comments_dict: + print(f"Posting to IriusRisk: '{full_message}'") + post_to_iriusrisk(full_message, countermeasure_id) + + # Sync from IriusRisk to Github + for core_message, full_message in IR_comments_dict.items(): + if core_message not in GH_comments_dict: + print(f"Posting to Github: '{full_message}'") + post_to_github(full_message, GH_API_url) + +def post_to_iriusrisk(comment, countermeasure_id): + data = {"countermeasure": {"id": countermeasure_id}, "comment": comment} + response = requests.post(f"{config.domain}/api/v2/projects/countermeasures/comments", headers={'api-token': config.apitoken}, json=data) + if response.status_code == 200: + print('Comment added to IriusRisk') + +def post_to_github(comment, api_url): + data = {"body": comment} + response = requests.post(api_url + '/comments', headers=config.GH_head, json=data) + if response.status_code == 201: + print('Comment added to Github') + +if __name__ == "__main__": + sync_comments() diff --git a/Integrations/IriusRisk Github Issue Tracker Integration/config.py b/Integrations/IriusRisk Github Issue Tracker Integration/config.py new file mode 100644 index 0000000..6fbed7e --- /dev/null +++ b/Integrations/IriusRisk Github Issue Tracker Integration/config.py @@ -0,0 +1,12 @@ +#----IriusRisk---- +domain = 'https://.iriusrisk.com' +sub_url = '/api/v1/products' #initialise +sub_url_api_v2 = '/api/v2/projects' +apitoken = '' #IriusRisk API token +head = {'api-token': apitoken} + +#----Github---- +owner = "" #GH org +repo = "" #GH project +personal_access_token = "" #GH Personal access token +GH_head = {'Authorization': 'Bearer ' + personal_access_token} \ No newline at end of file