From d4fb97bf0dab2ccfcd57426923bb8f0dccea9ea7 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 10:13:31 -0700 Subject: [PATCH 001/155] initial setup of automation solution with a login test --- e2e/.eslintrc.json | 35 ++++++++++++++ e2e/.gitignore | 3 ++ e2e/.prettierrc | 14 ++++++ e2e/Dockerfile | 10 ++++ e2e/READEME.md | 66 +++++++++++++++++++++++++++ e2e/cypress.env.local.json | 6 +++ e2e/cypress.json | 8 ++++ e2e/cypress/support/api-commands.ts | 8 ++++ e2e/cypress/support/commands.ts | 25 ++++++++++ e2e/cypress/support/global.d.ts | 11 +++++ e2e/cypress/support/index.ts | 4 ++ e2e/cypress/support/login-commands.ts | 38 +++++++++++++++ e2e/cypress/tests/login.spec.ts | 19 ++++++++ e2e/docker-compose.yml | 10 ++++ e2e/package.json | 27 +++++++++++ e2e/tsconfig.json | 11 +++++ 16 files changed, 295 insertions(+) create mode 100644 e2e/.eslintrc.json create mode 100644 e2e/.gitignore create mode 100644 e2e/.prettierrc create mode 100644 e2e/Dockerfile create mode 100644 e2e/READEME.md create mode 100644 e2e/cypress.env.local.json create mode 100644 e2e/cypress.json create mode 100644 e2e/cypress/support/api-commands.ts create mode 100644 e2e/cypress/support/commands.ts create mode 100644 e2e/cypress/support/global.d.ts create mode 100644 e2e/cypress/support/index.ts create mode 100644 e2e/cypress/support/login-commands.ts create mode 100644 e2e/cypress/tests/login.spec.ts create mode 100644 e2e/docker-compose.yml create mode 100644 e2e/package.json create mode 100644 e2e/tsconfig.json diff --git a/e2e/.eslintrc.json b/e2e/.eslintrc.json new file mode 100644 index 000000000..09f75e2b9 --- /dev/null +++ b/e2e/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "prettier/@typescript-eslint", + "plugin:prettier/recommended", + "plugin:cypress/recommended", + "plugin:chai-friendly/recommended" + ], + "plugins": ["@typescript-eslint", "prettier", "cypress", "chai-friendly"], + "env": { + "browser": true, + "node": true, + "commonjs": true, + "es6": true, + "cypress/globals": true + }, + "rules": { + "prettier/prettier": [ + "error", + { "singleQuote": true, "semi": false, "printWidth": 90, "endOfLine": "auto" } + ], + "no-useless-catch": "off", + "no-unused-expressions": 0, + "@typescript-eslint/camelcase": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "cypress/no-assigning-return-values": "error", + "cypress/no-unnecessary-waiting": "error", + "cypress/assertion-before-screenshot": "warn", + "cypress/no-force": "warn", + "cypress/no-async-tests": "error", + "chai-friendly/no-unused-expressions": 2 + }, + "parser": "@typescript-eslint/parser" +} diff --git a/e2e/.gitignore b/e2e/.gitignore new file mode 100644 index 000000000..3138a5752 --- /dev/null +++ b/e2e/.gitignore @@ -0,0 +1,3 @@ +integration +*-lock.json +cypress.env.json \ No newline at end of file diff --git a/e2e/.prettierrc b/e2e/.prettierrc new file mode 100644 index 000000000..1385df39a --- /dev/null +++ b/e2e/.prettierrc @@ -0,0 +1,14 @@ + +{ + "semi": false, + "singleQuote": true, + "printWidth": 90, + "overrides": [ + { + "files": "*.spec.ts", + "options": { + "printWidth": 120 + } + } + ] + } \ No newline at end of file diff --git a/e2e/Dockerfile b/e2e/Dockerfile new file mode 100644 index 000000000..175fc533b --- /dev/null +++ b/e2e/Dockerfile @@ -0,0 +1,10 @@ +FROM cypress/included:3.2.0 + +COPY . /e2e + +RUN npm install + +CMD [ "cy:run" ] + +ENTRYPOINT [ "npm", "run" ] + diff --git a/e2e/READEME.md b/e2e/READEME.md new file mode 100644 index 000000000..82198eb57 --- /dev/null +++ b/e2e/READEME.md @@ -0,0 +1,66 @@ +# End-to-End Test Automation + +This repository contains a testing solution, with the tests written in Cypress. + +Additionally this app is configured to run tests locally and Docker. + +The tests are written to be directly compared to the official API Services Portal tests. + +Each test covers the same functionality found in the official API Services Portal tests but utilizes the Cypress API. + +## Help + Testing + +The steps below will take you all the way through Cypress. It is assumed you have nothing installed except for node + git. + +**If you get stuck, here is more help:** + +- [Gitter Channel](https://gitter.im/cypress-io/cypress) +- [Cypress Docs](https://on.cypress.io) +- [Cypress CLI Tool Docs](https://github.com/cypress-io/cypress-cli) + +### 1. Install Cypress + +[Follow these instructions to install Cypress.](https://docs.cypress.io/guides/getting-started/installing-cypress) + +### 2. Run Tests + +* Clone this repository +* Create a new file `cypress.env.json` from `cypress.env.local.json` + +#### Locally + +* Run `npm install` to install all the dependencies +* Run `npm run cy:run` to run the tests + +#### Docker + +#### Docker Compose + +#### GitHub Actions + + + +## Cypress IntelliSense + +If you use modern IDE that supports TypeScript (like VSCode), you can benefit +from Cypress type declarations included with the `cypress` NPM module. Just +add `@ts-check` to the spec file and configure "dummy" +[tsconfig.json](tsconfig.json) file and see IntelliSense over `cy.` +commands. + +### Custom commands + +* This project also adds several custom commands in [cypress/support/index.js](cypress/support/index.ts). +* To let TypeScript compiler know that we have added a custom command and have IntelliSense working, I have described the type signature of the custom command in file [cypress/support/global.d.ts](cypress/support/global.d.ts). +* To include the new ".d.ts" file into IntelliSense, I could update `tsconfig.json` or I could add another special comment to the JavaScript spec files - `/// + +// type definitions for custom commands will resolve to "cypress/support/global.d.ts" +/// +``` + +**Related:** [IntelliSense for custom Chai assertions added to Cypress](https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/extending-cypress__chai-assertions#code-completion) + diff --git a/e2e/cypress.env.local.json b/e2e/cypress.env.local.json new file mode 100644 index 000000000..0afacafa3 --- /dev/null +++ b/e2e/cypress.env.local.json @@ -0,0 +1,6 @@ +{ + "oidc-issuer": "https://authz-apps-gov-bc-ca.dev.api.gov.bc.ca/auth/realms/aps-v2", + "tests-env": "dev", + "username": "", + "password": "" +} diff --git a/e2e/cypress.json b/e2e/cypress.json new file mode 100644 index 000000000..f0ec5afa2 --- /dev/null +++ b/e2e/cypress.json @@ -0,0 +1,8 @@ +{ + "baseUrl": "https://api-services-portal-dev.apps.silver.devops.gov.bc.ca", + "integrationFolder": "cypress/tests", + "screenshotOnRunFailure": false, + "video": false, + "defaultCommandTimeout": 1000, + "requestTimeout": 1000 +} diff --git a/e2e/cypress/support/api-commands.ts b/e2e/cypress/support/api-commands.ts new file mode 100644 index 000000000..4a79b87d5 --- /dev/null +++ b/e2e/cypress/support/api-commands.ts @@ -0,0 +1,8 @@ +Cypress.Commands.add('callApi', (options: any) => { + cy.request({ + ...options, + }).then((res) => { + expect([200, 201]).to.contain(res.status) + cy.wrap(res) + }) +}) diff --git a/e2e/cypress/support/commands.ts b/e2e/cypress/support/commands.ts new file mode 100644 index 000000000..119ab03f7 --- /dev/null +++ b/e2e/cypress/support/commands.ts @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts new file mode 100644 index 000000000..cf361fce9 --- /dev/null +++ b/e2e/cypress/support/global.d.ts @@ -0,0 +1,11 @@ +/// + +declare namespace Cypress { + interface Chainable { + loginToDev(username: string, password: string): Chainable + + verifySession(url: string): Chainable + + callApi(options: Partial): Chainable> + } +} diff --git a/e2e/cypress/support/index.ts b/e2e/cypress/support/index.ts new file mode 100644 index 000000000..15b04314a --- /dev/null +++ b/e2e/cypress/support/index.ts @@ -0,0 +1,4 @@ +import './commands' +import 'cypress-xpath' +import './login-commands' +import './api-commands' diff --git a/e2e/cypress/support/login-commands.ts b/e2e/cypress/support/login-commands.ts new file mode 100644 index 000000000..0c2d42b9e --- /dev/null +++ b/e2e/cypress/support/login-commands.ts @@ -0,0 +1,38 @@ +Cypress.Commands.add('loginToDev', (username, password) => { + const oidcProviderURL = new URL(Cypress.env('oidc-issuer')) + const appURL = new URL(Cypress.config('baseUrl')) + + cy.location().should((loc) => { + expect(loc.protocol).to.eq(oidcProviderURL.protocol) + expect(loc.hostname).to.eq(oidcProviderURL.hostname) + }) + + Cypress.log({ + name: 'Login to Dev', + displayName: 'LOGIN_DEV', + message: [`🔐 Authenticating | ${username}`], + }) + + cy.get('#username').type(username) + cy.get('#password').type(password) + cy.get('#kc-login').click() + + cy.location().should((loc) => { + expect(loc.protocol).to.eq(appURL.protocol) + expect(loc.hostname).to.eq(appURL.hostname) + }) +}) + +Cypress.Commands.add('verifySession', (url: string) => { + cy.callApi({ method: 'GET', url: url }).then((res) => { + expect(res.body).to.include({ + anonymous: false, + }) + Cypress.log({ + name: 'Session Info', + displayName: 'SESSION_INFO', + message: JSON.stringify(res.body), + }) + cy.log('Session established successfully') + }) +}) diff --git a/e2e/cypress/tests/login.spec.ts b/e2e/cypress/tests/login.spec.ts new file mode 100644 index 000000000..77b6af042 --- /dev/null +++ b/e2e/cypress/tests/login.spec.ts @@ -0,0 +1,19 @@ +describe('aps portal login page', () => { + beforeEach(() => { + cy.visit('/') + }) + + it('displays login button', () => { + cy.xpath('//button').contains('Login') + }) + + it('login into portal', () => { + cy.xpath("//button[normalize-space()='Login']").click() + const oidcProviderURL = new URL(Cypress.env('oidc-issuer')) + + if (Cypress.env('tests-env') === 'dev') { + cy.loginToDev(Cypress.env('username'), Cypress.env('password')) + cy.verifySession(Cypress.config('baseUrl') + '/admin/session') + } + }) +}) diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml new file mode 100644 index 000000000..f2b52664c --- /dev/null +++ b/e2e/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3.2' + +services: + cypress: + image: 'cypress/included:3.2.0' + container_name: cypress-e2e + command: npm run cy:run + working_dir: /e2e + volumes: + - ./:/e2e diff --git a/e2e/package.json b/e2e/package.json new file mode 100644 index 000000000..256e9c0fe --- /dev/null +++ b/e2e/package.json @@ -0,0 +1,27 @@ +{ + "name": "bcgov-aps-portal-e2e", + "version": "1.0.0", + "description": "End to End and Integration Tests for APS Portal", + "main": "index.js", + "author": "BC Gov APS", + "license": "MIT", + "scripts": { + "cy:open": "cypress open", + "cy:run": "cypress run --config watchForFileChanges=false" + }, + "devDependencies": { + "@cypress/code-coverage": "^3.9.8", + "@cypress/instrument-cra": "^1.4.0", + "@typescript-eslint/eslint-plugin": "^4.28.1", + "@typescript-eslint/parser": "^4.28.1", + "cypress": "^7.6.0", + "cypress-xpath": "^1.6.2", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-chai-friendly": "^0.7.1", + "eslint-plugin-cypress": "^2.11.3", + "eslint-plugin-import": "^2.23.4", + "eslint-plugin-prettier": "^3.4.0", + "prettier": "^2.3.2", + "typescript": "^4.3.5" + } +} diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json new file mode 100644 index 000000000..5d3536730 --- /dev/null +++ b/e2e/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["es5", "dom", "ES2015"], + "types": ["cypress"], + "allowJs": true + }, + "include": ["./cypress/**/*.ts"], + "exclude": [], + "noEmit": true +} From fb39c2b4c6a1492a5cf7cf99edbb25df1fd1aa3a Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 10:23:19 -0700 Subject: [PATCH 002/155] Adding a sample plugin index file --- e2e/cypress/plugins/index.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 e2e/cypress/plugins/index.js diff --git a/e2e/cypress/plugins/index.js b/e2e/cypress/plugins/index.js new file mode 100644 index 000000000..fd170fba6 --- /dev/null +++ b/e2e/cypress/plugins/index.js @@ -0,0 +1,17 @@ +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} From b6166c4f4467d505de30acb618d51f05cb8e34c1 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 10:24:57 -0700 Subject: [PATCH 003/155] Updating it to ts --- e2e/cypress/plugins/{index.js => index.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename e2e/cypress/plugins/{index.js => index.ts} (100%) diff --git a/e2e/cypress/plugins/index.js b/e2e/cypress/plugins/index.ts similarity index 100% rename from e2e/cypress/plugins/index.js rename to e2e/cypress/plugins/index.ts From 08695159e4fc1e9baea811da3264e77b8eec6380 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 12:44:17 -0700 Subject: [PATCH 004/155] updated docker file and compose to run the e2e as a service locally --- e2e/Dockerfile | 16 +++++++++------- e2e/cypress.json | 6 +++++- e2e/cypress/tests/login.spec.ts | 6 +++--- e2e/docker-compose.yml | 11 ++++++----- e2e/package.json | 10 ++++++---- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 175fc533b..8033e548a 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -1,10 +1,12 @@ -FROM cypress/included:3.2.0 +FROM cypress/included:7.6.0 -COPY . /e2e +COPY cypress.json . +COPY cypress.env.json . +COPY tsconfig.json . +COPY package.json . +COPY package-lock.json . +COPY ./cypress/ cypress -RUN npm install - -CMD [ "cy:run" ] - -ENTRYPOINT [ "npm", "run" ] +RUN npm ci --production +CMD [ "--config-file", "./cypress.json" ] \ No newline at end of file diff --git a/e2e/cypress.json b/e2e/cypress.json index f0ec5afa2..a8210bc9f 100644 --- a/e2e/cypress.json +++ b/e2e/cypress.json @@ -4,5 +4,9 @@ "screenshotOnRunFailure": false, "video": false, "defaultCommandTimeout": 1000, - "requestTimeout": 1000 + "requestTimeout": 1000, + "reporter": "junit", + "reporterOptions": { + "toConsole": true + } } diff --git a/e2e/cypress/tests/login.spec.ts b/e2e/cypress/tests/login.spec.ts index 77b6af042..27d913429 100644 --- a/e2e/cypress/tests/login.spec.ts +++ b/e2e/cypress/tests/login.spec.ts @@ -1,13 +1,13 @@ -describe('aps portal login page', () => { +describe('User navigates aps portal login page and', () => { beforeEach(() => { cy.visit('/') }) - it('displays login button', () => { + it('finds login button', () => { cy.xpath('//button').contains('Login') }) - it('login into portal', () => { + it('enter credentials to login into portal', () => { cy.xpath("//button[normalize-space()='Login']").click() const oidcProviderURL = new URL(Cypress.env('oidc-issuer')) diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index f2b52664c..679e42cb4 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -2,9 +2,10 @@ version: '3.2' services: cypress: - image: 'cypress/included:3.2.0' + image: 'aps-cypress-e2e:latest' container_name: cypress-e2e - command: npm run cy:run - working_dir: /e2e - volumes: - - ./:/e2e + build: + context: . + dockerfile: Dockerfile + # environment: + # DEBUG: cypress:* - Writes complete log diff --git a/e2e/package.json b/e2e/package.json index 256e9c0fe..87b787a23 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -10,18 +10,20 @@ "cy:run": "cypress run --config watchForFileChanges=false" }, "devDependencies": { - "@cypress/code-coverage": "^3.9.8", - "@cypress/instrument-cra": "^1.4.0", "@typescript-eslint/eslint-plugin": "^4.28.1", "@typescript-eslint/parser": "^4.28.1", "cypress": "^7.6.0", - "cypress-xpath": "^1.6.2", "eslint-config-prettier": "^8.3.0", "eslint-plugin-chai-friendly": "^0.7.1", "eslint-plugin-cypress": "^2.11.3", "eslint-plugin-import": "^2.23.4", "eslint-plugin-prettier": "^3.4.0", - "prettier": "^2.3.2", + "prettier": "^2.3.2" + }, + "dependencies": { + "@cypress/code-coverage": "^3.9.8", + "@cypress/instrument-cra": "^1.4.0", + "cypress-xpath": "^1.6.2", "typescript": "^4.3.5" } } From 5c77863a018cba4001e9c23d57fc36d78fe081e6 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 13:00:34 -0700 Subject: [PATCH 005/155] Updated the readme with docker instructions --- e2e/READEME.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/e2e/READEME.md b/e2e/READEME.md index 82198eb57..3a8dcfac8 100644 --- a/e2e/READEME.md +++ b/e2e/READEME.md @@ -27,18 +27,24 @@ The steps below will take you all the way through Cypress. It is assumed you hav * Clone this repository * Create a new file `cypress.env.json` from `cypress.env.local.json` -#### Locally +#### 2.1 Locally * Run `npm install` to install all the dependencies * Run `npm run cy:run` to run the tests -#### Docker +#### 2.2 Docker -#### Docker Compose +* Run `docker build -t aps-cypress-e2e:latest ` to build an image +* Run `docker run --rm -it -name aps-cypress-e2e aps-cypress-e2e:latest` to spin up a container to run the tests -#### GitHub Actions +#### 2.3 Docker Compose +* Run `docker-compose up` to spin a container that run cypress as a service and it executes the tests +* Run `docker-compose down` to tear down the container +#### 2.4 GitHub Actions + +* Any new commit pushed to `feature` branch would trigger a job and deploys a container and it executes the tests ## Cypress IntelliSense From c3cae4fef50f790899202aca3b7e510b78f5b064 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 13:36:22 -0700 Subject: [PATCH 006/155] Added a github workflow to build and deploy to an openshift container --- .github/workflows/ci-build-deploy-e2e.yaml | 122 +++++++++++++++++++++ e2e/READEME.md | 25 ++--- 2 files changed, 134 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/ci-build-deploy-e2e.yaml diff --git a/.github/workflows/ci-build-deploy-e2e.yaml b/.github/workflows/ci-build-deploy-e2e.yaml new file mode 100644 index 000000000..94ecb45fa --- /dev/null +++ b/.github/workflows/ci-build-deploy-e2e.yaml @@ -0,0 +1,122 @@ +name: Build and Deploy Cypress and Execute Tests + +on: + push: + branches: + - 'util/automation-*' + +env: + REGISTRY: docker.pkg.github.com + REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Docker meta + id: docker_meta + uses: docker/metadata-action@v3 + with: + images: ${{ env.REGISTRY }}/bcgov/api-services-portal/aps-cypress-e2e + + - name: Set DEPLOY_ID which will deploy a custom deploy to 'dev' environment + run: | + echo '::set-output name=DEPLOY_ID::${{ steps.docker_meta.outputs.version }}' + echo '::set-output name=APP_VERSION::${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.version'] }}' + echo '::set-output name=APP_REVISION::${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.revision'] }}' + id: set-deploy-id + + - name: Get deploy ID + run: echo "The DEPLOY_ID is ${{ steps.set-deploy-id.outputs.DEPLOY_ID }}" + + - uses: actions/checkout@v2 + + - name: Install oc + uses: redhat-actions/oc-installer@v1 + with: + version: '4.6' + + - name: Authenticate and set context + uses: redhat-actions/oc-login@v1 + with: + openshift_server_url: ${{ secrets.OPENSHIFT_SERVER }} + openshift_token: ${{ secrets.OPENSHIFT_TOKEN }} + + # Disables SSL cert checking. Use this if you don't have the certificate authority data. + insecure_skip_tls_verify: true + + namespace: ${{ env.OPENSHIFT_NAMESPACE }} + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ env.REGISTRY_USERNAME }} + password: ${{ env.REGISTRY_PASSWORD }} + + - uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v1 + + - name: Build + uses: docker/build-push-action@v2 + with: + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + context: ./e2e + file: Dockerfile + tags: ${{ steps.docker_meta.outputs.tags }} + load: true + build-args: | + GITHUB_API_TOKEN=${{ secrets.CONTAINER_REGISTRY_PASSWORD }} + APP_VERSION=${{ steps.set-deploy-id.outputs.APP_VERSION }} + APP_REVISION=${{ steps.set-deploy-id.outputs.APP_REVISION }} + + - name: Push + run: docker push ${{ steps.docker_meta.outputs.tags }} + + - name: 'Get Helm' + run: | + curl -L -O https://get.helm.sh/helm-v3.4.2-linux-amd64.tar.gz + tar -xf helm-v3.4.2-linux-amd64.tar.gz + + - name: 'Deploy e2e Testing Suite' + run: | + export PATH=$PATH:`pwd`/linux-amd64 + + echo " + podAnnotations: + sha: $GITHUB_SHA + + replicaCount: 1 + + rollingUpdate: + maxUnavailable: 50% + maxSurge: 50% + + image: + repository: ${{ env.REGISTRY }}/bcgov/api-services-portal/aps-cypress-e2e + tag: ${{ steps.set-deploy-id.outputs.DEPLOY_ID }} + pullPolicy: Always + + imagePullSecrets: + - name: dev-github-read-packages-creds + + podSecurityContext: + fsGroup: ${{ secrets.RUNNING_UID_GID }} + + securityContext: + runAsUser: ${{ secrets.RUNNING_UID_GID }} + + " > values.yaml + + helm repo add bcgov http://bcgov.github.io/helm-charts + helm upgrade --install proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }} -f values.yaml bcgov/generic-api diff --git a/e2e/READEME.md b/e2e/READEME.md index 3a8dcfac8..a72d4fd57 100644 --- a/e2e/READEME.md +++ b/e2e/READEME.md @@ -24,27 +24,27 @@ The steps below will take you all the way through Cypress. It is assumed you hav ### 2. Run Tests -* Clone this repository -* Create a new file `cypress.env.json` from `cypress.env.local.json` +- Clone this repository +- Create a new file `cypress.env.json` from `cypress.env.local.json` #### 2.1 Locally -* Run `npm install` to install all the dependencies -* Run `npm run cy:run` to run the tests +- Run `npm install` to install all the dependencies +- Run `npm run cy:run` to run the tests #### 2.2 Docker -* Run `docker build -t aps-cypress-e2e:latest ` to build an image -* Run `docker run --rm -it -name aps-cypress-e2e aps-cypress-e2e:latest` to spin up a container to run the tests +- Run `docker build -t aps-cypress-e2e:latest ` to build an image +- Run `docker run --rm -it -name aps-cypress-e2e aps-cypress-e2e:latest` to spin up a container to run the tests #### 2.3 Docker Compose -* Run `docker-compose up` to spin a container that run cypress as a service and it executes the tests -* Run `docker-compose down` to tear down the container +- Run `docker-compose up` to spin a container that run cypress as a service and it executes the tests +- Run `docker-compose down` to tear down the container #### 2.4 GitHub Actions -* Any new commit pushed to `feature` branch would trigger a job and deploys a container and it executes the tests +- Any new commit pushed to `feature/automation-*` branch triggers a job (`.github/workflows/ci-build-deploy-e2e.yaml`) and deploys a container to execute the test suite ## Cypress IntelliSense @@ -56,9 +56,9 @@ commands. ### Custom commands -* This project also adds several custom commands in [cypress/support/index.js](cypress/support/index.ts). -* To let TypeScript compiler know that we have added a custom command and have IntelliSense working, I have described the type signature of the custom command in file [cypress/support/global.d.ts](cypress/support/global.d.ts). -* To include the new ".d.ts" file into IntelliSense, I could update `tsconfig.json` or I could add another special comment to the JavaScript spec files - `/// Date: Tue, 6 Jul 2021 13:38:34 -0700 Subject: [PATCH 007/155] Updated the path to Dockerfile --- .github/workflows/ci-build-deploy-e2e.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy-e2e.yaml b/.github/workflows/ci-build-deploy-e2e.yaml index 94ecb45fa..fc65bcca3 100644 --- a/.github/workflows/ci-build-deploy-e2e.yaml +++ b/.github/workflows/ci-build-deploy-e2e.yaml @@ -72,7 +72,7 @@ jobs: cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache context: ./e2e - file: Dockerfile + file: ./e2e/Dockerfile tags: ${{ steps.docker_meta.outputs.tags }} load: true build-args: | From b1c0c26f6b47dbd83b56a6377614a914b0726171 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 13:40:39 -0700 Subject: [PATCH 008/155] Updated gitignore to include package-lock --- e2e/.gitignore | 1 - e2e/package-lock.json | 6568 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 6568 insertions(+), 1 deletion(-) create mode 100644 e2e/package-lock.json diff --git a/e2e/.gitignore b/e2e/.gitignore index 3138a5752..ebd8db215 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,3 +1,2 @@ integration -*-lock.json cypress.env.json \ No newline at end of file diff --git a/e2e/package-lock.json b/e2e/package-lock.json new file mode 100644 index 000000000..8c11dee3f --- /dev/null +++ b/e2e/package-lock.json @@ -0,0 +1,6568 @@ +{ + "name": "bcgov-aps-portal-e2e", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/compat-data": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", + "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==" + }, + "@babel/core": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", + "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helpers": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.5", + "@babel/types": "^7.4.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", + "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", + "requires": { + "@babel/types": "^7.14.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", + "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz", + "integrity": "sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", + "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "requires": { + "@babel/compat-data": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.6.tgz", + "integrity": "sha512-Z6gsfGofTxH/+LQXqYEK45kxmcensbzmk/oi8DmaQytlQCgqNZt9XQF8iqlI/SeXWVjaMNxvYvzaYw+kh42mDg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", + "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "regexpu-core": "^4.7.1" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz", + "integrity": "sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "requires": { + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", + "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz", + "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==", + "requires": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz", + "integrity": "sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-wrap-function": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-replace-supers": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", + "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz", + "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz", + "integrity": "sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==" + }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" + }, + "@babel/helper-wrap-function": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz", + "integrity": "sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==", + "requires": { + "@babel/helper-function-name": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helpers": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", + "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", + "requires": { + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@babel/parser": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", + "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==" + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz", + "integrity": "sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz", + "integrity": "sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.3.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", + "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz", + "integrity": "sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", + "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", + "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz", + "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", + "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", + "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "requires": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", + "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz", + "integrity": "sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.5.tgz", + "integrity": "sha512-J4VxKAMykM06K/64z9rwiL6xnBHgB1+FVspqvlgCdwD1KUbQNfszeKVVOMh59w3sztHYIZDgnhOC4WbdEfHFDA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", + "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", + "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", + "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", + "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", + "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz", + "integrity": "sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", + "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "requires": { + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", + "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", + "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", + "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "requires": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz", + "integrity": "sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A==", + "requires": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz", + "integrity": "sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA==", + "requires": { + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", + "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "requires": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz", + "integrity": "sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", + "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", + "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", + "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", + "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.14.5.tgz", + "integrity": "sha512-07aqY1ChoPgIxsuDviptRpVkWCSbXWmzQqcgy65C6YSFOfPFvb/DX3bBRHh7pCd/PMEEYHYWUTSVkCbkVainYQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.5.tgz", + "integrity": "sha512-7RylxNeDnxc1OleDm0F5Q/BSL+whYRbOAR+bwgCxIr0L32v7UFh/pz1DLMZideAUxKT6eMoS2zQH6fyODLEi8Q==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-jsx": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.14.5.tgz", + "integrity": "sha512-M/fmDX6n0cfHK/NLTcPmrfVAORKDhK8tyjDhyxlUjYyPYYO8FRWwuxBA3WBx8kWN/uBUuwGa3s/0+hQ9JIN3Tg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.14.5.tgz", + "integrity": "sha512-1TpSDnD9XR/rQ2tzunBVPThF5poaYT9GqP+of8fAtguYuI/dm2RkrMBDemsxtY0XBzvW7nXjYM0hRyKX9QYj7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", + "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", + "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz", + "integrity": "sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", + "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", + "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", + "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", + "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", + "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", + "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/preset-env": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz", + "integrity": "sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.4.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.4.4", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.4.4", + "@babel/plugin-transform-classes": "^7.4.4", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-duplicate-keys": "^7.2.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.4.4", + "@babel/plugin-transform-modules-systemjs": "^7.4.4", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.2.0", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "browserslist": "^4.6.0", + "core-js-compat": "^3.1.1", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + }, + "dependencies": { + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", + "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", + "requires": { + "@babel/compat-data": "^7.14.7", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.14.5" + } + } + } + }, + "@babel/preset-react": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", + "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0" + } + }, + "@babel/runtime": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz", + "integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==", + "requires": { + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, + "@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/traverse": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.7.tgz", + "integrity": "sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.14.7", + "@babel/types": "^7.14.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", + "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "to-fast-properties": "^2.0.0" + } + }, + "@cypress/browserify-preprocessor": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.1.tgz", + "integrity": "sha512-sErmFSEr5287bLMRl0POGnyFtJCs/lSk5yxrUIJUIHZ8eDvtTEr0V93xRgLjJVG54gJU4MbpHy1mRPA9VZbtQA==", + "requires": { + "@babel/core": "7.4.5", + "@babel/plugin-proposal-class-properties": "7.3.0", + "@babel/plugin-proposal-object-rest-spread": "7.3.2", + "@babel/plugin-transform-runtime": "7.2.0", + "@babel/preset-env": "7.4.5", + "@babel/preset-react": "7.0.0", + "@babel/runtime": "7.3.1", + "babel-plugin-add-module-exports": "1.0.2", + "babelify": "10.0.0", + "bluebird": "3.5.3", + "browserify": "16.2.3", + "coffeeify": "3.0.1", + "coffeescript": "1.12.7", + "debug": "4.1.1", + "fs-extra": "9.0.0", + "lodash.clonedeep": "4.5.0", + "through2": "^2.0.0", + "watchify": "3.11.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@cypress/code-coverage": { + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.9.8.tgz", + "integrity": "sha512-DxZjozoLoIq8h0xrlB6CKb7gcEo1wqFaLYhb/V1oZwixogwRXUgWnQuqTdgBo9A7TrlOc6LsKXEAbIRps0R+Jg==", + "requires": { + "@cypress/browserify-preprocessor": "3.0.1", + "chalk": "4.1.1", + "dayjs": "1.10.5", + "debug": "4.3.2", + "execa": "4.1.0", + "globby": "11.0.4", + "istanbul-lib-coverage": "3.0.0", + "js-yaml": "3.14.1", + "nyc": "15.1.0" + } + }, + "@cypress/instrument-cra": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@cypress/instrument-cra/-/instrument-cra-1.4.0.tgz", + "integrity": "sha512-gXf540xL0jcUXkWyrA2Ug9rzs+jRkc9EPhnRi8XfbnRjdF4lvnn108N6x0lgTApMTbbpCDbVuskHGXDmIuD3CQ==", + "requires": { + "babel-plugin-istanbul": "6.0.0", + "debug": "4.2.0", + "find-yarn-workspace-root": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "requires": { + "ms": "2.1.2" + } + } + } + }, + "@cypress/request": { + "version": "2.88.5", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.5.tgz", + "integrity": "sha512-TzEC1XMi1hJkywWpRfD2clreTa/Z+lOrXDCxxBTBPEcY5azdPi56A6Xw+O4tWJnaJH3iIE7G5aDXZC6JgRZLcA==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "@types/node": { + "version": "14.17.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.4.tgz", + "integrity": "sha512-8kQ3+wKGRNN0ghtEn7EGps/B8CzuBz1nXZEIGGLP2GnwbqYn4dbTs7k+VKLTq1HvZLRCIDtN3Snx1Ege8B7L5A==", + "dev": true + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.3.tgz", + "integrity": "sha512-E1dU4fzC9wN2QK2Cr1MLCfyHM8BoNnRFvuf45LYMPNDA+WqbNzC45S4UzPxvp1fFJ1rvSGU0bPvdd35VLmXG8g==", + "dev": true + }, + "@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "dev": true + }, + "@types/yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.2.tgz", + "integrity": "sha512-PGqpLLzHSxq956rzNGasO3GsAPf2lY9lDUBXhS++SKonglUmJypaUtcKzRtUte8CV7nruwnDxtLUKpVxs0wQBw==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.28.2", + "@typescript-eslint/scope-manager": "4.28.2", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.2.tgz", + "integrity": "sha512-MwHPsL6qo98RC55IoWWP8/opTykjTp4JzfPu1VfO2Z0MshNP0UZ1GEV5rYSSnZSUI8VD7iHvtIPVGW5Nfh7klQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.28.2", + "@typescript-eslint/types": "4.28.2", + "@typescript-eslint/typescript-estree": "4.28.2", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.2.tgz", + "integrity": "sha512-Q0gSCN51eikAgFGY+gnd5p9bhhCUAl0ERMiDKrTzpSoMYRubdB8MJrTTR/BBii8z+iFwz8oihxd0RAdP4l8w8w==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.28.2", + "@typescript-eslint/types": "4.28.2", + "@typescript-eslint/typescript-estree": "4.28.2", + "debug": "^4.3.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.2.tgz", + "integrity": "sha512-MqbypNjIkJFEFuOwPWNDjq0nqXAKZvDNNs9yNseoGBB1wYfz1G0WHC2AVOy4XD7di3KCcW3+nhZyN6zruqmp2A==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.2", + "@typescript-eslint/visitor-keys": "4.28.2" + } + }, + "@typescript-eslint/types": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.2.tgz", + "integrity": "sha512-Gr15fuQVd93uD9zzxbApz3wf7ua3yk4ZujABZlZhaxxKY8ojo448u7XTm/+ETpy0V0dlMtj6t4VdDvdc0JmUhA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.2.tgz", + "integrity": "sha512-86lLstLvK6QjNZjMoYUBMMsULFw0hPHJlk1fzhAVoNjDBuPVxiwvGuPQq3fsBMCxuDJwmX87tM/AXoadhHRljg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.2", + "@typescript-eslint/visitor-keys": "4.28.2", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.2.tgz", + "integrity": "sha512-aT2B4PLyyRDUVUafXzpZFoc0C9t0za4BJAKP5sgWIhG+jHECQZUEjuQSCIwZdiJJ4w4cgu5r3Kh20SOdtEBl0w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.2", + "eslint-visitor-keys": "^2.0.0" + } + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "babel-plugin-add-module-exports": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.2.tgz", + "integrity": "sha512-4paN7RivvU3Rzju1vGSHWPjO8Y0rI6droWvSFKI6dvEQ4mvoV0zGojnlzVRfI6N8zISo6VERXt3coIuVmzuvNg==", + "requires": { + "chokidar": "^2.0.4" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babelify": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-10.0.0.tgz", + "integrity": "sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "dev": true + }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "requires": { + "JSONStream": "^1.0.3", + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + } + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + } + } + }, + "browserify": { + "version": "16.2.3", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz", + "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==", + "requires": { + "JSONStream": "^1.0.3", + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^1.11.0", + "browserify-zlib": "~0.2.0", + "buffer": "^5.0.2", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.0", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^2.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.0.0", + "labeled-stream-splicer": "^2.0.0", + "mkdirp": "^0.5.0", + "module-deps": "^6.0.0", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^2.0.0", + "stream-http": "^2.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.10.1", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cached-path-relative": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", + "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==" + }, + "cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "caniuse-lite": { + "version": "1.0.30001242", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001242.tgz", + "integrity": "sha512-KvNuZ/duufelMB3w2xtf9gEWCSxJwUgoxOx5b6ScLXC4kPc9xsczUVCPrQU26j5kOsHM4pSUL54tAZt5THQKug==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-table3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", + "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^4.2.0" + } + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "coffeeify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/coffeeify/-/coffeeify-3.0.1.tgz", + "integrity": "sha512-Qjnr7UX6ldK1PHV7wCnv7AuCd4q19KTUtwJnu/6JRJB4rfm12zvcXtKdacUoePOKr1I4ka/ydKiwWpNAdsQb0g==", + "requires": { + "convert-source-map": "^1.3.0", + "through2": "^2.0.0" + } + }, + "coffeescript": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz", + "integrity": "sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "optional": true + }, + "combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "requires": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + }, + "dependencies": { + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" + } + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js-compat": { + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.2.tgz", + "integrity": "sha512-Wp+BJVvwopjI+A1EFqm2dwUmWYXrvucmtIB2LgXn/Rb+gWPKYxtmb4GKHGKG/KGF1eK9jfjzT38DITbTOCX/SQ==", + "requires": { + "browserslist": "^4.16.6", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "cypress": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-7.6.0.tgz", + "integrity": "sha512-tTwQExY28CKt6cY85/2V1uLExcMfpBEBWXt/EcE2ht/Onl9k4lxUS7ul1UnUO5MrYwMIHMdGVh13DxdzXj4Z5w==", + "dev": true, + "requires": { + "@cypress/request": "^2.88.5", + "@cypress/xvfb": "^1.2.4", + "@types/node": "^14.14.31", + "@types/sinonjs__fake-timers": "^6.0.2", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.0", + "commander": "^5.1.0", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "eventemitter2": "^6.4.3", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.0", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.5", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "ramda": "~0.27.1", + "request-progress": "^3.0.0", + "supports-color": "^8.1.1", + "tmp": "~0.2.1", + "untildify": "^4.0.0", + "url": "^0.11.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "cypress-xpath": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/cypress-xpath/-/cypress-xpath-1.6.2.tgz", + "integrity": "sha512-mtwJPl840GQPGtb480fKR5vDIcijBHhAVwby5/AIPIT/UVT7UJhM2L42/R+venR7N01I0PoOJErb6UiMbCyUxg==" + }, + "dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "dayjs": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.5.tgz", + "integrity": "sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g==" + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "requires": { + "strip-bom": "^4.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "requires": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "^2.0.2" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "electron-to-chromium": { + "version": "1.3.768", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.768.tgz", + "integrity": "sha512-I4UMZHhVSK2pwt8jOIxTi3GIuc41NkddtKT/hpuxp9GO5UWJgDKTBa4TACppbVAuKtKbMK6BhQZvT5tFF1bcNA==" + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-chai-friendly": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.7.1.tgz", + "integrity": "sha512-0xhGiSQ+9oWtNc6IZPUR+6ChKbEvLXwT9oZZ5NcGlPzHVKGn1YKwQFj7a9yL3rnRKbWF7b3RkRYEP8kN6dPOwQ==", + "dev": true + }, + "eslint-plugin-cypress": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.3.tgz", + "integrity": "sha512-hOoAid+XNFtpvOzZSNWP5LDrQBEJwbZwjib4XJ1KcRYKjeVj0mAmPmucG4Egli4j/aruv+Ow/acacoloWWCl9Q==", + "dev": true, + "requires": { + "globals": "^11.12.0" + } + }, + "eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "eventemitter2": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.4.tgz", + "integrity": "sha512-HLU3NDY6wARrLCEwyGKRBvuWYyvW6mHYv72SJJAH3iJN3a6eVUvkjFkcxah1bcTgGVBBrFdIopBJPhCQFMLyXw==", + "dev": true + }, + "events": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", + "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==" + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "requires": { + "pify": "^2.2.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", + "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "fastq": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.1.tgz", + "integrity": "sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "requires": { + "micromatch": "^4.0.2" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==" + }, + "fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "dev": true, + "requires": { + "async": "^3.2.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "requires": { + "ini": "2.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + }, + "inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "requires": { + "source-map": "~0.5.3" + } + }, + "insert-module-globals": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", + "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", + "requires": { + "JSONStream": "^1.0.3", + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "dev": true + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==" + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "@babel/core": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz", + "integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helpers": "^7.14.6", + "@babel/parser": "^7.14.6", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "requires": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, + "lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "dev": true + }, + "listr2": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.10.0.tgz", + "integrity": "sha512-eP40ZHihu70sSmqFNbNy2NL1YwImmlMmPh9WO5sLmPDleurMHt3n+SwEWNu2kzKScexZnkyFtc1VI0z/TGlmpw==", + "dev": true, + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^1.2.2", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rxjs": "^6.6.7", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=" + }, + "lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + } + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "mime-db": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "dev": true, + "requires": { + "mime-db": "1.48.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "module-deps": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", + "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", + "requires": { + "JSONStream": "^1.0.3", + "browser-resolve": "^2.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.2.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "requires": { + "resolve": "^1.17.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "requires": { + "process-on-spawn": "^1.0.0" + } + }, + "node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=", + "dev": true + }, + "outpipe": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz", + "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=", + "requires": { + "shell-quote": "^1.4.2" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "requires": { + "path-platform": "~0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "requires": { + "fromentries": "^1.2.0" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "ramda": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "requires": { + "readable-stream": "^2.0.2" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "requires": { + "@babel/runtime": "^7.8.4" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", + "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + }, + "regjsparser": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", + "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + } + } + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "requires": { + "es6-error": "^4.0.1" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", + "dev": true, + "requires": { + "throttleit": "^1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", + "requires": { + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" + } + }, + "shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "requires": { + "fast-safe-stringify": "^2.0.7" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "requires": { + "minimist": "^1.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "requires": { + "acorn-node": "^1.2.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "requires": { + "process": "~0.11.0" + } + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, + "tsconfig-paths": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", + "integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", + "dev": true, + "requires": { + "json5": "^2.2.0", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==" + }, + "umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==" + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "requires": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "watchify": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.11.1.tgz", + "integrity": "sha512-WwnUClyFNRMB2NIiHgJU9RQPQNqVeFk7OmZaWf5dC5EnNa0Mgr7imBydbaJ7tGTuPM2hz1Cb4uiBvK9NVxMfog==", + "requires": { + "anymatch": "^2.0.0", + "browserify": "^16.1.0", + "chokidar": "^2.1.1", + "defined": "^1.0.0", + "outpipe": "^1.1.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} From 0109d72c5b4ccf4554c42cb87b784c8d5b03eac5 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 15:42:39 -0700 Subject: [PATCH 009/155] using .env file to store the user creds --- .github/workflows/ci-build-deploy-e2e.yaml | 10 ++++++++++ e2e/.env.local | 2 ++ e2e/Dockerfile | 1 - e2e/READEME.md | 3 ++- e2e/cypress.env.local.json | 6 ------ e2e/cypress.json | 4 ++++ e2e/cypress/plugins/index.ts | 2 ++ e2e/cypress/support/login-commands.ts | 2 +- e2e/cypress/tests/login.spec.ts | 6 +++--- e2e/docker-compose.yml | 2 ++ e2e/package-lock.json | 17 ++++++++++++++--- e2e/package.json | 2 ++ e2e/tsconfig.json | 2 +- 13 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 e2e/.env.local delete mode 100644 e2e/cypress.env.local.json diff --git a/.github/workflows/ci-build-deploy-e2e.yaml b/.github/workflows/ci-build-deploy-e2e.yaml index fc65bcca3..be8361e74 100644 --- a/.github/workflows/ci-build-deploy-e2e.yaml +++ b/.github/workflows/ci-build-deploy-e2e.yaml @@ -116,6 +116,16 @@ jobs: securityContext: runAsUser: ${{ secrets.RUNNING_UID_GID }} + extraVolumeMounts: + - name: aps-portal-e2e-user-creds + mountPath: "/" + readOnly: true + + extraVolumes: + - name: aps-portal-e2e-user-creds + secret: + secretName: bcgov-aps-portal-e2e-generic-api-secrets + " > values.yaml helm repo add bcgov http://bcgov.github.io/helm-charts diff --git a/e2e/.env.local b/e2e/.env.local new file mode 100644 index 000000000..5482c11d2 --- /dev/null +++ b/e2e/.env.local @@ -0,0 +1,2 @@ +CYPRESS_PORTAL_USERNAME= +CYPRESS_PORTAL_PASSWORD= \ No newline at end of file diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 8033e548a..a695c0dea 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -1,7 +1,6 @@ FROM cypress/included:7.6.0 COPY cypress.json . -COPY cypress.env.json . COPY tsconfig.json . COPY package.json . COPY package-lock.json . diff --git a/e2e/READEME.md b/e2e/READEME.md index a72d4fd57..8f43493a6 100644 --- a/e2e/READEME.md +++ b/e2e/READEME.md @@ -25,7 +25,8 @@ The steps below will take you all the way through Cypress. It is assumed you hav ### 2. Run Tests - Clone this repository -- Create a new file `cypress.env.json` from `cypress.env.local.json` +- Create a new file `.env` from `.env.local` +- Replace `` with appropriate values #### 2.1 Locally diff --git a/e2e/cypress.env.local.json b/e2e/cypress.env.local.json deleted file mode 100644 index 0afacafa3..000000000 --- a/e2e/cypress.env.local.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "oidc-issuer": "https://authz-apps-gov-bc-ca.dev.api.gov.bc.ca/auth/realms/aps-v2", - "tests-env": "dev", - "username": "", - "password": "" -} diff --git a/e2e/cypress.json b/e2e/cypress.json index a8210bc9f..d19b556c3 100644 --- a/e2e/cypress.json +++ b/e2e/cypress.json @@ -8,5 +8,9 @@ "reporter": "junit", "reporterOptions": { "toConsole": true + }, + "env": { + "OIDC_ISSUER": "https://authz-apps-gov-bc-ca.dev.api.gov.bc.ca/auth/realms/aps-v2", + "TESTS_ENV": "dev" } } diff --git a/e2e/cypress/plugins/index.ts b/e2e/cypress/plugins/index.ts index fd170fba6..6e55f6cb5 100644 --- a/e2e/cypress/plugins/index.ts +++ b/e2e/cypress/plugins/index.ts @@ -15,3 +15,5 @@ module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config } + +require('dotenv').config() diff --git a/e2e/cypress/support/login-commands.ts b/e2e/cypress/support/login-commands.ts index 0c2d42b9e..0b73e1571 100644 --- a/e2e/cypress/support/login-commands.ts +++ b/e2e/cypress/support/login-commands.ts @@ -1,5 +1,5 @@ Cypress.Commands.add('loginToDev', (username, password) => { - const oidcProviderURL = new URL(Cypress.env('oidc-issuer')) + const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) const appURL = new URL(Cypress.config('baseUrl')) cy.location().should((loc) => { diff --git a/e2e/cypress/tests/login.spec.ts b/e2e/cypress/tests/login.spec.ts index 27d913429..fecf5efd5 100644 --- a/e2e/cypress/tests/login.spec.ts +++ b/e2e/cypress/tests/login.spec.ts @@ -9,10 +9,10 @@ describe('User navigates aps portal login page and', () => { it('enter credentials to login into portal', () => { cy.xpath("//button[normalize-space()='Login']").click() - const oidcProviderURL = new URL(Cypress.env('oidc-issuer')) + const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) - if (Cypress.env('tests-env') === 'dev') { - cy.loginToDev(Cypress.env('username'), Cypress.env('password')) + if (Cypress.env('TESTS_ENV') === 'dev') { + cy.loginToDev(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) cy.verifySession(Cypress.config('baseUrl') + '/admin/session') } }) diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 679e42cb4..90138f43f 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -9,3 +9,5 @@ services: dockerfile: Dockerfile # environment: # DEBUG: cypress:* - Writes complete log + env_file: + - .env diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 8c11dee3f..6f2eba1f5 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -998,9 +998,9 @@ "dev": true }, "@types/node": { - "version": "14.17.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.4.tgz", - "integrity": "sha512-8kQ3+wKGRNN0ghtEn7EGps/B8CzuBz1nXZEIGGLP2GnwbqYn4dbTs7k+VKLTq1HvZLRCIDtN3Snx1Ege8B7L5A==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.0.0.tgz", + "integrity": "sha512-TmCW5HoZ2o2/z2EYi109jLqIaPIi9y/lc2LmDCWzuCi35bcaQ+OtUh6nwBiFK7SOu25FAU5+YKdqFZUwtqGSdg==", "dev": true }, "@types/sinonjs__fake-timers": { @@ -2288,6 +2288,12 @@ "yauzl": "^2.10.0" }, "dependencies": { + "@types/node": { + "version": "14.17.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.4.tgz", + "integrity": "sha512-8kQ3+wKGRNN0ghtEn7EGps/B8CzuBz1nXZEIGGLP2GnwbqYn4dbTs7k+VKLTq1HvZLRCIDtN3Snx1Ege8B7L5A==", + "dev": true + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -2504,6 +2510,11 @@ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", diff --git a/e2e/package.json b/e2e/package.json index 87b787a23..fe6a86910 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -10,6 +10,7 @@ "cy:run": "cypress run --config watchForFileChanges=false" }, "devDependencies": { + "@types/node": "^16.0.0", "@typescript-eslint/eslint-plugin": "^4.28.1", "@typescript-eslint/parser": "^4.28.1", "cypress": "^7.6.0", @@ -24,6 +25,7 @@ "@cypress/code-coverage": "^3.9.8", "@cypress/instrument-cra": "^1.4.0", "cypress-xpath": "^1.6.2", + "dotenv": "^10.0.0", "typescript": "^4.3.5" } } diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json index 5d3536730..693c528bb 100644 --- a/e2e/tsconfig.json +++ b/e2e/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "es5", "lib": ["es5", "dom", "ES2015"], - "types": ["cypress"], + "types": ["cypress", "node"], "allowJs": true }, "include": ["./cypress/**/*.ts"], From be339a73a00e3100e5ac623a3c6b18cf60d5c39d Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 17:05:12 -0700 Subject: [PATCH 010/155] added workdir to dockerfile and updated the secret mount path --- .github/workflows/ci-build-deploy-e2e.yaml | 2 +- e2e/Dockerfile | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy-e2e.yaml b/.github/workflows/ci-build-deploy-e2e.yaml index be8361e74..a957af05b 100644 --- a/.github/workflows/ci-build-deploy-e2e.yaml +++ b/.github/workflows/ci-build-deploy-e2e.yaml @@ -118,7 +118,7 @@ jobs: extraVolumeMounts: - name: aps-portal-e2e-user-creds - mountPath: "/" + mountPath: "/e2e" readOnly: true extraVolumes: diff --git a/e2e/Dockerfile b/e2e/Dockerfile index a695c0dea..e33a9feee 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -1,5 +1,7 @@ FROM cypress/included:7.6.0 +WORKDIR /e2e + COPY cypress.json . COPY tsconfig.json . COPY package.json . From 97014acd2eb7faf896a4e4512d8ff83309b9462b Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 6 Jul 2021 19:27:36 -0700 Subject: [PATCH 011/155] Updated dockerfile and mount path for env --- .github/workflows/ci-build-deploy-e2e.yaml | 2 +- e2e/Dockerfile | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-build-deploy-e2e.yaml b/.github/workflows/ci-build-deploy-e2e.yaml index a957af05b..54f6365db 100644 --- a/.github/workflows/ci-build-deploy-e2e.yaml +++ b/.github/workflows/ci-build-deploy-e2e.yaml @@ -118,7 +118,7 @@ jobs: extraVolumeMounts: - name: aps-portal-e2e-user-creds - mountPath: "/e2e" + mountPath: "/app" readOnly: true extraVolumes: diff --git a/e2e/Dockerfile b/e2e/Dockerfile index e33a9feee..0f0a21771 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -1,13 +1,15 @@ -FROM cypress/included:7.6.0 +FROM cypress/base:12.19.0 -WORKDIR /e2e +WORKDIR /app -COPY cypress.json . -COPY tsconfig.json . -COPY package.json . -COPY package-lock.json . -COPY ./cypress/ cypress +COPY cypress.json /app +COPY tsconfig.json /app +COPY package.json /app +COPY package-lock.json /app +ADD cypress /app/cypress -RUN npm ci --production +RUN npm install -CMD [ "--config-file", "./cypress.json" ] \ No newline at end of file +CMD [ "--config-file", "/app/cypress.json" ] + +ENTRYPOINT ["npm", "run", "cy:run"] \ No newline at end of file From 468809c662ca255c34502b8f6c541095d1eadf51 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 7 Jul 2021 07:49:47 -0700 Subject: [PATCH 012/155] Running the auto tests through github actions --- .github/workflows/aps-cypress-e2e.yaml | 17 +++ .github/workflows/ci-build-deploy-e2e.yaml | 132 --------------------- e2e/.env.local | 2 - e2e/Dockerfile | 18 +-- e2e/READEME.md | 2 +- e2e/cypress.env.local.json | 4 + e2e/cypress/plugins/index.ts | 4 +- e2e/docker-compose.yml | 2 - 8 files changed, 33 insertions(+), 148 deletions(-) create mode 100644 .github/workflows/aps-cypress-e2e.yaml delete mode 100644 .github/workflows/ci-build-deploy-e2e.yaml delete mode 100644 e2e/.env.local create mode 100644 e2e/cypress.env.local.json diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml new file mode 100644 index 000000000..301d1e657 --- /dev/null +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -0,0 +1,17 @@ +name: Build and Deploy Cypress and Execute Tests + +on: + push: + branches: + - 'util/automation-*' + +jobs: + cypress-run: + runs-on: ubuntu-latest + container: cypress/included:4.11.0 + steps: + - uses: actions/checkout@v1 + - run: | + cd e2e + npm install --production + npm run cy:run --config-file cypress.json diff --git a/.github/workflows/ci-build-deploy-e2e.yaml b/.github/workflows/ci-build-deploy-e2e.yaml deleted file mode 100644 index 54f6365db..000000000 --- a/.github/workflows/ci-build-deploy-e2e.yaml +++ /dev/null @@ -1,132 +0,0 @@ -name: Build and Deploy Cypress and Execute Tests - -on: - push: - branches: - - 'util/automation-*' - -env: - REGISTRY: docker.pkg.github.com - REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} - REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Docker meta - id: docker_meta - uses: docker/metadata-action@v3 - with: - images: ${{ env.REGISTRY }}/bcgov/api-services-portal/aps-cypress-e2e - - - name: Set DEPLOY_ID which will deploy a custom deploy to 'dev' environment - run: | - echo '::set-output name=DEPLOY_ID::${{ steps.docker_meta.outputs.version }}' - echo '::set-output name=APP_VERSION::${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.version'] }}' - echo '::set-output name=APP_REVISION::${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.revision'] }}' - id: set-deploy-id - - - name: Get deploy ID - run: echo "The DEPLOY_ID is ${{ steps.set-deploy-id.outputs.DEPLOY_ID }}" - - - uses: actions/checkout@v2 - - - name: Install oc - uses: redhat-actions/oc-installer@v1 - with: - version: '4.6' - - - name: Authenticate and set context - uses: redhat-actions/oc-login@v1 - with: - openshift_server_url: ${{ secrets.OPENSHIFT_SERVER }} - openshift_token: ${{ secrets.OPENSHIFT_TOKEN }} - - # Disables SSL cert checking. Use this if you don't have the certificate authority data. - insecure_skip_tls_verify: true - - namespace: ${{ env.OPENSHIFT_NAMESPACE }} - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ env.REGISTRY_USERNAME }} - password: ${{ env.REGISTRY_PASSWORD }} - - - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v1 - - - name: Build - uses: docker/build-push-action@v2 - with: - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache - context: ./e2e - file: ./e2e/Dockerfile - tags: ${{ steps.docker_meta.outputs.tags }} - load: true - build-args: | - GITHUB_API_TOKEN=${{ secrets.CONTAINER_REGISTRY_PASSWORD }} - APP_VERSION=${{ steps.set-deploy-id.outputs.APP_VERSION }} - APP_REVISION=${{ steps.set-deploy-id.outputs.APP_REVISION }} - - - name: Push - run: docker push ${{ steps.docker_meta.outputs.tags }} - - - name: 'Get Helm' - run: | - curl -L -O https://get.helm.sh/helm-v3.4.2-linux-amd64.tar.gz - tar -xf helm-v3.4.2-linux-amd64.tar.gz - - - name: 'Deploy e2e Testing Suite' - run: | - export PATH=$PATH:`pwd`/linux-amd64 - - echo " - podAnnotations: - sha: $GITHUB_SHA - - replicaCount: 1 - - rollingUpdate: - maxUnavailable: 50% - maxSurge: 50% - - image: - repository: ${{ env.REGISTRY }}/bcgov/api-services-portal/aps-cypress-e2e - tag: ${{ steps.set-deploy-id.outputs.DEPLOY_ID }} - pullPolicy: Always - - imagePullSecrets: - - name: dev-github-read-packages-creds - - podSecurityContext: - fsGroup: ${{ secrets.RUNNING_UID_GID }} - - securityContext: - runAsUser: ${{ secrets.RUNNING_UID_GID }} - - extraVolumeMounts: - - name: aps-portal-e2e-user-creds - mountPath: "/app" - readOnly: true - - extraVolumes: - - name: aps-portal-e2e-user-creds - secret: - secretName: bcgov-aps-portal-e2e-generic-api-secrets - - " > values.yaml - - helm repo add bcgov http://bcgov.github.io/helm-charts - helm upgrade --install proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }} -f values.yaml bcgov/generic-api diff --git a/e2e/.env.local b/e2e/.env.local deleted file mode 100644 index 5482c11d2..000000000 --- a/e2e/.env.local +++ /dev/null @@ -1,2 +0,0 @@ -CYPRESS_PORTAL_USERNAME= -CYPRESS_PORTAL_PASSWORD= \ No newline at end of file diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 0f0a21771..02e2f395d 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -1,15 +1,15 @@ -FROM cypress/base:12.19.0 +FROM cypress/included:7.6.0 -WORKDIR /app +WORKDIR /e2e -COPY cypress.json /app -COPY tsconfig.json /app -COPY package.json /app -COPY package-lock.json /app -ADD cypress /app/cypress +COPY cypress.json /e2e +COPY tsconfig.json /e2e +COPY package.json /e2e +COPY package-lock.json /e2e +ADD cypress /e2e/cypress -RUN npm install +RUN npm install --production -CMD [ "--config-file", "/app/cypress.json" ] +CMD [ "--config-file", "/e2e/cypress.json" ] ENTRYPOINT ["npm", "run", "cy:run"] \ No newline at end of file diff --git a/e2e/READEME.md b/e2e/READEME.md index 8f43493a6..d41dbde44 100644 --- a/e2e/READEME.md +++ b/e2e/READEME.md @@ -25,7 +25,7 @@ The steps below will take you all the way through Cypress. It is assumed you hav ### 2. Run Tests - Clone this repository -- Create a new file `.env` from `.env.local` +- Create a new file `cypress.env.json` from `cypress.env.local.json` - Replace `` with appropriate values #### 2.1 Locally diff --git a/e2e/cypress.env.local.json b/e2e/cypress.env.local.json new file mode 100644 index 000000000..e247c77f0 --- /dev/null +++ b/e2e/cypress.env.local.json @@ -0,0 +1,4 @@ +{ + "PORTAL_USERNAME": "", + "PORTAL_PASSWORD": "" +} diff --git a/e2e/cypress/plugins/index.ts b/e2e/cypress/plugins/index.ts index 6e55f6cb5..da055abb7 100644 --- a/e2e/cypress/plugins/index.ts +++ b/e2e/cypress/plugins/index.ts @@ -11,9 +11,9 @@ // This function is called when a project is opened or re-opened (e.g. due to // the project's config changing) +require('dotenv').config() + module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config } - -require('dotenv').config() diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 90138f43f..679e42cb4 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -9,5 +9,3 @@ services: dockerfile: Dockerfile # environment: # DEBUG: cypress:* - Writes complete log - env_file: - - .env From e4ecb7a76a19dfa9025df6e32df98f1a3c14e28c Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 7 Jul 2021 08:09:15 -0700 Subject: [PATCH 013/155] Added mochawesome reporter --- e2e/cypress.json | 6 +- e2e/package-lock.json | 268 +++++++++++++++++++++++++++++++++++++++++- e2e/package.json | 1 + 3 files changed, 271 insertions(+), 4 deletions(-) diff --git a/e2e/cypress.json b/e2e/cypress.json index d19b556c3..880e547ba 100644 --- a/e2e/cypress.json +++ b/e2e/cypress.json @@ -5,9 +5,11 @@ "video": false, "defaultCommandTimeout": 1000, "requestTimeout": 1000, - "reporter": "junit", + "reporter": "mochawesome", "reporterOptions": { - "toConsole": true + "reportFilename": "bcgov-aps-cypress-e2e-report", + "quiet": true, + "reportDir": "results" }, "env": { "OIDC_ISSUER": "https://authz-apps-gov-bc-ca.dev.api.gov.bc.ca/auth/realms/aps-v2", diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 6f2eba1f5..7f8fc9fb7 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -2354,6 +2354,11 @@ "assert-plus": "^1.0.0" } }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" + }, "dayjs": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.5.tgz", @@ -2471,6 +2476,11 @@ "minimist": "^1.1.1" } }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" + }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -2635,6 +2645,11 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3389,6 +3404,11 @@ "nan": "^2.12.1" } }, + "fsu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fsu/-/fsu-1.1.1.tgz", + "integrity": "sha512-xQVsnjJ/5pQtcKh+KjUoZGzVWn4uNkchxTF6Lwjr4Gf7nQr8fmUfhKJ62zE77+xQg9xnxi5KUps7XGs+VC986A==" + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -4196,8 +4216,7 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json5": { "version": "2.2.0", @@ -4375,6 +4394,26 @@ "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=" }, + "lodash.isempty": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", + "integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=" + }, + "lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "lodash.isobject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "lodash.memoize": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", @@ -4616,6 +4655,193 @@ "minimist": "^1.2.5" } }, + "mochawesome": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/mochawesome/-/mochawesome-6.2.2.tgz", + "integrity": "sha512-NuIxYo8zczmL5XWLNFiud21OsAJHXrflt2lcRY2u8a3TilGwglhzTPjUHZCLqJvbqj2CnIHX2ueqOh1ViUNDPw==", + "requires": { + "chalk": "^4.1.0", + "diff": "^5.0.0", + "json-stringify-safe": "^5.0.1", + "lodash.isempty": "^4.4.0", + "lodash.isfunction": "^3.0.9", + "lodash.isobject": "^3.0.2", + "lodash.isstring": "^4.0.1", + "mochawesome-report-generator": "^5.2.0", + "strip-ansi": "^6.0.0", + "uuid": "^8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, + "mochawesome-report-generator": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mochawesome-report-generator/-/mochawesome-report-generator-5.2.0.tgz", + "integrity": "sha512-DDY/3jSkM/VrWy0vJtdYOf6qBLdaPaLcI7rQmBVbnclIX7AKniE1Rhz3T/cMT/7u54W5EHNo1z84z7efotq/Eg==", + "requires": { + "chalk": "^2.4.2", + "dateformat": "^3.0.2", + "escape-html": "^1.0.3", + "fs-extra": "^7.0.0", + "fsu": "^1.0.2", + "lodash.isfunction": "^3.0.8", + "opener": "^1.5.2", + "prop-types": "^15.7.2", + "tcomb": "^3.2.17", + "tcomb-validation": "^3.3.0", + "validator": "^10.11.0", + "yargs": "^13.2.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "module-deps": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", @@ -4853,6 +5079,11 @@ "mimic-fn": "^2.1.0" } }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" + }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", @@ -5139,6 +5370,16 @@ "fromentries": "^1.2.0" } }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -5223,6 +5464,11 @@ "safe-buffer": "^5.1.0" } }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", @@ -6033,6 +6279,19 @@ "acorn-node": "^1.2.0" } }, + "tcomb": { + "version": "3.2.29", + "resolved": "https://registry.npmjs.org/tcomb/-/tcomb-3.2.29.tgz", + "integrity": "sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ==" + }, + "tcomb-validation": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tcomb-validation/-/tcomb-validation-3.4.1.tgz", + "integrity": "sha512-urVVMQOma4RXwiVCa2nM2eqrAomHROHvWPuj6UkDGz/eb5kcy0x6P0dVt6kzpUZtYMNoAqJLWmz1BPtxrtjtrA==", + "requires": { + "tcomb": "^3.0.0" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -6417,6 +6676,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", diff --git a/e2e/package.json b/e2e/package.json index fe6a86910..9c8c08946 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -26,6 +26,7 @@ "@cypress/instrument-cra": "^1.4.0", "cypress-xpath": "^1.6.2", "dotenv": "^10.0.0", + "mochawesome": "^6.2.2", "typescript": "^4.3.5" } } From 86742501a935245e5247add2988d95073f254d15 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 8 Jul 2021 16:11:56 -0700 Subject: [PATCH 014/155] Added a new custom commands to get session and token information. Created a new spec to verify the logout functionality --- e2e/.gitignore | 3 +- e2e/cypress.json | 10 +- e2e/cypress/support/api-commands.ts | 5 +- e2e/cypress/support/auth-commands.ts | 87 ++++++++++++++ e2e/cypress/support/commands.ts | 7 ++ e2e/cypress/support/global.d.ts | 8 +- e2e/cypress/support/index.ts | 2 +- e2e/cypress/support/login-commands.ts | 38 ------ e2e/cypress/tests/login.spec.ts | 15 ++- e2e/cypress/tests/logout.spec.ts | 33 ++++++ e2e/package-lock.json | 137 +++++++++++++++++++++- e2e/package.json | 11 +- e2e/tsconfig.json | 2 +- local/oauth2-proxy/oauth2-proxy-local.cfg | 3 +- 14 files changed, 300 insertions(+), 61 deletions(-) create mode 100644 e2e/cypress/support/auth-commands.ts delete mode 100644 e2e/cypress/support/login-commands.ts create mode 100644 e2e/cypress/tests/logout.spec.ts diff --git a/e2e/.gitignore b/e2e/.gitignore index ebd8db215..4ba72e3b3 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,2 +1,3 @@ integration -cypress.env.json \ No newline at end of file +cypress.env.json +results \ No newline at end of file diff --git a/e2e/cypress.json b/e2e/cypress.json index 880e547ba..1ffe26ed5 100644 --- a/e2e/cypress.json +++ b/e2e/cypress.json @@ -3,13 +3,13 @@ "integrationFolder": "cypress/tests", "screenshotOnRunFailure": false, "video": false, - "defaultCommandTimeout": 1000, - "requestTimeout": 1000, + "watchForFileChanges": true, "reporter": "mochawesome", "reporterOptions": { - "reportFilename": "bcgov-aps-cypress-e2e-report", - "quiet": true, - "reportDir": "results" + "reportDir": "results", + "html": false, + "json": true, + "overwrite": false }, "env": { "OIDC_ISSUER": "https://authz-apps-gov-bc-ca.dev.api.gov.bc.ca/auth/realms/aps-v2", diff --git a/e2e/cypress/support/api-commands.ts b/e2e/cypress/support/api-commands.ts index 4a79b87d5..ca96766c8 100644 --- a/e2e/cypress/support/api-commands.ts +++ b/e2e/cypress/support/api-commands.ts @@ -1,8 +1,9 @@ -Cypress.Commands.add('callApi', (options: any) => { +Cypress.Commands.add('callApi', (options: Cypress.RequestOptions) => { cy.request({ ...options, - }).then((res) => { + }).then((res: Cypress.Response) => { expect([200, 201]).to.contain(res.status) + cy.log(JSON.stringify(res)) cy.wrap(res) }) }) diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts new file mode 100644 index 000000000..52d27adb3 --- /dev/null +++ b/e2e/cypress/support/auth-commands.ts @@ -0,0 +1,87 @@ +import { opendir } from 'fs' +import * as jwt from 'jsonwebtoken' + +Cypress.Commands.add('loginToDev', (username, password) => { + const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) + const appURL = new URL(Cypress.config('baseUrl')) + + cy.location().should((loc) => { + expect(loc.protocol).to.eq(oidcProviderURL.protocol) + expect(loc.hostname).to.eq(oidcProviderURL.hostname) + }) + + const log = Cypress.log({ + name: 'Login to Dev', + displayName: 'LOGIN_DEV', + message: [`🔐 Authenticating | ${username}`], + autoEnd: false, + }) + + cy.get('#username').type(username) + cy.get('#password').type(password) + cy.get('#kc-login').click() + + cy.location().should((loc) => { + expect(loc.protocol).to.eq(appURL.protocol) + expect(loc.hostname).to.eq(appURL.hostname) + }) + //saving the session cookie + cy.getCookies().then((cookies) => { + cookies.map((cookie) => { + Cypress.Cookies.preserveOnce(cookie.name) + }) + }) + + log.end() +}) + +Cypress.Commands.add('getSession', (url: string) => { + cy.request({ method: 'GET', url: url }) + .then((response) => { + expect(response.status).to.eq(200) + expect(response.body).to.include({ anonymous: false }) + }) + .then((response: any) => { + const log = Cypress.log({ + name: 'Session Info', + displayName: 'SESSION_INFO', + message: JSON.stringify(response.body.user), + }) + }) + .then((response) => { + cy.wrap(response.body) + }) +}) + +Cypress.Commands.add('loginByAuthAPI', (username: string, password: string) => { + const log = Cypress.log({ + displayName: 'AUTH0 LOGIN', + message: [`🔐 Authenticating | ${username}`], + autoEnd: false, + }) + log.snapshot('before') + cy.request({ + method: 'POST', + url: Cypress.env('OIDC_ISSUER') + '/protocol/openid-connect/token', + body: { + grant_type: 'password', + username: Cypress.env('PORTAL_USERNAME'), + password: Cypress.env('PORTAL_PASSWORD'), + Scope: 'openid', + client_id: Cypress.env('CLIENT_ID'), + client_secret: Cypress.env('CLIENT_SECRET'), + }, + form: true, + }).then(({ body }: any) => { + const user: any = jwt.decode(body.id_token) + const userItem = { + token: body.access_token, + user: { + ...user, + }, + } + cy.log(JSON.stringify(userItem)) + }) + log.snapshot('after') + log.end() +}) diff --git a/e2e/cypress/support/commands.ts b/e2e/cypress/support/commands.ts index 119ab03f7..12d76a91e 100644 --- a/e2e/cypress/support/commands.ts +++ b/e2e/cypress/support/commands.ts @@ -22,4 +22,11 @@ // // // -- This will overwrite an existing command -- + +import * as Mocha from 'mocha' + // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +const addContext = require('mochawesome/addContext') +Cypress.Commands.add('addContext', (message) => { + cy.once('test:after:run', (test) => addContext({ test }, message)) +}) diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts index cf361fce9..d133d4755 100644 --- a/e2e/cypress/support/global.d.ts +++ b/e2e/cypress/support/global.d.ts @@ -4,8 +4,12 @@ declare namespace Cypress { interface Chainable { loginToDev(username: string, password: string): Chainable - verifySession(url: string): Chainable + getSession(url: string): Chainable - callApi(options: Partial): Chainable> + callApi(options: Partial): Chainable + + addContext(message: any): Chainable + + loginByAuthAPI(username: string, password: string): Chainable } } diff --git a/e2e/cypress/support/index.ts b/e2e/cypress/support/index.ts index 15b04314a..a3a3948cb 100644 --- a/e2e/cypress/support/index.ts +++ b/e2e/cypress/support/index.ts @@ -1,4 +1,4 @@ import './commands' import 'cypress-xpath' -import './login-commands' +import './auth-commands' import './api-commands' diff --git a/e2e/cypress/support/login-commands.ts b/e2e/cypress/support/login-commands.ts deleted file mode 100644 index 0b73e1571..000000000 --- a/e2e/cypress/support/login-commands.ts +++ /dev/null @@ -1,38 +0,0 @@ -Cypress.Commands.add('loginToDev', (username, password) => { - const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) - const appURL = new URL(Cypress.config('baseUrl')) - - cy.location().should((loc) => { - expect(loc.protocol).to.eq(oidcProviderURL.protocol) - expect(loc.hostname).to.eq(oidcProviderURL.hostname) - }) - - Cypress.log({ - name: 'Login to Dev', - displayName: 'LOGIN_DEV', - message: [`🔐 Authenticating | ${username}`], - }) - - cy.get('#username').type(username) - cy.get('#password').type(password) - cy.get('#kc-login').click() - - cy.location().should((loc) => { - expect(loc.protocol).to.eq(appURL.protocol) - expect(loc.hostname).to.eq(appURL.hostname) - }) -}) - -Cypress.Commands.add('verifySession', (url: string) => { - cy.callApi({ method: 'GET', url: url }).then((res) => { - expect(res.body).to.include({ - anonymous: false, - }) - Cypress.log({ - name: 'Session Info', - displayName: 'SESSION_INFO', - message: JSON.stringify(res.body), - }) - cy.log('Session established successfully') - }) -}) diff --git a/e2e/cypress/tests/login.spec.ts b/e2e/cypress/tests/login.spec.ts index fecf5efd5..1698d814c 100644 --- a/e2e/cypress/tests/login.spec.ts +++ b/e2e/cypress/tests/login.spec.ts @@ -1,19 +1,22 @@ -describe('User navigates aps portal login page and', () => { +describe('Login spec', () => { beforeEach(() => { cy.visit('/') }) - - it('finds login button', () => { + it('should have login button', () => { cy.xpath('//button').contains('Login') }) - it('enter credentials to login into portal', () => { + it('should allow user to authenticate', () => { cy.xpath("//button[normalize-space()='Login']").click() - const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) if (Cypress.env('TESTS_ENV') === 'dev') { cy.loginToDev(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) - cy.verifySession(Cypress.config('baseUrl') + '/admin/session') } }) + + it('should save user session after login', () => { + cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { + cy.log('logged user - ' + JSON.stringify(sessionObj.user)) + }) + }) }) diff --git a/e2e/cypress/tests/logout.spec.ts b/e2e/cypress/tests/logout.spec.ts new file mode 100644 index 000000000..5ececcf05 --- /dev/null +++ b/e2e/cypress/tests/logout.spec.ts @@ -0,0 +1,33 @@ +describe('Logout spec', () => { + beforeEach(() => { + cy.visit('/') + }) + it('should check user session and login if not logged on', () => { + if (cy.xpath('//button').contains('Login')) { + cy.xpath("//button[normalize-space()='Login']").click() + if (Cypress.env('TESTS_ENV') === 'dev') { + cy.loginToDev(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) + } + cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { + expect(sessionObj.anonymous).to.eq(false) + cy.log('logged user - ' + JSON.stringify(sessionObj.user)) + }) + } else { + cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { + cy.log('logged user - ' + JSON.stringify(sessionObj.user)) + }) + } + }) + + it('should allow user to logout', () => { + cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { + cy.contains(sessionObj.user.name).click() + }) + + cy.contains('Sign Out').click() + }) + + it('should show login button after logout', () => { + cy.xpath('//button').contains('Login') + }) +}) diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 7f8fc9fb7..d8f790ce6 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -997,6 +997,30 @@ "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", "dev": true }, + "@types/jsonwebtoken": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.4.tgz", + "integrity": "sha512-4L8msWK31oXwdtC81RmRBAULd0ShnAHjBuKT9MRQpjP0piNrZdXyTRcKY9/UIfhGeKIT4PvF5amOOUbbT/9Wpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/mocha": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", + "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", + "dev": true + }, + "@types/mochawesome": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@types/mochawesome/-/mochawesome-6.2.0.tgz", + "integrity": "sha512-OiwEcIy47t99YEW479OuQe9Ljvu3y6PPPQyPChV0GO0MtraZq9FgGVIBPU1DxqlsIjxw7Edij6j49HutvQOzKQ==", + "dev": true, + "requires": { + "@types/mocha": "*" + } + }, "@types/node": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.0.0.tgz", @@ -1784,6 +1808,11 @@ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -2543,6 +2572,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "electron-to-chromium": { "version": "1.3.768", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.768.tgz", @@ -4252,6 +4289,23 @@ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4264,6 +4318,25 @@ "verror": "1.10.0" } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -4394,6 +4467,16 @@ "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, "lodash.isempty": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", @@ -4404,11 +4487,26 @@ "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, "lodash.isobject": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=" }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, "lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", @@ -4422,8 +4520,7 @@ "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", - "dev": true + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, "log-symbols": { "version": "4.1.0", @@ -4679,6 +4776,42 @@ } } }, + "mochawesome-merge": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mochawesome-merge/-/mochawesome-merge-4.2.0.tgz", + "integrity": "sha512-FSMzagh+8hTShhFXdBLE4/zS2WALcDruoD0bmtiwHEjfyQszR/iEGFTgbuM5ewA5At3qeSGwGsT0k2Stt64NdQ==", + "requires": { + "fs-extra": "^7.0.1", + "glob": "^7.1.6", + "uuid": "^3.3.2", + "yargs": "^15.3.1" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } + }, "mochawesome-report-generator": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/mochawesome-report-generator/-/mochawesome-report-generator-5.2.0.tgz", diff --git a/e2e/package.json b/e2e/package.json index 9c8c08946..5c7541deb 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -6,10 +6,15 @@ "author": "BC Gov APS", "license": "MIT", "scripts": { - "cy:open": "cypress open", - "cy:run": "cypress run --config watchForFileChanges=false" + "cy:open": "cypress open --config-file cypress.json", + "cy:run": "cypress run --config-file cypress.json", + "cy:run:cfg": "cypress run --config", + "moch:json": "mochawesome-merge -f results/*.json -o results/report/bcgov-aps-cypress-e2e-report.json", + "moch:html": "marge results/report/bcgov-aps-cypress-e2e-report.json --reportDir results/report --inline" }, "devDependencies": { + "@types/jsonwebtoken": "^8.5.4", + "@types/mochawesome": "^6.2.0", "@types/node": "^16.0.0", "@typescript-eslint/eslint-plugin": "^4.28.1", "@typescript-eslint/parser": "^4.28.1", @@ -26,7 +31,9 @@ "@cypress/instrument-cra": "^1.4.0", "cypress-xpath": "^1.6.2", "dotenv": "^10.0.0", + "jsonwebtoken": "^8.5.1", "mochawesome": "^6.2.2", + "mochawesome-merge": "^4.2.0", "typescript": "^4.3.5" } } diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json index 693c528bb..849470c00 100644 --- a/e2e/tsconfig.json +++ b/e2e/tsconfig.json @@ -5,7 +5,7 @@ "types": ["cypress", "node"], "allowJs": true }, - "include": ["./cypress/**/*.ts"], + "include": ["./cypress/**/*.ts", "**/*.d.ts"], "exclude": [], "noEmit": true } diff --git a/local/oauth2-proxy/oauth2-proxy-local.cfg b/local/oauth2-proxy/oauth2-proxy-local.cfg index 77d3c73a3..7d1aae073 100644 --- a/local/oauth2-proxy/oauth2-proxy-local.cfg +++ b/local/oauth2-proxy/oauth2-proxy-local.cfg @@ -22,4 +22,5 @@ set_authorization_header="false" pass_authorization_header="false" skip_auth_regex="/health|/home|/public|/docs|/redirect|/_next|/images|/devportal|/manager|/ds/api|/signout|/ds/api/swagger.yaml|^[/]$" whitelist_domains="*" -upstreams=["http://apsportal.localtest.me:3000"] \ No newline at end of file +upstreams=["http://apsportal.localtest.me:3000"] +skip_provider_button='true' \ No newline at end of file From f5f2d2c2e90be1fc1c8c207af3aa20d81b877e01 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 13:41:28 -0700 Subject: [PATCH 015/155] Added cypress as a service to run the e2e tests --- docker-compose.yml | 17 ++++++++++++++++- e2e/Dockerfile | 3 +++ e2e/cypress.env.local.json | 4 +++- e2e/cypress.json | 5 +++-- e2e/entrypoint.sh | 19 +++++++++++++++++++ 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100755 e2e/entrypoint.sh diff --git a/docker-compose.yml b/docker-compose.yml index d66981272..4fb2b4ed5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -102,12 +102,27 @@ services: entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" depends_on: - feeder - restart: on-failure volumes: - ./local/feeder-init:/tmp networks: - portal - keycloak + # cypress: + # image: 'aps-cypress-e2e:latest' + # container_name: cypress-e2e + # entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" + # build: + # context: ./e2e + # dockerfile: Dockerfile + # environment: + # # DEBUG: cypress:* - Writes complete log + # CYPRESS_PORTAL_USERNAME: local + # CYPRESS_PORTAL_PASSWORD: local + # CYPRESS_CLIENT_ID: aps-portal + # CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 + # networks: + # - keycloak + # - oauth2-proxy kong-db: image: postgres:latest container_name: kong-db diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 02e2f395d..5460f8ddd 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -2,10 +2,13 @@ FROM cypress/included:7.6.0 WORKDIR /e2e +RUN apt-get install curl + COPY cypress.json /e2e COPY tsconfig.json /e2e COPY package.json /e2e COPY package-lock.json /e2e +COPY entrypoint.sh /tmp ADD cypress /e2e/cypress RUN npm install --production diff --git a/e2e/cypress.env.local.json b/e2e/cypress.env.local.json index e247c77f0..adb6be601 100644 --- a/e2e/cypress.env.local.json +++ b/e2e/cypress.env.local.json @@ -1,4 +1,6 @@ { "PORTAL_USERNAME": "", - "PORTAL_PASSWORD": "" + "PORTAL_PASSWORD": "", + "CLIENT_ID": "", + "CLIENT_SECRET": "" } diff --git a/e2e/cypress.json b/e2e/cypress.json index 1ffe26ed5..0988a7b93 100644 --- a/e2e/cypress.json +++ b/e2e/cypress.json @@ -1,5 +1,5 @@ { - "baseUrl": "https://api-services-portal-dev.apps.silver.devops.gov.bc.ca", + "baseUrl": "http://oauth2proxy.localtest.me:4180", "integrationFolder": "cypress/tests", "screenshotOnRunFailure": false, "video": false, @@ -11,8 +11,9 @@ "json": true, "overwrite": false }, + "chromeWebSecurity": false, "env": { - "OIDC_ISSUER": "https://authz-apps-gov-bc-ca.dev.api.gov.bc.ca/auth/realms/aps-v2", + "OIDC_ISSUER": "http://keycloak.localtest.me:9080/auth/realms/master", "TESTS_ENV": "dev" } } diff --git a/e2e/entrypoint.sh b/e2e/entrypoint.sh new file mode 100755 index 000000000..8650aa65a --- /dev/null +++ b/e2e/entrypoint.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +cd /tmp + +while true; do + keycloakstatus=$(curl -o /dev/null -Isw '%{http_code}\n' http://keycloak.localtest.me:9080/auth/realms/master) + echo "$keycloakstatus" + if [[ "$keycloakstatus" == "200" ]]; then + echo "Keycloak is up" + cd /e2e + npm run cy:run + break + else + echo "Waiting for Keycloak....." + sleep 2m + fi +done + + From 9c5a9a2b5826184b0986737825cb64b877c36756 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 14:12:11 -0700 Subject: [PATCH 016/155] Optimized the login custom command --- e2e/cypress/support/auth-commands.ts | 4 ++-- e2e/cypress/support/global.d.ts | 2 +- e2e/cypress/tests/login.spec.ts | 6 +----- e2e/cypress/tests/logout.spec.ts | 6 +----- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index 52d27adb3..0e523d015 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -1,10 +1,10 @@ import { opendir } from 'fs' import * as jwt from 'jsonwebtoken' -Cypress.Commands.add('loginToDev', (username, password) => { +Cypress.Commands.add('login', (username, password) => { const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) const appURL = new URL(Cypress.config('baseUrl')) - + cy.xpath("//button[normalize-space()='Login']").click() cy.location().should((loc) => { expect(loc.protocol).to.eq(oidcProviderURL.protocol) expect(loc.hostname).to.eq(oidcProviderURL.hostname) diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts index d133d4755..d77bacc9f 100644 --- a/e2e/cypress/support/global.d.ts +++ b/e2e/cypress/support/global.d.ts @@ -2,7 +2,7 @@ declare namespace Cypress { interface Chainable { - loginToDev(username: string, password: string): Chainable + login(username: string, password: string): Chainable getSession(url: string): Chainable diff --git a/e2e/cypress/tests/login.spec.ts b/e2e/cypress/tests/login.spec.ts index 1698d814c..794c49dfd 100644 --- a/e2e/cypress/tests/login.spec.ts +++ b/e2e/cypress/tests/login.spec.ts @@ -7,11 +7,7 @@ describe('Login spec', () => { }) it('should allow user to authenticate', () => { - cy.xpath("//button[normalize-space()='Login']").click() - - if (Cypress.env('TESTS_ENV') === 'dev') { - cy.loginToDev(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) - } + cy.login(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) }) it('should save user session after login', () => { diff --git a/e2e/cypress/tests/logout.spec.ts b/e2e/cypress/tests/logout.spec.ts index 5ececcf05..e41261919 100644 --- a/e2e/cypress/tests/logout.spec.ts +++ b/e2e/cypress/tests/logout.spec.ts @@ -4,12 +4,8 @@ describe('Logout spec', () => { }) it('should check user session and login if not logged on', () => { if (cy.xpath('//button').contains('Login')) { - cy.xpath("//button[normalize-space()='Login']").click() - if (Cypress.env('TESTS_ENV') === 'dev') { - cy.loginToDev(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) - } + cy.login(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { - expect(sessionObj.anonymous).to.eq(false) cy.log('logged user - ' + JSON.stringify(sessionObj.user)) }) } else { From 85c2a45790b36e853670b8859f17d23e93d70b54 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 18:48:25 -0700 Subject: [PATCH 017/155] Updated E2E github actions to spin up aps portal and perform E2E testing --- .env.local | 4 ++- .github/workflows/aps-cypress-e2e.yaml | 23 ++++++++++++---- docker-compose.yml | 38 +++++++++++++------------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/.env.local b/.env.local index 485f151d7..fb9322868 100644 --- a/.env.local +++ b/.env.local @@ -21,4 +21,6 @@ KEYCLOAK_REALM=master EMAIL_ENABLED=false EXTERNAL_URL=http://oauth2proxy.localtest.me:4180 OIDC_ISSUER=http://keycloak.localtest.me:9080/auth/realms/master -LOCAL_ENV=true \ No newline at end of file +LOCAL_ENV=true +WORKING_PATH=/tmp +DESTINATION_URL= \ No newline at end of file diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 301d1e657..271fb04f7 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -8,10 +8,23 @@ on: jobs: cypress-run: runs-on: ubuntu-latest - container: cypress/included:4.11.0 + container: + image: lucasalt/act_base:latest steps: - uses: actions/checkout@v1 - - run: | - cd e2e - npm install --production - npm run cy:run --config-file cypress.json + - name: Spin up API Services Portal and Run E2E Tests + run: docker-compose -f docker-compose.yml up -d + - name: Stop the Containers + run: | + while true; do + if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then + # cleanup + docker-compose stop + sleep 1m + docker-compose down + break + else + echo "Waiting for Cypress to Complete E2E Tests....." + sleep 3m + fi + done diff --git a/docker-compose.yml b/docker-compose.yml index 4fb2b4ed5..4792d6792 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,7 +51,7 @@ services: - ./local/oauth2-proxy/oauth2-proxy-local.cfg:/oauth2-proxy.cfg restart: unless-stopped env_file: - - .env + - .env.local networks: keycloak: {} portal: {} @@ -68,7 +68,7 @@ services: context: . dockerfile: Dockerfile env_file: - - .env + - .env.local ports: - 3000:3000 networks: @@ -87,7 +87,7 @@ services: context: ./feeds dockerfile: Dockerfile env_file: - - ./feeds/.env + - ./feeds/.env.local ports: - 6000:6000 networks: @@ -107,22 +107,22 @@ services: networks: - portal - keycloak - # cypress: - # image: 'aps-cypress-e2e:latest' - # container_name: cypress-e2e - # entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" - # build: - # context: ./e2e - # dockerfile: Dockerfile - # environment: - # # DEBUG: cypress:* - Writes complete log - # CYPRESS_PORTAL_USERNAME: local - # CYPRESS_PORTAL_PASSWORD: local - # CYPRESS_CLIENT_ID: aps-portal - # CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 - # networks: - # - keycloak - # - oauth2-proxy + cypress: + image: 'aps-cypress-e2e:latest' + container_name: cypress-e2e + entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" + build: + context: ./e2e + dockerfile: Dockerfile + environment: + # DEBUG: cypress:* - Writes complete log + CYPRESS_PORTAL_USERNAME: local + CYPRESS_PORTAL_PASSWORD: local + CYPRESS_CLIENT_ID: aps-portal + CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 + networks: + - keycloak + - oauth2-proxy kong-db: image: postgres:latest container_name: kong-db From 21fa4083c97c3c0aa3145c885d85e0ef9e2c1b8e Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 19:32:56 -0700 Subject: [PATCH 018/155] Added a command to check the status of containers --- .github/workflows/aps-cypress-e2e.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 271fb04f7..b17bea8d5 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -24,7 +24,8 @@ jobs: docker-compose down break else + docker ps -a echo "Waiting for Cypress to Complete E2E Tests....." - sleep 3m + sleep 1m fi done From b83a0f754725a5cea73b2cffe2ab2523f3ff5fb2 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 19:58:12 -0700 Subject: [PATCH 019/155] Testing keycloak in github environment --- .github/workflows/aps-cypress-e2e.yaml | 2 +- docker-compose.yml | 258 ++++++++++++------------- 2 files changed, 129 insertions(+), 131 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index b17bea8d5..518952b21 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -17,7 +17,7 @@ jobs: - name: Stop the Containers run: | while true; do - if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then + if [ "$(docker ps -aq -f status=exited -f name=keycloak)" ]; then # cleanup docker-compose stop sleep 1m diff --git a/docker-compose.yml b/docker-compose.yml index 4792d6792..222ccf0fb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,90 +39,90 @@ services: keycloak: aliases: - keycloak.localtest.me - oauth2-proxy: - image: quay.io/oauth2-proxy/oauth2-proxy:v7.1.3 - container_name: oauth2-proxy - command: --config ./oauth2-proxy.cfg - depends_on: - - keycloak - ports: - - 4180:4180/tcp - volumes: - - ./local/oauth2-proxy/oauth2-proxy-local.cfg:/oauth2-proxy.cfg - restart: unless-stopped - env_file: - - .env.local - networks: - keycloak: {} - portal: {} - kong-net: {} - oauth2-proxy: - aliases: - - oauth2proxy.localtest.me - apsportal: - container_name: apsportal - image: apsportal:latest - depends_on: - - keycloak - build: - context: . - dockerfile: Dockerfile - env_file: - - .env.local - ports: - - 3000:3000 - networks: - portal: - aliases: - - apsportal.localtest.me - keycloak: {} - oauth2-proxy: {} - kong-net: {} - feeder: - container_name: feeder - image: feeder:latest - depends_on: - - oauth2-proxy - build: - context: ./feeds - dockerfile: Dockerfile - env_file: - - ./feeds/.env.local - ports: - - 6000:6000 - networks: - portal: - aliases: - - feeder.localtest.me - kong-net: {} - feeder-seeding: - container_name: feeder-seeding - image: feeder:latest - command: '' - entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" - depends_on: - - feeder - volumes: - - ./local/feeder-init:/tmp - networks: - - portal - - keycloak - cypress: - image: 'aps-cypress-e2e:latest' - container_name: cypress-e2e - entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" - build: - context: ./e2e - dockerfile: Dockerfile - environment: - # DEBUG: cypress:* - Writes complete log - CYPRESS_PORTAL_USERNAME: local - CYPRESS_PORTAL_PASSWORD: local - CYPRESS_CLIENT_ID: aps-portal - CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 - networks: - - keycloak - - oauth2-proxy + # oauth2-proxy: + # image: quay.io/oauth2-proxy/oauth2-proxy:v7.1.3 + # container_name: oauth2-proxy + # command: --config ./oauth2-proxy.cfg + # depends_on: + # - keycloak + # ports: + # - 4180:4180/tcp + # volumes: + # - ./local/oauth2-proxy/oauth2-proxy-local.cfg:/oauth2-proxy.cfg + # restart: unless-stopped + # env_file: + # - .env.local + # networks: + # keycloak: {} + # portal: {} + # kong-net: {} + # oauth2-proxy: + # aliases: + # - oauth2proxy.localtest.me + # apsportal: + # container_name: apsportal + # image: apsportal:latest + # depends_on: + # - keycloak + # build: + # context: . + # dockerfile: Dockerfile + # env_file: + # - .env.local + # ports: + # - 3000:3000 + # networks: + # portal: + # aliases: + # - apsportal.localtest.me + # keycloak: {} + # oauth2-proxy: {} + # kong-net: {} + # feeder: + # container_name: feeder + # image: feeder:latest + # depends_on: + # - oauth2-proxy + # build: + # context: ./feeds + # dockerfile: Dockerfile + # env_file: + # - ./feeds/.env.local + # ports: + # - 6000:6000 + # networks: + # portal: + # aliases: + # - feeder.localtest.me + # kong-net: {} + # feeder-seeding: + # container_name: feeder-seeding + # image: feeder:latest + # command: '' + # entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" + # depends_on: + # - feeder + # volumes: + # - ./local/feeder-init:/tmp + # networks: + # - portal + # - keycloak + # cypress: + # image: 'aps-cypress-e2e:latest' + # container_name: cypress-e2e + # entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" + # build: + # context: ./e2e + # dockerfile: Dockerfile + # environment: + # # DEBUG: cypress:* - Writes complete log + # CYPRESS_PORTAL_USERNAME: local + # CYPRESS_PORTAL_PASSWORD: local + # CYPRESS_CLIENT_ID: aps-portal + # CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 + # networks: + # - keycloak + # - oauth2-proxy kong-db: image: postgres:latest container_name: kong-db @@ -140,51 +140,49 @@ services: - kong-net - keycloak - portal - kong-migrations: - image: kong:latest - command: kong migrations bootstrap - depends_on: - - kong-db - environment: *common-variables - networks: - - kong-net - restart: on-failure - kong-migrations-up: - image: kong:latest - command: kong migrations up && kong migrations finish - depends_on: - - kong-db - environment: *common-variables - networks: - - kong-net - restart: on-failure - kong: - image: kong:latest - container_name: kong - depends_on: - - kong-migrations - - kong-migrations-up - environment: - <<: *common-variables - KONG_ADMIN_ACCESS_LOG: /dev/stdout - KONG_ADMIN_ERROR_LOG: /dev/stderr - KONG_CASSANDRA_CONTACT_POINTS: kong-db - KONG_NGINX_WORKER_PROCESSES: '1' - KONG_PROXY_ACCESS_LOG: /dev/stdout - KONG_PROXY_ERROR_LOG: /dev/stderr - KONG_ADMIN_LISTEN: 0.0.0.0:8001 - ports: - - 8000:8000 - - 8001:8001 - networks: - kong-net: - aliases: - - kong.localtest.me - restart: on-failure:5 + # kong-migrations: + # image: kong:latest + # command: kong migrations bootstrap + # depends_on: + # - kong-db + # environment: *common-variables + # networks: + # - kong-net + # restart: on-failure + # kong-migrations-up: + # image: kong:latest + # command: kong migrations up && kong migrations finish + # depends_on: + # - kong-db + # environment: *common-variables + # networks: + # - kong-net + # restart: on-failure + # kong: + # image: kong:latest + # container_name: kong + # depends_on: + # - kong-migrations + # - kong-migrations-up + # environment: + # <<: *common-variables + # KONG_ADMIN_ACCESS_LOG: /dev/stdout + # KONG_ADMIN_ERROR_LOG: /dev/stderr + # KONG_CASSANDRA_CONTACT_POINTS: kong-db + # KONG_NGINX_WORKER_PROCESSES: '1' + # KONG_PROXY_ACCESS_LOG: /dev/stdout + # KONG_PROXY_ERROR_LOG: /dev/stderr + # KONG_ADMIN_LISTEN: 0.0.0.0:8001 + # ports: + # - 8000:8000 + # - 8001:8001 + # networks: + # kong-net: + # aliases: + # - kong.localtest.me + # restart: on-failure:5 networks: keycloak: {} - oauth2-proxy: {} - portal: {} - kong-net: {} -volumes: - aps-pg-data: {} + # oauth2-proxy: {} + # portal: {} + # kong-net: {} From b01825304be04519a47a21d74292630d4dd945b4 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 19:58:53 -0700 Subject: [PATCH 020/155] Added missing network --- docker-compose.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 222ccf0fb..0f038475d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,6 +39,7 @@ services: keycloak: aliases: - keycloak.localtest.me + kong-net: {} # oauth2-proxy: # image: quay.io/oauth2-proxy/oauth2-proxy:v7.1.3 # container_name: oauth2-proxy @@ -139,7 +140,7 @@ services: networks: - kong-net - keycloak - - portal + #- portal # kong-migrations: # image: kong:latest # command: kong migrations bootstrap @@ -185,4 +186,4 @@ networks: keycloak: {} # oauth2-proxy: {} # portal: {} - # kong-net: {} + kong-net: {} From 437901aa8830d151a6ff4885db88f946ede5dd66 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 20:06:29 -0700 Subject: [PATCH 021/155] Running services open to view the complete log --- .github/workflows/aps-cypress-e2e.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 518952b21..123385020 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: Spin up API Services Portal and Run E2E Tests - run: docker-compose -f docker-compose.yml up -d + run: docker-compose -f docker-compose.yml up - name: Stop the Containers run: | while true; do From 07952ea9ca59417d4ead70cee295d9c8fbf06374 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 20:29:20 -0700 Subject: [PATCH 022/155] Adding volumes --- .github/workflows/aps-cypress-e2e.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 123385020..ad9da11eb 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -10,6 +10,7 @@ jobs: runs-on: ubuntu-latest container: image: lucasalt/act_base:latest + options: -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}:/home/nkuruba/nithin/Git/api-services-portal steps: - uses: actions/checkout@v1 - name: Spin up API Services Portal and Run E2E Tests From 6c8b874c124bc0a7e804501daff225064e40b702 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 23:28:24 -0700 Subject: [PATCH 023/155] updated github workflow to use default ubuntu-latest image to run the docker compose --- .github/workflows/aps-cypress-e2e.yaml | 5 +- docker-compose.yml | 257 +++++++++++++------------ 2 files changed, 130 insertions(+), 132 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index ad9da11eb..0f97d5f77 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -8,13 +8,10 @@ on: jobs: cypress-run: runs-on: ubuntu-latest - container: - image: lucasalt/act_base:latest - options: -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}:/home/nkuruba/nithin/Git/api-services-portal steps: - uses: actions/checkout@v1 - name: Spin up API Services Portal and Run E2E Tests - run: docker-compose -f docker-compose.yml up + run: docker-compose up - name: Stop the Containers run: | while true; do diff --git a/docker-compose.yml b/docker-compose.yml index 0f038475d..fb4e5522a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,90 +40,91 @@ services: aliases: - keycloak.localtest.me kong-net: {} - # oauth2-proxy: - # image: quay.io/oauth2-proxy/oauth2-proxy:v7.1.3 - # container_name: oauth2-proxy - # command: --config ./oauth2-proxy.cfg - # depends_on: - # - keycloak - # ports: - # - 4180:4180/tcp - # volumes: - # - ./local/oauth2-proxy/oauth2-proxy-local.cfg:/oauth2-proxy.cfg - # restart: unless-stopped - # env_file: - # - .env.local - # networks: - # keycloak: {} - # portal: {} - # kong-net: {} - # oauth2-proxy: - # aliases: - # - oauth2proxy.localtest.me - # apsportal: - # container_name: apsportal - # image: apsportal:latest - # depends_on: - # - keycloak - # build: - # context: . - # dockerfile: Dockerfile - # env_file: - # - .env.local - # ports: - # - 3000:3000 - # networks: - # portal: - # aliases: - # - apsportal.localtest.me - # keycloak: {} - # oauth2-proxy: {} - # kong-net: {} - # feeder: - # container_name: feeder - # image: feeder:latest - # depends_on: - # - oauth2-proxy - # build: - # context: ./feeds - # dockerfile: Dockerfile - # env_file: - # - ./feeds/.env.local - # ports: - # - 6000:6000 - # networks: - # portal: - # aliases: - # - feeder.localtest.me - # kong-net: {} - # feeder-seeding: - # container_name: feeder-seeding - # image: feeder:latest - # command: '' - # entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" - # depends_on: - # - feeder - # volumes: - # - ./local/feeder-init:/tmp - # networks: - # - portal - # - keycloak - # cypress: - # image: 'aps-cypress-e2e:latest' - # container_name: cypress-e2e - # entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" - # build: - # context: ./e2e - # dockerfile: Dockerfile - # environment: - # # DEBUG: cypress:* - Writes complete log - # CYPRESS_PORTAL_USERNAME: local - # CYPRESS_PORTAL_PASSWORD: local - # CYPRESS_CLIENT_ID: aps-portal - # CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 - # networks: - # - keycloak - # - oauth2-proxy + oauth2-proxy: + image: quay.io/oauth2-proxy/oauth2-proxy:v7.1.3 + container_name: oauth2-proxy + command: --config ./oauth2-proxy.cfg + depends_on: + - keycloak + ports: + - 4180:4180/tcp + volumes: + - ./local/oauth2-proxy/oauth2-proxy-local.cfg:/oauth2-proxy.cfg + restart: unless-stopped + env_file: + - .env + networks: + keycloak: {} + portal: {} + kong-net: {} + oauth2-proxy: + aliases: + - oauth2proxy.localtest.me + apsportal: + container_name: apsportal + image: apsportal:latest + depends_on: + - keycloak + build: + context: . + dockerfile: Dockerfile + env_file: + - .env + ports: + - 3000:3000 + networks: + portal: + aliases: + - apsportal.localtest.me + keycloak: {} + oauth2-proxy: {} + kong-net: {} + feeder: + container_name: feeder + image: feeder:latest + depends_on: + - oauth2-proxy + build: + context: ./feeds + dockerfile: Dockerfile + env_file: + - ./feeds/.env + restart: on-failure + ports: + - 6000:6000 + networks: + portal: + aliases: + - feeder.localtest.me + kong-net: {} + feeder-seeding: + container_name: feeder-seeding + image: feeder:latest + command: '' + entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" + depends_on: + - feeder + volumes: + - ./local/feeder-init:/tmp + networks: + - portal + - keycloak + cypress: + image: 'aps-cypress-e2e:latest' + container_name: cypress-e2e + entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" + build: + context: ./e2e + dockerfile: Dockerfile + environment: + # DEBUG: cypress:* - Writes complete log + CYPRESS_PORTAL_USERNAME: local + CYPRESS_PORTAL_PASSWORD: local + CYPRESS_CLIENT_ID: aps-portal + CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 + networks: + - keycloak + - oauth2-proxy kong-db: image: postgres:latest container_name: kong-db @@ -140,50 +141,50 @@ services: networks: - kong-net - keycloak - #- portal - # kong-migrations: - # image: kong:latest - # command: kong migrations bootstrap - # depends_on: - # - kong-db - # environment: *common-variables - # networks: - # - kong-net - # restart: on-failure - # kong-migrations-up: - # image: kong:latest - # command: kong migrations up && kong migrations finish - # depends_on: - # - kong-db - # environment: *common-variables - # networks: - # - kong-net - # restart: on-failure - # kong: - # image: kong:latest - # container_name: kong - # depends_on: - # - kong-migrations - # - kong-migrations-up - # environment: - # <<: *common-variables - # KONG_ADMIN_ACCESS_LOG: /dev/stdout - # KONG_ADMIN_ERROR_LOG: /dev/stderr - # KONG_CASSANDRA_CONTACT_POINTS: kong-db - # KONG_NGINX_WORKER_PROCESSES: '1' - # KONG_PROXY_ACCESS_LOG: /dev/stdout - # KONG_PROXY_ERROR_LOG: /dev/stderr - # KONG_ADMIN_LISTEN: 0.0.0.0:8001 - # ports: - # - 8000:8000 - # - 8001:8001 - # networks: - # kong-net: - # aliases: - # - kong.localtest.me - # restart: on-failure:5 + - portal + kong-migrations: + image: kong:latest + command: kong migrations bootstrap + depends_on: + - kong-db + environment: *common-variables + networks: + - kong-net + restart: on-failure + kong-migrations-up: + image: kong:latest + command: kong migrations up && kong migrations finish + depends_on: + - kong-db + environment: *common-variables + networks: + - kong-net + restart: on-failure + kong: + image: kong:latest + container_name: kong + depends_on: + - kong-migrations + - kong-migrations-up + environment: + <<: *common-variables + KONG_ADMIN_ACCESS_LOG: /dev/stdout + KONG_ADMIN_ERROR_LOG: /dev/stderr + KONG_CASSANDRA_CONTACT_POINTS: kong-db + KONG_NGINX_WORKER_PROCESSES: '1' + KONG_PROXY_ACCESS_LOG: /dev/stdout + KONG_PROXY_ERROR_LOG: /dev/stderr + KONG_ADMIN_LISTEN: 0.0.0.0:8001 + ports: + - 8000:8000 + - 8001:8001 + networks: + kong-net: + aliases: + - kong.localtest.me + restart: on-failure:5 networks: keycloak: {} - # oauth2-proxy: {} - # portal: {} + oauth2-proxy: {} + portal: {} kong-net: {} From 94e4b4fc3576e56b5f5b6f3d1ac2ca4f0728dadf Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 23:29:47 -0700 Subject: [PATCH 024/155] upddated docker compose to use .env.local file --- docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index fb4e5522a..10fa78a13 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,7 +52,7 @@ services: - ./local/oauth2-proxy/oauth2-proxy-local.cfg:/oauth2-proxy.cfg restart: unless-stopped env_file: - - .env + - .env.local networks: keycloak: {} portal: {} @@ -69,7 +69,7 @@ services: context: . dockerfile: Dockerfile env_file: - - .env + - .env.local ports: - 3000:3000 networks: @@ -88,7 +88,7 @@ services: context: ./feeds dockerfile: Dockerfile env_file: - - ./feeds/.env + - ./feeds/.env.local restart: on-failure ports: - 6000:6000 From b20669298a38fe9c209c7f50564f24d3ed75945b Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 9 Jul 2021 23:47:27 -0700 Subject: [PATCH 025/155] Updated wait time for cypress to allow for initial data seeding --- .github/workflows/aps-cypress-e2e.yaml | 4 ++-- e2e/entrypoint.sh | 4 +++- local/feeder-init/init.sh | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 0f97d5f77..2553b92a5 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -11,11 +11,11 @@ jobs: steps: - uses: actions/checkout@v1 - name: Spin up API Services Portal and Run E2E Tests - run: docker-compose up + run: docker-compose up -d - name: Stop the Containers run: | while true; do - if [ "$(docker ps -aq -f status=exited -f name=keycloak)" ]; then + if [ "$(docker ps -aq -f status=exited -f name=cypress)" ]; then # cleanup docker-compose stop sleep 1m diff --git a/e2e/entrypoint.sh b/e2e/entrypoint.sh index 8650aa65a..0c7eac025 100755 --- a/e2e/entrypoint.sh +++ b/e2e/entrypoint.sh @@ -8,11 +8,13 @@ while true; do if [[ "$keycloakstatus" == "200" ]]; then echo "Keycloak is up" cd /e2e + # added sleep to wait for initial data seeding + sleep 2m npm run cy:run break else echo "Waiting for Keycloak....." - sleep 2m + sleep 3m fi done diff --git a/local/feeder-init/init.sh b/local/feeder-init/init.sh index 9025c00ed..94b616dd0 100755 --- a/local/feeder-init/init.sh +++ b/local/feeder-init/init.sh @@ -16,7 +16,7 @@ while true; do break else echo "Waiting for Keycloak....." - sleep 2m + sleep 1m fi done From 2e7dd932dd752d5876efafb4694cffda8629d66c Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sat, 10 Jul 2021 21:43:26 -0700 Subject: [PATCH 026/155] Updated github action to save the test report as artifact --- .github/workflows/aps-cypress-e2e.yaml | 8 +- docker-compose.yml | 2 + e2e/Dockerfile | 4 +- e2e/docker-compose.yml | 2 + e2e/entrypoint.sh | 2 +- e2e/package-lock.json | 157 +++++++++++++++++-------- e2e/package.json | 4 +- 7 files changed, 122 insertions(+), 57 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 2553b92a5..1cc95358b 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -12,17 +12,21 @@ jobs: - uses: actions/checkout@v1 - name: Spin up API Services Portal and Run E2E Tests run: docker-compose up -d + - name: Upload E2E Test Report as Artifact + run: actions/upload-artifact@v2 + with: + name: E2E Test Report + path: ${{ github.workspace }}/e2e/results/report/*.html - name: Stop the Containers run: | while true; do - if [ "$(docker ps -aq -f status=exited -f name=cypress)" ]; then + if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then # cleanup docker-compose stop sleep 1m docker-compose down break else - docker ps -a echo "Waiting for Cypress to Complete E2E Tests....." sleep 1m fi diff --git a/docker-compose.yml b/docker-compose.yml index 10fa78a13..2a5b4175e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -122,6 +122,8 @@ services: CYPRESS_PORTAL_PASSWORD: local CYPRESS_CLIENT_ID: aps-portal CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 + volumes: + - ./e2e/results/report:/e2e/results/report networks: - keycloak - oauth2-proxy diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 5460f8ddd..2a271ca3f 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -13,6 +13,4 @@ ADD cypress /e2e/cypress RUN npm install --production -CMD [ "--config-file", "/e2e/cypress.json" ] - -ENTRYPOINT ["npm", "run", "cy:run"] \ No newline at end of file +ENTRYPOINT ["npm", "run", "cy:run:html"] \ No newline at end of file diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 679e42cb4..eff818669 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -9,3 +9,5 @@ services: dockerfile: Dockerfile # environment: # DEBUG: cypress:* - Writes complete log + volumes: + - ./results/report:/e2e/results/report diff --git a/e2e/entrypoint.sh b/e2e/entrypoint.sh index 0c7eac025..2a7104f18 100755 --- a/e2e/entrypoint.sh +++ b/e2e/entrypoint.sh @@ -10,7 +10,7 @@ while true; do cd /e2e # added sleep to wait for initial data seeding sleep 2m - npm run cy:run + npm run cy:run:html break else echo "Waiting for Keycloak....." diff --git a/e2e/package-lock.json b/e2e/package-lock.json index d8f790ce6..5bf22e9c5 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -2632,7 +2632,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -2641,7 +2640,6 @@ "version": "1.18.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -2665,7 +2663,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -3609,8 +3606,7 @@ "has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" }, "has-flag": { "version": "3.0.0", @@ -3709,8 +3705,7 @@ "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" }, "html-escaper": { "version": "2.0.2", @@ -3837,14 +3832,12 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-bigint": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" }, "is-binary-path": { "version": "1.0.1", @@ -3858,7 +3851,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "dev": true, "requires": { "call-bind": "^1.0.2" } @@ -3871,8 +3863,7 @@ "is-callable": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" }, "is-ci": { "version": "3.0.0", @@ -3912,8 +3903,7 @@ "is-date-object": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==" }, "is-descriptor": { "version": "0.1.6", @@ -3968,8 +3958,7 @@ "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" }, "is-number": { "version": "3.0.0", @@ -3992,8 +3981,7 @@ "is-number-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==" }, "is-path-inside": { "version": "3.0.3", @@ -4013,7 +4001,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-symbols": "^1.0.2" @@ -4027,14 +4014,12 @@ "is-string": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" }, "is-symbol": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -4227,8 +4212,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-schema": { "version": "0.2.3", @@ -4422,7 +4406,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", @@ -4433,14 +4416,12 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" } } }, @@ -4636,6 +4617,11 @@ "safe-buffer": "^5.1.2" } }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5036,6 +5022,11 @@ "to-regex": "^3.0.1" } }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -5053,7 +5044,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -5066,6 +5056,72 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -5150,8 +5206,7 @@ "object-inspect": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", - "dev": true + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" }, "object-keys": { "version": "1.1.1", @@ -5305,7 +5360,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -5385,6 +5439,11 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, + "pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==" + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -5614,7 +5673,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, "requires": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", @@ -5625,7 +5683,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, "requires": { "pify": "^3.0.0" } @@ -5633,8 +5690,7 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" } } }, @@ -6216,7 +6272,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -6225,14 +6280,12 @@ "spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" }, "spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -6241,8 +6294,7 @@ "spdx-license-ids": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==" }, "split-string": { "version": "3.1.0", @@ -6342,11 +6394,20 @@ "strip-ansi": "^6.0.0" } }, + "string.prototype.padend": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", + "integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, "string.prototype.trimend": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -6356,7 +6417,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -6624,7 +6684,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has-bigints": "^1.0.1", @@ -6803,7 +6862,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -6856,7 +6914,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", diff --git a/e2e/package.json b/e2e/package.json index 5c7541deb..847e4b484 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -10,7 +10,8 @@ "cy:run": "cypress run --config-file cypress.json", "cy:run:cfg": "cypress run --config", "moch:json": "mochawesome-merge -f results/*.json -o results/report/bcgov-aps-cypress-e2e-report.json", - "moch:html": "marge results/report/bcgov-aps-cypress-e2e-report.json --reportDir results/report --inline" + "moch:html": "marge results/report/bcgov-aps-cypress-e2e-report.json --reportDir results/report --inline", + "cy:run:html": "run-s --continue-on-error cy:run moch:json moch:html" }, "devDependencies": { "@types/jsonwebtoken": "^8.5.4", @@ -34,6 +35,7 @@ "jsonwebtoken": "^8.5.1", "mochawesome": "^6.2.2", "mochawesome-merge": "^4.2.0", + "npm-run-all": "^4.1.5", "typescript": "^4.3.5" } } From fe0d6bf3e931aa4e146d473f1fbc2bedbac76e03 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sat, 10 Jul 2021 21:46:30 -0700 Subject: [PATCH 027/155] Updated github action workflow syntax --- .github/workflows/aps-cypress-e2e.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 1cc95358b..d5d86aaf1 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -13,7 +13,7 @@ jobs: - name: Spin up API Services Portal and Run E2E Tests run: docker-compose up -d - name: Upload E2E Test Report as Artifact - run: actions/upload-artifact@v2 + uses: actions/upload-artifact@v2 with: name: E2E Test Report path: ${{ github.workspace }}/e2e/results/report/*.html From 275e557dc2730069a3804e4983ad7320ff7a5840 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sat, 10 Jul 2021 22:04:01 -0700 Subject: [PATCH 028/155] Updated workflow to wait until cypress exits to upload the artifact --- .github/workflows/aps-cypress-e2e.yaml | 10 +++++----- e2e/entrypoint.sh | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index d5d86aaf1..4e6889c5a 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -12,11 +12,6 @@ jobs: - uses: actions/checkout@v1 - name: Spin up API Services Portal and Run E2E Tests run: docker-compose up -d - - name: Upload E2E Test Report as Artifact - uses: actions/upload-artifact@v2 - with: - name: E2E Test Report - path: ${{ github.workspace }}/e2e/results/report/*.html - name: Stop the Containers run: | while true; do @@ -31,3 +26,8 @@ jobs: sleep 1m fi done + - name: Upload E2E Test Report as Artifact + uses: actions/upload-artifact@v2 + with: + name: E2E Test Report + path: ${{ github.workspace }}/e2e/results/report/*.html diff --git a/e2e/entrypoint.sh b/e2e/entrypoint.sh index 2a7104f18..ced59c816 100755 --- a/e2e/entrypoint.sh +++ b/e2e/entrypoint.sh @@ -9,12 +9,12 @@ while true; do echo "Keycloak is up" cd /e2e # added sleep to wait for initial data seeding - sleep 2m + sleep 1m npm run cy:run:html break else echo "Waiting for Keycloak....." - sleep 3m + sleep 2m fi done From 479df31e8346d139d77d6032e3166f6ff1f119d0 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sun, 11 Jul 2021 23:20:42 -0700 Subject: [PATCH 029/155] Updated environment variables and documentation --- docker-compose.yml | 3 +++ e2e/.env.local | 6 ++++++ e2e/READEME.md | 6 +++--- e2e/cypress.env.local.json | 6 ------ e2e/cypress.json | 7 +------ e2e/docker-compose.yml | 4 ++-- e2e/package.json | 4 ++-- 7 files changed, 17 insertions(+), 19 deletions(-) create mode 100644 e2e/.env.local delete mode 100644 e2e/cypress.env.local.json diff --git a/docker-compose.yml b/docker-compose.yml index 2a5b4175e..6d6b374db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -102,6 +102,7 @@ services: image: feeder:latest command: '' entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" + restart: on-failure depends_on: - feeder volumes: @@ -118,10 +119,12 @@ services: dockerfile: Dockerfile environment: # DEBUG: cypress:* - Writes complete log + CYPRESS_BASE_URL: http://oauth2proxy.localtest.me:4180 CYPRESS_PORTAL_USERNAME: local CYPRESS_PORTAL_PASSWORD: local CYPRESS_CLIENT_ID: aps-portal CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 + CYPRESS_OIDC_ISSUER: http://keycloak.localtest.me:9080/auth/realms/master volumes: - ./e2e/results/report:/e2e/results/report networks: diff --git a/e2e/.env.local b/e2e/.env.local new file mode 100644 index 000000000..607363d47 --- /dev/null +++ b/e2e/.env.local @@ -0,0 +1,6 @@ +CYPRESS_BASE_URL= +CYPRESS_PORTAL_USERNAME= +CYPRESS_PORTAL_PASSWORD= +CYPRESS_CLIENT_ID= +CYPRESS_CLIENT_SECRET= +CYPRESS_OIDC_ISSUER= diff --git a/e2e/READEME.md b/e2e/READEME.md index d41dbde44..3d6ba1176 100644 --- a/e2e/READEME.md +++ b/e2e/READEME.md @@ -25,7 +25,7 @@ The steps below will take you all the way through Cypress. It is assumed you hav ### 2. Run Tests - Clone this repository -- Create a new file `cypress.env.json` from `cypress.env.local.json` +- Create a new file `.env` from `.env.local` - Replace `` with appropriate values #### 2.1 Locally @@ -36,7 +36,7 @@ The steps below will take you all the way through Cypress. It is assumed you hav #### 2.2 Docker - Run `docker build -t aps-cypress-e2e:latest ` to build an image -- Run `docker run --rm -it -name aps-cypress-e2e aps-cypress-e2e:latest` to spin up a container to run the tests +- Run `docker run --rm -it --env-file .env -name aps-cypress-e2e aps-cypress-e2e:latest` to spin up a container to run the tests #### 2.3 Docker Compose @@ -45,7 +45,7 @@ The steps below will take you all the way through Cypress. It is assumed you hav #### 2.4 GitHub Actions -- Any new commit pushed to `feature/automation-*` branch triggers a job (`.github/workflows/ci-build-deploy-e2e.yaml`) and deploys a container to execute the test suite +- Any new commit pushed to `feature/automation-*` branch triggers a job (`.github/workflows/aps-cypress-e2e.yaml`) and deploys a container to execute the test suite ## Cypress IntelliSense diff --git a/e2e/cypress.env.local.json b/e2e/cypress.env.local.json deleted file mode 100644 index adb6be601..000000000 --- a/e2e/cypress.env.local.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "PORTAL_USERNAME": "", - "PORTAL_PASSWORD": "", - "CLIENT_ID": "", - "CLIENT_SECRET": "" -} diff --git a/e2e/cypress.json b/e2e/cypress.json index 0988a7b93..47ab9f178 100644 --- a/e2e/cypress.json +++ b/e2e/cypress.json @@ -1,5 +1,4 @@ { - "baseUrl": "http://oauth2proxy.localtest.me:4180", "integrationFolder": "cypress/tests", "screenshotOnRunFailure": false, "video": false, @@ -11,9 +10,5 @@ "json": true, "overwrite": false }, - "chromeWebSecurity": false, - "env": { - "OIDC_ISSUER": "http://keycloak.localtest.me:9080/auth/realms/master", - "TESTS_ENV": "dev" - } + "chromeWebSecurity": false } diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index eff818669..f23b2eaad 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -7,7 +7,7 @@ services: build: context: . dockerfile: Dockerfile - # environment: - # DEBUG: cypress:* - Writes complete log + env_file: + - .env volumes: - ./results/report:/e2e/results/report diff --git a/e2e/package.json b/e2e/package.json index 847e4b484..44efffd9e 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -9,8 +9,8 @@ "cy:open": "cypress open --config-file cypress.json", "cy:run": "cypress run --config-file cypress.json", "cy:run:cfg": "cypress run --config", - "moch:json": "mochawesome-merge -f results/*.json -o results/report/bcgov-aps-cypress-e2e-report.json", - "moch:html": "marge results/report/bcgov-aps-cypress-e2e-report.json --reportDir results/report --inline", + "moch:json": "mochawesome-merge -f results/*.json -o results/report/bcgov-aps-e2e-report.json", + "moch:html": "marge results/report/bcgov-aps-e2e-report.json --reportDir results/report -i -t 'API Services Portal E2E Test Report'", "cy:run:html": "run-s --continue-on-error cy:run moch:json moch:html" }, "devDependencies": { From 3eadd97164dce35940f2b4145d4b955662435921 Mon Sep 17 00:00:00 2001 From: NithinKuruba <81444731+NithinKuruba@users.noreply.github.com> Date: Mon, 12 Jul 2021 12:14:27 -0700 Subject: [PATCH 030/155] Removing cypress.json to make it environment specific --- e2e/cypress.json | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 e2e/cypress.json diff --git a/e2e/cypress.json b/e2e/cypress.json deleted file mode 100644 index 47ab9f178..000000000 --- a/e2e/cypress.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "integrationFolder": "cypress/tests", - "screenshotOnRunFailure": false, - "video": false, - "watchForFileChanges": true, - "reporter": "mochawesome", - "reporterOptions": { - "reportDir": "results", - "html": false, - "json": true, - "overwrite": false - }, - "chromeWebSecurity": false -} From 12b895e148b7493dee5934748b132d6a6e036a9e Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Mon, 12 Jul 2021 12:38:36 -0700 Subject: [PATCH 031/155] Updated the cypress config file and readme --- docker-compose.yml | 8 -------- e2e/.env.local | 6 ------ e2e/.gitignore | 3 ++- e2e/Dockerfile | 2 +- e2e/{READEME.md => README.md} | 22 ++++++++++++---------- e2e/cypress.local.json | 22 ++++++++++++++++++++++ e2e/docker-compose.yml | 13 ------------- e2e/package.json | 4 ++-- 8 files changed, 39 insertions(+), 41 deletions(-) delete mode 100644 e2e/.env.local rename e2e/{READEME.md => README.md} (79%) create mode 100644 e2e/cypress.local.json delete mode 100644 e2e/docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml index 6d6b374db..8eaf97aa4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -117,14 +117,6 @@ services: build: context: ./e2e dockerfile: Dockerfile - environment: - # DEBUG: cypress:* - Writes complete log - CYPRESS_BASE_URL: http://oauth2proxy.localtest.me:4180 - CYPRESS_PORTAL_USERNAME: local - CYPRESS_PORTAL_PASSWORD: local - CYPRESS_CLIENT_ID: aps-portal - CYPRESS_CLIENT_SECRET: 8e1a17ed-cb93-4806-ac32-e303d1c86018 - CYPRESS_OIDC_ISSUER: http://keycloak.localtest.me:9080/auth/realms/master volumes: - ./e2e/results/report:/e2e/results/report networks: diff --git a/e2e/.env.local b/e2e/.env.local deleted file mode 100644 index 607363d47..000000000 --- a/e2e/.env.local +++ /dev/null @@ -1,6 +0,0 @@ -CYPRESS_BASE_URL= -CYPRESS_PORTAL_USERNAME= -CYPRESS_PORTAL_PASSWORD= -CYPRESS_CLIENT_ID= -CYPRESS_CLIENT_SECRET= -CYPRESS_OIDC_ISSUER= diff --git a/e2e/.gitignore b/e2e/.gitignore index 4ba72e3b3..16e8fbf37 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,3 +1,4 @@ integration cypress.env.json -results \ No newline at end of file +results +cypress.json \ No newline at end of file diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 2a271ca3f..649647a78 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /e2e RUN apt-get install curl -COPY cypress.json /e2e +COPY cypress.local.json /e2e COPY tsconfig.json /e2e COPY package.json /e2e COPY package-lock.json /e2e diff --git a/e2e/READEME.md b/e2e/README.md similarity index 79% rename from e2e/READEME.md rename to e2e/README.md index 3d6ba1176..3be3cd86c 100644 --- a/e2e/READEME.md +++ b/e2e/README.md @@ -25,23 +25,25 @@ The steps below will take you all the way through Cypress. It is assumed you hav ### 2. Run Tests - Clone this repository -- Create a new file `.env` from `.env.local` -- Replace `` with appropriate values +- Run `npm install` to install all the dependencies #### 2.1 Locally -- Run `npm install` to install all the dependencies -- Run `npm run cy:run` to run the tests +##### 2.1.1 Cypress Test Runner + +- Create a new file `cypress.json` from `cypress.local.json` + +- Run `npm run cy:open` to open the test runner and execute tests selectively -#### 2.2 Docker +##### 2.2.2 Cypress Headless -- Run `docker build -t aps-cypress-e2e:latest ` to build an image -- Run `docker run --rm -it --env-file .env -name aps-cypress-e2e aps-cypress-e2e:latest` to spin up a container to run the tests +- Run `npm run cy:run` to run the tests and print the results to the console +- Run `npm run cy:run:html` to run the tests and generate `mochawesome` report under `results/report` -#### 2.3 Docker Compose +#### 2.2 Docker Compose -- Run `docker-compose up` to spin a container that run cypress as a service and it executes the tests -- Run `docker-compose down` to tear down the container +- Run `docker-compose up` under parent folder `api-services-portal` to spin up a local environment, which includes cypress as one of the service and it executes the tests +- Run `docker-compose down` to tear down the containers #### 2.4 GitHub Actions diff --git a/e2e/cypress.local.json b/e2e/cypress.local.json new file mode 100644 index 000000000..833bf2c87 --- /dev/null +++ b/e2e/cypress.local.json @@ -0,0 +1,22 @@ +{ + "baseUrl": "http://oauth2proxy.localtest.me:4180", + "integrationFolder": "cypress/tests", + "screenshotOnRunFailure": false, + "video": false, + "watchForFileChanges": true, + "reporter": "mochawesome", + "reporterOptions": { + "reportDir": "results", + "html": false, + "json": true, + "overwrite": false + }, + "chromeWebSecurity": false, + "env": { + "PORTAL_USERNAME": "local", + "PORTAL_PASSWORD": "local", + "CLIENT_ID": "aps-portal", + "CLIENT_SECRET": "8e1a17ed-cb93-4806-ac32-e303d1c86018", + "OIDC_ISSUER": "http://keycloak.localtest.me:9080" + } +} diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml deleted file mode 100644 index f23b2eaad..000000000 --- a/e2e/docker-compose.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: '3.2' - -services: - cypress: - image: 'aps-cypress-e2e:latest' - container_name: cypress-e2e - build: - context: . - dockerfile: Dockerfile - env_file: - - .env - volumes: - - ./results/report:/e2e/results/report diff --git a/e2e/package.json b/e2e/package.json index 44efffd9e..a5f4f6159 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -7,8 +7,8 @@ "license": "MIT", "scripts": { "cy:open": "cypress open --config-file cypress.json", - "cy:run": "cypress run --config-file cypress.json", - "cy:run:cfg": "cypress run --config", + "cy:run": "cypress run --config-file cypress.local.json", + "cy:run:dev": "cypress run --config-file cypress.json", "moch:json": "mochawesome-merge -f results/*.json -o results/report/bcgov-aps-e2e-report.json", "moch:html": "marge results/report/bcgov-aps-e2e-report.json --reportDir results/report -i -t 'API Services Portal E2E Test Report'", "cy:run:html": "run-s --continue-on-error cy:run moch:json moch:html" From 124caf759cede7252c8dec5aa8798df47afbe529 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Mon, 12 Jul 2021 19:55:33 -0700 Subject: [PATCH 032/155] added a dependency to cypress --- docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 8eaf97aa4..815effe0f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -114,6 +114,8 @@ services: image: 'aps-cypress-e2e:latest' container_name: cypress-e2e entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" + depends_on: + - feeder-seeding build: context: ./e2e dockerfile: Dockerfile From 76bef0e5e75512ff574b902327832e38dbe93297 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 13 Jul 2021 11:13:34 -0700 Subject: [PATCH 033/155] Updated login and logout specs to one single spec that defines authentication flow --- e2e/cypress/support/auth-commands.ts | 35 +++++++++++++++++----------- e2e/cypress/support/global.d.ts | 6 ++++- e2e/cypress/tests/01-auth.spec.ts | 28 ++++++++++++++++++++++ e2e/cypress/tests/login.spec.ts | 18 -------------- e2e/cypress/tests/logout.spec.ts | 29 ----------------------- 5 files changed, 54 insertions(+), 62 deletions(-) create mode 100644 e2e/cypress/tests/01-auth.spec.ts delete mode 100644 e2e/cypress/tests/login.spec.ts delete mode 100644 e2e/cypress/tests/logout.spec.ts diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index 0e523d015..a7a3f89da 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -25,32 +25,30 @@ Cypress.Commands.add('login', (username, password) => { expect(loc.protocol).to.eq(appURL.protocol) expect(loc.hostname).to.eq(appURL.hostname) }) + log.end() +}) + +Cypress.Commands.add('saveCookies', () => { //saving the session cookie cy.getCookies().then((cookies) => { cookies.map((cookie) => { Cypress.Cookies.preserveOnce(cookie.name) }) }) - - log.end() }) -Cypress.Commands.add('getSession', (url: string) => { - cy.request({ method: 'GET', url: url }) - .then((response) => { - expect(response.status).to.eq(200) - expect(response.body).to.include({ anonymous: false }) - }) - .then((response: any) => { +Cypress.Commands.add('getSession', () => { + cy.request({ method: 'GET', url: Cypress.config('baseUrl') + '/admin/session' }).then( + (res) => { + cy.wrap(res).as('session') + expect(res.status).to.eq(200) const log = Cypress.log({ name: 'Session Info', displayName: 'SESSION_INFO', - message: JSON.stringify(response.body.user), + message: JSON.stringify(res.body), }) - }) - .then((response) => { - cy.wrap(response.body) - }) + } + ) }) Cypress.Commands.add('loginByAuthAPI', (username: string, password: string) => { @@ -85,3 +83,12 @@ Cypress.Commands.add('loginByAuthAPI', (username: string, password: string) => { log.snapshot('after') log.end() }) + +Cypress.Commands.add('logout', () => { + cy.getSession().then(() => { + cy.get('@session').then((res: any) => { + cy.contains(res.body.user.name).click() + cy.contains('Sign Out').click() + }) + }) +}) diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts index d77bacc9f..5c054e047 100644 --- a/e2e/cypress/support/global.d.ts +++ b/e2e/cypress/support/global.d.ts @@ -4,12 +4,16 @@ declare namespace Cypress { interface Chainable { login(username: string, password: string): Chainable - getSession(url: string): Chainable + getSession(): Chainable callApi(options: Partial): Chainable addContext(message: any): Chainable loginByAuthAPI(username: string, password: string): Chainable + + logout(): Chainable + + saveCookies(): Chainable } } diff --git a/e2e/cypress/tests/01-auth.spec.ts b/e2e/cypress/tests/01-auth.spec.ts new file mode 100644 index 000000000..e9d5c46f7 --- /dev/null +++ b/e2e/cypress/tests/01-auth.spec.ts @@ -0,0 +1,28 @@ +describe('Authentication spec', () => { + before(() => { + cy.clearCookies() + }) + afterEach(() => { + cy.saveCookies() + }) + it('should find login button', () => { + cy.visit('/') + cy.xpath('//button').contains('Login') + }) + + it('should allow user to authenticate', () => { + cy.login(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) + }) + + it('should save user session after login', () => { + cy.getSession().then(() => { + cy.get('@session').then((res: any) => { + expect(res.body).to.include({ anonymous: false }) + }) + }) + }) + + it('should allow user to logout', () => { + cy.logout() + }) +}) diff --git a/e2e/cypress/tests/login.spec.ts b/e2e/cypress/tests/login.spec.ts deleted file mode 100644 index 794c49dfd..000000000 --- a/e2e/cypress/tests/login.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -describe('Login spec', () => { - beforeEach(() => { - cy.visit('/') - }) - it('should have login button', () => { - cy.xpath('//button').contains('Login') - }) - - it('should allow user to authenticate', () => { - cy.login(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) - }) - - it('should save user session after login', () => { - cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { - cy.log('logged user - ' + JSON.stringify(sessionObj.user)) - }) - }) -}) diff --git a/e2e/cypress/tests/logout.spec.ts b/e2e/cypress/tests/logout.spec.ts deleted file mode 100644 index e41261919..000000000 --- a/e2e/cypress/tests/logout.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -describe('Logout spec', () => { - beforeEach(() => { - cy.visit('/') - }) - it('should check user session and login if not logged on', () => { - if (cy.xpath('//button').contains('Login')) { - cy.login(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) - cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { - cy.log('logged user - ' + JSON.stringify(sessionObj.user)) - }) - } else { - cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { - cy.log('logged user - ' + JSON.stringify(sessionObj.user)) - }) - } - }) - - it('should allow user to logout', () => { - cy.getSession(Cypress.config('baseUrl') + '/admin/session').then((sessionObj: any) => { - cy.contains(sessionObj.user.name).click() - }) - - cy.contains('Sign Out').click() - }) - - it('should show login button after logout', () => { - cy.xpath('//button').contains('Login') - }) -}) From eed2466dc034bf05a79fe9e06966d55d6d08cd7f Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 13 Jul 2021 11:53:01 -0700 Subject: [PATCH 034/155] Saving cookies before each test --- e2e/README.md | 6 +++--- e2e/cypress/support/auth-commands.ts | 2 ++ e2e/cypress/tests/01-auth.spec.ts | 7 ++++--- e2e/package.json | 3 ++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/e2e/README.md b/e2e/README.md index 3be3cd86c..81f3bf9f4 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -29,16 +29,16 @@ The steps below will take you all the way through Cypress. It is assumed you hav #### 2.1 Locally -##### 2.1.1 Cypress Test Runner +- Create a new file `cypress.json` from `cypress.local.json` and update any params if necessary -- Create a new file `cypress.json` from `cypress.local.json` +##### 2.1.1 Cypress Test Runner - Run `npm run cy:open` to open the test runner and execute tests selectively ##### 2.2.2 Cypress Headless - Run `npm run cy:run` to run the tests and print the results to the console -- Run `npm run cy:run:html` to run the tests and generate `mochawesome` report under `results/report` +- Run `npm run cy:run:dev:html` to run the tests and generate `mochawesome` report under `results/report` #### 2.2 Docker Compose diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index a7a3f89da..1858119ac 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -26,6 +26,7 @@ Cypress.Commands.add('login', (username, password) => { expect(loc.hostname).to.eq(appURL.hostname) }) log.end() + cy.saveCookies() }) Cypress.Commands.add('saveCookies', () => { @@ -49,6 +50,7 @@ Cypress.Commands.add('getSession', () => { }) } ) + cy.saveCookies() }) Cypress.Commands.add('loginByAuthAPI', (username: string, password: string) => { diff --git a/e2e/cypress/tests/01-auth.spec.ts b/e2e/cypress/tests/01-auth.spec.ts index e9d5c46f7..4a993af9a 100644 --- a/e2e/cypress/tests/01-auth.spec.ts +++ b/e2e/cypress/tests/01-auth.spec.ts @@ -1,9 +1,10 @@ -describe('Authentication spec', () => { +describe('Authentication spec', { retries: 2 }, () => { before(() => { cy.clearCookies() }) - afterEach(() => { - cy.saveCookies() + + beforeEach(() => { + cy.visit('/') }) it('should find login button', () => { cy.visit('/') diff --git a/e2e/package.json b/e2e/package.json index a5f4f6159..2fef30564 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -11,7 +11,8 @@ "cy:run:dev": "cypress run --config-file cypress.json", "moch:json": "mochawesome-merge -f results/*.json -o results/report/bcgov-aps-e2e-report.json", "moch:html": "marge results/report/bcgov-aps-e2e-report.json --reportDir results/report -i -t 'API Services Portal E2E Test Report'", - "cy:run:html": "run-s --continue-on-error cy:run moch:json moch:html" + "cy:run:html": "run-s --continue-on-error cy:run moch:json moch:html", + "cy:run:dev:html": "run-s --continue-on-error cy:run:dev moch:json moch:html" }, "devDependencies": { "@types/jsonwebtoken": "^8.5.4", From 2df64c64512309fbaedcc0b172e01f50dfd64169 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 13 Jul 2021 19:47:48 -0700 Subject: [PATCH 035/155] Updated the cypress config to include app screenshots upon test failure --- .github/workflows/aps-cypress-e2e.yaml | 4 ++-- e2e/cypress.local.json | 3 ++- e2e/cypress/support/auth-commands.ts | 2 +- e2e/cypress/support/index.ts | 9 +++++++++ e2e/package.json | 4 ++-- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 4e6889c5a..c143c87dd 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -29,5 +29,5 @@ jobs: - name: Upload E2E Test Report as Artifact uses: actions/upload-artifact@v2 with: - name: E2E Test Report - path: ${{ github.workspace }}/e2e/results/report/*.html + name: report + path: ${{ github.workspace }}/e2e/results/report diff --git a/e2e/cypress.local.json b/e2e/cypress.local.json index 833bf2c87..cb4529417 100644 --- a/e2e/cypress.local.json +++ b/e2e/cypress.local.json @@ -1,7 +1,8 @@ { "baseUrl": "http://oauth2proxy.localtest.me:4180", "integrationFolder": "cypress/tests", - "screenshotOnRunFailure": false, + "screenshotOnRunFailure": true, + "screenshotsFolder": "results/report/assets", "video": false, "watchForFileChanges": true, "reporter": "mochawesome", diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index 1858119ac..63a6dc57f 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -4,7 +4,7 @@ import * as jwt from 'jsonwebtoken' Cypress.Commands.add('login', (username, password) => { const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) const appURL = new URL(Cypress.config('baseUrl')) - cy.xpath("//button[normalize-space()='Login']").click() + cy.xpath('//button').contains('Login').click() cy.location().should((loc) => { expect(loc.protocol).to.eq(oidcProviderURL.protocol) expect(loc.hostname).to.eq(oidcProviderURL.hostname) diff --git a/e2e/cypress/support/index.ts b/e2e/cypress/support/index.ts index a3a3948cb..02e72124f 100644 --- a/e2e/cypress/support/index.ts +++ b/e2e/cypress/support/index.ts @@ -2,3 +2,12 @@ import './commands' import 'cypress-xpath' import './auth-commands' import './api-commands' + +const addContext = require('mochawesome/addContext') + +Cypress.on('test:after:run', (test, runnable) => { + if (test.state === 'failed') { + const screenshot = `assets/${Cypress.spec.name}/${runnable.parent.title} -- ${test.title} (failed).png` + addContext({ test }, screenshot) + } +}) diff --git a/e2e/package.json b/e2e/package.json index 2fef30564..c349f7c7a 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -9,8 +9,8 @@ "cy:open": "cypress open --config-file cypress.json", "cy:run": "cypress run --config-file cypress.local.json", "cy:run:dev": "cypress run --config-file cypress.json", - "moch:json": "mochawesome-merge -f results/*.json -o results/report/bcgov-aps-e2e-report.json", - "moch:html": "marge results/report/bcgov-aps-e2e-report.json --reportDir results/report -i -t 'API Services Portal E2E Test Report'", + "moch:json": "mochawesome-merge -f results/*.json -o results/bcgov-aps-e2e-report.json", + "moch:html": "marge results/bcgov-aps-e2e-report.json --reportDir results/report -i -t \"API Services Portal E2E Test Report\"", "cy:run:html": "run-s --continue-on-error cy:run moch:json moch:html", "cy:run:dev:html": "run-s --continue-on-error cy:run:dev moch:json moch:html" }, From a0099fdb5a0afa7ab380a8f4656bfe1f01240c14 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 13 Jul 2021 20:21:30 -0700 Subject: [PATCH 036/155] Saving cookies by name and removed custom command that used to save all the cookies --- e2e/cypress/support/auth-commands.ts | 11 ----------- e2e/cypress/support/global.d.ts | 2 -- e2e/cypress/support/index.ts | 9 +++++++++ e2e/cypress/tests/01-auth.spec.ts | 6 +----- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index 63a6dc57f..5c490a238 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -26,16 +26,6 @@ Cypress.Commands.add('login', (username, password) => { expect(loc.hostname).to.eq(appURL.hostname) }) log.end() - cy.saveCookies() -}) - -Cypress.Commands.add('saveCookies', () => { - //saving the session cookie - cy.getCookies().then((cookies) => { - cookies.map((cookie) => { - Cypress.Cookies.preserveOnce(cookie.name) - }) - }) }) Cypress.Commands.add('getSession', () => { @@ -50,7 +40,6 @@ Cypress.Commands.add('getSession', () => { }) } ) - cy.saveCookies() }) Cypress.Commands.add('loginByAuthAPI', (username: string, password: string) => { diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts index 5c054e047..d8ae9e9eb 100644 --- a/e2e/cypress/support/global.d.ts +++ b/e2e/cypress/support/global.d.ts @@ -13,7 +13,5 @@ declare namespace Cypress { loginByAuthAPI(username: string, password: string): Chainable logout(): Chainable - - saveCookies(): Chainable } } diff --git a/e2e/cypress/support/index.ts b/e2e/cypress/support/index.ts index 02e72124f..8a665a111 100644 --- a/e2e/cypress/support/index.ts +++ b/e2e/cypress/support/index.ts @@ -11,3 +11,12 @@ Cypress.on('test:after:run', (test, runnable) => { addContext({ test }, screenshot) } }) + +Cypress.Cookies.defaults({ + preserve: [ + '_oauth2_proxy', + '_oauth2_proxy_csrf', + 'ab547b670fc5c67e38dbef98822b7c8d', + 'keystone.sid', + ], +}) diff --git a/e2e/cypress/tests/01-auth.spec.ts b/e2e/cypress/tests/01-auth.spec.ts index 4a993af9a..ae389bbc5 100644 --- a/e2e/cypress/tests/01-auth.spec.ts +++ b/e2e/cypress/tests/01-auth.spec.ts @@ -1,8 +1,4 @@ -describe('Authentication spec', { retries: 2 }, () => { - before(() => { - cy.clearCookies() - }) - +describe('Authentication spec', () => { beforeEach(() => { cy.visit('/') }) From 1d33f907e09f387b678a23ef8afb47abe09aeaa5 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 15 Jul 2021 10:24:55 -0700 Subject: [PATCH 037/155] added redis as a service for storing user sessions --- docker-compose.yml | 14 ++++++++++++++ local/oauth2-proxy/oauth2-proxy-local.cfg | 10 +++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 815effe0f..fae8db0cc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -57,6 +57,7 @@ services: keycloak: {} portal: {} kong-net: {} + redis-net: {} oauth2-proxy: aliases: - oauth2proxy.localtest.me @@ -182,8 +183,21 @@ services: aliases: - kong.localtest.me restart: on-failure:5 + redis: + image: bitnami/redis:latest + container_name: redis + environment: + - REDIS_PASSWORD=s3cr3t + restart: on-failure + ports: + - 6379:6379 + networks: + redis-net: + aliases: + - redis.localtest.me networks: keycloak: {} oauth2-proxy: {} portal: {} kong-net: {} + redis-net: {} diff --git a/local/oauth2-proxy/oauth2-proxy-local.cfg b/local/oauth2-proxy/oauth2-proxy-local.cfg index e5b9242b9..066f7826d 100644 --- a/local/oauth2-proxy/oauth2-proxy-local.cfg +++ b/local/oauth2-proxy/oauth2-proxy-local.cfg @@ -11,9 +11,10 @@ login_url="http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid- redeem_url="http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid-connect/token" validate_url="http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid-connect/userinfo" redirect_url="http://oauth2proxy.localtest.me:4180/oauth2/callback" +profile_url="http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid-connect/userinfo" cookie_secure="false" -cookie_refresh="5m" -cookie_expire="2h" +cookie_refresh="3m" +cookie_expire="24h" pass_basic_auth="false" pass_access_token="true" set_xauthrequest="true" @@ -23,4 +24,7 @@ pass_authorization_header="false" skip_auth_regex="/health|/home|/public|/docs|/redirect|/_next|/images|/devportal|/manager|/ds/api|/signout|/ds/api/swagger.yaml|^[/]$" whitelist_domains="*" upstreams=["http://apsportal.localtest.me:3000"] -skip_provider_button='true' \ No newline at end of file +skip_provider_button='true' +redis_connection_url="redis://redis.localtest.me:6379" +session_store_type='redis' +redis_password='s3cr3t' \ No newline at end of file From df5b429f9261ba300de5f64f6c307b0cca61f7a7 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Mon, 19 Jul 2021 19:56:34 -0700 Subject: [PATCH 038/155] Added latest test cases to create namespace and service account. Also added code to save the state to a file and use it in the later tests. --- e2e/.gitignore | 3 +- e2e/Dockerfile | 2 +- e2e/{cypress.local.json => cypress.json} | 5 +- e2e/cypress/fixtures/api-owner.json | 12 +++++ e2e/cypress/fixtures/developer.json | 8 +++ e2e/cypress/fixtures/service.yaml | 19 +++++++ e2e/cypress/fixtures/state/store.json | 3 ++ e2e/cypress/pageObjects/home.ts | 26 ++++++++++ e2e/cypress/pageObjects/login.ts | 10 ++++ e2e/cypress/pageObjects/namespaces.ts | 9 ++++ e2e/cypress/pageObjects/serviceAccounts.ts | 29 +++++++++++ e2e/cypress/pageObjects/toolbar.ts | 10 ++++ e2e/cypress/support/api-commands.ts | 9 ---- e2e/cypress/support/auth-commands.ts | 19 +++---- e2e/cypress/support/commands.ts | 8 --- e2e/cypress/support/global.d.ts | 17 ++++--- e2e/cypress/support/index.ts | 17 ++----- e2e/cypress/support/util-commands.ts | 49 +++++++++++++++++++ .../{ => 01-Authentication}/01-auth.spec.ts | 14 ++++-- .../tests/02-CreateAPI/01-namespace.ts | 35 +++++++++++++ .../tests/02-CreateAPI/02-serviceaccount.ts | 47 ++++++++++++++++++ e2e/package-lock.json | 9 ++++ e2e/package.json | 11 +++-- e2e/tsconfig.json | 6 ++- 24 files changed, 316 insertions(+), 61 deletions(-) rename e2e/{cypress.local.json => cypress.json} (76%) create mode 100644 e2e/cypress/fixtures/api-owner.json create mode 100644 e2e/cypress/fixtures/developer.json create mode 100644 e2e/cypress/fixtures/service.yaml create mode 100644 e2e/cypress/fixtures/state/store.json create mode 100644 e2e/cypress/pageObjects/home.ts create mode 100644 e2e/cypress/pageObjects/login.ts create mode 100644 e2e/cypress/pageObjects/namespaces.ts create mode 100644 e2e/cypress/pageObjects/serviceAccounts.ts create mode 100644 e2e/cypress/pageObjects/toolbar.ts delete mode 100644 e2e/cypress/support/api-commands.ts create mode 100644 e2e/cypress/support/util-commands.ts rename e2e/cypress/tests/{ => 01-Authentication}/01-auth.spec.ts (55%) create mode 100644 e2e/cypress/tests/02-CreateAPI/01-namespace.ts create mode 100644 e2e/cypress/tests/02-CreateAPI/02-serviceaccount.ts diff --git a/e2e/.gitignore b/e2e/.gitignore index 16e8fbf37..4ba72e3b3 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,4 +1,3 @@ integration cypress.env.json -results -cypress.json \ No newline at end of file +results \ No newline at end of file diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 649647a78..2a271ca3f 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /e2e RUN apt-get install curl -COPY cypress.local.json /e2e +COPY cypress.json /e2e COPY tsconfig.json /e2e COPY package.json /e2e COPY package-lock.json /e2e diff --git a/e2e/cypress.local.json b/e2e/cypress.json similarity index 76% rename from e2e/cypress.local.json rename to e2e/cypress.json index cb4529417..287245166 100644 --- a/e2e/cypress.local.json +++ b/e2e/cypress.json @@ -14,10 +14,9 @@ }, "chromeWebSecurity": false, "env": { - "PORTAL_USERNAME": "local", - "PORTAL_PASSWORD": "local", "CLIENT_ID": "aps-portal", "CLIENT_SECRET": "8e1a17ed-cb93-4806-ac32-e303d1c86018", - "OIDC_ISSUER": "http://keycloak.localtest.me:9080" + "OIDC_ISSUER": "http://keycloak.localtest.me:9080", + "TOKEN_URL": "http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid-connect/token" } } diff --git a/e2e/cypress/fixtures/api-owner.json b/e2e/cypress/fixtures/api-owner.json new file mode 100644 index 000000000..e14a5a8dc --- /dev/null +++ b/e2e/cypress/fixtures/api-owner.json @@ -0,0 +1,12 @@ +{ + "user": { + "credentials": { + "username": "awsummer@idir", + "password": "awsummer" + } + }, + "namespace": "platform", + "serviceAccount": { + "scopes": ["GatewayConfig.Publish", "Namespace.Manage", "Content.Publish"] + } +} diff --git a/e2e/cypress/fixtures/developer.json b/e2e/cypress/fixtures/developer.json new file mode 100644 index 000000000..e734d0caf --- /dev/null +++ b/e2e/cypress/fixtures/developer.json @@ -0,0 +1,8 @@ +{ + "user": { + "credentials": { + "username": "local", + "password": "local" + } + } +} diff --git a/e2e/cypress/fixtures/service.yaml b/e2e/cypress/fixtures/service.yaml new file mode 100644 index 000000000..92c1163bf --- /dev/null +++ b/e2e/cypress/fixtures/service.yaml @@ -0,0 +1,19 @@ +services: + - name: a-service-for-platform + host: httpbin.org + tags: [ns.platform] + port: 443 + protocol: https + retries: 0 + routes: + - name: a-service-for-platform-route + tags: [ns.platform] + hosts: + - a-service-for-platform.api.gov.bc.ca + paths: + - / + methods: + - GET + strip_path: false + https_redirect_status_code: 426 + path_handling: v0 diff --git a/e2e/cypress/fixtures/state/store.json b/e2e/cypress/fixtures/state/store.json new file mode 100644 index 000000000..e123ef5d0 --- /dev/null +++ b/e2e/cypress/fixtures/state/store.json @@ -0,0 +1,3 @@ +{ + "sa-platform-e0000000-37f7896427da": "9f0f0dc8-a5fa-4279-96dd-5f6d121a2293" +} \ No newline at end of file diff --git a/e2e/cypress/pageObjects/home.ts b/e2e/cypress/pageObjects/home.ts new file mode 100644 index 000000000..475680fc8 --- /dev/null +++ b/e2e/cypress/pageObjects/home.ts @@ -0,0 +1,26 @@ +class HomePage { + namespaceDropdown: string = + '/html[1]/body[1]/div[1]/header[1]/hgroup[2]/div[1]/div[1]/button[1]' + + namespaceSelected: string = '/html/body/div[1]/header/hgroup[2]/div[1]/div/button/span' + + namespaceNameInput: string = '/html/body/div[3]/div[4]/div/section/div/form/div/input' + + createNamespace(name: string): void { + cy.xpath(this.namespaceDropdown).click() + cy.contains('Create New Namespace').click() + cy.xpath(this.namespaceNameInput).should('be.visible').type(name) // using `platform` as a default ns as its being seeding through feeder + cy.xpath("//button[normalize-space()='Create']").click() + cy.contains('Namespace ' + name + ' created!').should('be.visible') + cy.contains('Switched to ' + name + ' namespace').should('be.visible') + } + + useNamespace(name: string): void { + cy.xpath(this.namespaceDropdown).click() + cy.contains(name).click() + cy.contains('Switched to ' + name + ' namespace').should('be.visible') + cy.xpath(this.namespaceSelected).should('include.text', name) + } +} + +export default HomePage diff --git a/e2e/cypress/pageObjects/login.ts b/e2e/cypress/pageObjects/login.ts new file mode 100644 index 000000000..e2bc3477e --- /dev/null +++ b/e2e/cypress/pageObjects/login.ts @@ -0,0 +1,10 @@ +class LoginPage { + path: string = '/' + + loginButton: string = "//button[normalize-space()='Login']" + usernameInput: string = "//input[@id='username']" + passwordInput: string = "//input[@id='password']" + loginSubmitButton: string = "//input[@id='kc-login']" +} + +export default LoginPage diff --git a/e2e/cypress/pageObjects/namespaces.ts b/e2e/cypress/pageObjects/namespaces.ts new file mode 100644 index 000000000..e66ed5371 --- /dev/null +++ b/e2e/cypress/pageObjects/namespaces.ts @@ -0,0 +1,9 @@ +import ToolBar from './toolbar' + +class NamespacesPage { + path: string = '' + serviceAccount: string = + '/html[1]/body[1]/div[1]/main[1]/div[1]/div[3]/div[1]/div[3]/h2[1]/a[1]' +} + +export default NamespacesPage diff --git a/e2e/cypress/pageObjects/serviceAccounts.ts b/e2e/cypress/pageObjects/serviceAccounts.ts new file mode 100644 index 000000000..a7feaba51 --- /dev/null +++ b/e2e/cypress/pageObjects/serviceAccounts.ts @@ -0,0 +1,29 @@ +class ServiceAccountsPage { + path: string = '/manager/namespaces' + newServiceAccount: string = + '/html/body/div[1]/main/div/div[2]/table/tbody/tr/td/div/div/div/button' + shareButton: string = '/html/body/div[4]/div[4]/div/section/footer/div/button[2]' + + clientId: string = + '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[1]/div[1]/code[1]' + + clientSecret: string = + '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[2]/div[1]/code[1]' + + createServiceAccount(scopes: string[]): void { + scopes.forEach((scope) => { + cy.contains(scope).click() + }) + cy.xpath(this.shareButton).click() + } + + saveServiceAcctCreds(): void { + cy.xpath(this.clientId).then(($clientId) => { + cy.xpath(this.clientSecret).then(($clientSecret) => { + cy.saveState($clientId.text(), $clientSecret.text()) + }) + }) + } +} + +export default ServiceAccountsPage diff --git a/e2e/cypress/pageObjects/toolbar.ts b/e2e/cypress/pageObjects/toolbar.ts new file mode 100644 index 000000000..2fb518eed --- /dev/null +++ b/e2e/cypress/pageObjects/toolbar.ts @@ -0,0 +1,10 @@ +class ToolBar { + optionList = '/html[1]/body[1]/div[1]/nav[1]/ul[1]' + directory: string = this.optionList + '/li[1]' + apiAccess: string = this.optionList + '/li[2]' + applications: string = this.optionList + '/li[3]' + namespaces: string = this.optionList + '/li[4]' + documentation: string = this.optionList + '/li[5]' +} + +export default ToolBar diff --git a/e2e/cypress/support/api-commands.ts b/e2e/cypress/support/api-commands.ts deleted file mode 100644 index ca96766c8..000000000 --- a/e2e/cypress/support/api-commands.ts +++ /dev/null @@ -1,9 +0,0 @@ -Cypress.Commands.add('callApi', (options: Cypress.RequestOptions) => { - cy.request({ - ...options, - }).then((res: Cypress.Response) => { - expect([200, 201]).to.contain(res.status) - cy.log(JSON.stringify(res)) - cy.wrap(res) - }) -}) diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index 5c490a238..39d4e3065 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -1,10 +1,11 @@ -import { opendir } from 'fs' import * as jwt from 'jsonwebtoken' +import LoginPage from '../pageObjects/login' -Cypress.Commands.add('login', (username, password) => { +Cypress.Commands.add('login', (username: string, password: string) => { + const login = new LoginPage() const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) - const appURL = new URL(Cypress.config('baseUrl')) - cy.xpath('//button').contains('Login').click() + const appURL = new URL(Cypress.config('baseUrl') || '') + cy.xpath(login.loginButton).click() cy.location().should((loc) => { expect(loc.protocol).to.eq(oidcProviderURL.protocol) expect(loc.hostname).to.eq(oidcProviderURL.hostname) @@ -17,9 +18,9 @@ Cypress.Commands.add('login', (username, password) => { autoEnd: false, }) - cy.get('#username').type(username) - cy.get('#password').type(password) - cy.get('#kc-login').click() + cy.xpath(login.usernameInput).type(username) + cy.xpath(login.passwordInput).type(password) + cy.xpath(login.loginSubmitButton).click() cy.location().should((loc) => { expect(loc.protocol).to.eq(appURL.protocol) @@ -54,8 +55,8 @@ Cypress.Commands.add('loginByAuthAPI', (username: string, password: string) => { url: Cypress.env('OIDC_ISSUER') + '/protocol/openid-connect/token', body: { grant_type: 'password', - username: Cypress.env('PORTAL_USERNAME'), - password: Cypress.env('PORTAL_PASSWORD'), + username: Cypress.env('DEV_USERNAME'), + password: Cypress.env('DEV_PASSWORD'), Scope: 'openid', client_id: Cypress.env('CLIENT_ID'), client_secret: Cypress.env('CLIENT_SECRET'), diff --git a/e2e/cypress/support/commands.ts b/e2e/cypress/support/commands.ts index 12d76a91e..a007e9dd0 100644 --- a/e2e/cypress/support/commands.ts +++ b/e2e/cypress/support/commands.ts @@ -22,11 +22,3 @@ // // // -- This will overwrite an existing command -- - -import * as Mocha from 'mocha' - -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -const addContext = require('mochawesome/addContext') -Cypress.Commands.add('addContext', (message) => { - cy.once('test:after:run', (test) => addContext({ test }, message)) -}) diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts index d8ae9e9eb..de5ede856 100644 --- a/e2e/cypress/support/global.d.ts +++ b/e2e/cypress/support/global.d.ts @@ -1,17 +1,22 @@ /// +/// declare namespace Cypress { interface Chainable { - login(username: string, password: string): Chainable + login(username: string, password: string): void - getSession(): Chainable + getSession(): Chainable> - callApi(options: Partial): Chainable + loginByAuthAPI(username: string, password: string): Chainable> - addContext(message: any): Chainable + logout(): void - loginByAuthAPI(username: string, password: string): Chainable + preserveCookies(): void - logout(): Chainable + saveState(key: string, value: string): void + + getState(key: string): string + + clearState(): void } } diff --git a/e2e/cypress/support/index.ts b/e2e/cypress/support/index.ts index 8a665a111..488eae4ae 100644 --- a/e2e/cypress/support/index.ts +++ b/e2e/cypress/support/index.ts @@ -1,22 +1,15 @@ import './commands' import 'cypress-xpath' import './auth-commands' -import './api-commands' +import './util-commands' +const _ = require('lodash') +const YAML = require('yamljs') const addContext = require('mochawesome/addContext') -Cypress.on('test:after:run', (test, runnable) => { +Cypress.on('test:after:run', (test: Mocha.Test, runnable: Mocha.Runnable) => { if (test.state === 'failed') { - const screenshot = `assets/${Cypress.spec.name}/${runnable.parent.title} -- ${test.title} (failed).png` + const screenshot = `assets/${Cypress.spec.name}/${runnable?.parent?.title} -- ${test.title} (failed).png` addContext({ test }, screenshot) } }) - -Cypress.Cookies.defaults({ - preserve: [ - '_oauth2_proxy', - '_oauth2_proxy_csrf', - 'ab547b670fc5c67e38dbef98822b7c8d', - 'keystone.sid', - ], -}) diff --git a/e2e/cypress/support/util-commands.ts b/e2e/cypress/support/util-commands.ts new file mode 100644 index 000000000..6c0e22894 --- /dev/null +++ b/e2e/cypress/support/util-commands.ts @@ -0,0 +1,49 @@ +Cypress.Commands.add('preserveCookies', () => { + Cypress.Cookies.preserveOnce( + ...[ + '_oauth2_proxy', + '_oauth2_proxy_csrf', + 'ab547b670fc5c67e38dbef98822b7c8d', + 'keystone.sid', + ] + ) + Cypress.Cookies.debug(true, { verbose: false }) +}) + +Cypress.Commands.add('saveState', (key: string, value: string) => { + cy.log(key, value) + if (key.includes('>')) { + let keyItems = key.split('>') + cy.readFile('cypress/fixtures/state/store.json').then((currState) => { + let newState = currState + _.set(newState, keyItems, value) + cy.writeFile('cypress/fixtures/state/store.json', newState) + }) + } else { + cy.readFile('cypress/fixtures/state/store.json').then((currState) => { + currState[key] = value + cy.writeFile('cypress/fixtures/state/store.json', currState) + }) + } +}) + +Cypress.Commands.add('getState', (key: string) => { + if (key.includes('>')) { + let keyItems = key.split('>') + cy.readFile('cypress/fixtures/state/store.json').then((state) => { + return _.get(state, keyItems) + }) + } else { + cy.readFile('cypress/fixtures/state/store.json').then((state) => { + return state[key] + }) + } +}) + +Cypress.Commands.add('clearState', () => { + cy.readFile('cypress/fixtures/state/store.json').then((currState) => { + currState = {} + cy.writeFile('cypress/fixtures/state/store.json', currState) + }) + cy.log('Test state was reset') +}) diff --git a/e2e/cypress/tests/01-auth.spec.ts b/e2e/cypress/tests/01-Authentication/01-auth.spec.ts similarity index 55% rename from e2e/cypress/tests/01-auth.spec.ts rename to e2e/cypress/tests/01-Authentication/01-auth.spec.ts index ae389bbc5..a304c0efe 100644 --- a/e2e/cypress/tests/01-auth.spec.ts +++ b/e2e/cypress/tests/01-Authentication/01-auth.spec.ts @@ -1,14 +1,20 @@ +import LoginPage from '../../pageObjects/login' + describe('Authentication spec', () => { + const login = new LoginPage() beforeEach(() => { - cy.visit('/') + cy.fixture('developer').as('developer') + cy.visit(login.path) + cy.preserveCookies() }) it('should find login button', () => { - cy.visit('/') - cy.xpath('//button').contains('Login') + cy.xpath(login.loginButton).should('be.visible') }) it('should allow user to authenticate', () => { - cy.login(Cypress.env('PORTAL_USERNAME'), Cypress.env('PORTAL_PASSWORD')) + cy.get('@developer').then(({ user }: any) => { + cy.login(user.credentials.username, user.credentials.password) + }) }) it('should save user session after login', () => { diff --git a/e2e/cypress/tests/02-CreateAPI/01-namespace.ts b/e2e/cypress/tests/02-CreateAPI/01-namespace.ts new file mode 100644 index 000000000..ff320109c --- /dev/null +++ b/e2e/cypress/tests/02-CreateAPI/01-namespace.ts @@ -0,0 +1,35 @@ +import HomePage from '../../pageObjects/home' + +describe('Namespace spec', () => { + const home = new HomePage() + beforeEach(() => { + cy.visit('/') + cy.preserveCookies() + cy.fixture('api-owner').as('api-owner') + }) + + it('should allow user to login as API Owner', () => { + cy.get('@api-owner').then(({ user }: any) => { + cy.login(user.credentials.username, user.credentials.password) + }) + }) + it('should display namespaces dropdown', () => { + cy.xpath(home.namespaceDropdown).should('be.visible') + }) + + it('should allow user to create a new namespace', () => { + cy.get('@api-owner').then(({ namespace }: any) => { + home.createNamespace(namespace) + }) + }) + + it('should allow user to switch to new namespace', () => { + cy.get('@api-owner').then(({ namespace }: any) => { + home.useNamespace(namespace) + }) + }) + + after(() => { + cy.logout() + }) +}) diff --git a/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.ts b/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.ts new file mode 100644 index 000000000..c4f763660 --- /dev/null +++ b/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.ts @@ -0,0 +1,47 @@ +import HomePage from '../../pageObjects/home' +import NamespacesPage from '../../pageObjects/namespaces' +import ServiceAccountsPage from '../../pageObjects/serviceAccounts' +import ToolBar from '../../pageObjects/toolbar' + +describe('Service Account spec', () => { + const home = new HomePage() + const nss = new NamespacesPage() + const sa = new ServiceAccountsPage() + const tb = new ToolBar() + before(() => { + cy.visit('/') + cy.fixture('api-owner').as('api-owner') + cy.get('@api-owner').then(({ user, namespace }: any) => { + cy.login(user.credentials.username, user.credentials.password) + home.useNamespace(namespace) + }) + cy.xpath(tb.namespaces).click() + }) + + beforeEach(() => { + cy.preserveCookies() + cy.fixture('api-owner').as('api-owner') + }) + + it('should service accounts tab', () => { + cy.xpath(nss.serviceAccount).should('include.text', 'Service Accounts') + }) + + it('should allow user to create a new service account', () => { + cy.xpath(nss.serviceAccount).click({ force: true }) + cy.xpath(sa.newServiceAccount).click() + cy.get('@api-owner').then(({ serviceAccount }: any) => { + cy.log(serviceAccount.scopes) + sa.createServiceAccount(serviceAccount.scopes) + }) + }) + + it('should verify if client id and secret are generated', () => { + cy.xpath(sa.clientId).should('be.visible') + cy.xpath(sa.clientSecret).should('be.visible') + sa.saveServiceAcctCreds() + }) + after(() => { + cy.logout() + }) +}) diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 5bf22e9c5..8846a008b 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -6992,6 +6992,15 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "requires": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + } + }, "yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", diff --git a/e2e/package.json b/e2e/package.json index c349f7c7a..adc4315b3 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -7,15 +7,14 @@ "license": "MIT", "scripts": { "cy:open": "cypress open --config-file cypress.json", - "cy:run": "cypress run --config-file cypress.local.json", - "cy:run:dev": "cypress run --config-file cypress.json", + "cy:run": "cypress run --config-file cypress.json", "moch:json": "mochawesome-merge -f results/*.json -o results/bcgov-aps-e2e-report.json", "moch:html": "marge results/bcgov-aps-e2e-report.json --reportDir results/report -i -t \"API Services Portal E2E Test Report\"", - "cy:run:html": "run-s --continue-on-error cy:run moch:json moch:html", - "cy:run:dev:html": "run-s --continue-on-error cy:run:dev moch:json moch:html" + "cy:run:html": "run-s --continue-on-error cy:run moch:json moch:html" }, "devDependencies": { "@types/jsonwebtoken": "^8.5.4", + "@types/mocha": "^8.2.3", "@types/mochawesome": "^6.2.0", "@types/node": "^16.0.0", "@typescript-eslint/eslint-plugin": "^4.28.1", @@ -34,9 +33,11 @@ "cypress-xpath": "^1.6.2", "dotenv": "^10.0.0", "jsonwebtoken": "^8.5.1", + "lodash": "^4.17.21", "mochawesome": "^6.2.2", "mochawesome-merge": "^4.2.0", "npm-run-all": "^4.1.5", - "typescript": "^4.3.5" + "typescript": "^4.3.5", + "yamljs": "^0.3.0" } } diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json index 849470c00..6bad8a76a 100644 --- a/e2e/tsconfig.json +++ b/e2e/tsconfig.json @@ -2,8 +2,10 @@ "compilerOptions": { "target": "es5", "lib": ["es5", "dom", "ES2015"], - "types": ["cypress", "node"], - "allowJs": true + "types": ["cypress", "node", "mocha", "cypress-xpath"], + "allowJs": true, + "noImplicitAny": true, + "strict": true }, "include": ["./cypress/**/*.ts", "**/*.d.ts"], "exclude": [], From 936d65755199b882c519a8d22d907f744cb258b3 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Mon, 19 Jul 2021 19:58:17 -0700 Subject: [PATCH 039/155] Updated docker compose config for keycloak to use postgres db and added organization and org unit data as part of initial data seeding --- docker-compose.yml | 22 ++++++++ feeds/.env.local | 4 +- local/feeder-init/init.sh | 2 + local/feeder-init/organization-unit.yaml | 10 ++++ local/feeder-init/organization.yaml | 11 ++++ local/gwa-api/.env.local | 24 +++++++++ local/gwa-api/entrypoint.sh | 67 ++++++++++++++++++++++++ 7 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 local/feeder-init/organization-unit.yaml create mode 100644 local/feeder-init/organization.yaml create mode 100644 local/gwa-api/.env.local create mode 100755 local/gwa-api/entrypoint.sh diff --git a/docker-compose.yml b/docker-compose.yml index fae8db0cc..22c3958ef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,8 @@ services: environment: #KEYCLOAK_USER: local #KEYCLOAK_PASSWORD: local + DB_VENDOR: POSTGRES + DB_SCHEMA: public DB_ADDR: kong-db:5432 DB_USER: keycloakuser DB_PASSWORD: keycloakuser @@ -195,9 +197,29 @@ services: redis-net: aliases: - redis.localtest.me + gwa-api: + image: gateway-api:latest + container_name: gwa-api + entrypoint: sh -c "chmod +x /tmp/gwa/entrypoint.sh && sh /tmp/gwa/entrypoint.sh" + ports: + - 2000:2000 + env_file: + - ./local/gwa-api/.env.local + restart: on-failure:5 + volumes: + - ./local/gwa-api:/tmp/gwa + networks: + gwa-net: + aliases: + - gwa-api.localtest.me + oauth2-proxy: {} + portal: {} + kong-net: {} + keycloak: {} networks: keycloak: {} oauth2-proxy: {} portal: {} kong-net: {} redis-net: {} + gwa-net: {} diff --git a/feeds/.env.local b/feeds/.env.local index 8c898f3e3..c9eb7c447 100644 --- a/feeds/.env.local +++ b/feeds/.env.local @@ -1,3 +1,5 @@ WORKING_PATH=/tmp DESTINATION_URL=http://apsportal.localtest.me:3000 -KONG_ADMIN_URL=http://kong.localtest.me:8001 \ No newline at end of file +KONG_ADMIN_URL=http://kong.localtest.me:8001 +CKAN_URL=https://catalog.data.gov.bc.ca +LOG_FEEDS=false \ No newline at end of file diff --git a/local/feeder-init/init.sh b/local/feeder-init/init.sh index 94b616dd0..943dba45b 100755 --- a/local/feeder-init/init.sh +++ b/local/feeder-init/init.sh @@ -13,6 +13,8 @@ while true; do curl http://feeder.localtest.me:6000/push -F yaml=@developer-user.yaml curl http://feeder.localtest.me:6000/push -F yaml=@platform-authz-profile.yaml curl http://feeder.localtest.me:6000/push -F yaml=@platform-gwa-api.yaml + curl http://feeder.localtest.me:6000/push -F yaml=@organization.yaml + curl http://feeder.localtest.me:6000/push -F yaml=@organization-unit.yaml break else echo "Waiting for Keycloak....." diff --git a/local/feeder-init/organization-unit.yaml b/local/feeder-init/organization-unit.yaml new file mode 100644 index 000000000..2434f0b99 --- /dev/null +++ b/local/feeder-init/organization-unit.yaml @@ -0,0 +1,10 @@ +entity: OrganizationUnit +record: + id: 319b3297-846d-4b97-8095-ceb3ec505fb8 + name: planning-and-innovation-division + sector: 'Health and Safety' + title: 'Planning and Innovation Division' + tags: [] + description: '' + extSource: '' + extRecordHash: '' diff --git a/local/feeder-init/organization.yaml b/local/feeder-init/organization.yaml new file mode 100644 index 000000000..e7d5af7d7 --- /dev/null +++ b/local/feeder-init/organization.yaml @@ -0,0 +1,11 @@ +entity: Organization +record: + id: 7a66db63-26f4-4052-9cd5-3272b63910f8 + type: organization + name: ministry-of-health + sector: '' + title: 'Ministry of Health' + tags: [] + description: 'The Ministry of Health1 has overall responsibility for ensuring that quality, appropriate, cost effective and timely health services are available for all British Columbians.' + extSource: '' + extRecordHash: '' diff --git a/local/gwa-api/.env.local b/local/gwa-api/.env.local new file mode 100644 index 000000000..5f135b12b --- /dev/null +++ b/local/gwa-api/.env.local @@ -0,0 +1,24 @@ +PORT=2000 +LOG_LEVEL=DEBUG +OIDC_BASE_URL=http://keycloak.localtest.me:9080/auth/realms/master +TOKEN_MATCH_AUD=gwa +WORKING_FOLDER=/tmp +CONFIG_PATH=/tmp/production.json +ENVIRONMENT=production +KONG_ADMIN_URL=http://kong.localtest.me:8001 +KC_SERVER_URL=http://keycloak.localtest.me:9080/auth/ +KC_REALM=master +KC_USERNAME=local +KC_PASSWORD=local +KC_USER_REALM=master +KC_CLIENT_ID=admin-cli +KC_RES_SVR_CLIENT_ID=gwa-api +KC_RES_SVR_CLIENT_SECRET=18900468-3db1-43f7-a8af-e75f079eb742 +NSP_ENABLED=false +PROTECTED_KUBE_NAMESPACES= +PORTAL_ACTIVITY_URL=http://apsportal.localtest.me:3000 +PORTAL_ACTIVITY_TOKEN= +HOST_TRANSFORM_ENABLED=false +HOST_TRANSFORM_BASE_URL= +PLUGINS_RATELIMITING_REDIS_PASSWORD=s3cr3t +LOCAL_ENVIRONMENT=True \ No newline at end of file diff --git a/local/gwa-api/entrypoint.sh b/local/gwa-api/entrypoint.sh new file mode 100755 index 000000000..fc44bc97b --- /dev/null +++ b/local/gwa-api/entrypoint.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +mkdir -p ./config + +cat > "${CONFIG_PATH:-./config/default.json}" < /tmp/deck.yaml < Date: Tue, 20 Jul 2021 08:54:08 -0700 Subject: [PATCH 040/155] added trivy image scanner to scan the image --- .github/workflows/ci-container-img-scan.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci-container-img-scan.yaml b/.github/workflows/ci-container-img-scan.yaml index 5cad5fc72..051e2fcdd 100644 --- a/.github/workflows/ci-container-img-scan.yaml +++ b/.github/workflows/ci-container-img-scan.yaml @@ -22,3 +22,12 @@ jobs: uses: github/codeql-action/upload-sarif@v1 with: sarif_file: results.sarif + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: 'bcgov/api-services-portal:scan' + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' From 93765cd5d0f514d47b5a0adb1734a1c96c5f189d Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 20 Jul 2021 09:12:54 -0700 Subject: [PATCH 041/155] updated the exit code and included medium level vulns --- .github/workflows/ci-container-img-scan.yaml | 4 ++-- e2e/results/report/bcgov-aps-e2e-report.html | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 e2e/results/report/bcgov-aps-e2e-report.html diff --git a/.github/workflows/ci-container-img-scan.yaml b/.github/workflows/ci-container-img-scan.yaml index 051e2fcdd..c94c04177 100644 --- a/.github/workflows/ci-container-img-scan.yaml +++ b/.github/workflows/ci-container-img-scan.yaml @@ -27,7 +27,7 @@ jobs: with: image-ref: 'bcgov/api-services-portal:scan' format: 'table' - exit-code: '1' + exit-code: '0' ignore-unfixed: true vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' + severity: 'CRITICAL,HIGH,MEDIUM' diff --git a/e2e/results/report/bcgov-aps-e2e-report.html b/e2e/results/report/bcgov-aps-e2e-report.html new file mode 100644 index 000000000..db384c337 --- /dev/null +++ b/e2e/results/report/bcgov-aps-e2e-report.html @@ -0,0 +1,17 @@ + +Mochawesome Report
\ No newline at end of file From 6e04a864c51d4a326608758d28997534bf86323c Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 20 Jul 2021 17:42:34 -0700 Subject: [PATCH 042/155] Updated tests with state management --- .../{api-owner.json => apiowner.json} | 0 e2e/cypress/fixtures/state/store.json | 2 +- e2e/cypress/pageObjects/home.ts | 10 +---- e2e/cypress/pageObjects/namespaces.ts | 9 ----- e2e/cypress/pageObjects/serviceAccounts.ts | 13 +++++-- e2e/cypress/support/auth-commands.ts | 7 ++++ e2e/cypress/support/global.d.ts | 2 +- e2e/cypress/support/util-commands.ts | 6 ++- .../tests/01-Authentication/01-auth.spec.ts | 3 ++ .../tests/02-CreateAPI/01-namespace.spec.ts | 33 ++++++++++++++++ .../tests/02-CreateAPI/01-namespace.ts | 35 ----------------- ...ceaccount.ts => 02-serviceaccount.spec.ts} | 38 +++++++++---------- 12 files changed, 79 insertions(+), 79 deletions(-) rename e2e/cypress/fixtures/{api-owner.json => apiowner.json} (100%) delete mode 100644 e2e/cypress/pageObjects/namespaces.ts create mode 100644 e2e/cypress/tests/02-CreateAPI/01-namespace.spec.ts delete mode 100644 e2e/cypress/tests/02-CreateAPI/01-namespace.ts rename e2e/cypress/tests/02-CreateAPI/{02-serviceaccount.ts => 02-serviceaccount.spec.ts} (53%) diff --git a/e2e/cypress/fixtures/api-owner.json b/e2e/cypress/fixtures/apiowner.json similarity index 100% rename from e2e/cypress/fixtures/api-owner.json rename to e2e/cypress/fixtures/apiowner.json diff --git a/e2e/cypress/fixtures/state/store.json b/e2e/cypress/fixtures/state/store.json index e123ef5d0..5d06da884 100644 --- a/e2e/cypress/fixtures/state/store.json +++ b/e2e/cypress/fixtures/state/store.json @@ -1,3 +1,3 @@ { - "sa-platform-e0000000-37f7896427da": "9f0f0dc8-a5fa-4279-96dd-5f6d121a2293" + "credentials": "{'clientId': 'sa-platform-e0000000-9f1c8ffc62c4', 'clientSecret': 'bd5b926a-bcf1-4b8c-b966-a01837bbc4d2'}" } \ No newline at end of file diff --git a/e2e/cypress/pageObjects/home.ts b/e2e/cypress/pageObjects/home.ts index 475680fc8..f71b13b56 100644 --- a/e2e/cypress/pageObjects/home.ts +++ b/e2e/cypress/pageObjects/home.ts @@ -1,8 +1,5 @@ class HomePage { - namespaceDropdown: string = - '/html[1]/body[1]/div[1]/header[1]/hgroup[2]/div[1]/div[1]/button[1]' - - namespaceSelected: string = '/html/body/div[1]/header/hgroup[2]/div[1]/div/button/span' + namespaceDropdown: string = '/html/body/div[1]/header/hgroup[2]/div[1]/div/button' namespaceNameInput: string = '/html/body/div[3]/div[4]/div/section/div/form/div/input' @@ -11,15 +8,12 @@ class HomePage { cy.contains('Create New Namespace').click() cy.xpath(this.namespaceNameInput).should('be.visible').type(name) // using `platform` as a default ns as its being seeding through feeder cy.xpath("//button[normalize-space()='Create']").click() - cy.contains('Namespace ' + name + ' created!').should('be.visible') - cy.contains('Switched to ' + name + ' namespace').should('be.visible') } useNamespace(name: string): void { cy.xpath(this.namespaceDropdown).click() cy.contains(name).click() - cy.contains('Switched to ' + name + ' namespace').should('be.visible') - cy.xpath(this.namespaceSelected).should('include.text', name) + cy.xpath(this.namespaceDropdown).should('include.text', name) } } diff --git a/e2e/cypress/pageObjects/namespaces.ts b/e2e/cypress/pageObjects/namespaces.ts deleted file mode 100644 index e66ed5371..000000000 --- a/e2e/cypress/pageObjects/namespaces.ts +++ /dev/null @@ -1,9 +0,0 @@ -import ToolBar from './toolbar' - -class NamespacesPage { - path: string = '' - serviceAccount: string = - '/html[1]/body[1]/div[1]/main[1]/div[1]/div[3]/div[1]/div[3]/h2[1]/a[1]' -} - -export default NamespacesPage diff --git a/e2e/cypress/pageObjects/serviceAccounts.ts b/e2e/cypress/pageObjects/serviceAccounts.ts index a7feaba51..de41c54fe 100644 --- a/e2e/cypress/pageObjects/serviceAccounts.ts +++ b/e2e/cypress/pageObjects/serviceAccounts.ts @@ -5,10 +5,10 @@ class ServiceAccountsPage { shareButton: string = '/html/body/div[4]/div[4]/div/section/footer/div/button[2]' clientId: string = - '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[1]/div[1]/code[1]' + '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[1]/div[1]/code' clientSecret: string = - '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[2]/div[1]/code[1]' + '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[2]/div[1]/code' createServiceAccount(scopes: string[]): void { scopes.forEach((scope) => { @@ -20,7 +20,14 @@ class ServiceAccountsPage { saveServiceAcctCreds(): void { cy.xpath(this.clientId).then(($clientId) => { cy.xpath(this.clientSecret).then(($clientSecret) => { - cy.saveState($clientId.text(), $clientSecret.text()) + cy.saveState( + 'credentials', + "{'clientId': '" + + $clientId.text() + + "', 'clientSecret': '" + + $clientSecret.text() + + "'}" + ) }) }) } diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index 39d4e3065..8f8bacdd3 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -2,6 +2,7 @@ import * as jwt from 'jsonwebtoken' import LoginPage from '../pageObjects/login' Cypress.Commands.add('login', (username: string, password: string) => { + cy.log('< Log in with user ' + username) const login = new LoginPage() const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) const appURL = new URL(Cypress.config('baseUrl') || '') @@ -27,9 +28,11 @@ Cypress.Commands.add('login', (username: string, password: string) => { expect(loc.hostname).to.eq(appURL.hostname) }) log.end() + cy.log('> Log in') }) Cypress.Commands.add('getSession', () => { + cy.log('< Get Session') cy.request({ method: 'GET', url: Cypress.config('baseUrl') + '/admin/session' }).then( (res) => { cy.wrap(res).as('session') @@ -41,6 +44,7 @@ Cypress.Commands.add('getSession', () => { }) } ) + cy.log('> Get Session') }) Cypress.Commands.add('loginByAuthAPI', (username: string, password: string) => { @@ -77,10 +81,13 @@ Cypress.Commands.add('loginByAuthAPI', (username: string, password: string) => { }) Cypress.Commands.add('logout', () => { + cy.log('< Logging out') cy.getSession().then(() => { cy.get('@session').then((res: any) => { cy.contains(res.body.user.name).click() cy.contains('Sign Out').click() + cy.clearCookies() }) }) + cy.log('> Logging out') }) diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts index de5ede856..45d3599da 100644 --- a/e2e/cypress/support/global.d.ts +++ b/e2e/cypress/support/global.d.ts @@ -17,6 +17,6 @@ declare namespace Cypress { getState(key: string): string - clearState(): void + resetState(): void } } diff --git a/e2e/cypress/support/util-commands.ts b/e2e/cypress/support/util-commands.ts index 6c0e22894..e436cb3a2 100644 --- a/e2e/cypress/support/util-commands.ts +++ b/e2e/cypress/support/util-commands.ts @@ -1,4 +1,5 @@ Cypress.Commands.add('preserveCookies', () => { + cy.log('< Saving Cookies') Cypress.Cookies.preserveOnce( ...[ '_oauth2_proxy', @@ -8,9 +9,11 @@ Cypress.Commands.add('preserveCookies', () => { ] ) Cypress.Cookies.debug(true, { verbose: false }) + cy.log('> Saving Cookies') }) Cypress.Commands.add('saveState', (key: string, value: string) => { + cy.log('< Saving State') cy.log(key, value) if (key.includes('>')) { let keyItems = key.split('>') @@ -25,6 +28,7 @@ Cypress.Commands.add('saveState', (key: string, value: string) => { cy.writeFile('cypress/fixtures/state/store.json', currState) }) } + cy.log('< Saving State') }) Cypress.Commands.add('getState', (key: string) => { @@ -40,7 +44,7 @@ Cypress.Commands.add('getState', (key: string) => { } }) -Cypress.Commands.add('clearState', () => { +Cypress.Commands.add('resetState', () => { cy.readFile('cypress/fixtures/state/store.json').then((currState) => { currState = {} cy.writeFile('cypress/fixtures/state/store.json', currState) diff --git a/e2e/cypress/tests/01-Authentication/01-auth.spec.ts b/e2e/cypress/tests/01-Authentication/01-auth.spec.ts index a304c0efe..03fe6ac21 100644 --- a/e2e/cypress/tests/01-Authentication/01-auth.spec.ts +++ b/e2e/cypress/tests/01-Authentication/01-auth.spec.ts @@ -2,6 +2,9 @@ import LoginPage from '../../pageObjects/login' describe('Authentication spec', () => { const login = new LoginPage() + before(() => { + cy.resetState() + }) beforeEach(() => { cy.fixture('developer').as('developer') cy.visit(login.path) diff --git a/e2e/cypress/tests/02-CreateAPI/01-namespace.spec.ts b/e2e/cypress/tests/02-CreateAPI/01-namespace.spec.ts new file mode 100644 index 000000000..24236b646 --- /dev/null +++ b/e2e/cypress/tests/02-CreateAPI/01-namespace.spec.ts @@ -0,0 +1,33 @@ +import HomePage from '../../pageObjects/home' +import LoginPage from '../../pageObjects/login' + +describe('Namespace spec', () => { + const login = new LoginPage() + const home = new HomePage() + + beforeEach(() => { + cy.fixture('apiowner').as('apiowner') + cy.visit(login.path) + cy.preserveCookies() + }) + it('find login button', () => { + cy.xpath(login.loginButton).should('be.visible') + }) + + it('user authentication', () => { + cy.get('@apiowner').then(({ user }: any) => { + cy.login(user.credentials.username, user.credentials.password) + }) + }) + + it('should allow user to create and switch to new namespace', () => { + cy.get('@apiowner').then(({ namespace }: any) => { + home.createNamespace(namespace) + home.useNamespace(namespace) + }) + }) + + after(() => { + cy.logout() + }) +}) diff --git a/e2e/cypress/tests/02-CreateAPI/01-namespace.ts b/e2e/cypress/tests/02-CreateAPI/01-namespace.ts deleted file mode 100644 index ff320109c..000000000 --- a/e2e/cypress/tests/02-CreateAPI/01-namespace.ts +++ /dev/null @@ -1,35 +0,0 @@ -import HomePage from '../../pageObjects/home' - -describe('Namespace spec', () => { - const home = new HomePage() - beforeEach(() => { - cy.visit('/') - cy.preserveCookies() - cy.fixture('api-owner').as('api-owner') - }) - - it('should allow user to login as API Owner', () => { - cy.get('@api-owner').then(({ user }: any) => { - cy.login(user.credentials.username, user.credentials.password) - }) - }) - it('should display namespaces dropdown', () => { - cy.xpath(home.namespaceDropdown).should('be.visible') - }) - - it('should allow user to create a new namespace', () => { - cy.get('@api-owner').then(({ namespace }: any) => { - home.createNamespace(namespace) - }) - }) - - it('should allow user to switch to new namespace', () => { - cy.get('@api-owner').then(({ namespace }: any) => { - home.useNamespace(namespace) - }) - }) - - after(() => { - cy.logout() - }) -}) diff --git a/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.ts b/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.spec.ts similarity index 53% rename from e2e/cypress/tests/02-CreateAPI/02-serviceaccount.ts rename to e2e/cypress/tests/02-CreateAPI/02-serviceaccount.spec.ts index c4f763660..ab76fd334 100644 --- a/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.ts +++ b/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.spec.ts @@ -1,44 +1,40 @@ import HomePage from '../../pageObjects/home' -import NamespacesPage from '../../pageObjects/namespaces' +import LoginPage from '../../pageObjects/login' import ServiceAccountsPage from '../../pageObjects/serviceAccounts' import ToolBar from '../../pageObjects/toolbar' describe('Service Account spec', () => { const home = new HomePage() - const nss = new NamespacesPage() const sa = new ServiceAccountsPage() const tb = new ToolBar() - before(() => { - cy.visit('/') - cy.fixture('api-owner').as('api-owner') - cy.get('@api-owner').then(({ user, namespace }: any) => { - cy.login(user.credentials.username, user.credentials.password) - home.useNamespace(namespace) - }) - cy.xpath(tb.namespaces).click() - }) + const login = new LoginPage() beforeEach(() => { + cy.fixture('apiowner').as('apiowner') + cy.visit(login.path) cy.preserveCookies() - cy.fixture('api-owner').as('api-owner') + }) + it('find login button', () => { + cy.xpath(login.loginButton).should('be.visible') }) - it('should service accounts tab', () => { - cy.xpath(nss.serviceAccount).should('include.text', 'Service Accounts') + it('user authentication', () => { + cy.get('@apiowner').then(({ user }: any) => { + cy.login(user.credentials.username, user.credentials.password) + }) }) it('should allow user to create a new service account', () => { - cy.xpath(nss.serviceAccount).click({ force: true }) + cy.get('@apiowner').then(({ namespace }: any) => { + home.useNamespace(namespace) + }) + cy.xpath(tb.namespaces).click() + cy.contains('Service Accounts').click({ force: true }) cy.xpath(sa.newServiceAccount).click() - cy.get('@api-owner').then(({ serviceAccount }: any) => { + cy.get('@apiowner').then(({ serviceAccount }: any) => { cy.log(serviceAccount.scopes) sa.createServiceAccount(serviceAccount.scopes) }) - }) - - it('should verify if client id and secret are generated', () => { - cy.xpath(sa.clientId).should('be.visible') - cy.xpath(sa.clientSecret).should('be.visible') sa.saveServiceAcctCreds() }) after(() => { From e16caa8db9e330f40606fa5ca306254559306b5c Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 21 Jul 2021 10:23:25 -0700 Subject: [PATCH 043/155] Merged tests to resolve issues with cookies --- e2e/cypress/fixtures/developer.json | 8 ---- e2e/cypress/fixtures/state/store.json | 4 +- e2e/cypress/pageObjects/home.ts | 4 +- e2e/cypress/pageObjects/serviceAccounts.ts | 5 +-- e2e/cypress/support/auth-commands.ts | 18 ++++---- e2e/cypress/support/global.d.ts | 4 +- e2e/cypress/support/util-commands.ts | 41 ++++++++++++++++++- .../tests/01-Authentication/01-auth.spec.ts | 34 --------------- ...eaccount.spec.ts => 01-create-api.spec.ts} | 29 ++++++------- .../tests/02-CreateAPI/01-namespace.spec.ts | 33 --------------- 10 files changed, 70 insertions(+), 110 deletions(-) delete mode 100644 e2e/cypress/fixtures/developer.json delete mode 100644 e2e/cypress/tests/01-Authentication/01-auth.spec.ts rename e2e/cypress/tests/{02-CreateAPI/02-serviceaccount.spec.ts => 01-create-api.spec.ts} (62%) delete mode 100644 e2e/cypress/tests/02-CreateAPI/01-namespace.spec.ts diff --git a/e2e/cypress/fixtures/developer.json b/e2e/cypress/fixtures/developer.json deleted file mode 100644 index e734d0caf..000000000 --- a/e2e/cypress/fixtures/developer.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "user": { - "credentials": { - "username": "local", - "password": "local" - } - } -} diff --git a/e2e/cypress/fixtures/state/store.json b/e2e/cypress/fixtures/state/store.json index 5d06da884..0967ef424 100644 --- a/e2e/cypress/fixtures/state/store.json +++ b/e2e/cypress/fixtures/state/store.json @@ -1,3 +1 @@ -{ - "credentials": "{'clientId': 'sa-platform-e0000000-9f1c8ffc62c4', 'clientSecret': 'bd5b926a-bcf1-4b8c-b966-a01837bbc4d2'}" -} \ No newline at end of file +{} diff --git a/e2e/cypress/pageObjects/home.ts b/e2e/cypress/pageObjects/home.ts index f71b13b56..2cfda66be 100644 --- a/e2e/cypress/pageObjects/home.ts +++ b/e2e/cypress/pageObjects/home.ts @@ -1,12 +1,14 @@ class HomePage { namespaceDropdown: string = '/html/body/div[1]/header/hgroup[2]/div[1]/div/button' + profileIcon: string = + '/html/body/div[1]/header/hgroup[2]/div[1]/div/span/button/span/svg[1]' namespaceNameInput: string = '/html/body/div[3]/div[4]/div/section/div/form/div/input' createNamespace(name: string): void { cy.xpath(this.namespaceDropdown).click() cy.contains('Create New Namespace').click() - cy.xpath(this.namespaceNameInput).should('be.visible').type(name) // using `platform` as a default ns as its being seeding through feeder + cy.xpath(this.namespaceNameInput).type(name) // using `platform` as a default ns as its being seeding through feeder cy.xpath("//button[normalize-space()='Create']").click() } diff --git a/e2e/cypress/pageObjects/serviceAccounts.ts b/e2e/cypress/pageObjects/serviceAccounts.ts index de41c54fe..176547b50 100644 --- a/e2e/cypress/pageObjects/serviceAccounts.ts +++ b/e2e/cypress/pageObjects/serviceAccounts.ts @@ -1,8 +1,6 @@ class ServiceAccountsPage { path: string = '/manager/namespaces' - newServiceAccount: string = - '/html/body/div[1]/main/div/div[2]/table/tbody/tr/td/div/div/div/button' - shareButton: string = '/html/body/div[4]/div[4]/div/section/footer/div/button[2]' + shareButton: string = "//button[normalize-space()='Share']" clientId: string = '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[1]/div[1]/code' @@ -11,6 +9,7 @@ class ServiceAccountsPage { '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[2]/div[1]/code' createServiceAccount(scopes: string[]): void { + cy.contains('New Service Account').click() scopes.forEach((scope) => { cy.contains(scope).click() }) diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index 8f8bacdd3..f09fbbf2c 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -1,16 +1,12 @@ import * as jwt from 'jsonwebtoken' +import HomePage from '../pageObjects/home' import LoginPage from '../pageObjects/login' Cypress.Commands.add('login', (username: string, password: string) => { cy.log('< Log in with user ' + username) const login = new LoginPage() - const oidcProviderURL = new URL(Cypress.env('OIDC_ISSUER')) - const appURL = new URL(Cypress.config('baseUrl') || '') - cy.xpath(login.loginButton).click() - cy.location().should((loc) => { - expect(loc.protocol).to.eq(oidcProviderURL.protocol) - expect(loc.hostname).to.eq(oidcProviderURL.hostname) - }) + const appURL = new URL(Cypress.config('baseUrl')!) + cy.xpath(login.loginButton).should('be.visible').click() const log = Cypress.log({ name: 'Login to Dev', @@ -22,12 +18,11 @@ Cypress.Commands.add('login', (username: string, password: string) => { cy.xpath(login.usernameInput).type(username) cy.xpath(login.passwordInput).type(password) cy.xpath(login.loginSubmitButton).click() + cy.wait(1000) - cy.location().should((loc) => { - expect(loc.protocol).to.eq(appURL.protocol) - expect(loc.hostname).to.eq(appURL.hostname) - }) + log.snapshot('Post Login') log.end() + cy.xpath(login.loginButton).should('not.exist') cy.log('> Log in') }) @@ -89,5 +84,6 @@ Cypress.Commands.add('logout', () => { cy.clearCookies() }) }) + cy.wait(2000) cy.log('> Logging out') }) diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts index 45d3599da..b2e80bec3 100644 --- a/e2e/cypress/support/global.d.ts +++ b/e2e/cypress/support/global.d.ts @@ -3,7 +3,7 @@ declare namespace Cypress { interface Chainable { - login(username: string, password: string): void + login(username: string, password: string): Chainable getSession(): Chainable> @@ -13,6 +13,8 @@ declare namespace Cypress { preserveCookies(): void + preserveCookiesDefaults(): void + saveState(key: string, value: string): void getState(key: string): string diff --git a/e2e/cypress/support/util-commands.ts b/e2e/cypress/support/util-commands.ts index e436cb3a2..d251d6318 100644 --- a/e2e/cypress/support/util-commands.ts +++ b/e2e/cypress/support/util-commands.ts @@ -2,13 +2,50 @@ Cypress.Commands.add('preserveCookies', () => { cy.log('< Saving Cookies') Cypress.Cookies.preserveOnce( ...[ + 'AUTH_SESSION_ID_LEGACY', + 'KC_RESTART', + 'KEYCLOAK_IDENTITY_LEGACY', + 'KEYCLOAK_LOCALE', + 'KEYCLOAK_LOCALE', + 'KEYCLOAK_SESSION_LEGACY', '_oauth2_proxy', '_oauth2_proxy_csrf', - 'ab547b670fc5c67e38dbef98822b7c8d', 'keystone.sid', ] ) - Cypress.Cookies.debug(true, { verbose: false }) + // Cypress.Cookies.defaults({ + // preserve: [ + // 'AUTH_SESSION_ID_LEGACY', + // 'KC_RESTART', + // 'KEYCLOAK_IDENTITY_LEGACY', + // 'KEYCLOAK_LOCALE', + // 'KEYCLOAK_LOCALE', + // 'KEYCLOAK_SESSION_LEGACY', + // '_oauth2_proxy', + // '_oauth2_proxy_csrf', + // 'keystone.sid', + // ], + // }) + Cypress.Cookies.debug(true) + cy.log('> Saving Cookies') +}) + +Cypress.Commands.add('preserveCookiesDefaults', () => { + cy.log('< Saving Cookies as Defaults') + Cypress.Cookies.defaults({ + preserve: [ + 'AUTH_SESSION_ID_LEGACY', + 'KC_RESTART', + 'KEYCLOAK_IDENTITY_LEGACY', + 'KEYCLOAK_LOCALE', + 'KEYCLOAK_LOCALE', + 'KEYCLOAK_SESSION_LEGACY', + '_oauth2_proxy', + '_oauth2_proxy_csrf', + 'keystone.sid', + ], + }) + Cypress.Cookies.debug(true) cy.log('> Saving Cookies') }) diff --git a/e2e/cypress/tests/01-Authentication/01-auth.spec.ts b/e2e/cypress/tests/01-Authentication/01-auth.spec.ts deleted file mode 100644 index 03fe6ac21..000000000 --- a/e2e/cypress/tests/01-Authentication/01-auth.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import LoginPage from '../../pageObjects/login' - -describe('Authentication spec', () => { - const login = new LoginPage() - before(() => { - cy.resetState() - }) - beforeEach(() => { - cy.fixture('developer').as('developer') - cy.visit(login.path) - cy.preserveCookies() - }) - it('should find login button', () => { - cy.xpath(login.loginButton).should('be.visible') - }) - - it('should allow user to authenticate', () => { - cy.get('@developer').then(({ user }: any) => { - cy.login(user.credentials.username, user.credentials.password) - }) - }) - - it('should save user session after login', () => { - cy.getSession().then(() => { - cy.get('@session').then((res: any) => { - expect(res.body).to.include({ anonymous: false }) - }) - }) - }) - - it('should allow user to logout', () => { - cy.logout() - }) -}) diff --git a/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.spec.ts b/e2e/cypress/tests/01-create-api.spec.ts similarity index 62% rename from e2e/cypress/tests/02-CreateAPI/02-serviceaccount.spec.ts rename to e2e/cypress/tests/01-create-api.spec.ts index ab76fd334..7acfb22b8 100644 --- a/e2e/cypress/tests/02-CreateAPI/02-serviceaccount.spec.ts +++ b/e2e/cypress/tests/01-create-api.spec.ts @@ -1,42 +1,43 @@ -import HomePage from '../../pageObjects/home' -import LoginPage from '../../pageObjects/login' -import ServiceAccountsPage from '../../pageObjects/serviceAccounts' -import ToolBar from '../../pageObjects/toolbar' +import HomePage from '../pageObjects/home' +import LoginPage from '../pageObjects/login' +import ServiceAccountsPage from '../pageObjects/serviceAccounts' +import ToolBar from '../pageObjects/toolbar' -describe('Service Account spec', () => { +describe('Create API Spec', () => { + const login = new LoginPage() const home = new HomePage() - const sa = new ServiceAccountsPage() const tb = new ToolBar() - const login = new LoginPage() + const sa = new ServiceAccountsPage() beforeEach(() => { cy.fixture('apiowner').as('apiowner') cy.visit(login.path) - cy.preserveCookies() - }) - it('find login button', () => { - cy.xpath(login.loginButton).should('be.visible') }) - it('user authentication', () => { + it('authenticates api owner', () => { cy.get('@apiowner').then(({ user }: any) => { cy.login(user.credentials.username, user.credentials.password) }) }) - it('should allow user to create a new service account', () => { + it('creates and activates new namespace', () => { cy.get('@apiowner').then(({ namespace }: any) => { + home.createNamespace(namespace) home.useNamespace(namespace) }) + }) + it('creates a new service account', () => { cy.xpath(tb.namespaces).click() cy.contains('Service Accounts').click({ force: true }) - cy.xpath(sa.newServiceAccount).click() cy.get('@apiowner').then(({ serviceAccount }: any) => { cy.log(serviceAccount.scopes) sa.createServiceAccount(serviceAccount.scopes) }) sa.saveServiceAcctCreds() }) + afterEach(() => { + cy.preserveCookies() + }) after(() => { cy.logout() }) diff --git a/e2e/cypress/tests/02-CreateAPI/01-namespace.spec.ts b/e2e/cypress/tests/02-CreateAPI/01-namespace.spec.ts deleted file mode 100644 index 24236b646..000000000 --- a/e2e/cypress/tests/02-CreateAPI/01-namespace.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import HomePage from '../../pageObjects/home' -import LoginPage from '../../pageObjects/login' - -describe('Namespace spec', () => { - const login = new LoginPage() - const home = new HomePage() - - beforeEach(() => { - cy.fixture('apiowner').as('apiowner') - cy.visit(login.path) - cy.preserveCookies() - }) - it('find login button', () => { - cy.xpath(login.loginButton).should('be.visible') - }) - - it('user authentication', () => { - cy.get('@apiowner').then(({ user }: any) => { - cy.login(user.credentials.username, user.credentials.password) - }) - }) - - it('should allow user to create and switch to new namespace', () => { - cy.get('@apiowner').then(({ namespace }: any) => { - home.createNamespace(namespace) - home.useNamespace(namespace) - }) - }) - - after(() => { - cy.logout() - }) -}) From f8ba64edb82ed3b90c0fd377821844ca8539ae6a Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 22 Jul 2021 08:34:17 -0700 Subject: [PATCH 044/155] Chained namespace name assertion with the click command --- e2e/cypress/pageObjects/home.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/e2e/cypress/pageObjects/home.ts b/e2e/cypress/pageObjects/home.ts index 2cfda66be..d1fdc6daf 100644 --- a/e2e/cypress/pageObjects/home.ts +++ b/e2e/cypress/pageObjects/home.ts @@ -14,8 +14,11 @@ class HomePage { useNamespace(name: string): void { cy.xpath(this.namespaceDropdown).click() - cy.contains(name).click() - cy.xpath(this.namespaceDropdown).should('include.text', name) + cy.contains(name) + .click() + .then(() => { + cy.xpath(this.namespaceDropdown).should('include.text', name) + }) } } From ee88804b8bc52e0c2ab64dc087f6a11b0215d7cb Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Thu, 22 Jul 2021 21:44:13 -0700 Subject: [PATCH 045/155] Add new mock data --- src/nextapp/pages/manager/services/index.tsx | 5 +- src/test/mock-server/data/metrics-data.js | 266 ++++++++++--------- src/test/mock-server/server.js | 27 +- 3 files changed, 149 insertions(+), 149 deletions(-) diff --git a/src/nextapp/pages/manager/services/index.tsx b/src/nextapp/pages/manager/services/index.tsx index f4bff0c7f..02dd0605b 100644 --- a/src/nextapp/pages/manager/services/index.tsx +++ b/src/nextapp/pages/manager/services/index.tsx @@ -18,7 +18,7 @@ import SearchInput from '@/components/search-input'; import { FaCaretSquareUp, FaFilter } from 'react-icons/fa'; import ServicesFilters from '@/components/services-list/services-filters'; -import breadcrumbs from '@/components/ns-breadcrumb' +import breadcrumbs from '@/components/ns-breadcrumb'; // export const getServerSideProps = withAuth(async (context) => { // const { user } = context; @@ -54,7 +54,7 @@ const ServicesPage: React.FC = () => {

- + { new MockList(2, (_, { id }) => ({ id })), allGatewayConsumers: () => new MockList(4, (_, { id }) => ({ id })), allPlugins: () => new MockList(4, (_, { id }) => ({ id })), - allMetrics: (_query, _, args) => { - const result = args.variableValues.days.map((d, index) => { - const metrics = metricsData[index]; - const date = parse(d, 'yyyy-MM-dd', new Date()); - const values = []; - - times(24, (n) => { - const hour = addHours(date, n); - - if (metrics[n]) { - values.push([hour.getTime(), metrics[n]]); - } - }); - - return { - name: `kong_http_requests_hourly.${d}.{}`, - query: 'kong_http_requests_hourly', - day: d, - metric: '{}', - values: JSON.stringify(values), - }; - }); - - return result; - }, + allMetrics: (_query, _, args) => metricsData, getPermissionTickets: () => new MockList(6, (_, { id }) => ({ id })), getPermissionTicketsForResource: () => new MockList(6, (_, { id }) => ({ id })), @@ -124,7 +100,6 @@ const server = mockServer(schemaWithMocks, { legalName: 'Smith Associates', address: { addressLine1: '2233 Broadway South', - addressLine1: '', city: 'Mincetown', postal: 'V1B4A3', province: 'BC', From 19788b1efd7abf3c3813c415a2566464383223f8 Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Mon, 26 Jul 2021 00:24:23 -0700 Subject: [PATCH 046/155] Touch up metric counts --- .../components/services-list/metric-graph.tsx | 26 ++++++++++++++----- src/nextapp/pages/manager/services/[id].tsx | 12 ++++----- src/test/mock-server/server.js | 2 ++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/nextapp/components/services-list/metric-graph.tsx b/src/nextapp/components/services-list/metric-graph.tsx index 36bc012b3..b4ca57b09 100644 --- a/src/nextapp/components/services-list/metric-graph.tsx +++ b/src/nextapp/components/services-list/metric-graph.tsx @@ -23,6 +23,7 @@ import { scaleLinear } from 'd3-scale'; import formatISO from 'date-fns/formatISO'; import format from 'date-fns/format'; import differenceInDays from 'date-fns/differenceInDays'; +import max from 'lodash/max'; import mean from 'lodash/mean'; import numeral from 'numeral'; import round from 'lodash/round'; @@ -121,7 +122,20 @@ const MetricGraph: React.FC = ({ const totalHours = 24 * 5; const downtime = sum(dailies.map((d) => d.downtime)); const totalRequests = sum(dailies.map((d) => d.total)); - const requestsAverage = mean(dailies.map((d) => d.total)); + const peak: number[] | [number, string] = dailies.reduce( + (memo, d) => { + const prevPeak = Number(memo[1]); + const currentPeak = Number(d.peak[1]); + + if (currentPeak > prevPeak) { + return d.peak; + } + return memo; + }, + [0, '0'] + ); + const peakRequests = round(Number(peak[1]), 2); + const peakDay = format(new Date(peak[0] * 1000), 'EEE'); const usage = downtime / totalHours; const usagePercent = usage * 100; const color = interpolateRdYlGn(usage); @@ -155,8 +169,8 @@ const MetricGraph: React.FC = ({ - Avg - {numeral(requestsAverage).format('0.0a')} + Peak + {peakRequests} Total Req @@ -165,10 +179,8 @@ const MetricGraph: React.FC = ({ - Days since - - {differenceInDays(new Date(), new Date(service?.updatedAt))} - + Peak Day + {peakDay} Plugins diff --git a/src/nextapp/pages/manager/services/[id].tsx b/src/nextapp/pages/manager/services/[id].tsx index 740b3a292..5a3ae494f 100644 --- a/src/nextapp/pages/manager/services/[id].tsx +++ b/src/nextapp/pages/manager/services/[id].tsx @@ -95,9 +95,9 @@ const ServicePage: React.FC< breadcrumb={breadcrumb} title={ - {data?.GatewayService.name} + {data?.GatewayService?.name} @@ -120,7 +120,7 @@ const ServicePage: React.FC< @@ -150,7 +150,7 @@ const ServicePage: React.FC< alt days={range} height={100} - id={data?.GatewayService.name} + id={data?.GatewayService?.name} service={data?.GatewayService} /> @@ -171,7 +171,7 @@ const ServicePage: React.FC< - + @@ -200,7 +200,7 @@ const ServicePage: React.FC< Host - {data?.GatewayService.host} + {data?.GatewayService?.host} Tags diff --git a/src/test/mock-server/server.js b/src/test/mock-server/server.js index fbf69d3bd..fc45b0a84 100644 --- a/src/test/mock-server/server.js +++ b/src/test/mock-server/server.js @@ -315,6 +315,8 @@ const server = mockServer(schemaWithMocks, { casual.random_element(['GET', 'POST', 'PUT', 'DELETE']), ]), tags: '["ns.sample"]', + hosts: JSON.stringify(['route']), + paths: JSON.stringify(['/path']), }), CredentialIssuer: () => { const flow = casual.random_element([ From ddb1ccd8ae4b2bdb5a270b5001a956c3efe29e41 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Mon, 26 Jul 2021 19:04:32 -0700 Subject: [PATCH 047/155] seeding organization data for testing --- local/feeder-init/init.sh | 2 ++ local/feeder-init/organization-unit.yaml | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 local/feeder-init/organization-unit.yaml diff --git a/local/feeder-init/init.sh b/local/feeder-init/init.sh index 94b616dd0..0a175bfce 100755 --- a/local/feeder-init/init.sh +++ b/local/feeder-init/init.sh @@ -13,6 +13,8 @@ while true; do curl http://feeder.localtest.me:6000/push -F yaml=@developer-user.yaml curl http://feeder.localtest.me:6000/push -F yaml=@platform-authz-profile.yaml curl http://feeder.localtest.me:6000/push -F yaml=@platform-gwa-api.yaml + curl http://feeder.localtest.me:6000/push -F yaml=@organization-unit.yaml + break else echo "Waiting for Keycloak....." diff --git a/local/feeder-init/organization-unit.yaml b/local/feeder-init/organization-unit.yaml new file mode 100644 index 000000000..d7e176570 --- /dev/null +++ b/local/feeder-init/organization-unit.yaml @@ -0,0 +1,20 @@ +entity: Organization +record: + id: 7a66db63-26f4-4052-9cd5-3272b63910f8 + type: organization + name: ministry-of-health + sector: '' + title: 'Ministry of Health' + tags: [] + description: 'The Ministry of Health has overall responsibility for ensuring that quality, appropriate, cost effective and timely health services are available for all British Columbians.' + extSource: '' + extRecordHash: '' + orgUnits: + - id: 319b3297-846d-4b97-8095-ceb3ec505fb8 + name: planning-and-innovation-division + sector: 'Health and Safety' + title: 'Planning and Innovation Division' + tags: [] + description: '' + extSource: '' + extRecordHash: '' From c08c3fc51cf58e6a12a5bcbcee6c564b1c76d671 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 27 Jul 2021 08:20:18 -0700 Subject: [PATCH 048/155] Seeding organization data for tests --- local/feeder-init/init.sh | 5 ----- local/feeder-init/organization-unit.yaml | 13 ------------- local/feeder-init/organization.yaml | 11 ----------- 3 files changed, 29 deletions(-) delete mode 100644 local/feeder-init/organization.yaml diff --git a/local/feeder-init/init.sh b/local/feeder-init/init.sh index fde15f4c3..0a175bfce 100755 --- a/local/feeder-init/init.sh +++ b/local/feeder-init/init.sh @@ -13,13 +13,8 @@ while true; do curl http://feeder.localtest.me:6000/push -F yaml=@developer-user.yaml curl http://feeder.localtest.me:6000/push -F yaml=@platform-authz-profile.yaml curl http://feeder.localtest.me:6000/push -F yaml=@platform-gwa-api.yaml -<<<<<<< HEAD curl http://feeder.localtest.me:6000/push -F yaml=@organization-unit.yaml -======= - curl http://feeder.localtest.me:6000/push -F yaml=@organization.yaml - curl http://feeder.localtest.me:6000/push -F yaml=@organization-unit.yaml ->>>>>>> feature/rate-limit-redis break else echo "Waiting for Keycloak....." diff --git a/local/feeder-init/organization-unit.yaml b/local/feeder-init/organization-unit.yaml index 7472658bb..d7e176570 100644 --- a/local/feeder-init/organization-unit.yaml +++ b/local/feeder-init/organization-unit.yaml @@ -1,4 +1,3 @@ -<<<<<<< HEAD entity: Organization record: id: 7a66db63-26f4-4052-9cd5-3272b63910f8 @@ -19,15 +18,3 @@ record: description: '' extSource: '' extRecordHash: '' -======= -entity: OrganizationUnit -record: - id: 319b3297-846d-4b97-8095-ceb3ec505fb8 - name: planning-and-innovation-division - sector: 'Health and Safety' - title: 'Planning and Innovation Division' - tags: [] - description: '' - extSource: '' - extRecordHash: '' ->>>>>>> feature/rate-limit-redis diff --git a/local/feeder-init/organization.yaml b/local/feeder-init/organization.yaml deleted file mode 100644 index e7d5af7d7..000000000 --- a/local/feeder-init/organization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -entity: Organization -record: - id: 7a66db63-26f4-4052-9cd5-3272b63910f8 - type: organization - name: ministry-of-health - sector: '' - title: 'Ministry of Health' - tags: [] - description: 'The Ministry of Health1 has overall responsibility for ensuring that quality, appropriate, cost effective and timely health services are available for all British Columbians.' - extSource: '' - extRecordHash: '' From 3e70e5fa8ce776f8feb4ea138220866479865e4c Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Tue, 27 Jul 2021 10:54:04 -0700 Subject: [PATCH 049/155] Tidy up list --- src/nextapp/components/services-list/metric-graph.tsx | 5 +---- src/nextapp/components/services-list/services-list.tsx | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/nextapp/components/services-list/metric-graph.tsx b/src/nextapp/components/services-list/metric-graph.tsx index b4ca57b09..2086194aa 100644 --- a/src/nextapp/components/services-list/metric-graph.tsx +++ b/src/nextapp/components/services-list/metric-graph.tsx @@ -22,9 +22,6 @@ import { interpolateRdYlGn } from 'd3-scale-chromatic'; import { scaleLinear } from 'd3-scale'; import formatISO from 'date-fns/formatISO'; import format from 'date-fns/format'; -import differenceInDays from 'date-fns/differenceInDays'; -import max from 'lodash/max'; -import mean from 'lodash/mean'; import numeral from 'numeral'; import round from 'lodash/round'; import sum from 'lodash/sum'; @@ -135,7 +132,7 @@ const MetricGraph: React.FC = ({ [0, '0'] ); const peakRequests = round(Number(peak[1]), 2); - const peakDay = format(new Date(peak[0] * 1000), 'EEE'); + const peakDay = format(new Date(peak[0] * 1000), 'LLL d'); const usage = downtime / totalHours; const usagePercent = usage * 100; const color = interpolateRdYlGn(usage); diff --git a/src/nextapp/components/services-list/services-list.tsx b/src/nextapp/components/services-list/services-list.tsx index 5d6851bff..746e3d725 100644 --- a/src/nextapp/components/services-list/services-list.tsx +++ b/src/nextapp/components/services-list/services-list.tsx @@ -17,7 +17,7 @@ const ServicesList: React.FC = ({ search }) => { const { data } = useApi( 'gateway-services', { - query: LIST_GATEWAY_SERVICES + query: LIST_GATEWAY_SERVICES, }, { suspense: true, @@ -37,7 +37,6 @@ const ServicesList: React.FC = ({ search }) => { )} From fd0edd5dd64b8eabadafc9309772031db6128acd Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Tue, 27 Jul 2021 22:15:08 -0700 Subject: [PATCH 050/155] Use total requests as the number to compare against 5 day totals for each service --- .../components/services-list/metric-graph.tsx | 16 ++++----- .../components/services-list/service-item.tsx | 15 ++++++-- .../services-list/services-list.tsx | 35 ++++++++++++++++++- .../shared/queries/gateway-service-queries.ts | 11 +++++- src/test/mock-server/data/db.js | 2 +- src/test/mock-server/server.js | 2 +- 6 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/nextapp/components/services-list/metric-graph.tsx b/src/nextapp/components/services-list/metric-graph.tsx index 2086194aa..e9a65d584 100644 --- a/src/nextapp/components/services-list/metric-graph.tsx +++ b/src/nextapp/components/services-list/metric-graph.tsx @@ -40,7 +40,7 @@ interface DailyDatum { downtime: number; requests: number[]; total: number; - peak: number[]; + peak: number | number[]; } interface MetricGraphProps { @@ -49,6 +49,7 @@ interface MetricGraphProps { height?: number; id: string; service: GatewayService; + totalRequests: number; } const MetricGraph: React.FC = ({ @@ -57,6 +58,7 @@ const MetricGraph: React.FC = ({ height = 100, id, service, + totalRequests, }) => { const { data } = useApi(['metric', id], { query: GET_METRICS, @@ -84,7 +86,7 @@ const MetricGraph: React.FC = ({ }, 0); const downtime = 24 - values.length; const defaultPeakDate: number = firstDateValue.getTime(); - const peak: any = value.reduce( + const peak: number | [number, number] = value.reduce( (memo, v) => { if (memo[1] < Number(v[1])) { return v; @@ -116,10 +118,8 @@ const MetricGraph: React.FC = ({ requests, }; }); - const totalHours = 24 * 5; - const downtime = sum(dailies.map((d) => d.downtime)); - const totalRequests = sum(dailies.map((d) => d.total)); - const peak: number[] | [number, string] = dailies.reduce( + const totalDailyRequests = sum(dailies.map((d) => d.total)); + const peak = dailies.reduce( (memo, d) => { const prevPeak = Number(memo[1]); const currentPeak = Number(d.peak[1]); @@ -133,7 +133,7 @@ const MetricGraph: React.FC = ({ ); const peakRequests = round(Number(peak[1]), 2); const peakDay = format(new Date(peak[0] * 1000), 'LLL d'); - const usage = downtime / totalHours; + const usage = totalDailyRequests / totalRequests; const usagePercent = usage * 100; const color = interpolateRdYlGn(usage); const y = scaleLinear().range([0, height]).domain([0, 1]); @@ -172,7 +172,7 @@ const MetricGraph: React.FC = ({ Total Req - {numeral(totalRequests).format('0.0a')} + {numeral(totalDailyRequests).format('0.0a')} diff --git a/src/nextapp/components/services-list/service-item.tsx b/src/nextapp/components/services-list/service-item.tsx index fcc78fb8a..ada8378b9 100644 --- a/src/nextapp/components/services-list/service-item.tsx +++ b/src/nextapp/components/services-list/service-item.tsx @@ -11,9 +11,14 @@ import { GatewayService } from '@/shared/types/query.types'; interface ServiceItemProps { data: GatewayService; range: string[]; + totalRequests: number; } -const ServiceItem: React.FC = ({ data, range }) => { +const ServiceItem: React.FC = ({ + data, + range, + totalRequests, +}) => { const { ref, inView } = useInView(); return ( @@ -56,7 +61,13 @@ const ServiceItem: React.FC = ({ data, range }) => { {!inView && } {inView && ( }> - + )} diff --git a/src/nextapp/components/services-list/services-list.tsx b/src/nextapp/components/services-list/services-list.tsx index 746e3d725..21de79f04 100644 --- a/src/nextapp/components/services-list/services-list.tsx +++ b/src/nextapp/components/services-list/services-list.tsx @@ -7,22 +7,50 @@ import { useApi } from '@/shared/services/api'; import { LIST_GATEWAY_SERVICES } from '@/shared/queries/gateway-service-queries'; import { dateRange } from './utils'; import ServiceItem from './service-item'; +import { useAuth } from '@/shared/services/auth'; interface ServicesListProps { search: string; } const ServicesList: React.FC = ({ search }) => { + const { user } = useAuth(); const range = dateRange(); const { data } = useApi( 'gateway-services', { query: LIST_GATEWAY_SERVICES, + variables: { + days: range, + }, }, { suspense: true, } ); + const totalNamespaceRequests: number = React.useMemo(() => { + const { namespace } = user; + let result = 0; + + if (data?.allMetrics) { + data.allMetrics.forEach((m) => { + const metric = JSON.parse(m.metric); + + if (metric.service === namespace) { + const values = JSON.parse(m.values); + const dayValues = values.reduce( + (memo: number, v: number[] | [number, string]) => { + return memo + Number(v[1]); + }, + 0 + ); + result = result + dayValues; + } + }); + } + + return result; + }, [data, user]); const filterServices = React.useCallback( (d) => { return d.name.search(search) >= 0; @@ -41,7 +69,12 @@ const ServicesList: React.FC = ({ search }) => { )} {data.allGatewayServicesByNamespace.filter(filterServices).map((d) => ( - + ))} ); diff --git a/src/nextapp/shared/queries/gateway-service-queries.ts b/src/nextapp/shared/queries/gateway-service-queries.ts index 5d2f3f235..ca6094ad0 100644 --- a/src/nextapp/shared/queries/gateway-service-queries.ts +++ b/src/nextapp/shared/queries/gateway-service-queries.ts @@ -1,7 +1,7 @@ import { gql } from 'graphql-request'; export const LIST_GATEWAY_SERVICES = gql` - query GetServices { + query GetServices($days: [String!]) { allGatewayServicesByNamespace(first: 200) { id name @@ -30,6 +30,15 @@ export const LIST_GATEWAY_SERVICES = gql` name } } + allMetrics( + sortBy: day_ASC + where: { query: "kong_http_requests_daily_namespace", day_in: $days } + ) { + query + day + metric + values + } } `; diff --git a/src/test/mock-server/data/db.js b/src/test/mock-server/data/db.js index dcd40d714..acbc810dd 100644 --- a/src/test/mock-server/data/db.js +++ b/src/test/mock-server/data/db.js @@ -19,7 +19,7 @@ class MockDatabase { name: 'Viktor Vaughn', username: 'vikvaughn', email: 'villain@doom.net', - roles: [role], + roles: [role, 'portal-user'], isAdmin: false, namespace, groups: null, diff --git a/src/test/mock-server/server.js b/src/test/mock-server/server.js index fc45b0a84..629f965ee 100644 --- a/src/test/mock-server/server.js +++ b/src/test/mock-server/server.js @@ -23,7 +23,7 @@ const schemas = require('./schemas'); const { sample } = require('lodash'); const app = express(); -const db = new MockDatabase('api-owner', 'dss-loc'); +const db = new MockDatabase('api-owner', 'aps-portal'); const port = 4000; const randomNullValue = () => { From 43d82030adbe64e3dcf9d2ae441116ce2471e1ca Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Tue, 27 Jul 2021 22:56:57 -0700 Subject: [PATCH 051/155] Style docs link on redirect page. --- src/nextapp/pages/redirect/[id].tsx | 81 ++++++++++++++++------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/src/nextapp/pages/redirect/[id].tsx b/src/nextapp/pages/redirect/[id].tsx index 0b5a885c8..2eee10a37 100644 --- a/src/nextapp/pages/redirect/[id].tsx +++ b/src/nextapp/pages/redirect/[id].tsx @@ -5,14 +5,13 @@ import { AlertIcon, AlertTitle, AlertDescription, - Link, - VStack, + Button, } from '@chakra-ui/react'; import Head from 'next/head'; -import { useAuth } from '@/shared/services/auth'; +import NextLink from 'next/link'; import { GetServerSideProps, InferGetServerSidePropsType } from 'next'; -import { Box, Center, Heading, Icon } from '@chakra-ui/react'; -import { FaExclamationCircle } from 'react-icons/fa'; +import { Icon } from '@chakra-ui/react'; +import { FaArrowCircleRight } from 'react-icons/fa'; export const getServerSideProps: GetServerSideProps = async (context) => { const { id } = context.params; @@ -20,7 +19,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => { return { props: { id, - url, + url: url ?? '', }, }; }; @@ -52,41 +51,51 @@ const RedirectPage: React.FC< moreDetails: '/docs/platform-api-services-portal-released', }, }; - if (!(id in sources)) { - return <>; - } return ( <> API Services Portal | Redirect - - - - - {sources[id].title} - - - {sources[id].moreDetails && ( - {`View the release notes..`} - )} - - + {sources[id] && ( + + + + + {sources[id].title} + + + {sources[id].moreDetails && ( + + + + )} + + + )} ); }; From 5fe0b39f83ec56fc362e9decaf394e5d65f0fcea Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Wed, 28 Jul 2021 09:24:09 -0700 Subject: [PATCH 052/155] Add link styling to description links --- src/nextapp/pages/redirect/[id].tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/nextapp/pages/redirect/[id].tsx b/src/nextapp/pages/redirect/[id].tsx index 2eee10a37..32f37148d 100644 --- a/src/nextapp/pages/redirect/[id].tsx +++ b/src/nextapp/pages/redirect/[id].tsx @@ -75,6 +75,15 @@ const RedirectPage: React.FC< maxWidth="lg" pb={5} dangerouslySetInnerHTML={{ __html: sources[id].description }} + sx={{ + '& a': { + textDecoration: 'underline', + color: 'bc-link', + '&:hover': { + textDecoration: 'none', + }, + }, + }} > {sources[id].moreDetails && ( From aa63a252f834e1897448573e60ed5297e62939ea Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Wed, 28 Jul 2021 12:05:14 -0700 Subject: [PATCH 053/155] Use total namespace requests for the metric --- .../services-list/services-list.tsx | 30 +--- src/nextapp/components/services-list/utils.ts | 34 ++++ src/nextapp/pages/manager/services/[id].tsx | 15 +- .../shared/queries/gateway-service-queries.ts | 11 +- src/test/mock-server/data/metrics-data.js | 155 +++++++++++++++++- src/test/mock-server/server.js | 7 +- 6 files changed, 216 insertions(+), 36 deletions(-) diff --git a/src/nextapp/components/services-list/services-list.tsx b/src/nextapp/components/services-list/services-list.tsx index 21de79f04..bcb1eda06 100644 --- a/src/nextapp/components/services-list/services-list.tsx +++ b/src/nextapp/components/services-list/services-list.tsx @@ -3,18 +3,16 @@ import { Box } from '@chakra-ui/react'; import EmptyPane from '@/components/empty-pane'; import NewProduct from '@/components/new-product'; import { useApi } from '@/shared/services/api'; - import { LIST_GATEWAY_SERVICES } from '@/shared/queries/gateway-service-queries'; -import { dateRange } from './utils'; + +import { dateRange, useTotalRequests } from './utils'; import ServiceItem from './service-item'; -import { useAuth } from '@/shared/services/auth'; interface ServicesListProps { search: string; } const ServicesList: React.FC = ({ search }) => { - const { user } = useAuth(); const range = dateRange(); const { data } = useApi( 'gateway-services', @@ -28,29 +26,7 @@ const ServicesList: React.FC = ({ search }) => { suspense: true, } ); - const totalNamespaceRequests: number = React.useMemo(() => { - const { namespace } = user; - let result = 0; - - if (data?.allMetrics) { - data.allMetrics.forEach((m) => { - const metric = JSON.parse(m.metric); - - if (metric.service === namespace) { - const values = JSON.parse(m.values); - const dayValues = values.reduce( - (memo: number, v: number[] | [number, string]) => { - return memo + Number(v[1]); - }, - 0 - ); - result = result + dayValues; - } - }); - } - - return result; - }, [data, user]); + const totalNamespaceRequests = useTotalRequests(data); const filterServices = React.useCallback( (d) => { return d.name.search(search) >= 0; diff --git a/src/nextapp/components/services-list/utils.ts b/src/nextapp/components/services-list/utils.ts index 390577f18..69c71aed0 100644 --- a/src/nextapp/components/services-list/utils.ts +++ b/src/nextapp/components/services-list/utils.ts @@ -1,6 +1,9 @@ +import * as React from 'react'; +import { useAuth } from '@/shared/services/auth'; import format from 'date-fns/format'; import subDays from 'date-fns/subDays'; import times from 'lodash/times'; +import { Query } from '@/shared/types/query.types'; export function dateRange(days = 5): string[] { const result = []; @@ -14,3 +17,34 @@ export function dateRange(days = 5): string[] { return result; } + +export function useTotalRequests(data: Query): number { + const { user } = useAuth(); + const totalNamespaceRequests: number = React.useMemo(() => { + let result = 0; + if (user) { + const { namespace } = user; + + if (data?.allMetrics) { + data.allMetrics.forEach((m) => { + const metric = JSON.parse(m.metric); + + if (metric.service === namespace) { + const values = JSON.parse(m.values); + const dayValues = values.reduce( + (memo: number, v: number[] | [number, string]) => { + return memo + Number(v[1]); + }, + 0 + ); + result = result + dayValues; + } + }); + } + } + + return result; + }, [data, user]); + + return totalNamespaceRequests; +} diff --git a/src/nextapp/pages/manager/services/[id].tsx b/src/nextapp/pages/manager/services/[id].tsx index 5a3ae494f..af3472f9a 100644 --- a/src/nextapp/pages/manager/services/[id].tsx +++ b/src/nextapp/pages/manager/services/[id].tsx @@ -12,8 +12,6 @@ import { Tbody, Td, Text, - Th, - Thead, Tr, Wrap, WrapItem, @@ -22,7 +20,7 @@ import ClientRequest from '@/components/client-request'; import isEmpty from 'lodash/isEmpty'; import PageHeader from '@/components/page-header'; import api, { useApi } from '@/shared/services/api'; -import { dateRange } from '@/components/services-list/utils'; +import { dateRange, useTotalRequests } from '@/components/services-list/utils'; import { GET_GATEWAY_SERVICE } from '@/shared/queries/gateway-service-queries'; import { FaExternalLinkSquareAlt } from 'react-icons/fa'; import EnvironmentBadge from '@/components/environment-badge'; @@ -36,6 +34,7 @@ import { Query } from '@/shared/types/query.types'; import breadcrumbs from '@/components/ns-breadcrumb'; export const getServerSideProps: GetServerSideProps = async (context) => { + const range: string[] = dateRange(); const queryClient = new QueryClient(); await queryClient.prefetchQuery( @@ -43,7 +42,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => { async () => await api( GET_GATEWAY_SERVICE, - { id: context.params.id }, + { id: context.params.id, days: range }, { headers: context.req.headers as HeadersInit, } @@ -54,24 +53,26 @@ export const getServerSideProps: GetServerSideProps = async (context) => { props: { id: context.params.id, dehydratedState: dehydrate(queryClient), + range, }, }; }; const ServicePage: React.FC< InferGetServerSidePropsType -> = ({ id }) => { - const range = dateRange(); +> = ({ id, range }) => { const { data } = useApi( ['gateway-service', id], { query: GET_GATEWAY_SERVICE, variables: { id, + days: range, }, }, { enabled: Boolean(id), suspense: false } ); + const totalNamespaceRequests = useTotalRequests(data); const breadcrumb = breadcrumbs([ { href: '/manager/services', text: 'Services' }, ]); @@ -122,6 +123,7 @@ const ServicePage: React.FC< height={100} id={data?.GatewayService?.name} service={data?.GatewayService} + totalRequests={totalNamespaceRequests} /> )} @@ -152,6 +154,7 @@ const ServicePage: React.FC< height={100} id={data?.GatewayService?.name} service={data?.GatewayService} + totalRequests={totalNamespaceRequests} /> )} diff --git a/src/nextapp/shared/queries/gateway-service-queries.ts b/src/nextapp/shared/queries/gateway-service-queries.ts index ca6094ad0..c6e37500a 100644 --- a/src/nextapp/shared/queries/gateway-service-queries.ts +++ b/src/nextapp/shared/queries/gateway-service-queries.ts @@ -43,7 +43,7 @@ export const LIST_GATEWAY_SERVICES = gql` `; export const GET_GATEWAY_SERVICE = gql` - query GET($id: ID!) { + query GET($id: ID!, $days: [String!]) { GatewayService(where: { id: $id }) { id name @@ -78,6 +78,15 @@ export const GET_GATEWAY_SERVICE = gql` } updatedAt } + allMetrics( + sortBy: day_ASC + where: { query: "kong_http_requests_daily_namespace", day_in: $days } + ) { + query + day + metric + values + } } `; diff --git a/src/test/mock-server/data/metrics-data.js b/src/test/mock-server/data/metrics-data.js index 3b450983c..4c63a8023 100644 --- a/src/test/mock-server/data/metrics-data.js +++ b/src/test/mock-server/data/metrics-data.js @@ -1,4 +1,152 @@ -module.exports = [ +const namespaceMetrics = [ + { + query: 'kong_http_requests_daily_namespace', + day: '2021-07-10', + metric: JSON.stringify({ service: 'aps-portal' }), + values: JSON.stringify([ + [1625900400, '0'], + [1625904000, '10.29'], + [1625907600, '6.00418410041841'], + [1625911200, '130.00418410041841'], + [1625914800, '100.00418410041841'], + [1625918400, '0'], + [1625922000, '0'], + [1625925600, '0'], + [1625929200, '0'], + [1625932800, '0'], + [1625936400, '0'], + [1625940000, '14.01673640167364'], + [1625943600, '616.90376569037656'], + [1625947200, '871.9665271966527'], + [1625950800, '3.01255230125523'], + [1625954400, '46.06694560669456'], + [1625958000, '20.1255230125523'], + [1625961600, '100.00418410041841'], + [1625965200, '0'], + [1625968800, '0'], + [1625972400, '0'], + [1625976000, '0'], + [1625979600, '0'], + [1625983200, '303.13807531380753'], + ]), + service: { name: 'aps-portal' }, + }, + { + query: 'kong_http_requests_daily_namespace', + day: '2021-07-11', + metric: JSON.stringify({ service: 'aps-portal' }), + values: JSON.stringify([ + [1625986800, '0'], + [1625990400, '12.00836820083682'], + [1625994000, '0'], + [1625997600, '12.00836820083682'], + [1626001200, '43.01255230125523'], + [1626004800, '49.01673640167364'], + [1626008400, '10.00418410041841'], + [1626012000, '48.03347280334728'], + [1626015600, '10.00418410041841'], + [1626019200, '1.00418410041841'], + [1626022800, '0'], + [1626026400, '0'], + [1626030000, '30.01255230125523'], + [1626033600, '2.00836820083682'], + [1626037200, '200.00836820083682'], + [1626040800, '35.146443514644346'], + [1626044400, '1.00418410041841'], + [1626048000, '64.2678471329176'], + [1626051600, '1041.5899581589958'], + [1626055200, '0'], + [1626058800, '8.03347280334728'], + [1626062400, '20.00836820083682'], + [1626066000, '2.00836820083682'], + [1626069600, '155.64853556485355'], + ]), + service: { name: 'aps-portal' }, + }, + { + query: 'kong_http_requests_daily_namespace', + day: '2021-07-12', + metric: JSON.stringify({ service: 'aps-portal' }), + values: JSON.stringify([ + [1626073200, '0'], + [1626076800, '200.00836820083682'], + [1626080400, '10.00418410041841'], + [1626084000, '0'], + [1626087600, '9.00418410041841'], + [1626091200, '6.00836820083682'], + [1626094800, '2.00836820083682'], + [1626098400, '10.00418410041841'], + [1626102000, '0'], + [1626105600, '1.00418410041841'], + [1626109200, '576.73640167364016'], + [1626112800, '200.00836820083682'], + [1626116400, '30.01255230125523'], + [1626120000, '15.00418410041841'], + [1626123600, '15.00418410041841'], + [1626127200, '141.58995815899578'], + [1626130800, '97.40585774058577'], + [1626134400, '93.17991631799163'], + [1626138000, '100.00418410041841'], + [1626141600, '0'], + [1626145200, '0'], + [1626148800, '20.00418410041841'], + [1626152400, '50.00418410041841'], + [1626156000, '20.00836820083682'], + ]), + service: { name: 'aps-portal' }, + }, + { + query: 'kong_http_requests_daily_namespace', + day: '2021-07-13', + metric: JSON.stringify({ service: 'aps-portal' }), + values: JSON.stringify([ + [1626159600, '18.00418410041841'], + [1626163200, '18.00418410041841'], + [1626166800, '18.00418410041841'], + [1626170400, '0'], + [1626174000, '30.01255230125523'], + [1626177600, '0'], + [1626181200, '10.00418410041841'], + [1626184800, '3.01255230125523'], + [1626188400, '1.00418410041841'], + [1626192000, '0'], + [1626195600, '808.4518828451883'], + [1626199200, '802.4285007487669'], + [1626202800, '91.3807531380753'], + [1626206400, '238.57740585774056'], + [1626210000, '0'], + [1626213600, '804.1004184100418'], + [1626217200, '30.01255230125523'], + [1626220800, '171.29708569548971'], + [1626224400, '106.06694560669456'], + [1626228000, '20.00836820083682'], + [1626231600, '10.00418410041841'], + [1626235200, '10.00418410041841'], + [1626238800, '174.72803347280333'], + [1626242400, '20.00836820083682'], + ]), + service: { name: 'aps-portal' }, + }, + { + query: 'kong_http_requests_daily_namespace', + day: '2021-07-14', + metric: JSON.stringify({ service: 'aps-portal' }), + values: JSON.stringify([ + [1626246000, '0'], + [1626249600, '0'], + [1626253200, '0'], + [1626256800, '0'], + [1626260400, '0'], + [1626264000, '100.00418410041841'], + [1626267600, '0'], + [1626271200, '0'], + [1626274800, '75.035573770491804'], + ]), + service: { name: 'aps-portal' }, + }, +]; + +const serviceMetrics = [ { query: 'kong_http_requests_hourly_service', day: '2021-07-10', @@ -145,3 +293,8 @@ module.exports = [ service: { name: 'aps-portal' }, }, ]; + +module.exports = { + namespaceMetrics, + serviceMetrics, +}; diff --git a/src/test/mock-server/server.js b/src/test/mock-server/server.js index 629f965ee..3d8612ab5 100644 --- a/src/test/mock-server/server.js +++ b/src/test/mock-server/server.js @@ -81,7 +81,12 @@ const server = mockServer(schemaWithMocks, { allNamespaceServiceAccounts: () => new MockList(2, (_, { id }) => ({ id })), allGatewayConsumers: () => new MockList(4, (_, { id }) => ({ id })), allPlugins: () => new MockList(4, (_, { id }) => ({ id })), - allMetrics: (_query, _, args) => metricsData, + allMetrics: (query) => { + if (query.where.query === 'kong_http_requests_daily_namespace') { + return metricsData.namespaceMetrics; + } + return metricsData.serviceMetrics; + }, getPermissionTickets: () => new MockList(6, (_, { id }) => ({ id })), getPermissionTicketsForResource: () => new MockList(6, (_, { id }) => ({ id })), From f5bf3835804c32cb02fb4243ef8c8b33a4dcc909 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 28 Jul 2021 12:58:52 -0700 Subject: [PATCH 054/155] updated github action to generate trivy results and upload them to security tab. Removed e2e test result --- .github/workflows/ci-container-img-scan.yaml | 12 +++++++++--- e2e/results/report/bcgov-aps-e2e-report.html | 17 ----------------- 2 files changed, 9 insertions(+), 20 deletions(-) delete mode 100644 e2e/results/report/bcgov-aps-e2e-report.html diff --git a/.github/workflows/ci-container-img-scan.yaml b/.github/workflows/ci-container-img-scan.yaml index c94c04177..307ecdbe3 100644 --- a/.github/workflows/ci-container-img-scan.yaml +++ b/.github/workflows/ci-container-img-scan.yaml @@ -5,7 +5,7 @@ on: branches: [dev, main, scan/*] jobs: - Anchore-Build-Scan: + portal-image-Scan: runs-on: ubuntu-latest steps: - name: Checkout the code @@ -18,7 +18,7 @@ jobs: image: 'bcgov/api-services-portal:scan' acs-report-enable: true fail-build: false - - name: Upload Anchore Scan Report + - name: Upload Anchore Scan Results uses: github/codeql-action/upload-sarif@v1 with: sarif_file: results.sarif @@ -26,8 +26,14 @@ jobs: uses: aquasecurity/trivy-action@master with: image-ref: 'bcgov/api-services-portal:scan' - format: 'table' + format: 'template' exit-code: '0' ignore-unfixed: true vuln-type: 'os,library' severity: 'CRITICAL,HIGH,MEDIUM' + template: '@/contrib/sarif.tpl' + output: 'trivy-results.sarif' + - name: Upload Trivy Scan Results + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: 'trivy-results.sarif' diff --git a/e2e/results/report/bcgov-aps-e2e-report.html b/e2e/results/report/bcgov-aps-e2e-report.html deleted file mode 100644 index db384c337..000000000 --- a/e2e/results/report/bcgov-aps-e2e-report.html +++ /dev/null @@ -1,17 +0,0 @@ - -Mochawesome Report
\ No newline at end of file From f8c27ef491012075acfbd7fce9c1b961334fd77b Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 28 Jul 2021 13:20:06 -0700 Subject: [PATCH 055/155] separated anchore and trivy to be able to upload both the results to security tab --- .github/workflows/ci-anchore-img-scan.yaml | 24 ++++++++++++ .github/workflows/ci-container-img-scan.yaml | 39 -------------------- .github/workflows/ci-trivy-img-scan.yaml | 25 +++++++++++++ 3 files changed, 49 insertions(+), 39 deletions(-) create mode 100644 .github/workflows/ci-anchore-img-scan.yaml delete mode 100644 .github/workflows/ci-container-img-scan.yaml create mode 100644 .github/workflows/ci-trivy-img-scan.yaml diff --git a/.github/workflows/ci-anchore-img-scan.yaml b/.github/workflows/ci-anchore-img-scan.yaml new file mode 100644 index 000000000..006693df1 --- /dev/null +++ b/.github/workflows/ci-anchore-img-scan.yaml @@ -0,0 +1,24 @@ +name: Scan for Vulnerabilities - Anchore + +on: + push: + branches: [dev, main, scan/*] + +jobs: + anchore-image-Scan: + runs-on: ubuntu-latest + steps: + # - name: Checkout the code + # uses: actions/checkout@v2 + # - name: Build the Docker image + # run: docker build . --file Dockerfile --tag bcgov/api-services-portal:scan + - name: Run the Anchore Scan + uses: anchore/scan-action@main + with: + image: ${{ env.REGISTRY }}/bcgov/api-services-portal/api-services-portal + acs-report-enable: true + fail-build: false + - name: Upload Anchore Scan Results + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: anchore-results.sarif diff --git a/.github/workflows/ci-container-img-scan.yaml b/.github/workflows/ci-container-img-scan.yaml deleted file mode 100644 index 307ecdbe3..000000000 --- a/.github/workflows/ci-container-img-scan.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: Scan for Vulnerabilities in API Services Portal Container Image - -on: - push: - branches: [dev, main, scan/*] - -jobs: - portal-image-Scan: - runs-on: ubuntu-latest - steps: - - name: Checkout the code - uses: actions/checkout@v2 - - name: Build the Docker image - run: docker build . --file Dockerfile --tag bcgov/api-services-portal:scan - - name: Run the Anchore scan action itself with GitHub Advanced Security code scanning integration enabled - uses: anchore/scan-action@main - with: - image: 'bcgov/api-services-portal:scan' - acs-report-enable: true - fail-build: false - - name: Upload Anchore Scan Results - uses: github/codeql-action/upload-sarif@v1 - with: - sarif_file: results.sarif - - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@master - with: - image-ref: 'bcgov/api-services-portal:scan' - format: 'template' - exit-code: '0' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH,MEDIUM' - template: '@/contrib/sarif.tpl' - output: 'trivy-results.sarif' - - name: Upload Trivy Scan Results - uses: github/codeql-action/upload-sarif@v1 - with: - sarif_file: 'trivy-results.sarif' diff --git a/.github/workflows/ci-trivy-img-scan.yaml b/.github/workflows/ci-trivy-img-scan.yaml new file mode 100644 index 000000000..4c6ddc013 --- /dev/null +++ b/.github/workflows/ci-trivy-img-scan.yaml @@ -0,0 +1,25 @@ +name: Scan for Vulnerabilities in API Services Portal Container Image + +on: + push: + branches: [dev, main, scan/*] + +jobs: + trivy-image-Scan: + runs-on: ubuntu-latest + steps: + - name: Run Trivy Scan + uses: aquasecurity/trivy-action@master + with: + image-ref: ${{ env.REGISTRY }}/bcgov/api-services-portal/api-services-portal + format: 'template' + exit-code: '0' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH,MEDIUM' + template: '@/contrib/sarif.tpl' + output: 'trivy-results.sarif' + - name: Upload Trivy Scan Results + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: 'trivy-results.sarif' From fe06886175e07ca4da5b68538d3c9be486e1037d Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 28 Jul 2021 13:35:25 -0700 Subject: [PATCH 056/155] added env vars to pull image from container registry --- .github/workflows/ci-anchore-img-scan.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ci-anchore-img-scan.yaml b/.github/workflows/ci-anchore-img-scan.yaml index 006693df1..1831c8e56 100644 --- a/.github/workflows/ci-anchore-img-scan.yaml +++ b/.github/workflows/ci-anchore-img-scan.yaml @@ -4,6 +4,11 @@ on: push: branches: [dev, main, scan/*] +env: + REGISTRY: ghcr.io + REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} + jobs: anchore-image-Scan: runs-on: ubuntu-latest @@ -12,6 +17,12 @@ jobs: # uses: actions/checkout@v2 # - name: Build the Docker image # run: docker build . --file Dockerfile --tag bcgov/api-services-portal:scan + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ env.REGISTRY_USERNAME }} + password: ${{ env.REGISTRY_PASSWORD }} - name: Run the Anchore Scan uses: anchore/scan-action@main with: From c6cdbc33bd9dfe71a0c6c81f87965eb58693b181 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 28 Jul 2021 14:02:24 -0700 Subject: [PATCH 057/155] building an image for scanning --- .github/workflows/ci-anchore-img-scan.yaml | 21 +++++---------------- .github/workflows/ci-trivy-img-scan.yaml | 8 ++++++-- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci-anchore-img-scan.yaml b/.github/workflows/ci-anchore-img-scan.yaml index 1831c8e56..f01ac34dd 100644 --- a/.github/workflows/ci-anchore-img-scan.yaml +++ b/.github/workflows/ci-anchore-img-scan.yaml @@ -4,29 +4,18 @@ on: push: branches: [dev, main, scan/*] -env: - REGISTRY: ghcr.io - REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} - REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} - jobs: anchore-image-Scan: runs-on: ubuntu-latest steps: - # - name: Checkout the code - # uses: actions/checkout@v2 - # - name: Build the Docker image - # run: docker build . --file Dockerfile --tag bcgov/api-services-portal:scan - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ env.REGISTRY_USERNAME }} - password: ${{ env.REGISTRY_PASSWORD }} + - name: Checkout the code + uses: actions/checkout@v2 + - name: Build the Docker image + run: docker build . --file Dockerfile --tag bcgov/api-services-portal:anchore-scan - name: Run the Anchore Scan uses: anchore/scan-action@main with: - image: ${{ env.REGISTRY }}/bcgov/api-services-portal/api-services-portal + image: 'bcgov/api-services-portal:anchore-scan' acs-report-enable: true fail-build: false - name: Upload Anchore Scan Results diff --git a/.github/workflows/ci-trivy-img-scan.yaml b/.github/workflows/ci-trivy-img-scan.yaml index 4c6ddc013..4a08ebeda 100644 --- a/.github/workflows/ci-trivy-img-scan.yaml +++ b/.github/workflows/ci-trivy-img-scan.yaml @@ -1,4 +1,4 @@ -name: Scan for Vulnerabilities in API Services Portal Container Image +name: Scan for Vulnerabilities - Trivy on: push: @@ -8,10 +8,14 @@ jobs: trivy-image-Scan: runs-on: ubuntu-latest steps: + - name: Checkout the code + uses: actions/checkout@v2 + - name: Build the Docker image + run: docker build . --file Dockerfile --tag bcgov/api-services-portal:trivy-scan - name: Run Trivy Scan uses: aquasecurity/trivy-action@master with: - image-ref: ${{ env.REGISTRY }}/bcgov/api-services-portal/api-services-portal + image-ref: 'bcgov/api-services-portal:trivy-scan' format: 'template' exit-code: '0' ignore-unfixed: true From 5ed903bf8e0ab09250d00c1149a300394787dfd9 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 28 Jul 2021 14:26:27 -0700 Subject: [PATCH 058/155] updated the results file name --- .github/workflows/ci-anchore-img-scan.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-anchore-img-scan.yaml b/.github/workflows/ci-anchore-img-scan.yaml index f01ac34dd..39ee38ae8 100644 --- a/.github/workflows/ci-anchore-img-scan.yaml +++ b/.github/workflows/ci-anchore-img-scan.yaml @@ -21,4 +21,4 @@ jobs: - name: Upload Anchore Scan Results uses: github/codeql-action/upload-sarif@v1 with: - sarif_file: anchore-results.sarif + sarif_file: results.sarif From a9fd82499d26648f9bfda4e8d40ed29cd1229541 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Wed, 28 Jul 2021 15:28:36 -0700 Subject: [PATCH 059/155] fix CredentialIssuer authedItem missing --- src/lists/CredentialIssuer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lists/CredentialIssuer.js b/src/lists/CredentialIssuer.js index ce95b0450..eb8dd83de 100644 --- a/src/lists/CredentialIssuer.js +++ b/src/lists/CredentialIssuer.js @@ -157,7 +157,7 @@ module.exports = { if (!('owner' in resolvedData) && context['authedItem']) { resolvedData['owner'] = context.authedItem.userId; } - if ('namespace' in context['authedItem']) { + if (context['authedItem'] && 'namespace' in context['authedItem']) { resolvedData['namespace'] = context['authedItem']['namespace']; } } From e93535b02034e38650f4df4d85d7bf0504c1c6de Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 29 Jul 2021 11:48:56 -0700 Subject: [PATCH 060/155] added test ids for portal elements for better visibility in cypress tests --- .github/workflows/aps-cypress-e2e.yaml | 2 +- docker-compose-portal.yml | 40 +++ docker-compose.yml | 130 ++++----- local/feeder-init/init.sh | 2 +- .../components/auth-action/auth-action.tsx | 8 +- .../namespace-menu/namespace-menu.tsx | 9 +- src/nextapp/components/nav-bar/nav-bar.tsx | 1 + .../new-namespace/new-namespace.tsx | 6 +- .../service-account-create.tsx | 9 +- .../pages/manager/poc/namespaces/nav.tsx | 247 +++++++++--------- .../manager/poc/service-accounts/index.tsx | 7 +- 11 files changed, 259 insertions(+), 202 deletions(-) create mode 100644 docker-compose-portal.yml diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index c143c87dd..e36c4fc7a 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -3,7 +3,7 @@ name: Build and Deploy Cypress and Execute Tests on: push: branches: - - 'util/automation-*' + - 'util/automation-not*' jobs: cypress-run: diff --git a/docker-compose-portal.yml b/docker-compose-portal.yml new file mode 100644 index 000000000..c2d311133 --- /dev/null +++ b/docker-compose-portal.yml @@ -0,0 +1,40 @@ +version: '3.8' + +services: + apsportal: + container_name: apsportal + image: apsportal:latest + build: + context: . + dockerfile: Dockerfile + env_file: + - .env.local + ports: + - 3000:3000 + networks: + aps-net: + aliases: + - apsportal.localtest.me +# feeder-seeding: +# container_name: feeder-seeding +# image: feeder:latest +# command: '' +# entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" +# restart: on-failure +# volumes: +# - ./local/feeder-init:/tmp +# networks: +# - aps-net +# cypress: +# image: 'aps-cypress-e2e:latest' +# container_name: cypress-e2e +# entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" +# build: +# context: ./e2e +# dockerfile: Dockerfile +# volumes: +# - ./e2e/results/report:/e2e/results/report +# networks: +# - aps-net +networks: + aps-net: {} diff --git a/docker-compose.yml b/docker-compose.yml index 22c3958ef..b9a273266 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,10 +38,9 @@ services: volumes: - ./local/keycloak/master-realm.json:/tmp/realm-config/master-realm.json networks: - keycloak: + aps-net: aliases: - keycloak.localtest.me - kong-net: {} oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy:v7.1.3 container_name: oauth2-proxy @@ -56,32 +55,25 @@ services: env_file: - .env.local networks: - keycloak: {} - portal: {} - kong-net: {} - redis-net: {} - oauth2-proxy: + aps-net: aliases: - oauth2proxy.localtest.me - apsportal: - container_name: apsportal - image: apsportal:latest - depends_on: - - keycloak - build: - context: . - dockerfile: Dockerfile - env_file: - - .env.local - ports: - - 3000:3000 - networks: - portal: - aliases: - - apsportal.localtest.me - keycloak: {} - oauth2-proxy: {} - kong-net: {} + # apsportal: + # container_name: apsportal + # image: apsportal:latest + # depends_on: + # - keycloak + # build: + # context: . + # dockerfile: Dockerfile + # env_file: + # - .env.local + # ports: + # - 3000:3000 + # networks: + # aps-net: + # aliases: + # - apsportal.localtest.me feeder: container_name: feeder image: feeder:latest @@ -96,37 +88,34 @@ services: ports: - 6000:6000 networks: - portal: + aps-net: aliases: - feeder.localtest.me - kong-net: {} - feeder-seeding: - container_name: feeder-seeding - image: feeder:latest - command: '' - entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" - restart: on-failure - depends_on: - - feeder - volumes: - - ./local/feeder-init:/tmp - networks: - - portal - - keycloak - cypress: - image: 'aps-cypress-e2e:latest' - container_name: cypress-e2e - entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" - depends_on: - - feeder-seeding - build: - context: ./e2e - dockerfile: Dockerfile - volumes: - - ./e2e/results/report:/e2e/results/report - networks: - - keycloak - - oauth2-proxy + # feeder-seeding: + # container_name: feeder-seeding + # image: feeder:latest + # command: '' + # entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" + # restart: on-failure + # depends_on: + # - feeder + # volumes: + # - ./local/feeder-init:/tmp + # networks: + # - aps-net + # cypress: + # image: 'aps-cypress-e2e:latest' + # container_name: cypress-e2e + # entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" + # depends_on: + # - feeder-seeding + # build: + # context: ./e2e + # dockerfile: Dockerfile + # volumes: + # - ./e2e/results/report:/e2e/results/report + # networks: + # - aps-net kong-db: image: postgres:latest container_name: kong-db @@ -141,9 +130,7 @@ services: - ./local/db/database-init.sql:/docker-entrypoint-initdb.d/1-init.sql - ./local/db/keystone-init.sql:/docker-entrypoint-initdb.d/2-init.sql networks: - - kong-net - - keycloak - - portal + - aps-net kong-migrations: image: kong:latest command: kong migrations bootstrap @@ -151,7 +138,7 @@ services: - kong-db environment: *common-variables networks: - - kong-net + - aps-net restart: on-failure kong-migrations-up: image: kong:latest @@ -160,7 +147,7 @@ services: - kong-db environment: *common-variables networks: - - kong-net + - aps-net restart: on-failure kong: image: kong:latest @@ -181,7 +168,7 @@ services: - 8000:8000 - 8001:8001 networks: - kong-net: + aps-net: aliases: - kong.localtest.me restart: on-failure:5 @@ -194,12 +181,12 @@ services: ports: - 6379:6379 networks: - redis-net: + aps-net: aliases: - redis.localtest.me - gwa-api: - image: gateway-api:latest - container_name: gwa-api + gwa-gateway-api: + image: ghcr.io/bcgov/gwa-api/gwa-gateway-api:feature-add-consumer-service + container_name: gwa-gateway-api entrypoint: sh -c "chmod +x /tmp/gwa/entrypoint.sh && sh /tmp/gwa/entrypoint.sh" ports: - 2000:2000 @@ -209,17 +196,8 @@ services: volumes: - ./local/gwa-api:/tmp/gwa networks: - gwa-net: + aps-net: aliases: - gwa-api.localtest.me - oauth2-proxy: {} - portal: {} - kong-net: {} - keycloak: {} networks: - keycloak: {} - oauth2-proxy: {} - portal: {} - kong-net: {} - redis-net: {} - gwa-net: {} + aps-net: {} diff --git a/local/feeder-init/init.sh b/local/feeder-init/init.sh index 0a175bfce..a95616801 100755 --- a/local/feeder-init/init.sh +++ b/local/feeder-init/init.sh @@ -4,7 +4,7 @@ apk add --no-cache curl cd /tmp while true; do - keycloakstatus=$(curl -o /dev/null -Isw '%{http_code}\n' http://keycloak.localtest.me:9080/auth/realms/master) + keycloakstatus=$(curl -o /dev/null -Isw '%{http_code}\n' http://oauth2proxy.localtest.me:4180) echo "$keycloakstatus" if [[ "$keycloakstatus" == "200" ]]; then echo "Keycloak is up" diff --git a/src/nextapp/components/auth-action/auth-action.tsx b/src/nextapp/components/auth-action/auth-action.tsx index 83ab1e254..90ca640a1 100644 --- a/src/nextapp/components/auth-action/auth-action.tsx +++ b/src/nextapp/components/auth-action/auth-action.tsx @@ -57,10 +57,16 @@ const Signin: React.FC = ({ site }) => { color="text" onClick={onNextLinkClick} value="/poc/my-profile" + data-testid="auth-menu-user-profile" > My Profile - + Sign Out diff --git a/src/nextapp/components/namespace-menu/namespace-menu.tsx b/src/nextapp/components/namespace-menu/namespace-menu.tsx index 16be9546a..0cc365fdb 100644 --- a/src/nextapp/components/namespace-menu/namespace-menu.tsx +++ b/src/nextapp/components/namespace-menu/namespace-menu.tsx @@ -79,6 +79,7 @@ const NamespaceMenu: React.FC = ({ user }) => { _hover={{ bg: 'gray.400' }} _expanded={{ bg: 'blue.400' }} _focus={{ boxShadow: 'outline' }} + data-testid="ns-dropdown-btn" > {user?.namespace ?? 'No Active Namespace'} @@ -96,7 +97,11 @@ const NamespaceMenu: React.FC = ({ user }) => { .filter((n) => n.name !== user.namespace) .sort((a, b) => a.name.localeCompare(b.name)) .map((n) => ( - + {n.name} ))} @@ -111,6 +116,7 @@ const NamespaceMenu: React.FC = ({ user }) => { icon={} color="bc-blue-alt" onClick={managerDisclosure.onOpen} + data-testid="ns-dropdown-manage-btn" > Manage Namespaces @@ -119,6 +125,7 @@ const NamespaceMenu: React.FC = ({ user }) => { onClick={newNamespaceDisclosure.onOpen} fontWeight="bold" color="bc-blue-alt" + data-testid="ns-dropdown-create-btn" > Create New Namespace diff --git a/src/nextapp/components/nav-bar/nav-bar.tsx b/src/nextapp/components/nav-bar/nav-bar.tsx index 48f0166b9..f6446c767 100644 --- a/src/nextapp/components/nav-bar/nav-bar.tsx +++ b/src/nextapp/components/nav-bar/nav-bar.tsx @@ -80,6 +80,7 @@ const NavBar: React.FC = ({ site, links, pathname }) => { ? 'page' : false } + data-testid={'navbar-link-' + link.name} > {link.name} diff --git a/src/nextapp/components/new-namespace/new-namespace.tsx b/src/nextapp/components/new-namespace/new-namespace.tsx index c1c02fbb7..1a494a7e1 100644 --- a/src/nextapp/components/new-namespace/new-namespace.tsx +++ b/src/nextapp/components/new-namespace/new-namespace.tsx @@ -81,17 +81,21 @@ const NewNamespace: React.FC = ({ isOpen, onClose }) => { name="name" type="text" variant="bc-input" + data-testid="ns-modal-name-input" /> - + diff --git a/src/nextapp/components/service-account-create/service-account-create.tsx b/src/nextapp/components/service-account-create/service-account-create.tsx index 484bbcfb6..123421546 100644 --- a/src/nextapp/components/service-account-create/service-account-create.tsx +++ b/src/nextapp/components/service-account-create/service-account-create.tsx @@ -79,6 +79,7 @@ const ServiceAccountCreate: React.FC = ({ leftIcon={} variant="primary" onClick={onOpen} + data-testid="sa-create-second-btn" > New Service Account @@ -103,7 +104,11 @@ const ServiceAccountCreate: React.FC = ({ {isSuccess && data?.currentNamespace.scopes.map((s) => ( - + {s.name} @@ -119,6 +124,7 @@ const ServiceAccountCreate: React.FC = ({ @@ -126,6 +132,7 @@ const ServiceAccountCreate: React.FC = ({ isLoading={credentialGenerator.isLoading} variant="primary" onClick={handleCreate} + data-testid="sa-scopes-share-btn" > Share diff --git a/src/nextapp/pages/manager/poc/namespaces/nav.tsx b/src/nextapp/pages/manager/poc/namespaces/nav.tsx index a7ecc70df..72d4ccacf 100644 --- a/src/nextapp/pages/manager/poc/namespaces/nav.tsx +++ b/src/nextapp/pages/manager/poc/namespaces/nav.tsx @@ -1,137 +1,148 @@ import * as React from 'react'; -import { Box, Container, Divider, Grid, Heading, Icon, Link, Text } from '@chakra-ui/react'; +import { + Box, + Container, + Divider, + Grid, + Heading, + Icon, + Link, + Text, +} from '@chakra-ui/react'; import Head from 'next/head'; import NextLink from 'next/link'; import Card from '@/components/card'; import GridLayout from '@/layouts/grid'; -import { - FaServer, -} from 'react-icons/fa'; - +import { FaServer } from 'react-icons/fa'; + import { useAuth } from '@/shared/services/auth'; type HomeActions = { - title: string; - url: string; - icon: React.ComponentType; - roles: string[]; - description: string; - }; + title: string; + url: string; + icon: React.ComponentType; + roles: string[]; + description: string; +}; + +const actions: HomeActions[] = [ + { + title: 'Gateway Services', + url: '/manager/services', + icon: FaServer, + roles: [], + description: + 'View your current gateway configuration, metrics and traffic patterns', + }, + { + title: 'Products', + url: '/manager/products', + icon: FaServer, + roles: [], + description: 'Publish your API and make it discoverable', + }, + { + title: 'Consumers', + url: '/manager/consumers', + icon: FaServer, + roles: [], + description: + 'Manage your prospective and existing clients - add controls, approve access, view usage', + }, +]; - const actions: HomeActions[] = [ - { - title: 'Gateway Services', - url: '/manager/services', - icon: FaServer, - roles: [], - description: "View your current gateway configuration, metrics and traffic patterns" - }, - { - title: 'Products', - url: '/manager/products', - icon: FaServer, - roles: [], - description: "Publish your API and make it discoverable" - }, - { - title: 'Consumers', - url: '/manager/consumers', - icon: FaServer, - roles: [], - description: "Manage your prospective and existing clients - add controls, approve access, view usage" - } - ]; +const secondaryActions: HomeActions[] = [ + { + title: 'Authorization Profiles', + url: '/manager/poc/credential-issuers', + icon: FaServer, + roles: [], + description: 'Manage authorization servers used to protect your APIs', + }, + { + title: 'Service Accounts', + url: '/manager/poc/service-accounts', + icon: FaServer, + roles: [], + description: + 'Manage service accounts for performing functions on the namespace', + }, + { + title: 'Activity', + url: '/manager/poc/activity', + icon: FaServer, + roles: [], + description: 'View all the activity within your namepace.', + }, +]; - const secondaryActions: HomeActions[] = [ - { - title: 'Authorization Profiles', - url: '/manager/poc/credential-issuers', - icon: FaServer, - roles: [], - description: "Manage authorization servers used to protect your APIs" - }, - { - title: 'Service Accounts', - url: '/manager/poc/service-accounts', - icon: FaServer, - roles: [], - description: "Manage service accounts for performing functions on the namespace" - }, - { - title: 'Activity', - url: '/manager/poc/activity', - icon: FaServer, - roles: [], - description: "View all the activity within your namepace." - }, - ]; - const Navigation = () => { - const { user } = useAuth() + const { user } = useAuth(); - return ( + return ( - - - - {actions - .filter( - (action) => - user?.roles.some((r: string) => action.roles.includes(r)) || - action.roles.length === 0 - ) - .map((action) => ( - - - - - - {action.title} - - - -

- {action.description} -

-
- ))} -
-
- - - Other Actions: + + + + {actions + .filter( + (action) => + user?.roles.some((r: string) => action.roles.includes(r)) || + action.roles.length === 0 + ) + .map((action) => ( + + + + + + {action.title} + + + +

{action.description}

+
+ ))} +
+
- - {secondaryActions - .filter( - (action) => - user?.roles.some((r: string) => action.roles.includes(r)) || - action.roles.length === 0 - ) - .map((action) => ( - - - - - - {action.title} - - - - - ))} - -
+ + Other Actions: + + {secondaryActions + .filter( + (action) => + user?.roles.some((r: string) => action.roles.includes(r)) || + action.roles.length === 0 + ) + .map((action) => ( + + + + + + {action.title} + + + + + ))} + +
- ) -} + ); +}; export default Navigation; - - diff --git a/src/nextapp/pages/manager/poc/service-accounts/index.tsx b/src/nextapp/pages/manager/poc/service-accounts/index.tsx index 8d83ace85..718a43665 100644 --- a/src/nextapp/pages/manager/poc/service-accounts/index.tsx +++ b/src/nextapp/pages/manager/poc/service-accounts/index.tsx @@ -109,7 +109,11 @@ const ApplicationsPage: React.FC< }; const actions = [ - , ]; @@ -227,4 +231,3 @@ const CREATE = gql` } } `; - From 080940289248c4f35070856608806b020bdaad92 Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Thu, 29 Jul 2021 12:39:31 -0700 Subject: [PATCH 061/155] Replace custom button component --- src/nextapp/components/auth-action/auth-action.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/nextapp/components/auth-action/auth-action.tsx b/src/nextapp/components/auth-action/auth-action.tsx index 90ca640a1..918f624c0 100644 --- a/src/nextapp/components/auth-action/auth-action.tsx +++ b/src/nextapp/components/auth-action/auth-action.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; import { Box, + Button, Icon, Menu, MenuButton, MenuList, MenuItem, } from '@chakra-ui/react'; -import Button from '@/components/button'; import { FaChevronDown, FaUserCircle } from 'react-icons/fa'; import { useAuth } from '@/shared/services/auth'; import { useRouter } from 'next/router'; @@ -29,7 +29,12 @@ const Signin: React.FC = ({ site }) => { if (!user) { return ( - ); From 41fe8f6fed09b1221b0c32a2259ae89650232047 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 29 Jul 2021 14:11:32 -0700 Subject: [PATCH 062/155] updated the kong url to gwa url for managing consumer plugins --- src/lists/GatewayConsumer.js | 9 ++++++--- src/services/kong/consumer-service.ts | 28 ++++++++++++++++----------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/lists/GatewayConsumer.js b/src/lists/GatewayConsumer.js index 47d73a0d5..0263a6e8d 100644 --- a/src/lists/GatewayConsumer.js +++ b/src/lists/GatewayConsumer.js @@ -96,7 +96,8 @@ module.exports = { const result = await kongApi.addPluginToConsumer( kongConsumerPK, - JSON.parse(args.plugin) + JSON.parse(args.plugin), + context.req.user.namespace ); await feederApi.forceSync('kong', 'consumer', kongConsumerPK); @@ -123,7 +124,8 @@ module.exports = { const result = await kongApi.updateConsumerPlugin( kongConsumerPK, args.pluginExtForeignKey, - JSON.parse(args.plugin) + JSON.parse(args.plugin), + context.req.user.namespace ); await feederApi.forceSync('kong', 'consumer', kongConsumerPK); @@ -149,7 +151,8 @@ module.exports = { const result = await kongApi.deleteConsumerPlugin( kongConsumerPK, - args.pluginExtForeignKey + args.pluginExtForeignKey, + context.req.user.namespace ); await feederApi.forceSync('kong', 'consumer', kongConsumerPK); diff --git a/src/services/kong/consumer-service.ts b/src/services/kong/consumer-service.ts index b347b13e1..9ac2ad040 100644 --- a/src/services/kong/consumer-service.ts +++ b/src/services/kong/consumer-service.ts @@ -140,13 +140,14 @@ export class KongConsumerService { public async addPluginToConsumer( consumerPK: string, - plugin: KongPlugin + plugin: KongPlugin, + namespace: string ): Promise { const body = {}; logger.debug('[addPluginToConsumer] CALLING with ' + consumerPK); const response = await fetch( - `${this.kongUrl}/consumers/${consumerPK}/plugins`, + `/gw/api/namespaces/${namespace}/consumers/${consumerPK}/plugins`, { method: 'post', body: JSON.stringify(plugin), @@ -167,12 +168,13 @@ export class KongConsumerService { public async updateConsumerPlugin( consumerPK: string, pluginPK: string, - plugin: KongPlugin + plugin: KongPlugin, + namespace: string ): Promise { logger.debug('[updateConsumerPlugin] C=%s P=%s', consumerPK, pluginPK); const response = await fetch( - `${this.kongUrl}/consumers/${consumerPK}/plugins/${pluginPK}`, + `/gw/api/namespaces/${namespace}/consumers/${consumerPK}/plugins/${pluginPK}`, { method: 'put', body: JSON.stringify(plugin), @@ -189,14 +191,18 @@ export class KongConsumerService { public async deleteConsumerPlugin( consumerPK: string, - pluginPK: string + pluginPK: string, + namespace: string ): Promise { - await fetch(`${this.kongUrl}/consumers/${consumerPK}/plugins/${pluginPK}`, { - method: 'delete', - headers: { - 'Content-Type': 'application/json', - }, - }).then(checkStatus); + await fetch( + `/gw/api/namespaces/${namespace}/consumers/${consumerPK}/plugins/${pluginPK}`, + { + method: 'delete', + headers: { + 'Content-Type': 'application/json', + }, + } + ).then(checkStatus); } public async genKeyForConsumerKeyAuth(consumerPK: string, keyAuthPK: string) { From 183050450f0df98f72e190444c57b242971011e8 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 29 Jul 2021 15:51:20 -0700 Subject: [PATCH 063/155] updated docker compose --- docker-compose-portal.yml | 40 ---------------------------- docker-compose.yml | 56 +++++++++++++++++++-------------------- local/feeder-init/init.sh | 2 +- 3 files changed, 29 insertions(+), 69 deletions(-) delete mode 100644 docker-compose-portal.yml diff --git a/docker-compose-portal.yml b/docker-compose-portal.yml deleted file mode 100644 index c2d311133..000000000 --- a/docker-compose-portal.yml +++ /dev/null @@ -1,40 +0,0 @@ -version: '3.8' - -services: - apsportal: - container_name: apsportal - image: apsportal:latest - build: - context: . - dockerfile: Dockerfile - env_file: - - .env.local - ports: - - 3000:3000 - networks: - aps-net: - aliases: - - apsportal.localtest.me -# feeder-seeding: -# container_name: feeder-seeding -# image: feeder:latest -# command: '' -# entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" -# restart: on-failure -# volumes: -# - ./local/feeder-init:/tmp -# networks: -# - aps-net -# cypress: -# image: 'aps-cypress-e2e:latest' -# container_name: cypress-e2e -# entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" -# build: -# context: ./e2e -# dockerfile: Dockerfile -# volumes: -# - ./e2e/results/report:/e2e/results/report -# networks: -# - aps-net -networks: - aps-net: {} diff --git a/docker-compose.yml b/docker-compose.yml index b9a273266..4ff66e5b8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -58,22 +58,22 @@ services: aps-net: aliases: - oauth2proxy.localtest.me - # apsportal: - # container_name: apsportal - # image: apsportal:latest - # depends_on: - # - keycloak - # build: - # context: . - # dockerfile: Dockerfile - # env_file: - # - .env.local - # ports: - # - 3000:3000 - # networks: - # aps-net: - # aliases: - # - apsportal.localtest.me + apsportal: + container_name: apsportal + image: apsportal:latest + depends_on: + - keycloak + build: + context: . + dockerfile: Dockerfile + env_file: + - .env.local + ports: + - 3000:3000 + networks: + aps-net: + aliases: + - apsportal.localtest.me feeder: container_name: feeder image: feeder:latest @@ -91,18 +91,18 @@ services: aps-net: aliases: - feeder.localtest.me - # feeder-seeding: - # container_name: feeder-seeding - # image: feeder:latest - # command: '' - # entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" - # restart: on-failure - # depends_on: - # - feeder - # volumes: - # - ./local/feeder-init:/tmp - # networks: - # - aps-net + feeder-seeding: + container_name: feeder-seeding + image: feeder:latest + command: '' + entrypoint: sh -c "chmod +x /tmp/init.sh && sh /tmp/init.sh" + restart: on-failure + depends_on: + - feeder + volumes: + - ./local/feeder-init:/tmp + networks: + - aps-net # cypress: # image: 'aps-cypress-e2e:latest' # container_name: cypress-e2e diff --git a/local/feeder-init/init.sh b/local/feeder-init/init.sh index a95616801..0a175bfce 100755 --- a/local/feeder-init/init.sh +++ b/local/feeder-init/init.sh @@ -4,7 +4,7 @@ apk add --no-cache curl cd /tmp while true; do - keycloakstatus=$(curl -o /dev/null -Isw '%{http_code}\n' http://oauth2proxy.localtest.me:4180) + keycloakstatus=$(curl -o /dev/null -Isw '%{http_code}\n' http://keycloak.localtest.me:9080/auth/realms/master) echo "$keycloakstatus" if [[ "$keycloakstatus" == "200" ]]; then echo "Keycloak is up" From 828062ec085394777d9cd4dd67149e4d14e2616d Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 29 Jul 2021 16:03:32 -0700 Subject: [PATCH 064/155] updated the function definition --- src/services/workflow/apply.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/services/workflow/apply.ts b/src/services/workflow/apply.ts index 09a03a5df..89884a039 100644 --- a/src/services/workflow/apply.ts +++ b/src/services/workflow/apply.ts @@ -330,7 +330,11 @@ async function setupAuthorizationAndEnable( if ('plugins' in controls) { for (const plugin of controls.plugins) { // assume the service and route IDs are Kong's unique IDs for them - await kongApi.addPluginToConsumer(kongConsumerPK, plugin); + await kongApi.addPluginToConsumer( + kongConsumerPK, + plugin, + context.req.user.namespace + ); } } From ea3371dc1c1f92ba092f07c9724d25cac815089f Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Thu, 29 Jul 2021 16:22:03 -0700 Subject: [PATCH 065/155] Fix appearance of signed in button --- src/nextapp/components/auth-action/auth-action.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/nextapp/components/auth-action/auth-action.tsx b/src/nextapp/components/auth-action/auth-action.tsx index 918f624c0..e7e9809ec 100644 --- a/src/nextapp/components/auth-action/auth-action.tsx +++ b/src/nextapp/components/auth-action/auth-action.tsx @@ -52,7 +52,12 @@ const Signin: React.FC = ({ site }) => { zIndex={2} > - + {user.name} From 15af1fc8dc27d41f9d741faa593d6d10d2ec664f Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sat, 31 Jul 2021 08:01:09 -0700 Subject: [PATCH 066/155] added product related tags for testing --- .../components/auth-action/auth-action.tsx | 1 + .../new-product/new-product-dialog.tsx | 36 +++++++++++++++---- .../components/new-product/new-product.tsx | 1 + .../components/products-list/edit-product.tsx | 1 + .../pages/manager/namespaces/index.tsx | 12 +++++-- 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/nextapp/components/auth-action/auth-action.tsx b/src/nextapp/components/auth-action/auth-action.tsx index e7e9809ec..bf66e21a3 100644 --- a/src/nextapp/components/auth-action/auth-action.tsx +++ b/src/nextapp/components/auth-action/auth-action.tsx @@ -57,6 +57,7 @@ const Signin: React.FC = ({ site }) => { alignItems="center" display="flex" variant="bc-blue-alt" + data-testid="auth-menu-user" > {user.name} diff --git a/src/nextapp/components/new-product/new-product-dialog.tsx b/src/nextapp/components/new-product/new-product-dialog.tsx index 8d5e404b4..ebbd00f42 100644 --- a/src/nextapp/components/new-product/new-product-dialog.tsx +++ b/src/nextapp/components/new-product/new-product-dialog.tsx @@ -96,25 +96,46 @@ const NewProductDialog: React.FC = ({ placeholder="Product Name" name="name" variant="bc-input" + data-testid="prd-name-input" /> Environment - + Development - + Test - + Sandbox - + Production - + Other @@ -127,11 +148,14 @@ const NewProductDialog: React.FC = ({ - + diff --git a/src/nextapp/components/new-product/new-product.tsx b/src/nextapp/components/new-product/new-product.tsx index 7f5c5f86d..8dc5f902f 100644 --- a/src/nextapp/components/new-product/new-product.tsx +++ b/src/nextapp/components/new-product/new-product.tsx @@ -13,6 +13,7 @@ const NewProduct: React.FC = () => { variant="primary" onClick={onOpen} leftIcon={} + data-testid="prds-new-btn" > New Product diff --git a/src/nextapp/components/products-list/edit-product.tsx b/src/nextapp/components/products-list/edit-product.tsx index d77b90d69..e794dc51b 100644 --- a/src/nextapp/components/products-list/edit-product.tsx +++ b/src/nextapp/components/products-list/edit-product.tsx @@ -94,6 +94,7 @@ const EditProduct: React.FC = ({ data }) => { variant="tertiary" leftIcon={} onClick={onOpen} + data-testid="prd-edit-btn" > Edit diff --git a/src/nextapp/pages/manager/namespaces/index.tsx b/src/nextapp/pages/manager/namespaces/index.tsx index ea5b91021..b539a4292 100644 --- a/src/nextapp/pages/manager/namespaces/index.tsx +++ b/src/nextapp/pages/manager/namespaces/index.tsx @@ -175,7 +175,10 @@ const NamespacesPage: React.FC = () => { - + {a.title} { - {a.title} + + {a.title} + From 05dcd619b28d85b9489ed686fce0f8abca71952a Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sat, 31 Jul 2021 22:26:15 -0700 Subject: [PATCH 067/155] Updated gwa url for plugin management --- .env.local | 2 +- src/services/kong/consumer-service.ts | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.env.local b/.env.local index fb9322868..f9a3b1495 100644 --- a/.env.local +++ b/.env.local @@ -12,7 +12,7 @@ KONG_URL=http://kong.localtest.me:8001 JWKS_URL=http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid-connect/certs FEEDER_URL=http://feeder.localtest.me:6000 NEXT_PUBLIC_API_ROOT=http://oauth2proxy.localtest.me:4180 -GWA_API_URL=http://localhost:2000 +GWA_API_URL=http://gwa-api.localtest.me:2000 GWA_PROD_ENV_SLUG=E0000000 GWA_RES_SVR_CLIENT_ID=gwa-api GWA_RES_SVR_CLIENT_SECRET=18900468-3db1-43f7-a8af-e75f079eb742 diff --git a/src/services/kong/consumer-service.ts b/src/services/kong/consumer-service.ts index 9ac2ad040..05e246723 100644 --- a/src/services/kong/consumer-service.ts +++ b/src/services/kong/consumer-service.ts @@ -39,6 +39,7 @@ const logger = Logger('kong'); export class KongConsumerService { private kongUrl: string; + private gwaUrl: string = process.env.GWA_API_URL; constructor(kongUrl: string) { this.kongUrl = kongUrl; @@ -143,14 +144,14 @@ export class KongConsumerService { plugin: KongPlugin, namespace: string ): Promise { - const body = {}; + const body = { ...plugin, tags: ['ns.' + namespace] }; logger.debug('[addPluginToConsumer] CALLING with ' + consumerPK); const response = await fetch( - `/gw/api/namespaces/${namespace}/consumers/${consumerPK}/plugins`, + `${this.gwaUrl}/v2/namespaces/${namespace}/consumers/${consumerPK}/plugins`, { method: 'post', - body: JSON.stringify(plugin), + body: JSON.stringify(body), headers: { 'Content-Type': 'application/json', }, @@ -172,12 +173,12 @@ export class KongConsumerService { namespace: string ): Promise { logger.debug('[updateConsumerPlugin] C=%s P=%s', consumerPK, pluginPK); - + const body = { ...plugin, tags: ['ns.' + namespace] }; const response = await fetch( - `/gw/api/namespaces/${namespace}/consumers/${consumerPK}/plugins/${pluginPK}`, + `${this.gwaUrl}/v2/namespaces/${namespace}/consumers/${consumerPK}/plugins/${pluginPK}`, { method: 'put', - body: JSON.stringify(plugin), + body: JSON.stringify(body), headers: { 'Content-Type': 'application/json', }, @@ -195,7 +196,7 @@ export class KongConsumerService { namespace: string ): Promise { await fetch( - `/gw/api/namespaces/${namespace}/consumers/${consumerPK}/plugins/${pluginPK}`, + `${this.gwaUrl}/v2/namespaces/${namespace}/consumers/${consumerPK}/plugins/${pluginPK}`, { method: 'delete', headers: { From 3971fc734326e2eaa944d3ffaf644e6f9f3cbbb9 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sat, 31 Jul 2021 22:53:11 -0700 Subject: [PATCH 068/155] added more tags to manage products in cypress tests --- .../components/environments-list/delete-environment.tsx | 1 + .../components/environments-list/environments-list.tsx | 6 +++++- src/nextapp/components/products-list/add-environment.tsx | 9 +++++++-- src/nextapp/components/products-list/delete-product.tsx | 6 +++++- src/nextapp/components/products-list/edit-product.tsx | 4 +++- .../components/products-list/organization-select.tsx | 1 + 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/nextapp/components/environments-list/delete-environment.tsx b/src/nextapp/components/environments-list/delete-environment.tsx index 89132572a..734eaaa99 100644 --- a/src/nextapp/components/environments-list/delete-environment.tsx +++ b/src/nextapp/components/environments-list/delete-environment.tsx @@ -53,6 +53,7 @@ const DeleteEnvironment: React.FC = ({ id }) => { size="xs" variant="outline" onClick={onConfirm} + data-testid="prd-env-delete-btn" > diff --git a/src/nextapp/components/environments-list/environments-list.tsx b/src/nextapp/components/environments-list/environments-list.tsx index 9460a04ee..71fca0141 100644 --- a/src/nextapp/components/environments-list/environments-list.tsx +++ b/src/nextapp/components/environments-list/environments-list.tsx @@ -119,7 +119,11 @@ const EnvironmentsList: React.FC = ({ data }) => { - diff --git a/src/nextapp/components/products-list/add-environment.tsx b/src/nextapp/components/products-list/add-environment.tsx index 4e20c9f30..97e7d19c9 100644 --- a/src/nextapp/components/products-list/add-environment.tsx +++ b/src/nextapp/components/products-list/add-environment.tsx @@ -55,14 +55,19 @@ const AddEnvironment: React.FC = ({ return ( - + {children} {options .filter((e) => !environments.includes(e.value)) .map((e) => ( - + {e.name} ))} diff --git a/src/nextapp/components/products-list/delete-product.tsx b/src/nextapp/components/products-list/delete-product.tsx index ca9147571..f8d94b083 100644 --- a/src/nextapp/components/products-list/delete-product.tsx +++ b/src/nextapp/components/products-list/delete-product.tsx @@ -48,7 +48,11 @@ const DeleteProduct: React.FC = ({ id, onDeleted }) => { return ( <> - = ({ data }) => { name="name" defaultValue={data.name} variant="bc-input" + data-testid="prd-edit-name-input" /> Must be unique @@ -124,7 +125,7 @@ const EditProduct: React.FC = ({ data }) => { - diff --git a/src/nextapp/components/products-list/organization-select.tsx b/src/nextapp/components/products-list/organization-select.tsx index 083531a3d..1a99bb4e1 100644 --- a/src/nextapp/components/products-list/organization-select.tsx +++ b/src/nextapp/components/products-list/organization-select.tsx @@ -68,6 +68,7 @@ const OrganizationSelect: React.FC = ({ data }) => { name="organization" variant="bc-input" value={organization} + data-testid="prd-edit-org-dd" > {organizationsQuery.data?.allOrganizations.map((org) => ( From 4003b606d9fd9117d9a51d9e8dfbf9ee54ce6929 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sun, 1 Aug 2021 18:56:12 -0700 Subject: [PATCH 069/155] added test ids for new service account creds --- src/nextapp/components/view-secret/view-secret.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/nextapp/components/view-secret/view-secret.tsx b/src/nextapp/components/view-secret/view-secret.tsx index 8b244f343..cc8d6d48b 100644 --- a/src/nextapp/components/view-secret/view-secret.tsx +++ b/src/nextapp/components/view-secret/view-secret.tsx @@ -60,7 +60,12 @@ const ViewSecret: React.FC = ({ credentials }) => { {c.label} - + {credentials[c.name]} Date: Mon, 2 Aug 2021 20:10:09 -0700 Subject: [PATCH 070/155] Added new tests and functions for publishing API --- e2e/cypress.json | 3 +- .../fixtures/{service.yaml => service.yml} | 0 e2e/cypress/fixtures/state/store.json | 4 +- e2e/cypress/pageObjects/home.ts | 39 +++-- e2e/cypress/pageObjects/login.ts | 8 +- e2e/cypress/pageObjects/serviceAccounts.ts | 38 ++--- e2e/cypress/support/auth-commands.ts | 95 +++++++++-- e2e/cypress/support/global.d.ts | 7 + e2e/cypress/tests/01-create-api.spec.ts | 15 +- e2e/package-lock.json | 153 ++++++++++-------- e2e/package.json | 2 + e2e/tsconfig.json | 5 +- 12 files changed, 247 insertions(+), 122 deletions(-) rename e2e/cypress/fixtures/{service.yaml => service.yml} (100%) diff --git a/e2e/cypress.json b/e2e/cypress.json index 287245166..6da21279d 100644 --- a/e2e/cypress.json +++ b/e2e/cypress.json @@ -17,6 +17,7 @@ "CLIENT_ID": "aps-portal", "CLIENT_SECRET": "8e1a17ed-cb93-4806-ac32-e303d1c86018", "OIDC_ISSUER": "http://keycloak.localtest.me:9080", - "TOKEN_URL": "http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid-connect/token" + "TOKEN_URL": "http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid-connect/token", + "GWA_API_URL": "http://gwa-api.localtest.me:2000/v2" } } diff --git a/e2e/cypress/fixtures/service.yaml b/e2e/cypress/fixtures/service.yml similarity index 100% rename from e2e/cypress/fixtures/service.yaml rename to e2e/cypress/fixtures/service.yml diff --git a/e2e/cypress/fixtures/state/store.json b/e2e/cypress/fixtures/state/store.json index 0967ef424..94b7c2ac5 100644 --- a/e2e/cypress/fixtures/state/store.json +++ b/e2e/cypress/fixtures/state/store.json @@ -1 +1,3 @@ -{} +{ + "credentials": "{\"clientId\": \"sa-platform-e0000000-139ce1fa615a\", \"clientSecret\": \"5ef6c992-af9a-46e6-a2be-10cc957e1ab3\"}" +} \ No newline at end of file diff --git a/e2e/cypress/pageObjects/home.ts b/e2e/cypress/pageObjects/home.ts index d1fdc6daf..739f45fad 100644 --- a/e2e/cypress/pageObjects/home.ts +++ b/e2e/cypress/pageObjects/home.ts @@ -1,24 +1,33 @@ class HomePage { - namespaceDropdown: string = '/html/body/div[1]/header/hgroup[2]/div[1]/div/button' - profileIcon: string = - '/html/body/div[1]/header/hgroup[2]/div[1]/div/span/button/span/svg[1]' - - namespaceNameInput: string = '/html/body/div[3]/div[4]/div/section/div/form/div/input' + nsDropdown: string = '[data-testid=ns-dropdown-btn]' + nsDropdownCreateNsBtn: string = '[data-testid=ns-dropdown-create-btn]' + nsDropdownManageNsBtn: string = '[data-testid=ns-dropdown-manage-btn]' + namespaceNameInput: string = '[data-testid=ns-modal-name-input]' + nsCreateBtn: string = '[data-testid=ns-modal-create-btn]' + nsSelectNamespace: string = '[data-testid=ns-dropdown-item-]' createNamespace(name: string): void { - cy.xpath(this.namespaceDropdown).click() - cy.contains('Create New Namespace').click() - cy.xpath(this.namespaceNameInput).type(name) // using `platform` as a default ns as its being seeding through feeder - cy.xpath("//button[normalize-space()='Create']").click() + cy.get(this.nsDropdown).click() + cy.get(this.nsDropdownCreateNsBtn).click() + cy.get(this.namespaceNameInput).type(name) // using `platform` as a default ns as its being seeding through feeder + cy.get(this.nsCreateBtn).click() + cy.wait(2000) // wait for dropdown to have latest text + cy.get(this.nsDropdown).then(($el) => { + expect($el).contain(name) + }) } useNamespace(name: string): void { - cy.xpath(this.namespaceDropdown).click() - cy.contains(name) - .click() - .then(() => { - cy.xpath(this.namespaceDropdown).should('include.text', name) - }) + cy.get(this.nsDropdown).click() + cy.get(this.getNamespaceTestId(name)).click() + cy.wait(2000) // wait for dropdown to have latest text + cy.get(this.nsDropdown).then(($el) => { + expect($el.text().trim()).to.eq(name) + }) + } + + getNamespaceTestId(name: string): string { + return '[data-testid=ns-dropdown-item-' + name + ']' } } diff --git a/e2e/cypress/pageObjects/login.ts b/e2e/cypress/pageObjects/login.ts index e2bc3477e..2513dafe8 100644 --- a/e2e/cypress/pageObjects/login.ts +++ b/e2e/cypress/pageObjects/login.ts @@ -1,10 +1,10 @@ class LoginPage { path: string = '/' - loginButton: string = "//button[normalize-space()='Login']" - usernameInput: string = "//input[@id='username']" - passwordInput: string = "//input[@id='password']" - loginSubmitButton: string = "//input[@id='kc-login']" + loginButton: string = '[data-testid=login-btn]' + usernameInput: string = '[id=username]' + passwordInput: string = '[id=password]' + loginSubmitButton: string = '[id=kc-login]' } export default LoginPage diff --git a/e2e/cypress/pageObjects/serviceAccounts.ts b/e2e/cypress/pageObjects/serviceAccounts.ts index 176547b50..9d3ed8711 100644 --- a/e2e/cypress/pageObjects/serviceAccounts.ts +++ b/e2e/cypress/pageObjects/serviceAccounts.ts @@ -1,35 +1,37 @@ class ServiceAccountsPage { - path: string = '/manager/namespaces' - shareButton: string = "//button[normalize-space()='Share']" - - clientId: string = - '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[1]/div[1]/code' - - clientSecret: string = - '/html[1]/body[1]/div[1]/main[1]/div[1]/div[2]/div[3]/div[2]/div[1]/code' + path: string = '/manager/service-accounts' + shareBtn: string = '[data-testid=sa-scopes-share-btn]' + newServiceAccountBtn: string = '[data-testid=sa-create-second-btn]' + clientId: string = '[data-testid=sa-new-creds-client-id]' + clientSecret: string = '[data-testid=sa-new-creds-client-secret]' + tokenEndpoint: string = '[data-testid=sa-new-creds-token-endpoint]' createServiceAccount(scopes: string[]): void { - cy.contains('New Service Account').click() - scopes.forEach((scope) => { - cy.contains(scope).click() - }) - cy.xpath(this.shareButton).click() + cy.get(this.newServiceAccountBtn).first().click() + this.selectPermissions(scopes) + cy.get(this.shareBtn).click() } saveServiceAcctCreds(): void { - cy.xpath(this.clientId).then(($clientId) => { - cy.xpath(this.clientSecret).then(($clientSecret) => { + cy.get(this.clientId).then(($clientId) => { + cy.get(this.clientSecret).then(($clientSecret) => { cy.saveState( 'credentials', - "{'clientId': '" + + '{"clientId": "' + $clientId.text() + - "', 'clientSecret': '" + + '", "clientSecret": "' + $clientSecret.text() + - "'}" + '"}' ) }) }) } + + selectPermissions(scopes: string[]): void { + scopes.forEach((scope) => { + cy.contains(scope).click() + }) + } } export default ServiceAccountsPage diff --git a/e2e/cypress/support/auth-commands.ts b/e2e/cypress/support/auth-commands.ts index f09fbbf2c..1281567d6 100644 --- a/e2e/cypress/support/auth-commands.ts +++ b/e2e/cypress/support/auth-commands.ts @@ -1,12 +1,20 @@ import * as jwt from 'jsonwebtoken' import HomePage from '../pageObjects/home' import LoginPage from '../pageObjects/login' +import request = require('request') +import { method } from 'cypress/types/bluebird' +import { url } from 'inspector' + +interface formDataRequestOptions { + method: string + url: string +} Cypress.Commands.add('login', (username: string, password: string) => { cy.log('< Log in with user ' + username) const login = new LoginPage() - const appURL = new URL(Cypress.config('baseUrl')!) - cy.xpath(login.loginButton).should('be.visible').click() + const home = new HomePage() + cy.get(login.loginButton).click() const log = Cypress.log({ name: 'Login to Dev', @@ -14,15 +22,17 @@ Cypress.Commands.add('login', (username: string, password: string) => { message: [`🔐 Authenticating | ${username}`], autoEnd: false, }) + cy.wait(1500) // wait added to evade login timeout + cy.get(login.usernameInput).type(username) + cy.get(login.passwordInput).type(password) + cy.get(login.loginSubmitButton).click() - cy.xpath(login.usernameInput).type(username) - cy.xpath(login.passwordInput).type(password) - cy.xpath(login.loginSubmitButton).click() - cy.wait(1000) - - log.snapshot('Post Login') log.end() - cy.xpath(login.loginButton).should('not.exist') + cy.get(home.nsDropdown, { timeout: 6000 }).then(($el) => { + expect($el).to.exist + expect($el).to.be.visible + expect($el).contain('No Active Namespace') + }) cy.log('> Log in') }) @@ -84,6 +94,71 @@ Cypress.Commands.add('logout', () => { cy.clearCookies() }) }) - cy.wait(2000) cy.log('> Logging out') }) + +Cypress.Commands.add('getAccessToken', (client_id: string, client_secret: string) => { + cy.log('< Get Token') + cy.request({ + method: 'POST', + url: Cypress.env('TOKEN_URL'), + body: { + grant_type: 'client_credentials', + scope: 'openid', + client_id, + client_secret, + }, + form: true, + }).then((res) => { + cy.wrap(res).as('accessTokenResponse') + expect(res.status).to.eq(200) + }) + cy.log('> Get Token') +}) + +Cypress.Commands.add('publishApi', (fileName: string) => { + cy.log('< Publish API') + const requestName: string = 'publishAPI' + cy.fixture('state/store').then((creds: any) => { + const serviceAcctCreds = JSON.parse(creds.credentials) + cy.getAccessToken(serviceAcctCreds.clientId, serviceAcctCreds.clientSecret).then( + () => { + cy.get('@accessTokenResponse').then((res: any) => { + const options = { + method: 'PUT', + url: Cypress.env('GWA_API_URL') + '/namespaces/platform/gateway', + } + formDataRequest(options, res.body.access_token, fileName, requestName) + cy.wait(`@${requestName}`).then((res: any) => { + cy.wrap(res.response).as('publishAPIResponse') + }) + }) + } + ) + }) +}) + +const formDataRequest = ( + options: formDataRequestOptions, + accessToken: string, + fileName: string, + requestName: string +) => { + const data = new FormData() + data.append('hasHeader', 'true') + cy.intercept(options.method, options.url) + .as(requestName) + .window() + .then((win) => { + cy.fixture(fileName, 'binary') + .then((bin) => Cypress.Blob.binaryStringToBlob(bin)) + .then((blob) => { + const xhr = new win.XMLHttpRequest() + data.set('configFile', blob, fileName) + data.set('dryRun', 'true') + xhr.open(options.method, options.url) + xhr.setRequestHeader('Authorization', `Bearer ${accessToken}`) + xhr.send(data) + }) + }) +} diff --git a/e2e/cypress/support/global.d.ts b/e2e/cypress/support/global.d.ts index b2e80bec3..170fe191d 100644 --- a/e2e/cypress/support/global.d.ts +++ b/e2e/cypress/support/global.d.ts @@ -20,5 +20,12 @@ declare namespace Cypress { getState(key: string): string resetState(): void + + getAccessToken( + client_id: string, + client_secret: string + ): Chainable> + + publishApi(content: any): Chainable> } } diff --git a/e2e/cypress/tests/01-create-api.spec.ts b/e2e/cypress/tests/01-create-api.spec.ts index 7acfb22b8..04f354cf8 100644 --- a/e2e/cypress/tests/01-create-api.spec.ts +++ b/e2e/cypress/tests/01-create-api.spec.ts @@ -10,6 +10,7 @@ describe('Create API Spec', () => { const sa = new ServiceAccountsPage() beforeEach(() => { + cy.preserveCookies() cy.fixture('apiowner').as('apiowner') cy.visit(login.path) }) @@ -23,20 +24,22 @@ describe('Create API Spec', () => { it('creates and activates new namespace', () => { cy.get('@apiowner').then(({ namespace }: any) => { home.createNamespace(namespace) - home.useNamespace(namespace) }) }) it('creates a new service account', () => { - cy.xpath(tb.namespaces).click() - cy.contains('Service Accounts').click({ force: true }) + cy.visit(sa.path) cy.get('@apiowner').then(({ serviceAccount }: any) => { - cy.log(serviceAccount.scopes) sa.createServiceAccount(serviceAccount.scopes) }) sa.saveServiceAcctCreds() }) - afterEach(() => { - cy.preserveCookies() + + it('publishes a new API to Kong Gateway', () => { + cy.publishApi('service.yml').then(() => { + cy.get('@publishAPIResponse').then((res: any) => { + cy.log(JSON.stringify(res.body)) + }) + }) }) after(() => { cy.logout() diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 8846a008b..1d5b9abbf 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -991,6 +991,12 @@ "fastq": "^1.6.0" } }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, "@types/json-schema": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", @@ -1027,6 +1033,31 @@ "integrity": "sha512-TmCW5HoZ2o2/z2EYi109jLqIaPIi9y/lc2LmDCWzuCi35bcaQ+OtUh6nwBiFK7SOu25FAU5+YKdqFZUwtqGSdg==", "dev": true }, + "@types/request": { + "version": "2.48.7", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.7.tgz", + "integrity": "sha512-GWP9AZW7foLd4YQxyFZDBepl0lPsWLMEXDZUjQ/c1gqVPDPECrRZyEzuhJdnPWioFCq3Tv0qoGpMD6U+ygd4ZA==", + "dev": true, + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + }, + "dependencies": { + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + } + } + }, "@types/sinonjs__fake-timers": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.3.tgz", @@ -1039,6 +1070,12 @@ "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", "dev": true }, + "@types/tough-cookie": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", + "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==", + "dev": true + }, "@types/yauzl": { "version": "2.9.2", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", @@ -1195,7 +1232,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1338,7 +1374,6 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, "requires": { "safer-buffer": "~2.1.0" } @@ -1388,8 +1423,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "assign-symbols": { "version": "1.0.0", @@ -1416,8 +1450,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "at-least-node": { "version": "1.0.0", @@ -1432,14 +1465,12 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "babel-plugin-add-module-exports": { "version": "1.0.2", @@ -1538,7 +1569,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, "requires": { "tweetnacl": "^0.14.3" } @@ -1888,8 +1918,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { "version": "4.1.1", @@ -2112,7 +2141,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -2378,7 +2406,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -2472,8 +2499,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "deps-sort": { "version": "2.0.1", @@ -2566,7 +2592,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -3066,8 +3091,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -3162,14 +3186,12 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-diff": { "version": "1.2.0", @@ -3240,8 +3262,7 @@ "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fast-safe-stringify": { "version": "2.0.7", @@ -3385,14 +3406,12 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -3510,7 +3529,6 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -3582,14 +3600,12 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -3721,7 +3737,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -4058,8 +4073,7 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-lib-coverage": { "version": "3.0.0", @@ -4201,8 +4215,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsesc": { "version": "2.5.2", @@ -4217,14 +4230,12 @@ "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify": { "version": "0.0.1", @@ -4294,7 +4305,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -4671,14 +4681,12 @@ "mime-db": { "version": "1.48.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", - "dev": true + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" }, "mime-types": { "version": "2.1.31", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", - "dev": true, "requires": { "mime-db": "1.48.0" } @@ -5167,8 +5175,7 @@ "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", @@ -5431,8 +5438,7 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picomatch": { "version": "2.3.0", @@ -5575,8 +5581,7 @@ "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, "public-encrypt": { "version": "4.0.3", @@ -5615,8 +5620,7 @@ "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "querystring": { "version": "0.2.0", @@ -5886,6 +5890,33 @@ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, "request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", @@ -6313,7 +6344,6 @@ "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -6584,7 +6614,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, "requires": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -6593,8 +6622,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" } } }, @@ -6641,7 +6669,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -6649,8 +6676,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-fest": { "version": "0.8.1", @@ -6794,7 +6820,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "requires": { "punycode": "^2.1.0" }, @@ -6802,8 +6827,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" } } }, @@ -6876,7 +6900,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", diff --git a/e2e/package.json b/e2e/package.json index adc4315b3..94d38493f 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -17,6 +17,7 @@ "@types/mocha": "^8.2.3", "@types/mochawesome": "^6.2.0", "@types/node": "^16.0.0", + "@types/request": "^2.48.7", "@typescript-eslint/eslint-plugin": "^4.28.1", "@typescript-eslint/parser": "^4.28.1", "cypress": "^7.6.0", @@ -37,6 +38,7 @@ "mochawesome": "^6.2.2", "mochawesome-merge": "^4.2.0", "npm-run-all": "^4.1.5", + "request": "^2.88.2", "typescript": "^4.3.5", "yamljs": "^0.3.0" } diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json index 6bad8a76a..b1bbfc6dc 100644 --- a/e2e/tsconfig.json +++ b/e2e/tsconfig.json @@ -1,11 +1,12 @@ { "compilerOptions": { "target": "es5", - "lib": ["es5", "dom", "ES2015"], + "lib": ["es5", "dom", "ES2015", "ES6"], "types": ["cypress", "node", "mocha", "cypress-xpath"], "allowJs": true, "noImplicitAny": true, - "strict": true + "strict": true, + "module": "commonjs" }, "include": ["./cypress/**/*.ts", "**/*.d.ts"], "exclude": [], From 0f69fef2a4bd6de64aaf31a718a685ec440c354c Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Mon, 2 Aug 2021 21:55:44 -0700 Subject: [PATCH 071/155] updated data test ids of generated creds --- .../service-account-create/service-account-create.tsx | 6 +----- src/nextapp/components/view-secret/view-secret.tsx | 4 +++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/nextapp/components/service-account-create/service-account-create.tsx b/src/nextapp/components/service-account-create/service-account-create.tsx index 123421546..72bd362c1 100644 --- a/src/nextapp/components/service-account-create/service-account-create.tsx +++ b/src/nextapp/components/service-account-create/service-account-create.tsx @@ -104,11 +104,7 @@ const ServiceAccountCreate: React.FC = ({ {isSuccess && data?.currentNamespace.scopes.map((s) => ( - + {s.name} diff --git a/src/nextapp/components/view-secret/view-secret.tsx b/src/nextapp/components/view-secret/view-secret.tsx index cc8d6d48b..cc3e8bc6d 100644 --- a/src/nextapp/components/view-secret/view-secret.tsx +++ b/src/nextapp/components/view-secret/view-secret.tsx @@ -64,7 +64,9 @@ const ViewSecret: React.FC = ({ credentials }) => { as="code" wordBreak="break-all" noOfLines={1} - data-testid={'sa-new-creds' + c.label} + data-testid={ + 'sa-new-creds-' + c.label.toLowerCase().replace(' ', '-') + } > {credentials[c.name]} From d0313765cd10fe1686b090d502733ea22089d2ba Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 3 Aug 2021 09:01:53 -0700 Subject: [PATCH 072/155] enabled github action to run cypress and added a step to build gwa-api --- .github/workflows/aps-cypress-e2e.yaml | 50 ++++++++++++++------------ docker-compose.yml | 26 +++++++------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index e36c4fc7a..06486641e 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -3,31 +3,35 @@ name: Build and Deploy Cypress and Execute Tests on: push: branches: - - 'util/automation-not*' + - 'util/automation-*' jobs: cypress-run: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: Spin up API Services Portal and Run E2E Tests - run: docker-compose up -d - - name: Stop the Containers - run: | - while true; do - if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then - # cleanup - docker-compose stop - sleep 1m - docker-compose down - break - else - echo "Waiting for Cypress to Complete E2E Tests....." - sleep 1m - fi - done - - name: Upload E2E Test Report as Artifact - uses: actions/upload-artifact@v2 - with: - name: report - path: ${{ github.workspace }}/e2e/results/report + - name: Build GWA API Image + - run: | + git clone https://github.com/bcgov/gwa-api.git + cd gwa-api/microservices/gatewayApi + docker build -t gateway-api:test . + + # - uses: actions/checkout@v1 + # - name: Spin up API Services Portal and Run E2E Tests + # run: docker-compose up -d + # - name: Stop the Containers + # run: | + # while true; do + # if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then + # # cleanup + # docker-compose down + # break + # else + # echo "Waiting for Cypress to Complete E2E Tests....." + # sleep 1m + # fi + # done + # - name: Upload E2E Test Report as Artifact + # uses: actions/upload-artifact@v2 + # with: + # name: report + # path: ${{ github.workspace }}/e2e/results/report diff --git a/docker-compose.yml b/docker-compose.yml index 4ff66e5b8..3a951da7a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -103,19 +103,19 @@ services: - ./local/feeder-init:/tmp networks: - aps-net - # cypress: - # image: 'aps-cypress-e2e:latest' - # container_name: cypress-e2e - # entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" - # depends_on: - # - feeder-seeding - # build: - # context: ./e2e - # dockerfile: Dockerfile - # volumes: - # - ./e2e/results/report:/e2e/results/report - # networks: - # - aps-net + cypress: + image: 'aps-cypress-e2e:latest' + container_name: cypress-e2e + entrypoint: sh -c "chmod +x /tmp/entrypoint.sh && /tmp/entrypoint.sh" + depends_on: + - feeder-seeding + build: + context: ./e2e + dockerfile: Dockerfile + volumes: + - ./e2e/results/report:/e2e/results/report + networks: + - aps-net kong-db: image: postgres:latest container_name: kong-db From e70f5b1d51e5296568cad674c8feb87acc717b5d Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 3 Aug 2021 09:03:20 -0700 Subject: [PATCH 073/155] fixed syntax --- .github/workflows/aps-cypress-e2e.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 06486641e..eb7671bed 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Build GWA API Image - - run: | + run: | git clone https://github.com/bcgov/gwa-api.git cd gwa-api/microservices/gatewayApi docker build -t gateway-api:test . From 66ea9282f425afcbe32fb059afb01592e2f1f410 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 3 Aug 2021 09:11:43 -0700 Subject: [PATCH 074/155] running the cypress e2e test in github actions --- .github/workflows/aps-cypress-e2e.yaml | 45 +++++++++++++------------- docker-compose.yml | 2 +- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index eb7671bed..6ba9e8629 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -11,27 +11,26 @@ jobs: steps: - name: Build GWA API Image run: | - git clone https://github.com/bcgov/gwa-api.git + git clone https://github.com/bcgov/gwa-api.git -b feature/add-consumer-service cd gwa-api/microservices/gatewayApi - docker build -t gateway-api:test . - - # - uses: actions/checkout@v1 - # - name: Spin up API Services Portal and Run E2E Tests - # run: docker-compose up -d - # - name: Stop the Containers - # run: | - # while true; do - # if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then - # # cleanup - # docker-compose down - # break - # else - # echo "Waiting for Cypress to Complete E2E Tests....." - # sleep 1m - # fi - # done - # - name: Upload E2E Test Report as Artifact - # uses: actions/upload-artifact@v2 - # with: - # name: report - # path: ${{ github.workspace }}/e2e/results/report + docker build -t gateway-api:e2e-testing . + - uses: actions/checkout@v1 + - name: Spin up API Services Portal and Run E2E Tests + run: docker-compose up -d + - name: Stop the Containers + run: | + while true; do + if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then + # cleanup + docker-compose down + break + else + echo "Waiting for Cypress to Complete E2E Tests....." + sleep 1m + fi + done + - name: Upload E2E Test Report as Artifact + uses: actions/upload-artifact@v2 + with: + name: report + path: ${{ github.workspace }}/e2e/results/report diff --git a/docker-compose.yml b/docker-compose.yml index 3a951da7a..f01aad6c3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -185,7 +185,7 @@ services: aliases: - redis.localtest.me gwa-gateway-api: - image: ghcr.io/bcgov/gwa-api/gwa-gateway-api:feature-add-consumer-service + image: gateway-api:e2e-testing container_name: gwa-gateway-api entrypoint: sh -c "chmod +x /tmp/gwa/entrypoint.sh && sh /tmp/gwa/entrypoint.sh" ports: From 0f45528a34e1dd9553d82545e2c62b951dd7f6f4 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Tue, 3 Aug 2021 09:29:23 -0700 Subject: [PATCH 075/155] update gwa api url --- .env.local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.local b/.env.local index fb9322868..f9a3b1495 100644 --- a/.env.local +++ b/.env.local @@ -12,7 +12,7 @@ KONG_URL=http://kong.localtest.me:8001 JWKS_URL=http://keycloak.localtest.me:9080/auth/realms/master/protocol/openid-connect/certs FEEDER_URL=http://feeder.localtest.me:6000 NEXT_PUBLIC_API_ROOT=http://oauth2proxy.localtest.me:4180 -GWA_API_URL=http://localhost:2000 +GWA_API_URL=http://gwa-api.localtest.me:2000 GWA_PROD_ENV_SLUG=E0000000 GWA_RES_SVR_CLIENT_ID=gwa-api GWA_RES_SVR_CLIENT_SECRET=18900468-3db1-43f7-a8af-e75f079eb742 From 5275ca32bd70fcc681fb62029cef5f69b93a852f Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Tue, 3 Aug 2021 22:34:00 -0700 Subject: [PATCH 076/155] add new GatewayServices queries --- src/authz/whitelist.json | 1706 +++++++++++++++++++------------------- 1 file changed, 858 insertions(+), 848 deletions(-) diff --git a/src/authz/whitelist.json b/src/authz/whitelist.json index b6e3b6d56..e0810b9c4 100644 --- a/src/authz/whitelist.json +++ b/src/authz/whitelist.json @@ -812,851 +812,861 @@ "query": "\n mutation updateGatewayConsumerPlugin(\n $id: ID!\n $pluginExtForeignKey: String!\n $controls: String!\n ) {\n updateGatewayConsumerPlugin(\n id: $id\n pluginExtForeignKey: $pluginExtForeignKey\n plugin: $controls\n ) {\n id\n }\n }\n", "added": "2021-07-03T03:23:01.128Z" }, - "21052b1e50cbb20c2edf94571d41481a": { - "query": "query IntrospectionQuery {\n __schema {\n queryType {\n name\n }\n mutationType {\n name\n }\n subscriptionType {\n name\n }\n types {\n ...FullType\n }\n directives {\n name\n description\n locations\n args {\n ...InputValue\n }\n }\n }\n}\n\nfragment FullType on __Type {\n kind\n name\n description\n fields(includeDeprecated: true) {\n name\n description\n args {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n description\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n}\n\nfragment InputValue on __InputValue {\n name\n description\n type {\n ...TypeRef\n }\n defaultValue\n}\n\nfragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}\n" - }, - "cb82824c55ad2de70494934fcd039a48": { - "operation": null, - "query": "{\n allDiscoverableProducts(where: {environments_some: {active: true}}) {\n name\n environments(where: {active: true}) {\n name\n }\n organization {\n name\n title\n }\n }\n myApplications {\n id\n name\n }\n}\n" - }, - "70e5b9605d48517c6789b61e29896e51": { - "query": "\n query GetProducts {\n allDiscoverableProducts {\n id\n name\n environments {\n name\n active\n flow\n \n }\n dataset {\n name\n title\n notes\n sector\n license_title\n view_audience\n security_class\n record_publish_date\n tags\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n" - }, - "34ee04d6606f3146f6ae3efbde3fa8a3": { - "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n }\n" - }, - "869946a26aaff1ff57516f887d259257": { - "query": "\n mutation Add($name: String!, $description: String) {\n createApplication(\n data: {\n name: $name\n description: $description\n }\n ) {\n id\n }\n }\n" - }, - "7fc130b9b34f65c83baa8f8479b304aa": { - "query": "\n mutation Remove($id: ID!) {\n deleteApplication(id: $id) {\n name\n id\n }\n }\n" - }, - "24542e8cf6c82e22dfe190586953c155": { - "query": "\n {\n allDiscoverableContents(where: { isComplete: true }) {\n id\n title\n slug\n description\n }\n }\n " - }, - "5dd78f79f254b02170a335e91e364e4c": { - "query": "\n query Get($id: ID!) {\n allDiscoverableProducts(where: { id: $id }) {\n id\n name\n environments {\n id\n name\n active\n flow\n legal {\n title\n description\n link\n }\n }\n }\n myApplications {\n id\n name\n }\n allTemporaryIdentities {\n id\n userId\n name\n username\n email\n }\n }\n" - }, - "98cbb3dbd8f72cd1d327821fb7b8f5dc": { - "query": "\n mutation AddAccessRequest(\n $name: String!\n $controls: String\n $requestor: ID!\n $applicationId: ID!\n $productEnvironmentId: ID!\n ) {\n createAccessRequest(\n data: {\n name: $name\n controls: $controls\n requestor: { connect: { id: $requestor } }\n application: { connect: { id: $applicationId } }\n productEnvironment: { connect: { id: $productEnvironmentId } }\n }\n ) {\n id\n }\n }\n" - }, - "7810501cf245180d98808ec179840788": { - "query": "\n mutation GenCredential($id: ID!) {\n updateAccessRequest(id: $id, data: { credential: \"NEW\" }) {\n credential\n }\n }\n" - }, - "164cbfac4188793d3974ee08150f2ba9": { - "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n myServiceAccesses(where: { }) {\n id\n name\n active\n application {\n appId\n }\n productEnvironment {\n name\n flow\n credentialIssuer {\n instruction\n }\n product {\n name\n }\n services {\n name\n routes {\n name\n hosts\n methods\n paths\n }\n }\n }\n } \n allAccessRequests(where: { isComplete: null }) {\n id\n name\n isIssued\n application {\n appId\n }\n productEnvironment {\n name\n flow\n credentialIssuer {\n instruction\n }\n product {\n name\n }\n services {\n name\n routes {\n name\n hosts\n methods\n paths\n }\n }\n }\n } \n }\n" - }, - "7e84ad633cdd38bfc769043aa1fb9515": { - "query": "\n query GetEnvironmentsByProduct($id: ID!) {\n Product(where: { id: $id }) {\n name\n environments {\n name\n credentialIssuer {\n id\n resourceType\n }\n }\n }\n }\n" - }, - "0b9b0fc556d52772e77193b6878a6012": { - "query": "\n query GetCredentialIssuers {\n allCredentialIssuers(orderBy: \"name_ASC\") {\n id\n name\n flow\n mode\n owner {\n name\n username\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n" - }, - "7282c6a41c25452fc04ba0a3ca4d7205": { - "query": "\n query GetCredentialIssuer($id: ID!) {\n allCredentialIssuers(where: { id: $id }) {\n id\n name\n flow\n mode\n clientId\n clientRegistration\n oidcDiscoveryUrl\n apiKeyName\n clientRoles\n availableScopes\n resourceType\n owner {\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n" - }, - "7649571474cb2bd3ff1f4361c68d184a": { - "query": "\n mutation CreateAuthzProfile($data: CredentialIssuerCreateInput!) {\n createCredentialIssuer (data: $data) {\n id\n }\n }\n" - }, - "f3c0324ebffe1c696c114ad3ebeb93ee": { - "query": "\n mutation UpdateAuthorization($id: ID!, $clientRoles: String!, $availableScopes: String!, $resourceType: String!) {\n updateCredentialIssuer (id: $id, data: { clientRoles: $clientRoles, availableScopes: $availableScopes, resourceType: $resourceType }) {\n id\n }\n }\n" - }, - "8aae948f7df8007aa9c504b139c00441": { - "query": "\n mutation CreateAuthzProfile($id: ID!) {\n deleteCredentialIssuer (id: $id) {\n id\n }\n }\n" - }, - "9136c4059c9a7a394a0698fe2b4f7690": { - "query": "\n query GetServices {\n allGatewayServices(first: 200) {\n id\n name\n updatedAt\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n routes {\n id\n name\n }\n plugins {\n id\n name\n }\n }\n }\n" - }, - "f190c0aa0b258974dc57e01ad51fc441": { - "query": "\n query GetMetrics($service: String!, $days: [String!]) {\n allMetrics(\n sortBy: day_ASC\n where: {\n query: \"kong_http_requests_hourly_service\"\n day_in: $days\n service: { name_contains: $service }\n }\n ) {\n query\n day\n metric\n values\n service {\n name\n }\n }\n }\n" - }, - "ff1e589711145245d9494f5ae28e8e39": { - "query": "\n query GET($id: ID!) {\n GatewayService(where: { id: $id }) {\n id\n name\n namespace\n tags\n host\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n plugins {\n id\n name\n }\n routes {\n id\n name\n namespace\n }\n updatedAt\n }\n }\n" - }, - "5df41c6ebcd0b801e7768ea3c1252a2e": { - "query": "\n query GET($namespace: String!) {\n allProducts(where: { namespace: $namespace }) {\n id\n name\n description\n organization {\n title\n }\n organizationUnit {\n title\n }\n dataset {\n title\n notes\n sector\n license_title\n }\n environments {\n id\n name\n active\n flow\n services {\n id\n name\n host\n }\n credentialIssuer {\n name\n }\n }\n }\n }\n" - }, - "c9e0e6923870f82ef5f974206adca3c3": { - "query": "\n mutation Add($name: String!) {\n createProduct(data: { name: $name }) {\n id\n name\n }\n }\n" - }, - "d43e71e35248d38a4127741c269bc1b3": { - "query": "\n mutation Add($name: String!, $product: ID!) {\n createEnvironment(\n data: { name: $name, product: { connect: { id: $product } } }\n ) {\n id\n name\n }\n }\n" - }, - "45c0fc9cce5fc64e144c801fb4b23754": { - "query": "\n query GET($search: String!) {\n allDatasets(search: $search) {\n id\n name\n title\n }\n }\n" - }, - "36815dfc37c8cdb868bca959e408a31a": { - "query": "\n query GET {\n allOrganizations(sortBy: name_DESC) {\n id\n name\n }\n }\n" - }, - "5e0b44a99515f4df85fe0cbb48665cc2": { - "query": "\n mutation Update($id: ID!, $data: ProductUpdateInput) {\n updateProduct(id: $id, data: $data) {\n id\n }\n }\n" - }, - "942e09ea1b601bc8b6199c344708766e": { - "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n }\n" - }, - "021c11cfb3125f496fc2494bd75617b4": { - "query": "\n query GET($ns: String!) {\n allGatewayServices(where: { namespace: $ns }) {\n id\n name\n environment {\n id\n }\n }\n }\n" - }, - "2f3bfb09b72c9c8bdcac6e31126b1a73": { - "query": "\n query GET($flow: String) {\n allCredentialIssuers(where: { flow: $flow}) {\n id\n name\n }\n }\n" - }, - "014de0429336e44dec6fe61fec09b23f": { - "query": "\n mutation Update($id: ID!, $data: EnvironmentUpdateInput) {\n updateEnvironment(id: $id, data: $data) {\n name\n id\n }\n }\n" - }, - "e89d3ac8414daa7a223dedb390dde834": { - "query": "\n mutation Remove($id: ID!) {\n deleteEnvironment(id: $id) {\n name\n id\n }\n }\n" - }, - "8cdc18ee9bfecd766bf3a70e7d1dba74": { - "query": "\n mutation Remove($id: ID!) {\n deleteProduct(id: $id) {\n id\n }\n }\n" - }, - "ff9924389e62e9b2eef670aac8cbacd8": { - "query": "\n query GetConsumers {\n allServiceAccesses(first: 200, sortBy: updatedAt_DESC) {\n consumer {\n id\n username\n aclGroups\n customId\n plugins {\n name\n }\n tags\n createdAt\n }\n }\n\n allAccessRequests(where: { isComplete_not: true }) {\n id\n }\n }\n" - }, - "fa715cbb607cacb74fd02264e73e95e0": { - "query": "\n query GetPendingAccessRequests {\n allAccessRequests(where: { isIssued_not: true }) {\n id\n name\n requestor {\n name\n }\n }\n }\n" - }, - "5bed012bae91c559ee46f42a202eb16a": { - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n }\n" - }, - "1d931bda7dd081d70775d8941c649981": { - "query": "\n query GetControlContent {\n allGatewayRoutes {\n name\n extForeignKey\n }\n allGatewayServices {\n name\n extForeignKey\n }\n }\n" - }, - "e5f972a2af707166c38822c721dbb1c0": { - "query": "\n mutation createGatewayConsumerPlugin($id: ID!, $controls: String!) {\n createGatewayConsumerPlugin(id: $id, plugin: $controls) {\n id\n }\n }\n" - }, - "9b19b9946a80f6844b9eb7f0938159e2": { - "query": "\n query GetAccessRequest($id: ID!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n }\n }\n }\n" - }, - "582f2d0d70c73d27ce92360c50b1321f": { - "query": "\n query GetAccessRequests($id: ID!) {\n allAccessRequests(where: { id: $id } ) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n email\n }\n application {\n appId\n name\n }\n serviceAccess {\n consumer {\n username\n customId\n }\n }\n productEnvironment {\n name\n appId\n active\n flow\n credentialIssuer {\n name\n flow\n mode\n availableScopes\n }\n product {\n name\n organization {\n name\n title\n }\n organizationUnit {\n name\n title\n }\n }\n services {\n name\n host\n }\n }\n }\n }\n" - }, - "64b78fbe48840e7f53da945f15fae866": { - "query": "\n query GetProducts {\n allServiceAccesses {\n id\n name\n active\n productEnvironment {\n name\n flow\n credentialIssuer {\n id\n name\n flow\n clientId\n availableScopes\n resourceType\n }\n product {\n name\n }\n }\n }\n }\n" - }, - "712871fae3631b0248b8179dd835576c": { - "query": "\n query GetResources($credIssuerId: ID!, $owner: String!, $resourceType: String) {\n getResourceSet(credIssuerId: $credIssuerId, owner: $owner, type: $resourceType) {\n id\n name\n type\n }\n\n getPermissionTickets(credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n } \n }\n" - }, - "87b01376c9dcbda37902baced783b9fd": { - "query": "\n query GetPermissions($resourceId: String, $credIssuerId: ID!) {\n getPermissionTickets(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n \n CredentialIssuer(where: {id: $credIssuerId}) {\n clientId\n resourceType\n availableScopes\n }\n\n getResourceSet(credIssuerId: $credIssuerId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n }\n" - }, - "30c6496ff07f4cd2dd4cd362b07ef00b": { - "query": "\n query GET {\n allServiceAccesses(orderBy: \"createdAt_DESC\", where: { consumerType: client, namespace_not: null, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n" - }, - "b5285a969b9069defb9b30ae88f98fb4": { - "query": "\n mutation CreateServiceAccount {\n createServiceAccount {\n id\n name\n credentials\n }\n }\n" - }, - "ba4d42582863f7c602e22943d72d6fda": { - "query": "\n mutation DeleteServiceAccount($id: ID!) {\n deleteServiceAccess(id: $id) {\n id\n }\n }\n" - }, - "5e7fd453e8e15d6bae8de06f873cbf1b": { - "query": "\n mutation GrantSAAccess($credIssuerId: ID!, $resourceId: String!, $data: UMAPolicyInput!) {\n createUmaPolicy(credIssuerId: $credIssuerId, resourceId: $resourceId, data: $data) {\n id\n }\n }\n" - }, - "649ead71deeaaa84f086ab4b4ef2d0c7": { - "query": "\n mutation RevokeSAAccess($credIssuerId: ID!, $policyId: String!) {\n deleteUmaPolicy(credIssuerId: $credIssuerId, policyId: $policyId)\n }\n" - }, - "54e201721dd1b4abf27ffc7750e8cdeb": { - "query": "\n mutation GrantUserAccess($credIssuerId: ID!, $data: UMAPermissionTicketInput!) {\n grantPermissions(credIssuerId: $credIssuerId, data: $data) {\n id\n }\n }\n" - }, - "572b4b99eaafbc288d879d0651be430f": { - "query": "\n mutation RevokeAccess($credIssuerId: ID!, $tickets: [String]!) {\n revokePermissions(credIssuerId: $credIssuerId, ids: $tickets)\n }\n" - }, - "1a67f5abb4549467bc88388e673610e2": { - "query": "\n mutation GrantAccess($credIssuerId: ID!, $resourceId: String!, $requesterId: String!, $scopes: [String]!) {\n approvePermissions(credIssuerId: $credIssuerId, resourceId: $resourceId, requesterId: $requesterId, scopes: $scopes)\n }\n" - }, - "6e2213798c7c4afb0d4932731aaee746": { - "query": "\n query GetResources(\n $credIssuerId: ID!\n $owner: String\n $resourceType: String\n ) {\n getResourceSet(\n credIssuerId: $credIssuerId\n owner: $owner\n type: $resourceType\n ) {\n id\n name\n type\n }\n\n getPermissionTickets(credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n }\n" - }, - "98d9f61d8809fcd6092dca49d436ea13": { - "query": "\n query GetPermissions($resourceId: String, $credIssuerId: ID!) {\n getPermissionTickets(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n CredentialIssuerSummary(where: { id: $credIssuerId }) {\n clientId\n resourceType\n availableScopes\n }\n\n getResourceSet(credIssuerId: $credIssuerId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n }\n" - }, - "61e234b0c352d681316ea661ba205396": { - "query": "\n query GetPermissions($resourceId: String, $credIssuerId: ID!) {\n getPermissionTickets(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n \n getResourceSet(credIssuerId: $credIssuerId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n }\n" - }, - "efaee2304be960c21f4773d243b25022": { - "query": "\n mutation GrantAccess(\n $credIssuerId: ID!\n $resourceId: String!\n $requesterId: String!\n $scopes: [String]!\n ) {\n approvePermissions(\n credIssuerId: $credIssuerId\n resourceId: $resourceId\n requesterId: $requesterId\n scopes: $scopes\n )\n }\n" - }, - "8d9178bbb517008260143d6d1ad3e48e": { - "query": "\n mutation GrantUserAccess(\n $credIssuerId: ID!\n $data: UMAPermissionTicketInput!\n ) {\n grantPermissions(credIssuerId: $credIssuerId, data: $data) {\n id\n }\n }\n" - }, - "f7010c1f5b042f81a053149d6edb7a97": { - "query": "{\n allDiscoverableProducts(where: {environments_some: {active: true}}) {\n name\n environments(where: {active: true}) {\n name\n }\n organization {\n title\n }\n }\n myApplications {\n id\n name\n }\n}\n" - }, - "0f881afe8034802d5fc2a7fdf8ee53b3": { - "query": "{\n allDiscoverableProducts(where: {environments_some: {active: true}}) {\n name\n environments(where: {active: true}) {\n name\n }\n organization {\n title\n name\n }\n }\n myApplications {\n id\n name\n }\n}\n", - "added": "2021-05-01T17:44:10.807Z" - }, - "b3ac613649f34f9ed58e458d8c4e0be8": { - "query": "\n query {\n myApplications {\n id\n appId\n name\n owner {\n name\n }\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-05-01T17:51:07.471Z" - }, - "5561d1afeb4febb005966d7efc725737": { - "query": "\n mutation Update($id: ID!, $active: Boolean) {\n updateEnvironment(id: $id, data: { active: $active }) {\n name\n id\n active\n }\n }\n", - "added": "2021-05-01T17:56:15.429Z" - }, - "e387e4dfe77a0d5207a7364b6ec1f3b8": { - "query": "\n mutation FulfillRequest($id: ID!, $controls: String!) {\n updateAccessRequest(id: $id, data: { isApproved: true, isIssued: true, isComplete: true, controls: $controls }) {\n id\n }\n }\n", - "added": "2021-05-01T17:58:35.147Z" - }, - "fc522a4bb2d6f449ad51225bdd4356a3": { - "query": "\n query GetAccessRequests {\n allAccessRequests(sortBy: [createdAt_DESC]) {\n id\n name\n isApproved\n isIssued\n isComplete\n createdAt\n requestor {\n name\n username\n email\n }\n application {\n name\n }\n serviceAccess {\n id\n }\n productEnvironment {\n name\n flow\n credentialIssuer {\n name\n flow\n mode\n }\n product {\n name\n organization {\n name\n title\n }\n organizationUnit {\n name\n title\n }\n }\n services {\n name\n host\n }\n }\n }\n }\n", - "added": "2021-05-01T17:58:43.603Z" - }, - "270ce32ff612cd6b50909442791afc2c": { - "query": "\n mutation Approve($id: ID!) {\n updateAccessRequest(\n id: $id\n data: { isApproved: false, isComplete: true }\n ) {\n id\n }\n }\n", - "added": "2021-05-01T17:59:33.903Z" - }, - "da4627820b7d026bff6c2e0ad74d6993": { - "referer": "http://localhost:4180/devportal/access", - "query": "\n mutation CancelAccess($id: ID!) {\n deleteServiceAccess(id: $id) {\n id\n }\n }\n", - "added": "2021-05-03T03:51:18.805Z" - }, - "57ccbeb6ab6385f4d9157ec71d0af66b": { - "referer": "http://localhost:4180/manager/services", - "query": "\n query GetServices {\n allGatewayServicesByNamespace(first: 200) {\n id\n name\n updatedAt\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n routes {\n id\n name\n }\n plugins {\n id\n name\n }\n }\n }\n", - "added": "2021-05-03T04:06:59.242Z" - }, - "1b4e9f470ad0cbd09765e61f3a3191f3": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetConsumers {\n allServiceAccessesByNamespace(first: 200, sortBy: updatedAt_DESC) {\n consumer {\n id\n username\n aclGroups\n customId\n plugins {\n name\n }\n tags\n createdAt\n }\n }\n\n allAccessRequestsByNamespace(where: { isComplete_not: true }) {\n id\n }\n }\n", - "added": "2021-05-03T04:15:00.918Z" - }, - "627ab65d15887b4073ae0a42af759ee5": { - "referer": "http://localhost:4180/manager/products", - "query": "\n query GET($namespace: String!) {\n allProductsByNamespace(where: { namespace: $namespace }) {\n id\n name\n description\n organization {\n title\n }\n organizationUnit {\n title\n }\n dataset {\n title\n notes\n sector\n license_title\n }\n environments {\n id\n name\n active\n flow\n services {\n id\n name\n host\n }\n credentialIssuer {\n name\n }\n }\n }\n }\n", - "added": "2021-05-03T04:22:20.770Z" - }, - "ca3396cb109a027586f8a88fcafab178": { - "referer": "http://localhost:4180/manager/products", - "query": "\n query GET {\n allProductsByNamespace {\n id\n name\n description\n organization {\n title\n }\n organizationUnit {\n title\n }\n dataset {\n title\n notes\n sector\n license_title\n }\n environments {\n id\n name\n active\n flow\n services {\n id\n name\n host\n }\n credentialIssuer {\n name\n }\n }\n }\n }\n", - "added": "2021-05-03T04:24:57.504Z" - }, - "ef9b39b6026c6e986bbbde767554b33e": { - "referer": "http://localhost:4180/manager/products", - "query": "\n query GetConsumers {\n allServiceAccessesByNamespace(first: 200) {\n consumer {\n id\n username\n aclGroups\n customId\n plugins {\n name\n }\n tags\n createdAt\n }\n }\n\n allAccessRequestsByNamespace(where: { isComplete_not: true }) {\n id\n }\n }\n", - "added": "2021-05-03T04:40:49.957Z" - }, - "762f7f4b9177e5529396855275a8b882": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetPendingAccessRequests {\n allAccessRequestsByNamespace(where: { isIssued_not: true }) {\n id\n name\n requestor {\n name\n }\n }\n }\n", - "added": "2021-05-03T04:40:56.037Z" - }, - "2cbccd27ed2332806aecc26ceef80130": { - "referer": "http://localhost:4180/manager/poc/service-accounts", - "query": "\n query GET {\n allServiceAccessesByNamespace(orderBy: \"createdAt_DESC\", where: { consumerType: client, namespace_not: null, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-05-03T04:56:47.774Z" - }, - "5d18a6f55463ea75b85fe2be5bc4716e": { - "referer": "http://localhost:4180/manager/poc/namespaces", - "query": "\n query GET {\n allServiceAccessesByNamespace(where: { consumerType: client, namespace_not: null, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-05-03T04:57:01.498Z" - }, - "bcc7104dcd32b65018369a958321227f": { - "referer": "http://localhost:4180/manager/poc/service-accounts", - "query": "\n query GET {\n allServiceAccessesByNamespace(where: { consumerType: client, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-05-03T04:57:58.781Z" - }, - "0f0729e54266db6ca0bf4faab9b669cf": { - "referer": "http://localhost:4180/manager/poc/service-accounts", - "query": "\n query GET {\n allNamespaceServiceAccounts(where: { consumerType: client, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-05-03T05:01:05.655Z" - }, - "66c93863f727adee6fe73f330e337456": { - "referer": "http://localhost:4180/manager/poc/activity", - "query": "\n query GET($first: Int, $skip: Int) {\n allActivities( first:$first, skip: $skip, sortBy: createdAt_DESC) {\n id\n type\n name\n action\n result\n message\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n }\n }\n }\n", - "added": "2021-05-03T05:02:23.332Z" - }, - "ce126df31b7c93cde098d4a414f5e867": { - "referer": "http://localhost:4180/manager/poc/credential-issuers", - "query": "\n query GetCredentialIssuers {\n allCredentialIssuersByNamespace(orderBy: \"name_ASC\") {\n id\n name\n flow\n mode\n owner {\n name\n username\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-03T05:22:03.167Z" - }, - "fa743ec5f90e1b2c1897efdf67f7c8a1": { - "referer": "http://localhost:4180/manager/poc/credential-issuers", - "query": "\n query GetCredentialIssuers {\n allCredentialIssuersByNamespace(first:20) {\n id\n name\n flow\n mode\n owner {\n name\n username\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-03T05:22:43.164Z" - }, - "c039b050c3d605fbb834577d1092c90e": { - "referer": "http://localhost:4180/manager/poc/credential-issuers", - "query": "\n query GetCredentialIssuers {\n allCredentialIssuersByNamespace {\n id\n name\n flow\n mode\n owner {\n name\n username\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-03T05:24:17.055Z" - }, - "fbe730b4789ce693f47d4e2ff3a56bef": { - "referer": "http://localhost:4180/manager/poc/credential-issuers/issuer/608f892d7aa28b3ee36d727c", - "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n clientId\n clientRegistration\n oidcDiscoveryUrl\n apiKeyName\n clientRoles\n availableScopes\n resourceType\n owner {\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-03T05:27:43.598Z" - }, - "afb6752f2404a9e442c8830f47b1290d": { - "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", - "query": "\n query GET($flow: String) {\n allCredentialIssuersByNamespace(where: { flow: $flow}) {\n id\n name\n }\n }\n", - "added": "2021-05-03T21:31:04.049Z" - }, - "18eee5343281a196598afaaa92d07d3a": { - "referer": "http://localhost:4180/devportal/requests/new/608d963a0eac350a840c5032", - "query": "\n query Get($id: ID!) {\n allDiscoverableProducts(where: { id: $id }) {\n id\n name\n environments {\n id\n name\n active\n flow\n additionalDetailsToRequest\n legal {\n title\n description\n link\n }\n }\n }\n myApplications {\n id\n name\n }\n allTemporaryIdentities {\n id\n userId\n name\n username\n email\n }\n }\n", - "added": "2021-05-03T22:27:56.512Z" - }, - "5113980c0b07afe1f73d33e0d910483c": { - "referer": "http://localhost:4180/manager/consumers/60907a60b9eaf28737811b68", - "query": "\n query GetControlContent {\n allGatewayServicesByNamespace {\n name\n extForeignKey\n routes {\n name\n extForeignKey\n }\n }\n }\n", - "added": "2021-05-03T22:43:23.802Z" - }, - "5473c4e41e5fc59d9acd22fbfa413cf0": { - "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", - "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n additionalDetailsToRequest\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n }\n", - "added": "2021-05-03T22:45:25.519Z" - }, - "c6794f580490706e453e4f2122f6b6ef": { - "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", - "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n legal {\n id\n title\n reference\n }\n approval\n additionalDetailsToRequest\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n }\n", - "added": "2021-05-03T22:48:34.130Z" - }, - "938f6cb6a17ca50d63d2e3b07b6ee259": { - "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", - "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n legal {\n id\n title\n reference\n }\n approval\n additionalDetailsToRequest\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n allLegals {\n id\n title\n reference\n }\n }\n", - "added": "2021-05-04T02:37:02.723Z" - }, - "241b17af5a14298c47cd72c45603c2af": { - "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", - "query": "\n query GET($flow: String) {\n allLegals {\n id\n title\n reference\n }\n }\n", - "added": "2021-05-04T02:40:11.782Z" - }, - "1af923113867cf18699bf9fd48ed9c8d": { - "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", - "query": "\n query GET {\n allLegals {\n id\n title\n reference\n }\n }\n", - "added": "2021-05-04T02:40:33.167Z" - }, - "40235fd96287814fea547af0c9421ead": { - "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", - "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n legal {\n id\n title\n reference\n }\n credentialIssuer {\n id\n }\n approval\n additionalDetailsToRequest\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n }\n", - "added": "2021-05-04T03:30:56.003Z" - }, - "5454858e3bace6259f2c4cf260d138ae": { - "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", - "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n clientId\n clientSecret\n apiKeyName\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n environmentDetails\n owner {\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-04T04:17:43.565Z" - }, - "88375d8583bdf9825bfeab3b4874e3f8": { - "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", - "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n apiKeyName\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n environmentDetails\n owner {\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-04T04:18:42.431Z" - }, - "1361e818c2e03e1f0217de58ed9512e9": { - "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", - "query": "\n mutation UpdateAuthzProfile($id: ID!, $data: CredentialIssuerUpdateInput!) {\n updateCredentialIssuer (id: $id, data: $data) {\n id\n }\n }\n", - "added": "2021-05-04T04:28:51.350Z" - }, - "c31548fe29ec8603691b8179e7f9e6d9": { - "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", - "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n apiKeyName\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n environmentDetails\n owner {\n id\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-04T04:32:19.426Z" - }, - "b1e92b051e98f539460355efcdec561d": { - "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", - "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n apiKeyName\n clientAuthenticator\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n environmentDetails\n owner {\n id\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-04T04:43:58.652Z" - }, - "c79882ca813f2e28692cf91ced827993": { - "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", - "query": "\n query GET($flow: String) {\n allCredentialIssuersByNamespace(where: { flow: $flow}) {\n id\n name\n environmentDetails\n }\n }\n", - "added": "2021-05-04T05:10:30.959Z" - }, - "430e99af1246c6d0cc496e62f15e3fff": { - "referer": "http://localhost:4180/devportal/poc/resources", - "query": "\n query GetResources($prodEnvId: ID!, $owner: String!, $resourceType: String) {\n getResourceSet(prodEnvId: $prodEnvId, owner: $owner, type: $resourceType) {\n id\n name\n type\n }\n\n getPermissionTickets(prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n } \n }\n", - "added": "2021-05-04T18:03:59.755Z" - }, - "6ca967cf2a262c338e0f78f35df02438": { - "referer": "http://localhost:4180/devportal/access", - "query": "\n query GetEnvironmentsByProduct($id: ID!) {\n Product(where: { id: $id }) {\n name\n environments {\n id\n name\n credentialIssuer {\n id\n resourceType\n }\n }\n }\n }\n", - "added": "2021-05-04T18:12:02.852Z" - }, - "36c7f83dd514eadf3de094f02918036c": { - "referer": "http://localhost:4180/devportal/access/608d963a0eac350a840c5032", - "query": "\n query GetResources(\n $prodEnvId: ID!\n $owner: String\n $resourceType: String\n ) {\n getResourceSet(\n prodEnvId: $prodEnvId\n owner: $owner\n type: $resourceType\n ) {\n id\n name\n type\n }\n\n getPermissionTickets(prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n }\n", - "added": "2021-05-04T18:12:02.935Z" - }, - "447b524ac079e6c372a8ebcfaa41a591": { - "referer": "http://localhost:4180/devportal/access/605e7afa2420523942b05f9a", - "query": "\n query GetPermissions($resourceId: String, $prodEnvId: ID!) {\n getPermissionTickets(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n }\n", - "added": "2021-05-04T18:18:12.090Z" - }, - "34e5387304ea50ceadc7f891e26be174": { - "referer": "http://localhost:4180/devportal/resources/f2dab0ff-f9e9-466d-a115-52010a1bb47d?peid=605e7afb2420523942b05f9b", - "query": "\n query GetPermissions($resourceId: String, $prodEnvId: ID!) {\n getPermissionTickets(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n \n Environment(where: { id: $prodEnvId }) {\n name\n product {\n name\n }\n }\n }\n", - "added": "2021-05-04T18:21:42.374Z" - }, - "43df0bdd0b7d750ddf04ae78b2d4b18b": { - "referer": "http://localhost:4180/devportal/resources/f2dab0ff-f9e9-466d-a115-52010a1bb47d?peid=605e7afb2420523942b05f9b", - "query": "\n mutation RevokeAccess($prodEnvId: ID!, $tickets: [String]!) {\n revokePermissions(prodEnvId: $prodEnvId, ids: $tickets)\n }\n", - "added": "2021-05-04T18:27:04.146Z" - }, - "af9082e55fb2892d63c1ab971a7821d5": { - "referer": "http://localhost:4180/devportal/resources/f2dab0ff-f9e9-466d-a115-52010a1bb47d?peid=605e7afb2420523942b05f9b", - "query": "\n mutation GrantUserAccess(\n $prodEnvId: ID!\n $data: UMAPermissionTicketInput!\n ) {\n grantPermissions(prodEnvId: $prodEnvId, data: $data) {\n id\n }\n }\n", - "added": "2021-05-04T18:30:01.528Z" - }, - "9d48c2d21e114b26b8dd56be972af0f1": { - "referer": "http://localhost:4180/devportal/access/605e7afa2420523942b05f9a", - "query": "\n query GetPermissions($resourceId: String, $prodEnvId: ID!) {\n getPermissionTickets(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n \n Environment(where: { id: $prodEnvId }) {\n name\n product {\n id\n name\n }\n }\n }\n", - "added": "2021-05-04T18:35:01.952Z" - }, - "ea089f3e222ef310c3240d23ad4f7b11": { - "referer": "http://localhost:4180/devportal/resources/2a9640cc-c89e-44d5-826a-458b4460b91a?peid=606393b601ac0b48cfadcb0c", - "query": "\n mutation GrantSAAccess(\n $prodEnvId: ID!, \n $resourceId: String!, \n $data: UMAPolicyInput!) {\n createUmaPolicy(prodEnvId: $prodEnvId, resourceId: $resourceId, data: $data) {\n id\n }\n }\n", - "added": "2021-05-04T19:15:51.757Z" - }, - "0cb51f5035bc27157165bd5c0a5443b7": { - "referer": "http://localhost:4180/devportal/resources/2a9640cc-c89e-44d5-826a-458b4460b91a?peid=606393b601ac0b48cfadcb0c", - "query": "\n mutation RevokeSAAccess(\n $prodEnvId: ID!, \n $policyId: String!) {\n deleteUmaPolicy(prodEnvId: $prodEnvId, policyId: $policyId)\n}\n", - "added": "2021-05-04T19:28:41.943Z" - }, - "8473d241baf6d7d70afcb43dce12e21f": { - "referer": "http://localhost:4180/manager/requests/609231a5681d3210b7707bbe", - "query": "\n query GetAccessRequest($id: ID!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n }\n }\n }\n }\n", - "added": "2021-05-05T06:06:10.473Z" - }, - "af09f8310abb04f6c77fdd6f1ad8f77c": { - "referer": "http://localhost:4180/manager/requests/609231a5681d3210b7707bbe", - "query": "\n mutation FulfillRequest($id: ID!, $controls: String!) {\n updateAccessRequest(\n id: $id, \n data: { isApproved: true, isIssued: true, isComplete: true, controls: $controls }\n ) {\n id\n }\n }\n", - "added": "2021-05-05T06:18:03.288Z" - }, - "08c0b2daa3e2c3226afe1ac150ae917f": { - "referer": "http://localhost:4180/manager/products", - "query": "\n query GET($id: ID!) {\n Organization(where: { id: $id }) {\n id\n orgUnits {\n name\n id\n }\n }\n }\n", - "added": "2021-05-05T16:06:08.199Z" - }, - "08ea470b98ac8542f103fff6c1f35492": { - "referer": "http://localhost:4180/manager/requests/606418fdb391bd7bfd1d6193", - "query": "\n query GetAccessRequest($id: ID!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n }\n }\n }\n }\n", - "added": "2021-05-05T17:18:37.806Z" - }, - "b1429527c4b1b450366f693247b7120e": { - "referer": "http://localhost:4180/devportal/requests/new/605e7afa2420523942b05f9a", - "query": "\n mutation AddAccessRequest(\n $name: String!\n $controls: String\n $requestor: ID!\n $applicationId: ID!\n $productEnvironmentId: ID!\n $additionalDetails: String\n ) {\n createAccessRequest(\n data: {\n name: $name\n controls: $controls\n additionalDetails: $additionalDetails\n requestor: { connect: { id: $requestor } }\n application: { connect: { id: $applicationId } }\n productEnvironment: { connect: { id: $productEnvironmentId } }\n }\n ) {\n id\n }\n }\n", - "added": "2021-05-05T17:24:39.378Z" - }, - "3f0ca27697b28bff1965c71ba90ce1c7": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetAccessRequest($id: ID!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n }\n", - "added": "2021-05-05T17:31:13.555Z" - }, - "69301c687a618189e45f23f1ef4a39b6": { - "referer": "http://localhost:4180/admin/graphiql", - "query": "mutation ($data: ContentCreateInput) {\n createContent(data: $data) {\n id\n }\n}\n", - "added": "2021-05-27T21:27:58.114Z" - }, - "afc05a67a1753aa00ef23d7da3d25597": { - "referer": "http://localhost:4180/", - "query": "\n query GetNamespaces {\n allNamespaces {\n id\n name\n }\n }\n", - "added": "2021-05-27T21:30:07.761Z" - }, - "cc8bbd6f18ffbbab95c1a7b0caaa52e6": { - "referer": "http://localhost:4180/devportal/access/609c5bf79b8ceca36d31ce95", - "query": "\n query GetResources($prodEnvId: ID!, $resourceType: String) {\n allResourceSets(prodEnvId: $prodEnvId, type: $resourceType) {\n id\n name\n type\n }\n\n allPermissionTickets(prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n }\n", - "added": "2021-05-27T21:30:43.926Z" - }, - "5742c25e1531eec7ad2c1846fd0649cb": { - "referer": "http://localhost:4180/manager/products", - "query": "\n query GET {\n allProductsByNamespace {\n id\n name\n description\n organization {\n id\n title\n }\n organizationUnit {\n id\n title\n }\n dataset {\n name\n title\n notes\n sector\n license_title\n }\n environments {\n id\n name\n active\n flow\n services {\n id\n name\n host\n }\n credentialIssuer {\n name\n }\n }\n }\n }\n", - "added": "2021-05-28T02:55:37.527Z" - }, - "242f50e1670aa197d678c8fef078a6c5": { - "referer": "http://localhost:4180/devportal/access/609c5bf79b8ceca36d31ce95", - "query": "\n query GetPermissions($resourceId: String!, $prodEnvId: ID!) {\n getPermissionTicketsForResource(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPoliciesForResource(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n \n Environment(where: { id: $prodEnvId }) {\n name\n product {\n id\n name\n }\n }\n }\n", - "added": "2021-05-28T02:59:47.750Z" - }, - "663c0683e24542fa7529a53e31e1e96e": { - "referer": "http://localhost:4180/manager/poc/credential-issuers/609daa674a180ccfaaedbe0b", - "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n apiKeyName\n clientAuthenticator\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n resourceAccessScope\n environmentDetails\n owner {\n id\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", - "added": "2021-05-28T03:05:38.617Z" - }, - "c6fff2d82e5ee7d1238f729783a5148f": { - "referer": "http://localhost:4180/devportal/resources/d30f6967-254b-4a19-abb7-abd02f14f23e?peid=609c5bf79b8ceca36d31ce94", - "query": "\n mutation RevokeSAAccess(\n $prodEnvId: ID!, \n $resourceId: String!,\n $policyId: String!) {\n deleteUmaPolicy(prodEnvId: $prodEnvId, resourceId: $resourceId, policyId: $policyId)\n}\n", - "added": "2021-05-28T03:06:08.587Z" - }, - "170f0c898f22eb5819b4b73dd95503ac": { - "referer": "http://localhost:4180/", - "query": "\nmutation CreateNamespace ($name: String!) {\n createNamespace(namespace: $name) {\n id\n name\n }\n}\n", - "added": "2021-05-28T05:25:03.543Z" - }, - "1e983d443f49213db444d1b2a5842865": { - "referer": "http://localhost:4180/", - "query": "\nmutation DeleteNamespace ($name: String!) {\n deleteNamespace(namespace: $name)\n}\n", - "added": "2021-05-28T05:25:29.789Z" - }, - "caadf1abf799958a180d79b8fb3acbcd": { - "referer": "http://localhost:4180/devportal/api-directory/609c1ecb4337bc74fb7205ca", - "query": "\n query Get($id: ID!) {\n allDiscoverableProducts(where: { id: $id }) {\n id\n name\n environments {\n id\n name\n active\n flow\n additionalDetailsToRequest\n legal {\n title\n description\n link\n reference\n }\n credentialIssuer {\n clientAuthenticator\n }\n }\n }\n myApplications {\n id\n name\n }\n mySelf {\n legalsAgreed\n }\n allTemporaryIdentities {\n id\n userId\n name\n username\n email\n }\n }\n", - "added": "2021-05-28T05:43:48.994Z" - }, - "398091e26a0271254962eb43f0345132": { - "referer": "http://localhost:4180/devportal/applications", - "query": "\n mutation Add($name: String!, $description: String) {\n createApplication(data: { name: $name, description: $description }) {\n id\n }\n }\n", - "added": "2021-05-28T05:44:19.642Z" - }, - "02a1cbc8cc2a615ae533f6b82bcabb05": { - "referer": "http://localhost:4180/manager/poc/activity", - "query": "\n query GET($first: Int, $skip: Int) {\n allActivities( first:$first, skip: $skip, sortBy: createdAt_DESC) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", - "added": "2021-05-28T05:46:48.377Z" - }, - "e1b6fe1d5e8a6230fbda9f9afdff5c72": { - "referer": "http://localhost:4180/devportal/requests/new/60a34109b1fd0a61670dcbed", - "query": "\n mutation AddAccessRequest(\n $name: String!\n $controls: String\n $requestor: ID!\n $applicationId: ID!\n $productEnvironmentId: ID!\n $additionalDetails: String\n $acceptLegal: Boolean!\n ) {\n acceptLegal(\n productEnvironmentId: $productEnvironmentId\n acceptLegal: $acceptLegal\n ) {\n legalsAgreed\n }\n\n createAccessRequest(\n data: {\n name: $name\n controls: $controls\n additionalDetails: $additionalDetails\n requestor: { connect: { id: $requestor } }\n application: { connect: { id: $applicationId } }\n productEnvironment: { connect: { id: $productEnvironmentId } }\n }\n ) {\n id\n }\n }\n", - "added": "2021-05-28T05:48:43.618Z" - }, - "d8a1fe9c4cd13380ae02a8a77ed3105e": { - "referer": "http://localhost:4180/manager/namespaces", - "query": "\n query GetConsumers {\n allServiceAccessesByNamespace(first: 200, orderBy: \"updatedAt_DESC\") {\n consumer {\n id\n username\n aclGroups\n customId\n plugins {\n name\n }\n tags\n updatedAt\n }\n application {\n name\n appId\n }\n }\n\n allAccessRequestsByNamespace(where: { isComplete_not: true }) {\n id\n }\n }\n", - "added": "2021-05-28T07:03:39.853Z" - }, - "676efc6d02cd0becae418438ea621d04": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities( sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", - "added": "2021-05-28T07:03:58.064Z" - }, - "c9e3c7d3203e4b3c095e454aa721f901": { - "referer": "http://localhost:4180/manager/requests/60ac9c8d58615f36c3f2f7be", - "query": "\n mutation FulfillRequest($id: ID!, $controls: String!) {\n updateAccessRequest(\n id: $id\n data: {\n isApproved: true\n isIssued: true\n isComplete: true\n controls: $controls\n }\n ) {\n id\n }\n }\n", - "added": "2021-05-28T07:04:00.664Z" - }, - "aa7c2da58bd0ede8b7a28394e915807e": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n }\n", - "added": "2021-05-28T07:04:12.402Z" - }, - "adb2e7dc535971400d2d58af811d5dfd": { - "referer": "http://localhost:4180/manager/consumers/60b05e2d2e7ef60dc63477ed", - "query": "\n query GetControlContent {\n allGatewayServicesByNamespace {\n id\n name\n extForeignKey\n routes {\n id\n name\n extForeignKey\n }\n }\n }\n", - "added": "2021-05-28T07:04:13.819Z" - }, - "e373a8ddc9d8d43ad06d081777d4c1a3": { - "referer": "http://localhost:4180/manager/consumers/60b05e2d2e7ef60dc63477ed", - "query": "\n mutation Remove($consumerId: ID!, $pluginExtForeignKey: String!) {\n deleteGatewayConsumerPlugin(\n id: $consumerId\n pluginExtForeignKey: $pluginExtForeignKey\n ) {\n id\n }\n }\n", - "added": "2021-05-28T07:04:35.684Z" - }, - "b7b196ea3c68aeb81b2d8e7b6bc5d223": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities(sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", - "added": "2021-05-28T08:16:22.934Z" - }, - "317080585c1dbf0467005f8a097a3f1b": { - "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n name\n active\n flow\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-05-31T20:40:38.403Z" - }, - "75a5ca12217591d7a6717438f8b3074c": { - "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n appId\n name\n active\n flow\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-05-31T20:41:59.684Z" - }, - "7aa9867cc96445124e0303cf9f6abb36": { - "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-05-31T20:46:02.815Z" - }, - "c2e7d12c9c1ec1d1e62979e9a04e5ad7": { - "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", - "query": "\n mutation ToggleConsumerACLMembership(\n $prodEnvId: ID!\n $consumerId: ID!\n $group: String!\n $grant: Boolean!\n ) {\n updateConsumerGroupMembership(id: $id)\n }\n", - "added": "2021-05-31T21:16:57.066Z" - }, - "8d4decae694fbb666484100a54f069de": { - "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", - "query": "\n mutation ToggleConsumerACLMembership(\n $prodEnvId: ID!\n $consumerId: ID!\n $group: String!\n $grant: Boolean!\n ) {\n updateConsumerGroupMembership(\n prodEnvId: $prodEnvId\n consumerId: $consumerId\n group: $group\n grant: $grant\n )\n }\n", - "added": "2021-05-31T21:20:57.095Z" - }, - "fc22131d32aa7f5601781ab0446e1f38": { - "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-05-31T22:02:40.182Z" - }, - "b9264ef73166bdb92aca1ee0d1baeb61": { - "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", - "query": "\n query GetConsumerScopesAndRoles(\n $prodEnvId: ID!\n $consumerUsername: ID!\n $consumerType: String!\n ) {\n consumerScopesAndRoles(\n prodEnvId: $prodEnvId\n consumerUsername: $consumerUsername\n consumerType: $consumerType\n ) {\n id\n consumerType\n defaultScopes\n optionalScopes\n clientRoles\n }\n }\n", - "added": "2021-06-01T03:53:38.063Z" - }, - "b3349812a0132f09f7b24833baa00430": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n mutation LinkConsumerToNamespace($username: String!) {\n linkConsumerToNamespace(username: $username)\n }\n", - "added": "2021-06-01T05:04:50.018Z" - }, - "f8cacde2afa67d4526c5911a6c8bbe66": { - "referer": "http://localhost:4180/admin", - "query": "{\n user: authenticatedTemporaryIdentity {\n id\n _label_\n __typename\n }\n}\n", - "added": "2021-06-01T05:16:25.224Z" - }, - "061263c3840dce7943360f72e4984f30": { - "referer": "http://localhost:4180/admin/gateway-consumers?fields=_label_%2Cusername%2CcustomId%2CaclGroups%2Cplugins&!aclGroups_contains_i=%22router_user%22", - "query": "query getList($where: GatewayConsumerWhereInput, $search: String, $sortBy: [SortGatewayConsumersBy!], $first: Int, $skip: Int) {\n allGatewayConsumers(\n where: $where\n search: $search\n sortBy: $sortBy\n first: $first\n skip: $skip\n ) {\n _label_\n id\n username\n customId\n aclGroups\n plugins {\n id\n _label_\n __typename\n }\n __typename\n }\n _allGatewayConsumersMeta(where: $where, search: $search) {\n count\n __typename\n }\n}\n", - "added": "2021-06-01T05:16:28.717Z" - }, - "81d7ccbf028ce2abfe6cda6ea84849cc": { - "referer": "http://localhost:4180/manager/consumers/60b5c8a811dc5e48f6cbd863", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n namespace\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-06-01T06:08:06.801Z" - }, - "a7100c780acc3377cec5f891d0dca3d6": { - "referer": "http://localhost:4180/manager/consumers/60b5c8a811dc5e48f6cbd863", - "query": "\n mutation ToggleConsumerRoles(\n $prodEnvId: ID!\n $consumerId: ID!\n $roleName: String!\n $grant: Boolean!\n ) {\n updateConsumerRoleAssignment(\n prodEnvId: $prodEnvId\n consumerId: $consumerId\n roleName: $roleName\n grant: $grant\n )\n }\n", - "added": "2021-06-01T06:19:54.225Z" - }, - "3f49e70c55b37148d7f10fda3d9cea5a": { - "referer": "http://localhost:4180/manager/consumers/60b5bff29dc26943fb23d4b6", - "query": "\n query GetConsumerScopesAndRoles($prodEnvId: ID!, $consumerUsername: ID!) {\n consumerScopesAndRoles(\n prodEnvId: $prodEnvId\n consumerUsername: $consumerUsername\n ) {\n id\n consumerType\n defaultScopes\n optionalScopes\n clientRoles\n }\n }\n", - "added": "2021-06-01T06:27:34.830Z" - }, - "602067643dc862654d0ce78db879da9d": { - "referer": "http://localhost:4180/manager/consumers/60b5bff29dc26943fb23d4b6", - "query": "\n mutation ToggleConsumerRoles(\n $prodEnvId: ID!\n $consumerUsername: String!\n $roleName: String!\n $grant: Boolean!\n ) {\n updateConsumerRoleAssignment(\n prodEnvId: $prodEnvId\n consumerUsername: $consumerUsername\n roleName: $roleName\n grant: $grant\n )\n }\n", - "added": "2021-06-01T06:49:33.063Z" - }, - "905704bc61eebe0a395cd3c550dbf158": { - "referer": "http://localhost:4180/manager/services/60a7f41eb3c6f22ab455ec1f", - "query": "\n query GET($id: ID!) {\n GatewayService(where: { id: $id }) {\n id\n name\n namespace\n tags\n host\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n plugins {\n id\n name\n }\n routes {\n id\n name\n host\n }\n updatedAt\n }\n }\n", - "added": "2021-06-01T20:45:09.617Z" - }, - "5600ed61fad01032ac67ec031deb1c7c": { - "referer": "http://localhost:4180/manager/services/60a7f41eb3c6f22ab455ec1f", - "query": "\n query GET($id: ID!) {\n GatewayService(where: { id: $id }) {\n id\n name\n namespace\n tags\n host\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n plugins {\n id\n name\n }\n routes {\n id\n name\n hosts\n paths\n methods\n }\n updatedAt\n }\n }\n", - "added": "2021-06-01T20:45:18.071Z" - }, - "cd62d7dd83bb2ede2e38f7bb91000dfe": { - "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60b7e9074b74934a7b6ad728", - "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n allAccessRequests(where: { isComplete: null }) {\n productEnvironment {\n credentialIssuer {\n instruction\n }\n }\n }\n }\n", - "added": "2021-06-02T20:24:42.443Z" - }, - "a4320a0fa32c22f2637725d5e3771ad1": { - "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60b7e9074b74934a7b6ad728", - "query": "\n mutation GenCredential($id: ID!) {\n updateAccessRequest(id: $id, data: { credential: \"NEW\" }) {\n credential\n }\n }\n", - "added": "2021-06-02T20:24:52.161Z" - }, - "cc7ad864ebfca2ba9fd78a713dc6f149": { - "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60b7e9074b74934a7b6ad728", - "query": "\n mutation DeleteNamespace($name: String!) {\n deleteNamespace(namespace: $name)\n }\n", - "added": "2021-06-02T20:26:44.095Z" - }, - "a45894f8cb7cf5ad9abcea1c3d2c4f0a": { - "referer": "http://localhost:4180/manager/namespaces", - "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-06-08T21:39:33.120Z" - }, - "df53970ba9e6fc294d5bf30686437fcb": { - "referer": "http://localhost:4180/manager/poc/service-accounts", - "query": "\n mutation CreateServiceAccount {\n createServiceAccount {\n id\n name\n credentials\n }\n }\n", - "added": "2021-06-08T21:39:34.517Z" - }, - "e81b929f8dc81567309f774bd93ee4ee": { - "referer": "http://localhost:4180/manager/poc/service-accounts", - "query": "\n mutation DeleteServiceAccount($id: ID!) {\n deleteServiceAccess(id: $id) {\n id\n }\n }\n", - "added": "2021-06-08T21:39:55.771Z" - }, - "5918f7500ca71b9bcd5853c3c9da3318": { - "referer": "http://localhost:4180/", - "query": "\n mutation CreateNamespace($name: String!) {\n createNamespace(namespace: $name) {\n id\n name\n }\n }\n", - "added": "2021-06-08T23:23:29.330Z" - }, - "21581865a450d056abc17a0552a75a27": { - "referer": "http://localhost:4180/devportal/resources/28f9bdbd-dbdb-4fe4-b999-3875b6aae17a?peid=609c5bf79b8ceca36d31ce94", - "query": "\n mutation RevokeAccess($prodEnvId: ID!, $resourceId: String!, $tickets: [String]!) {\n revokePermissions(prodEnvId: $prodEnvId, resourceId: $resourceId, ids: $tickets)\n }\n", - "added": "2021-06-10T20:28:29.544Z" - }, - "eb765e1d5ea1ecd8bf0e64f1a1b3bc1d": { - "referer": "http://localhost:4180/manager/products", - "query": "\n query GET {\n allOrganizations(sortBy: name_DESC) {\n id\n name\n title\n }\n }\n", - "added": "2021-06-11T05:54:50.249Z" - }, - "3ff59d8d44a038c1416655d5a89f5a60": { - "referer": "http://localhost:4180/manager/products", - "query": "\n query GET($id: ID!) {\n Organization(where: { id: $id }) {\n id\n orgUnits {\n name\n id\n title\n }\n }\n }\n", - "added": "2021-06-11T05:55:08.602Z" - }, - "34c8c044db0ee8eb0b6808b6b29ba080": { - "referer": "http://localhost:4180/manager/namespaces", - "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n currentNamespace {\n name\n prodEnvId\n }\n }\n", - "added": "2021-06-08T22:56:06.255Z" - }, - "c51c963657cc256fcd69c6a294e9ac5f": { - "referer": "http://localhost:4180/manager/poc/service-accounts", - "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n currentNamespace {\n id\n name\n prodEnvId\n }\n }\n", - "added": "2021-06-08T22:57:49.425Z" - }, - "dd757f543a0e7bcf0989286c6bb219b4": { - "referer": "http://localhost:4180/manager/poc/service-accounts", - "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n currentNamespace {\n id\n name\n scopes\n prodEnvId\n }\n }\n", - "added": "2021-06-08T22:58:28.096Z" - }, - "82ee3140c55e3dcdcc07b487505ee8ae": { - "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n currentNamespace {\n id\n name\n scopes {\n name\n }\n prodEnvId\n }\n }\n", - "added": "2021-06-08T22:59:02.979Z" - }, - "5f804316eb2333f7b1eecc24c0a53a2a": { - "referer": "http://localhost:4180/manager/service-accounts", - "query": "\n query GET {\n currentNamespace {\n id\n name\n scopes {\n name\n }\n prodEnvId\n }\n }\n", - "added": "2021-06-14T18:10:33.121Z" - }, - "f68ed4753e35892e58b5857e8639810b": { - "referer": "http://localhost:4180/manager/service-accounts", - "query": "\n query GET {\n allNamespaceServiceAccounts(\n sortBy: ['createdAt_DESC']\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-06-14T18:11:39.697Z" - }, - "09935650941dae862d8890c98e7fd99e": { - "query": "\n query GET {\n allNamespaceServiceAccounts(\n sortBy: ['createdAt_DESC'],\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-06-14T18:11:50.748Z" - }, - "f5b50797d3ca4254bcca638cc47ddee5": { - "query": "\n query GET {\n allNamespaceServiceAccounts(\n orderBy: 'createdAt_DESC',\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-06-14T18:12:22.679Z" - }, - "204058b06089cb6256e511032a2eb7c3": { - "query": "\n query GET {\n allNamespaceServiceAccounts(\n orderBy: 'createdAt_DESC'\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-06-14T18:12:37.683Z" - }, - "57fa329defc7fd4f7ceaa3da860b8752": { - "query": "\n query GET {\n allNamespaceServiceAccounts(\n orderBy: \"createdAt_DESC\"\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", - "added": "2021-06-14T18:13:40.046Z" - }, - "030610692ee4f492182724d9d2651544": { - "referer": "http://localhost:4180/manager/namespace-access", - "query": "\n query currentNamespace {\n name\n scopes\n }\n", - "added": "2021-06-15T21:02:21.221Z" - }, - "cb73913a56ecc7305c3d0add835a07d7": { - "referer": "http://localhost:4180/manager/namespace-access", - "query": "\n query GetPermissions($resourceId: String!, $prodEnvId: ID!) {\n getPermissionTicketsForResource(\n prodEnvId: $prodEnvId\n resourceId: $resourceId\n ) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPoliciesForResource(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n\n Environment(where: { id: $prodEnvId }) {\n name\n product {\n id\n name\n }\n }\n }\n", - "added": "2021-06-15T21:21:13.325Z" - }, - "83fc109d25042aa0f3d88f46349776d3": { - "referer": "http://localhost:4180/manager/service-accounts", - "query": "\n mutation CreateServiceAccount($scopes: [String]!) {\n createServiceAccount(scopes: $scopes) {\n id\n name\n credentials\n }\n }\n", - "added": "2021-06-16T05:24:25.027Z" - }, - "61a4f5840dd36e50e94cc5066c739ac9": { - "referer": "http://localhost:4180/manager/service-accounts", - "query": "\n mutation CreateServiceAccount($resourceId: String!, $scopes: [String]!) {\n createServiceAccount(resourceId: $resourceId, scopes: $scopes) {\n id\n name\n credentials\n }\n }\n", - "added": "2021-06-16T05:56:54.209Z" - }, - "b13519f4421dc481f3c23247dcb63d12": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n serviceAccess {\n id\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities(sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", - "added": "2021-06-24T05:32:11.325Z" - }, - "1f3608db1a9f3c60ea6fc0eaa283c4e6": { - "referer": "http://localhost:4180/manager/requests/609daa814a180ccfaaedbe0d", - "query": "\n query GetBusinessProfile($serviceAccessId: ID!) {\n BusinessProfile(serviceAccessId: $serviceAccessId) {\n user {\n displayName\n firstname\n surname\n email\n isSuspended\n isManagerDisabled\n }\n institution {\n type\n legalName\n address {\n addressLine1\n addressLine2\n city\n postal\n province\n country\n }\n isSuspended\n businessTypeOther\n }\n }\n }\n", - "added": "2021-06-24T05:43:48.010Z" - }, - "e500280ae6fa283e22d0e9095e1174c7": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetPendingAccessRequests {\n allAccessRequestsByNamespace(where: { isIssued_not: true }) {\n id\n name\n requestor {\n name\n username\n }\n }\n }\n", - "added": "2021-06-29T22:14:01.196Z" - }, - "0ebc74e357250ab2d8cdca8afd3aff7e": { - "referer": "http://localhost:4180/manager/requests/60dba098fb76a41bf6a8e74e", - "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n email\n }\n application {\n name\n }\n serviceAccess {\n id\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities(sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", - "added": "2021-06-29T22:42:13.261Z" - }, - "4eccdd9ef225022880be1cc65bfcf5a3": { - "referer": "http://localhost:4180/manager/requests/60dba098fb76a41bf6a8e74e", - "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n email\n }\n application {\n name\n }\n serviceAccess {\n id\n }\n productEnvironment {\n name\n additionalDetailsToRequest\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities(sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", - "added": "2021-06-29T22:48:41.365Z" - }, - "78b1987847e9566263124c3b003f06bd": { - "referer": "http://localhost:4180/manager/consumers/60b53dbaa6802a80a0ff27dd", - "query": "\n mutation ToggleConsumerScopes(\n $prodEnvId: ID!\n $consumerUsername: String!\n $scopeName: String!\n $grant: Boolean!\n ) {\n updateConsumerScopeAssignment(\n prodEnvId: $prodEnvId\n consumerUsername: $consumerUsername\n scopeName: $scopeName\n grant: $grant\n )\n }\n", - "added": "2021-07-02T23:59:23.643Z" - }, - "7238409bbbc0954b2c00cd03a8162054": { - "referer": "http://localhost:4180/manager/consumers/60b53dbaa6802a80a0ff27dd", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-07-03T00:43:58.265Z" - }, - "1aa9f1d913d81a275515d46091053bec": { - "referer": "http://localhost:4180/manager/consumers/60b53dbaa6802a80a0ff27dd", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allServiceAccesses(where: { consumer: { id: $id } }) {\n application {\n name\n owner {\n username\n }\n }\n }\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-07-03T01:43:27.940Z" - }, - "13758b33b8f2db459bfb37fd789e5309": { - "referer": "http://localhost:4180/manager/consumers/60b5bff29dc26943fb23d4b6", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allServiceAccesses(where: { consumer: { id: $id } }) {\n name\n consumerType\n application {\n appId\n name\n owner {\n username\n }\n }\n }\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-07-03T01:46:50.029Z" - }, - "0d9d51ac4ff398172f53dac66b86e481": { - "referer": "http://localhost:4180/manager/consumers/60ad8e1044cf9a36ef674085", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allServiceAccesses(where: { consumer: { id: $id } }) {\n name\n consumerType\n application {\n appId\n name\n owner {\n name\n username\n email\n }\n }\n }\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-07-03T01:47:50.661Z" - }, - "b35cd8088be328bd3528db32a3ba97cf": { - "referer": "http://localhost:4180/manager/consumers/60ad8e1044cf9a36ef674085", - "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allServiceAccesses(where: { consumer: { id: $id } }) {\n name\n consumerType\n application {\n appId\n name\n owner {\n name\n username\n email\n }\n }\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", - "added": "2021-07-03T01:47:59.254Z" - }, - "b2e2c4b6ce7586668c34d3226ae6c5da": { - "referer": "http://localhost:4180/manager/consumers/60b7e9154b74934a7b6ad72a", - "query": "\n mutation updateGatewayConsumerPlugin($id: ID!, $controls: String!) {\n updateGatewayConsumerPlugin(id: $id, plugin: $controls) {\n id\n }\n }\n", - "added": "2021-07-03T03:10:14.327Z" - }, - "7073ccad4a36f9d6b1fae48ad9e00f72": { - "referer": "http://localhost:4180/manager/consumers/60b7e9154b74934a7b6ad72a", - "query": "\n mutation updateGatewayConsumerPlugin(\n $id: ID!\n $pluginExtForeignKey: String!\n $controls: String!\n ) {\n updateGatewayConsumerPlugin(\n id: $id\n pluginExtForeignKey: $pluginExtForeignKey\n plugin: $controls\n ) {\n id\n }\n }\n", - "added": "2021-07-03T03:23:01.128Z" - }, - "a2750969742e7ffa0880f452f82ee58b": { - "referer": "http://localhost:4180/manager/namespace-access", - "query": "\n mutation GrantUserAccess($prodEnvId: ID!, $data: UMAPermissionTicketInput!) {\n grantPermissions(prodEnvId: $prodEnvId, data: $data) {\n id\n }\n }\n", - "added": "2021-07-05T23:29:33.635Z" - }, - "d78565ea5ddbf2b4c6f47b7654cb52c4": { - "referer": "http://localhost:4180/manager/namespace-access", - "query": "\n mutation GrantSAAccess(\n $prodEnvId: ID!\n $resourceId: String!\n $data: UMAPolicyInput!\n ) {\n createUmaPolicy(\n prodEnvId: $prodEnvId\n resourceId: $resourceId\n data: $data\n ) {\n id\n }\n }\n", - "added": "2021-07-06T02:58:10.429Z" - }, - "990f9d0261b747a2d571b0898a9680a8": { - "referer": "http://localhost:4180/manager/namespace-access", - "query": "\n mutation RevokeSAAccess(\n $prodEnvId: ID!\n $resourceId: String!\n $policyId: String!\n ) {\n deleteUmaPolicy(\n prodEnvId: $prodEnvId\n resourceId: $resourceId\n policyId: $policyId\n )\n }\n", - "added": "2021-07-06T02:58:35.159Z" - }, - "48d6d4f62bd088ecee52b2e148bca8d7": { - "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60edd451bcb1bb2c65f30536", - "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n allAccessRequests(where: { isComplete: null }) {\n productEnvironment {\n flow\n credentialIssuer {\n instruction\n }\n }\n }\n }\n", - "added": "2021-07-13T18:01:04.016Z" - }, - "739a3831e5e5df76264c51e002b5ca31": { - "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60edd451bcb1bb2c65f30536", - "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n allAccessRequests(where: { isComplete: null }) {\n id\n productEnvironment {\n flow\n credentialIssuer {\n instruction\n }\n }\n }\n }\n", - "added": "2021-07-13T18:04:08.689Z" - }, - "b2c257133d36336168846295b682372d": { - "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60edd451bcb1bb2c65f30536", - "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n allAccessRequests(where: { isComplete: null }) {\n id\n productEnvironment {\n approval\n credentialIssuer {\n instruction\n }\n }\n }\n }\n", - "added": "2021-07-13T18:06:49.925Z" - }, - "cf3b7dee56b04cfd41b95d196bd4907f": { - "referer": "http://localhost:4180/devportal/access", - "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n allAccessRequests(where: { isComplete: null }) {\n id\n productEnvironment {\n id\n name\n product {\n id\n name\n }\n }\n }\n }\n", - "added": "2021-07-13T18:27:27.458Z" - }, - "e0984d8a4083b05c52e1dbd03c7bd809": { - "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n allAccessRequests(\n where: { isComplete: null, serviceAccess_is_null: true }\n ) {\n id\n productEnvironment {\n id\n name\n product {\n id\n name\n }\n }\n }\n }\n", - "added": "2021-07-13T18:28:21.222Z" - }, - "72b5db83f7405b97305008f03b71ab14": { - "referer": "http://localhost:4180/devportal/access", - "query": "\n mutation CancelAccessRequest($id: ID!) {\n deleteAccessRequest(id: $id) {\n id\n }\n }\n", - "added": "2021-07-13T19:09:22.827Z" - }, - "e67b6f45513db1744aa777371a7c8c4d": { - "referer": "http://localhost:4180/devportal/access", - "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n application {\n name\n }\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n allAccessRequests(\n where: { isComplete: null, serviceAccess_is_null: true }\n ) {\n id\n productEnvironment {\n id\n name\n product {\n id\n name\n }\n }\n }\n }\n", - "added": "2021-07-13T19:33:53.428Z" - }, - "b3703f6e3e6b8ee7176ca9ab756f8dde": { - "referer": "http://localhost:4180/", - "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n application {\n name\n }\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n allAccessRequests(where: { serviceAccess_is_null: true }) {\n id\n productEnvironment {\n id\n name\n product {\n id\n name\n }\n }\n }\n }\n", - "added": "2021-07-13T20:26:37.682Z" - }, - "bce730773f7c2aa9ef4ceb5ea1d8712e": { - "referer": "http://localhost:4180/manager/consumers", - "query": "\n query GetPendingAccessRequests {\n allAccessRequestsByNamespace(where: { isIssued_not: true }) {\n id\n name\n requestor {\n name\n username\n }\n serviceAccess {\n id\n }\n }\n }\n", - "added": "2021-07-13T20:59:20.473Z" - } -} \ No newline at end of file + "21052b1e50cbb20c2edf94571d41481a": { + "query": "query IntrospectionQuery {\n __schema {\n queryType {\n name\n }\n mutationType {\n name\n }\n subscriptionType {\n name\n }\n types {\n ...FullType\n }\n directives {\n name\n description\n locations\n args {\n ...InputValue\n }\n }\n }\n}\n\nfragment FullType on __Type {\n kind\n name\n description\n fields(includeDeprecated: true) {\n name\n description\n args {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n description\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n}\n\nfragment InputValue on __InputValue {\n name\n description\n type {\n ...TypeRef\n }\n defaultValue\n}\n\nfragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}\n" + }, + "cb82824c55ad2de70494934fcd039a48": { + "operation": null, + "query": "{\n allDiscoverableProducts(where: {environments_some: {active: true}}) {\n name\n environments(where: {active: true}) {\n name\n }\n organization {\n name\n title\n }\n }\n myApplications {\n id\n name\n }\n}\n" + }, + "70e5b9605d48517c6789b61e29896e51": { + "query": "\n query GetProducts {\n allDiscoverableProducts {\n id\n name\n environments {\n name\n active\n flow\n \n }\n dataset {\n name\n title\n notes\n sector\n license_title\n view_audience\n security_class\n record_publish_date\n tags\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n" + }, + "34ee04d6606f3146f6ae3efbde3fa8a3": { + "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n }\n" + }, + "869946a26aaff1ff57516f887d259257": { + "query": "\n mutation Add($name: String!, $description: String) {\n createApplication(\n data: {\n name: $name\n description: $description\n }\n ) {\n id\n }\n }\n" + }, + "7fc130b9b34f65c83baa8f8479b304aa": { + "query": "\n mutation Remove($id: ID!) {\n deleteApplication(id: $id) {\n name\n id\n }\n }\n" + }, + "24542e8cf6c82e22dfe190586953c155": { + "query": "\n {\n allDiscoverableContents(where: { isComplete: true }) {\n id\n title\n slug\n description\n }\n }\n " + }, + "5dd78f79f254b02170a335e91e364e4c": { + "query": "\n query Get($id: ID!) {\n allDiscoverableProducts(where: { id: $id }) {\n id\n name\n environments {\n id\n name\n active\n flow\n legal {\n title\n description\n link\n }\n }\n }\n myApplications {\n id\n name\n }\n allTemporaryIdentities {\n id\n userId\n name\n username\n email\n }\n }\n" + }, + "98cbb3dbd8f72cd1d327821fb7b8f5dc": { + "query": "\n mutation AddAccessRequest(\n $name: String!\n $controls: String\n $requestor: ID!\n $applicationId: ID!\n $productEnvironmentId: ID!\n ) {\n createAccessRequest(\n data: {\n name: $name\n controls: $controls\n requestor: { connect: { id: $requestor } }\n application: { connect: { id: $applicationId } }\n productEnvironment: { connect: { id: $productEnvironmentId } }\n }\n ) {\n id\n }\n }\n" + }, + "7810501cf245180d98808ec179840788": { + "query": "\n mutation GenCredential($id: ID!) {\n updateAccessRequest(id: $id, data: { credential: \"NEW\" }) {\n credential\n }\n }\n" + }, + "164cbfac4188793d3974ee08150f2ba9": { + "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n myServiceAccesses(where: { }) {\n id\n name\n active\n application {\n appId\n }\n productEnvironment {\n name\n flow\n credentialIssuer {\n instruction\n }\n product {\n name\n }\n services {\n name\n routes {\n name\n hosts\n methods\n paths\n }\n }\n }\n } \n allAccessRequests(where: { isComplete: null }) {\n id\n name\n isIssued\n application {\n appId\n }\n productEnvironment {\n name\n flow\n credentialIssuer {\n instruction\n }\n product {\n name\n }\n services {\n name\n routes {\n name\n hosts\n methods\n paths\n }\n }\n }\n } \n }\n" + }, + "7e84ad633cdd38bfc769043aa1fb9515": { + "query": "\n query GetEnvironmentsByProduct($id: ID!) {\n Product(where: { id: $id }) {\n name\n environments {\n name\n credentialIssuer {\n id\n resourceType\n }\n }\n }\n }\n" + }, + "0b9b0fc556d52772e77193b6878a6012": { + "query": "\n query GetCredentialIssuers {\n allCredentialIssuers(orderBy: \"name_ASC\") {\n id\n name\n flow\n mode\n owner {\n name\n username\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n" + }, + "7282c6a41c25452fc04ba0a3ca4d7205": { + "query": "\n query GetCredentialIssuer($id: ID!) {\n allCredentialIssuers(where: { id: $id }) {\n id\n name\n flow\n mode\n clientId\n clientRegistration\n oidcDiscoveryUrl\n apiKeyName\n clientRoles\n availableScopes\n resourceType\n owner {\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n" + }, + "7649571474cb2bd3ff1f4361c68d184a": { + "query": "\n mutation CreateAuthzProfile($data: CredentialIssuerCreateInput!) {\n createCredentialIssuer (data: $data) {\n id\n }\n }\n" + }, + "f3c0324ebffe1c696c114ad3ebeb93ee": { + "query": "\n mutation UpdateAuthorization($id: ID!, $clientRoles: String!, $availableScopes: String!, $resourceType: String!) {\n updateCredentialIssuer (id: $id, data: { clientRoles: $clientRoles, availableScopes: $availableScopes, resourceType: $resourceType }) {\n id\n }\n }\n" + }, + "8aae948f7df8007aa9c504b139c00441": { + "query": "\n mutation CreateAuthzProfile($id: ID!) {\n deleteCredentialIssuer (id: $id) {\n id\n }\n }\n" + }, + "9136c4059c9a7a394a0698fe2b4f7690": { + "query": "\n query GetServices {\n allGatewayServices(first: 200) {\n id\n name\n updatedAt\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n routes {\n id\n name\n }\n plugins {\n id\n name\n }\n }\n }\n" + }, + "f190c0aa0b258974dc57e01ad51fc441": { + "query": "\n query GetMetrics($service: String!, $days: [String!]) {\n allMetrics(\n sortBy: day_ASC\n where: {\n query: \"kong_http_requests_hourly_service\"\n day_in: $days\n service: { name_contains: $service }\n }\n ) {\n query\n day\n metric\n values\n service {\n name\n }\n }\n }\n" + }, + "ff1e589711145245d9494f5ae28e8e39": { + "query": "\n query GET($id: ID!) {\n GatewayService(where: { id: $id }) {\n id\n name\n namespace\n tags\n host\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n plugins {\n id\n name\n }\n routes {\n id\n name\n namespace\n }\n updatedAt\n }\n }\n" + }, + "5df41c6ebcd0b801e7768ea3c1252a2e": { + "query": "\n query GET($namespace: String!) {\n allProducts(where: { namespace: $namespace }) {\n id\n name\n description\n organization {\n title\n }\n organizationUnit {\n title\n }\n dataset {\n title\n notes\n sector\n license_title\n }\n environments {\n id\n name\n active\n flow\n services {\n id\n name\n host\n }\n credentialIssuer {\n name\n }\n }\n }\n }\n" + }, + "c9e0e6923870f82ef5f974206adca3c3": { + "query": "\n mutation Add($name: String!) {\n createProduct(data: { name: $name }) {\n id\n name\n }\n }\n" + }, + "d43e71e35248d38a4127741c269bc1b3": { + "query": "\n mutation Add($name: String!, $product: ID!) {\n createEnvironment(\n data: { name: $name, product: { connect: { id: $product } } }\n ) {\n id\n name\n }\n }\n" + }, + "45c0fc9cce5fc64e144c801fb4b23754": { + "query": "\n query GET($search: String!) {\n allDatasets(search: $search) {\n id\n name\n title\n }\n }\n" + }, + "36815dfc37c8cdb868bca959e408a31a": { + "query": "\n query GET {\n allOrganizations(sortBy: name_DESC) {\n id\n name\n }\n }\n" + }, + "5e0b44a99515f4df85fe0cbb48665cc2": { + "query": "\n mutation Update($id: ID!, $data: ProductUpdateInput) {\n updateProduct(id: $id, data: $data) {\n id\n }\n }\n" + }, + "942e09ea1b601bc8b6199c344708766e": { + "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n }\n" + }, + "021c11cfb3125f496fc2494bd75617b4": { + "query": "\n query GET($ns: String!) {\n allGatewayServices(where: { namespace: $ns }) {\n id\n name\n environment {\n id\n }\n }\n }\n" + }, + "2f3bfb09b72c9c8bdcac6e31126b1a73": { + "query": "\n query GET($flow: String) {\n allCredentialIssuers(where: { flow: $flow}) {\n id\n name\n }\n }\n" + }, + "014de0429336e44dec6fe61fec09b23f": { + "query": "\n mutation Update($id: ID!, $data: EnvironmentUpdateInput) {\n updateEnvironment(id: $id, data: $data) {\n name\n id\n }\n }\n" + }, + "e89d3ac8414daa7a223dedb390dde834": { + "query": "\n mutation Remove($id: ID!) {\n deleteEnvironment(id: $id) {\n name\n id\n }\n }\n" + }, + "8cdc18ee9bfecd766bf3a70e7d1dba74": { + "query": "\n mutation Remove($id: ID!) {\n deleteProduct(id: $id) {\n id\n }\n }\n" + }, + "ff9924389e62e9b2eef670aac8cbacd8": { + "query": "\n query GetConsumers {\n allServiceAccesses(first: 200, sortBy: updatedAt_DESC) {\n consumer {\n id\n username\n aclGroups\n customId\n plugins {\n name\n }\n tags\n createdAt\n }\n }\n\n allAccessRequests(where: { isComplete_not: true }) {\n id\n }\n }\n" + }, + "fa715cbb607cacb74fd02264e73e95e0": { + "query": "\n query GetPendingAccessRequests {\n allAccessRequests(where: { isIssued_not: true }) {\n id\n name\n requestor {\n name\n }\n }\n }\n" + }, + "5bed012bae91c559ee46f42a202eb16a": { + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n }\n" + }, + "1d931bda7dd081d70775d8941c649981": { + "query": "\n query GetControlContent {\n allGatewayRoutes {\n name\n extForeignKey\n }\n allGatewayServices {\n name\n extForeignKey\n }\n }\n" + }, + "e5f972a2af707166c38822c721dbb1c0": { + "query": "\n mutation createGatewayConsumerPlugin($id: ID!, $controls: String!) {\n createGatewayConsumerPlugin(id: $id, plugin: $controls) {\n id\n }\n }\n" + }, + "9b19b9946a80f6844b9eb7f0938159e2": { + "query": "\n query GetAccessRequest($id: ID!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n }\n }\n }\n" + }, + "582f2d0d70c73d27ce92360c50b1321f": { + "query": "\n query GetAccessRequests($id: ID!) {\n allAccessRequests(where: { id: $id } ) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n email\n }\n application {\n appId\n name\n }\n serviceAccess {\n consumer {\n username\n customId\n }\n }\n productEnvironment {\n name\n appId\n active\n flow\n credentialIssuer {\n name\n flow\n mode\n availableScopes\n }\n product {\n name\n organization {\n name\n title\n }\n organizationUnit {\n name\n title\n }\n }\n services {\n name\n host\n }\n }\n }\n }\n" + }, + "64b78fbe48840e7f53da945f15fae866": { + "query": "\n query GetProducts {\n allServiceAccesses {\n id\n name\n active\n productEnvironment {\n name\n flow\n credentialIssuer {\n id\n name\n flow\n clientId\n availableScopes\n resourceType\n }\n product {\n name\n }\n }\n }\n }\n" + }, + "712871fae3631b0248b8179dd835576c": { + "query": "\n query GetResources($credIssuerId: ID!, $owner: String!, $resourceType: String) {\n getResourceSet(credIssuerId: $credIssuerId, owner: $owner, type: $resourceType) {\n id\n name\n type\n }\n\n getPermissionTickets(credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n } \n }\n" + }, + "87b01376c9dcbda37902baced783b9fd": { + "query": "\n query GetPermissions($resourceId: String, $credIssuerId: ID!) {\n getPermissionTickets(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n \n CredentialIssuer(where: {id: $credIssuerId}) {\n clientId\n resourceType\n availableScopes\n }\n\n getResourceSet(credIssuerId: $credIssuerId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n }\n" + }, + "30c6496ff07f4cd2dd4cd362b07ef00b": { + "query": "\n query GET {\n allServiceAccesses(orderBy: \"createdAt_DESC\", where: { consumerType: client, namespace_not: null, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n" + }, + "b5285a969b9069defb9b30ae88f98fb4": { + "query": "\n mutation CreateServiceAccount {\n createServiceAccount {\n id\n name\n credentials\n }\n }\n" + }, + "ba4d42582863f7c602e22943d72d6fda": { + "query": "\n mutation DeleteServiceAccount($id: ID!) {\n deleteServiceAccess(id: $id) {\n id\n }\n }\n" + }, + "5e7fd453e8e15d6bae8de06f873cbf1b": { + "query": "\n mutation GrantSAAccess($credIssuerId: ID!, $resourceId: String!, $data: UMAPolicyInput!) {\n createUmaPolicy(credIssuerId: $credIssuerId, resourceId: $resourceId, data: $data) {\n id\n }\n }\n" + }, + "649ead71deeaaa84f086ab4b4ef2d0c7": { + "query": "\n mutation RevokeSAAccess($credIssuerId: ID!, $policyId: String!) {\n deleteUmaPolicy(credIssuerId: $credIssuerId, policyId: $policyId)\n }\n" + }, + "54e201721dd1b4abf27ffc7750e8cdeb": { + "query": "\n mutation GrantUserAccess($credIssuerId: ID!, $data: UMAPermissionTicketInput!) {\n grantPermissions(credIssuerId: $credIssuerId, data: $data) {\n id\n }\n }\n" + }, + "572b4b99eaafbc288d879d0651be430f": { + "query": "\n mutation RevokeAccess($credIssuerId: ID!, $tickets: [String]!) {\n revokePermissions(credIssuerId: $credIssuerId, ids: $tickets)\n }\n" + }, + "1a67f5abb4549467bc88388e673610e2": { + "query": "\n mutation GrantAccess($credIssuerId: ID!, $resourceId: String!, $requesterId: String!, $scopes: [String]!) {\n approvePermissions(credIssuerId: $credIssuerId, resourceId: $resourceId, requesterId: $requesterId, scopes: $scopes)\n }\n" + }, + "6e2213798c7c4afb0d4932731aaee746": { + "query": "\n query GetResources(\n $credIssuerId: ID!\n $owner: String\n $resourceType: String\n ) {\n getResourceSet(\n credIssuerId: $credIssuerId\n owner: $owner\n type: $resourceType\n ) {\n id\n name\n type\n }\n\n getPermissionTickets(credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n }\n" + }, + "98d9f61d8809fcd6092dca49d436ea13": { + "query": "\n query GetPermissions($resourceId: String, $credIssuerId: ID!) {\n getPermissionTickets(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n CredentialIssuerSummary(where: { id: $credIssuerId }) {\n clientId\n resourceType\n availableScopes\n }\n\n getResourceSet(credIssuerId: $credIssuerId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n }\n" + }, + "61e234b0c352d681316ea661ba205396": { + "query": "\n query GetPermissions($resourceId: String, $credIssuerId: ID!) {\n getPermissionTickets(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, credIssuerId: $credIssuerId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n \n getResourceSet(credIssuerId: $credIssuerId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n }\n" + }, + "efaee2304be960c21f4773d243b25022": { + "query": "\n mutation GrantAccess(\n $credIssuerId: ID!\n $resourceId: String!\n $requesterId: String!\n $scopes: [String]!\n ) {\n approvePermissions(\n credIssuerId: $credIssuerId\n resourceId: $resourceId\n requesterId: $requesterId\n scopes: $scopes\n )\n }\n" + }, + "8d9178bbb517008260143d6d1ad3e48e": { + "query": "\n mutation GrantUserAccess(\n $credIssuerId: ID!\n $data: UMAPermissionTicketInput!\n ) {\n grantPermissions(credIssuerId: $credIssuerId, data: $data) {\n id\n }\n }\n" + }, + "f7010c1f5b042f81a053149d6edb7a97": { + "query": "{\n allDiscoverableProducts(where: {environments_some: {active: true}}) {\n name\n environments(where: {active: true}) {\n name\n }\n organization {\n title\n }\n }\n myApplications {\n id\n name\n }\n}\n" + }, + "0f881afe8034802d5fc2a7fdf8ee53b3": { + "query": "{\n allDiscoverableProducts(where: {environments_some: {active: true}}) {\n name\n environments(where: {active: true}) {\n name\n }\n organization {\n title\n name\n }\n }\n myApplications {\n id\n name\n }\n}\n", + "added": "2021-05-01T17:44:10.807Z" + }, + "b3ac613649f34f9ed58e458d8c4e0be8": { + "query": "\n query {\n myApplications {\n id\n appId\n name\n owner {\n name\n }\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-05-01T17:51:07.471Z" + }, + "5561d1afeb4febb005966d7efc725737": { + "query": "\n mutation Update($id: ID!, $active: Boolean) {\n updateEnvironment(id: $id, data: { active: $active }) {\n name\n id\n active\n }\n }\n", + "added": "2021-05-01T17:56:15.429Z" + }, + "e387e4dfe77a0d5207a7364b6ec1f3b8": { + "query": "\n mutation FulfillRequest($id: ID!, $controls: String!) {\n updateAccessRequest(id: $id, data: { isApproved: true, isIssued: true, isComplete: true, controls: $controls }) {\n id\n }\n }\n", + "added": "2021-05-01T17:58:35.147Z" + }, + "fc522a4bb2d6f449ad51225bdd4356a3": { + "query": "\n query GetAccessRequests {\n allAccessRequests(sortBy: [createdAt_DESC]) {\n id\n name\n isApproved\n isIssued\n isComplete\n createdAt\n requestor {\n name\n username\n email\n }\n application {\n name\n }\n serviceAccess {\n id\n }\n productEnvironment {\n name\n flow\n credentialIssuer {\n name\n flow\n mode\n }\n product {\n name\n organization {\n name\n title\n }\n organizationUnit {\n name\n title\n }\n }\n services {\n name\n host\n }\n }\n }\n }\n", + "added": "2021-05-01T17:58:43.603Z" + }, + "270ce32ff612cd6b50909442791afc2c": { + "query": "\n mutation Approve($id: ID!) {\n updateAccessRequest(\n id: $id\n data: { isApproved: false, isComplete: true }\n ) {\n id\n }\n }\n", + "added": "2021-05-01T17:59:33.903Z" + }, + "da4627820b7d026bff6c2e0ad74d6993": { + "referer": "http://localhost:4180/devportal/access", + "query": "\n mutation CancelAccess($id: ID!) {\n deleteServiceAccess(id: $id) {\n id\n }\n }\n", + "added": "2021-05-03T03:51:18.805Z" + }, + "57ccbeb6ab6385f4d9157ec71d0af66b": { + "referer": "http://localhost:4180/manager/services", + "query": "\n query GetServices {\n allGatewayServicesByNamespace(first: 200) {\n id\n name\n updatedAt\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n routes {\n id\n name\n }\n plugins {\n id\n name\n }\n }\n }\n", + "added": "2021-05-03T04:06:59.242Z" + }, + "1b4e9f470ad0cbd09765e61f3a3191f3": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetConsumers {\n allServiceAccessesByNamespace(first: 200, sortBy: updatedAt_DESC) {\n consumer {\n id\n username\n aclGroups\n customId\n plugins {\n name\n }\n tags\n createdAt\n }\n }\n\n allAccessRequestsByNamespace(where: { isComplete_not: true }) {\n id\n }\n }\n", + "added": "2021-05-03T04:15:00.918Z" + }, + "627ab65d15887b4073ae0a42af759ee5": { + "referer": "http://localhost:4180/manager/products", + "query": "\n query GET($namespace: String!) {\n allProductsByNamespace(where: { namespace: $namespace }) {\n id\n name\n description\n organization {\n title\n }\n organizationUnit {\n title\n }\n dataset {\n title\n notes\n sector\n license_title\n }\n environments {\n id\n name\n active\n flow\n services {\n id\n name\n host\n }\n credentialIssuer {\n name\n }\n }\n }\n }\n", + "added": "2021-05-03T04:22:20.770Z" + }, + "ca3396cb109a027586f8a88fcafab178": { + "referer": "http://localhost:4180/manager/products", + "query": "\n query GET {\n allProductsByNamespace {\n id\n name\n description\n organization {\n title\n }\n organizationUnit {\n title\n }\n dataset {\n title\n notes\n sector\n license_title\n }\n environments {\n id\n name\n active\n flow\n services {\n id\n name\n host\n }\n credentialIssuer {\n name\n }\n }\n }\n }\n", + "added": "2021-05-03T04:24:57.504Z" + }, + "ef9b39b6026c6e986bbbde767554b33e": { + "referer": "http://localhost:4180/manager/products", + "query": "\n query GetConsumers {\n allServiceAccessesByNamespace(first: 200) {\n consumer {\n id\n username\n aclGroups\n customId\n plugins {\n name\n }\n tags\n createdAt\n }\n }\n\n allAccessRequestsByNamespace(where: { isComplete_not: true }) {\n id\n }\n }\n", + "added": "2021-05-03T04:40:49.957Z" + }, + "762f7f4b9177e5529396855275a8b882": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetPendingAccessRequests {\n allAccessRequestsByNamespace(where: { isIssued_not: true }) {\n id\n name\n requestor {\n name\n }\n }\n }\n", + "added": "2021-05-03T04:40:56.037Z" + }, + "2cbccd27ed2332806aecc26ceef80130": { + "referer": "http://localhost:4180/manager/poc/service-accounts", + "query": "\n query GET {\n allServiceAccessesByNamespace(orderBy: \"createdAt_DESC\", where: { consumerType: client, namespace_not: null, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-05-03T04:56:47.774Z" + }, + "5d18a6f55463ea75b85fe2be5bc4716e": { + "referer": "http://localhost:4180/manager/poc/namespaces", + "query": "\n query GET {\n allServiceAccessesByNamespace(where: { consumerType: client, namespace_not: null, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-05-03T04:57:01.498Z" + }, + "bcc7104dcd32b65018369a958321227f": { + "referer": "http://localhost:4180/manager/poc/service-accounts", + "query": "\n query GET {\n allServiceAccessesByNamespace(where: { consumerType: client, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-05-03T04:57:58.781Z" + }, + "0f0729e54266db6ca0bf4faab9b669cf": { + "referer": "http://localhost:4180/manager/poc/service-accounts", + "query": "\n query GET {\n allNamespaceServiceAccounts(where: { consumerType: client, application_is_null: true }) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-05-03T05:01:05.655Z" + }, + "66c93863f727adee6fe73f330e337456": { + "referer": "http://localhost:4180/manager/poc/activity", + "query": "\n query GET($first: Int, $skip: Int) {\n allActivities( first:$first, skip: $skip, sortBy: createdAt_DESC) {\n id\n type\n name\n action\n result\n message\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n }\n }\n }\n", + "added": "2021-05-03T05:02:23.332Z" + }, + "ce126df31b7c93cde098d4a414f5e867": { + "referer": "http://localhost:4180/manager/poc/credential-issuers", + "query": "\n query GetCredentialIssuers {\n allCredentialIssuersByNamespace(orderBy: \"name_ASC\") {\n id\n name\n flow\n mode\n owner {\n name\n username\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-03T05:22:03.167Z" + }, + "fa743ec5f90e1b2c1897efdf67f7c8a1": { + "referer": "http://localhost:4180/manager/poc/credential-issuers", + "query": "\n query GetCredentialIssuers {\n allCredentialIssuersByNamespace(first:20) {\n id\n name\n flow\n mode\n owner {\n name\n username\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-03T05:22:43.164Z" + }, + "c039b050c3d605fbb834577d1092c90e": { + "referer": "http://localhost:4180/manager/poc/credential-issuers", + "query": "\n query GetCredentialIssuers {\n allCredentialIssuersByNamespace {\n id\n name\n flow\n mode\n owner {\n name\n username\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-03T05:24:17.055Z" + }, + "fbe730b4789ce693f47d4e2ff3a56bef": { + "referer": "http://localhost:4180/manager/poc/credential-issuers/issuer/608f892d7aa28b3ee36d727c", + "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n clientId\n clientRegistration\n oidcDiscoveryUrl\n apiKeyName\n clientRoles\n availableScopes\n resourceType\n owner {\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-03T05:27:43.598Z" + }, + "afb6752f2404a9e442c8830f47b1290d": { + "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", + "query": "\n query GET($flow: String) {\n allCredentialIssuersByNamespace(where: { flow: $flow}) {\n id\n name\n }\n }\n", + "added": "2021-05-03T21:31:04.049Z" + }, + "18eee5343281a196598afaaa92d07d3a": { + "referer": "http://localhost:4180/devportal/requests/new/608d963a0eac350a840c5032", + "query": "\n query Get($id: ID!) {\n allDiscoverableProducts(where: { id: $id }) {\n id\n name\n environments {\n id\n name\n active\n flow\n additionalDetailsToRequest\n legal {\n title\n description\n link\n }\n }\n }\n myApplications {\n id\n name\n }\n allTemporaryIdentities {\n id\n userId\n name\n username\n email\n }\n }\n", + "added": "2021-05-03T22:27:56.512Z" + }, + "5113980c0b07afe1f73d33e0d910483c": { + "referer": "http://localhost:4180/manager/consumers/60907a60b9eaf28737811b68", + "query": "\n query GetControlContent {\n allGatewayServicesByNamespace {\n name\n extForeignKey\n routes {\n name\n extForeignKey\n }\n }\n }\n", + "added": "2021-05-03T22:43:23.802Z" + }, + "5473c4e41e5fc59d9acd22fbfa413cf0": { + "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", + "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n additionalDetailsToRequest\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n }\n", + "added": "2021-05-03T22:45:25.519Z" + }, + "c6794f580490706e453e4f2122f6b6ef": { + "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", + "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n legal {\n id\n title\n reference\n }\n approval\n additionalDetailsToRequest\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n }\n", + "added": "2021-05-03T22:48:34.130Z" + }, + "938f6cb6a17ca50d63d2e3b07b6ee259": { + "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", + "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n legal {\n id\n title\n reference\n }\n approval\n additionalDetailsToRequest\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n allLegals {\n id\n title\n reference\n }\n }\n", + "added": "2021-05-04T02:37:02.723Z" + }, + "241b17af5a14298c47cd72c45603c2af": { + "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", + "query": "\n query GET($flow: String) {\n allLegals {\n id\n title\n reference\n }\n }\n", + "added": "2021-05-04T02:40:11.782Z" + }, + "1af923113867cf18699bf9fd48ed9c8d": { + "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", + "query": "\n query GET {\n allLegals {\n id\n title\n reference\n }\n }\n", + "added": "2021-05-04T02:40:33.167Z" + }, + "40235fd96287814fea547af0c9421ead": { + "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", + "query": "\n query GET($id: ID!) {\n Environment(where: { id: $id }) {\n id\n name\n active\n flow\n appId\n legal {\n id\n title\n reference\n }\n credentialIssuer {\n id\n }\n approval\n additionalDetailsToRequest\n product {\n name\n namespace\n organization {\n name\n }\n environments {\n name\n id\n }\n }\n services {\n name\n id\n }\n }\n }\n", + "added": "2021-05-04T03:30:56.003Z" + }, + "5454858e3bace6259f2c4cf260d138ae": { + "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", + "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n clientId\n clientSecret\n apiKeyName\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n environmentDetails\n owner {\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-04T04:17:43.565Z" + }, + "88375d8583bdf9825bfeab3b4874e3f8": { + "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", + "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n apiKeyName\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n environmentDetails\n owner {\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-04T04:18:42.431Z" + }, + "1361e818c2e03e1f0217de58ed9512e9": { + "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", + "query": "\n mutation UpdateAuthzProfile($id: ID!, $data: CredentialIssuerUpdateInput!) {\n updateCredentialIssuer (id: $id, data: $data) {\n id\n }\n }\n", + "added": "2021-05-04T04:28:51.350Z" + }, + "c31548fe29ec8603691b8179e7f9e6d9": { + "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", + "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n apiKeyName\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n environmentDetails\n owner {\n id\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-04T04:32:19.426Z" + }, + "b1e92b051e98f539460355efcdec561d": { + "referer": "http://localhost:4180/manager/poc/credential-issuers/60906b21460cd07f48f147e9", + "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n apiKeyName\n clientAuthenticator\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n environmentDetails\n owner {\n id\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-04T04:43:58.652Z" + }, + "c79882ca813f2e28692cf91ced827993": { + "referer": "http://localhost:4180/manager/products/608d963a0eac350a840c5033", + "query": "\n query GET($flow: String) {\n allCredentialIssuersByNamespace(where: { flow: $flow}) {\n id\n name\n environmentDetails\n }\n }\n", + "added": "2021-05-04T05:10:30.959Z" + }, + "430e99af1246c6d0cc496e62f15e3fff": { + "referer": "http://localhost:4180/devportal/poc/resources", + "query": "\n query GetResources($prodEnvId: ID!, $owner: String!, $resourceType: String) {\n getResourceSet(prodEnvId: $prodEnvId, owner: $owner, type: $resourceType) {\n id\n name\n type\n }\n\n getPermissionTickets(prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n } \n }\n", + "added": "2021-05-04T18:03:59.755Z" + }, + "6ca967cf2a262c338e0f78f35df02438": { + "referer": "http://localhost:4180/devportal/access", + "query": "\n query GetEnvironmentsByProduct($id: ID!) {\n Product(where: { id: $id }) {\n name\n environments {\n id\n name\n credentialIssuer {\n id\n resourceType\n }\n }\n }\n }\n", + "added": "2021-05-04T18:12:02.852Z" + }, + "36c7f83dd514eadf3de094f02918036c": { + "referer": "http://localhost:4180/devportal/access/608d963a0eac350a840c5032", + "query": "\n query GetResources(\n $prodEnvId: ID!\n $owner: String\n $resourceType: String\n ) {\n getResourceSet(\n prodEnvId: $prodEnvId\n owner: $owner\n type: $resourceType\n ) {\n id\n name\n type\n }\n\n getPermissionTickets(prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n }\n", + "added": "2021-05-04T18:12:02.935Z" + }, + "447b524ac079e6c372a8ebcfaa41a591": { + "referer": "http://localhost:4180/devportal/access/605e7afa2420523942b05f9a", + "query": "\n query GetPermissions($resourceId: String, $prodEnvId: ID!) {\n getPermissionTickets(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n }\n", + "added": "2021-05-04T18:18:12.090Z" + }, + "34e5387304ea50ceadc7f891e26be174": { + "referer": "http://localhost:4180/devportal/resources/f2dab0ff-f9e9-466d-a115-52010a1bb47d?peid=605e7afb2420523942b05f9b", + "query": "\n query GetPermissions($resourceId: String, $prodEnvId: ID!) {\n getPermissionTickets(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n \n Environment(where: { id: $prodEnvId }) {\n name\n product {\n name\n }\n }\n }\n", + "added": "2021-05-04T18:21:42.374Z" + }, + "43df0bdd0b7d750ddf04ae78b2d4b18b": { + "referer": "http://localhost:4180/devportal/resources/f2dab0ff-f9e9-466d-a115-52010a1bb47d?peid=605e7afb2420523942b05f9b", + "query": "\n mutation RevokeAccess($prodEnvId: ID!, $tickets: [String]!) {\n revokePermissions(prodEnvId: $prodEnvId, ids: $tickets)\n }\n", + "added": "2021-05-04T18:27:04.146Z" + }, + "af9082e55fb2892d63c1ab971a7821d5": { + "referer": "http://localhost:4180/devportal/resources/f2dab0ff-f9e9-466d-a115-52010a1bb47d?peid=605e7afb2420523942b05f9b", + "query": "\n mutation GrantUserAccess(\n $prodEnvId: ID!\n $data: UMAPermissionTicketInput!\n ) {\n grantPermissions(prodEnvId: $prodEnvId, data: $data) {\n id\n }\n }\n", + "added": "2021-05-04T18:30:01.528Z" + }, + "9d48c2d21e114b26b8dd56be972af0f1": { + "referer": "http://localhost:4180/devportal/access/605e7afa2420523942b05f9a", + "query": "\n query GetPermissions($resourceId: String, $prodEnvId: ID!) {\n getPermissionTickets(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPolicies(resourceId: $resourceId, prodEnvId: $prodEnvId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n \n Environment(where: { id: $prodEnvId }) {\n name\n product {\n id\n name\n }\n }\n }\n", + "added": "2021-05-04T18:35:01.952Z" + }, + "ea089f3e222ef310c3240d23ad4f7b11": { + "referer": "http://localhost:4180/devportal/resources/2a9640cc-c89e-44d5-826a-458b4460b91a?peid=606393b601ac0b48cfadcb0c", + "query": "\n mutation GrantSAAccess(\n $prodEnvId: ID!, \n $resourceId: String!, \n $data: UMAPolicyInput!) {\n createUmaPolicy(prodEnvId: $prodEnvId, resourceId: $resourceId, data: $data) {\n id\n }\n }\n", + "added": "2021-05-04T19:15:51.757Z" + }, + "0cb51f5035bc27157165bd5c0a5443b7": { + "referer": "http://localhost:4180/devportal/resources/2a9640cc-c89e-44d5-826a-458b4460b91a?peid=606393b601ac0b48cfadcb0c", + "query": "\n mutation RevokeSAAccess(\n $prodEnvId: ID!, \n $policyId: String!) {\n deleteUmaPolicy(prodEnvId: $prodEnvId, policyId: $policyId)\n}\n", + "added": "2021-05-04T19:28:41.943Z" + }, + "8473d241baf6d7d70afcb43dce12e21f": { + "referer": "http://localhost:4180/manager/requests/609231a5681d3210b7707bbe", + "query": "\n query GetAccessRequest($id: ID!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n }\n }\n }\n }\n", + "added": "2021-05-05T06:06:10.473Z" + }, + "af09f8310abb04f6c77fdd6f1ad8f77c": { + "referer": "http://localhost:4180/manager/requests/609231a5681d3210b7707bbe", + "query": "\n mutation FulfillRequest($id: ID!, $controls: String!) {\n updateAccessRequest(\n id: $id, \n data: { isApproved: true, isIssued: true, isComplete: true, controls: $controls }\n ) {\n id\n }\n }\n", + "added": "2021-05-05T06:18:03.288Z" + }, + "08c0b2daa3e2c3226afe1ac150ae917f": { + "referer": "http://localhost:4180/manager/products", + "query": "\n query GET($id: ID!) {\n Organization(where: { id: $id }) {\n id\n orgUnits {\n name\n id\n }\n }\n }\n", + "added": "2021-05-05T16:06:08.199Z" + }, + "08ea470b98ac8542f103fff6c1f35492": { + "referer": "http://localhost:4180/manager/requests/606418fdb391bd7bfd1d6193", + "query": "\n query GetAccessRequest($id: ID!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n }\n }\n }\n }\n", + "added": "2021-05-05T17:18:37.806Z" + }, + "b1429527c4b1b450366f693247b7120e": { + "referer": "http://localhost:4180/devportal/requests/new/605e7afa2420523942b05f9a", + "query": "\n mutation AddAccessRequest(\n $name: String!\n $controls: String\n $requestor: ID!\n $applicationId: ID!\n $productEnvironmentId: ID!\n $additionalDetails: String\n ) {\n createAccessRequest(\n data: {\n name: $name\n controls: $controls\n additionalDetails: $additionalDetails\n requestor: { connect: { id: $requestor } }\n application: { connect: { id: $applicationId } }\n productEnvironment: { connect: { id: $productEnvironmentId } }\n }\n ) {\n id\n }\n }\n", + "added": "2021-05-05T17:24:39.378Z" + }, + "3f0ca27697b28bff1965c71ba90ce1c7": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetAccessRequest($id: ID!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n }\n", + "added": "2021-05-05T17:31:13.555Z" + }, + "69301c687a618189e45f23f1ef4a39b6": { + "referer": "http://localhost:4180/admin/graphiql", + "query": "mutation ($data: ContentCreateInput) {\n createContent(data: $data) {\n id\n }\n}\n", + "added": "2021-05-27T21:27:58.114Z" + }, + "afc05a67a1753aa00ef23d7da3d25597": { + "referer": "http://localhost:4180/", + "query": "\n query GetNamespaces {\n allNamespaces {\n id\n name\n }\n }\n", + "added": "2021-05-27T21:30:07.761Z" + }, + "cc8bbd6f18ffbbab95c1a7b0caaa52e6": { + "referer": "http://localhost:4180/devportal/access/609c5bf79b8ceca36d31ce95", + "query": "\n query GetResources($prodEnvId: ID!, $resourceType: String) {\n allResourceSets(prodEnvId: $prodEnvId, type: $resourceType) {\n id\n name\n type\n }\n\n allPermissionTickets(prodEnvId: $prodEnvId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n }\n", + "added": "2021-05-27T21:30:43.926Z" + }, + "5742c25e1531eec7ad2c1846fd0649cb": { + "referer": "http://localhost:4180/manager/products", + "query": "\n query GET {\n allProductsByNamespace {\n id\n name\n description\n organization {\n id\n title\n }\n organizationUnit {\n id\n title\n }\n dataset {\n name\n title\n notes\n sector\n license_title\n }\n environments {\n id\n name\n active\n flow\n services {\n id\n name\n host\n }\n credentialIssuer {\n name\n }\n }\n }\n }\n", + "added": "2021-05-28T02:55:37.527Z" + }, + "242f50e1670aa197d678c8fef078a6c5": { + "referer": "http://localhost:4180/devportal/access/609c5bf79b8ceca36d31ce95", + "query": "\n query GetPermissions($resourceId: String!, $prodEnvId: ID!) {\n getPermissionTicketsForResource(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPoliciesForResource(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n \n Environment(where: { id: $prodEnvId }) {\n name\n product {\n id\n name\n }\n }\n }\n", + "added": "2021-05-28T02:59:47.750Z" + }, + "663c0683e24542fa7529a53e31e1e96e": { + "referer": "http://localhost:4180/manager/poc/credential-issuers/609daa674a180ccfaaedbe0b", + "query": "\n query GetCredentialIssuer($id: ID!) {\n CredentialIssuer(where: { id: $id }) {\n id\n name\n flow\n mode\n apiKeyName\n clientAuthenticator\n clientRoles\n availableScopes\n resourceScopes\n resourceType\n resourceAccessScope\n environmentDetails\n owner {\n id\n name\n username\n email\n }\n environments {\n name\n product {\n name\n }\n }\n }\n }\n", + "added": "2021-05-28T03:05:38.617Z" + }, + "c6fff2d82e5ee7d1238f729783a5148f": { + "referer": "http://localhost:4180/devportal/resources/d30f6967-254b-4a19-abb7-abd02f14f23e?peid=609c5bf79b8ceca36d31ce94", + "query": "\n mutation RevokeSAAccess(\n $prodEnvId: ID!, \n $resourceId: String!,\n $policyId: String!) {\n deleteUmaPolicy(prodEnvId: $prodEnvId, resourceId: $resourceId, policyId: $policyId)\n}\n", + "added": "2021-05-28T03:06:08.587Z" + }, + "170f0c898f22eb5819b4b73dd95503ac": { + "referer": "http://localhost:4180/", + "query": "\nmutation CreateNamespace ($name: String!) {\n createNamespace(namespace: $name) {\n id\n name\n }\n}\n", + "added": "2021-05-28T05:25:03.543Z" + }, + "1e983d443f49213db444d1b2a5842865": { + "referer": "http://localhost:4180/", + "query": "\nmutation DeleteNamespace ($name: String!) {\n deleteNamespace(namespace: $name)\n}\n", + "added": "2021-05-28T05:25:29.789Z" + }, + "caadf1abf799958a180d79b8fb3acbcd": { + "referer": "http://localhost:4180/devportal/api-directory/609c1ecb4337bc74fb7205ca", + "query": "\n query Get($id: ID!) {\n allDiscoverableProducts(where: { id: $id }) {\n id\n name\n environments {\n id\n name\n active\n flow\n additionalDetailsToRequest\n legal {\n title\n description\n link\n reference\n }\n credentialIssuer {\n clientAuthenticator\n }\n }\n }\n myApplications {\n id\n name\n }\n mySelf {\n legalsAgreed\n }\n allTemporaryIdentities {\n id\n userId\n name\n username\n email\n }\n }\n", + "added": "2021-05-28T05:43:48.994Z" + }, + "398091e26a0271254962eb43f0345132": { + "referer": "http://localhost:4180/devportal/applications", + "query": "\n mutation Add($name: String!, $description: String) {\n createApplication(data: { name: $name, description: $description }) {\n id\n }\n }\n", + "added": "2021-05-28T05:44:19.642Z" + }, + "02a1cbc8cc2a615ae533f6b82bcabb05": { + "referer": "http://localhost:4180/manager/poc/activity", + "query": "\n query GET($first: Int, $skip: Int) {\n allActivities( first:$first, skip: $skip, sortBy: createdAt_DESC) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", + "added": "2021-05-28T05:46:48.377Z" + }, + "e1b6fe1d5e8a6230fbda9f9afdff5c72": { + "referer": "http://localhost:4180/devportal/requests/new/60a34109b1fd0a61670dcbed", + "query": "\n mutation AddAccessRequest(\n $name: String!\n $controls: String\n $requestor: ID!\n $applicationId: ID!\n $productEnvironmentId: ID!\n $additionalDetails: String\n $acceptLegal: Boolean!\n ) {\n acceptLegal(\n productEnvironmentId: $productEnvironmentId\n acceptLegal: $acceptLegal\n ) {\n legalsAgreed\n }\n\n createAccessRequest(\n data: {\n name: $name\n controls: $controls\n additionalDetails: $additionalDetails\n requestor: { connect: { id: $requestor } }\n application: { connect: { id: $applicationId } }\n productEnvironment: { connect: { id: $productEnvironmentId } }\n }\n ) {\n id\n }\n }\n", + "added": "2021-05-28T05:48:43.618Z" + }, + "d8a1fe9c4cd13380ae02a8a77ed3105e": { + "referer": "http://localhost:4180/manager/namespaces", + "query": "\n query GetConsumers {\n allServiceAccessesByNamespace(first: 200, orderBy: \"updatedAt_DESC\") {\n consumer {\n id\n username\n aclGroups\n customId\n plugins {\n name\n }\n tags\n updatedAt\n }\n application {\n name\n appId\n }\n }\n\n allAccessRequestsByNamespace(where: { isComplete_not: true }) {\n id\n }\n }\n", + "added": "2021-05-28T07:03:39.853Z" + }, + "676efc6d02cd0becae418438ea621d04": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities( sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", + "added": "2021-05-28T07:03:58.064Z" + }, + "c9e3c7d3203e4b3c095e454aa721f901": { + "referer": "http://localhost:4180/manager/requests/60ac9c8d58615f36c3f2f7be", + "query": "\n mutation FulfillRequest($id: ID!, $controls: String!) {\n updateAccessRequest(\n id: $id\n data: {\n isApproved: true\n isIssued: true\n isComplete: true\n controls: $controls\n }\n ) {\n id\n }\n }\n", + "added": "2021-05-28T07:04:00.664Z" + }, + "aa7c2da58bd0ede8b7a28394e915807e": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n }\n", + "added": "2021-05-28T07:04:12.402Z" + }, + "adb2e7dc535971400d2d58af811d5dfd": { + "referer": "http://localhost:4180/manager/consumers/60b05e2d2e7ef60dc63477ed", + "query": "\n query GetControlContent {\n allGatewayServicesByNamespace {\n id\n name\n extForeignKey\n routes {\n id\n name\n extForeignKey\n }\n }\n }\n", + "added": "2021-05-28T07:04:13.819Z" + }, + "e373a8ddc9d8d43ad06d081777d4c1a3": { + "referer": "http://localhost:4180/manager/consumers/60b05e2d2e7ef60dc63477ed", + "query": "\n mutation Remove($consumerId: ID!, $pluginExtForeignKey: String!) {\n deleteGatewayConsumerPlugin(\n id: $consumerId\n pluginExtForeignKey: $pluginExtForeignKey\n ) {\n id\n }\n }\n", + "added": "2021-05-28T07:04:35.684Z" + }, + "b7b196ea3c68aeb81b2d8e7b6bc5d223": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities(sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", + "added": "2021-05-28T08:16:22.934Z" + }, + "317080585c1dbf0467005f8a097a3f1b": { + "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n name\n active\n flow\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-05-31T20:40:38.403Z" + }, + "75a5ca12217591d7a6717438f8b3074c": { + "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n appId\n name\n active\n flow\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-05-31T20:41:59.684Z" + }, + "7aa9867cc96445124e0303cf9f6abb36": { + "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-05-31T20:46:02.815Z" + }, + "c2e7d12c9c1ec1d1e62979e9a04e5ad7": { + "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", + "query": "\n mutation ToggleConsumerACLMembership(\n $prodEnvId: ID!\n $consumerId: ID!\n $group: String!\n $grant: Boolean!\n ) {\n updateConsumerGroupMembership(id: $id)\n }\n", + "added": "2021-05-31T21:16:57.066Z" + }, + "8d4decae694fbb666484100a54f069de": { + "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", + "query": "\n mutation ToggleConsumerACLMembership(\n $prodEnvId: ID!\n $consumerId: ID!\n $group: String!\n $grant: Boolean!\n ) {\n updateConsumerGroupMembership(\n prodEnvId: $prodEnvId\n consumerId: $consumerId\n group: $group\n grant: $grant\n )\n }\n", + "added": "2021-05-31T21:20:57.095Z" + }, + "fc22131d32aa7f5601781ab0446e1f38": { + "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-05-31T22:02:40.182Z" + }, + "b9264ef73166bdb92aca1ee0d1baeb61": { + "referer": "http://localhost:4180/manager/consumers/60b548b107d3401764f3eee8", + "query": "\n query GetConsumerScopesAndRoles(\n $prodEnvId: ID!\n $consumerUsername: ID!\n $consumerType: String!\n ) {\n consumerScopesAndRoles(\n prodEnvId: $prodEnvId\n consumerUsername: $consumerUsername\n consumerType: $consumerType\n ) {\n id\n consumerType\n defaultScopes\n optionalScopes\n clientRoles\n }\n }\n", + "added": "2021-06-01T03:53:38.063Z" + }, + "b3349812a0132f09f7b24833baa00430": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n mutation LinkConsumerToNamespace($username: String!) {\n linkConsumerToNamespace(username: $username)\n }\n", + "added": "2021-06-01T05:04:50.018Z" + }, + "f8cacde2afa67d4526c5911a6c8bbe66": { + "referer": "http://localhost:4180/admin", + "query": "{\n user: authenticatedTemporaryIdentity {\n id\n _label_\n __typename\n }\n}\n", + "added": "2021-06-01T05:16:25.224Z" + }, + "061263c3840dce7943360f72e4984f30": { + "referer": "http://localhost:4180/admin/gateway-consumers?fields=_label_%2Cusername%2CcustomId%2CaclGroups%2Cplugins&!aclGroups_contains_i=%22router_user%22", + "query": "query getList($where: GatewayConsumerWhereInput, $search: String, $sortBy: [SortGatewayConsumersBy!], $first: Int, $skip: Int) {\n allGatewayConsumers(\n where: $where\n search: $search\n sortBy: $sortBy\n first: $first\n skip: $skip\n ) {\n _label_\n id\n username\n customId\n aclGroups\n plugins {\n id\n _label_\n __typename\n }\n __typename\n }\n _allGatewayConsumersMeta(where: $where, search: $search) {\n count\n __typename\n }\n}\n", + "added": "2021-06-01T05:16:28.717Z" + }, + "81d7ccbf028ce2abfe6cda6ea84849cc": { + "referer": "http://localhost:4180/manager/consumers/60b5c8a811dc5e48f6cbd863", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n namespace\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-06-01T06:08:06.801Z" + }, + "a7100c780acc3377cec5f891d0dca3d6": { + "referer": "http://localhost:4180/manager/consumers/60b5c8a811dc5e48f6cbd863", + "query": "\n mutation ToggleConsumerRoles(\n $prodEnvId: ID!\n $consumerId: ID!\n $roleName: String!\n $grant: Boolean!\n ) {\n updateConsumerRoleAssignment(\n prodEnvId: $prodEnvId\n consumerId: $consumerId\n roleName: $roleName\n grant: $grant\n )\n }\n", + "added": "2021-06-01T06:19:54.225Z" + }, + "3f49e70c55b37148d7f10fda3d9cea5a": { + "referer": "http://localhost:4180/manager/consumers/60b5bff29dc26943fb23d4b6", + "query": "\n query GetConsumerScopesAndRoles($prodEnvId: ID!, $consumerUsername: ID!) {\n consumerScopesAndRoles(\n prodEnvId: $prodEnvId\n consumerUsername: $consumerUsername\n ) {\n id\n consumerType\n defaultScopes\n optionalScopes\n clientRoles\n }\n }\n", + "added": "2021-06-01T06:27:34.830Z" + }, + "602067643dc862654d0ce78db879da9d": { + "referer": "http://localhost:4180/manager/consumers/60b5bff29dc26943fb23d4b6", + "query": "\n mutation ToggleConsumerRoles(\n $prodEnvId: ID!\n $consumerUsername: String!\n $roleName: String!\n $grant: Boolean!\n ) {\n updateConsumerRoleAssignment(\n prodEnvId: $prodEnvId\n consumerUsername: $consumerUsername\n roleName: $roleName\n grant: $grant\n )\n }\n", + "added": "2021-06-01T06:49:33.063Z" + }, + "905704bc61eebe0a395cd3c550dbf158": { + "referer": "http://localhost:4180/manager/services/60a7f41eb3c6f22ab455ec1f", + "query": "\n query GET($id: ID!) {\n GatewayService(where: { id: $id }) {\n id\n name\n namespace\n tags\n host\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n plugins {\n id\n name\n }\n routes {\n id\n name\n host\n }\n updatedAt\n }\n }\n", + "added": "2021-06-01T20:45:09.617Z" + }, + "5600ed61fad01032ac67ec031deb1c7c": { + "referer": "http://localhost:4180/manager/services/60a7f41eb3c6f22ab455ec1f", + "query": "\n query GET($id: ID!) {\n GatewayService(where: { id: $id }) {\n id\n name\n namespace\n tags\n host\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n plugins {\n id\n name\n }\n routes {\n id\n name\n hosts\n paths\n methods\n }\n updatedAt\n }\n }\n", + "added": "2021-06-01T20:45:18.071Z" + }, + "cd62d7dd83bb2ede2e38f7bb91000dfe": { + "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60b7e9074b74934a7b6ad728", + "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n allAccessRequests(where: { isComplete: null }) {\n productEnvironment {\n credentialIssuer {\n instruction\n }\n }\n }\n }\n", + "added": "2021-06-02T20:24:42.443Z" + }, + "a4320a0fa32c22f2637725d5e3771ad1": { + "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60b7e9074b74934a7b6ad728", + "query": "\n mutation GenCredential($id: ID!) {\n updateAccessRequest(id: $id, data: { credential: \"NEW\" }) {\n credential\n }\n }\n", + "added": "2021-06-02T20:24:52.161Z" + }, + "cc7ad864ebfca2ba9fd78a713dc6f149": { + "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60b7e9074b74934a7b6ad728", + "query": "\n mutation DeleteNamespace($name: String!) {\n deleteNamespace(namespace: $name)\n }\n", + "added": "2021-06-02T20:26:44.095Z" + }, + "a45894f8cb7cf5ad9abcea1c3d2c4f0a": { + "referer": "http://localhost:4180/manager/namespaces", + "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-06-08T21:39:33.120Z" + }, + "df53970ba9e6fc294d5bf30686437fcb": { + "referer": "http://localhost:4180/manager/poc/service-accounts", + "query": "\n mutation CreateServiceAccount {\n createServiceAccount {\n id\n name\n credentials\n }\n }\n", + "added": "2021-06-08T21:39:34.517Z" + }, + "e81b929f8dc81567309f774bd93ee4ee": { + "referer": "http://localhost:4180/manager/poc/service-accounts", + "query": "\n mutation DeleteServiceAccount($id: ID!) {\n deleteServiceAccess(id: $id) {\n id\n }\n }\n", + "added": "2021-06-08T21:39:55.771Z" + }, + "5918f7500ca71b9bcd5853c3c9da3318": { + "referer": "http://localhost:4180/", + "query": "\n mutation CreateNamespace($name: String!) {\n createNamespace(namespace: $name) {\n id\n name\n }\n }\n", + "added": "2021-06-08T23:23:29.330Z" + }, + "21581865a450d056abc17a0552a75a27": { + "referer": "http://localhost:4180/devportal/resources/28f9bdbd-dbdb-4fe4-b999-3875b6aae17a?peid=609c5bf79b8ceca36d31ce94", + "query": "\n mutation RevokeAccess($prodEnvId: ID!, $resourceId: String!, $tickets: [String]!) {\n revokePermissions(prodEnvId: $prodEnvId, resourceId: $resourceId, ids: $tickets)\n }\n", + "added": "2021-06-10T20:28:29.544Z" + }, + "eb765e1d5ea1ecd8bf0e64f1a1b3bc1d": { + "referer": "http://localhost:4180/manager/products", + "query": "\n query GET {\n allOrganizations(sortBy: name_DESC) {\n id\n name\n title\n }\n }\n", + "added": "2021-06-11T05:54:50.249Z" + }, + "3ff59d8d44a038c1416655d5a89f5a60": { + "referer": "http://localhost:4180/manager/products", + "query": "\n query GET($id: ID!) {\n Organization(where: { id: $id }) {\n id\n orgUnits {\n name\n id\n title\n }\n }\n }\n", + "added": "2021-06-11T05:55:08.602Z" + }, + "34c8c044db0ee8eb0b6808b6b29ba080": { + "referer": "http://localhost:4180/manager/namespaces", + "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n currentNamespace {\n name\n prodEnvId\n }\n }\n", + "added": "2021-06-08T22:56:06.255Z" + }, + "c51c963657cc256fcd69c6a294e9ac5f": { + "referer": "http://localhost:4180/manager/poc/service-accounts", + "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n currentNamespace {\n id\n name\n prodEnvId\n }\n }\n", + "added": "2021-06-08T22:57:49.425Z" + }, + "dd757f543a0e7bcf0989286c6bb219b4": { + "referer": "http://localhost:4180/manager/poc/service-accounts", + "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n currentNamespace {\n id\n name\n scopes\n prodEnvId\n }\n }\n", + "added": "2021-06-08T22:58:28.096Z" + }, + "82ee3140c55e3dcdcc07b487505ee8ae": { + "query": "\n query GET {\n allNamespaceServiceAccounts(\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n currentNamespace {\n id\n name\n scopes {\n name\n }\n prodEnvId\n }\n }\n", + "added": "2021-06-08T22:59:02.979Z" + }, + "5f804316eb2333f7b1eecc24c0a53a2a": { + "referer": "http://localhost:4180/manager/service-accounts", + "query": "\n query GET {\n currentNamespace {\n id\n name\n scopes {\n name\n }\n prodEnvId\n }\n }\n", + "added": "2021-06-14T18:10:33.121Z" + }, + "f68ed4753e35892e58b5857e8639810b": { + "referer": "http://localhost:4180/manager/service-accounts", + "query": "\n query GET {\n allNamespaceServiceAccounts(\n sortBy: ['createdAt_DESC']\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-06-14T18:11:39.697Z" + }, + "09935650941dae862d8890c98e7fd99e": { + "query": "\n query GET {\n allNamespaceServiceAccounts(\n sortBy: ['createdAt_DESC'],\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-06-14T18:11:50.748Z" + }, + "f5b50797d3ca4254bcca638cc47ddee5": { + "query": "\n query GET {\n allNamespaceServiceAccounts(\n orderBy: 'createdAt_DESC',\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-06-14T18:12:22.679Z" + }, + "204058b06089cb6256e511032a2eb7c3": { + "query": "\n query GET {\n allNamespaceServiceAccounts(\n orderBy: 'createdAt_DESC'\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-06-14T18:12:37.683Z" + }, + "57fa329defc7fd4f7ceaa3da860b8752": { + "query": "\n query GET {\n allNamespaceServiceAccounts(\n orderBy: \"createdAt_DESC\"\n where: { consumerType: client, application_is_null: true }\n ) {\n id\n name\n createdAt\n }\n allTemporaryIdentities {\n id\n userId\n }\n }\n", + "added": "2021-06-14T18:13:40.046Z" + }, + "030610692ee4f492182724d9d2651544": { + "referer": "http://localhost:4180/manager/namespace-access", + "query": "\n query currentNamespace {\n name\n scopes\n }\n", + "added": "2021-06-15T21:02:21.221Z" + }, + "cb73913a56ecc7305c3d0add835a07d7": { + "referer": "http://localhost:4180/manager/namespace-access", + "query": "\n query GetPermissions($resourceId: String!, $prodEnvId: ID!) {\n getPermissionTicketsForResource(\n prodEnvId: $prodEnvId\n resourceId: $resourceId\n ) {\n id\n owner\n ownerName\n requester\n requesterName\n resource\n resourceName\n scope\n scopeName\n granted\n }\n\n getUmaPoliciesForResource(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n description\n type\n logic\n decisionStrategy\n owner\n clients\n users\n scopes\n }\n\n getResourceSet(prodEnvId: $prodEnvId, resourceId: $resourceId) {\n id\n name\n type\n resource_scopes {\n name\n }\n }\n\n Environment(where: { id: $prodEnvId }) {\n name\n product {\n id\n name\n }\n }\n }\n", + "added": "2021-06-15T21:21:13.325Z" + }, + "83fc109d25042aa0f3d88f46349776d3": { + "referer": "http://localhost:4180/manager/service-accounts", + "query": "\n mutation CreateServiceAccount($scopes: [String]!) {\n createServiceAccount(scopes: $scopes) {\n id\n name\n credentials\n }\n }\n", + "added": "2021-06-16T05:24:25.027Z" + }, + "61a4f5840dd36e50e94cc5066c739ac9": { + "referer": "http://localhost:4180/manager/service-accounts", + "query": "\n mutation CreateServiceAccount($resourceId: String!, $scopes: [String]!) {\n createServiceAccount(resourceId: $resourceId, scopes: $scopes) {\n id\n name\n credentials\n }\n }\n", + "added": "2021-06-16T05:56:54.209Z" + }, + "b13519f4421dc481f3c23247dcb63d12": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n }\n application {\n name\n }\n serviceAccess {\n id\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities(sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", + "added": "2021-06-24T05:32:11.325Z" + }, + "1f3608db1a9f3c60ea6fc0eaa283c4e6": { + "referer": "http://localhost:4180/manager/requests/609daa814a180ccfaaedbe0d", + "query": "\n query GetBusinessProfile($serviceAccessId: ID!) {\n BusinessProfile(serviceAccessId: $serviceAccessId) {\n user {\n displayName\n firstname\n surname\n email\n isSuspended\n isManagerDisabled\n }\n institution {\n type\n legalName\n address {\n addressLine1\n addressLine2\n city\n postal\n province\n country\n }\n isSuspended\n businessTypeOther\n }\n }\n }\n", + "added": "2021-06-24T05:43:48.010Z" + }, + "e500280ae6fa283e22d0e9095e1174c7": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetPendingAccessRequests {\n allAccessRequestsByNamespace(where: { isIssued_not: true }) {\n id\n name\n requestor {\n name\n username\n }\n }\n }\n", + "added": "2021-06-29T22:14:01.196Z" + }, + "0ebc74e357250ab2d8cdca8afd3aff7e": { + "referer": "http://localhost:4180/manager/requests/60dba098fb76a41bf6a8e74e", + "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n email\n }\n application {\n name\n }\n serviceAccess {\n id\n }\n productEnvironment {\n name\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities(sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", + "added": "2021-06-29T22:42:13.261Z" + }, + "4eccdd9ef225022880be1cc65bfcf5a3": { + "referer": "http://localhost:4180/manager/requests/60dba098fb76a41bf6a8e74e", + "query": "\n query GetAccessRequest($id: ID!, $rid: String!) {\n AccessRequest(where: { id: $id }) {\n id\n name\n isApproved\n isIssued\n controls\n additionalDetails\n createdAt\n requestor {\n name\n username\n email\n }\n application {\n name\n }\n serviceAccess {\n id\n }\n productEnvironment {\n name\n additionalDetailsToRequest\n product {\n name\n }\n credentialIssuer {\n availableScopes\n clientRoles\n }\n }\n }\n\n allActivities(sortBy: createdAt_DESC, where: { refId: $rid }) {\n id\n type\n name\n action\n result\n message\n context\n refId\n namespace\n extRefId\n createdAt\n actor {\n name\n username\n }\n }\n }\n", + "added": "2021-06-29T22:48:41.365Z" + }, + "78b1987847e9566263124c3b003f06bd": { + "referer": "http://localhost:4180/manager/consumers/60b53dbaa6802a80a0ff27dd", + "query": "\n mutation ToggleConsumerScopes(\n $prodEnvId: ID!\n $consumerUsername: String!\n $scopeName: String!\n $grant: Boolean!\n ) {\n updateConsumerScopeAssignment(\n prodEnvId: $prodEnvId\n consumerUsername: $consumerUsername\n scopeName: $scopeName\n grant: $grant\n )\n }\n", + "added": "2021-07-02T23:59:23.643Z" + }, + "7238409bbbc0954b2c00cd03a8162054": { + "referer": "http://localhost:4180/manager/consumers/60b53dbaa6802a80a0ff27dd", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-07-03T00:43:58.265Z" + }, + "1aa9f1d913d81a275515d46091053bec": { + "referer": "http://localhost:4180/manager/consumers/60b53dbaa6802a80a0ff27dd", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allServiceAccesses(where: { consumer: { id: $id } }) {\n application {\n name\n owner {\n username\n }\n }\n }\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-07-03T01:43:27.940Z" + }, + "13758b33b8f2db459bfb37fd789e5309": { + "referer": "http://localhost:4180/manager/consumers/60b5bff29dc26943fb23d4b6", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allServiceAccesses(where: { consumer: { id: $id } }) {\n name\n consumerType\n application {\n appId\n name\n owner {\n username\n }\n }\n }\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-07-03T01:46:50.029Z" + }, + "0d9d51ac4ff398172f53dac66b86e481": { + "referer": "http://localhost:4180/manager/consumers/60ad8e1044cf9a36ef674085", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allServiceAccesses(where: { consumer: { id: $id } }) {\n name\n consumerType\n application {\n appId\n name\n owner {\n name\n username\n email\n }\n }\n }\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-07-03T01:47:50.661Z" + }, + "b35cd8088be328bd3528db32a3ba97cf": { + "referer": "http://localhost:4180/manager/consumers/60ad8e1044cf9a36ef674085", + "query": "\n query GetConsumer($id: ID!) {\n getGatewayConsumerPlugins(id: $id) {\n id\n username\n aclGroups\n customId\n extForeignKey\n namespace\n plugins {\n id\n name\n extForeignKey\n config\n service {\n id\n name\n }\n route {\n id\n name\n }\n }\n tags\n createdAt\n }\n\n allServiceAccesses(where: { consumer: { id: $id } }) {\n name\n consumerType\n application {\n appId\n name\n owner {\n name\n username\n email\n }\n }\n }\n\n allProductsByNamespace {\n id\n name\n environments {\n id\n appId\n name\n active\n flow\n credentialIssuer {\n id\n availableScopes\n clientRoles\n }\n services {\n name\n routes {\n name\n }\n }\n }\n }\n }\n", + "added": "2021-07-03T01:47:59.254Z" + }, + "b2e2c4b6ce7586668c34d3226ae6c5da": { + "referer": "http://localhost:4180/manager/consumers/60b7e9154b74934a7b6ad72a", + "query": "\n mutation updateGatewayConsumerPlugin($id: ID!, $controls: String!) {\n updateGatewayConsumerPlugin(id: $id, plugin: $controls) {\n id\n }\n }\n", + "added": "2021-07-03T03:10:14.327Z" + }, + "7073ccad4a36f9d6b1fae48ad9e00f72": { + "referer": "http://localhost:4180/manager/consumers/60b7e9154b74934a7b6ad72a", + "query": "\n mutation updateGatewayConsumerPlugin(\n $id: ID!\n $pluginExtForeignKey: String!\n $controls: String!\n ) {\n updateGatewayConsumerPlugin(\n id: $id\n pluginExtForeignKey: $pluginExtForeignKey\n plugin: $controls\n ) {\n id\n }\n }\n", + "added": "2021-07-03T03:23:01.128Z" + }, + "a2750969742e7ffa0880f452f82ee58b": { + "referer": "http://localhost:4180/manager/namespace-access", + "query": "\n mutation GrantUserAccess($prodEnvId: ID!, $data: UMAPermissionTicketInput!) {\n grantPermissions(prodEnvId: $prodEnvId, data: $data) {\n id\n }\n }\n", + "added": "2021-07-05T23:29:33.635Z" + }, + "d78565ea5ddbf2b4c6f47b7654cb52c4": { + "referer": "http://localhost:4180/manager/namespace-access", + "query": "\n mutation GrantSAAccess(\n $prodEnvId: ID!\n $resourceId: String!\n $data: UMAPolicyInput!\n ) {\n createUmaPolicy(\n prodEnvId: $prodEnvId\n resourceId: $resourceId\n data: $data\n ) {\n id\n }\n }\n", + "added": "2021-07-06T02:58:10.429Z" + }, + "990f9d0261b747a2d571b0898a9680a8": { + "referer": "http://localhost:4180/manager/namespace-access", + "query": "\n mutation RevokeSAAccess(\n $prodEnvId: ID!\n $resourceId: String!\n $policyId: String!\n ) {\n deleteUmaPolicy(\n prodEnvId: $prodEnvId\n resourceId: $resourceId\n policyId: $policyId\n )\n }\n", + "added": "2021-07-06T02:58:35.159Z" + }, + "48d6d4f62bd088ecee52b2e148bca8d7": { + "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60edd451bcb1bb2c65f30536", + "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n allAccessRequests(where: { isComplete: null }) {\n productEnvironment {\n flow\n credentialIssuer {\n instruction\n }\n }\n }\n }\n", + "added": "2021-07-13T18:01:04.016Z" + }, + "739a3831e5e5df76264c51e002b5ca31": { + "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60edd451bcb1bb2c65f30536", + "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n allAccessRequests(where: { isComplete: null }) {\n id\n productEnvironment {\n flow\n credentialIssuer {\n instruction\n }\n }\n }\n }\n", + "added": "2021-07-13T18:04:08.689Z" + }, + "b2c257133d36336168846295b682372d": { + "referer": "http://localhost:4180/devportal/requests/new/tokens?requestId=60edd451bcb1bb2c65f30536", + "query": "\n query GET {\n allTemporaryIdentities {\n id\n userId\n }\n allAccessRequests(where: { isComplete: null }) {\n id\n productEnvironment {\n approval\n credentialIssuer {\n instruction\n }\n }\n }\n }\n", + "added": "2021-07-13T18:06:49.925Z" + }, + "cf3b7dee56b04cfd41b95d196bd4907f": { + "referer": "http://localhost:4180/devportal/access", + "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n allAccessRequests(where: { isComplete: null }) {\n id\n productEnvironment {\n id\n name\n product {\n id\n name\n }\n }\n }\n }\n", + "added": "2021-07-13T18:27:27.458Z" + }, + "e0984d8a4083b05c52e1dbd03c7bd809": { + "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n allAccessRequests(\n where: { isComplete: null, serviceAccess_is_null: true }\n ) {\n id\n productEnvironment {\n id\n name\n product {\n id\n name\n }\n }\n }\n }\n", + "added": "2021-07-13T18:28:21.222Z" + }, + "72b5db83f7405b97305008f03b71ab14": { + "referer": "http://localhost:4180/devportal/access", + "query": "\n mutation CancelAccessRequest($id: ID!) {\n deleteAccessRequest(id: $id) {\n id\n }\n }\n", + "added": "2021-07-13T19:09:22.827Z" + }, + "e67b6f45513db1744aa777371a7c8c4d": { + "referer": "http://localhost:4180/devportal/access", + "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n application {\n name\n }\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n allAccessRequests(\n where: { isComplete: null, serviceAccess_is_null: true }\n ) {\n id\n productEnvironment {\n id\n name\n product {\n id\n name\n }\n }\n }\n }\n", + "added": "2021-07-13T19:33:53.428Z" + }, + "b3703f6e3e6b8ee7176ca9ab756f8dde": { + "referer": "http://localhost:4180/", + "query": "\n query GetMyServiceAccesses {\n myServiceAccesses {\n id\n name\n active\n application {\n name\n }\n productEnvironment {\n id\n name\n flow\n services {\n id\n name\n }\n credentialIssuer {\n id\n name\n flow\n resourceType\n }\n product {\n id\n name\n }\n }\n }\n allAccessRequests(where: { serviceAccess_is_null: true }) {\n id\n productEnvironment {\n id\n name\n product {\n id\n name\n }\n }\n }\n }\n", + "added": "2021-07-13T20:26:37.682Z" + }, + "bce730773f7c2aa9ef4ceb5ea1d8712e": { + "referer": "http://localhost:4180/manager/consumers", + "query": "\n query GetPendingAccessRequests {\n allAccessRequestsByNamespace(where: { isIssued_not: true }) {\n id\n name\n requestor {\n name\n username\n }\n serviceAccess {\n id\n }\n }\n }\n", + "added": "2021-07-13T20:59:20.473Z" + }, + "91cd73b5151d80a63afa7a479bf765d5": { + "referer": "http://localhost:4180/manager/services", + "query": "\n query GetServices($days: [String!]) {\n allGatewayServicesByNamespace(first: 200) {\n id\n name\n updatedAt\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n routes {\n id\n name\n }\n plugins {\n id\n name\n }\n }\n allMetrics(\n sortBy: day_ASC\n where: { query: \"kong_http_requests_daily_namespace\", day_in: $days }\n ) {\n query\n day\n metric\n values\n }\n }\n", + "added": "2021-08-04T05:31:02.013Z" + }, + "58458d0e1825a63b36f998879a8e0040": { + "referer": "http://localhost:4180/manager/services", + "query": "\n query GET($id: ID!, $days: [String!]) {\n GatewayService(where: { id: $id }) {\n id\n name\n namespace\n tags\n host\n environment {\n id\n name\n active\n flow\n product {\n name\n organization {\n title\n }\n organizationUnit {\n title\n }\n }\n }\n plugins {\n id\n name\n }\n routes {\n id\n name\n hosts\n paths\n methods\n }\n updatedAt\n }\n allMetrics(\n sortBy: day_ASC\n where: { query: \"kong_http_requests_daily_namespace\", day_in: $days }\n ) {\n query\n day\n metric\n values\n }\n }\n", + "added": "2021-08-04T05:31:16.274Z" + } +} From e92abaf96a83a8db5746ce894b795e8b8ecfc295 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Wed, 4 Aug 2021 08:58:15 -0700 Subject: [PATCH 077/155] adj prometheus metrics collection --- feeds/prometheus/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feeds/prometheus/index.js b/feeds/prometheus/index.js index 7dc9450dd..b46fdd58b 100644 --- a/feeds/prometheus/index.js +++ b/feeds/prometheus/index.js @@ -5,7 +5,7 @@ const { portal } = require('../utils/portal'); const queries = [ { - query: 'sum(increase(kong_http_status[60m])) by (service,code)', + query: 'sum(increase(kong_http_status[1d])) by (service,code)', step: 60 * 60 * 24, id: 'kong_http_requests_daily_service_code', }, @@ -20,18 +20,18 @@ const queries = [ id: 'kong_http_requests_hourly_namespace', }, { - query: 'sum(increase(kong_http_status[60m])) by (namespace)', + query: 'sum(increase(kong_http_status[1d])) by (namespace)', step: 60 * 60 * 24, id: 'kong_http_requests_daily_namespace', }, { - query: 'sum(increase(kong_http_status[60m]))', + query: 'sum(increase(kong_http_status[1d]))', step: 60 * 60 * 24, id: 'kong_http_requests_daily', }, { query: - 'sum(increase(konglog_service_consumer_counter[60m])) by (consumer,service)', + 'sum(increase(konglog_service_consumer_counter[1d])) by (consumer,service)', step: 60 * 60 * 24, id: 'konglog_service_consumer_daily', }, From 6fde8e916fa46f677cbea77d93242b075e014a5a Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 4 Aug 2021 10:41:43 -0700 Subject: [PATCH 078/155] adding a namespace service under keystone set of services --- src/services/keystone/namespace.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/services/keystone/namespace.ts diff --git a/src/services/keystone/namespace.ts b/src/services/keystone/namespace.ts new file mode 100644 index 000000000..4b04a2246 --- /dev/null +++ b/src/services/keystone/namespace.ts @@ -0,0 +1,21 @@ +import { Namespace } from './types'; +import { Logger } from '../../logger'; + +const logger = Logger('keystone.user'); + +export async function getCurrentNamespace(context: any): Promise { + const result = await context.executeGraphQL({ + query: `query GetCurrentNamespace { + currentNamespace { + id + name + scopes { + name + } + prodEnvId + } + }`, + }); + logger.debug('Query [getCurrentNamespace] result %j', result); + return JSON.parse(result.data); +} From 92917530ebdd5a622cc1685e92a7ee0dd2b472ed Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 4 Aug 2021 10:46:04 -0700 Subject: [PATCH 079/155] undo last commit --- src/services/keystone/namespace.ts | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 src/services/keystone/namespace.ts diff --git a/src/services/keystone/namespace.ts b/src/services/keystone/namespace.ts deleted file mode 100644 index 4b04a2246..000000000 --- a/src/services/keystone/namespace.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Namespace } from './types'; -import { Logger } from '../../logger'; - -const logger = Logger('keystone.user'); - -export async function getCurrentNamespace(context: any): Promise { - const result = await context.executeGraphQL({ - query: `query GetCurrentNamespace { - currentNamespace { - id - name - scopes { - name - } - prodEnvId - } - }`, - }); - logger.debug('Query [getCurrentNamespace] result %j', result); - return JSON.parse(result.data); -} From 5229f1dbb7b1eac39468d4057edecb560e4c9b18 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 4 Aug 2021 11:03:49 -0700 Subject: [PATCH 080/155] Updated the Kong Service Constructor Defition - Included GWA URL --- src/lists/GatewayConsumer.js | 15 +++++-- src/lists/extensions/ConsumerGroups.ts | 5 ++- src/services/kong/consumer-service.ts | 5 ++- src/services/workflow/apply.ts | 5 ++- .../workflow/create-service-account.ts | 5 ++- src/services/workflow/delete-access.ts | 5 ++- src/services/workflow/generate-credential.ts | 5 ++- src/services/workflow/kong-api-key.ts | 42 ++++++++++++------- .../workflow/link-consumer-to-namespace.ts | 5 ++- 9 files changed, 66 insertions(+), 26 deletions(-) diff --git a/src/lists/GatewayConsumer.js b/src/lists/GatewayConsumer.js index 0263a6e8d..e3c00a2d5 100644 --- a/src/lists/GatewayConsumer.js +++ b/src/lists/GatewayConsumer.js @@ -86,7 +86,10 @@ module.exports = { schema: 'createGatewayConsumerPlugin(id: ID!, plugin: String!): GatewayConsumer', resolver: async (item, args, context, info, { query, access }) => { - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); const feederApi = new FeederService(process.env.FEEDER_URL); const kongConsumerPK = await lookupKongConsumerId( @@ -113,7 +116,10 @@ module.exports = { skipAccessControl: true, }); - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); const feederApi = new FeederService(process.env.FEEDER_URL); const kongConsumerPK = await lookupKongConsumerId( @@ -141,7 +147,10 @@ module.exports = { skipAccessControl: true, }); - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); const feederApi = new FeederService(process.env.FEEDER_URL); const kongConsumerPK = await lookupKongConsumerId( diff --git a/src/lists/extensions/ConsumerGroups.ts b/src/lists/extensions/ConsumerGroups.ts index 192c3cdfd..cc8de0e8f 100644 --- a/src/lists/extensions/ConsumerGroups.ts +++ b/src/lists/extensions/ConsumerGroups.ts @@ -42,7 +42,10 @@ module.exports = { ); const namespace = context.req.user.namespace; - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); args.grant ? await kongApi.assignConsumerACL( diff --git a/src/services/kong/consumer-service.ts b/src/services/kong/consumer-service.ts index 05e246723..bcad0cee5 100644 --- a/src/services/kong/consumer-service.ts +++ b/src/services/kong/consumer-service.ts @@ -39,10 +39,11 @@ const logger = Logger('kong'); export class KongConsumerService { private kongUrl: string; - private gwaUrl: string = process.env.GWA_API_URL; + private gwaUrl: string; - constructor(kongUrl: string) { + constructor(kongUrl: string, gwaUrl: string) { this.kongUrl = kongUrl; + this.gwaUrl = gwaUrl; } public async getConsumerByUsername(username: string) { diff --git a/src/services/workflow/apply.ts b/src/services/workflow/apply.ts index 89884a039..047975ade 100644 --- a/src/services/workflow/apply.ts +++ b/src/services/workflow/apply.ts @@ -218,7 +218,10 @@ async function setupAuthorizationAndEnable( context: any, setup: SetupAuthorizationInput ) { - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); const feederApi = new FeederService(process.env.FEEDER_URL); const flow = setup.flow; diff --git a/src/services/workflow/create-service-account.ts b/src/services/workflow/create-service-account.ts index 86e345532..469df6fd5 100644 --- a/src/services/workflow/create-service-account.ts +++ b/src/services/workflow/create-service-account.ts @@ -75,7 +75,10 @@ export const CreateServiceAccount = async ( const clientId = client.client.clientId; const nickname = client.client.clientId; - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); const consumer = await kongApi.createKongConsumer(nickname, clientId); const consumerPK = await AddClientConsumer( context, diff --git a/src/services/workflow/delete-access.ts b/src/services/workflow/delete-access.ts index 681170939..9c5fac5ba 100644 --- a/src/services/workflow/delete-access.ts +++ b/src/services/workflow/delete-access.ts @@ -19,7 +19,10 @@ import { UMAPolicyService } from '../uma2'; const logger = Logger('wf.DeleteAccess'); export const DeleteAccess = async (context: any, operation: any, keys: any) => { - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); // From the Application, get all the related ServiceAccesses // From these, call Kong and Keycloak to delete them diff --git a/src/services/workflow/generate-credential.ts b/src/services/workflow/generate-credential.ts index c75dbe63a..d65509bbd 100644 --- a/src/services/workflow/generate-credential.ts +++ b/src/services/workflow/generate-credential.ts @@ -133,7 +133,10 @@ export const generateCredential = async ( logger.debug('new-client %j', newClient); - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); const consumer = await kongApi.createKongConsumer(nickname, clientId); const consumerPK = await AddClientConsumer( context, diff --git a/src/services/workflow/kong-api-key.ts b/src/services/workflow/kong-api-key.ts index 4bf48a7d0..cf7b71153 100644 --- a/src/services/workflow/kong-api-key.ts +++ b/src/services/workflow/kong-api-key.ts @@ -1,28 +1,40 @@ -const { addKongConsumer } = require('../../services/keystone') +const { addKongConsumer } = require('../../services/keystone'); -import { KongConsumerService } from '../kong' +import { KongConsumerService } from '../kong'; /** * Steps: * - create the Client in the idP * - create the corresponding Consumer in Kong * - sync the Kong Consumer in KeystoneJS - * - * @param {*} credentialIssuerPK - * @param {*} newClientId + * + * @param {*} credentialIssuerPK + * @param {*} newClientId */ -export async function registerApiKey (context: any, newClientId: string, nickname: string) { - const kongApi = new KongConsumerService(process.env.KONG_URL) +export async function registerApiKey( + context: any, + newClientId: string, + nickname: string +) { + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); - const consumer = await kongApi.createKongConsumer (nickname, newClientId) + const consumer = await kongApi.createKongConsumer(nickname, newClientId); - const apiKey = await kongApi.addKeyAuthToConsumer (consumer.id) + const apiKey = await kongApi.addKeyAuthToConsumer(consumer.id); - const consumerPK = await addKongConsumer(context, nickname, newClientId, consumer.id) + const consumerPK = await addKongConsumer( + context, + nickname, + newClientId, + consumer.id + ); - return { - apiKey, - consumer, - consumerPK - } + return { + apiKey, + consumer, + consumerPK, + }; } diff --git a/src/services/workflow/link-consumer-to-namespace.ts b/src/services/workflow/link-consumer-to-namespace.ts index 0b6fcbecd..68f6f4b98 100644 --- a/src/services/workflow/link-consumer-to-namespace.ts +++ b/src/services/workflow/link-consumer-to-namespace.ts @@ -27,7 +27,10 @@ export const LinkConsumerToNamespace = async ( consumerType: string, consumerUsername?: string ): Promise => { - const kongApi = new KongConsumerService(process.env.KONG_URL); + const kongApi = new KongConsumerService( + process.env.KONG_URL, + process.env.GWA_API_URL + ); const consumerResult = await kongApi.createOrGetConsumer( consumerUsername, null From 845455de12870922b993d973d7d435527272b278 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Wed, 4 Aug 2021 11:20:49 -0700 Subject: [PATCH 081/155] verifying the namespace data after access request change --- src/lists/AccessRequest.js | 4 ++++ src/services/keystone/namespace.ts | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/services/keystone/namespace.ts diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index 726b205f4..01205917f 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -12,6 +12,8 @@ const { const { Apply, Validate } = require('../services/workflow'); +const { getCurrentNamespace } = require('../services/keystone/namespace'); + module.exports = { fields: { name: { @@ -113,6 +115,8 @@ module.exports = { originalInput, updatedItem ); + const namespaceData = await getCurrentNamespace(context); + console.log(JSON.stringify(namespaceData)); }, }, }; diff --git a/src/services/keystone/namespace.ts b/src/services/keystone/namespace.ts new file mode 100644 index 000000000..4b04a2246 --- /dev/null +++ b/src/services/keystone/namespace.ts @@ -0,0 +1,21 @@ +import { Namespace } from './types'; +import { Logger } from '../../logger'; + +const logger = Logger('keystone.user'); + +export async function getCurrentNamespace(context: any): Promise { + const result = await context.executeGraphQL({ + query: `query GetCurrentNamespace { + currentNamespace { + id + name + scopes { + name + } + prodEnvId + } + }`, + }); + logger.debug('Query [getCurrentNamespace] result %j', result); + return JSON.parse(result.data); +} From eba2c7f53837f77e1d44266325ede90573cebca4 Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Wed, 4 Aug 2021 12:53:35 -0700 Subject: [PATCH 082/155] Fix exceptions when crunching namespace content. --- .../components/services-list/metric-graph.tsx | 9 +++--- src/nextapp/components/services-list/utils.ts | 30 ++++++++----------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/nextapp/components/services-list/metric-graph.tsx b/src/nextapp/components/services-list/metric-graph.tsx index e9a65d584..75699c2af 100644 --- a/src/nextapp/components/services-list/metric-graph.tsx +++ b/src/nextapp/components/services-list/metric-graph.tsx @@ -132,10 +132,11 @@ const MetricGraph: React.FC = ({ [0, '0'] ); const peakRequests = round(Number(peak[1]), 2); - const peakDay = format(new Date(peak[0] * 1000), 'LLL d'); - const usage = totalDailyRequests / totalRequests; - const usagePercent = usage * 100; - const color = interpolateRdYlGn(usage); + const peakDay = + peak[1] > 0 ? format(new Date(peak[0] * 1000), 'LLL d') : 'n/a'; + const usage = totalRequests > 0 ? totalDailyRequests / totalRequests : 0; + const usagePercent = usage ? usage * 100 : 0; + const color = usage ? interpolateRdYlGn(usage) : '#eee'; const y = scaleLinear().range([0, height]).domain([0, 1]); if (data.allMetrics) { diff --git a/src/nextapp/components/services-list/utils.ts b/src/nextapp/components/services-list/utils.ts index 69c71aed0..ba3591e0b 100644 --- a/src/nextapp/components/services-list/utils.ts +++ b/src/nextapp/components/services-list/utils.ts @@ -1,5 +1,4 @@ import * as React from 'react'; -import { useAuth } from '@/shared/services/auth'; import format from 'date-fns/format'; import subDays from 'date-fns/subDays'; import times from 'lodash/times'; @@ -19,32 +18,27 @@ export function dateRange(days = 5): string[] { } export function useTotalRequests(data: Query): number { - const { user } = useAuth(); const totalNamespaceRequests: number = React.useMemo(() => { let result = 0; - if (user) { - const { namespace } = user; - + try { if (data?.allMetrics) { data.allMetrics.forEach((m) => { - const metric = JSON.parse(m.metric); - - if (metric.service === namespace) { - const values = JSON.parse(m.values); - const dayValues = values.reduce( - (memo: number, v: number[] | [number, string]) => { - return memo + Number(v[1]); - }, - 0 - ); - result = result + dayValues; - } + const values = JSON.parse(m.values); + const dayValues = values.reduce( + (memo: number, v: number[] | [number, string]) => { + return memo + Number(v[1]); + }, + 0 + ); + result = result + dayValues; }); } + } catch { + return result; } return result; - }, [data, user]); + }, [data]); return totalNamespaceRequests; } From 916faec9c5fbf1c3c075335bb8d9dfd065398544 Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Wed, 4 Aug 2021 12:58:53 -0700 Subject: [PATCH 083/155] Add back the metric object to user namespace comparison. --- src/nextapp/components/services-list/utils.ts | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/nextapp/components/services-list/utils.ts b/src/nextapp/components/services-list/utils.ts index ba3591e0b..1e2d9a1d6 100644 --- a/src/nextapp/components/services-list/utils.ts +++ b/src/nextapp/components/services-list/utils.ts @@ -1,4 +1,5 @@ import * as React from 'react'; +import { useAuth } from '@/shared/services/auth'; import format from 'date-fns/format'; import subDays from 'date-fns/subDays'; import times from 'lodash/times'; @@ -18,27 +19,37 @@ export function dateRange(days = 5): string[] { } export function useTotalRequests(data: Query): number { + const { user } = useAuth(); const totalNamespaceRequests: number = React.useMemo(() => { let result = 0; - try { - if (data?.allMetrics) { - data.allMetrics.forEach((m) => { - const values = JSON.parse(m.values); - const dayValues = values.reduce( - (memo: number, v: number[] | [number, string]) => { - return memo + Number(v[1]); - }, - 0 - ); - result = result + dayValues; - }); + + if (user) { + try { + const { namespace } = user; + + if (data?.allMetrics) { + data.allMetrics.forEach((m) => { + const metric = JSON.parse(m.metric); + + if (metric.namespace === namespace) { + const values = JSON.parse(m.values); + const dayValues = values.reduce( + (memo: number, v: number[] | [number, string]) => { + return memo + Number(v[1]); + }, + 0 + ); + result = result + dayValues; + } + }); + } + } catch { + return result; } - } catch { - return result; } return result; - }, [data]); + }, [data, user]); return totalNamespaceRequests; } From f73d508e2c7a8dd0f8b84a60c65712b55217efb1 Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Wed, 4 Aug 2021 13:00:03 -0700 Subject: [PATCH 084/155] Match mock data. --- src/test/mock-server/data/metrics-data.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/mock-server/data/metrics-data.js b/src/test/mock-server/data/metrics-data.js index 4c63a8023..0a5b2af78 100644 --- a/src/test/mock-server/data/metrics-data.js +++ b/src/test/mock-server/data/metrics-data.js @@ -2,7 +2,7 @@ const namespaceMetrics = [ { query: 'kong_http_requests_daily_namespace', day: '2021-07-10', - metric: JSON.stringify({ service: 'aps-portal' }), + metric: JSON.stringify({ namespace: 'aps-portal' }), values: JSON.stringify([ [1625900400, '0'], [1625904000, '10.29'], @@ -34,7 +34,7 @@ const namespaceMetrics = [ { query: 'kong_http_requests_daily_namespace', day: '2021-07-11', - metric: JSON.stringify({ service: 'aps-portal' }), + metric: JSON.stringify({ namespace: 'aps-portal' }), values: JSON.stringify([ [1625986800, '0'], [1625990400, '12.00836820083682'], @@ -66,7 +66,7 @@ const namespaceMetrics = [ { query: 'kong_http_requests_daily_namespace', day: '2021-07-12', - metric: JSON.stringify({ service: 'aps-portal' }), + metric: JSON.stringify({ namespace: 'aps-portal' }), values: JSON.stringify([ [1626073200, '0'], [1626076800, '200.00836820083682'], @@ -98,7 +98,7 @@ const namespaceMetrics = [ { query: 'kong_http_requests_daily_namespace', day: '2021-07-13', - metric: JSON.stringify({ service: 'aps-portal' }), + metric: JSON.stringify({ namespace: 'aps-portal' }), values: JSON.stringify([ [1626159600, '18.00418410041841'], [1626163200, '18.00418410041841'], @@ -130,7 +130,7 @@ const namespaceMetrics = [ { query: 'kong_http_requests_daily_namespace', day: '2021-07-14', - metric: JSON.stringify({ service: 'aps-portal' }), + metric: JSON.stringify({ namespace: 'aps-portal' }), values: JSON.stringify([ [1626246000, '0'], [1626249600, '0'], From b4cb50b857b680b15f6b8024530cd5ec225a0139 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 5 Aug 2021 08:57:30 -0700 Subject: [PATCH 085/155] fetching the namespace from product --- src/lists/AccessRequest.js | 20 ++++++++++++++++---- src/services/keystone/namespace.ts | 21 --------------------- 2 files changed, 16 insertions(+), 25 deletions(-) delete mode 100644 src/services/keystone/namespace.ts diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index 01205917f..9abfd869a 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -12,7 +12,9 @@ const { const { Apply, Validate } = require('../services/workflow'); -const { getCurrentNamespace } = require('../services/keystone/namespace'); +const { + lookupEnvironmentAndApplicationByAccessRequest, +} = require('../services/keystone/access-request'); module.exports = { fields: { @@ -108,15 +110,25 @@ module.exports = { listKey, fieldPath, // exists only for field hooks }) { + const noauthContext = context + .createContext({ skipAccessControl: true }) + .sudo(); await Apply( - context.createContext({ skipAccessControl: true }), + noauthContext, operation, existingItem, originalInput, updatedItem ); - const namespaceData = await getCurrentNamespace(context); - console.log(JSON.stringify(namespaceData)); + + const accessRequest = await lookupEnvironmentAndApplicationByAccessRequest( + noauthContext, + updatedItem.id + ); + console.log( + 'This is Awesome Result Namespace: ' + + accessRequest.productEnvironment.product.namespace + ); }, }, }; diff --git a/src/services/keystone/namespace.ts b/src/services/keystone/namespace.ts deleted file mode 100644 index 4b04a2246..000000000 --- a/src/services/keystone/namespace.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Namespace } from './types'; -import { Logger } from '../../logger'; - -const logger = Logger('keystone.user'); - -export async function getCurrentNamespace(context: any): Promise { - const result = await context.executeGraphQL({ - query: `query GetCurrentNamespace { - currentNamespace { - id - name - scopes { - name - } - prodEnvId - } - }`, - }); - logger.debug('Query [getCurrentNamespace] result %j', result); - return JSON.parse(result.data); -} From bd4d5e528a7d540ec53856cb699aaedd08e52cf4 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 14:02:05 -0700 Subject: [PATCH 086/155] fix issue with public key --- src/services/keycloak/client-registration-service.ts | 2 +- src/services/keycloak/templates/client-template-client-jwt.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/keycloak/client-registration-service.ts b/src/services/keycloak/client-registration-service.ts index 8734e2a0c..8b6450e18 100644 --- a/src/services/keycloak/client-registration-service.ts +++ b/src/services/keycloak/client-registration-service.ts @@ -62,7 +62,7 @@ export class KeycloakClientRegistrationService { enabled, clientId, attributes: { - 'jwt.credential.certificate': certificate, + 'jwt.credential.public.key': certificate, }, }) : Object.assign(clientTemplateClientSecret, { diff --git a/src/services/keycloak/templates/client-template-client-jwt.ts b/src/services/keycloak/templates/client-template-client-jwt.ts index ebf722b44..5e44623f9 100644 --- a/src/services/keycloak/templates/client-template-client-jwt.ts +++ b/src/services/keycloak/templates/client-template-client-jwt.ts @@ -33,7 +33,7 @@ export const clientTemplateClientJwt = { 'saml.authnstatement': 'false', 'display.on.consent.screen': 'false', 'saml.onetimeuse.condition': 'false', - 'jwt.credential.certificate': '', + 'jwt.credential.public.key': '', }, authenticationFlowBindingOverrides: {}, fullScopeAllowed: false, From ef0c369307e2787b1132513425feea6754d1f689 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 14:52:45 -0700 Subject: [PATCH 087/155] Add support for jwks url --- src/lists/CredentialIssuer.js | 1 + .../authentication.tsx | 5 +- .../pages/devportal/requests/new/[id].tsx | 29 +++- .../keycloak/client-registration-service.ts | 23 ++- src/services/workflow/apply.ts | 10 +- src/services/workflow/client-credentials.ts | 163 ++++++++++++------ src/services/workflow/generate-credential.ts | 2 + src/services/workflow/types.ts | 1 + 8 files changed, 164 insertions(+), 70 deletions(-) diff --git a/src/lists/CredentialIssuer.js b/src/lists/CredentialIssuer.js index eb8dd83de..970c65861 100644 --- a/src/lists/CredentialIssuer.js +++ b/src/lists/CredentialIssuer.js @@ -79,6 +79,7 @@ module.exports = { options: [ { value: 'client-secret', label: 'Client ID and Secret' }, { value: 'client-jwt', label: 'Signed JWT' }, + { value: 'client-jwt-jwks-url', label: 'Signed JWT with JWKS URL' }, ], }, authPlugin: { diff --git a/src/nextapp/components/authorization-profile-controls/authentication.tsx b/src/nextapp/components/authorization-profile-controls/authentication.tsx index 2eca6fc37..c93413dc3 100644 --- a/src/nextapp/components/authorization-profile-controls/authentication.tsx +++ b/src/nextapp/components/authorization-profile-controls/authentication.tsx @@ -102,7 +102,10 @@ const AuthorizationProfileAuthentication: React.FC - Signed JWT + Signed JWT - Generated Key Pair + + + Signed JWT with JWKS URL diff --git a/src/nextapp/pages/devportal/requests/new/[id].tsx b/src/nextapp/pages/devportal/requests/new/[id].tsx index 1f0cda386..576fe23f1 100644 --- a/src/nextapp/pages/devportal/requests/new/[id].tsx +++ b/src/nextapp/pages/devportal/requests/new/[id].tsx @@ -5,6 +5,9 @@ import { Button, Box, Container, + FormLabel, + FormControl, + Input, VStack, Text, Flex, @@ -85,6 +88,9 @@ const NewRequestsPage: React.FC< const selectedEnvironment: Environment = dataset.environments.find( (e) => e.id === environment ); + const clientAuthenticator = + selectedEnvironment?.credentialIssuer?.clientAuthenticator; + const apiTitle = data.allDiscoverableProducts.reduce((memo: string, d) => { if (isEmpty(memo) && d.id !== id) { return 'API'; @@ -128,9 +134,11 @@ const NewRequestsPage: React.FC< : data.allTemporaryIdentities[0].username }`, controls: JSON.stringify({ - clientGenCertificate: - selectedEnvironment?.credentialIssuer?.clientAuthenticator === - 'client-jwt', + clientGenCertificate: clientAuthenticator === 'client-jwt', + jwksUrl: + clientAuthenticator === 'client-jwt-jwks-url' + ? formData.get('jwksUrl') + : '', }), requestor: data.allTemporaryIdentities[0].userId, applicationId: formData.get('applicationId'), @@ -235,6 +243,21 @@ const NewRequestsPage: React.FC< }))} value={environment} /> + {clientAuthenticator == 'client-jwt-jwks-url' && ( + + + + JWKS URL of Public Keys for Signed JWT Authentication + + + + + )} { const body = - authenticator === ClientAuthenticator.ClientJWT + authenticator === ClientAuthenticator.ClientSecret + ? Object.assign(clientTemplateClientSecret, { + enabled, + clientId, + secret: clientSecret, + }) + : authenticator === ClientAuthenticator.ClientJWT ? Object.assign(clientTemplateClientJwt, { enabled, clientId, @@ -65,10 +73,14 @@ export class KeycloakClientRegistrationService { 'jwt.credential.public.key': certificate, }, }) - : Object.assign(clientTemplateClientSecret, { + : Object.assign(clientTemplateClientJwt, { enabled, clientId, - secret: clientSecret, + attributes: { + 'jwt.credential.public.key': '', + 'jwks.url': jwksUrl, + 'use.jwks.url': 'true', + }, }); logger.debug( @@ -92,7 +104,10 @@ export class KeycloakClientRegistrationService { id: response['id'], enabled: response['enabled'], clientId: response['clientId'], - clientSecret: clientSecret, + clientSecret: + authenticator === ClientAuthenticator.ClientSecret + ? clientSecret + : null, registrationAccessToken: response['registrationAccessToken'], } as ClientRegResponse; } diff --git a/src/services/workflow/apply.ts b/src/services/workflow/apply.ts index 09a03a5df..9bfe70722 100644 --- a/src/services/workflow/apply.ts +++ b/src/services/workflow/apply.ts @@ -272,11 +272,6 @@ async function setupAuthorizationAndEnable( token ); - await kcClientService.updateClientRegistration(clientId, { - clientId, - enabled: true, - }); - // Only valid for 'managed' client registration // const kcadminApi = new KeycloakClientService(baseUrl, realm) await kcClientService.login( @@ -289,6 +284,11 @@ async function setupAuthorizationAndEnable( [] ); + await kcClientService.updateClientRegistration(clientId, { + clientId, + enabled: true, + }); + await markActiveTheServiceAccess(context, setup.serviceAccessId); } else if (flow == 'kong-api-key-acl' || flow == 'kong-acl-only') { // update the Consumer ACL group membership to requestDetails.productEnvironment.appId diff --git a/src/services/workflow/client-credentials.ts b/src/services/workflow/client-credentials.ts index 9adedc45c..005403978 100644 --- a/src/services/workflow/client-credentials.ts +++ b/src/services/workflow/client-credentials.ts @@ -1,71 +1,120 @@ -const { lookupCredentialIssuerById, addKongConsumer } = require('../keystone') +const { lookupCredentialIssuerById, addKongConsumer } = require('../keystone'); -import { KeycloakClientRegistrationService, KeycloakClientService, KeycloakTokenService, getOpenidFromIssuer } from '../keycloak' +import { + KeycloakClientRegistrationService, + KeycloakClientService, + KeycloakTokenService, + getOpenidFromIssuer, +} from '../keycloak'; -import {v4 as uuidv4} from 'uuid' +import { v4 as uuidv4 } from 'uuid'; -import { strict as assert } from 'assert' - -import { CredentialIssuer } from '../keystone/types' -import { IssuerEnvironmentConfig, getIssuerEnvironmentConfig, RequestControls } from './types' -import { ClientAuthenticator } from '../keycloak/client-registration-service' +import { strict as assert } from 'assert'; +import { CredentialIssuer } from '../keystone/types'; +import { + IssuerEnvironmentConfig, + getIssuerEnvironmentConfig, + RequestControls, +} from './types'; +import { ClientAuthenticator } from '../keycloak/client-registration-service'; /** * Steps: * - create the Client in the idP * - create the corresponding Consumer in Kong * - sync the Kong Consumer in KeystoneJS - * - * @param {*} credentialIssuerPK - * @param {*} newClientId + * + * @param {*} credentialIssuerPK + * @param {*} newClientId */ -export async function registerClient (context: any, environment: string, credentialIssuerPK: string, controls: RequestControls, newClientId: string) { - - // Find the credential issuer and based on its type, go do the appropriate action - const issuer: CredentialIssuer = await lookupCredentialIssuerById(context, credentialIssuerPK) - - const issuerEnvConfig: IssuerEnvironmentConfig = getIssuerEnvironmentConfig(issuer, environment) - - const openid = await getOpenidFromIssuer(issuerEnvConfig.issuerUrl) - - // token is NULL if 'iat' - // token is retrieved from doing a /token login using the provided client ID and secret if 'managed' - // issuer.initialAccessToken if 'iat' - const kctoksvc = new KeycloakTokenService(openid.issuer) - - const token = issuerEnvConfig.clientRegistration == 'anonymous' ? null : (issuerEnvConfig.clientRegistration == 'managed' ? await kctoksvc.getKeycloakSession(issuerEnvConfig.clientId, issuerEnvConfig.clientSecret) : issuerEnvConfig.initialAccessToken) - - // Find the Client ID for the ProductEnvironment - that will be used to associated the clientRoles - - // lookup Application and use the ID to make sure a corresponding Consumer exists (1 -- 1) - const client = await new KeycloakClientRegistrationService(openid.issuer, token).clientRegistration( issuer.clientAuthenticator, newClientId, uuidv4(), controls.clientCertificate, false) - assert.strictEqual(client.clientId, newClientId) - - return { - openid, - client - } +export async function registerClient( + context: any, + environment: string, + credentialIssuerPK: string, + controls: RequestControls, + newClientId: string +) { + // Find the credential issuer and based on its type, go do the appropriate action + const issuer: CredentialIssuer = await lookupCredentialIssuerById( + context, + credentialIssuerPK + ); + + const issuerEnvConfig: IssuerEnvironmentConfig = getIssuerEnvironmentConfig( + issuer, + environment + ); + + const openid = await getOpenidFromIssuer(issuerEnvConfig.issuerUrl); + + // token is NULL if 'iat' + // token is retrieved from doing a /token login using the provided client ID and secret if 'managed' + // issuer.initialAccessToken if 'iat' + const kctoksvc = new KeycloakTokenService(openid.issuer); + + const token = + issuerEnvConfig.clientRegistration == 'anonymous' + ? null + : issuerEnvConfig.clientRegistration == 'managed' + ? await kctoksvc.getKeycloakSession( + issuerEnvConfig.clientId, + issuerEnvConfig.clientSecret + ) + : issuerEnvConfig.initialAccessToken; + + // Find the Client ID for the ProductEnvironment - that will be used to associated the clientRoles + + // lookup Application and use the ID to make sure a corresponding Consumer exists (1 -- 1) + const client = await new KeycloakClientRegistrationService( + openid.issuer, + token + ).clientRegistration( + issuer.clientAuthenticator, + newClientId, + uuidv4(), + controls.clientCertificate, + controls.jwksUrl, + false + ); + assert.strictEqual(client.clientId, newClientId); + + return { + openid, + client, + }; } - -export async function findClient (context: any, environment: string, credentialIssuerPK: string, clientId: string) { - - // Find the credential issuer and based on its type, go do the appropriate action - const issuer: CredentialIssuer = await lookupCredentialIssuerById(context, credentialIssuerPK) - - const issuerEnvConfig: IssuerEnvironmentConfig = getIssuerEnvironmentConfig(issuer, environment) - - const openid = await getOpenidFromIssuer(issuerEnvConfig.issuerUrl) - - const kcClientService = new KeycloakClientService(openid.issuer, null) - - await kcClientService.login(issuerEnvConfig.clientId, issuerEnvConfig.clientSecret) - - const client = await kcClientService.findByClientId(clientId) - - return { - openid, - client - } +export async function findClient( + context: any, + environment: string, + credentialIssuerPK: string, + clientId: string +) { + // Find the credential issuer and based on its type, go do the appropriate action + const issuer: CredentialIssuer = await lookupCredentialIssuerById( + context, + credentialIssuerPK + ); + + const issuerEnvConfig: IssuerEnvironmentConfig = getIssuerEnvironmentConfig( + issuer, + environment + ); + + const openid = await getOpenidFromIssuer(issuerEnvConfig.issuerUrl); + + const kcClientService = new KeycloakClientService(openid.issuer, null); + + await kcClientService.login( + issuerEnvConfig.clientId, + issuerEnvConfig.clientSecret + ); + + const client = await kcClientService.findByClientId(clientId); + + return { + openid, + client, + }; } diff --git a/src/services/workflow/generate-credential.ts b/src/services/workflow/generate-credential.ts index c75dbe63a..14e39ece7 100644 --- a/src/services/workflow/generate-credential.ts +++ b/src/services/workflow/generate-credential.ts @@ -122,6 +122,8 @@ export const generateCredential = async ( clientSigning.publicKey = publicKey; clientSigning.privateKey = privateKey; controls.clientCertificate = clientSigning.publicKey; + } else { + controls.clientCertificate = null; } const newClient = await registerClient( context, diff --git a/src/services/workflow/types.ts b/src/services/workflow/types.ts index f0656bf24..eca555809 100644 --- a/src/services/workflow/types.ts +++ b/src/services/workflow/types.ts @@ -20,6 +20,7 @@ export interface RequestControls { plugins?: ConsumerPlugin[]; clientCertificate?: string; clientGenCertificate?: boolean; + jwksUrl?: string; } export interface Name { From 6575ad81e5fc35b514edeee12fc4114d3af443dc Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 15:15:35 -0700 Subject: [PATCH 088/155] switch the client id generation --- src/services/workflow/generate-credential.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/workflow/generate-credential.ts b/src/services/workflow/generate-credential.ts index 14e39ece7..4af40ff43 100644 --- a/src/services/workflow/generate-credential.ts +++ b/src/services/workflow/generate-credential.ts @@ -47,7 +47,7 @@ export const generateCredential = async ( ); //const extraIdentifier = uuidv4().replace(/-/g,'').toUpperCase().substr(0, 8) - const clientId = application.appId + '-' + productEnvironment.appId; + const clientId = productEnvironment.appId + '-' + application.appId; const nickname = clientId; From 70df4ef7293dce4cba27456caea4e4e99fffe9ce Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Thu, 5 Aug 2021 16:14:07 -0700 Subject: [PATCH 089/155] Use the peak day based on cumulative daily, not top hourly --- .../components/services-list/metric-graph.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/nextapp/components/services-list/metric-graph.tsx b/src/nextapp/components/services-list/metric-graph.tsx index 75699c2af..4957b334e 100644 --- a/src/nextapp/components/services-list/metric-graph.tsx +++ b/src/nextapp/components/services-list/metric-graph.tsx @@ -37,6 +37,7 @@ import { GatewayService } from '@/shared/types/query.types'; interface DailyDatum { day: string; dayFormatted: string; + dayFormattedShort: string; downtime: number; requests: number[]; total: number; @@ -112,6 +113,7 @@ const MetricGraph: React.FC = ({ return { day, dayFormatted: format(firstDateValue, 'E, LLL do, yyyy'), + dayFormattedShort: format(new Date(firstDateValue), 'LLL d'), downtime, total, peak, @@ -132,8 +134,13 @@ const MetricGraph: React.FC = ({ [0, '0'] ); const peakRequests = round(Number(peak[1]), 2); - const peakDay = - peak[1] > 0 ? format(new Date(peak[0] * 1000), 'LLL d') : 'n/a'; + const peakDay = dailies.reduce((memo, d) => { + if (!memo || d.total > memo.total) { + return d; + } + return memo; + }, null); + const peakDayText = peakDay ? peakDay.dayFormattedShort : 'n/a'; const usage = totalRequests > 0 ? totalDailyRequests / totalRequests : 0; const usagePercent = usage ? usage * 100 : 0; const color = usage ? interpolateRdYlGn(usage) : '#eee'; @@ -167,7 +174,7 @@ const MetricGraph: React.FC = ({ - Peak + Peak Req {peakRequests} @@ -178,7 +185,7 @@ const MetricGraph: React.FC = ({ Peak Day - {peakDay} + {peakDayText} Plugins From b995e3b1c8ebae5c292fd8a78bc5bb69c2bb85f6 Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Thu, 5 Aug 2021 16:20:01 -0700 Subject: [PATCH 090/155] Replace plugins with peak hour/daily instead --- .../components/services-list/metric-graph.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/nextapp/components/services-list/metric-graph.tsx b/src/nextapp/components/services-list/metric-graph.tsx index 4957b334e..a291ab890 100644 --- a/src/nextapp/components/services-list/metric-graph.tsx +++ b/src/nextapp/components/services-list/metric-graph.tsx @@ -174,22 +174,22 @@ const MetricGraph: React.FC = ({ - Peak Req + Peak Hourly {peakRequests} - Total Req - - {numeral(totalDailyRequests).format('0.0a')} - + Peak Daily + {numeral(peakDay.total).format('0.0a')} Peak Day {peakDayText} - Plugins - {service?.plugins.length} + Total Req + + {numeral(totalDailyRequests).format('0.0a')} + From 1fe12693f78d95e01bbe0ca4fdd4744b21a92780 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Thu, 5 Aug 2021 17:58:15 -0700 Subject: [PATCH 091/155] Able to fetch namespace by product and user list of that namespace --- src/lists/AccessRequest.js | 91 +++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 16 deletions(-) diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index 9abfd869a..e51d00b67 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -1,20 +1,34 @@ const { Text, Checkbox, Relationship } = require('@keystonejs/fields'); const { Markdown } = require('@keystonejs/fields-markdown'); - const { byTracking } = require('../components/ByTracking'); - const { atTracking } = require('@keystonejs/list-plugins'); - const { FieldEnforcementPoint, EnforcementPoint, } = require('../authz/enforcement'); - const { Apply, Validate } = require('../services/workflow'); - const { lookupEnvironmentAndApplicationByAccessRequest, } = require('../services/keystone/access-request'); +const { + lookupCredentialIssuerById, +} = require('../services/keystone/credential-issuer'); +const { + doClientLoginForCredentialIssuer, +} = require('../lists/extensions/Common'); +const { UMAResourceRegistrationService } = require('../services/uma2'); +const keystoneApi = require('../services/keystone'); +const { KeycloakPermissionTicketService } = require('../services/keycloak'); +const { + getSuitableOwnerToken, + getEnvironmentContext, + getResourceSets, + getNamespaceResourceSets, + isUserBasedResourceOwners, +} = require('../lists/extensions/Common'); +const { + lookupProductEnvironmentServicesBySlug, +} = require('../services/keystone'); module.exports = { fields: { @@ -110,9 +124,8 @@ module.exports = { listKey, fieldPath, // exists only for field hooks }) { - const noauthContext = context - .createContext({ skipAccessControl: true }) - .sudo(); + const noauthContext = context.createContext({ skipAccessControl: true }); + await Apply( noauthContext, operation, @@ -121,14 +134,60 @@ module.exports = { updatedItem ); - const accessRequest = await lookupEnvironmentAndApplicationByAccessRequest( - noauthContext, - updatedItem.id - ); - console.log( - 'This is Awesome Result Namespace: ' + - accessRequest.productEnvironment.product.namespace - ); + if (operation == 'create') { + const accessRequest = await lookupEnvironmentAndApplicationByAccessRequest( + noauthContext, + updatedItem.id + ); + console.log( + 'This is awesome namespace: ' + + accessRequest.productEnvironment.product.namespace + ); + const productEnvironmentSlug = process.env.GWA_PROD_ENV_SLUG; + + const prodEnv = await lookupProductEnvironmentServicesBySlug( + noauthContext, + productEnvironmentSlug + ); + const envCtx = await getEnvironmentContext(context, prodEnv.id, ''); + + console.log('This is envCtx: ', JSON.stringify(envCtx)); + + const resourceIds = await getResourceSets(envCtx); + const resourcesApi = new UMAResourceRegistrationService( + envCtx.issuerEnvConfig.issuerUrl, + envCtx.accessToken + ); + const namespaces = await resourcesApi.listResourcesByIdList( + resourceIds + ); + const matched = namespaces + .filter( + (ns) => + ns.name == accessRequest.productEnvironment.product.namespace + ) + .map((ns) => ({ + id: ns.id, + name: ns.name, + scopes: ns.resource_scopes, + prodEnvId: prodEnv.id, + })); + namespaceObj = matched[0]; + console.log( + 'This is the same namespace: ' + JSON.stringify(namespaceObj) + ); + const permissionApi = new KeycloakPermissionTicketService( + envCtx.issuerEnvConfig.issuerUrl, + envCtx.accessToken + ); + const params = { resourceId: namespaceObj.id, returnNames: true }; + const permissions = await permissionApi.listPermissions(params); + console.log('Permissions List: ' + JSON.stringify(permissions)); + permissions.forEach((user) => { + console.log('User Name: ' + user.requesterName); + console.log('User Scopes: ' + user.scopeName); + }); + } }, }, }; From a799c988e5c87e1e05869283b44431b84507a6c9 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 18:55:58 -0700 Subject: [PATCH 092/155] upd build --- .github/workflows/ci-build-deploy.yaml | 16 +++++++++++- .../workflows/scripts/feeder-init/legal.yaml | 7 +++++ .../feeder-init/platform-authz-profile.yaml | 26 +++++++++++++++++++ .../scripts/feeder-init/platform-gwa-api.yaml | 14 ++++++++++ .github/workflows/scripts/init.sh | 23 ++++++++++++++++ .github/workflows/scripts/template.py | 8 ++++++ 6 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/scripts/feeder-init/legal.yaml create mode 100644 .github/workflows/scripts/feeder-init/platform-authz-profile.yaml create mode 100644 .github/workflows/scripts/feeder-init/platform-gwa-api.yaml create mode 100755 .github/workflows/scripts/init.sh create mode 100644 .github/workflows/scripts/template.py diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index ac8d44470..1c4b72ec3 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -65,6 +65,16 @@ jobs: id: buildx uses: docker/setup-buildx-action@v1 + - name: 'Seed Data' + run: | + export PATH=$PATH:`pwd`/linux-amd64 + + PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ + OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ + OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ + OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ + .github/workflow/scripts/init.sh + - name: Build uses: docker/build-push-action@v2 with: @@ -214,8 +224,12 @@ jobs: value: 'https://grafana-apps-gov-bc-ca.dev.api.gov.bc.ca' GWA_API_URL: value: 'https://gwa-api-gov-bc-ca.dev.api.gov.bc.ca' + GWA_PROD_ENV_SLUG: + value: 'FB000000' GWA_RES_SVR_CLIENT_ID: - value: 'gwa-api' + value: '${{ secrets.OIDC_CLIENT_ID }}' + GWA_RES_SVR_CLIENT_SECRET: + value: '${{ secrets.OIDC_CLIENT_SECRET }}' KEYCLOAK_AUTH_URL: value: '${{ secrets.KEYCLOAK_AUTH }}' KEYCLOAK_REALM: diff --git a/.github/workflows/scripts/feeder-init/legal.yaml b/.github/workflows/scripts/feeder-init/legal.yaml new file mode 100644 index 000000000..257fc7a0d --- /dev/null +++ b/.github/workflows/scripts/feeder-init/legal.yaml @@ -0,0 +1,7 @@ +entity: Legal +record: + id: "terms-of-use-for-api-gateway-1" + title: "Terms of Use for API Gateway" + link: "https://www2.gov.bc.ca/gov/content/data/open-data/api-terms-of-use-for-ogl-information" + document: terms-of-use + version: 1 diff --git a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml new file mode 100644 index 000000000..08f93b34d --- /dev/null +++ b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml @@ -0,0 +1,26 @@ +entity: CredentialIssuer +record: + id: 'Gateway Services Resource Server' + namespace: platform + description: 'Authorization Profile for protecting the Gateway Services API' + flow: client-credentials + mode: auto + clientAuthenticator: client-secret + authPlugin: jwt-keycloak + clientRoles: [] + availableScopes: [] + resourceType: platform + resourceAccessScope: Namespace.Manage + resourceScopes: + - Namespace.Manage + - Namespace.View + - Access.Manage + - GatewayConfig.Publish + - Content.Publish + owner: awsummer@idir + environmentDetails: + - environment: prod + issuerUrl: '{OIDC_ISSUER}' + clientId: '{OIDC_CLIENT_ID}' + clientSecret: '{OIDC_CLIENT_SECRET}' + clientRegistration: managed diff --git a/.github/workflows/scripts/feeder-init/platform-gwa-api.yaml b/.github/workflows/scripts/feeder-init/platform-gwa-api.yaml new file mode 100644 index 000000000..c60cb50fd --- /dev/null +++ b/.github/workflows/scripts/feeder-init/platform-gwa-api.yaml @@ -0,0 +1,14 @@ +entity: Product +record: + id: 748D98F1F56C + name: Gateway Services API + namespace: platform + environments: + - id: FB000000 + name: prod + active: true + approval: true + flow: client-credentials + legal: terms-of-use-for-api-gateway-1 + services: [] + credentialIssuer: 'Gateway Services Resource Server' diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh new file mode 100755 index 000000000..8338fca80 --- /dev/null +++ b/.github/workflows/scripts/init.sh @@ -0,0 +1,23 @@ +#/bin/bash + +python scripts/template.py scripts/feeder-init/legal.yaml legal.yaml) +python scripts/template.py scripts/feeder-init/platform-authz-profile.yaml platform-authz-profile.yaml +python scripts/template.py scripts/feeder-init/platform-gwa-api.yaml platform-gwa-api.yaml + +while true; do + status=$(curl -o /dev/null -Isw '%{http_code}\n' ${PORTAL_URL}/health) + echo "$status" + if [[ "$status" == "200" ]]; then + echo "Portal is up" + kubectl port-forward service/${SERVICE} 8080:80 & + FWD_PID=$! + curl http://localhost:8080/push -F yaml=@legal.yaml + curl http://localhost:8080/push -F yaml=@platform-authz-profile.yaml + curl http://localhost:8080/push -F yaml=@platform-gwa-api.yaml + kill -9 $FWD_PID + break + else + echo "Waiting for Portal....." + sleep 1m + fi +done diff --git a/.github/workflows/scripts/template.py b/.github/workflows/scripts/template.py new file mode 100644 index 000000000..048a1cb0a --- /dev/null +++ b/.github/workflows/scripts/template.py @@ -0,0 +1,8 @@ + +import sys +import os + +t = open(sys.argv[1]).read().format(**os.environ) + +with open(sys.argv[2], 'w') as outfile: + outfile.write(t) From fc1fe7683c6b9d87f00b5b90f79f4453286a4b4f Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 18:57:38 -0700 Subject: [PATCH 093/155] upd build --- .github/workflows/ci-build-deploy.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 1c4b72ec3..07737db0c 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -69,11 +69,12 @@ jobs: run: | export PATH=$PATH:`pwd`/linux-amd64 + ls -l PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ - .github/workflow/scripts/init.sh + .github/workflows/scripts/init.sh - name: Build uses: docker/build-push-action@v2 From 8f3e245e8ed0d2f2f89b9aa5530afaded1d7b12b Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 18:59:02 -0700 Subject: [PATCH 094/155] tweak init.sh --- .github/workflows/ci-build-deploy.yaml | 8 ++++---- .github/workflows/scripts/init.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 07737db0c..574644c10 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -61,10 +61,6 @@ jobs: restore-keys: | ${{ runner.os }}-buildx- - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v1 - - name: 'Seed Data' run: | export PATH=$PATH:`pwd`/linux-amd64 @@ -76,6 +72,10 @@ jobs: OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ .github/workflows/scripts/init.sh + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v1 + - name: Build uses: docker/build-push-action@v2 with: diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh index 8338fca80..16eca4cac 100755 --- a/.github/workflows/scripts/init.sh +++ b/.github/workflows/scripts/init.sh @@ -1,6 +1,6 @@ #/bin/bash -python scripts/template.py scripts/feeder-init/legal.yaml legal.yaml) +python scripts/template.py scripts/feeder-init/legal.yaml legal.yaml python scripts/template.py scripts/feeder-init/platform-authz-profile.yaml platform-authz-profile.yaml python scripts/template.py scripts/feeder-init/platform-gwa-api.yaml platform-gwa-api.yaml From c692b5c8d5482998f4210e47d606e0c533348de3 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:00:01 -0700 Subject: [PATCH 095/155] tweak ghaction --- .github/workflows/ci-build-deploy.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 574644c10..84788c57e 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -65,12 +65,12 @@ jobs: run: | export PATH=$PATH:`pwd`/linux-amd64 - ls -l + PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ - .github/workflows/scripts/init.sh + (cd .github/workflows/scripts && ./init.sh) - name: Set up Docker Buildx id: buildx From 788b7d17b7465c045cc5f54a6245b0218e366185 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:00:40 -0700 Subject: [PATCH 096/155] tweak ghaction --- .github/workflows/ci-build-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 84788c57e..cb2596bb6 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -70,7 +70,7 @@ jobs: OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ - (cd .github/workflows/scripts && ./init.sh) + (cd .github/workflows && ./init.sh) - name: Set up Docker Buildx id: buildx From ce90b6d1e1bf314441596e1256833ecef6e4ee5b Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:01:10 -0700 Subject: [PATCH 097/155] tweak ghaction --- .github/workflows/scripts/init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh index 16eca4cac..7d900e5eb 100755 --- a/.github/workflows/scripts/init.sh +++ b/.github/workflows/scripts/init.sh @@ -1,4 +1,4 @@ -#/bin/bash +#/bin/bash -e python scripts/template.py scripts/feeder-init/legal.yaml legal.yaml python scripts/template.py scripts/feeder-init/platform-authz-profile.yaml platform-authz-profile.yaml From 27aca9f145ae21b8dfa2b04e08d3bce3b15ab4f9 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:01:45 -0700 Subject: [PATCH 098/155] tweak ghaction --- .github/workflows/ci-build-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index cb2596bb6..b8db816e8 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -70,7 +70,7 @@ jobs: OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ - (cd .github/workflows && ./init.sh) + (cd .github/workflows && ./scripts/init.sh) - name: Set up Docker Buildx id: buildx From fdb2f949552020361cfb75a9b324edcfc7a103f1 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:02:15 -0700 Subject: [PATCH 099/155] tweak ghaction --- .github/workflows/ci-build-deploy.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index b8db816e8..5db546cc0 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -65,12 +65,12 @@ jobs: run: | export PATH=$PATH:`pwd`/linux-amd64 - + cd .github/workflows PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ - (cd .github/workflows && ./scripts/init.sh) + ./scripts/init.sh - name: Set up Docker Buildx id: buildx From 0b1b31d42ab73d4cca847913c2fb42d161b60aa1 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:05:04 -0700 Subject: [PATCH 100/155] tweak ghaction --- .github/workflows/ci-build-deploy.yaml | 1 + .github/workflows/scripts/init.sh | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 5db546cc0..178dbba5b 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -66,6 +66,7 @@ jobs: export PATH=$PATH:`pwd`/linux-amd64 cd .github/workflows + SERVICE=proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-generic-api \ PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh index 7d900e5eb..118bcbe61 100755 --- a/.github/workflows/scripts/init.sh +++ b/.github/workflows/scripts/init.sh @@ -1,4 +1,4 @@ -#/bin/bash -e +#/bin/bash -e +x python scripts/template.py scripts/feeder-init/legal.yaml legal.yaml python scripts/template.py scripts/feeder-init/platform-authz-profile.yaml platform-authz-profile.yaml @@ -11,9 +11,9 @@ while true; do echo "Portal is up" kubectl port-forward service/${SERVICE} 8080:80 & FWD_PID=$! - curl http://localhost:8080/push -F yaml=@legal.yaml - curl http://localhost:8080/push -F yaml=@platform-authz-profile.yaml - curl http://localhost:8080/push -F yaml=@platform-gwa-api.yaml + curl --fail http://localhost:8080/push -F yaml=@legal.yaml + curl --fail http://localhost:8080/push -F yaml=@platform-authz-profile.yaml + curl --fail http://localhost:8080/push -F yaml=@platform-gwa-api.yaml kill -9 $FWD_PID break else From 2220603c52f4f7cefdaa710112bafcf7eb7d0232 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:06:26 -0700 Subject: [PATCH 101/155] tweak ghaction --- .github/workflows/scripts/init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh index 118bcbe61..4a7356abc 100755 --- a/.github/workflows/scripts/init.sh +++ b/.github/workflows/scripts/init.sh @@ -1,4 +1,4 @@ -#/bin/bash -e +x +#/bin/bash +e -x python scripts/template.py scripts/feeder-init/legal.yaml legal.yaml python scripts/template.py scripts/feeder-init/platform-authz-profile.yaml platform-authz-profile.yaml From 68d1fa82406dfbccd2a906e9ce3384ae286e4560 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:08:06 -0700 Subject: [PATCH 102/155] tweak ghaction --- .github/workflows/ci-build-deploy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 178dbba5b..554965b11 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -64,6 +64,7 @@ jobs: - name: 'Seed Data' run: | export PATH=$PATH:`pwd`/linux-amd64 + kubectl get pods cd .github/workflows SERVICE=proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-generic-api \ From ebe598eb5a86d4e77a4afad9e7989fdb0b3eb79a Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:09:35 -0700 Subject: [PATCH 103/155] tweak ghaction --- .github/workflows/scripts/init.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh index 4a7356abc..3bf680ee5 100755 --- a/.github/workflows/scripts/init.sh +++ b/.github/workflows/scripts/init.sh @@ -1,4 +1,4 @@ -#/bin/bash +e -x +#/bin/bash -e -x python scripts/template.py scripts/feeder-init/legal.yaml legal.yaml python scripts/template.py scripts/feeder-init/platform-authz-profile.yaml platform-authz-profile.yaml @@ -11,6 +11,7 @@ while true; do echo "Portal is up" kubectl port-forward service/${SERVICE} 8080:80 & FWD_PID=$! + echo "Port forwarded ${SERVICE} with $FWD_PID" curl --fail http://localhost:8080/push -F yaml=@legal.yaml curl --fail http://localhost:8080/push -F yaml=@platform-authz-profile.yaml curl --fail http://localhost:8080/push -F yaml=@platform-gwa-api.yaml From 07e74146822e28193bb0656f7813614cc1815148 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:14:28 -0700 Subject: [PATCH 104/155] tweak ghaction --- .github/workflows/nohup.out | 9 +++++++++ .github/workflows/scripts/init.sh | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/nohup.out diff --git a/.github/workflows/nohup.out b/.github/workflows/nohup.out new file mode 100644 index 000000000..80caff80f --- /dev/null +++ b/.github/workflows/nohup.out @@ -0,0 +1,9 @@ +error: You must be logged in to the server (Unauthorized) +error: You must be logged in to the server (Unauthorized) +error: You must be logged in to the server (Unauthorized) +Forwarding from 127.0.0.1:8080 -> 6000 +Forwarding from [::1]:8080 -> 6000 +Forwarding from 127.0.0.1:8080 -> 6000 +Forwarding from [::1]:8080 -> 6000 +Forwarding from 127.0.0.1:8080 -> 6000 +Forwarding from [::1]:8080 -> 6000 diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh index 3bf680ee5..2b1f22225 100755 --- a/.github/workflows/scripts/init.sh +++ b/.github/workflows/scripts/init.sh @@ -9,13 +9,13 @@ while true; do echo "$status" if [[ "$status" == "200" ]]; then echo "Portal is up" - kubectl port-forward service/${SERVICE} 8080:80 & + nohup kubectl port-forward service/${SERVICE} 8080:80 & FWD_PID=$! echo "Port forwarded ${SERVICE} with $FWD_PID" curl --fail http://localhost:8080/push -F yaml=@legal.yaml curl --fail http://localhost:8080/push -F yaml=@platform-authz-profile.yaml curl --fail http://localhost:8080/push -F yaml=@platform-gwa-api.yaml - kill -9 $FWD_PID + kill $FWD_PID break else echo "Waiting for Portal....." From c845d72bf46fc1c058dba17349b9fb9759844e30 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:15:39 -0700 Subject: [PATCH 105/155] tweak ghaction --- .github/workflows/scripts/init.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh index 2b1f22225..c0898f5b2 100755 --- a/.github/workflows/scripts/init.sh +++ b/.github/workflows/scripts/init.sh @@ -12,6 +12,7 @@ while true; do nohup kubectl port-forward service/${SERVICE} 8080:80 & FWD_PID=$! echo "Port forwarded ${SERVICE} with $FWD_PID" + sleep 5 curl --fail http://localhost:8080/push -F yaml=@legal.yaml curl --fail http://localhost:8080/push -F yaml=@platform-authz-profile.yaml curl --fail http://localhost:8080/push -F yaml=@platform-gwa-api.yaml From 784670f04c26379653aad304e823f3336b7a1962 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:17:54 -0700 Subject: [PATCH 106/155] tweak ghaction --- .../workflows/scripts/feeder-init/platform-authz-profile.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml index 08f93b34d..d488b2501 100644 --- a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml +++ b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml @@ -17,7 +17,7 @@ record: - Access.Manage - GatewayConfig.Publish - Content.Publish - owner: awsummer@idir + owner: acope@idir environmentDetails: - environment: prod issuerUrl: '{OIDC_ISSUER}' From 2e9e1c9fd4d9ddcdc95849129dc1237ee502449a Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:23:05 -0700 Subject: [PATCH 107/155] tweak ghaction --- .github/workflows/scripts/init.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scripts/init.sh b/.github/workflows/scripts/init.sh index c0898f5b2..dd0f941b7 100755 --- a/.github/workflows/scripts/init.sh +++ b/.github/workflows/scripts/init.sh @@ -13,9 +13,9 @@ while true; do FWD_PID=$! echo "Port forwarded ${SERVICE} with $FWD_PID" sleep 5 - curl --fail http://localhost:8080/push -F yaml=@legal.yaml - curl --fail http://localhost:8080/push -F yaml=@platform-authz-profile.yaml - curl --fail http://localhost:8080/push -F yaml=@platform-gwa-api.yaml + curl --fail -v http://localhost:8080/push -F yaml=@legal.yaml + curl --fail -v http://localhost:8080/push -F yaml=@platform-authz-profile.yaml + curl --fail -v http://localhost:8080/push -F yaml=@platform-gwa-api.yaml kill $FWD_PID break else From 843918fdc147e8cb558244d6249c0703370fce05 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:26:20 -0700 Subject: [PATCH 108/155] tweak ghaction --- .github/workflows/ci-build-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 554965b11..6959aabf9 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -67,7 +67,7 @@ jobs: kubectl get pods cd .github/workflows - SERVICE=proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-generic-api \ + SERVICE=proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-feeder-generic-api \ PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ From 75c6052dc745b7aeb371f74c3e36f6602ecda1cb Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:26:27 -0700 Subject: [PATCH 109/155] tweak ghaction --- .github/workflows/ci-build-deploy.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 6959aabf9..166d3f2a4 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -64,7 +64,6 @@ jobs: - name: 'Seed Data' run: | export PATH=$PATH:`pwd`/linux-amd64 - kubectl get pods cd .github/workflows SERVICE=proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-feeder-generic-api \ From c2be320b190b6a727d37fccc25912f6701561b1b Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:38:59 -0700 Subject: [PATCH 110/155] tweak ghaction --- .../workflows/scripts/feeder-init/platform-authz-profile.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml index d488b2501..8f8028dd2 100644 --- a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml +++ b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml @@ -17,7 +17,7 @@ record: - Access.Manage - GatewayConfig.Publish - Content.Publish - owner: acope@idir + owner: user_api-owner environmentDetails: - environment: prod issuerUrl: '{OIDC_ISSUER}' From 2d71ec419eb58050cfd686e1b0f48dbf4f6dcf6f Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:51:46 -0700 Subject: [PATCH 111/155] fix clientId --- src/services/workflow/generate-credential.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/services/workflow/generate-credential.ts b/src/services/workflow/generate-credential.ts index 4af40ff43..ed2a059fb 100644 --- a/src/services/workflow/generate-credential.ts +++ b/src/services/workflow/generate-credential.ts @@ -46,7 +46,6 @@ export const generateCredential = async ( requestDetails.application.id ); - //const extraIdentifier = uuidv4().replace(/-/g,'').toUpperCase().substr(0, 8) const clientId = productEnvironment.appId + '-' + application.appId; const nickname = clientId; @@ -100,8 +99,7 @@ export const generateCredential = async ( requestDetails.application.id ); - //const extraIdentifier = uuidv4().replace(/-/g,'').toUpperCase().substr(0, 8) - const clientId = application.appId + '-' + productEnvironment.appId; + const clientId = productEnvironment.appId + '-' + application.appId; const nickname = clientId; From 72aaf7f89afd5aac261dcf0aac93d03df9e12331 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:52:22 -0700 Subject: [PATCH 112/155] upd init --- .github/workflows/ci-build-deploy.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index 166d3f2a4..ce4eaf47c 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -61,18 +61,6 @@ jobs: restore-keys: | ${{ runner.os }}-buildx- - - name: 'Seed Data' - run: | - export PATH=$PATH:`pwd`/linux-amd64 - - cd .github/workflows - SERVICE=proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-feeder-generic-api \ - PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ - OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ - OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ - OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ - ./scripts/init.sh - - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v1 @@ -266,3 +254,15 @@ jobs: " > values.yaml helm repo add bcgov http://bcgov.github.io/helm-charts helm upgrade --install proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-routes -f values.yaml bcgov/ocp-route + + - name: 'Seed Data' + run: | + export PATH=$PATH:`pwd`/linux-amd64 + + cd .github/workflows + SERVICE=proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-feeder-generic-api \ + PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ + OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ + OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ + OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ + ./scripts/init.sh From db222f255a4ad90aadcd446c66303859b62ed389 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 19:59:54 -0700 Subject: [PATCH 113/155] try exact username match --- src/services/keycloak/user-service.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/services/keycloak/user-service.ts b/src/services/keycloak/user-service.ts index b914e115d..ba86bb5c3 100644 --- a/src/services/keycloak/user-service.ts +++ b/src/services/keycloak/user-service.ts @@ -17,7 +17,10 @@ export class KeycloakUserService { public async lookupUserByUsername(username: string) { logger.debug('[lookupUserByUsername] %s', username); - const users = await this.kcAdminClient.users.find({ username: username }); + const users = await this.kcAdminClient.users.find({ + exact: true, + username: username, + }); logger.debug('[lookupUserByUsername] : %j', users); assert.strictEqual(users.length, 1, 'User not found ' + username); return users[0].id; From 8d62d23a3420007948311de6e7a336d6f2acad6a Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 20:18:15 -0700 Subject: [PATCH 114/155] remove irrelevant files --- .github/workflows/ci-build-deploy.yaml | 2 +- .github/workflows/nohup.out | 9 --------- .../scripts/feeder-init/platform-authz-profile.yaml | 1 + 3 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 .github/workflows/nohup.out diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index ce4eaf47c..df9604fd7 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -232,7 +232,7 @@ jobs: command: - sh - -c - - 'state=$(curl -XGET -m 2 --silent -f -H \"Accept: application/json\" http://localhost:3000/health | jq -r \".loading | ascii_downcase\"); if [ \"$loading\" == \"true\" ]; then exit 1; fi' + - 'state=$(curl -XGET -m 2 --silent -f -H \"Accept: application/json\" http://localhost:3000/health | jq -r \".loading | ascii_downcase\"); if [ ! \"$status\" == \"ready\" ]; then exit 1; fi' " > values.yaml diff --git a/.github/workflows/nohup.out b/.github/workflows/nohup.out deleted file mode 100644 index 80caff80f..000000000 --- a/.github/workflows/nohup.out +++ /dev/null @@ -1,9 +0,0 @@ -error: You must be logged in to the server (Unauthorized) -error: You must be logged in to the server (Unauthorized) -error: You must be logged in to the server (Unauthorized) -Forwarding from 127.0.0.1:8080 -> 6000 -Forwarding from [::1]:8080 -> 6000 -Forwarding from 127.0.0.1:8080 -> 6000 -Forwarding from [::1]:8080 -> 6000 -Forwarding from 127.0.0.1:8080 -> 6000 -Forwarding from [::1]:8080 -> 6000 diff --git a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml index 8f8028dd2..4ab0acbd7 100644 --- a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml +++ b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml @@ -17,6 +17,7 @@ record: - Access.Manage - GatewayConfig.Publish - Content.Publish + - CredentialIssuer.Admin owner: user_api-owner environmentDetails: - environment: prod From e6baf29d3c9962baf6e0cf8a0786df06e83766c2 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 5 Aug 2021 20:18:57 -0700 Subject: [PATCH 115/155] remove irrelevant files --- .../workflows/scripts/feeder-init/platform-authz-profile.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml index 4ab0acbd7..db6272aff 100644 --- a/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml +++ b/.github/workflows/scripts/feeder-init/platform-authz-profile.yaml @@ -8,7 +8,7 @@ record: clientAuthenticator: client-secret authPlugin: jwt-keycloak clientRoles: [] - availableScopes: [] + availableScopes: [Sample.*] resourceType: platform resourceAccessScope: Namespace.Manage resourceScopes: From 180e7bbcf3585af0c6a8324eda82f2303eaf5bad Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Fri, 6 Aug 2021 11:19:54 -0700 Subject: [PATCH 116/155] Update ci-build-deploy.yaml --- .github/workflows/ci-build-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index df9604fd7..db58bdbfe 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -232,7 +232,7 @@ jobs: command: - sh - -c - - 'state=$(curl -XGET -m 2 --silent -f -H \"Accept: application/json\" http://localhost:3000/health | jq -r \".loading | ascii_downcase\"); if [ ! \"$status\" == \"ready\" ]; then exit 1; fi' + - 'state=$(curl -XGET -m 2 --silent -f -H \"Accept: application/json\" http://localhost:3000/health | jq -r \".status | ascii_downcase\"); if [ ! \"$state\" == \"ready\" ]; then exit 1; fi' " > values.yaml From 933439ec6bf6c4b77041a4fc197371d13bf40a53 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Fri, 6 Aug 2021 11:47:19 -0700 Subject: [PATCH 117/155] Update ci-build-deploy.yaml --- .github/workflows/ci-build-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index db58bdbfe..ae87a9cdd 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -232,7 +232,7 @@ jobs: command: - sh - -c - - 'state=$(curl -XGET -m 2 --silent -f -H \"Accept: application/json\" http://localhost:3000/health | jq -r \".status | ascii_downcase\"); if [ ! \"$state\" == \"ready\" ]; then exit 1; fi' + - 'state=\$(curl -XGET -m 2 --silent -f -H \"Accept: application/json\" http://localhost:3000/health | jq -r \".status | ascii_downcase\"); if [ ! \"\$state\" == \"ready\" ]; then exit 1; fi' " > values.yaml From 4f8a431e8820a58e4730878da010a1b7d4c266a5 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 6 Aug 2021 13:25:52 -0700 Subject: [PATCH 118/155] created a custom query to fetch user details by username --- src/lists/AccessRequest.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index e51d00b67..eb3469b22 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -30,6 +30,8 @@ const { lookupProductEnvironmentServicesBySlug, } = require('../services/keystone'); +const KeystoneService = require('../services/keystone'); + module.exports = { fields: { name: { @@ -183,9 +185,28 @@ module.exports = { const params = { resourceId: namespaceObj.id, returnNames: true }; const permissions = await permissionApi.listPermissions(params); console.log('Permissions List: ' + JSON.stringify(permissions)); - permissions.forEach((user) => { + permissions.forEach(async (user) => { console.log('User Name: ' + user.requesterName); console.log('User Scopes: ' + user.scopeName); + const userResult = await noauthContext.executeGraphQL({ + query: `query GetUserWithUsername($username: String!) { + allUsers(where: {username: $username}) { + id + name + username + email + } + }`, + variables: { username: user.requesterName }, + }); + + console.log( + 'User object errors: ' + JSON.stringify(userResult.errors) + ); + console.log( + 'This is the user object: ' + + JSON.stringify(userResult.data.allUsers) + ); }); } }, From 0fe87aa09e86a58cef19c396746c473bf7b52a93 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Fri, 6 Aug 2021 16:15:46 -0700 Subject: [PATCH 119/155] Added config to test the email notifications --- .github/workflows/ci-build-deploy.yaml | 6 + src/lists/AccessRequest.js | 50 ++++--- src/services/keystone/index.ts | 7 +- src/services/keystone/user.ts | 103 ++++++++++----- .../notification/notification.service.ts | 125 +++++++++--------- 5 files changed, 174 insertions(+), 117 deletions(-) diff --git a/.github/workflows/ci-build-deploy.yaml b/.github/workflows/ci-build-deploy.yaml index ac8d44470..1f9aea118 100644 --- a/.github/workflows/ci-build-deploy.yaml +++ b/.github/workflows/ci-build-deploy.yaml @@ -222,6 +222,12 @@ jobs: value: '${{ secrets.KEYCLOAK_REALM }}' COOKIE_SECURE: value: 'true' + EMAIL_ENABLED: + value: 'true' + EMAIL_FROM: + value: 'API.Services.Portal@gov.bc.ca' + EMAIL_HOST: + value: 'apps.smtp.gov.bc.ca' readinessProbe: exec: diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index eb3469b22..ba21872ad 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -28,6 +28,7 @@ const { } = require('../lists/extensions/Common'); const { lookupProductEnvironmentServicesBySlug, + lookupUserByUsername, } = require('../services/keystone'); const KeystoneService = require('../services/keystone'); @@ -185,28 +186,35 @@ module.exports = { const params = { resourceId: namespaceObj.id, returnNames: true }; const permissions = await permissionApi.listPermissions(params); console.log('Permissions List: ' + JSON.stringify(permissions)); - permissions.forEach(async (user) => { - console.log('User Name: ' + user.requesterName); - console.log('User Scopes: ' + user.scopeName); - const userResult = await noauthContext.executeGraphQL({ - query: `query GetUserWithUsername($username: String!) { - allUsers(where: {username: $username}) { - id - name - username - email - } - }`, - variables: { username: user.requesterName }, - }); - - console.log( - 'User object errors: ' + JSON.stringify(userResult.errors) - ); - console.log( - 'This is the user object: ' + - JSON.stringify(userResult.data.allUsers) + const { + NotificationService, + } = require('../services/notification/notification.service'); + const NotifyConfig = { + enabled: true, + secure: true, + from: process.env.EMAIL_FROM || '', + host: process.env.EMAIL_HOST || '', + port: process.env.EMAIL_PORT || 25, + user: process.env.EMAIL_USER || '', + pass: process.env.EMAIL_PASS || '', + }; + const nc = new NotificationService(NotifyConfig); + permissions.forEach(async (perm) => { + const userDetails = await lookupUserByUsername( + context, + perm.requesterName ); + nc.notify( + { email: 'nithu.everyyear@gmail.com', name: 'Nithin Kuruba' }, + { template: 'email-template', subject: 'Yeah!' } + ) + .then((answer) => { + console.log('DONE!'); + console.log('ANSWER = ' + JSON.stringify(answer)); + }) + .catch((err) => { + console.log('ERROR ! ' + err); + }); }); } }, diff --git a/src/services/keystone/index.ts b/src/services/keystone/index.ts index 88b6608ab..6f9dcf38b 100644 --- a/src/services/keystone/index.ts +++ b/src/services/keystone/index.ts @@ -39,4 +39,9 @@ export { markActiveTheServiceAccess, } from './service-access'; -export { lookupUserLegals, updateUserLegalAccept, LegalAgreed } from './user'; +export { + lookupUserLegals, + updateUserLegalAccept, + LegalAgreed, + lookupUserByUsername, +} from './user'; diff --git a/src/services/keystone/user.ts b/src/services/keystone/user.ts index ac6529471..4ba0e27d2 100644 --- a/src/services/keystone/user.ts +++ b/src/services/keystone/user.ts @@ -1,53 +1,88 @@ -import { Logger } from "../../logger" -import { User } from "./types" +import { Logger } from '../../logger'; +import { User } from './types'; const assert = require('assert').strict; -const logger = Logger('keystone.user') +const logger = Logger('keystone.user'); export interface LegalAgreed { - reference: string, - agreedTimestamp: string + reference: string; + agreedTimestamp: string; } -export async function lookupUserLegals (context: any, id: string) : Promise { - const result = await context.executeGraphQL({ - query: `query GetUser($id: ID!) { +export async function lookupUserLegals( + context: any, + id: string +): Promise { + const result = await context.executeGraphQL({ + query: `query GetUser($id: ID!) { User(where: {id: $id}) { legalsAgreed } }`, - variables: { id: id }, - }) - logger.debug("Query [lookupUserLegals] result %j", result) - assert.strictEqual(result.data.User != null, true, "User not found") - result.data.User.legalsAgreed == null && (result.data.User.legalsAgreed = '[]') - return JSON.parse(result.data.User.legalsAgreed) + variables: { id: id }, + }); + logger.debug('Query [lookupUserLegals] result %j', result); + assert.strictEqual(result.data.User != null, true, 'User not found'); + result.data.User.legalsAgreed == null && + (result.data.User.legalsAgreed = '[]'); + return JSON.parse(result.data.User.legalsAgreed); } -export async function updateUserLegalAccept (context: any, userId: string, legalReference: string) : Promise { - - const legalsAgreed : LegalAgreed[] = await lookupUserLegals (context, userId) +export async function updateUserLegalAccept( + context: any, + userId: string, + legalReference: string +): Promise { + const legalsAgreed: LegalAgreed[] = await lookupUserLegals(context, userId); - if (legalsAgreed.filter(ag => ag.reference === legalReference).length == 0) { - legalsAgreed.push({ - reference: legalReference, - agreedTimestamp: new Date().toISOString() - }) - const result = await context.executeGraphQL({ - query: `mutation UpdateUserWithLegalAccept($userId: ID!, $legalsAgreed: String!) { + if ( + legalsAgreed.filter((ag) => ag.reference === legalReference).length == 0 + ) { + legalsAgreed.push({ + reference: legalReference, + agreedTimestamp: new Date().toISOString(), + }); + const result = await context.executeGraphQL({ + query: `mutation UpdateUserWithLegalAccept($userId: ID!, $legalsAgreed: String!) { updateUser(id: $userId, data: { legalsAgreed: $legalsAgreed } ) { legalsAgreed } }`, - variables: { userId, legalsAgreed: JSON.stringify(legalsAgreed) }, - }) - logger.debug("[updateUserLegalAccept] RESULT %j", result) - assert.strictEqual(result.data.updateUser != null, true, "Failed to update legal terms for user") - return JSON.parse(result.data.updateUser.legalsAgreed) - } else { - logger.warn("[updateUserLegalAccept] User '%s' already agreed to '%s' terms", userId, legalReference) - return legalsAgreed - } + variables: { userId, legalsAgreed: JSON.stringify(legalsAgreed) }, + }); + logger.debug('[updateUserLegalAccept] RESULT %j', result); + assert.strictEqual( + result.data.updateUser != null, + true, + 'Failed to update legal terms for user' + ); + return JSON.parse(result.data.updateUser.legalsAgreed); + } else { + logger.warn( + "[updateUserLegalAccept] User '%s' already agreed to '%s' terms", + userId, + legalReference + ); + return legalsAgreed; + } } - +export async function lookupUserByUsername( + context: any, + username: string +): Promise { + const result = await context.executeGraphQL({ + query: `query GetUserWithUsername($username: String!) { + allUsers(where: {username: $username}) { + id + name + username + email + } + }`, + variables: { username: username }, + }); + logger.debug('Query [lookupUserByUsername] result %j', result); + assert.strictEqual(result.data.allUsers.length, 1, 'UserNotFound'); + return result.data.allUsers; +} diff --git a/src/services/notification/notification.service.ts b/src/services/notification/notification.service.ts index 79fc7d063..99c34f56e 100644 --- a/src/services/notification/notification.service.ts +++ b/src/services/notification/notification.service.ts @@ -1,74 +1,77 @@ -import fs from 'fs' -import path from 'path' +import fs from 'fs'; +import path from 'path'; -import nodemailer from 'nodemailer' +import nodemailer from 'nodemailer'; -import { Logger } from '../../logger' +import { Logger } from '../../logger'; -import { NotificationConfig, EmailNotification, User } from './config' +import { NotificationConfig, EmailNotification, User } from './config'; -import { ConfigService } from '../bceid/config.service' +import { ConfigService } from '../bceid/config.service'; export class NotificationService { - private notifyConfig: NotificationConfig; - constructor(private readonly config: ConfigService) { - this.notifyConfig = this.config.getConfig().notification; + private notifyConfig: NotificationConfig; + constructor(private readonly config: NotificationConfig) { + this.notifyConfig = this.config; + } + + private templateToContent(to: User, templateName: string) { + const template = fs.readFileSync( + path.resolve(__dirname, `templates/${templateName}.html`), + 'utf8' + ); + return template.replace('{{name}}', to.name); + } + + public async notify(user: User, email: EmailNotification) { + if (!this.notifyConfig.enabled) { + return; } - private templateToContent (to: User, templateName: string) { - const template = fs.readFileSync(path.resolve(__dirname, `templates/${templateName}.html`), 'utf8'); - return template.replace("{{name}}", to.name); + this.logger.verbose('Notification triggered', user); + + //we don't notify the active user at all as they made the change + var emailContent = this.templateToContent(user, email.template); + + var transportOpts = { + host: this.notifyConfig.host, + port: this.notifyConfig.port, + secure: this.notifyConfig.secure, + tls: { rejectUnauthorized: true }, + auth: { user: null as any, pass: null as any }, + }; + + if (!this.notifyConfig.secure) { + transportOpts['tls'] = { + rejectUnauthorized: false, + }; } - public async notify (user: User, email: EmailNotification) { - if (!this.notifyConfig.enabled){ - return; - } - - this.logger.verbose("Notification triggered", user); - - //we don't notify the active user at all as they made the change - var emailContent = this.templateToContent(user, email.template); - - var transportOpts = { - host: this.notifyConfig.host, - port: this.notifyConfig.port, - secure: this.notifyConfig.secure, - tls: { rejectUnauthorized: true }, - auth: { user: null as any, pass: null as any } - } - - if (!this.notifyConfig.secure){ - transportOpts['tls'] = { - rejectUnauthorized: false - } - } - - if ( (this.notifyConfig.user !== "") && (this.notifyConfig.pass !== "") ){ - transportOpts['auth'] = { - user: this.notifyConfig.user, - pass: this.notifyConfig.pass - } - } - - var transporter = nodemailer.createTransport(transportOpts); - - var mailOptions = { - from: this.notifyConfig.from, - to: user.email, - subject: email.subject, - html: emailContent - }; - - return transporter.sendMail(mailOptions) - // , function (error : any, info : any) { - // if (error) { - // this.logger.error("Error sending email to " + mailOptions.to, error); - // return; - // } - // this.logger.debug("Email sent: " + info.response); - // }) + if (this.notifyConfig.user !== '' && this.notifyConfig.pass !== '') { + transportOpts['auth'] = { + user: this.notifyConfig.user, + pass: this.notifyConfig.pass, + }; } - logger = Logger('notification.service') + var transporter = nodemailer.createTransport(transportOpts); + + var mailOptions = { + from: this.notifyConfig.from, + to: user.email, + subject: email.subject, + html: emailContent, + }; + + return transporter.sendMail(mailOptions); + // , function (error : any, info : any) { + // if (error) { + // this.logger.error("Error sending email to " + mailOptions.to, error); + // return; + // } + // this.logger.debug("Email sent: " + info.response); + // }) + } + + logger = Logger('notification.service'); } From adf3c9f7f042323c586f2d8c3967a494f5de7dad Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sat, 7 Aug 2021 08:53:59 -0700 Subject: [PATCH 120/155] updated the notification service constructor definition to use config service and cleaned up access request list --- src/lists/AccessRequest.js | 31 ++++--------------- .../notification/notification.service.ts | 4 +-- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index ba21872ad..c3ac659e3 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -10,28 +10,21 @@ const { Apply, Validate } = require('../services/workflow'); const { lookupEnvironmentAndApplicationByAccessRequest, } = require('../services/keystone/access-request'); -const { - lookupCredentialIssuerById, -} = require('../services/keystone/credential-issuer'); -const { - doClientLoginForCredentialIssuer, -} = require('../lists/extensions/Common'); const { UMAResourceRegistrationService } = require('../services/uma2'); -const keystoneApi = require('../services/keystone'); const { KeycloakPermissionTicketService } = require('../services/keycloak'); const { - getSuitableOwnerToken, getEnvironmentContext, getResourceSets, - getNamespaceResourceSets, - isUserBasedResourceOwners, } = require('../lists/extensions/Common'); const { lookupProductEnvironmentServicesBySlug, lookupUserByUsername, } = require('../services/keystone'); -const KeystoneService = require('../services/keystone'); +const { ConfigService } = require('../services/bceid/config.service'); +const { + NotificationService, +} = require('../services/notification/notification.service'); module.exports = { fields: { @@ -186,22 +179,10 @@ module.exports = { const params = { resourceId: namespaceObj.id, returnNames: true }; const permissions = await permissionApi.listPermissions(params); console.log('Permissions List: ' + JSON.stringify(permissions)); - const { - NotificationService, - } = require('../services/notification/notification.service'); - const NotifyConfig = { - enabled: true, - secure: true, - from: process.env.EMAIL_FROM || '', - host: process.env.EMAIL_HOST || '', - port: process.env.EMAIL_PORT || 25, - user: process.env.EMAIL_USER || '', - pass: process.env.EMAIL_PASS || '', - }; - const nc = new NotificationService(NotifyConfig); + const nc = new NotificationService(new ConfigService()); permissions.forEach(async (perm) => { const userDetails = await lookupUserByUsername( - context, + noauthContext, perm.requesterName ); nc.notify( diff --git a/src/services/notification/notification.service.ts b/src/services/notification/notification.service.ts index 99c34f56e..a9e8df72f 100644 --- a/src/services/notification/notification.service.ts +++ b/src/services/notification/notification.service.ts @@ -11,8 +11,8 @@ import { ConfigService } from '../bceid/config.service'; export class NotificationService { private notifyConfig: NotificationConfig; - constructor(private readonly config: NotificationConfig) { - this.notifyConfig = this.config; + constructor(private readonly config: ConfigService) { + this.notifyConfig = this.config.getConfig().notification; } private templateToContent(to: User, templateName: string) { From aab190d6be8934eb963d33dad0d4893d43120cd2 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sun, 8 Aug 2021 22:21:50 -0700 Subject: [PATCH 121/155] moved config service out of bcied to use it as common code and created an custom query to fetch users by namespace for sending notifications --- src/lists/AccessRequest.js | 87 ++++++---------- src/lists/extensions/BusinessProfile.ts | 2 +- src/lists/extensions/Namespace.ts | 99 ++++++++++++++++++- src/nextapp/shared/types/query.types.ts | 14 +++ src/services/bceid/bceid.service.ts | 2 +- src/services/{bceid => }/config.service.ts | 16 +-- src/services/keystone/types.ts | 14 +++ src/services/keystone/user.ts | 2 +- .../notification/notification.service.ts | 2 +- src/tsconfig.json | 56 ++++------- 10 files changed, 187 insertions(+), 107 deletions(-) rename src/services/{bceid => }/config.service.ts (83%) diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index c3ac659e3..8a9f368b4 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -21,7 +21,7 @@ const { lookupUserByUsername, } = require('../services/keystone'); -const { ConfigService } = require('../services/bceid/config.service'); +const { ConfigService } = require('../services/config.service'); const { NotificationService, } = require('../services/notification/notification.service'); @@ -139,65 +139,36 @@ module.exports = { 'This is awesome namespace: ' + accessRequest.productEnvironment.product.namespace ); - const productEnvironmentSlug = process.env.GWA_PROD_ENV_SLUG; - - const prodEnv = await lookupProductEnvironmentServicesBySlug( - noauthContext, - productEnvironmentSlug - ); - const envCtx = await getEnvironmentContext(context, prodEnv.id, ''); - - console.log('This is envCtx: ', JSON.stringify(envCtx)); - - const resourceIds = await getResourceSets(envCtx); - const resourcesApi = new UMAResourceRegistrationService( - envCtx.issuerEnvConfig.issuerUrl, - envCtx.accessToken - ); - const namespaces = await resourcesApi.listResourcesByIdList( - resourceIds - ); - const matched = namespaces - .filter( - (ns) => - ns.name == accessRequest.productEnvironment.product.namespace - ) - .map((ns) => ({ - id: ns.id, - name: ns.name, - scopes: ns.resource_scopes, - prodEnvId: prodEnv.id, - })); - namespaceObj = matched[0]; - console.log( - 'This is the same namespace: ' + JSON.stringify(namespaceObj) - ); - const permissionApi = new KeycloakPermissionTicketService( - envCtx.issuerEnvConfig.issuerUrl, - envCtx.accessToken - ); - const params = { resourceId: namespaceObj.id, returnNames: true }; - const permissions = await permissionApi.listPermissions(params); - console.log('Permissions List: ' + JSON.stringify(permissions)); - const nc = new NotificationService(new ConfigService()); - permissions.forEach(async (perm) => { - const userDetails = await lookupUserByUsername( - noauthContext, - perm.requesterName - ); - nc.notify( - { email: 'nithu.everyyear@gmail.com', name: 'Nithin Kuruba' }, - { template: 'email-template', subject: 'Yeah!' } - ) - .then((answer) => { - console.log('DONE!'); - console.log('ANSWER = ' + JSON.stringify(answer)); - }) - .catch((err) => { - console.log('ERROR ! ' + err); - }); + const userContactList = await noauthContext.executeGraphQL({ + query: `query ListUsersByNamespace($namespace: String!) { + usersByNamespace(namespace: $namespace) { + id + name + username + email + } + }`, + variables: { + namespace: accessRequest.productEnvironment.product.namespace, + }, }); + console.log('userContactList: ' + JSON.stringify(userContactList)); } + const nc = new NotificationService(new ConfigService()); + userContactList.data.usersByNamespace.forEach((contact) => { + nc.notify( + { email: 'nithu.everyyear@gmail.com', name: 'Nithin Kuruba' }, + { template: 'email-template', subject: 'Yeah!' } + ) + .then((info) => { + console.log( + `[SUCCESS][${info}] Notification sent to ${contact.email}` + ); + }) + .catch((err) => { + console.log('[ERROR] Sending notification failed!' + err); + }); + }); }, }, }; diff --git a/src/lists/extensions/BusinessProfile.ts b/src/lists/extensions/BusinessProfile.ts index 7553dcd66..9750fca56 100644 --- a/src/lists/extensions/BusinessProfile.ts +++ b/src/lists/extensions/BusinessProfile.ts @@ -2,7 +2,7 @@ import { EnforcementPoint } from '../../authz/enforcement'; import { lookupCredentialReferenceByServiceAccess } from '../../services/keystone'; -import { ConfigService } from '../../services/bceid/config.service'; +import { ConfigService } from '../../services/config.service'; import { BCeIDService } from '../../services/bceid/bceid.service'; const typeBusinessProfile = ` diff --git a/src/lists/extensions/Namespace.ts b/src/lists/extensions/Namespace.ts index 3c024e3fc..a9ea85559 100644 --- a/src/lists/extensions/Namespace.ts +++ b/src/lists/extensions/Namespace.ts @@ -6,13 +6,17 @@ import { ResourceSet, ResourceSetInput, } from '../../services/uma2'; -import { lookupProductEnvironmentServicesBySlug } from '../../services/keystone'; +import { + lookupProductEnvironmentServicesBySlug, + lookupUserByUsername, +} from '../../services/keystone'; import { getSuitableOwnerToken, getEnvironmentContext, getResourceSets, getNamespaceResourceSets, isUserBasedResourceOwners, + doClientLoginForCredentialIssuer, } from './Common'; import type { TokenExchangeResult } from './Common'; import { @@ -24,6 +28,15 @@ import { Logger } from '../../logger'; const logger = Logger('ext.Namespace'); import { strict as assert } from 'assert'; +import { User } from '@/services/keystone/types'; + +const typeUserContact = ` + type UserContact { + id: ID! + name: String! + username: String! + email: String! + }`; const typeNamespace = ` type Namespace { @@ -44,7 +57,11 @@ module.exports = { extensions: [ (keystone: any) => { keystone.extendGraphQLSchema({ - types: [{ type: typeNamespace }, { type: typeNamespaceInput }], + types: [ + { type: typeNamespace }, + { type: typeNamespaceInput }, + { type: typeUserContact }, + ], queries: [ { schema: 'currentNamespace: Namespace', @@ -97,7 +114,6 @@ module.exports = { }, access: EnforcementPoint, }, - { schema: 'allNamespaces: [Namespace]', resolver: async ( @@ -138,6 +154,83 @@ module.exports = { }, access: EnforcementPoint, }, + { + schema: 'usersByNamespace(namespace: String!): [UserContact]', + resolver: async ( + item: any, + args: any, + context: any, + info: any, + { query, access }: any + ) => { + const namespaceValidationRule = '^[a-z][a-z0-9-]{4,14}$'; + const re = new RegExp(namespaceValidationRule); + assert.strictEqual( + re.test(args.namespace), + true, + 'Namespace name must be between 5 and 15 alpha-numeric lowercase characters and begin with an alphabet.' + ); + const noauthContext = context.createContext({ + skipAccessControl: true, + }); + + const prodEnv = await lookupProductEnvironmentServicesBySlug( + noauthContext, + process.env.GWA_PROD_ENV_SLUG + ); + + const tokenResult: TokenExchangeResult = await doClientLoginForCredentialIssuer( + noauthContext, + prodEnv.id + ); + + const kcprotectApi = new UMAResourceRegistrationService( + tokenResult.issuer, + tokenResult.accessToken + ); + const resOwnerResourceIds = await kcprotectApi.listResources({ + owner: tokenResult.clientUuid, + type: 'namespace', + } as ResourceSetQuery); + + const namespaces = await kcprotectApi.listResourcesByIdList( + resOwnerResourceIds + ); + + const matched = namespaces + .filter((ns) => ns.name == args.namespace) + .map((ns) => ({ + id: ns.id, + name: ns.name, + scopes: ns.resource_scopes, + prodEnvId: prodEnv.id, + })); + const namespaceObj = matched[0]; + const permissionApi = new KeycloakPermissionTicketService( + tokenResult.issuer, + tokenResult.accessToken + ); + const params = { resourceId: namespaceObj.id, returnNames: true }; + const permissions = await permissionApi.listPermissions(params); + const listOfUsers: Array = []; + for (const perm of permissions) { + if (perm.granted) { + const user = await lookupUserByUsername( + noauthContext, + perm.requesterName + ); + listOfUsers.push({ + id: user[0].id, + name: user[0].name, + username: user[0].username, + email: user[0].email, + }); + } + } + return listOfUsers; + }, + access: EnforcementPoint, + }, ], mutations: [ { diff --git a/src/nextapp/shared/types/query.types.ts b/src/nextapp/shared/types/query.types.ts index 13b110251..4d075d655 100644 --- a/src/nextapp/shared/types/query.types.ts +++ b/src/nextapp/shared/types/query.types.ts @@ -5875,6 +5875,14 @@ export type NamespaceInput = { name: Scalars['String']; }; +export type UserContact = { + __typename?: 'UserContact'; + id: Scalars['String']; + name: Scalars['String']; + username: Scalars['String']; + email: Scalars['String']; +}; + export type ServiceAccount = { __typename?: 'ServiceAccount'; id: Scalars['String']; @@ -6164,6 +6172,7 @@ export type Query = { consumerScopesAndRoles?: Maybe; currentNamespace?: Maybe; allNamespaces?: Maybe>>; + usersByNamespace?: Maybe>>; getUmaPoliciesForResource?: Maybe>>; allResourceSets?: Maybe>>; getResourceSet?: Maybe; @@ -6841,6 +6850,11 @@ export type QueryConsumerScopesAndRolesArgs = { }; +export type QueryUsersByNamespaceArgs = { + namespace: Scalars['String']; +}; + + export type QueryGetUmaPoliciesForResourceArgs = { prodEnvId: Scalars['ID']; resourceId: Scalars['String']; diff --git a/src/services/bceid/bceid.service.ts b/src/services/bceid/bceid.service.ts index dff98fe39..2d434bc49 100644 --- a/src/services/bceid/bceid.service.ts +++ b/src/services/bceid/bceid.service.ts @@ -2,7 +2,7 @@ import { BasicAuthSecurity, Client, createClientAsync } from 'soap'; import { BCeIDConfig } from './config'; // import { LoggerService } from "../../logger/logger.service"; -import { ConfigService } from './config.service'; +import { ConfigService } from '../config.service'; import { AccountDetails } from './account-details.model'; import { BCeIDAccountTypeCodes, diff --git a/src/services/bceid/config.service.ts b/src/services/config.service.ts similarity index 83% rename from src/services/bceid/config.service.ts rename to src/services/config.service.ts index e80b05ed4..66436f07b 100644 --- a/src/services/bceid/config.service.ts +++ b/src/services/config.service.ts @@ -1,4 +1,4 @@ -import { IConfig } from "./config"; +import { IConfig } from './bceid/config'; export class ConfigService { getConfig(): IConfig { @@ -33,21 +33,23 @@ export class ConfigService { }, }, notification: { - enabled: ['true','TRUE'].includes(process.env.EMAIL_ENABLED || 'false'), - secure: ['true','TRUE'].includes(process.env.EMAIL_SECURE || 'false'), + enabled: ['true', 'TRUE'].includes( + process.env.EMAIL_ENABLED || 'false' + ), + secure: ['true', 'TRUE'].includes(process.env.EMAIL_SECURE || 'false'), from: process.env.EMAIL_FROM || '', host: process.env.EMAIL_HOST || '', port: Number(process.env.EMAIL_PORT || 25), user: process.env.EMAIL_USER || '', - pass: process.env.EMAIL_PASS || '' - } + pass: process.env.EMAIL_PASS || '', + }, }; } private getOpenIdConfigurationUrl(): string { return new URL( `realms/${process.env.KEYCLOAK_REALM}/.well-known/openid-configuration`, - process.env.KEYCLOAK_AUTH_URL, + process.env.KEYCLOAK_AUTH_URL ).href; } -} \ No newline at end of file +} diff --git a/src/services/keystone/types.ts b/src/services/keystone/types.ts index 13b110251..4d075d655 100644 --- a/src/services/keystone/types.ts +++ b/src/services/keystone/types.ts @@ -5875,6 +5875,14 @@ export type NamespaceInput = { name: Scalars['String']; }; +export type UserContact = { + __typename?: 'UserContact'; + id: Scalars['String']; + name: Scalars['String']; + username: Scalars['String']; + email: Scalars['String']; +}; + export type ServiceAccount = { __typename?: 'ServiceAccount'; id: Scalars['String']; @@ -6164,6 +6172,7 @@ export type Query = { consumerScopesAndRoles?: Maybe; currentNamespace?: Maybe; allNamespaces?: Maybe>>; + usersByNamespace?: Maybe>>; getUmaPoliciesForResource?: Maybe>>; allResourceSets?: Maybe>>; getResourceSet?: Maybe; @@ -6841,6 +6850,11 @@ export type QueryConsumerScopesAndRolesArgs = { }; +export type QueryUsersByNamespaceArgs = { + namespace: Scalars['String']; +}; + + export type QueryGetUmaPoliciesForResourceArgs = { prodEnvId: Scalars['ID']; resourceId: Scalars['String']; diff --git a/src/services/keystone/user.ts b/src/services/keystone/user.ts index 4ba0e27d2..3b07a2536 100644 --- a/src/services/keystone/user.ts +++ b/src/services/keystone/user.ts @@ -70,7 +70,7 @@ export async function updateUserLegalAccept( export async function lookupUserByUsername( context: any, username: string -): Promise { +): Promise<[User]> { const result = await context.executeGraphQL({ query: `query GetUserWithUsername($username: String!) { allUsers(where: {username: $username}) { diff --git a/src/services/notification/notification.service.ts b/src/services/notification/notification.service.ts index a9e8df72f..1aa240840 100644 --- a/src/services/notification/notification.service.ts +++ b/src/services/notification/notification.service.ts @@ -7,7 +7,7 @@ import { Logger } from '../../logger'; import { NotificationConfig, EmailNotification, User } from './config'; -import { ConfigService } from '../bceid/config.service'; +import { ConfigService } from '../config.service'; export class NotificationService { private notifyConfig: NotificationConfig; diff --git a/src/tsconfig.json b/src/tsconfig.json index 57062b095..9fc4f0a3d 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -1,36 +1,22 @@ { - "compilerOptions": { - "module": "commonjs", - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "esModuleInterop": true, - "target": "es6", - "noImplicitAny": true, - "moduleResolution": "node", - "sourceMap": true, - "outDir": "dist", - "baseUrl": ".", - "paths": { - "@/logger": [ - "logger" - ], - "@/services/*": [ - "services/*" - ], - "@/controllers/*": [ - "controllers/*" - ], - "@/types": [ - "services/keystone/types.ts" - ] - }, - }, - "include": [ - "**/*.ts" - ], - "exclude": [ - "node_modules", - "nextapp", - "dist" - ], -} \ No newline at end of file + "compilerOptions": { + "module": "commonjs", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "esModuleInterop": true, + "target": "es6", + "noImplicitAny": true, + "moduleResolution": "node", + "sourceMap": true, + "outDir": "dist", + "baseUrl": ".", + "paths": { + "@/logger": ["logger"], + "@/services/*": ["services/*"], + "@/controllers/*": ["controllers/*"], + "@/types": ["services/keystone/types.ts"] + } + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "nextapp", "dist"] +} From a2577579e76e95aa9e60200e5abf8cd1cdc3d9c5 Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Sun, 8 Aug 2021 22:56:14 -0700 Subject: [PATCH 122/155] fixed undefined issue --- src/lists/AccessRequest.js | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index 8a9f368b4..6ac24053b 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -135,10 +135,6 @@ module.exports = { noauthContext, updatedItem.id ); - console.log( - 'This is awesome namespace: ' + - accessRequest.productEnvironment.product.namespace - ); const userContactList = await noauthContext.executeGraphQL({ query: `query ListUsersByNamespace($namespace: String!) { usersByNamespace(namespace: $namespace) { @@ -152,23 +148,22 @@ module.exports = { namespace: accessRequest.productEnvironment.product.namespace, }, }); - console.log('userContactList: ' + JSON.stringify(userContactList)); + const nc = new NotificationService(new ConfigService()); + userContactList.data.usersByNamespace.forEach((contact) => { + nc.notify( + { email: 'nithu.everyyear@gmail.com', name: 'Nithin Kuruba' }, + { template: 'email-template', subject: 'Yeah!' } + ) + .then((info) => { + console.log( + `[SUCCESS][${info}] Notification sent to ${contact.email}` + ); + }) + .catch((err) => { + console.log('[ERROR] Sending notification failed!' + err); + }); + }); } - const nc = new NotificationService(new ConfigService()); - userContactList.data.usersByNamespace.forEach((contact) => { - nc.notify( - { email: 'nithu.everyyear@gmail.com', name: 'Nithin Kuruba' }, - { template: 'email-template', subject: 'Yeah!' } - ) - .then((info) => { - console.log( - `[SUCCESS][${info}] Notification sent to ${contact.email}` - ); - }) - .catch((err) => { - console.log('[ERROR] Sending notification failed!' + err); - }); - }); }, }, }; From fb216eacabffb6fad2a1a591ade9929f20cd88cb Mon Sep 17 00:00:00 2001 From: Nithin Shekar Kuruba Date: Mon, 9 Aug 2021 18:19:08 -0700 Subject: [PATCH 123/155] added optional param to filter users by scope in a namespace and made the application selection mandatory --- src/lists/AccessRequest.js | 11 +++++++---- src/lists/extensions/Namespace.ts | 8 +++++++- src/nextapp/pages/devportal/requests/new/[id].tsx | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/lists/AccessRequest.js b/src/lists/AccessRequest.js index 6ac24053b..45b1769e4 100644 --- a/src/lists/AccessRequest.js +++ b/src/lists/AccessRequest.js @@ -136,8 +136,8 @@ module.exports = { updatedItem.id ); const userContactList = await noauthContext.executeGraphQL({ - query: `query ListUsersByNamespace($namespace: String!) { - usersByNamespace(namespace: $namespace) { + query: `query ListUsersByNamespace($namespace: String!, $scopeName: String) { + usersByNamespace(namespace: $namespace, scopeName: $scopeName) { id name username @@ -146,6 +146,7 @@ module.exports = { }`, variables: { namespace: accessRequest.productEnvironment.product.namespace, + scopeName: 'Access.Manage', }, }); const nc = new NotificationService(new ConfigService()); @@ -154,9 +155,11 @@ module.exports = { { email: 'nithu.everyyear@gmail.com', name: 'Nithin Kuruba' }, { template: 'email-template', subject: 'Yeah!' } ) - .then((info) => { + .then((answer) => { console.log( - `[SUCCESS][${info}] Notification sent to ${contact.email}` + `[SUCCESS][${JSON.stringify(answer)}] Notification sent to ${ + contact.email + }` ); }) .catch((err) => { diff --git a/src/lists/extensions/Namespace.ts b/src/lists/extensions/Namespace.ts index a9ea85559..be6f5291d 100644 --- a/src/lists/extensions/Namespace.ts +++ b/src/lists/extensions/Namespace.ts @@ -211,7 +211,13 @@ module.exports = { tokenResult.accessToken ); const params = { resourceId: namespaceObj.id, returnNames: true }; - const permissions = await permissionApi.listPermissions(params); + let permissions = await permissionApi.listPermissions(params); + if (args.scopeName) { + const updatedPermissions = permissions.filter((perm) => { + return perm.scope == args.scopeName; + }); + permissions = updatedPermissions; + } const listOfUsers: Array = []; for (const perm of permissions) { if (perm.granted) { diff --git a/src/nextapp/pages/devportal/requests/new/[id].tsx b/src/nextapp/pages/devportal/requests/new/[id].tsx index 576fe23f1..983d912f7 100644 --- a/src/nextapp/pages/devportal/requests/new/[id].tsx +++ b/src/nextapp/pages/devportal/requests/new/[id].tsx @@ -191,7 +191,7 @@ const NewRequestsPage: React.FC< Select an application to consume the API - {data.myApplications.map((a) => (