Skip to content

Commit

Permalink
Cypress astra local (#1022)
Browse files Browse the repository at this point in the history
* Added Astra scans to e2e tests
---------

Co-authored-by: ike thecoder <ikethecoder@copeconsulting.ca>
Co-authored-by: Joshua Jones <joshua@general-metrics.com>
Co-authored-by: Elson9 <Elson9@users.noreply.github.com>
Co-authored-by: Russell Vinegar <38586679+rustyjux@users.noreply.github.com>
Co-authored-by: Russell Vinegar <russell.vinegar@gov.bc.ca>
  • Loading branch information
6 people committed Apr 24, 2024
1 parent eb6e63d commit 22446d4
Show file tree
Hide file tree
Showing 28 changed files with 565 additions and 233 deletions.
127 changes: 127 additions & 0 deletions .github/astra-jira.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import os
from datetime import datetime
import json
from pathlib import Path
import requests
from requests.auth import HTTPBasicAuth
import sys

ASTRA_SCAN_RESULTS = os.environ.get('ASTRA_SCAN_RESULTS')

JIRA_EMAIL = os.environ.get('JIRA_EMAIL')
JIRA_API_KEY = os.environ.get('JIRA_API_KEY')
JIRA_API_URL = "https://dpdd.atlassian.net/rest/api/2"
JIRA_AUTH = HTTPBasicAuth(JIRA_EMAIL, JIRA_API_KEY)
HEADERS = {
"Accept": "application/json",
"Content-Type": "application/json"
}

IMPACT_LEVELS = ["Medium", "High"]

date = datetime.now()
date_str = date.strftime("%d %b %Y")
scan_name = f'{date_str} - Astra Scan Results'

def check_results(scan_result):
"""
Check if there are any significant vulnerabilities
"""
vulnerabilities = [vulnerability for sublist in scan_result for vulnerability in sublist]
for vulnerability in vulnerabilities:
if vulnerability["impact"] in IMPACT_LEVELS:
print('Issues found!')
return True

return False

def format_ticket(scan_results):
"""
Converts vulnerabilities into format that can be posted to Jira.
"""
description = 'See attached scan results for more details'
for sublist in scan_results:
for vulnerability in sublist:
if vulnerability["impact"] in IMPACT_LEVELS:
description += f'\n\n*Name: {vulnerability["name"]}*\n'
description += f'Impact: {vulnerability["impact"]}\n'
description += f'Description: {vulnerability["Description"]}\n'
description += f'Remediation: {vulnerability["remediation"]}\n'
description += f'URL: {vulnerability["url"]}\n'

return {'summary': scan_name, 'description': description}

def filter_vulnerabilities(scan_results):
"""
Filter vulnerabilities with medium and high severity to attach.
"""
filtered_vulnerabilities = []

for sublist in scan_results:
for vulnerability in sublist:
if vulnerability["impact"] in IMPACT_LEVELS:
filtered_vulnerabilities.append(vulnerability)

filtered_vulnerabilities_json = json.dumps(filtered_vulnerabilities, indent=4)
filtered_vulnerabilities_bytes = filtered_vulnerabilities_json.encode()

return filtered_vulnerabilities_bytes

def post_request(ticket, scan_results_data):
"""
Post issue request to Jira.
"""
payload = json.dumps({
"fields": {
"project": {
"key": "APS"
},
"summary": ticket['summary'],
"description": ticket['description'],
"issuetype": {
"name": "Story"
},
"customfield_10014": "APS-908",
"priority": {
"id": "10000"
}
}
})

post_url = JIRA_API_URL + '/issue'

response = requests.post(url=post_url, data=payload,
headers=HEADERS, auth=JIRA_AUTH)

print(response.text)

if response.status_code != 201:
print("Error occurred while creating Jira issue:", response.text)
return

# Attach scan results to the Jira issue
issue_key = response.json().get('key')
attach_url = f"{JIRA_API_URL}/issue/{issue_key}/attachments"
headers = {"X-Atlassian-Token": "nocheck"}
filename = scan_name + '.json'
attach_response = requests.post(url=attach_url, files={'file': (filename, scan_results_data)}, headers=headers, auth=JIRA_AUTH)

if attach_response.status_code == 200:
print("Jira issue created and file attached successfully!")
else:
print("Error occurred while attaching file to Jira issue:", attach_response.text)

def main():
with open(ASTRA_SCAN_RESULTS, "r") as file:
scan_results = json.load(file)
vulnerabilities = check_results(scan_results)

if vulnerabilities:
ticket_data = {}
ticket_data = format_ticket(scan_results)
filtered_vulnerabilities = filter_vulnerabilities(scan_results)
post_request(ticket_data, filtered_vulnerabilities)
sys.exit(1)

if __name__ == '__main__':
main()
53 changes: 28 additions & 25 deletions .github/workflows/aps-cypress-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,6 @@ jobs:
- name: Checkout Portal
uses: actions/checkout@v2

# - name: Determine Download file name
# id: set_variable
# run: |
# echo ${{ runner.arch }}
# if [ "${{ runner.arch }}" == "X64" ]; then
# echo "::set-output name=my_variable::gwa_Linux_x86_64.tgz"
# elif [ "${{ runner.arch }}" == "ARM64" ]; then
# echo "::set-output name=my_variable::gwa_Linux_arm64.tgz"
# else
# echo "unsupported architecture"
# fi

# - name: Download Binary
# uses: robinraju/release-downloader@v1.8
# with:
# repository: "bcgov/gwa-cli"
# latest: true
# fileName: ${{ steps.set_variable.outputs.my_variable }}
# out-file-path: "${{ github.workspace }}/e2e"

# - name: Unzip file
# run: |
# cd ${{ github.workspace }}/e2e
# tar xvzf ${{ steps.set_variable.outputs.my_variable }}

- name: Build Docker Images
run: |
docker compose --profile testsuite build
Expand Down Expand Up @@ -89,6 +64,12 @@ jobs:
name: test-results
path: ${{ github.workspace }}/e2e/results/report

- name: Upload E2E Code Coverage Report
uses: actions/upload-artifact@v2
with:
name: code-coverage
path: ${{ github.workspace }}/e2e/coverage

- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
with:
Expand All @@ -113,4 +94,26 @@ jobs:
echo -e "Stats: $STATS\n\nFailed Tests:\n$FAILED_TESTS\n\nRun Link: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" > msg
export MSG=$(cat msg)
gh issue create --title "FAILED: Automated Tests($FAILURE_COUNT)" --body "$MSG" --label "automation" --assignee "${{ env.GIT_COMMIT_AUTHOR }}"
exit 1
fi
- name: Set up Python 3.9
if: failure()
uses: actions/setup-python@v2
with:
python-version: "3.9"
architecture: "x64"

- name: Install Python dependencies
if: failure()
run: |
python -m pip install --upgrade pip
pip install requests
- name: Check Astra results and create Jira issue if necessary
if: failure()
run: python .github/astra-jira.py
env:
JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
JIRA_API_KEY: ${{ secrets.JIRA_API_KEY }}
ASTRA_SCAN_RESULTS: ${{ github.workspace }}/e2e/cypress/fixtures/state/scanResult.json
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ kc.js

# vs code settings
.vscode

e2e/cypress/fixtures/*-plugin.yml
e2e/cypress/fixtures/state/*.pub
e2e/cypress/fixtures/state/*.pem
e2e/cypress/fixtures/state/*.pem
e2e/cypress/fixtures/state/scanResult.json
e2e/cypress/fixtures/state/scanID.json
e2e/cypress/downloads/
28 changes: 27 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,5 +237,31 @@ services:
- aps-net
profiles:
- testsuite
astra-mongo:
image: mongo:4.2.2
container_name: astra-mongo
ports:
- '27017:27017'
networks:
aps-net:
aliases:
- mongo.localtest.me
astra-gui:
build:
context: local/astra
container_name: astra-gui
restart: always
environment:
MONGO_PORT_27017_TCP_ADDR: astra-mongo
networks:
aps-net:
aliases:
- astra.localtest.me
depends_on:
- astra-mongo
links:
- astra-mongo:mongo
ports:
- '8094:8094'
networks:
aps-net: {}
aps-net: {}
3 changes: 2 additions & 1 deletion e2e/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export default defineConfig({
'./cypress/tests/14-*/*.ts',
'./cypress/tests/15-*/*.ts',
'./cypress/tests/16-*/*.ts',
'./cypress/tests/17-*/*.ts'
'./cypress/tests/17-*/*.ts',
'./cypress/tests/18-*/*.ts'
]
return config
},
Expand Down
4 changes: 4 additions & 0 deletions e2e/cypress/fixtures/state/scanID.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"items": [
]
}
Empty file.
44 changes: 39 additions & 5 deletions e2e/cypress/support/auth-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,17 +422,51 @@ Cypress.Commands.add('setAuthorizationToken', (token: string) => {
})

Cypress.Commands.add('makeAPIRequest', (endPoint: string, methodType: string) => {

let body = {}

let requestData: any = {}
if (methodType.toUpperCase() === 'PUT' || methodType.toUpperCase() === 'POST') {
body = requestBody
}
return cy.request({
url: Cypress.env('BASE_URL') + '/' + endPoint,
method: methodType,
body: body,

requestData['appname'] = "Test1"
requestData['url'] = Cypress.env('BASE_URL') + '/' + endPoint
requestData['headers'] = headers
requestData['body'] = ""
requestData['method'] = methodType

// Scan request with Astra
cy.request({
url: 'http://astra.localtest.me:8094/scan/',
method: 'POST',
body: requestData,
headers: headers,
failOnStatusCode: false
}).then((astraResponse) => {
// Actual API request
cy.request({
url: Cypress.env('BASE_URL') + '/' + endPoint,
method: methodType,
body: body,
headers: headers,
failOnStatusCode: false
}).then((apiResponse) => {
// You can also return data or use it in further tests
const responseData = {
astraRes: astraResponse,
apiRes: apiResponse,
};
// cy.addToAstraScanIdList(response2.body.status)
return responseData;
})
});
})

Cypress.Commands.add('makeAPIRequestForScanResult', (scanID: string) => {
return cy.request({
url: 'http://astra.localtest.me:8094/alerts/' + scanID,
method: 'GET',
failOnStatusCode: false
})
})

Expand Down
6 changes: 6 additions & 0 deletions e2e/cypress/support/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,11 @@ declare namespace Cypress {
updateJsonBoby(json: any, key: string, newValue: string):Chainable<any>

deleteFileInE2EFolder(fileName: string):Chainable<any>

addToAstraScanIdList(item: any):Chainable<any>

checkAstraScanResultForVulnerability():Chainable<any>

makeAPIRequestForScanResult(scanID: string): Chainable<Cypress.Response<any>>
}
}
45 changes: 45 additions & 0 deletions e2e/cypress/support/util-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,21 @@ Cypress.Commands.add('deleteFileInE2EFolder', (fileName: string) => {
}
});

Cypress.Commands.add('addToAstraScanIdList', (item) => {
cy.readFile('cypress/fixtures/state/scanID.json').then((fileContent) => {
// Initialize the list if it doesn't exist
const items = fileContent.items || [];

// Append the new item to the list
items.push(item);

// Create an object with the updated list
const updatedData = { items };

// Write the updated object back to the file
cy.writeFile('cypress/fixtures/state/scanID.json', updatedData);
});
});

Cypress.Commands.add('replaceWord', (originalString: string, wordToReplace: string, replacementWord: string)=> {
// Create a regular expression with the 'g' flag for global search
Expand All @@ -180,4 +195,34 @@ Cypress.Commands.add('replaceWord', (originalString: string, wordToReplace: stri
replacedString = originalString.replace(regex, replacementWord);

return replacedString;
})

Cypress.Commands.add('checkAstraScanResultForVulnerability', () => {
let aggregatedData = {};
let existingData: any = [];
let flag = false
cy.readFile('cypress/fixtures/state/scanID.json').then((fileContent) => {
fileContent.items.forEach((item: string) => {
// Perform an action based on each item in the array
cy.makeAPIRequestForScanResult(item).then((response) => {
const newResponse = JSON.parse(JSON.stringify(response.body));
existingData.push(newResponse);
});
});
}).then(() => {
cy.writeFile('cypress/fixtures/state/scanResult.json', JSON.stringify(existingData))
for (var i = 0; i < existingData.length; i++) {
var jsonObject = existingData[i];
for (var j = 0; i < jsonObject.length; i++) {
if (jsonObject[j].hasOwnProperty("impact") &&
["High", "Medium"].includes(jsonObject[j]["impact"])) {
flag = true;
}
}
}
}).then(()=>{
if (flag){
assert.fail("Some of the results have high or medium severity security vulnerabilities. Please check the result file for more details.");
}
})
})
Loading

0 comments on commit 22446d4

Please sign in to comment.