Skip to content

Commit 1c0ca33

Browse files
authored
Merge pull request #1056 from bcgov/test
Cypress updates
2 parents 00556ce + 12edc4b commit 1c0ca33

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+26494
-35977
lines changed

.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ src/.npm
33
src/_tmp
44
src/.cache
55
src/.config
6+
src/.nyc_output
7+
src/dist
68
**/.next
79
_data

.github/astra-jira.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import os
2+
from datetime import datetime
3+
import json
4+
from pathlib import Path
5+
import requests
6+
from requests.auth import HTTPBasicAuth
7+
import sys
8+
9+
ASTRA_SCAN_RESULTS = os.environ.get('ASTRA_SCAN_RESULTS')
10+
11+
JIRA_EMAIL = os.environ.get('JIRA_EMAIL')
12+
JIRA_API_KEY = os.environ.get('JIRA_API_KEY')
13+
JIRA_API_URL = "https://dpdd.atlassian.net/rest/api/2"
14+
JIRA_AUTH = HTTPBasicAuth(JIRA_EMAIL, JIRA_API_KEY)
15+
HEADERS = {
16+
"Accept": "application/json",
17+
"Content-Type": "application/json"
18+
}
19+
20+
IMPACT_LEVELS = ["Medium", "High"]
21+
22+
date = datetime.now()
23+
date_str = date.strftime("%d %b %Y")
24+
scan_name = f'{date_str} - Astra Scan Results'
25+
26+
def check_results(scan_result):
27+
"""
28+
Check if there are any significant vulnerabilities
29+
"""
30+
vulnerabilities = [vulnerability for sublist in scan_result for vulnerability in sublist]
31+
for vulnerability in vulnerabilities:
32+
if vulnerability["impact"] in IMPACT_LEVELS:
33+
print('Issues found!')
34+
return True
35+
36+
return False
37+
38+
def format_ticket(scan_results):
39+
"""
40+
Converts vulnerabilities into format that can be posted to Jira.
41+
"""
42+
description = 'See attached scan results for more details'
43+
for sublist in scan_results:
44+
for vulnerability in sublist:
45+
if vulnerability["impact"] in IMPACT_LEVELS:
46+
description += f'\n\n*Name: {vulnerability["name"]}*\n'
47+
description += f'Impact: {vulnerability["impact"]}\n'
48+
description += f'Description: {vulnerability["Description"]}\n'
49+
description += f'Remediation: {vulnerability["remediation"]}\n'
50+
description += f'URL: {vulnerability["url"]}\n'
51+
52+
return {'summary': scan_name, 'description': description}
53+
54+
def filter_vulnerabilities(scan_results):
55+
"""
56+
Filter vulnerabilities with medium and high severity to attach.
57+
"""
58+
filtered_vulnerabilities = []
59+
60+
for sublist in scan_results:
61+
for vulnerability in sublist:
62+
if vulnerability["impact"] in IMPACT_LEVELS:
63+
filtered_vulnerabilities.append(vulnerability)
64+
65+
filtered_vulnerabilities_json = json.dumps(filtered_vulnerabilities, indent=4)
66+
filtered_vulnerabilities_bytes = filtered_vulnerabilities_json.encode()
67+
68+
return filtered_vulnerabilities_bytes
69+
70+
def post_request(ticket, scan_results_data):
71+
"""
72+
Post issue request to Jira.
73+
"""
74+
payload = json.dumps({
75+
"fields": {
76+
"project": {
77+
"key": "APS"
78+
},
79+
"summary": ticket['summary'],
80+
"description": ticket['description'],
81+
"issuetype": {
82+
"name": "Story"
83+
},
84+
"customfield_10014": "APS-908",
85+
"priority": {
86+
"id": "10000"
87+
}
88+
}
89+
})
90+
91+
post_url = JIRA_API_URL + '/issue'
92+
93+
response = requests.post(url=post_url, data=payload,
94+
headers=HEADERS, auth=JIRA_AUTH)
95+
96+
print(response.text)
97+
98+
if response.status_code != 201:
99+
print("Error occurred while creating Jira issue:", response.text)
100+
return
101+
102+
# Attach scan results to the Jira issue
103+
issue_key = response.json().get('key')
104+
attach_url = f"{JIRA_API_URL}/issue/{issue_key}/attachments"
105+
headers = {"X-Atlassian-Token": "nocheck"}
106+
filename = scan_name + '.json'
107+
attach_response = requests.post(url=attach_url, files={'file': (filename, scan_results_data)}, headers=headers, auth=JIRA_AUTH)
108+
109+
if attach_response.status_code == 200:
110+
print("Jira issue created and file attached successfully!")
111+
else:
112+
print("Error occurred while attaching file to Jira issue:", attach_response.text)
113+
114+
def main():
115+
with open(ASTRA_SCAN_RESULTS, "r") as file:
116+
scan_results = json.load(file)
117+
vulnerabilities = check_results(scan_results)
118+
119+
if vulnerabilities:
120+
ticket_data = {}
121+
ticket_data = format_ticket(scan_results)
122+
filtered_vulnerabilities = filter_vulnerabilities(scan_results)
123+
post_request(ticket_data, filtered_vulnerabilities)
124+
sys.exit(1)
125+
126+
if __name__ == '__main__':
127+
main()

.github/workflows/aps-cypress-e2e.yaml

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Cypress and Execute Tests
33
on:
44
workflow_dispatch: {}
55
push:
6-
branches: ['test', 'cypress*']
6+
branches: ['test', 'cypress/*']
77

88
env:
99
DASHBOARD_PROJECT_ID: ${{ secrets.CY_DASHBOARD_PRJ_ID }}
@@ -28,31 +28,6 @@ jobs:
2828
- name: Checkout Portal
2929
uses: actions/checkout@v2
3030

31-
# - name: Determine Download file name
32-
# id: set_variable
33-
# run: |
34-
# echo ${{ runner.arch }}
35-
# if [ "${{ runner.arch }}" == "X64" ]; then
36-
# echo "::set-output name=my_variable::gwa_Linux_x86_64.tgz"
37-
# elif [ "${{ runner.arch }}" == "ARM64" ]; then
38-
# echo "::set-output name=my_variable::gwa_Linux_arm64.tgz"
39-
# else
40-
# echo "unsupported architecture"
41-
# fi
42-
43-
# - name: Download Binary
44-
# uses: robinraju/release-downloader@v1.8
45-
# with:
46-
# repository: "bcgov/gwa-cli"
47-
# latest: true
48-
# fileName: ${{ steps.set_variable.outputs.my_variable }}
49-
# out-file-path: "${{ github.workspace }}/e2e"
50-
51-
# - name: Unzip file
52-
# run: |
53-
# cd ${{ github.workspace }}/e2e
54-
# tar xvzf ${{ steps.set_variable.outputs.my_variable }}
55-
5631
- name: Build Docker Images
5732
run: |
5833
docker compose --profile testsuite build
@@ -89,15 +64,32 @@ jobs:
8964
name: test-results
9065
path: ${{ github.workspace }}/e2e/results/report
9166

67+
- name: Upload E2E Code Coverage Report
68+
uses: actions/upload-artifact@v2
69+
with:
70+
name: code-coverage
71+
path: ${{ github.workspace }}/e2e/coverage
72+
73+
- name: Instrument the code for coverage analysis
74+
run: |
75+
# Rewrite the paths as the coverage starts with '../app'!
76+
sed -e 's/..\/app/./g' ./e2e/coverage/lcov.info > lcov.info
77+
78+
#cd src
79+
#npm install --legacy-peer-deps
80+
#npx nyc instrument --compact=false . --in-place
81+
9282
- name: SonarCloud Scan
9383
uses: sonarsource/sonarcloud-github-action@master
9484
with:
9585
args: >
9686
-Dsonar.organization=bcgov-oss
9787
-Dsonar.projectKey=aps-portal-e2e
9888
-Dsonar.host.url=https://sonarcloud.io
99-
-Dsonar.sources=src/nextapp
100-
-Dsonar.javascript.lcov.reportPaths=./e2e/coverage/lcov.info
89+
-Dsonar.projectBaseDir=src
90+
-Dsonar.sources=.
91+
-Dsonar.exclusions=nextapp/**,mocks/**,test/**,tools/**,*.json,*.js
92+
-Dsonar.javascript.lcov.reportPaths=/github/workspace/lcov.info
10193
env:
10294
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
10395
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
@@ -113,4 +105,26 @@ jobs:
113105
echo -e "Stats: $STATS\n\nFailed Tests:\n$FAILED_TESTS\n\nRun Link: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" > msg
114106
export MSG=$(cat msg)
115107
gh issue create --title "FAILED: Automated Tests($FAILURE_COUNT)" --body "$MSG" --label "automation" --assignee "${{ env.GIT_COMMIT_AUTHOR }}"
108+
exit 1
116109
fi
110+
111+
- name: Set up Python 3.9
112+
if: failure()
113+
uses: actions/setup-python@v2
114+
with:
115+
python-version: '3.9'
116+
architecture: 'x64'
117+
118+
- name: Install Python dependencies
119+
if: failure()
120+
run: |
121+
python -m pip install --upgrade pip
122+
pip install requests
123+
124+
- name: Check Astra results and create Jira issue if necessary
125+
if: failure()
126+
run: python .github/astra-jira.py
127+
env:
128+
JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
129+
JIRA_API_KEY: ${{ secrets.JIRA_API_KEY }}
130+
ASTRA_SCAN_RESULTS: ${{ github.workspace }}/e2e/cypress/fixtures/state/scanResult.json

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ kc.js
116116

117117
# vs code settings
118118
.vscode
119+
119120
e2e/cypress/fixtures/*-plugin.yml
120121
e2e/cypress/fixtures/state/*.pub
121-
e2e/cypress/fixtures/state/*.pem
122+
e2e/cypress/fixtures/state/*.pem
123+
e2e/cypress/fixtures/state/scanResult.json
124+
e2e/cypress/fixtures/state/scanID.json
125+
e2e/cypress/downloads/

README.md

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,30 @@
22

33
[![Lifecycle:Stable](https://img.shields.io/badge/Lifecycle-Stable-97ca00?style=for-the-badge)](https://github.com/bcgov/repomountie/blob/master/doc/lifecycle-badges.md)
44
[![GitHub Workflow Status (branch)](https://img.shields.io/github/actions/workflow/status/bcgov/api-services-portal/ci-build-deploy.yaml?branch=dev&style=for-the-badge)](https://github.com/bcgov/api-services-portal/actions/workflows/ci-build-deploy.yaml)
5-
[![Coverage](https://img.shields.io/sonar/coverage/aps-portal/dev?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge)](https://sonarcloud.io/summary/new_code?id=aps-portal)
5+
[![Coverage](https://img.shields.io/sonar/coverage/aps-portal-e2e/dev?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge)](https://sonarcloud.io/summary/overall?id=aps-portal-e2e)
66
![GitHub](https://img.shields.io/github/license/bcgov/aps-portal?style=for-the-badge)
77
![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/bcgov/aps-portal?label=release&style=for-the-badge)
88

9-
109
## Introduction
1110

12-
1311
The `API Services Portal` is a frontend for API Providers to manage the lifecycle of their APIs and for Developers to discover and access these APIs. It works in combination with the Kong Community Edition Gateway and Keycloak IAM solution.
1412

15-
1613
## Local Deployment
1714

18-
19-
The repo is setup to create a local deployment of the Portal along with required support services (Postgres, Keycloak, OAuth2-proxy, Feeder and Kong Gateway) using `docker compose`.
15+
The repo is setup to create a local deployment of the Portal along with required support services (Postgres, Keycloak, OAuth2-proxy, Feeder and Kong Gateway) using `docker compose`.
2016

2117
1. Clone and build the [Gateway Admin API](https://github.com/bcgov/gwa-api) (gwa-api)
2218

23-
```
24-
git clone https://github.com/bcgov/gwa-api
25-
cd ./microservices/gatewayApi
26-
docker build -t gwa-api:e2e .
27-
```
19+
```
20+
git clone https://github.com/bcgov/gwa-api
21+
cd ./microservices/gatewayApi
22+
docker build -t gwa-api:e2e .
23+
```
2824

2925
1. Build: Back in `api-services-portal`, run `docker compose build`.
3026
1. Run: `docker compose up`. Wait for startup to complete - look for `Swagger UI registered`.
3127
1. The Portal is now live at http://oauth2proxy.localtest.me:4180
32-
1. To login, use username `janis@idir` and password `awsummer` (or username `local` and password `local`).
28+
1. To login, use username `janis@idir` and password `awsummer` (or username `local` and password `local`).
3329
1. If you have made any changes to the app code, update images by running `docker compose build` then `docker compose up`.
3430
1. Clean up: `docker compose down` removes all the hosted services
3531

@@ -68,40 +64,39 @@ Use the following configuration to run the Portal locally (outside of Docker) ag
6864

6965
1. Follow [local deployment instructions](#local-deployment) and run `docker compose up`.
7066
1. In `/src` run `npm install`.
71-
1. If using Node version > 17, run `npm install --legacy-peer-deps`
67+
68+
1. If using Node version > 17, run `npm install --legacy-peer-deps`
7269

7370
1. Turn off the docker compose Portal: `docker stop apsportal`
7471
1. Configure the `oauth2-proxy` that is running in Docker:
75-
1. Update `upstreams` in `local/oauth2-proxy/oauth2-proxy-local.cfg` to include the IP address of your local machine, e.g. `upstreams=["http://172.100.100.01:3000"]`
76-
<br>You can obtain the IP address using `hostname -I`.
77-
78-
1. Restart the oauth2-proxy: `docker compose restart oauth2-proxy`
79-
1. Update `DESTINATION_URL` in `local/feeds/.env.local` to include the IP address of your local machine
80-
1. Restart the feeder: `docker compose restart feeder`
81-
1. Update `PORTAL_ACTIVITY_URL` in `local/gwa-api/.env.local` to include the IP address of your local machine
82-
1. Restart the feeder: `docker compose restart gwa-api`
83-
84-
72+
73+
1. Update `upstreams` in `local/oauth2-proxy/oauth2-proxy-local.cfg` to include the IP address of your local machine, e.g. `upstreams=["http://172.100.100.01:3000"]`
74+
<br>You can obtain the IP address using `hostname -I`.
75+
76+
1. Restart the oauth2-proxy: `docker compose restart oauth2-proxy`
77+
1. Update `DESTINATION_URL` in `local/feeds/.env.local` to include the IP address of your local machine
78+
1. Restart the feeder: `docker compose restart feeder`
79+
1. Update `PORTAL_ACTIVITY_URL` in `local/gwa-api/.env.local` to include the IP address of your local machine
80+
1. Restart the feeder: `docker compose restart gwa-api`
81+
8582
1. Start the Portal locally:
8683

87-
```sh
88-
cd src
89-
set -o allexport
90-
source ../.env.local
91-
LOG_LEVEL=debug
92-
KNEX_HOST=kong-db.localtest.me
93-
NEXT_PUBLIC_MOCKS=off
94-
set +o allexport
84+
```sh
85+
cd src
86+
set -o allexport
87+
source ../.env.local
88+
LOG_LEVEL=debug
89+
KNEX_HOST=kong-db.localtest.me
90+
NEXT_PUBLIC_MOCKS=off
91+
set +o allexport
9592

96-
npm run dev
97-
```
93+
npm run dev
94+
```
9895

9996
1. The Portal is now live at http://oauth2proxy.localtest.me:4180 and should auto-update on code changes.
10097

101-
10298
## Design
10399

104-
105100
The `API Services Portal` is a React application using the Chakra UI component library, and using two frameworks: KeystoneJS V5, and NextJS.
106101

107102
The application is divided up into the following six components:
@@ -176,10 +171,8 @@ Currently support feeders:
176171

177172
Source: `feeds`
178173

179-
180174
## Development
181175

182-
183176
### TypeScript
184177

185178
The client-side Next.js application uses TypeScript, and because it plays nicely with GraphQL types, uses a codegen to generate the API types.

0 commit comments

Comments
 (0)