├── .eslintignore ├── .gitignore ├── .eslintrc.js ├── integration ├── sslyze │ ├── templates │ │ └── sslyze.template.env │ ├── .eslintrc │ ├── docker-compose.yml │ ├── cucumber │ │ ├── environment.js │ │ └── sslyze.steps.js │ ├── service │ │ ├── package.json │ │ ├── Dockerfile │ │ └── index.js │ ├── package.json │ ├── pages │ │ └── sslyze.js │ └── features │ │ └── sslyze-scan.template.feature ├── snyk.io │ ├── templates │ │ └── snyk.io.template.env │ ├── cucumber │ │ ├── .eslintrc │ │ ├── environment.js │ │ └── snyk.steps.js │ ├── service │ │ ├── Dockerfile │ │ ├── package.json │ │ ├── index.js │ │ └── package-lock.json │ ├── docker-compose.yml │ ├── package.json │ ├── features │ │ └── snyk-io-scan.template.feature │ ├── pages │ │ └── snyk.io.js │ └── package-lock.json ├── zap │ ├── templates │ │ └── zap.template.env │ ├── docker-compose.yml │ ├── package.json │ ├── cucumber │ │ ├── environment.js │ │ └── zap.steps.js │ ├── features │ │ ├── zap-passive-scan.template.feature │ │ └── zap-active-scan.template.feature │ ├── pages │ │ └── zap-core.js │ └── package-lock.json ├── git │ ├── cucumber │ │ ├── .eslintrc │ │ ├── environment.js │ │ └── git.steps.js │ ├── service │ │ ├── Dockerfile │ │ ├── .eslintrc │ │ ├── package.json │ │ └── index.js │ ├── .eslintrc │ ├── docker-compose.yml │ ├── package.json │ ├── pages │ │ └── git.js │ ├── features │ │ └── git.template.feature │ └── package-lock.json ├── selenium │ ├── docker-compose.yml │ ├── cucumber │ │ ├── .eslintrc │ │ ├── steps.js │ │ └── setup-driver.js │ ├── templates │ │ ├── selenium.template.env │ │ └── remoteselenium.config.template.json │ └── package.json ├── slack │ ├── templates │ │ └── slack.template.env │ ├── package.json │ └── cucumber │ │ └── post-results.js ├── docker │ ├── .eslintrc │ ├── service │ │ ├── .eslintrc │ │ ├── Dockerfile │ │ ├── package.json │ │ └── index.js │ ├── cucumber │ │ ├── environment.js │ │ └── docker.steps.js │ ├── features │ │ └── docker.template.feature │ ├── package.json │ ├── docker-compose.yml │ ├── pages │ │ └── docker.js │ └── package-lock.json ├── cucumber-report │ ├── .eslintrc │ ├── integration.js │ ├── package.json │ ├── cucumber │ │ └── report.js │ └── package-lock.json └── node │ └── docker-compose.yml ├── .gitattributes ├── lib ├── run-install.js ├── run-uninstall.js ├── promisify.js ├── environment.js ├── config-env.js ├── config-sentinel.js ├── npm.js ├── docker-compose.js ├── filesystem.js ├── integration.js └── cli.js ├── index.js ├── .travis.yml ├── package.json ├── bin ├── install-dependencies.sh └── sentinel.js ├── Readme.md └── LICENSE /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | *.tgz -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb-base" 3 | }; -------------------------------------------------------------------------------- /integration/sslyze/templates/sslyze.template.env: -------------------------------------------------------------------------------- 1 | SSLYZE_SERVER_URL=http://sslyze:8081/ -------------------------------------------------------------------------------- /integration/snyk.io/templates/snyk.io.template.env: -------------------------------------------------------------------------------- 1 | SNYK_TOKEN=XYZ 2 | SNYK_URL=http://snyk:8086/ -------------------------------------------------------------------------------- /integration/zap/templates/zap.template.env: -------------------------------------------------------------------------------- 1 | ZAP_SERVER_URL=http://zap:8080/ 2 | ZAP_SCAN_TIMEOUT=60000 -------------------------------------------------------------------------------- /integration/git/cucumber/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-restricted-syntax": "off", 4 | "no-await-in-loop": "off" 5 | } 6 | } -------------------------------------------------------------------------------- /integration/git/cucumber/environment.js: -------------------------------------------------------------------------------- 1 | const sharedEnv = require('../../../lib/environment'); 2 | 3 | module.exports = Object.assign({}, sharedEnv); 4 | -------------------------------------------------------------------------------- /integration/selenium/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | services: 3 | selenium: 4 | image: selenium/standalone-chrome 5 | shm_size: '1gb' 6 | -------------------------------------------------------------------------------- /integration/slack/templates/slack.template.env: -------------------------------------------------------------------------------- 1 | SLACK_FEATURE=OFF 2 | SLACK_WEBHOOK_URI=#Refer this link to know more on Incoming webhooks - https://api.slack.com/incoming-webhooks -------------------------------------------------------------------------------- /integration/git/service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12 2 | 3 | COPY index.js /index.js 4 | COPY package.json /package.json 5 | 6 | RUN npm install 7 | 8 | CMD ["node", "/index.js"] 9 | -------------------------------------------------------------------------------- /integration/git/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "import/no-unresolved": "off", 5 | "func-names": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /integration/docker/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "import/no-unresolved": "off", 5 | "func-names": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /integration/sslyze/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "import/no-unresolved": "off", 5 | "func-names": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /integration/docker/service/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "import/no-unresolved": "off", 5 | "func-names": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /integration/git/service/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "import/no-unresolved": "off", 5 | "func-names": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /integration/cucumber-report/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "import/no-unresolved": "off", 5 | "func-names": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /integration/selenium/cucumber/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "import/no-unresolved": "off", 5 | "func-names": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /integration/snyk.io/cucumber/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "import/no-unresolved": "off", 5 | "func-names": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /integration/selenium/templates/selenium.template.env: -------------------------------------------------------------------------------- 1 | SELENIUM_REMOTE_URL=http://selenium:4444/wd/hub 2 | SELENIUM_REMOTE_CAPABILITY=./remoteSelenium.config.template.json 3 | AUT_SERVER_URL=http:/// -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Force Unix-style line endings on all files to avoid cross platform gotchas 2 | * text eol=lf 3 | 4 | # Force files w/ known binary extensions to be treated as such 5 | *.png binary 6 | *.jpg binary 7 | *.gif binary -------------------------------------------------------------------------------- /integration/node/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | node: 4 | image: node:12 5 | env_file: ##WORKING_DIR##/config.env 6 | volumes: 7 | - ##WORKING_DIR##:/working_dir 8 | working_dir: /working_dir -------------------------------------------------------------------------------- /integration/sslyze/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | sslyze: 4 | build: 5 | context: ##THIS_DIR##/service/. 6 | dockerfile: Dockerfile 7 | env_file: ##WORKING_DIR##/config.env 8 | ports: 9 | - 8081 -------------------------------------------------------------------------------- /integration/docker/cucumber/environment.js: -------------------------------------------------------------------------------- 1 | const sharedEnv = require('../../../lib/environment'); 2 | 3 | module.exports = Object.assign({}, sharedEnv, { 4 | username: process.env.DOCKER_USERNAME, 5 | password: process.env.DOCKER_PASSWORD, 6 | }); 7 | -------------------------------------------------------------------------------- /integration/docker/service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker:stable 2 | FROM node:12 3 | COPY --from=0 /usr/local/bin/docker /usr/local/bin/docker 4 | 5 | COPY index.js /index.js 6 | COPY package.json /package.json 7 | 8 | RUN npm install 9 | 10 | CMD ["node", "/index.js"] 11 | -------------------------------------------------------------------------------- /integration/snyk.io/service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM snyk/snyk-cli:npm 2 | WORKDIR /snykApi 3 | ENV SERVICE_DIR "/snykApi" 4 | COPY index.js index.js 5 | COPY package.json package.json 6 | COPY package-lock.json package-lock.json 7 | RUN npm ci 8 | ENTRYPOINT [] 9 | CMD ["node", "/snykApi/index.js"] -------------------------------------------------------------------------------- /integration/sslyze/cucumber/environment.js: -------------------------------------------------------------------------------- 1 | const sharedEnv = require('../../../lib/environment'); 2 | 3 | module.exports = Object.assign({}, sharedEnv, { 4 | serverHostName: process.env.AUT_SERVER_URL || '.', 5 | sslyzeServerUrl: process.env.SSLYZE_SERVER_URL || 'http://sslyze:8081/', 6 | }); 7 | -------------------------------------------------------------------------------- /lib/run-install.js: -------------------------------------------------------------------------------- 1 | const Npm = require('./npm'); 2 | const Integration = require('./integration'); 3 | 4 | const npm = new Npm(); 5 | npm.installForSubdirectories(Integration.integrationDirectory()) 6 | .catch((e) => { 7 | // eslint-disable-next-line 8 | console.log(e); 9 | process.exit(1); 10 | }); 11 | -------------------------------------------------------------------------------- /integration/snyk.io/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | snyk: 4 | build: 5 | context: ##THIS_DIR##/service/. 6 | dockerfile: Dockerfile 7 | env_file: ##WORKING_DIR##/config.env 8 | volumes: 9 | - ##WORKING_DIR##:/project 10 | working_dir: /project 11 | ports: 12 | - 8086 -------------------------------------------------------------------------------- /lib/run-uninstall.js: -------------------------------------------------------------------------------- 1 | const Npm = require('./npm'); 2 | const Integration = require('./integration'); 3 | 4 | const npm = new Npm(); 5 | npm.uninstallForSubdirectories(Integration.integrationDirectory()) 6 | .catch((e) => { 7 | // eslint-disable-next-line 8 | console.log(e); 9 | process.exit(1); 10 | }); 11 | -------------------------------------------------------------------------------- /integration/git/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | git: 4 | build: 5 | context: ##THIS_DIR##/service/. 6 | dockerfile: Dockerfile 7 | env_file: ##WORKING_DIR##/config.env 8 | volumes: 9 | - ##WORKING_DIR##:##WORKING_DIR## 10 | working_dir: ##WORKING_DIR## 11 | ports: 12 | - 8080 -------------------------------------------------------------------------------- /integration/zap/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | zap: 4 | command: [ zap.sh, -daemon, -host, "0.0.0.0", -port, "8080", -config, api.disablekey=true, -config, api.addrs.addr.name=.*, -config, api.addrs.addr.regex=true ] 5 | env_file: ##WORKING_DIR##/config.env 6 | image: owasp/zap2docker-bare 7 | ports: 8 | - 8080 -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const DockerCompose = require('./lib/docker-compose'); 2 | const ZapCore = require('./integration/zap/pages/zap-core'); 3 | 4 | /** 5 | * These are the classes that get imported when the consumer of this framework does this: 6 | * fw = require('sentinel-ast'); 7 | */ 8 | module.exports = { 9 | DockerCompose, 10 | ZapCore, 11 | }; 12 | -------------------------------------------------------------------------------- /integration/slack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slack", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "jsdom": "^12.0.0", 13 | "slackr": "^1.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /integration/docker/features/docker.template.feature: -------------------------------------------------------------------------------- 1 | @DOCKER 2 | Feature: Docker 3 | Utilities for docker 4 | 5 | Scenario: Log in and copy some files from a container 6 | Given I have logged into the docker registry quay.io 7 | And I have run the docker command 8 | | cmd | docker run -v $(pwd):/wd quay.io/repo/docker-image:tag cp -R node_modules /wd/node_modules | -------------------------------------------------------------------------------- /integration/git/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "UNLICENSED", 11 | "dependencies": { 12 | "request": "^2.88.0", 13 | "request-promise": "^4.2.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /integration/zap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zap", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "request": "^2.88.0", 13 | "request-promise": "^4.2.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /integration/docker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "UNLICENSED", 11 | "dependencies": { 12 | "request": "^2.88.0", 13 | "request-promise": "^4.2.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /integration/cucumber-report/integration.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const reportDir = process.env.CUCUMBER_REPORT_DIR || './report'; 4 | try { 5 | fs.mkdirSync(reportDir); 6 | } catch (err) { 7 | if (err.code !== 'EEXIST') 8 | throw err; 9 | } 10 | 11 | module.exports = { 12 | cucumberArgs: () => ['-f', `json:${reportDir}/cucumber_report.json`], 13 | }; -------------------------------------------------------------------------------- /integration/cucumber-report/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cucumber-report", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cucumber-html-reporter": "^5.0.0", 13 | "shelljs": "^0.8.5" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /integration/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | docker: 4 | build: 5 | context: ##THIS_DIR##/service/. 6 | dockerfile: Dockerfile 7 | env_file: ##WORKING_DIR##/config.env 8 | volumes: 9 | - ##WORKING_DIR##:##WORKING_DIR## 10 | - /var/run/docker.sock:/var/run/docker.sock 11 | working_dir: ##WORKING_DIR## 12 | ports: 13 | - 8080 -------------------------------------------------------------------------------- /integration/docker/pages/docker.js: -------------------------------------------------------------------------------- 1 | const rp = require('request-promise'); 2 | 3 | class Docker { 4 | async cmd(...args) { 5 | this.output = await rp({ 6 | uri: 'http://docker:8080/cmd', 7 | method: 'POST', 8 | body: { 9 | args, 10 | }, 11 | json: true, 12 | }); 13 | return this.output; 14 | } 15 | } 16 | 17 | module.exports = Docker; 18 | -------------------------------------------------------------------------------- /integration/zap/cucumber/environment.js: -------------------------------------------------------------------------------- 1 | const sharedEnv = require('../../../lib/environment'); 2 | 3 | module.exports = Object.assign({}, sharedEnv, { 4 | server: process.env.ZAP_SERVER_URL || 'http://zap:8080/', 5 | scanTimeout: sharedEnv.parseTimeout(process.env.ZAP_SCAN_TIMEOUT, 30000), 6 | maxDepth: process.env.ZAP_MAX_DEPTH || 5, 7 | threadCount: process.env.ZAP_THREAD_COUNT || 5, 8 | }); 9 | -------------------------------------------------------------------------------- /integration/snyk.io/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "snyk", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "request": "^2.88.0", 13 | "request-promise": "^4.2.1", 14 | "fs-extra": "^8.1.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /integration/git/pages/git.js: -------------------------------------------------------------------------------- 1 | const rp = require('request-promise'); 2 | 3 | class Git { 4 | async cmd(workingDir, ...args) { 5 | this.output = await rp({ 6 | uri: 'http://git:8080/cmd', 7 | method: 'POST', 8 | body: { 9 | args, 10 | workingDir, 11 | }, 12 | json: true, 13 | }); 14 | return this.output; 15 | } 16 | } 17 | 18 | module.exports = Git; 19 | -------------------------------------------------------------------------------- /integration/git/service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git-service", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "UNLICENSED", 11 | "dependencies": { 12 | "koa": "^2.5.0", 13 | "koa-bodyparser": "^4.2.0", 14 | "koa-router": "^7.4.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /integration/selenium/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "selenium", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "request": "^2.88.0", 13 | "request-promise-native": "^1.0.5", 14 | "selenium-webdriver": "^3.0.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /integration/snyk.io/features/snyk-io-scan.template.feature: -------------------------------------------------------------------------------- 1 | @SNYK @Security @Template 2 | Feature: SNYK.IO 3 | Ensure that there are no vulnerabilities reported while scanning the project dependencies 4 | 5 | Scenario: Ensure that there are no vulnerabilities reported while scanning the project dependencies 6 | Given the SNYK command is run against the project dependencies 7 | Then there should not be any vulnerable paths found -------------------------------------------------------------------------------- /integration/snyk.io/service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "snyk-service", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "koa": "^2.2.0", 13 | "koa-bodyparser": "^4.2.0", 14 | "koa-router": "^7.2.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /integration/docker/service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker-service", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "UNLICENSED", 11 | "dependencies": { 12 | "koa": "^2.5.0", 13 | "koa-bodyparser": "^4.2.0", 14 | "koa-router": "^7.4.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /integration/sslyze/service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sslyze-service", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "child-process-promise": "^2.2.1", 13 | "koa": "^2.2.0", 14 | "koa-router": "^7.2.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /integration/sslyze/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sslyze", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "chai": "^4.1.2", 13 | "chai-as-promised": "^7.1.1", 14 | "request": "^2.88.0", 15 | "request-promise": "^4.2.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /integration/selenium/cucumber/steps.js: -------------------------------------------------------------------------------- 1 | const sharedEnv = require('../../../lib/environment'); 2 | 3 | module.exports = function () { 4 | const autUrl = process.env.AUT_SERVER_URL || '.'; 5 | 6 | this.Given(/^I have loaded the web application$/, { timeout: sharedEnv.timeout }, async function () { 7 | return this.driver.get(`${autUrl}`); 8 | }); 9 | 10 | this.Given(/^I have loaded the web application with "([^"]+)"$/, { timeout: sharedEnv.timeout }, async function (url) { 11 | return this.driver.get(url); 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /integration/sslyze/service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-slim 2 | WORKDIR /app 3 | ADD ./package.json ./package.json 4 | RUN pip install -U sslyze && apt-get update && apt-get -y install --no-install-recommends gnupg curl \ 5 | && curl -sL https://deb.nodesource.com/setup_12.x | bash \ 6 | && apt-get -y install --no-install-recommends nodejs && npm install \ 7 | && npm cache clean --force --loglevel=error && rm -fr ~/.cache/pip \ 8 | && apt-get clean && rm -rf /var/lib/apt/lists/* && apt-get autoclean 9 | ADD ./index.js ./index.js 10 | CMD ["node", "index.js"] -------------------------------------------------------------------------------- /integration/git/features/git.template.feature: -------------------------------------------------------------------------------- 1 | @GIT 2 | Feature: Git 3 | Git Utilities 4 | 5 | Scenario: Log in and copy some files from a container 6 | Given I have cloned the following git repo into the directory: working-dir 7 | | url | cloneArguments | 8 | | https://org.visualstudio.com/org/_git/git-repo | --no-checkout | 9 | And I checkout the following files in the directory: working-dir 10 | | commit | file | 11 | | [ENV_VAR_GIT_SHA] | GemFile | 12 | | [ENV_VAR_GIT_SHA] | GemFile.lock | -------------------------------------------------------------------------------- /integration/snyk.io/cucumber/environment.js: -------------------------------------------------------------------------------- 1 | const sharedEnv = require('../../../lib/environment'); 2 | 3 | const configuredThreshold = (process.env.SNYK_FAILURE_LEVEL || 'high').toLowerCase(); 4 | const possibleThresholds = ['low', 'medium', 'high']; 5 | 6 | if (!possibleThresholds.includes(configuredThreshold)) { 7 | throw new Error(`Invalid snyk severity threshold: ${configuredThreshold}`); 8 | } 9 | 10 | module.exports = Object.assign({}, sharedEnv, { 11 | snykUrl: process.env.SNYK_URL || 'http://snyk:8086/', 12 | snykFailureLevels: possibleThresholds.slice(possibleThresholds.indexOf(configuredThreshold)), 13 | }); 14 | -------------------------------------------------------------------------------- /lib/promisify.js: -------------------------------------------------------------------------------- 1 | class Promisify { 2 | static promisifyObject(obj, properties) { 3 | const props = properties || Object.keys(obj); 4 | return props.reduce((newObj, p) => { 5 | // eslint-disable-next-line no-param-reassign 6 | newObj[p] = typeof obj[p] === 'function' ? (...args) => Promisify.promisify(cb => obj[p](...args, cb)) : obj[p]; 7 | return newObj; 8 | }, {}); 9 | } 10 | static promisify(func) { 11 | return new Promise((r, e) => { 12 | func((err, data) => { 13 | if (err) e(err); 14 | r(data); 15 | }); 16 | }); 17 | } 18 | } 19 | 20 | module.exports = Promisify; 21 | -------------------------------------------------------------------------------- /integration/zap/features/zap-passive-scan.template.feature: -------------------------------------------------------------------------------- 1 | @ZAPTest @Security @Template 2 | Feature: Application should not be vulnerable to Security Issues 3 | 4 | Background: 5 | Given a new scanning session 6 | And a scanner with all policies disabled 7 | And the navigation and spider status is reset 8 | 9 | Scenario: Check for Security vulnerabilities on Node Goat application by running Passive Scan 10 | Given I have loaded the web application 11 | And I've loaded the Workflows page 12 | Given the passive scanner is enabled 13 | And all existing alerts are deleted 14 | Then the application is spidered 15 | Then no higher risk vulnerabilities should be present -------------------------------------------------------------------------------- /lib/environment.js: -------------------------------------------------------------------------------- 1 | function parseTimeout(val, ifNanValue) { 2 | const parsed = parseInt(val, 10); 3 | if (isNaN(parsed)) { // eslint-disable-line no-restricted-globals 4 | return ifNanValue; 5 | } 6 | return parsed; 7 | } 8 | 9 | function envsubst(str) { 10 | const regex = /(?:\[([\w\d]+)\])+/g; 11 | let result = str; 12 | let match; 13 | // eslint-disable-next-line no-cond-assign 14 | while ((match = regex.exec(str)) !== null) { 15 | const [, envVar] = match; 16 | if (envVar && process.env[envVar] !== undefined) { 17 | result = result.replace(`[${envVar}]`, process.env[envVar]); 18 | } 19 | } 20 | return result; 21 | } 22 | 23 | module.exports = { 24 | parseTimeout, 25 | envsubst, 26 | timeout: parseTimeout(process.env.CUCUMBER_TIMEOUT, 10000), 27 | longTimeout: parseTimeout(process.env.CUCUMBER_LONG_TIMEOUT, 30000), 28 | }; 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '8' 4 | script: 5 | - npm run lint 6 | deploy: 7 | provider: npm 8 | email: perry.loh@nintex.com 9 | edge: true 10 | api_key: 11 | secure: NgvJsumMq+zsgfvqGfhywfkm0NjVkAUIb9FWOKpTh9BA9cxTs8wwb74Y2FGRavt6ijhpG+fFxDqghU1xVCtUdU5PdJj181jHJT3J0LPFmSat2c71MmUN99KJe/vd+Vy7WPZL4JAEuYw+g8Gg/+cBCmwwEDSvJ2iyXKA4MR620FwjdLCxBdwxhTRFYLyDH+ahRjhiVQrE7RuXupbErrx7qzeOcvE0klAk4NuOBEjNNR80ghh3X/u7KeDyimxGD5znKKTXALHWxnouHFi8Z9iRLWBhR1DOmZRwyC93WiSTlH2uQqT1FZSkqeUhyoyWdddxSHH4xiE78YF5W+sDFsSZ1eGiTg0UEml3+uKERgFl73nccC4WhdFpqWfKw2rbifB+9h3XszbfH85VNs1L//Dw/S/rSpwKKY9lFmgy/olnfhk2waXsiBKJ9MBPXkxGgUgO5F9NPIPAmGW4jOTi5G3Bt45EY0eWianLpLls3lREDCPRj/6VHbi2tdj1aj5apZU7dEzeU6f4dii/fYrwwE9rSGPKHhZj/Vuxr0onNTIQwpQemC1yfoKdvqbcQutE+RPbktYzdY4RSSMRl1K/XgeVR3iAnMkHXr8QYI92nmv3tVHdrZnXXzJ6+JVYlzLNeuOcOLWvK4Zxgu4LM1iFb7t2u9Iw78XPdqeSpDJN3uOtn8g= 12 | on: 13 | repo: nintexplatform/sentinel 14 | branch: master 15 | -------------------------------------------------------------------------------- /integration/selenium/templates/remoteselenium.config.template.json: -------------------------------------------------------------------------------- 1 | /* Capabilities for BrowserStack Cloud Platform */ 2 | { 3 | "browserName" : "Chrome", 4 | "browser_version" : "38.0", 5 | "os" : "Windows", 6 | "os_version" : "7", 7 | "browserstack.user" : "xyz", 8 | "browserstack.key" : "aBC12T", 9 | "resolution": "1920x1080" 10 | } 11 | 12 | /* Capabilities for SauceLabs Cloud Platform */ 13 | /* 14 | { 15 | "browserName" : "Chrome", 16 | "browser_version" : "38.0", 17 | "os" : "Windows", 18 | "os_version" : "7", 19 | "username" : "xyz", 20 | "accessKey" : "aBC12T", 21 | "resolution": "1920x1080" 22 | } 23 | */ 24 | 25 | /* Capabilities for Testing Bot Cloud Platform */ 26 | /* 27 | { 28 | "browserName" : "Chrome", 29 | "browser_version" : "38.0", 30 | "os" : "Windows", 31 | "os_version" : "7", 32 | "client_key" : "xyz", 33 | "client_secret" : "aBC12T", 34 | "resolution": "1920x1080" 35 | } 36 | */ -------------------------------------------------------------------------------- /lib/config-env.js: -------------------------------------------------------------------------------- 1 | const Files = require('./filesystem'); 2 | 3 | class EnvConfig { 4 | constructor({ 5 | filename = 'config.env', 6 | createIfMissing, 7 | envVarWhitelist, 8 | } = { 9 | createIfMissing: false, 10 | envVarWhitelist: null, 11 | }) { 12 | this.filename = filename; 13 | this.createIfMissing = createIfMissing; 14 | this.envVarWhitelist = envVarWhitelist; 15 | this.fs = new Files(); 16 | } 17 | async ensureFileIfRequired() { 18 | const exists = await this.fs.exists(this.filename); 19 | if (!exists && this.createIfMissing) { 20 | const envText = Object.keys(process.env) 21 | .filter(envVar => !this.envVarWhitelist || 22 | this.envVarWhitelist.includes(envVar)) 23 | .reduce((str, envVar) => `${str}${envVar}=${process.env[envVar]}\n`, ''); 24 | await this.fs.writeFile(this.filename, envText, { encoding: 'utf8', flag: 'w' }); 25 | } 26 | } 27 | } 28 | 29 | module.exports = EnvConfig; 30 | -------------------------------------------------------------------------------- /integration/snyk.io/pages/snyk.io.js: -------------------------------------------------------------------------------- 1 | const rp = require('request-promise'); 2 | const env = require('./../cucumber/environment'); 3 | 4 | class Snyk { 5 | async runScanInProjectDirectory() { 6 | this.output = await rp({ 7 | uri: `${env.snykUrl}snyk/run`, 8 | json: true, 9 | resolveWithFullResponse: true, 10 | simple: false, 11 | }); 12 | if (this.output.statusCode !== 200) { 13 | throw new Error(`Snyk error: ${JSON.stringify(this.output.body)}`); 14 | } 15 | return this.output; 16 | } 17 | async runScanInDirectory(dir) { 18 | this.output = await rp({ 19 | uri: `${env.snykUrl}snyk/run`, 20 | method: 'POST', 21 | json: true, 22 | resolveWithFullResponse: true, 23 | simple: false, 24 | body: { 25 | working_directory: dir, 26 | }, 27 | }); 28 | if (this.output.statusCode !== 200) { 29 | throw new Error(`Snyk error: ${JSON.stringify(this.output.body)}`); 30 | } 31 | return this.output; 32 | } 33 | } 34 | 35 | module.exports = Snyk; 36 | -------------------------------------------------------------------------------- /integration/git/cucumber/git.steps.js: -------------------------------------------------------------------------------- 1 | const Git = require('../pages/git'); 2 | const { longTimeout, envsubst } = require('./environment'); 3 | const assert = require('assert'); 4 | 5 | module.exports = function () { 6 | this.Before(function () { 7 | this.git = new Git(); 8 | }); 9 | 10 | this.Given(/^I have cloned the following git repo into the directory: (.+)$/, { timeout: longTimeout }, async function (workingDir, table) { 11 | const [repo] = table.hashes(); 12 | const args = repo.cloneArguments.split(' ') 13 | .filter(s => s) 14 | .map(s => s.trim()); 15 | const { code } = await this.git.cmd(workingDir, 'clone', ...args, envsubst(repo.url), '.'); 16 | assert(code === 0, `Command was unsuccessful: ${code}`); 17 | }); 18 | 19 | this.Given(/^I checkout the following files into the directory: (.+)$/, { timeout: longTimeout }, async function (workingDir, table) { 20 | const files = table.hashes(); 21 | for (const f of files) { 22 | const { code } = await this.git.cmd(workingDir, 'checkout', envsubst(f.commit), f.file); 23 | assert(code === 0, `Command was unsuccessful: ${code}`); 24 | } 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /integration/sslyze/service/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-unresolved */ 2 | const { exec } = require('child-process-promise'); 3 | const { readFileSync } = require('fs'); 4 | const Koa = require('koa'); 5 | 6 | const app = new Koa(); 7 | const router = require('koa-router')({ 8 | prefix: '', 9 | }); 10 | 11 | const port = process.env.SVC_PORT || '8081'; 12 | const svcTimeout = process.env.SSLYZE_SVC_TIMEOUT || '120000'; // 2 mins 13 | 14 | router.get('/sslyze/run/:host', async (ctx) => { 15 | const hostName = ctx.params.host; 16 | const fileName = `${hostName}.json`; 17 | try { 18 | const result = await exec(`sslyze --regular --http_headers ${hostName} --json_out=${fileName}`); 19 | console.log(result.stdout); // eslint-disable-line 20 | ctx.headers = { 'Content-Type': 'application/json' }; 21 | ctx.body = { 22 | stdOut: result.stdout, 23 | json: JSON.parse(readFileSync(fileName, 'utf8')), 24 | }; 25 | } catch (err) { 26 | ctx.body = err; 27 | } 28 | }); 29 | 30 | app 31 | .use(router.routes()) 32 | .use(router.allowedMethods()); 33 | 34 | app 35 | .listen(parseInt(port, 10)) 36 | .setTimeout(parseInt(svcTimeout, 10)); 37 | -------------------------------------------------------------------------------- /lib/config-sentinel.js: -------------------------------------------------------------------------------- 1 | const Files = require('./filesystem'); 2 | 3 | class SentinelConfig { 4 | constructor(filename = '.sentinel.json') { 5 | this.filename = filename; 6 | this.default = { 7 | integrations: { 8 | whitelist: [], 9 | customServices: [], 10 | }, 11 | configEnv: { 12 | createIfMissing: false, 13 | envVarWhitelist: null, 14 | }, 15 | }; 16 | } 17 | async ensureFile() { 18 | const fs = new Files(); 19 | try { 20 | await fs.writeFile( 21 | this.filename, 22 | JSON.stringify(this.default, null, 2), 23 | { flag: 'wx' }, 24 | ); 25 | } catch (ex) { 26 | // Ignore the file if it already exists. 27 | if (ex.code !== 'EEXIST') { 28 | throw ex; 29 | } 30 | } 31 | } 32 | async readFile() { 33 | const fs = new Files(); 34 | try { 35 | const contents = await fs.readFile(this.filename); 36 | return JSON.parse(contents); 37 | } catch (ex) { 38 | if (ex.code !== 'ENOTEXISTS' && ex.code !== 'ENOENT') { 39 | throw ex; 40 | } 41 | } 42 | return this.default; 43 | } 44 | } 45 | 46 | module.exports = SentinelConfig; 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sentinel-ast", 3 | "version": "1.4.21", 4 | "description": "Sentinel automated security testing framework", 5 | "main": "index.js", 6 | "repository": "https://github.com/nintexplatform/sentinel", 7 | "keywords": [ 8 | "sentinel", 9 | "security", 10 | "test", 11 | "testing", 12 | "docker", 13 | "selenium", 14 | "webdriver", 15 | "zap", 16 | "snyk.io", 17 | "sslyze", 18 | "automation", 19 | "cucumber", 20 | "gherkin" 21 | ], 22 | "scripts": { 23 | "lint": "./node_modules/.bin/eslint **/*.js", 24 | "postinstall": "node ./lib/run-install.js", 25 | "uninstall-all": "node ./lib/run-uninstall.js" 26 | }, 27 | "bin": { 28 | "sentinel": "./bin/sentinel.js" 29 | }, 30 | "files": [ 31 | "bin/", 32 | "lib/", 33 | "integration/" 34 | ], 35 | "author": "Nintex", 36 | "license": "Apache-2.0", 37 | "dependencies": { 38 | "child_process": "^1.0.2", 39 | "commander": "^2.11.0", 40 | "cucumber": "^1.2.0", 41 | "dotenv": "^2.0.0", 42 | "figlet": "^1.2.0", 43 | "js-yaml": "^3.9.1", 44 | "lodash.merge": "^4.6.2" 45 | }, 46 | "devDependencies": { 47 | "eslint": "^4.6.1", 48 | "eslint-config-airbnb-base": "^12.0.0", 49 | "eslint-plugin-import": "^2.7.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /integration/cucumber-report/cucumber/report.js: -------------------------------------------------------------------------------- 1 | /* eslint 2 | new-cap: 0, 3 | func-names: 0, 4 | prefer-arrow-callback: 0, 5 | no-console: 0 6 | */ 7 | 8 | const fs = require('fs'); 9 | const path = require('path'); 10 | const shell = require('shelljs'); 11 | const reporter = require('cucumber-html-reporter'); 12 | 13 | const reportDirectory = process.env.CUCUMBER_REPORT_DIR || './report/'; 14 | 15 | function bootstrap() { 16 | shell.mkdir('-p', reportDirectory); 17 | } 18 | 19 | function writeReport() { 20 | try { 21 | const jsonFile = path.join(reportDirectory, 'cucumber_report.json'); 22 | const output = path.join(reportDirectory, 'cucumber_report.html'); 23 | const stat = fs.statSync(jsonFile); 24 | if (stat.isFile()) { 25 | console.log(`Writing a report to ${output}`); 26 | const options = { 27 | theme: 'bootstrap', 28 | jsonFile, 29 | output, 30 | reportSuiteAsScenarios: true, 31 | }; 32 | reporter.generate(options); 33 | } 34 | } catch (e) { 35 | // If we cant read the file, then don't write the report 36 | console.log('Not writing report file. Cannot read cucumber_report.json'); 37 | } 38 | } 39 | 40 | module.exports = function () { 41 | this.BeforeFeatures(bootstrap); 42 | this.AfterFeatures(writeReport); 43 | }; 44 | -------------------------------------------------------------------------------- /integration/docker/service/index.js: -------------------------------------------------------------------------------- 1 | const Koa = require('koa'); 2 | const Router = require('koa-router'); 3 | const bodyParser = require('koa-bodyparser'); 4 | const { spawn } = require('child_process'); 5 | 6 | const app = new Koa(); 7 | const router = Router({ 8 | prefix: '', 9 | }); 10 | 11 | const port = process.env.SVC_PORT || '8080'; 12 | const svcTimeout = process.env.DOCKER_SVC_TIMEOUT || '300000'; // 5 mins 13 | 14 | function runCommand(prog, args, options = {}) { 15 | const cmd = spawn(prog, args, options); 16 | let result = ''; 17 | return new Promise((resolve, reject) => { 18 | cmd.stdout.on('data', (data) => { 19 | result += data; 20 | }); 21 | cmd.on('error', (err) => { 22 | console.log(err); 23 | reject(err); 24 | }); 25 | cmd.on('exit', (code) => { 26 | console.log(result); 27 | console.log(code); 28 | resolve({ code, result }); 29 | }); 30 | }); 31 | } 32 | 33 | router.post('/cmd', async (ctx) => { 34 | const args = ctx.request.body.args || []; 35 | const result = await runCommand('docker', args, { shell: true }); 36 | ctx.body = result; 37 | }); 38 | 39 | app 40 | .use(bodyParser()) 41 | .use(router.routes()) 42 | .use(router.allowedMethods()); 43 | 44 | app 45 | .listen(parseInt(port, 10)) 46 | .setTimeout(parseInt(svcTimeout, 10)); 47 | -------------------------------------------------------------------------------- /integration/sslyze/pages/sslyze.js: -------------------------------------------------------------------------------- 1 | const rp = require('request-promise'); 2 | const env = require('./../cucumber/environment'); 3 | 4 | class Sslyze { 5 | async startTheProcess(host) { 6 | this.output = await rp({ 7 | uri: `${env.sslyzeServerUrl}sslyze/run/${host}`, 8 | json: true, 9 | simple: true, 10 | resolveWithFullResponse: false, 11 | }); 12 | return this.output; 13 | } 14 | 15 | listAcceptedCipherSuites() { 16 | const results = this.output.json.server_scan_results[0].scan_commands_results; 17 | return Object.keys(results) 18 | .filter(k => k.endsWith('_cipher_suites')) 19 | .reduce((acceptedCiphers, suiteKey) => { 20 | const cipherType = suiteKey.replace('_cipher_suites', ''); 21 | if (results[suiteKey].accepted_cipher_suites && 22 | results[suiteKey].accepted_cipher_suites.length > 0) { 23 | return acceptedCiphers.concat(results[suiteKey].accepted_cipher_suites.map(suite => ({ 24 | type: cipherType, 25 | name: suite.cipher_suite.name, 26 | size: suite.cipher_suite.key_size, 27 | }))); 28 | } 29 | return acceptedCiphers; 30 | }, []); 31 | } 32 | 33 | static formatProtocol(p) { 34 | return p.toLowerCase().replace(/[ .]/g, '_'); 35 | } 36 | } 37 | 38 | module.exports = Sslyze; 39 | -------------------------------------------------------------------------------- /integration/git/service/index.js: -------------------------------------------------------------------------------- 1 | const Koa = require('koa'); 2 | const Router = require('koa-router'); 3 | const bodyParser = require('koa-bodyparser'); 4 | const { spawn } = require('child_process'); 5 | const { join } = require('path'); 6 | 7 | const app = new Koa(); 8 | const router = Router({ 9 | prefix: '', 10 | }); 11 | 12 | const port = process.env.SVC_PORT || '8080'; 13 | const svcTimeout = process.env.DOCKER_SVC_TIMEOUT || '300000'; // 5 mins 14 | 15 | function runCommand(prog, args, options = {}) { 16 | const cmd = spawn(prog, args, options); 17 | let result = ''; 18 | return new Promise((resolve, reject) => { 19 | cmd.stdout.on('data', (data) => { 20 | result += data; 21 | }); 22 | cmd.on('error', (err) => { 23 | console.log(err); 24 | reject(err); 25 | }); 26 | cmd.on('exit', (code) => { 27 | console.log(result); 28 | console.log(code); 29 | resolve({ code, result }); 30 | }); 31 | }); 32 | } 33 | 34 | router.post('/cmd', async (ctx) => { 35 | const args = ctx.request.body.args || []; 36 | // Only allow a single sub directory 37 | const wd = ctx.request.body.workingDir; 38 | const [validFilename] = wd.match(/^[^<>:;,?"*|/\\]+$/); 39 | if (!validFilename) { 40 | ctx.status = 400; 41 | return; 42 | } 43 | const cwd = join(process.cwd(), wd); 44 | const result = await runCommand('git', args, { shell: true, cwd }); 45 | ctx.body = result; 46 | }); 47 | 48 | app 49 | .use(bodyParser()) 50 | .use(router.routes()) 51 | .use(router.allowedMethods()); 52 | 53 | app 54 | .listen(parseInt(port, 10)) 55 | .setTimeout(parseInt(svcTimeout, 10)); 56 | -------------------------------------------------------------------------------- /integration/zap/features/zap-active-scan.template.feature: -------------------------------------------------------------------------------- 1 | @ZAPTest @Security @Template 2 | Feature: Application should not be vulnerable to Security Issues 3 | 4 | Background: 5 | Given a new scanning session 6 | And a scanner with all policies disabled 7 | And the navigation and spider status is reset 8 | 9 | Scenario Outline: Check for Security vulnerabilities on Node Goat application by running scan for 10 | Given I have loaded the web application 11 | And I've loaded the Workflows page 12 | And all existing alerts are deleted 13 | Then the application is spidered 14 | And the "" policy is enabled with "Low" threshold and "High" attack strength 15 | When the active scanner is run 16 | Then no higher risk vulnerabilities should be present 17 | 18 | Examples: 19 | | Policy | Role | 20 | | SQL Injection | Administrator | 21 | | Cross Site Scripting | Designer | 22 | | Path Traversal | Designer | 23 | | Remote File Inclusion | Administrator | 24 | | Server Side Include | Designer | 25 | | Server Side Code Injection | Administrator | 26 | | Remote OS Command Injection | Designer | 27 | | CRLF Injection | Designer | 28 | | External Redirect | Administrator | 29 | | Source Code Disclosure | Designer | 30 | | Shell Shock | Designer | 31 | | LDAP Injection | Administrator | 32 | | XPATH Injection | Designer | 33 | | XML External Entity | Administrator | 34 | | Padding Oracle | Designer | 35 | | Insecure HTTP Methods | Administrator | -------------------------------------------------------------------------------- /integration/docker/cucumber/docker.steps.js: -------------------------------------------------------------------------------- 1 | const Docker = require('../pages/docker'); 2 | const env = require('./environment'); 3 | const assert = require('assert'); 4 | 5 | module.exports = function () { 6 | this.Before(function () { 7 | this.docker = new Docker(); 8 | }); 9 | 10 | this.Given(/^I have logged into the docker registry (.+)$/, { timeout: env.longTimeout }, async function (server) { 11 | await this.docker.cmd('login', '-u', env.username, '-p', env.password, server); 12 | }); 13 | 14 | this.Given(/^I have run the docker command$/, { timeout: env.longTimeout }, async function (table) { 15 | const cmd = table.rowsHash().cmd || ''; 16 | const args = cmd.split(' '); 17 | if (args.length > 1 && args[0] === 'docker') { 18 | const { code } = await this.docker.cmd(...args.slice(1)); 19 | assert(code === 0, 'Login unsuccessful'); 20 | } 21 | }); 22 | 23 | this.Given(/^I have copied the paths from the docker image$/, { timeout: env.longTimeout }, async function (table) { 24 | const paths = table.hashes(); 25 | await Promise.all(paths.map((p) => { 26 | let { dockerImage } = p; 27 | const { dockerTag } = p; 28 | if (dockerTag) { 29 | dockerImage += `:${env.envsubst(dockerTag)}`; 30 | } 31 | if (p.type === 'file') { 32 | return this.docker.cmd('run', '--rm', '-v', '$(pwd):/wd', dockerImage, 'cp', p.fromPath, `/wd/${p.toPath}`) 33 | .then(({ result, code }) => { 34 | assert(code === 0, 'Copy was unsuccessful'); 35 | return result; 36 | }); 37 | } 38 | return this.docker.cmd('run', '--rm', '-v', '$(pwd):/wd', dockerImage, 'cp', '-R', p.fromPath, `/wd/${p.toPath}`) 39 | .then(({ result, code }) => { 40 | assert(code === 0, 'Copy was unsuccessful'); 41 | return result; 42 | }); 43 | })); 44 | }); 45 | }; 46 | -------------------------------------------------------------------------------- /integration/snyk.io/cucumber/snyk.steps.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const env = require('./environment'); 3 | const Snyk = require('../pages/snyk.io'); 4 | const fs = require('fs-extra'); 5 | 6 | module.exports = function () { 7 | this.Before(function () { 8 | this.snykOutput = null; 9 | }); 10 | 11 | this.When(/^the SNYK command is run in the directory: (.+)$/, { timeout: env.longTimeout }, async function (directory) { 12 | const snyk = new Snyk(); 13 | this.snykOutput = await snyk.runScanInDirectory(directory); 14 | }); 15 | 16 | this.When(/^the SNYK command is run against the project dependencies$/, { timeout: env.longTimeout }, async function () { 17 | const snyk = new Snyk(); 18 | this.snykOutput = await snyk.runScanInProjectDirectory(); 19 | }); 20 | 21 | this.Then(/^there should not be any vulnerable paths found$/, async function () { 22 | if (this.snykOutput) { 23 | this.snykOutput.body.detected = this.snykOutput.body.vulnerabilities 24 | .filter(vuln => env.snykFailureLevels.includes(vuln.severity)).length; 25 | assert(!this.snykOutput.body.vulnerabilities.some(vuln => env.snykFailureLevels.includes(vuln.severity)), 'Vulnerability detected.'); 26 | } 27 | }); 28 | 29 | this.After(async function (scenario) { 30 | if (this.snykOutput) { 31 | // Generate snyk html reports 32 | const reportDir = process.env.CUCUMBER_REPORT_DIR || './report/'; 33 | const reportName = tags => `${reportDir}snyk-report-${tags}.html`; 34 | try { 35 | const tags = scenario.getTags().map(e => e.getName()).join('-'); 36 | fs.writeFileSync(reportName(tags), this.snykOutput.body.report); 37 | } catch (err) { 38 | // eslint-disable-next-line no-console 39 | console.log(`Error generating Snyk HTML report : ${reportName('')} (${err})`); 40 | } 41 | scenario.attach(JSON.stringify(this.snykOutput.body.vulnerabilities, null, '\t')); 42 | } 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /lib/npm.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-underscore-dangle, no-console */ 2 | 3 | const path = require('path'); 4 | const { execSync } = require('child_process'); 5 | const Files = require('./filesystem'); 6 | 7 | class Npm { 8 | constructor() { 9 | this.fs = new Files(); 10 | this.filterOptions = { nameFilter: n => n !== 'node_modules' && !n.startsWith('.') }; 11 | } 12 | 13 | async installForSubdirectories(directory) { 14 | const subDirectoryList = await this.fs.getDirectories(directory, this.filterOptions); 15 | const packageDirs = await Promise.all(subDirectoryList 16 | .map(d => this.fs.exists(path.join(d, 'package.json')) 17 | .then(exists => ({ dir: d, isNodePackage: exists })))); 18 | packageDirs 19 | .filter(d => d.isNodePackage) 20 | .map(d => d.dir) 21 | .forEach((dir) => { 22 | if (dir !== directory) { 23 | console.log(`Performing "npm install" inside ./${path.relative(directory, dir)}`); 24 | Npm.install(dir); 25 | } 26 | }); 27 | } 28 | 29 | static install(where) { 30 | execSync(`cd ${where} && npm install`, { env: process.env, stdio: 'inherit' }); 31 | } 32 | 33 | async uninstallForSubdirectories(directory) { 34 | const subDirectoryList = await this.fs.getDirectories(directory, this.filterOptions); 35 | const packageDirs = await Promise.all(subDirectoryList 36 | .map(d => path.join(d, 'package.json')) 37 | .map(d => this.fs.exists(d).then(exists => ({ dir: d, isNodePackage: exists })))); 38 | packageDirs 39 | .filter(d => d.isNodePackage) 40 | .map(d => d.dir) 41 | .forEach((dir) => { 42 | if (dir !== directory) { 43 | console.log(`Performing "npm uninstall" inside ./${path.relative(directory, dir)}`); 44 | Npm.uninstall(directory); 45 | } 46 | }); 47 | } 48 | 49 | static uninstall(dir) { 50 | execSync(`cd ${dir} && rm -rf node_modules`, { env: process.env, stdio: 'inherit' }); 51 | } 52 | } 53 | 54 | module.exports = Npm; 55 | -------------------------------------------------------------------------------- /bin/install-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | success='\033[1;32m' 7 | error='\033[1;31m' 8 | info='\033[0;34m' 9 | reset='\033[0m' 10 | 11 | process="Docker" 12 | { 13 | echo -e "${info} Checking any existing versions of '$process'" 14 | docker -v 15 | } || { 16 | #Install docker 17 | echo -e "${info} No existing versions of '$process'" 18 | echo -e "${info} Download and Installation of '$process' has started ${reset}" 19 | curl -fsSL get.docker.com -o install-docker.sh 20 | sh install-docker.sh 21 | echo -e "${success} $process installed! ${reset}" 22 | } 23 | 24 | process="Docker-Compose" 25 | { 26 | echo -e "${info} Checking any existing versions of '$process'" 27 | docker-compose -v 28 | } || { 29 | #Install docker-compose 30 | echo -e "${info} No existing versions of '$process'" 31 | echo -e "${info} Download and Installation of '$process' has started ${reset}" 32 | dockerComposeVersion="$(git ls-remote https://github.com/docker/compose | grep "refs/tag" | grep -oP "[0-9]+\.[0-9]+\.[0-9]+" | tail -n1)" 33 | curl -L https://github.com/docker/compose/releases/download/$dockerComposeVersion/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 34 | sudo chmod +x /usr/local/bin/docker-compose 35 | echo -e "${success} $process installed! ${reset}" 36 | } 37 | 38 | echo -e "${info}------------------------------------------------------------${reset}" 39 | 40 | process="Node.js" 41 | { 42 | echo -e "${info} Checking any existing versions of '$process'" 43 | node -v 44 | } || { 45 | #Install Node.js 46 | echo -e "${info} No existing versions of '$process'" 47 | echo -e "${info} Download and Installation of '$process' has started ${reset}" 48 | curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.4/install.sh | bash 49 | source ~/.nvm/nvm.sh 50 | nvm install node 51 | echo -e "${success} $process installed! ${reset}" 52 | } 53 | 54 | echo -e "${info} Please Logout and Login back to take changes effect ${reset}" 55 | 56 | status=$? 57 | if [ $status -ne 0 ] 58 | then 59 | echo -e "${error} Installation of $process failed. Resolve the errors and Try again! ${reset}" 60 | exit 1 61 | fi -------------------------------------------------------------------------------- /lib/docker-compose.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const yaml = require('js-yaml'); 5 | const merge = require('lodash.merge'); 6 | 7 | class DockerCompose { 8 | constructor(composeFiles, options, workingDir) { 9 | this.composeFiles = (composeFiles && Array.isArray(composeFiles)) ? composeFiles : []; 10 | this.options = (options && Array.isArray(options)) ? options : []; 11 | this.file = null; 12 | this.workingDir = workingDir || '.'; 13 | } 14 | 15 | generateConfig(filePath) { 16 | const result = this.composeFiles.reduce((agg, f) => { 17 | const thisDir = path.parse(path.resolve(f)).dir; 18 | const contents = fs.readFileSync(f, 'utf8') 19 | .replace(/##THIS_DIR##/g, thisDir) 20 | .replace(/##WORKING_DIR##/g, process.cwd()); 21 | const config = yaml.safeLoad(contents); 22 | return merge(agg, config); 23 | }, {}); 24 | 25 | const output = yaml.safeDump(result); 26 | fs.writeFileSync(filePath, output); 27 | this.file = filePath; 28 | } 29 | 30 | createCommand(cmd, args) { 31 | if (this.file === null) { 32 | this.generateConfig(path.join(this.workingDir, 'docker-compose.yml')); 33 | } 34 | return [ 35 | 'docker-compose', 36 | ['-f', this.file] 37 | .concat(this.options) 38 | .concat(cmd, args), 39 | ]; 40 | } 41 | 42 | exec(cmd, args) { 43 | return new Promise((r, e) => { 44 | const [prog, progArgs] = this.createCommand(cmd, args); 45 | const child = spawn(prog, progArgs, { 46 | stdio: 'inherit', 47 | }); 48 | child.on('error', e); 49 | child.on('exit', (code) => { 50 | const cb = code === 0 ? r : e; 51 | cb(); 52 | }); 53 | }); 54 | } 55 | 56 | up(...args) { 57 | return this.exec('up', args); 58 | } 59 | down(...args) { 60 | return this.exec('down', args); 61 | } 62 | run(...args) { 63 | return this.exec('run', args); 64 | } 65 | logs(...args) { 66 | return this.exec('logs', args); 67 | } 68 | ps(...args) { 69 | return this.exec('ps', args); 70 | } 71 | } 72 | 73 | module.exports = DockerCompose; 74 | -------------------------------------------------------------------------------- /integration/slack/cucumber/post-results.js: -------------------------------------------------------------------------------- 1 | /* eslint 2 | no-console: 0 3 | */ 4 | 5 | const path = require('path'); 6 | const jsdom = require('jsdom'); 7 | const slackr = require('slackr'); 8 | 9 | const { JSDOM } = jsdom; 10 | const slackFlag = process.env.SLACK_FEATURE_FLAG || 'OFF'; 11 | const reportDirectory = process.env.CUCUMBER_REPORT_DIR || './report/'; 12 | const output = path.join(reportDirectory, 'cucumber_report.html'); 13 | 14 | async function postSlack(message) { 15 | const data = { 16 | attachments: [ 17 | { 18 | title: 'Test Result', 19 | text: `${message}`, 20 | fallback: `${message}`, 21 | color: 'good', 22 | mrkdwn_in: ['text', 'fallback'], 23 | }, 24 | ], 25 | }; 26 | 27 | const response = await slackr(data); 28 | if (response.code === 200) { 29 | console.log('Test results has been posted on Slack'); 30 | } else { 31 | console.log(`Error: ${response.body}`); 32 | } 33 | } 34 | 35 | async function writeMessageToSlack() { 36 | if (slackFlag === 'ON') { 37 | const dom = await JSDOM.fromFile(output); 38 | const { document } = dom.window; 39 | const pass = document.documentElement.getElementsByClassName('label label-success')[1]; 40 | const fail = document.documentElement.getElementsByClassName('label label-danger')[1]; 41 | const skipped = document.documentElement.getElementsByClassName('label label-warning')[1]; 42 | const envVar = document.documentElement.querySelectorAll('strong'); 43 | const status = { 44 | passCount: pass ? pass.textContent : 0, 45 | failCount: fail ? fail.textContent : 0, 46 | skippedCount: skipped && skipped.getAttribute('title') === 'scenarios' ? skipped.textContent : 0, 47 | }; 48 | status.total = parseInt(status.passCount, 10) 49 | + parseInt(status.failCount, 10) 50 | + parseInt(status.skippedCount, 10); 51 | envVar.forEach((env) => { 52 | const [key, val] = env.parentNode.textContent.trim().split(':'); 53 | status[key] = val; 54 | }); 55 | const statusMsg = `Run Stats for ${status.total} Scenarios: :white_check_mark: ${status.passCount} passed, :x: ${status.failCount} failed, :heavy_minus_sign: ${status.skippedCount} skipped\n`; 56 | await postSlack(statusMsg); 57 | } 58 | } 59 | 60 | // eslint-disable-next-line func-names 61 | module.exports = function () { 62 | this.AfterFeatures(writeMessageToSlack); 63 | }; 64 | -------------------------------------------------------------------------------- /integration/sslyze/features/sslyze-scan.template.feature: -------------------------------------------------------------------------------- 1 | @SSL @Security @Template 2 | Feature: SSL 3 | Ensure that the SSL configuration of the service is robust 4 | 5 | Background: Run the SSLyze command only once for all features 6 | When the SSLyze command is run against the host 7 | 8 | #SSL- CRIME ATTACK 9 | Scenario: Disable SSL deflate compression in order to mitigate the risk of the CRIME attack 10 | Then the SSLyze output must contain the text "Compression disabled" 11 | 12 | #SSL- CLIENT RENEGOTIATION 13 | Scenario: Disable client renegotiations 14 | Then the SSLyze output must contain a line that matches .*Client-initiated Renegotiation:\s+OK - Rejected.* 15 | 16 | #SSL - Secure Renegotiations 17 | Scenario: Server should support secure renegotiation 18 | Then the SSLyze output must contain a line that matches .*Secure Renegotiation:\s+OK - Supported.* 19 | 20 | #SSL - HEARTBLEED 21 | @Manual 22 | Scenario: Patch OpenSSL against the Heartbleed vulnerability 23 | Then the SSLyze output must contain the text "OK - Not vulnerable to Heartbleed" 24 | 25 | #SSL - Strong Cipher 26 | Scenario: The minimum cipher strength should meet requirements 27 | Then the minimum key size must be 128 bits 28 | 29 | #SSL - Disabled Protocols 30 | Scenario: Disable weak SSL protocols due to numerous cryptographic weaknesses 31 | Then the following protocols must not be supported 32 | |protocol | 33 | |SSL 2.0 | 34 | |SSL 3.0 | 35 | |TLS 1.1 | 36 | |TLS 1.0 | 37 | 38 | #SSL - OpenSSL CCS Injection vulnerability 39 | Scenario: Server should not be vulnerable to OpenSSL CCS Injection 40 | Then the SSLyze output must contain a line that matches .*OK - Not vulnerable to OpenSSL CCS injection.* 41 | 42 | #SSL - Support Strong Protocols 43 | Scenario: Support TLSv1.2 44 | Then the following protocols must be supported 45 | |protocol | 46 | |TLS 1.2 | 47 | 48 | #SSL - Perfect Forward Secrecy 49 | Scenario: Enable Perfect forward secrecy 50 | Then any of the following ciphers must be supported 51 | | ciphers | 52 | |TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | 53 | |TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 | 54 | |TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | 55 | |TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | 56 | 57 | #SSL - Not Support SHA-1 Certificate 58 | Scenario: The certificate does not use SHA-1 any more 59 | Then the SSLyze output must contain a line that matches .*OK - No SHA1-signed certificate in the verified certificate chain.* 60 | 61 | #SSL - Weak Cipher Suites 62 | Scenario: Weak cipher suites should be disabled 63 | Then the following ciphers must not be supported 64 | | cipher | 65 | | EXP- | 66 | | ADH | 67 | | AECDH | 68 | | NULL | 69 | | DES-CBC- | 70 | | RC2 | 71 | | RC5 | 72 | | MD5 | 73 | 74 | #Certificate Key Size should be 2048 bit 75 | Scenario: The server key should be large enough 76 | Then the SSLyze output must contain a line that matches .*Key Size:\s+2048.* 77 | 78 | #Certificate Should be in valid 79 | Scenario: The server certificate should be trusted 80 | Then the certificate has a matching host name 81 | And the certificate is in major root CA trust stores -------------------------------------------------------------------------------- /lib/filesystem.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const { promisify, promisifyObject } = require('./promisify'); 4 | 5 | class Files { 6 | constructor() { 7 | // Create async version of the fs module 8 | Object.assign(this, promisifyObject(fs, ['readdir', 'stat', 'readFile', 'appendFile', 'writeFile'])); 9 | // exists callback does not have an error as first arg. 10 | this.exists = filePath => promisify(cb => fs.exists(filePath, cb)).catch(result => result); 11 | } 12 | 13 | async statDirectory(directory, options) { 14 | const nameFilter = options && typeof options.nameFilter === 'function' ? options.nameFilter : () => true; 15 | const pathFilter = options && typeof options.pathFilter === 'function' ? options.pathFilter : () => true; 16 | const data = await this.readdir(directory); 17 | const filtered = data 18 | .filter(nameFilter) 19 | .map(sd => path.join(directory, sd)) 20 | .filter(pathFilter); 21 | return Promise.all(filtered.map(sd => this.stat(sd).then(stat => ({ 22 | path: sd, 23 | stat, 24 | })))); 25 | } 26 | 27 | async statDirectoryRecursive(directory, options) { 28 | const stats = await this.statDirectory(directory, options); 29 | const dirs = stats.filter(s => s.stat.isDirectory()).map(s => s.path); 30 | const substats = await Promise.all(dirs.reduce((agg, dir) => 31 | agg.concat(this.statDirectoryRecursive(dir, options)), [])); 32 | return Files.flatten(stats.concat(substats)); 33 | } 34 | 35 | async getDirectories(directory, options) { 36 | const stats = await this.statDirectory(directory, options); 37 | return stats 38 | .filter(s => s.stat.isDirectory()) 39 | .map(s => s.path); 40 | } 41 | 42 | async getFiles(directory, options) { 43 | const stats = await this.statDirectory(directory, options); 44 | return stats 45 | .filter(s => s.stat.isFile()) 46 | .map(s => s.path); 47 | } 48 | 49 | async getDirectoriesRecursive(directory, options) { 50 | const dirs = await this.getDirectories(directory, options); 51 | const subdirs = await Promise.all(dirs.reduce((agg, dir) => 52 | agg.concat(this.getDirectoriesRecursive(dir, options)), [])); 53 | return Files.flatten(dirs.concat(subdirs)); 54 | } 55 | 56 | async getFilesRecursive(directory, options) { 57 | const stats = await this.statDirectoryRecursive(directory, options); 58 | return stats.filter(s => s.stat.isFile()).map(s => s.path); 59 | } 60 | 61 | async copyFile(src, dest) { 62 | let target = dest; 63 | try { 64 | // if dest is an existing dir, copy into it with same filename 65 | const destStat = await this.stat(dest); 66 | target = destStat.isDirectory() ? path.join(dest, path.basename(src)) : dest; 67 | } catch (e) { 68 | // if dest doesnt exist. Ignore and attempt copy 69 | if (e.code !== 'ENOENT') { 70 | throw e; 71 | } 72 | } 73 | return new Promise((resolve, reject) => { 74 | let called = false; 75 | const rejectOnce = (e) => { 76 | if (!called) { 77 | called = true; 78 | reject(e); 79 | } 80 | }; 81 | const rd = fs.createReadStream(src); 82 | rd.on('error', rejectOnce); 83 | const wr = fs.createWriteStream(target); 84 | wr.on('error', rejectOnce); 85 | wr.on('close', resolve); 86 | rd.pipe(wr); 87 | }); 88 | } 89 | 90 | static flatten(lists) { 91 | return lists.reduce((a, b) => a.concat(b), []); 92 | } 93 | } 94 | 95 | module.exports = Files; 96 | -------------------------------------------------------------------------------- /lib/integration.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const Files = require('./filesystem'); 3 | 4 | class Integration { 5 | constructor() { 6 | this.userDirectory = process.cwd(); 7 | this.featureDir = process.env.FEATURE_DIR || path.join(this.userDirectory, 'features'); 8 | this.envConsolidate = '# These are the environment variables used in the tests container'; 9 | this.fs = new Files(); 10 | } 11 | 12 | static packageDirectory() { 13 | return path.resolve(path.join(__dirname, '..')); 14 | } 15 | 16 | static integrationDirectory() { 17 | return path.join(Integration.packageDirectory(), 'integration'); 18 | } 19 | 20 | async getFiles(options) { 21 | const integrationDirectory = Integration.integrationDirectory(); 22 | const exists = await this.fs.exists(integrationDirectory); 23 | if (!exists) { 24 | return []; 25 | } 26 | const integrationEnabled = d => !options 27 | || !Array.isArray(options.whitelistedIntegrations) 28 | || options.whitelistedIntegrations.length === 0 29 | || options.whitelistedIntegrations.some(wld => d.endsWith(wld)); 30 | const integrationDirectories = await this.fs.getDirectories(integrationDirectory, options); 31 | const integrationFiles = await Promise.all(integrationDirectories 32 | .filter(integrationEnabled) 33 | .map(d => this.fs.getFilesRecursive(d, options))); 34 | const integration = integrationFiles.reduce((agg, c) => agg.concat(c), []); 35 | if (options && options.withRelativePaths === true) { 36 | // Windows returns \ as directory separator. shell.find returns /. 37 | const cwd = process.cwd().replace(/\\/g, '/'); 38 | // Make all paths that reference the current working dir relative. 39 | // And any paths that reference the global install dir relative to local. 40 | return integration 41 | .map(f => f.replace(cwd, '.')) 42 | .map(f => f.replace(Integration.packageDirectory(), './node_modules/sentinel-ast')); 43 | } 44 | return integration; 45 | } 46 | 47 | static findFeatures(files) { 48 | return files.filter(f => f.match(/\.feature$/)); 49 | } 50 | 51 | static findSupportJs(files) { 52 | return files.filter(f => f.match(/\/cucumber\/.*\.js$/)); 53 | } 54 | 55 | static findCompose(files) { 56 | return files.filter(f => f.match(/docker-compose\.yml$/)); 57 | } 58 | 59 | static findIntegration(files) { 60 | return files.filter(f => f.match(/integration\.js$/)); 61 | } 62 | 63 | async intialize(moduleDirectory) { 64 | const subDirectoryList = await this.fs 65 | .getDirectoriesRecursive(moduleDirectory, { nameFilter: n => n !== 'node_modules' && !n.startsWith('.') }); 66 | const templateFiles = await Promise.all(subDirectoryList 67 | .map(d => this.fs.getFiles(d, { nameFilter: f => f.includes('.template.') }))); 68 | await Promise.all(templateFiles 69 | .filter(l => l) 70 | .reduce((agg, cur) => agg.concat(cur), []) 71 | .map(async (file) => { 72 | if (file.includes('.template.env')) { 73 | const input = await this.fs.readFile(file, { encoding: 'utf8' }); 74 | this.envConsolidate += `\n${input}`; 75 | } else if (file.includes('.template.feature')) { 76 | await this.fs.copyFile(file, this.featureDir); 77 | } else if (file.includes('.template.json')) { 78 | await this.fs.copyFile(file, this.userDirectory); 79 | } 80 | })); 81 | await this.writeConfigFile(path.join(this.userDirectory, 'config.env'), this.envConsolidate); 82 | } 83 | 84 | async writeConfigFile(file, contents) { 85 | return this.fs.appendFile(file, contents, { flag: 'w+' }); 86 | } 87 | } 88 | 89 | module.exports = Integration; 90 | -------------------------------------------------------------------------------- /bin/sentinel.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* eslint-disable no-console */ 3 | 4 | const program = require('commander'); 5 | const pkg = require('./../package.json'); 6 | const CLI = require('../lib/cli'); 7 | 8 | const cli = new CLI(); 9 | 10 | program 11 | .version(pkg.version); 12 | 13 | program 14 | .command('init') 15 | .description('Initializes the templates from core framework repo') 16 | .action(async () => { 17 | const ascii = await CLI.genAscii(); 18 | console.log(ascii); 19 | await cli.init(); 20 | console.log('Initialization Completed!'); 21 | }) 22 | .on('--help', () => { 23 | console.log('\n Examples:'); 24 | console.log(); 25 | console.log(' $ sentinel init'); 26 | console.log(); 27 | }); 28 | 29 | program 30 | .command('run-compose [ARGS...]') 31 | .description('Runs docker compose commands') 32 | .action((cmd, args) => cli.runCompose(cmd, args) 33 | .catch((ex) => { 34 | console.log(ex); 35 | process.exit(1); 36 | })) 37 | .on('--help', () => { 38 | console.log('\n Examples:'); 39 | console.log(); 40 | console.log(' $ sentinel run-compose ps'); 41 | console.log(); 42 | }); 43 | 44 | const cucumberArgs = []; 45 | const gatherCucumberArgs = param => (val) => { 46 | cucumberArgs.push(param, val); 47 | return cucumberArgs; 48 | }; 49 | program 50 | .command('run-cucumber [|...]') 51 | .description('Executes cucumber tests') 52 | .option('-n, --name', 'To specify a scenario by its name matching a regular expression', gatherCucumberArgs('--name'), cucumberArgs) 53 | .option('-r, --require ', 'To require support files before executing the features', gatherCucumberArgs('--require'), cucumberArgs) 54 | .option('-f, --format ', 'To specify the format of the output', gatherCucumberArgs('--format'), cucumberArgs) 55 | .option('-fo, --format-options ', 'To pass in format options', gatherCucumberArgs('--format-options'), cucumberArgs) 56 | .option('-p, --profile ', 'To set the profile', gatherCucumberArgs('--profile'), cucumberArgs) 57 | .option('-t, --tags ', 'To run specific features or scenarios', gatherCucumberArgs('--tags'), cucumberArgs) 58 | .option('-c, --compiler :', 'To transpile Step definitions and support files written in other languages to JS', gatherCucumberArgs('--compiler'), cucumberArgs) 59 | .option('-w, --world-parameters ', 'To pass in parameters to pass to the world constructor', gatherCucumberArgs('--world-parameters'), cucumberArgs) 60 | .action(args => cli.runCucumber(cucumberArgs.concat(args)) 61 | .catch((ex) => { 62 | console.log(ex); 63 | process.exit(1); 64 | })) 65 | .on('--help', () => { 66 | console.log('\n Examples:'); 67 | console.log(); 68 | console.log(' $ sentinel run-cucumber -t ~@Template -t ~@Manual'); 69 | console.log(); 70 | }); 71 | 72 | program 73 | .command('start-services') 74 | .description('Starts all the needed docker containers') 75 | .action(() => cli.startServices() 76 | .catch((ex) => { 77 | console.log(ex); 78 | process.exit(1); 79 | })) 80 | .on('--help', () => { 81 | console.log('\n Examples:'); 82 | console.log(); 83 | console.log(' $ sentinel start-services'); 84 | console.log(); 85 | }); 86 | 87 | program 88 | .command('stop-services') 89 | .description('Stops all the needed docker containers') 90 | .action(() => cli.stopServices() 91 | .catch((ex) => { 92 | console.log(ex); 93 | process.exit(1); 94 | })) 95 | .on('--help', () => { 96 | console.log('\n Examples:'); 97 | console.log(); 98 | console.log(' $ sentinel stop-services'); 99 | console.log(); 100 | }); 101 | 102 | program.parse(process.argv); 103 | 104 | // Print Usage output to console when user doesn't provie any command 105 | if (!process.argv.slice(2).length) program.outputHelp(); 106 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | const figlet = require('figlet'); 2 | const SentinelConfig = require('./config-sentinel'); 3 | const EnvConfig = require('./config-env'); 4 | const DockerCompose = require('./docker-compose'); 5 | const Integration = require('./integration'); 6 | const { promisify } = require('./promisify'); 7 | 8 | class CLI { 9 | constructor() { 10 | this.int = new Integration(); 11 | this.configrc = new SentinelConfig(); 12 | this.whitelistedIntegrations = []; 13 | this.additionalServices = []; 14 | this.readConfig = async () => { 15 | this.config = await this.configrc.readFile(); 16 | this.additionalServices = this.config 17 | && this.config.integrations 18 | && Array.isArray(this.config.integrations.customServices) 19 | ? this.config.integrations.customServices : []; 20 | this.whitelistedIntegrations = this.config 21 | && this.config.integrations 22 | && Array.isArray(this.config.integrations.whitelist) 23 | ? this.config.integrations.whitelist : []; 24 | const configenv = new EnvConfig(this.config.configEnv); 25 | await configenv.ensureFileIfRequired(); 26 | }; 27 | } 28 | 29 | async init() { 30 | await this.int.intialize(Integration.integrationDirectory()); 31 | await this.configrc.ensureFile(); 32 | } 33 | 34 | async runCompose(composeCommand, composeArgs) { 35 | await this.readConfig(); 36 | const files = await this.int.getFiles({ 37 | whitelistedIntegrations: this.whitelistedIntegrations, 38 | }); 39 | const composeFiles = Integration 40 | .findCompose(files) 41 | .concat(this.additionalServices); 42 | 43 | if (composeCommand === undefined) { 44 | throw new Error('docker-compose command required. e.g. run-compose ps'); 45 | } 46 | const dc = new DockerCompose(composeFiles, [], Integration.integrationDirectory()); 47 | return dc[composeCommand](...composeArgs); 48 | } 49 | 50 | async runCucumber(cucumberArgs) { 51 | await this.readConfig(); 52 | const featureDir = process.env.FEATURE_DIR || './features/'; 53 | 54 | // 1. require support files for each module) 55 | let files = await this.int.getFiles({ 56 | withRelativePaths: true, 57 | whitelistedIntegrations: this.whitelistedIntegrations, 58 | }); 59 | cucumberArgs.push(...Integration.findSupportJs(files) 60 | .reduce((a, f) => a.concat('--require', f), []) 61 | .concat('--require', featureDir) 62 | .concat('-t', '~@Template')); 63 | 64 | // 2. Bootstrap modules 65 | files = await this.int.getFiles({ 66 | whitelistedIntegrations: this.whitelistedIntegrations, 67 | }); 68 | Integration.findIntegration(files) 69 | .map(f => require(f)) // eslint-disable-line global-require, import/no-dynamic-require 70 | .filter(m => m.cucumberArgs) 71 | .forEach((m) => { 72 | cucumberArgs.push(...m.cucumberArgs()); 73 | }); 74 | 75 | const composeFiles = Integration.findCompose(files) 76 | .concat(this.additionalServices); 77 | const dc = new DockerCompose(composeFiles, [], Integration.integrationDirectory()); 78 | return Promise.resolve() 79 | .then(() => dc.up('--build', '-d')) 80 | .then(() => dc.run('node', './node_modules/.bin/cucumber.js', ...cucumberArgs)); 81 | } 82 | 83 | async startServices() { 84 | await this.readConfig(); 85 | const files = await this.int.getFiles({ 86 | whitelistedIntegrations: this.whitelistedIntegrations, 87 | }); 88 | const composeFiles = Integration.findCompose(files) 89 | .concat(this.additionalServices); 90 | const dc = new DockerCompose(composeFiles, [], Integration.integrationDirectory()); 91 | return dc.up('--build', '-d'); 92 | } 93 | 94 | async stopServices() { 95 | await this.readConfig(); 96 | const files = await this.int.getFiles({ 97 | whitelistedIntegrations: this.whitelistedIntegrations, 98 | }); 99 | const composeFiles = Integration.findCompose(files) 100 | .concat(this.additionalServices); 101 | const dc = new DockerCompose(composeFiles, [], Integration.integrationDirectory()); 102 | return dc.down(); 103 | } 104 | 105 | static genAscii() { 106 | return promisify(cb => figlet.text('sentinel', { 107 | font: 'Colossal', 108 | horizontalLayout: 'fitted', 109 | verticalLayout: 'default', 110 | }, cb)); 111 | } 112 | } 113 | 114 | module.exports = CLI; 115 | -------------------------------------------------------------------------------- /integration/zap/pages/zap-core.js: -------------------------------------------------------------------------------- 1 | /* eslint max-len: ["error", 150] */ 2 | const rp = require('request-promise'); 3 | const env = require('../cucumber/environment'); 4 | const { URL } = require('url'); 5 | 6 | class ZapCore { 7 | // eslint-disable-next-line class-methods-use-this 8 | async sendRequestToZAP(path, options = {}) { 9 | return rp(Object.assign({ 10 | uri: new URL(path, env.server).href, 11 | json: true, 12 | }, options)); 13 | } 14 | 15 | async setsetOptionMaxDepth(value) { 16 | return this.sendRequestToZAP('JSON/spider/action/setOptionMaxDepth', { 17 | qs: { 18 | zapapiformat: 'JSON', 19 | formMethod: 'GET', 20 | Integer: value, 21 | }, 22 | }); 23 | } 24 | 25 | async setOptionThreadCount(value) { 26 | return this.sendRequestToZAP('JSON/spider/action/setOptionThreadCount', { 27 | qs: { 28 | zapapiformat: 'JSON', 29 | formMethod: 'GET', 30 | Integer: value, 31 | }, 32 | }); 33 | } 34 | 35 | async startScan(value) { 36 | return this.sendRequestToZAP('JSON/spider/action/scan', { 37 | qs: { 38 | zapapiformat: 'JSON', 39 | formMethod: 'GET', 40 | url: value, 41 | maxChildren: '', 42 | recurse: '', 43 | contextName: '', 44 | subtreeOnly: '', 45 | }, 46 | }); 47 | } 48 | 49 | async startPassiveScan() { 50 | return this.sendRequestToZAP('JSON/pscan/action/enableAllScanners/', { 51 | qs: { 52 | zapapiformat: 'JSON', 53 | formMethod: 'GET', 54 | }, 55 | }); 56 | } 57 | 58 | async newScanSession() { 59 | return this.sendRequestToZAP('JSON/core/action/newSession/', { 60 | qs: { 61 | zapapiformat: 'JSON', 62 | formMethod: 'GET', 63 | name: '', 64 | overwrite: '', 65 | }, 66 | }); 67 | } 68 | 69 | async stopAllSpiderScans() { 70 | return this.sendRequestToZAP('JSON/spider/action/stopAllScans/', { 71 | qs: { 72 | zapapiformat: 'JSON', 73 | formMethod: 'GET', 74 | }, 75 | }); 76 | } 77 | 78 | async removeAllSpiderScans() { 79 | return this.sendRequestToZAP('JSON/spider/action/removeAllScans/', { 80 | qs: { 81 | zapapiformat: 'JSON', 82 | formMethod: 'GET', 83 | }, 84 | }); 85 | } 86 | 87 | async disableAllActiveScanners() { 88 | return this.sendRequestToZAP('JSON/ascan/action/disableAllScanners/', { 89 | qs: { 90 | zapapiformat: 'JSON', 91 | formMethod: 'GET', 92 | scanPolicyName: '', 93 | }, 94 | }); 95 | } 96 | 97 | async deleteExistingAlerts() { 98 | return this.sendRequestToZAP('JSON/core/action/deleteAllAlerts/', { 99 | qs: { 100 | zapapiformat: 'JSON', 101 | formMethod: 'GET', 102 | }, 103 | }); 104 | } 105 | 106 | async checkForAlerts() { 107 | return this.sendRequestToZAP('OTHER/core/other/mdreport/', { 108 | qs: { 109 | formMethod: 'GET', 110 | }, 111 | }); 112 | } 113 | 114 | async addScanPolicy(policy, threshold, attackStrength) { 115 | return this.sendRequestToZAP('JSON/ascan/action/addScanPolicy/', { 116 | qs: { 117 | zapapiformat: 'JSON', 118 | formMethod: 'GET', 119 | scanPolicyName: policy, 120 | alertThreshold: threshold, 121 | attackStrength, 122 | }, 123 | }); 124 | } 125 | 126 | async startActiveScan(url) { 127 | return this.sendRequestToZAP('JSON/ascan/action/scan', { 128 | qs: { 129 | zapapiformat: 'JSON', 130 | formMethod: 'GET', 131 | url, 132 | recurse: '', 133 | inScopeOnly: '', 134 | scanPolicyName: '', 135 | method: '', 136 | postData: '', 137 | contextId: '', 138 | }, 139 | }); 140 | } 141 | 142 | async checkSpiderStatus(scanId) { 143 | const resp = await this.sendRequestToZAP('JSON/spider/view/status', { 144 | qs: { 145 | zapapiformat: 'JSON', 146 | formMethod: 'GET', 147 | scanId, 148 | }, 149 | }); 150 | return resp.status === '100'; 151 | } 152 | 153 | async checkActiveScanStatus(scanId) { 154 | const resp = await this.sendRequestToZAP('JSON/ascan/view/status', { 155 | qs: { 156 | zapapiformat: 'JSON', 157 | formMethod: 'GET', 158 | scanId, 159 | }, 160 | }); 161 | return resp.status === '100'; 162 | } 163 | } 164 | module.exports = ZapCore; 165 | -------------------------------------------------------------------------------- /integration/selenium/cucumber/setup-driver.js: -------------------------------------------------------------------------------- 1 | /* eslint 2 | new-cap: 0, 3 | func-names: 0, 4 | prefer-arrow-callback: 0 5 | */ 6 | 7 | const webdriver = require('selenium-webdriver'); 8 | const proxy = require('selenium-webdriver/proxy'); 9 | const chrome = require('selenium-webdriver/chrome'); 10 | const fs = require('fs'); 11 | const { URL } = require('url'); 12 | const rp = require('request-promise-native'); 13 | const sharedEnv = require('../../../lib/environment'); 14 | 15 | const env = { 16 | browser: process.env.SELENIUM_BROWSER || 'chrome', 17 | remoteUrl: process.env.SELENIUM_REMOTE_URL || 'http://selenium:4444/wd/hub', 18 | executionEnv: process.env.EXECUTION_ENVIRONMENT || 'local', 19 | proxyURL: process.env.ZAP_SERVER_URL || 'http://zap:8080', 20 | pageLoadTimeout: sharedEnv.parseTimeout(process.env.WEBDRIVER_PAGE_TIMEOUT, 45000), 21 | remoteSeleniumcapabilities: process.env.SELENIUM_REMOTE_CAPABILITY, 22 | waitForSeleniumTimeout: sharedEnv.parseTimeout(process.env.SELENIUM_SERVICE_START_TIMEOUT, 45000), 23 | }; 24 | 25 | async function waitForSeleniumDriver() { 26 | let resp; 27 | let timedOut = false; 28 | const timeout = Date.now() + env.waitForSeleniumTimeout; 29 | const url = new URL(env.remoteUrl); 30 | do { 31 | try { 32 | resp = await rp({ // eslint-disable-line no-await-in-loop 33 | uri: url.href, 34 | resolveWithFullResponse: true, 35 | }); 36 | } catch (e) { 37 | // Ignore connection errors because we are waiting for the container to start 38 | resp = { statusCode: 418 }; 39 | await new Promise(r => setTimeout(r, 10000)); // eslint-disable-line no-await-in-loop 40 | } 41 | timedOut = Date.now() > timeout; 42 | if (timedOut) { 43 | throw new Error('Timeout waiting for request to succeed'); 44 | } 45 | } while (resp.statusCode !== 200); 46 | } 47 | 48 | function createDriver() { 49 | let builder = new webdriver.Builder() 50 | .forBrowser(env.browser); 51 | 52 | if (env.executionEnv === 'proxy') { 53 | const url = new URL(env.proxyURL); 54 | const options = new chrome.Options(); 55 | builder = builder 56 | .withCapabilities(options.toCapabilities()) 57 | .setProxy(proxy.manual({ http: `${url.host}` })); 58 | } 59 | 60 | if (env.executionEnv === 'remote') { 61 | let remoteSeleniumcapabilitiesParams; 62 | if (env.remoteSeleniumcapabilities) { 63 | remoteSeleniumcapabilitiesParams = JSON.parse(fs.readFileSync(env.remoteSeleniumcapabilities, 'utf8')); 64 | } 65 | builder = builder.withCapabilities(remoteSeleniumcapabilitiesParams); 66 | } 67 | 68 | const driver = builder.build(); 69 | 70 | 71 | if (env.executionEnv !== 'remote') { 72 | driver.manage().window().setSize(1920, 1080); 73 | } else { 74 | driver.manage().window().maximize(); 75 | } 76 | driver.manage().timeouts().pageLoadTimeout(env.pageLoadTimeout); 77 | return driver; 78 | } 79 | 80 | function configureDriver() { 81 | let driver; 82 | let hasDriver = false; 83 | Object.defineProperty(this, 'hasDriver', { 84 | get: () => hasDriver, 85 | set: (value) => { 86 | if (hasDriver && !value) { 87 | driver = undefined; 88 | } 89 | hasDriver = value; 90 | }, 91 | configurable: true, 92 | enumerable: true, 93 | }); 94 | Object.defineProperty(this, 'driver', { 95 | get: () => { 96 | if (!hasDriver) { 97 | driver = createDriver(); 98 | hasDriver = !!driver; 99 | } 100 | return driver; 101 | }, 102 | configurable: true, 103 | enumerable: true, 104 | }); 105 | this.getDriver = () => this.driver; 106 | } 107 | 108 | async function stopDriver() { 109 | if (this.hasDriver) { 110 | await this.driver.quit(); 111 | } 112 | this.hasDriver = false; 113 | } 114 | 115 | async function saveScreenshot(scenario) { 116 | if (!this.hasDriver) { 117 | return; 118 | } 119 | if (!scenario.isFailed()) { 120 | return; 121 | } 122 | // On a failed scenario, take a screenshot 123 | try { 124 | const data = await this.driver.takeScreenshot(); 125 | scenario.attach(Buffer.from(data, 'base64'), 'image/png'); 126 | } catch (e) { 127 | // Do not report another error here if the driver is unavailable. 128 | } 129 | } 130 | 131 | module.exports = function () { 132 | this.registerHandler('BeforeFeatures', { 133 | timeout: env.waitForSeleniumTimeout, 134 | }, waitForSeleniumDriver); 135 | this.Before(configureDriver); 136 | this.After(stopDriver); 137 | this.After(saveScreenshot); 138 | this.BeforeScenario(function (scenario) { 139 | env.testrunname = scenario.getName(); 140 | }); 141 | }; 142 | -------------------------------------------------------------------------------- /integration/snyk.io/service/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | /* eslint-disable import/no-unresolved */ 3 | const { spawn } = require('child_process'); 4 | const path = require('path'); 5 | const Koa = require('koa'); 6 | const bodyParser = require('koa-bodyparser'); 7 | 8 | const app = new Koa(); 9 | const router = require('koa-router')({ 10 | prefix: '', 11 | }); 12 | 13 | const port = process.env.SVC_PORT || '8086'; 14 | const svcTimeout = process.env.SNYK_SVC_TIMEOUT || '300000'; // 5 mins 15 | 16 | function runCommand(prog, args, options = {}) { 17 | const cmd = spawn(prog, args, options); 18 | let result = ''; 19 | return new Promise((resolve, reject) => { 20 | cmd.stdout.on('data', (data) => { 21 | result += data; 22 | }); 23 | cmd.on('error', (err) => { 24 | console.log(err); 25 | reject(err); 26 | }); 27 | cmd.on('exit', (code) => { 28 | console.log(result); 29 | console.log(code); 30 | resolve({ code, result }); 31 | }); 32 | }); 33 | } 34 | 35 | function uniqueArray(arr) { 36 | return [...new Set(arr.map(o => JSON.stringify(o)))].map(s => JSON.parse(s)); 37 | } 38 | 39 | async function snykTestToHtml(workingDir) { 40 | let snyk; 41 | if (workingDir === undefined) { 42 | snyk = spawn('snyk', ['test', '--all-projects', '--json']); 43 | } else { 44 | snyk = spawn('snyk', ['test', '--all-projects', '--json'], workingDir); 45 | } 46 | const snykToHtml = spawn('snyk-to-html', ['-s']); 47 | let snykHtmlresult = ''; 48 | let snykTestResult = ''; 49 | 50 | // Pipe snyk output into snykToHtml 51 | snyk.stdout.on('data', (data) => { 52 | snykTestResult += data.toString(); 53 | snykToHtml.stdin.write(data); 54 | }); 55 | snykToHtml.stdout.on('data', (data) => { 56 | snykHtmlresult += data.toString(); 57 | }); 58 | 59 | // Wait for the snyk process to finish 60 | await new Promise((resolve, reject) => { 61 | snyk.on('close', (code) => { 62 | console.log('snyk test', code); 63 | snykToHtml.stdin.end(); 64 | resolve(); 65 | }); 66 | snyk.on('error', (err) => { 67 | console.log('snyk test', err); 68 | reject(err); 69 | }); 70 | }); 71 | 72 | // Wait for the snyk-to-html process to finish 73 | await new Promise((resolve, reject) => { 74 | snykToHtml.on('close', (code) => { 75 | console.log('snyk-to-html', code); 76 | resolve(); 77 | }); 78 | snykToHtml.on('error', (err) => { 79 | console.log('snyk-to-html', err); 80 | reject(err); 81 | }); 82 | }); 83 | 84 | // Parse the snyk output as json 85 | const snykTestJSON = JSON.parse(snykTestResult); 86 | let vulns = []; 87 | 88 | if (snykTestJSON.ok !== undefined && !snykTestJSON.ok && snykTestJSON.error !== undefined) { 89 | throw new Error(snykTestJSON.error); 90 | } 91 | 92 | if (snykTestJSON.vulnerabilities) { 93 | vulns = snykTestJSON.vulnerabilities.map((vuln) => { 94 | const { 95 | id, title, severity, from, 96 | } = vuln; 97 | return { 98 | id, 99 | title, 100 | severity, 101 | from: from.join(','), 102 | url: `https://snyk.io/vuln/${id}`, 103 | }; 104 | }); 105 | } 106 | 107 | return { 108 | vulnerabilities: uniqueArray(vulns), 109 | report: snykHtmlresult, 110 | }; 111 | } 112 | 113 | router.get('/snyk/run', async (ctx) => { 114 | ctx.set('Content-type', 'application/json'); 115 | const authResult = await runCommand('snyk', ['auth', '$SNYK_TOKEN'], { shell: true }); 116 | if (authResult.code !== 0) { 117 | ctx.body = authResult; 118 | ctx.status = 500; 119 | return; 120 | } 121 | 122 | try { 123 | const testResult = snykTestToHtml(); 124 | ctx.body = testResult; 125 | return; 126 | } catch (parseError) { 127 | ctx.body = parseError.message; 128 | ctx.status = 500; 129 | } 130 | }); 131 | 132 | router.post('/snyk/run', async (ctx) => { 133 | ctx.set('Content-type', 'application/json'); 134 | const cwd = path.join(process.cwd(), ctx.request.body.working_directory || '.'); 135 | const authResult = await runCommand('snyk', ['auth', '$SNYK_TOKEN'], { cwd, shell: true }); 136 | if (authResult.code !== 0) { 137 | ctx.body = authResult; 138 | ctx.status = 500; 139 | return; 140 | } 141 | 142 | try { 143 | const testResult = await snykTestToHtml({ cwd }); 144 | ctx.body = testResult; 145 | return; 146 | } catch (parseError) { 147 | ctx.body = parseError.message; 148 | ctx.status = 500; 149 | } 150 | }); 151 | 152 | app 153 | .use(bodyParser()) 154 | .use(router.routes()) 155 | .use(router.allowedMethods()); 156 | 157 | app 158 | .listen(parseInt(port, 10)) 159 | .setTimeout(parseInt(svcTimeout, 10)); 160 | -------------------------------------------------------------------------------- /integration/zap/cucumber/zap.steps.js: -------------------------------------------------------------------------------- 1 | /* eslint 2 | new-cap: 0, 3 | func-names: 0, 4 | prefer-arrow-callback: 0, 5 | */ 6 | const assert = require('assert'); 7 | const ZapCore = require('../pages/zap-core'); 8 | const env = require('./environment'); 9 | 10 | let url = ''; 11 | const zap = new ZapCore(); 12 | 13 | async function sleep(ms) { 14 | return new Promise((resolve) => { 15 | setTimeout(resolve, ms); 16 | }); 17 | } 18 | 19 | async function waitForResult(result, timeout, action) { 20 | const now = Date.now(); 21 | let done = await action(); 22 | while (done !== result) { 23 | if (timeout > 0 && Date.now() > (now + timeout)) { 24 | throw new Error('Timeout waiting for zap scan to complete'); 25 | } 26 | await sleep(1000); // eslint-disable-line no-await-in-loop 27 | done = await action(); // eslint-disable-line no-await-in-loop 28 | } 29 | } 30 | 31 | module.exports = function () { 32 | this.Then(/^the application is spidered/, { timeout: env.longTimeout }, async function () { 33 | zap.setsetOptionMaxDepth(env.maxDepth); 34 | zap.setOptionThreadCount(env.threadCount); 35 | 36 | url = await this.driver.getCurrentUrl(); 37 | 38 | const resp = await zap.startScan(url); 39 | const scanID = resp.scan; 40 | await waitForResult(true, env.scanTimeout, () => zap.checkSpiderStatus(scanID)); 41 | }); 42 | 43 | this.Then(/^the passive scanner is enabled/, async function () { 44 | await zap.startPassiveScan(); 45 | }); 46 | 47 | this.Then(/^the active scanner is run/, { timeout: env.longTimeout }, async function () { 48 | const resp = await zap.startActiveScan(url); 49 | const scanID = resp.scan; 50 | await waitForResult(true, env.scanTimeout, () => zap.checkActiveScanStatus(scanID)); 51 | }); 52 | 53 | this.Then(/^a new scanning session/, async function () { 54 | await zap.newScanSession(); 55 | }); 56 | 57 | this.Then(/^the navigation and spider status is reset/, async function () { 58 | await zap.stopAllSpiderScans(); 59 | await zap.removeAllSpiderScans(); 60 | }); 61 | 62 | this.Then(/^a scanner with all policies disabled/, async function () { 63 | await zap.disableAllActiveScanners(); 64 | }); 65 | 66 | this.Then(/^all existing alerts are deleted/, async function () { 67 | await zap.disableAllActiveScanners(); 68 | }); 69 | 70 | this.Then(/^no higher risk vulnerabilities should be present/, async function () { 71 | const result = await zap.checkForAlerts(); 72 | assert(!(result.includes('High (')), 'We have HIGH security alert reported by ZAP'); 73 | }); 74 | 75 | this.Then(/^the "([^"]+)" policy is enabled with "([^"]+)" threshold and "([^"]+)" attack strength$/, async function (policy, threshold, alert) { 76 | switch (policy.toString().trim().toLowerCase()) { 77 | case 'sql injection': 78 | await zap.addScanPolicy('sql+injection', threshold, alert); 79 | break; 80 | case 'cross site scripting': 81 | await zap.addScanPolicy('cross+site+scripting', threshold, alert); 82 | break; 83 | case 'path traversal': 84 | await zap.addScanPolicy('path+traversal', threshold, alert); 85 | break; 86 | case 'remote file inclusion': 87 | await zap.addScanPolicy('remote+file+inclusion', threshold, alert); 88 | break; 89 | case 'server side include': 90 | await zap.addScanPolicy('server+side+include', threshold, alert); 91 | break; 92 | case 'server side code injection': 93 | await zap.addScanPolicy('server+side+code+injection', threshold, alert); 94 | break; 95 | case 'remote os command injection': 96 | await zap.addScanPolicy('remote+os+command+injection', threshold, alert); 97 | break; 98 | case 'crlf injection': 99 | await zap.addScanPolicy('crlf+injection', threshold, alert); 100 | break; 101 | case 'external redirect': 102 | await zap.addScanPolicy('external+redirect', threshold, alert); 103 | break; 104 | case 'source code disclosure': 105 | await zap.addScanPolicy('source+code+disclosure', threshold, alert); 106 | break; 107 | case 'shell shock': 108 | await zap.addScanPolicy('shell+shock', threshold, alert); 109 | break; 110 | case 'ldap injection': 111 | await zap.addScanPolicy('ldap+injection', threshold, alert); 112 | break; 113 | case 'xpath injection': 114 | await zap.addScanPolicy('xpath+injection', threshold, alert); 115 | break; 116 | case 'xml external entity': 117 | await zap.addScanPolicy('xml+external+entity', threshold, alert); 118 | break; 119 | case 'padding oracle': 120 | await zap.addScanPolicy('padding+oracle', threshold, alert); 121 | break; 122 | case 'insecure http methods': 123 | await zap.addScanPolicy('insecure+http+methods', threshold, alert); 124 | break; 125 | default: 126 | // Do Nothing For Now 127 | } 128 | }); 129 | }; 130 | -------------------------------------------------------------------------------- /integration/sslyze/cucumber/sslyze.steps.js: -------------------------------------------------------------------------------- 1 | /* eslint 2 | new-cap: 0, 3 | func-names: 0, 4 | prefer-arrow-callback: 0, 5 | no-console: 0, 6 | */ 7 | const { URL } = require('url'); 8 | const env = require('./environment'); 9 | const Sslyze = require('../pages/sslyze'); 10 | const chai = require('chai'); 11 | const chaiAsPromised = require('chai-as-promised'); 12 | 13 | chai.use(chaiAsPromised); 14 | const { assert } = chai; 15 | const errorMessage = 'Vulnerability detected'; 16 | 17 | const cachedOutput = {}; 18 | 19 | const getHost = function (url) { 20 | if (url.startsWith('http:') || url.startsWith('https:')) { 21 | return new URL(url).host; 22 | } 23 | return url; 24 | }; 25 | 26 | const getSslyzeOutput = async function (hostname) { 27 | const host = getHost(hostname); 28 | if (!cachedOutput[host]) { 29 | const sslyze = new Sslyze(); 30 | const results = await sslyze.startTheProcess(host); 31 | const ciphersSupported = sslyze.listAcceptedCipherSuites(); 32 | const protocolSupported = ciphersSupported.reduce((protocols, cipherSuite) => { 33 | if (protocols.includes(cipherSuite.type)) { 34 | return protocols; 35 | } 36 | return protocols.concat(cipherSuite.type); 37 | }, []); 38 | cachedOutput[host] = { 39 | sslyzeOutput: results, 40 | ciphersSupported, 41 | protocolSupported, 42 | }; 43 | console.log(cachedOutput[host].sslyzeOutput.stdOut); 44 | } 45 | return cachedOutput[host]; 46 | }; 47 | 48 | module.exports = function () { 49 | this.When(/^the SSLyze command is run against the host$/, { timeout: env.longTimeout }, async function () { 50 | const output = await getSslyzeOutput(env.serverHostName); 51 | Object.assign(this, output); 52 | }); 53 | 54 | this.When(/^the SSLyze command is run against the "([^"]*)"$/, { timeout: env.longTimeout }, async function (host) { 55 | const output = await getSslyzeOutput(host); 56 | Object.assign(this, output); 57 | }); 58 | 59 | this.Then(/^the SSLyze output must contain the text "([^"]*)"$/, function (arg1) { 60 | assert(this.sslyzeOutput.stdOut.indexOf(arg1) !== -1, `${errorMessage}: SSLyze scan did not contain any line matching - '${arg1}'`); 61 | }); 62 | 63 | this.Then(/^the SSLyze output must contain a line that matches (.*)$/, async function (regex) { 64 | assert(this.sslyzeOutput.stdOut.search(regex) !== -1, `${errorMessage}: SSLyze scan did not contain any line matching - '${regex}'`); 65 | }); 66 | 67 | this.Then(/^the minimum key size must be (.*) bits$/, function (arg1) { 68 | assert(this.ciphersSupported.length > 0, `${errorMessage}: The host does not support any valid ciphers`); 69 | 70 | this.ciphersSupported.forEach((ciphers) => { 71 | assert(ciphers.size >= arg1, `${errorMessage}: ${ciphers.name} has key size less than ${arg1} bits`); 72 | }); 73 | }); 74 | 75 | this.Then(/^the following protocols must not be supported$/, async function (table) { 76 | assert(this.protocolSupported.length > 0, `${errorMessage}: The host does not support any valid protocols`); 77 | const data = table.hashes(); 78 | const matches = data 79 | .map(d => Sslyze.formatProtocol(d.protocol)) 80 | .filter(d => this.protocolSupported.includes(d)); 81 | assert.deepEqual(matches, [], `${errorMessage}: protocols must not be supported`); 82 | }); 83 | 84 | this.Then(/^the following protocols must be supported$/, async function (table) { 85 | assert(this.protocolSupported.length > 0, `${errorMessage}: The host does not support any valid protocols`); 86 | const data = table.hashes(); 87 | const matches = data 88 | .map(d => Sslyze.formatProtocol(d.protocol)) 89 | .filter(p => !this.protocolSupported.includes(p)); 90 | assert.deepEqual(matches, [], `${errorMessage}: protocols must be supported`); 91 | }); 92 | 93 | this.Then(/^any of the following ciphers must be supported$/, async function (table) { 94 | assert(this.ciphersSupported.length > 0, `${errorMessage}: The host does not support any valid ciphers`); 95 | 96 | const data = table.hashes(); 97 | for (let i = 0; i < data.length; i += 1) { 98 | assert(this.ciphersSupported.some(ciphers => ciphers.name === data[i].ciphers), `${errorMessage}: ${data[i].ciphers} cipher is not supported`); 99 | } 100 | }); 101 | 102 | this.Then(/^the following ciphers must not be supported$/, async function (table) { 103 | assert(this.ciphersSupported.length > 0, `${errorMessage}: The host does not support any valid ciphers`); 104 | 105 | const data = table.hashes(); 106 | for (let i = 0; i < data.length; i += 1) { 107 | assert(!this.ciphersSupported.some(ciphers => ciphers.name === data[i].ciphers), `${errorMessage}: ${data[i].ciphers} cipher is supported`); 108 | } 109 | }); 110 | 111 | this.Then(/^the certificate has a matching host name$/, function () { 112 | assert(this.sslyzeOutput.stdOut.indexOf(`${env.serverHostName.replace(/^https?:\/\//, '')}`) !== -1, `${errorMessage}: None of Certificate has matching hostname - ${env.serverHostName.replace(/^https?:\/\//, '')}`); 113 | }); 114 | 115 | this.Then(/^the certificate is in major root CA trust stores$/, function () { 116 | assert(this.sslyzeOutput.stdOut.search('OK - Certificate is trusted') !== -1, `${errorMessage}: Found Certificate that is not trusted`); 117 | assert(this.sslyzeOutput.stdOut.search('Certificate is not trusted') === -1, `${errorMessage}: Found Certificate that is not trusted`); 118 | }); 119 | }; 120 | -------------------------------------------------------------------------------- /integration/cucumber-report/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cucumber-report", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "balanced-match": { 8 | "version": "1.0.2", 9 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 10 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 11 | }, 12 | "brace-expansion": { 13 | "version": "1.1.11", 14 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 15 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 16 | "requires": { 17 | "balanced-match": "^1.0.0", 18 | "concat-map": "0.0.1" 19 | } 20 | }, 21 | "concat-map": { 22 | "version": "0.0.1", 23 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 24 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 25 | }, 26 | "cucumber-html-reporter": { 27 | "version": "5.0.0", 28 | "resolved": "https://registry.npmjs.org/cucumber-html-reporter/-/cucumber-html-reporter-5.0.0.tgz", 29 | "integrity": "sha512-rZokbzSjeVONJVmode4eZbZF8NWJksvtebG15ZSdw1JnVx/pn4WqMRiwDz+XRmS2x1O/POSqVv5f/e+UJ1z8kQ==", 30 | "requires": { 31 | "find": "^0.2.7", 32 | "fs-extra": "^3.0.1", 33 | "js-base64": "^2.3.2", 34 | "jsonfile": "^3.0.0", 35 | "lodash": "^4.17.11", 36 | "opn": "5.3.0" 37 | } 38 | }, 39 | "find": { 40 | "version": "0.2.9", 41 | "resolved": "https://registry.npmjs.org/find/-/find-0.2.9.tgz", 42 | "integrity": "sha1-S3Px/55WrZG3bnFkB/5f/mVUu4w=", 43 | "requires": { 44 | "traverse-chain": "~0.1.0" 45 | } 46 | }, 47 | "fs-extra": { 48 | "version": "3.0.1", 49 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", 50 | "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", 51 | "requires": { 52 | "graceful-fs": "^4.1.2", 53 | "jsonfile": "^3.0.0", 54 | "universalify": "^0.1.0" 55 | } 56 | }, 57 | "fs.realpath": { 58 | "version": "1.0.0", 59 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 60 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 61 | }, 62 | "function-bind": { 63 | "version": "1.1.1", 64 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 65 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 66 | }, 67 | "glob": { 68 | "version": "7.2.0", 69 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 70 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 71 | "requires": { 72 | "fs.realpath": "^1.0.0", 73 | "inflight": "^1.0.4", 74 | "inherits": "2", 75 | "minimatch": "^3.0.4", 76 | "once": "^1.3.0", 77 | "path-is-absolute": "^1.0.0" 78 | } 79 | }, 80 | "graceful-fs": { 81 | "version": "4.1.15", 82 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", 83 | "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" 84 | }, 85 | "has": { 86 | "version": "1.0.3", 87 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 88 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 89 | "requires": { 90 | "function-bind": "^1.1.1" 91 | } 92 | }, 93 | "inflight": { 94 | "version": "1.0.6", 95 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 96 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 97 | "requires": { 98 | "once": "^1.3.0", 99 | "wrappy": "1" 100 | } 101 | }, 102 | "inherits": { 103 | "version": "2.0.4", 104 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 105 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 106 | }, 107 | "interpret": { 108 | "version": "1.4.0", 109 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", 110 | "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" 111 | }, 112 | "is-core-module": { 113 | "version": "2.8.1", 114 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", 115 | "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", 116 | "requires": { 117 | "has": "^1.0.3" 118 | } 119 | }, 120 | "is-wsl": { 121 | "version": "1.1.0", 122 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", 123 | "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" 124 | }, 125 | "js-base64": { 126 | "version": "2.5.1", 127 | "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", 128 | "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==" 129 | }, 130 | "jsonfile": { 131 | "version": "3.0.1", 132 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", 133 | "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", 134 | "requires": { 135 | "graceful-fs": "^4.1.6" 136 | } 137 | }, 138 | "lodash": { 139 | "version": "4.17.21", 140 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 141 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 142 | }, 143 | "minimatch": { 144 | "version": "3.0.4", 145 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 146 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 147 | "requires": { 148 | "brace-expansion": "^1.1.7" 149 | } 150 | }, 151 | "once": { 152 | "version": "1.4.0", 153 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 154 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 155 | "requires": { 156 | "wrappy": "1" 157 | } 158 | }, 159 | "opn": { 160 | "version": "5.3.0", 161 | "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", 162 | "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", 163 | "requires": { 164 | "is-wsl": "^1.1.0" 165 | } 166 | }, 167 | "path-is-absolute": { 168 | "version": "1.0.1", 169 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 170 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 171 | }, 172 | "path-parse": { 173 | "version": "1.0.7", 174 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 175 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" 176 | }, 177 | "rechoir": { 178 | "version": "0.6.2", 179 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 180 | "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", 181 | "requires": { 182 | "resolve": "^1.1.6" 183 | } 184 | }, 185 | "resolve": { 186 | "version": "1.21.0", 187 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", 188 | "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", 189 | "requires": { 190 | "is-core-module": "^2.8.0", 191 | "path-parse": "^1.0.7", 192 | "supports-preserve-symlinks-flag": "^1.0.0" 193 | } 194 | }, 195 | "shelljs": { 196 | "version": "0.8.5", 197 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", 198 | "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", 199 | "requires": { 200 | "glob": "^7.0.0", 201 | "interpret": "^1.0.0", 202 | "rechoir": "^0.6.2" 203 | } 204 | }, 205 | "supports-preserve-symlinks-flag": { 206 | "version": "1.0.0", 207 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 208 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" 209 | }, 210 | "traverse-chain": { 211 | "version": "0.1.0", 212 | "resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz", 213 | "integrity": "sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=" 214 | }, 215 | "universalify": { 216 | "version": "0.1.2", 217 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 218 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" 219 | }, 220 | "wrappy": { 221 | "version": "1.0.2", 222 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 223 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | [![npm](https://img.shields.io/npm/v/sentinel-ast.svg)](https://www.npmjs.com/package/sentinel-ast) 3 | [![License](https://img.shields.io/npm/l/sentinel-ast.svg)](https://github.com/nintexplatform/sentinel/blob/master/LICENSE) 4 | [![Build Status](https://travis-ci.org/nintexplatform/sentinel.svg?branch=master)](https://travis-ci.org/nintexplatform/sentinel) 5 | 6 | # Sentinel 7 | 8 | Sentinel is a framework that enables _automated security testing_ via a suite of industry standard test frameworks and security tools. 9 | 10 | It is built on Cucumber and Node.js. This allows for security test cases to be defined in Gherkin/BDD syntax making them human readable and self documenting. The idea is that we make security testing a concept that is approachable(tests written by developers, testers, security guys), repeatable(when integrated with your CI/CD pipelines) and auditable(when used to gather evidence in compliancy initiatives). 11 | 12 | Sentinel was inspired by existing security frameworks(Gauntlt, Mittn, BDD-Security) but we felt the need to provide our own flavour to security testing with a modern javascript and docker based environment. 13 | 14 | # Features 15 | Sentinel is currently integrated with 16 | - Automated security scanners - [Open Zap](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project), [SSLyze](https://github.com/nabla-c0d3/sslyze) and [snyk](https://snyk.io) to find security vulnerabilities in your web applications. 17 | - Selenium/WebDriver and Node.js for implementing browser and API based automated tests. 18 | - Docker/Compose that enables drop-in isolation of integrated components during runtime. It also enables what we call the Bring-Your-Own-Container(s) feature, which gives consumers of Sentinel the capability to attach their web applications/services as containers onto Sentinels' networking infrastructure. 19 | - Reporting tools. 20 | 21 | It has been designed from ground-up to be completely [extensible](#extensibility). 22 | 23 | # Quickstart 24 | 25 | We want to get you off the ground and started as quick as possible in just a few steps. Running commands below on your shell will install Node.js, Docker and Sentinel running security tests against a local containerized website. 26 | 27 | ```bash 28 | sh -c "$(curl -fsSL https://raw.githubusercontent.com/nintexplatform/sentinel/master/bin/install-dependencies.sh)" 29 | git clone https://github.com/nintexplatform/sentinel-example.git && cd sentinel-example 30 | npm install 31 | npm run test 32 | ``` 33 | 34 | On Linux, run the install-dependencies script under `sudo` for root privileges. 35 | 36 | Once the tests have completed, you can find a generated report under `sentinel-example/report` directory 37 | 38 | We've introduced an example use case of Sentinel in the [`sentinel-example`](https://github.com/nintexplatform/sentinel-example) repo 39 | 40 | # Getting Started 41 | To install the framework: 42 | 1. [Install prequisites](#install-prequisites) 43 | 2. [Install Sentinel](#install-sentinel-via-npm) via npm 44 | 45 | ## Install Prerequisites 46 | These prerequisites must be installed first. 47 | 1. [Node.js](https://nodejs.org/en/download/) Version 7+ 48 | 2. [Docker](https://docs.docker.com/engine/installation/) 49 | 3. [Docker Compose](https://docs.docker.com/compose/install/#install-compose) 50 | 51 | Alternatively, for Docker + Compose, you can also install Docker for [Mac](https://www.docker.com/docker-mac) or [Windows](https://www.docker.com/docker-windows) which is a fast and easy way to get Docker + Compose. 52 | 53 | -or- 54 | 55 | Use our quick-install script 56 | ```bash 57 | sh -c "$(curl -fsSL https://raw.githubusercontent.com/nintexplatform/sentinel/master/bin/install-dependencies.sh)" 58 | ``` 59 | 60 | ## Install Sentinel via npm 61 | 62 | ```bash 63 | npm install -g sentinel-ast 64 | ``` 65 | 66 | From this point, see the [For Developers](#for-developers) section below on how to use Sentinel. 67 | 68 | # For Developers 69 | 70 | ## Sentinel CLI 71 | 72 | Getting Sentinel to run is simple and done primarily through a global(if npm installed with `-g`) CLI. 73 | 74 | ``` bash 75 | sentinel 76 | 77 | Usage: sentinel [options] [command] 78 | 79 | 80 | Options: 81 | 82 | -V, --version output the version number 83 | -h, --help output usage information 84 | 85 | 86 | Commands: 87 | 88 | init Initializes configuration & test templates in the current directory 89 | run-compose [COMMAND] [ARGS...] Runs docker compose commands 90 | run-cucumber [options] [DIR] Runs cucumber tests 91 | start-services [options] Starts services in its containers 92 | stop-services [options] Stops services and its containers 93 | ``` 94 | ``` 95 | sentinel init 96 | ``` 97 | - From an empty directory, you should always run this command first. It initializes the current directory with a default config.env, feature templates and config json files. 98 | - The default parameters in config.env are [explained below](#environment-variables). They should be configured prior to starting up the services. 99 | 100 | ``` 101 | sentinel start-services 102 | ``` 103 | - This command starts all integrated services as containers. 104 | 105 | ``` 106 | sentinel stop-services 107 | ``` 108 | - This command stops all containers hosting integrated services. 109 | 110 | ``` 111 | sentinel run-compose 112 | ``` 113 | - This command proxies the CLI arguments to Docker compose. 114 | 115 | ``` 116 | sentinel run-cucumber 117 | ``` 118 | - This command proxies the CLI arguments to Cucumber-js. 119 | 120 | 121 | ## Integrations 122 | The framework ships with a few integrated components out of the box. If they are hosted within containers, we refer to them as **services**. 123 | 124 | ### Cucumber Report 125 | Adds cucumber hooks to create a report at the end of a test run. 126 | Integrates the [Cucumber Html Reporter](https://www.npmjs.com/package/cucumber-html-reporter) 127 | 128 | ### Slack 129 | Adds hooks to post results at the end of a test run to Slack. 130 | 131 | ### Node 132 | This is a general purpose Node.js container that tests are run in. 133 | It reads environment variables from config.env 134 | Node Version 7+ 135 | 136 | ### Selenium WebDriver 137 | The node [Selenium WebDriver](https://www.npmjs.com/package/selenium-webdriver) package. 138 | It has cucumber hooks to configure the webdriver and adds the driver instance to the world. 139 | It also has a docker service for running a chrome container for remote control of the browser. 140 | 141 | ### SSLyze 142 | A service which can be used for running a SSLyze scan against a host. 143 | [GitHub](https://github.com/iSECPartners/sslyze) 144 | 145 | ### Zap 146 | A service which hosts OWASP ZAP. 147 | [GitHub](https://github.com/zaproxy/zaproxy/) 148 | 149 | ### Snyk 150 | A service which can be used for packages and dependency scanning projects. 151 | [snyk.io](https://snyk.io) 152 | 153 | ## Enabling integrations 154 | Enabling integrations and loading up additional **services** is managed via a config file. It needs to be created in the root folder of the project that references Sentinel, as `.sentinel.json` 155 | 156 | Sample `.sentinel.json` : 157 | ``` 158 | { 159 | "integrations": { 160 | "whitelist": [ 161 | "node", 162 | "docker", 163 | "cucumber-report", 164 | "selenium", 165 | "sslyze", 166 | "zap" 167 | ], 168 | "customServices": [ 169 | "./nodegoat-app/docker-compose.yml" 170 | ] 171 | } 172 | } 173 | ``` 174 | 175 | ## Extensibility 176 | Extending the framework starts with packaging your new **component** as a sub-directory within the `/integration` directory. These components can hook into the Sentinel runtime in a number of ways. 177 | 178 | * Cucumber support files 179 | Any files found in a components `cucumber` folder gets required when starting tests. 180 | This can be used to add step definitions, modify the world, add hooks etc. 181 | (Refer to `/integration/selenium`) 182 | * Docker container/service 183 | Required binaries, cli tools, etc can be exposed as a webservice by adding a compose-*.yml file in the integrations folder. 184 | This lets you define containers that can host the cli and allows test code to use REST calls to access it by service name. 185 | (Refer to `/integration/sslyze`) 186 | * Javascript module 187 | You can create reusable Page Objects or interfaces needed to communicate to **services** by including the classes and exporting them from the `index.js` in the framework's root directory. By doing so, consumers of the Sentinel framework can have access to these objects at runtime. 188 | (Refer to `/integration/zap`) 189 | 190 | ## Environment Variables 191 | 192 | | Integration | Name | Description | Required | Default / Optional Values | 193 | |---------------------|-----------------------------|--------------------------------|----------|-------------| 194 | | sslyze | SSLYZE_SERVER_URL | Url to sslyze api server | false | http://sslyze:8081/ | 195 | | zap | ZAP_SERVER_URL | Url to zap api server | false | http://zap:8080/ | 196 | | zap | ZAP_MAX_DEPTH | zap crawling max depth | false | 5 | 197 | | zap | ZAP_THREAD_DEPTH | zap thread number | false | 5 | 198 | | snyk | SNYK_TOKEN | [Auth token](https://snyk.io/docs/using-snyk#authentication) for snyk| false | | 199 | | snyk | SNYK_URL | Url to snyk api server | false | http://snyk:8086/ | 200 | | application | AUT_SERVER_URL | Url to application under test | true | https://nodegoat:4000 | 201 | | selenium | SELENIUM_BROWSER | Webdriver capabilities | false | chrome | 202 | | selenium | SELENIUM_REMOTE_URL | Webdriver url | true | http://selenium:4444/wd/hub | 203 | | selenium | SELENIUM_REMOTE_CAPABILITY | For remote selenium services | false | ./remoteSelenium.config.template.json | 204 | | selenium | WEBDRIVER_PAGE_TIMEOUT | Webdriver page load timeout | false | 45000 | 205 | | selenium | WEBDRIVER_LONG_TIMEOUT | Timeout for long running step | false | 30000 | 206 | | selenium | EXECUTION_ENVIRONMENT | For zap proxy | false | local (default) / proxy / remote | 207 | | cucumber | FEATURE_DIR | Feature file location | false | ./features/ | 208 | | cucumber | CUCUMBER_LONG_TIMEOUT | timeout for cucumber steps | false | 30000 | 209 | | cucumber-report | CUCUMBER_REPORT_DIR | path to store reports | false | ./report/ | 210 | | slack | SLACK_FEATURE | *ON* or *OFF* the process | false | 'ON' / 'OFF' (default) | 211 | | slack | SLACK_WEBHOOK_URI | Specify the Incoming webhooks url - [Reference](https://api.slack.com/incoming-webhooks) | false | - | 212 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2017 Nintex 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. -------------------------------------------------------------------------------- /integration/git/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ajv": { 8 | "version": "6.12.6", 9 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 10 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 11 | "requires": { 12 | "fast-deep-equal": "^3.1.1", 13 | "fast-json-stable-stringify": "^2.0.0", 14 | "json-schema-traverse": "^0.4.1", 15 | "uri-js": "^4.2.2" 16 | }, 17 | "dependencies": { 18 | "fast-deep-equal": { 19 | "version": "3.1.3", 20 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 21 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 22 | } 23 | } 24 | }, 25 | "asn1": { 26 | "version": "0.2.4", 27 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 28 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 29 | "requires": { 30 | "safer-buffer": "~2.1.0" 31 | } 32 | }, 33 | "assert-plus": { 34 | "version": "1.0.0", 35 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 36 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 37 | }, 38 | "asynckit": { 39 | "version": "0.4.0", 40 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 41 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 42 | }, 43 | "aws-sign2": { 44 | "version": "0.7.0", 45 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 46 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 47 | }, 48 | "aws4": { 49 | "version": "1.8.0", 50 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 51 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 52 | }, 53 | "bcrypt-pbkdf": { 54 | "version": "1.0.2", 55 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 56 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 57 | "requires": { 58 | "tweetnacl": "^0.14.3" 59 | } 60 | }, 61 | "bluebird": { 62 | "version": "3.5.1", 63 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 64 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" 65 | }, 66 | "caseless": { 67 | "version": "0.12.0", 68 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 69 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 70 | }, 71 | "combined-stream": { 72 | "version": "1.0.7", 73 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 74 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 75 | "requires": { 76 | "delayed-stream": "~1.0.0" 77 | } 78 | }, 79 | "core-util-is": { 80 | "version": "1.0.2", 81 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 82 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 83 | }, 84 | "dashdash": { 85 | "version": "1.14.1", 86 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 87 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 88 | "requires": { 89 | "assert-plus": "^1.0.0" 90 | } 91 | }, 92 | "delayed-stream": { 93 | "version": "1.0.0", 94 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 95 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 96 | }, 97 | "ecc-jsbn": { 98 | "version": "0.1.2", 99 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 100 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 101 | "requires": { 102 | "jsbn": "~0.1.0", 103 | "safer-buffer": "^2.1.0" 104 | } 105 | }, 106 | "extend": { 107 | "version": "3.0.2", 108 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 109 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 110 | }, 111 | "extsprintf": { 112 | "version": "1.3.0", 113 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 114 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 115 | }, 116 | "fast-json-stable-stringify": { 117 | "version": "2.0.0", 118 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 119 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 120 | }, 121 | "forever-agent": { 122 | "version": "0.6.1", 123 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 124 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 125 | }, 126 | "form-data": { 127 | "version": "2.3.3", 128 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 129 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 130 | "requires": { 131 | "asynckit": "^0.4.0", 132 | "combined-stream": "^1.0.6", 133 | "mime-types": "^2.1.12" 134 | } 135 | }, 136 | "getpass": { 137 | "version": "0.1.7", 138 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 139 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 140 | "requires": { 141 | "assert-plus": "^1.0.0" 142 | } 143 | }, 144 | "har-schema": { 145 | "version": "2.0.0", 146 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 147 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 148 | }, 149 | "har-validator": { 150 | "version": "5.1.3", 151 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 152 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 153 | "requires": { 154 | "ajv": "^6.5.5", 155 | "har-schema": "^2.0.0" 156 | } 157 | }, 158 | "http-signature": { 159 | "version": "1.2.0", 160 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 161 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 162 | "requires": { 163 | "assert-plus": "^1.0.0", 164 | "jsprim": "^1.2.2", 165 | "sshpk": "^1.7.0" 166 | } 167 | }, 168 | "is-typedarray": { 169 | "version": "1.0.0", 170 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 171 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 172 | }, 173 | "isstream": { 174 | "version": "0.1.2", 175 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 176 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 177 | }, 178 | "jsbn": { 179 | "version": "0.1.1", 180 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 181 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 182 | }, 183 | "json-schema": { 184 | "version": "0.2.3", 185 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 186 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 187 | }, 188 | "json-schema-traverse": { 189 | "version": "0.4.1", 190 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 191 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 192 | }, 193 | "json-stringify-safe": { 194 | "version": "5.0.1", 195 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 196 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 197 | }, 198 | "jsprim": { 199 | "version": "1.4.1", 200 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 201 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 202 | "requires": { 203 | "assert-plus": "1.0.0", 204 | "extsprintf": "1.3.0", 205 | "json-schema": "0.2.3", 206 | "verror": "1.10.0" 207 | } 208 | }, 209 | "lodash": { 210 | "version": "4.17.21", 211 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 212 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 213 | }, 214 | "mime-db": { 215 | "version": "1.40.0", 216 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 217 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 218 | }, 219 | "mime-types": { 220 | "version": "2.1.24", 221 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 222 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 223 | "requires": { 224 | "mime-db": "1.40.0" 225 | } 226 | }, 227 | "oauth-sign": { 228 | "version": "0.9.0", 229 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 230 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 231 | }, 232 | "performance-now": { 233 | "version": "2.1.0", 234 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 235 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 236 | }, 237 | "psl": { 238 | "version": "1.1.31", 239 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", 240 | "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" 241 | }, 242 | "punycode": { 243 | "version": "1.4.1", 244 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 245 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 246 | }, 247 | "qs": { 248 | "version": "6.5.2", 249 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 250 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 251 | }, 252 | "request": { 253 | "version": "2.88.0", 254 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 255 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 256 | "requires": { 257 | "aws-sign2": "~0.7.0", 258 | "aws4": "^1.8.0", 259 | "caseless": "~0.12.0", 260 | "combined-stream": "~1.0.6", 261 | "extend": "~3.0.2", 262 | "forever-agent": "~0.6.1", 263 | "form-data": "~2.3.2", 264 | "har-validator": "~5.1.0", 265 | "http-signature": "~1.2.0", 266 | "is-typedarray": "~1.0.0", 267 | "isstream": "~0.1.2", 268 | "json-stringify-safe": "~5.0.1", 269 | "mime-types": "~2.1.19", 270 | "oauth-sign": "~0.9.0", 271 | "performance-now": "^2.1.0", 272 | "qs": "~6.5.2", 273 | "safe-buffer": "^5.1.2", 274 | "tough-cookie": "~2.4.3", 275 | "tunnel-agent": "^0.6.0", 276 | "uuid": "^3.3.2" 277 | }, 278 | "dependencies": { 279 | "tough-cookie": { 280 | "version": "2.4.3", 281 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 282 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 283 | "requires": { 284 | "psl": "^1.1.24", 285 | "punycode": "^1.4.1" 286 | } 287 | } 288 | } 289 | }, 290 | "request-promise": { 291 | "version": "4.2.2", 292 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", 293 | "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", 294 | "requires": { 295 | "bluebird": "^3.5.0", 296 | "request-promise-core": "1.1.1", 297 | "stealthy-require": "^1.1.0", 298 | "tough-cookie": ">=2.3.3" 299 | } 300 | }, 301 | "request-promise-core": { 302 | "version": "1.1.1", 303 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", 304 | "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", 305 | "requires": { 306 | "lodash": "^4.13.1" 307 | } 308 | }, 309 | "safe-buffer": { 310 | "version": "5.1.2", 311 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 312 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 313 | }, 314 | "safer-buffer": { 315 | "version": "2.1.2", 316 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 317 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 318 | }, 319 | "sshpk": { 320 | "version": "1.16.1", 321 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 322 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 323 | "requires": { 324 | "asn1": "~0.2.3", 325 | "assert-plus": "^1.0.0", 326 | "bcrypt-pbkdf": "^1.0.0", 327 | "dashdash": "^1.12.0", 328 | "ecc-jsbn": "~0.1.1", 329 | "getpass": "^0.1.1", 330 | "jsbn": "~0.1.0", 331 | "safer-buffer": "^2.0.2", 332 | "tweetnacl": "~0.14.0" 333 | } 334 | }, 335 | "stealthy-require": { 336 | "version": "1.1.1", 337 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 338 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" 339 | }, 340 | "tough-cookie": { 341 | "version": "2.3.4", 342 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", 343 | "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", 344 | "requires": { 345 | "punycode": "^1.4.1" 346 | } 347 | }, 348 | "tunnel-agent": { 349 | "version": "0.6.0", 350 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 351 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 352 | "requires": { 353 | "safe-buffer": "^5.0.1" 354 | } 355 | }, 356 | "tweetnacl": { 357 | "version": "0.14.5", 358 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 359 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 360 | }, 361 | "uri-js": { 362 | "version": "4.2.2", 363 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 364 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 365 | "requires": { 366 | "punycode": "^2.1.0" 367 | }, 368 | "dependencies": { 369 | "punycode": { 370 | "version": "2.1.1", 371 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 372 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 373 | } 374 | } 375 | }, 376 | "uuid": { 377 | "version": "3.3.2", 378 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 379 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 380 | }, 381 | "verror": { 382 | "version": "1.10.0", 383 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 384 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 385 | "requires": { 386 | "assert-plus": "^1.0.0", 387 | "core-util-is": "1.0.2", 388 | "extsprintf": "^1.2.0" 389 | } 390 | } 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /integration/zap/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zap", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ajv": { 8 | "version": "6.12.6", 9 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 10 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 11 | "requires": { 12 | "fast-deep-equal": "^3.1.1", 13 | "fast-json-stable-stringify": "^2.0.0", 14 | "json-schema-traverse": "^0.4.1", 15 | "uri-js": "^4.2.2" 16 | }, 17 | "dependencies": { 18 | "fast-deep-equal": { 19 | "version": "3.1.3", 20 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 21 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 22 | } 23 | } 24 | }, 25 | "asn1": { 26 | "version": "0.2.4", 27 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 28 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 29 | "requires": { 30 | "safer-buffer": "~2.1.0" 31 | } 32 | }, 33 | "assert-plus": { 34 | "version": "1.0.0", 35 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 36 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 37 | }, 38 | "asynckit": { 39 | "version": "0.4.0", 40 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 41 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 42 | }, 43 | "aws-sign2": { 44 | "version": "0.7.0", 45 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 46 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 47 | }, 48 | "aws4": { 49 | "version": "1.8.0", 50 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 51 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 52 | }, 53 | "bcrypt-pbkdf": { 54 | "version": "1.0.2", 55 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 56 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 57 | "requires": { 58 | "tweetnacl": "^0.14.3" 59 | } 60 | }, 61 | "bluebird": { 62 | "version": "3.5.1", 63 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 64 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" 65 | }, 66 | "caseless": { 67 | "version": "0.12.0", 68 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 69 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 70 | }, 71 | "combined-stream": { 72 | "version": "1.0.7", 73 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 74 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 75 | "requires": { 76 | "delayed-stream": "~1.0.0" 77 | } 78 | }, 79 | "core-util-is": { 80 | "version": "1.0.2", 81 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 82 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 83 | }, 84 | "dashdash": { 85 | "version": "1.14.1", 86 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 87 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 88 | "requires": { 89 | "assert-plus": "^1.0.0" 90 | } 91 | }, 92 | "delayed-stream": { 93 | "version": "1.0.0", 94 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 95 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 96 | }, 97 | "ecc-jsbn": { 98 | "version": "0.1.2", 99 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 100 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 101 | "requires": { 102 | "jsbn": "~0.1.0", 103 | "safer-buffer": "^2.1.0" 104 | } 105 | }, 106 | "extend": { 107 | "version": "3.0.2", 108 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 109 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 110 | }, 111 | "extsprintf": { 112 | "version": "1.3.0", 113 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 114 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 115 | }, 116 | "fast-json-stable-stringify": { 117 | "version": "2.0.0", 118 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 119 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 120 | }, 121 | "forever-agent": { 122 | "version": "0.6.1", 123 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 124 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 125 | }, 126 | "form-data": { 127 | "version": "2.3.3", 128 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 129 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 130 | "requires": { 131 | "asynckit": "^0.4.0", 132 | "combined-stream": "^1.0.6", 133 | "mime-types": "^2.1.12" 134 | } 135 | }, 136 | "getpass": { 137 | "version": "0.1.7", 138 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 139 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 140 | "requires": { 141 | "assert-plus": "^1.0.0" 142 | } 143 | }, 144 | "har-schema": { 145 | "version": "2.0.0", 146 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 147 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 148 | }, 149 | "har-validator": { 150 | "version": "5.1.3", 151 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 152 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 153 | "requires": { 154 | "ajv": "^6.5.5", 155 | "har-schema": "^2.0.0" 156 | } 157 | }, 158 | "http-signature": { 159 | "version": "1.2.0", 160 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 161 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 162 | "requires": { 163 | "assert-plus": "^1.0.0", 164 | "jsprim": "^1.2.2", 165 | "sshpk": "^1.7.0" 166 | } 167 | }, 168 | "is-typedarray": { 169 | "version": "1.0.0", 170 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 171 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 172 | }, 173 | "isstream": { 174 | "version": "0.1.2", 175 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 176 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 177 | }, 178 | "jsbn": { 179 | "version": "0.1.1", 180 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 181 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 182 | }, 183 | "json-schema": { 184 | "version": "0.2.3", 185 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 186 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 187 | }, 188 | "json-schema-traverse": { 189 | "version": "0.4.1", 190 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 191 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 192 | }, 193 | "json-stringify-safe": { 194 | "version": "5.0.1", 195 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 196 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 197 | }, 198 | "jsprim": { 199 | "version": "1.4.1", 200 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 201 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 202 | "requires": { 203 | "assert-plus": "1.0.0", 204 | "extsprintf": "1.3.0", 205 | "json-schema": "0.2.3", 206 | "verror": "1.10.0" 207 | } 208 | }, 209 | "lodash": { 210 | "version": "4.17.21", 211 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 212 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 213 | }, 214 | "mime-db": { 215 | "version": "1.40.0", 216 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 217 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 218 | }, 219 | "mime-types": { 220 | "version": "2.1.24", 221 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 222 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 223 | "requires": { 224 | "mime-db": "1.40.0" 225 | } 226 | }, 227 | "oauth-sign": { 228 | "version": "0.9.0", 229 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 230 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 231 | }, 232 | "performance-now": { 233 | "version": "2.1.0", 234 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 235 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 236 | }, 237 | "psl": { 238 | "version": "1.1.31", 239 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", 240 | "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" 241 | }, 242 | "punycode": { 243 | "version": "1.4.1", 244 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 245 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 246 | }, 247 | "qs": { 248 | "version": "6.5.2", 249 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 250 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 251 | }, 252 | "request": { 253 | "version": "2.88.0", 254 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 255 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 256 | "requires": { 257 | "aws-sign2": "~0.7.0", 258 | "aws4": "^1.8.0", 259 | "caseless": "~0.12.0", 260 | "combined-stream": "~1.0.6", 261 | "extend": "~3.0.2", 262 | "forever-agent": "~0.6.1", 263 | "form-data": "~2.3.2", 264 | "har-validator": "~5.1.0", 265 | "http-signature": "~1.2.0", 266 | "is-typedarray": "~1.0.0", 267 | "isstream": "~0.1.2", 268 | "json-stringify-safe": "~5.0.1", 269 | "mime-types": "~2.1.19", 270 | "oauth-sign": "~0.9.0", 271 | "performance-now": "^2.1.0", 272 | "qs": "~6.5.2", 273 | "safe-buffer": "^5.1.2", 274 | "tough-cookie": "~2.4.3", 275 | "tunnel-agent": "^0.6.0", 276 | "uuid": "^3.3.2" 277 | }, 278 | "dependencies": { 279 | "tough-cookie": { 280 | "version": "2.4.3", 281 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 282 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 283 | "requires": { 284 | "psl": "^1.1.24", 285 | "punycode": "^1.4.1" 286 | } 287 | } 288 | } 289 | }, 290 | "request-promise": { 291 | "version": "4.2.2", 292 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", 293 | "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", 294 | "requires": { 295 | "bluebird": "^3.5.0", 296 | "request-promise-core": "1.1.1", 297 | "stealthy-require": "^1.1.0", 298 | "tough-cookie": ">=2.3.3" 299 | } 300 | }, 301 | "request-promise-core": { 302 | "version": "1.1.1", 303 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", 304 | "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", 305 | "requires": { 306 | "lodash": "^4.13.1" 307 | } 308 | }, 309 | "safe-buffer": { 310 | "version": "5.1.2", 311 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 312 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 313 | }, 314 | "safer-buffer": { 315 | "version": "2.1.2", 316 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 317 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 318 | }, 319 | "sshpk": { 320 | "version": "1.16.1", 321 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 322 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 323 | "requires": { 324 | "asn1": "~0.2.3", 325 | "assert-plus": "^1.0.0", 326 | "bcrypt-pbkdf": "^1.0.0", 327 | "dashdash": "^1.12.0", 328 | "ecc-jsbn": "~0.1.1", 329 | "getpass": "^0.1.1", 330 | "jsbn": "~0.1.0", 331 | "safer-buffer": "^2.0.2", 332 | "tweetnacl": "~0.14.0" 333 | } 334 | }, 335 | "stealthy-require": { 336 | "version": "1.1.1", 337 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 338 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" 339 | }, 340 | "tough-cookie": { 341 | "version": "2.3.4", 342 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", 343 | "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", 344 | "requires": { 345 | "punycode": "^1.4.1" 346 | } 347 | }, 348 | "tunnel-agent": { 349 | "version": "0.6.0", 350 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 351 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 352 | "requires": { 353 | "safe-buffer": "^5.0.1" 354 | } 355 | }, 356 | "tweetnacl": { 357 | "version": "0.14.5", 358 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 359 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 360 | }, 361 | "uri-js": { 362 | "version": "4.2.2", 363 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 364 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 365 | "requires": { 366 | "punycode": "^2.1.0" 367 | }, 368 | "dependencies": { 369 | "punycode": { 370 | "version": "2.1.1", 371 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 372 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 373 | } 374 | } 375 | }, 376 | "uuid": { 377 | "version": "3.3.2", 378 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 379 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 380 | }, 381 | "verror": { 382 | "version": "1.10.0", 383 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 384 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 385 | "requires": { 386 | "assert-plus": "^1.0.0", 387 | "core-util-is": "1.0.2", 388 | "extsprintf": "^1.2.0" 389 | } 390 | } 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /integration/docker/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ajv": { 8 | "version": "6.12.6", 9 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 10 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 11 | "requires": { 12 | "fast-deep-equal": "^3.1.1", 13 | "fast-json-stable-stringify": "^2.0.0", 14 | "json-schema-traverse": "^0.4.1", 15 | "uri-js": "^4.2.2" 16 | }, 17 | "dependencies": { 18 | "fast-deep-equal": { 19 | "version": "3.1.3", 20 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 21 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 22 | } 23 | } 24 | }, 25 | "asn1": { 26 | "version": "0.2.4", 27 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 28 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 29 | "requires": { 30 | "safer-buffer": "~2.1.0" 31 | } 32 | }, 33 | "assert-plus": { 34 | "version": "1.0.0", 35 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 36 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 37 | }, 38 | "asynckit": { 39 | "version": "0.4.0", 40 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 41 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 42 | }, 43 | "aws-sign2": { 44 | "version": "0.7.0", 45 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 46 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 47 | }, 48 | "aws4": { 49 | "version": "1.8.0", 50 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 51 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 52 | }, 53 | "bcrypt-pbkdf": { 54 | "version": "1.0.2", 55 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 56 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 57 | "requires": { 58 | "tweetnacl": "^0.14.3" 59 | } 60 | }, 61 | "bluebird": { 62 | "version": "3.5.1", 63 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 64 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" 65 | }, 66 | "caseless": { 67 | "version": "0.12.0", 68 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 69 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 70 | }, 71 | "combined-stream": { 72 | "version": "1.0.7", 73 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 74 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 75 | "requires": { 76 | "delayed-stream": "~1.0.0" 77 | } 78 | }, 79 | "core-util-is": { 80 | "version": "1.0.2", 81 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 82 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 83 | }, 84 | "dashdash": { 85 | "version": "1.14.1", 86 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 87 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 88 | "requires": { 89 | "assert-plus": "^1.0.0" 90 | } 91 | }, 92 | "delayed-stream": { 93 | "version": "1.0.0", 94 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 95 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 96 | }, 97 | "ecc-jsbn": { 98 | "version": "0.1.2", 99 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 100 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 101 | "requires": { 102 | "jsbn": "~0.1.0", 103 | "safer-buffer": "^2.1.0" 104 | } 105 | }, 106 | "extend": { 107 | "version": "3.0.2", 108 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 109 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 110 | }, 111 | "extsprintf": { 112 | "version": "1.3.0", 113 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 114 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 115 | }, 116 | "fast-json-stable-stringify": { 117 | "version": "2.0.0", 118 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 119 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 120 | }, 121 | "forever-agent": { 122 | "version": "0.6.1", 123 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 124 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 125 | }, 126 | "form-data": { 127 | "version": "2.3.3", 128 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 129 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 130 | "requires": { 131 | "asynckit": "^0.4.0", 132 | "combined-stream": "^1.0.6", 133 | "mime-types": "^2.1.12" 134 | } 135 | }, 136 | "getpass": { 137 | "version": "0.1.7", 138 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 139 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 140 | "requires": { 141 | "assert-plus": "^1.0.0" 142 | } 143 | }, 144 | "har-schema": { 145 | "version": "2.0.0", 146 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 147 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 148 | }, 149 | "har-validator": { 150 | "version": "5.1.3", 151 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 152 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 153 | "requires": { 154 | "ajv": "^6.5.5", 155 | "har-schema": "^2.0.0" 156 | } 157 | }, 158 | "http-signature": { 159 | "version": "1.2.0", 160 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 161 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 162 | "requires": { 163 | "assert-plus": "^1.0.0", 164 | "jsprim": "^1.2.2", 165 | "sshpk": "^1.7.0" 166 | } 167 | }, 168 | "is-typedarray": { 169 | "version": "1.0.0", 170 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 171 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 172 | }, 173 | "isstream": { 174 | "version": "0.1.2", 175 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 176 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 177 | }, 178 | "jsbn": { 179 | "version": "0.1.1", 180 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 181 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 182 | }, 183 | "json-schema": { 184 | "version": "0.2.3", 185 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 186 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 187 | }, 188 | "json-schema-traverse": { 189 | "version": "0.4.1", 190 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 191 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 192 | }, 193 | "json-stringify-safe": { 194 | "version": "5.0.1", 195 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 196 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 197 | }, 198 | "jsprim": { 199 | "version": "1.4.1", 200 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 201 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 202 | "requires": { 203 | "assert-plus": "1.0.0", 204 | "extsprintf": "1.3.0", 205 | "json-schema": "0.2.3", 206 | "verror": "1.10.0" 207 | } 208 | }, 209 | "lodash": { 210 | "version": "4.17.21", 211 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 212 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 213 | }, 214 | "mime-db": { 215 | "version": "1.40.0", 216 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 217 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 218 | }, 219 | "mime-types": { 220 | "version": "2.1.24", 221 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 222 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 223 | "requires": { 224 | "mime-db": "1.40.0" 225 | } 226 | }, 227 | "oauth-sign": { 228 | "version": "0.9.0", 229 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 230 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 231 | }, 232 | "performance-now": { 233 | "version": "2.1.0", 234 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 235 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 236 | }, 237 | "psl": { 238 | "version": "1.1.31", 239 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", 240 | "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" 241 | }, 242 | "punycode": { 243 | "version": "1.4.1", 244 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 245 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 246 | }, 247 | "qs": { 248 | "version": "6.5.2", 249 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 250 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 251 | }, 252 | "request": { 253 | "version": "2.88.0", 254 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 255 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 256 | "requires": { 257 | "aws-sign2": "~0.7.0", 258 | "aws4": "^1.8.0", 259 | "caseless": "~0.12.0", 260 | "combined-stream": "~1.0.6", 261 | "extend": "~3.0.2", 262 | "forever-agent": "~0.6.1", 263 | "form-data": "~2.3.2", 264 | "har-validator": "~5.1.0", 265 | "http-signature": "~1.2.0", 266 | "is-typedarray": "~1.0.0", 267 | "isstream": "~0.1.2", 268 | "json-stringify-safe": "~5.0.1", 269 | "mime-types": "~2.1.19", 270 | "oauth-sign": "~0.9.0", 271 | "performance-now": "^2.1.0", 272 | "qs": "~6.5.2", 273 | "safe-buffer": "^5.1.2", 274 | "tough-cookie": "~2.4.3", 275 | "tunnel-agent": "^0.6.0", 276 | "uuid": "^3.3.2" 277 | }, 278 | "dependencies": { 279 | "tough-cookie": { 280 | "version": "2.4.3", 281 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 282 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 283 | "requires": { 284 | "psl": "^1.1.24", 285 | "punycode": "^1.4.1" 286 | } 287 | } 288 | } 289 | }, 290 | "request-promise": { 291 | "version": "4.2.2", 292 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", 293 | "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", 294 | "requires": { 295 | "bluebird": "^3.5.0", 296 | "request-promise-core": "1.1.1", 297 | "stealthy-require": "^1.1.0", 298 | "tough-cookie": ">=2.3.3" 299 | } 300 | }, 301 | "request-promise-core": { 302 | "version": "1.1.1", 303 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", 304 | "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", 305 | "requires": { 306 | "lodash": "^4.13.1" 307 | } 308 | }, 309 | "safe-buffer": { 310 | "version": "5.1.2", 311 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 312 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 313 | }, 314 | "safer-buffer": { 315 | "version": "2.1.2", 316 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 317 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 318 | }, 319 | "sshpk": { 320 | "version": "1.16.1", 321 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 322 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 323 | "requires": { 324 | "asn1": "~0.2.3", 325 | "assert-plus": "^1.0.0", 326 | "bcrypt-pbkdf": "^1.0.0", 327 | "dashdash": "^1.12.0", 328 | "ecc-jsbn": "~0.1.1", 329 | "getpass": "^0.1.1", 330 | "jsbn": "~0.1.0", 331 | "safer-buffer": "^2.0.2", 332 | "tweetnacl": "~0.14.0" 333 | } 334 | }, 335 | "stealthy-require": { 336 | "version": "1.1.1", 337 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 338 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" 339 | }, 340 | "tough-cookie": { 341 | "version": "2.3.4", 342 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", 343 | "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", 344 | "requires": { 345 | "punycode": "^1.4.1" 346 | } 347 | }, 348 | "tunnel-agent": { 349 | "version": "0.6.0", 350 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 351 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 352 | "requires": { 353 | "safe-buffer": "^5.0.1" 354 | } 355 | }, 356 | "tweetnacl": { 357 | "version": "0.14.5", 358 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 359 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 360 | }, 361 | "uri-js": { 362 | "version": "4.2.2", 363 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 364 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 365 | "requires": { 366 | "punycode": "^2.1.0" 367 | }, 368 | "dependencies": { 369 | "punycode": { 370 | "version": "2.1.1", 371 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 372 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 373 | } 374 | } 375 | }, 376 | "uuid": { 377 | "version": "3.3.2", 378 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 379 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 380 | }, 381 | "verror": { 382 | "version": "1.10.0", 383 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 384 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 385 | "requires": { 386 | "assert-plus": "^1.0.0", 387 | "core-util-is": "1.0.2", 388 | "extsprintf": "^1.2.0" 389 | } 390 | } 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /integration/snyk.io/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "snyk", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ajv": { 8 | "version": "6.12.6", 9 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 10 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 11 | "requires": { 12 | "fast-deep-equal": "^3.1.1", 13 | "fast-json-stable-stringify": "^2.0.0", 14 | "json-schema-traverse": "^0.4.1", 15 | "uri-js": "^4.2.2" 16 | }, 17 | "dependencies": { 18 | "fast-deep-equal": { 19 | "version": "3.1.3", 20 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 21 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 22 | } 23 | } 24 | }, 25 | "asn1": { 26 | "version": "0.2.4", 27 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 28 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 29 | "requires": { 30 | "safer-buffer": "~2.1.0" 31 | } 32 | }, 33 | "assert-plus": { 34 | "version": "1.0.0", 35 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 36 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 37 | }, 38 | "asynckit": { 39 | "version": "0.4.0", 40 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 41 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 42 | }, 43 | "aws-sign2": { 44 | "version": "0.7.0", 45 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 46 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 47 | }, 48 | "aws4": { 49 | "version": "1.8.0", 50 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 51 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 52 | }, 53 | "bcrypt-pbkdf": { 54 | "version": "1.0.2", 55 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 56 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 57 | "requires": { 58 | "tweetnacl": "^0.14.3" 59 | } 60 | }, 61 | "bluebird": { 62 | "version": "3.5.1", 63 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 64 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" 65 | }, 66 | "caseless": { 67 | "version": "0.12.0", 68 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 69 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 70 | }, 71 | "combined-stream": { 72 | "version": "1.0.7", 73 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 74 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 75 | "requires": { 76 | "delayed-stream": "~1.0.0" 77 | } 78 | }, 79 | "core-util-is": { 80 | "version": "1.0.2", 81 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 82 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 83 | }, 84 | "dashdash": { 85 | "version": "1.14.1", 86 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 87 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 88 | "requires": { 89 | "assert-plus": "^1.0.0" 90 | } 91 | }, 92 | "delayed-stream": { 93 | "version": "1.0.0", 94 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 95 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 96 | }, 97 | "ecc-jsbn": { 98 | "version": "0.1.2", 99 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 100 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 101 | "requires": { 102 | "jsbn": "~0.1.0", 103 | "safer-buffer": "^2.1.0" 104 | } 105 | }, 106 | "extend": { 107 | "version": "3.0.2", 108 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 109 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 110 | }, 111 | "extsprintf": { 112 | "version": "1.3.0", 113 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 114 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 115 | }, 116 | "fast-json-stable-stringify": { 117 | "version": "2.0.0", 118 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 119 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 120 | }, 121 | "forever-agent": { 122 | "version": "0.6.1", 123 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 124 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 125 | }, 126 | "form-data": { 127 | "version": "2.3.3", 128 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 129 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 130 | "requires": { 131 | "asynckit": "^0.4.0", 132 | "combined-stream": "^1.0.6", 133 | "mime-types": "^2.1.12" 134 | } 135 | }, 136 | "fs-extra": { 137 | "version": "8.1.0", 138 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 139 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 140 | "requires": { 141 | "graceful-fs": "^4.2.0", 142 | "jsonfile": "^4.0.0", 143 | "universalify": "^0.1.0" 144 | } 145 | }, 146 | "getpass": { 147 | "version": "0.1.7", 148 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 149 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 150 | "requires": { 151 | "assert-plus": "^1.0.0" 152 | } 153 | }, 154 | "graceful-fs": { 155 | "version": "4.2.3", 156 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", 157 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" 158 | }, 159 | "har-schema": { 160 | "version": "2.0.0", 161 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 162 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 163 | }, 164 | "har-validator": { 165 | "version": "5.1.3", 166 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 167 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 168 | "requires": { 169 | "ajv": "^6.5.5", 170 | "har-schema": "^2.0.0" 171 | } 172 | }, 173 | "http-signature": { 174 | "version": "1.2.0", 175 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 176 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 177 | "requires": { 178 | "assert-plus": "^1.0.0", 179 | "jsprim": "^1.2.2", 180 | "sshpk": "^1.7.0" 181 | } 182 | }, 183 | "is-typedarray": { 184 | "version": "1.0.0", 185 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 186 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 187 | }, 188 | "isstream": { 189 | "version": "0.1.2", 190 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 191 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 192 | }, 193 | "jsbn": { 194 | "version": "0.1.1", 195 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 196 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 197 | }, 198 | "json-schema": { 199 | "version": "0.2.3", 200 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 201 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 202 | }, 203 | "json-schema-traverse": { 204 | "version": "0.4.1", 205 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 206 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 207 | }, 208 | "json-stringify-safe": { 209 | "version": "5.0.1", 210 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 211 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 212 | }, 213 | "jsonfile": { 214 | "version": "4.0.0", 215 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 216 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 217 | "requires": { 218 | "graceful-fs": "^4.1.6" 219 | } 220 | }, 221 | "jsprim": { 222 | "version": "1.4.1", 223 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 224 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 225 | "requires": { 226 | "assert-plus": "1.0.0", 227 | "extsprintf": "1.3.0", 228 | "json-schema": "0.2.3", 229 | "verror": "1.10.0" 230 | } 231 | }, 232 | "lodash": { 233 | "version": "4.17.21", 234 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 235 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 236 | }, 237 | "mime-db": { 238 | "version": "1.40.0", 239 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 240 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 241 | }, 242 | "mime-types": { 243 | "version": "2.1.24", 244 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 245 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 246 | "requires": { 247 | "mime-db": "1.40.0" 248 | } 249 | }, 250 | "oauth-sign": { 251 | "version": "0.9.0", 252 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 253 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 254 | }, 255 | "performance-now": { 256 | "version": "2.1.0", 257 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 258 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 259 | }, 260 | "psl": { 261 | "version": "1.1.31", 262 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", 263 | "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" 264 | }, 265 | "punycode": { 266 | "version": "1.4.1", 267 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 268 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 269 | }, 270 | "qs": { 271 | "version": "6.5.2", 272 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 273 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 274 | }, 275 | "request": { 276 | "version": "2.88.0", 277 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 278 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 279 | "requires": { 280 | "aws-sign2": "~0.7.0", 281 | "aws4": "^1.8.0", 282 | "caseless": "~0.12.0", 283 | "combined-stream": "~1.0.6", 284 | "extend": "~3.0.2", 285 | "forever-agent": "~0.6.1", 286 | "form-data": "~2.3.2", 287 | "har-validator": "~5.1.0", 288 | "http-signature": "~1.2.0", 289 | "is-typedarray": "~1.0.0", 290 | "isstream": "~0.1.2", 291 | "json-stringify-safe": "~5.0.1", 292 | "mime-types": "~2.1.19", 293 | "oauth-sign": "~0.9.0", 294 | "performance-now": "^2.1.0", 295 | "qs": "~6.5.2", 296 | "safe-buffer": "^5.1.2", 297 | "tough-cookie": "~2.4.3", 298 | "tunnel-agent": "^0.6.0", 299 | "uuid": "^3.3.2" 300 | }, 301 | "dependencies": { 302 | "tough-cookie": { 303 | "version": "2.4.3", 304 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 305 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 306 | "requires": { 307 | "psl": "^1.1.24", 308 | "punycode": "^1.4.1" 309 | } 310 | } 311 | } 312 | }, 313 | "request-promise": { 314 | "version": "4.2.2", 315 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", 316 | "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", 317 | "requires": { 318 | "bluebird": "^3.5.0", 319 | "request-promise-core": "1.1.1", 320 | "stealthy-require": "^1.1.0", 321 | "tough-cookie": ">=2.3.3" 322 | } 323 | }, 324 | "request-promise-core": { 325 | "version": "1.1.1", 326 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", 327 | "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", 328 | "requires": { 329 | "lodash": "^4.13.1" 330 | } 331 | }, 332 | "safe-buffer": { 333 | "version": "5.1.2", 334 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 335 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 336 | }, 337 | "safer-buffer": { 338 | "version": "2.1.2", 339 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 340 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 341 | }, 342 | "sshpk": { 343 | "version": "1.16.1", 344 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 345 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 346 | "requires": { 347 | "asn1": "~0.2.3", 348 | "assert-plus": "^1.0.0", 349 | "bcrypt-pbkdf": "^1.0.0", 350 | "dashdash": "^1.12.0", 351 | "ecc-jsbn": "~0.1.1", 352 | "getpass": "^0.1.1", 353 | "jsbn": "~0.1.0", 354 | "safer-buffer": "^2.0.2", 355 | "tweetnacl": "~0.14.0" 356 | } 357 | }, 358 | "stealthy-require": { 359 | "version": "1.1.1", 360 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 361 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" 362 | }, 363 | "tough-cookie": { 364 | "version": "2.3.3", 365 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", 366 | "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", 367 | "requires": { 368 | "punycode": "^1.4.1" 369 | } 370 | }, 371 | "tunnel-agent": { 372 | "version": "0.6.0", 373 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 374 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 375 | "requires": { 376 | "safe-buffer": "^5.0.1" 377 | } 378 | }, 379 | "tweetnacl": { 380 | "version": "0.14.5", 381 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 382 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 383 | }, 384 | "universalify": { 385 | "version": "0.1.2", 386 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 387 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" 388 | }, 389 | "uri-js": { 390 | "version": "4.2.2", 391 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 392 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 393 | "requires": { 394 | "punycode": "^2.1.0" 395 | }, 396 | "dependencies": { 397 | "punycode": { 398 | "version": "2.1.1", 399 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 400 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 401 | } 402 | } 403 | }, 404 | "uuid": { 405 | "version": "3.3.2", 406 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 407 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 408 | }, 409 | "verror": { 410 | "version": "1.10.0", 411 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 412 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 413 | "requires": { 414 | "assert-plus": "^1.0.0", 415 | "core-util-is": "1.0.2", 416 | "extsprintf": "^1.2.0" 417 | } 418 | } 419 | } 420 | } 421 | -------------------------------------------------------------------------------- /integration/snyk.io/service/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "snyk-service", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.7", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 11 | "requires": { 12 | "mime-types": "~2.1.24", 13 | "negotiator": "0.6.2" 14 | } 15 | }, 16 | "any-promise": { 17 | "version": "1.3.0", 18 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 19 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" 20 | }, 21 | "bytes": { 22 | "version": "3.1.0", 23 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 24 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 25 | }, 26 | "cache-content-type": { 27 | "version": "1.0.1", 28 | "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", 29 | "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", 30 | "requires": { 31 | "mime-types": "^2.1.18", 32 | "ylru": "^1.2.0" 33 | } 34 | }, 35 | "co": { 36 | "version": "4.6.0", 37 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 38 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 39 | }, 40 | "co-body": { 41 | "version": "6.1.0", 42 | "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.1.0.tgz", 43 | "integrity": "sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==", 44 | "requires": { 45 | "inflation": "^2.0.0", 46 | "qs": "^6.5.2", 47 | "raw-body": "^2.3.3", 48 | "type-is": "^1.6.16" 49 | } 50 | }, 51 | "content-disposition": { 52 | "version": "0.5.3", 53 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 54 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 55 | "requires": { 56 | "safe-buffer": "5.1.2" 57 | } 58 | }, 59 | "content-type": { 60 | "version": "1.0.4", 61 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 62 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 63 | }, 64 | "cookies": { 65 | "version": "0.8.0", 66 | "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", 67 | "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", 68 | "requires": { 69 | "depd": "~2.0.0", 70 | "keygrip": "~1.1.0" 71 | }, 72 | "dependencies": { 73 | "depd": { 74 | "version": "2.0.0", 75 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 76 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 77 | } 78 | } 79 | }, 80 | "copy-to": { 81 | "version": "2.0.1", 82 | "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", 83 | "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=" 84 | }, 85 | "deep-equal": { 86 | "version": "1.0.1", 87 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", 88 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" 89 | }, 90 | "delegates": { 91 | "version": "1.0.0", 92 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 93 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" 94 | }, 95 | "depd": { 96 | "version": "1.1.2", 97 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 98 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 99 | }, 100 | "destroy": { 101 | "version": "1.0.4", 102 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 103 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 104 | }, 105 | "ee-first": { 106 | "version": "1.1.1", 107 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 108 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 109 | }, 110 | "encodeurl": { 111 | "version": "1.0.2", 112 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 113 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 114 | }, 115 | "escape-html": { 116 | "version": "1.0.3", 117 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 118 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 119 | }, 120 | "fresh": { 121 | "version": "0.5.2", 122 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 123 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 124 | }, 125 | "http-assert": { 126 | "version": "1.4.1", 127 | "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz", 128 | "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==", 129 | "requires": { 130 | "deep-equal": "~1.0.1", 131 | "http-errors": "~1.7.2" 132 | } 133 | }, 134 | "http-errors": { 135 | "version": "1.7.3", 136 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", 137 | "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", 138 | "requires": { 139 | "depd": "~1.1.2", 140 | "inherits": "2.0.4", 141 | "setprototypeof": "1.1.1", 142 | "statuses": ">= 1.5.0 < 2", 143 | "toidentifier": "1.0.0" 144 | } 145 | }, 146 | "iconv-lite": { 147 | "version": "0.4.24", 148 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 149 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 150 | "requires": { 151 | "safer-buffer": ">= 2.1.2 < 3" 152 | } 153 | }, 154 | "inflation": { 155 | "version": "2.0.0", 156 | "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", 157 | "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=" 158 | }, 159 | "inherits": { 160 | "version": "2.0.4", 161 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 162 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 163 | }, 164 | "is-generator-function": { 165 | "version": "1.0.7", 166 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", 167 | "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==" 168 | }, 169 | "isarray": { 170 | "version": "0.0.1", 171 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 172 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 173 | }, 174 | "keygrip": { 175 | "version": "1.1.0", 176 | "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", 177 | "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", 178 | "requires": { 179 | "tsscmp": "1.0.6" 180 | } 181 | }, 182 | "koa": { 183 | "version": "2.13.0", 184 | "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.0.tgz", 185 | "integrity": "sha512-i/XJVOfPw7npbMv67+bOeXr3gPqOAw6uh5wFyNs3QvJ47tUx3M3V9rIE0//WytY42MKz4l/MXKyGkQ2LQTfLUQ==", 186 | "requires": { 187 | "accepts": "^1.3.5", 188 | "cache-content-type": "^1.0.0", 189 | "content-disposition": "~0.5.2", 190 | "content-type": "^1.0.4", 191 | "cookies": "~0.8.0", 192 | "debug": "~3.1.0", 193 | "delegates": "^1.0.0", 194 | "depd": "^1.1.2", 195 | "destroy": "^1.0.4", 196 | "encodeurl": "^1.0.2", 197 | "escape-html": "^1.0.3", 198 | "fresh": "~0.5.2", 199 | "http-assert": "^1.3.0", 200 | "http-errors": "^1.6.3", 201 | "is-generator-function": "^1.0.7", 202 | "koa-compose": "^4.1.0", 203 | "koa-convert": "^1.2.0", 204 | "on-finished": "^2.3.0", 205 | "only": "~0.0.2", 206 | "parseurl": "^1.3.2", 207 | "statuses": "^1.5.0", 208 | "type-is": "^1.6.16", 209 | "vary": "^1.1.2" 210 | }, 211 | "dependencies": { 212 | "debug": { 213 | "version": "3.1.0", 214 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 215 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 216 | "requires": { 217 | "ms": "2.0.0" 218 | } 219 | }, 220 | "ms": { 221 | "version": "2.0.0", 222 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 223 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 224 | } 225 | } 226 | }, 227 | "koa-bodyparser": { 228 | "version": "4.3.0", 229 | "resolved": "https://registry.npmjs.org/koa-bodyparser/-/koa-bodyparser-4.3.0.tgz", 230 | "integrity": "sha512-uyV8G29KAGwZc4q/0WUAjH+Tsmuv9ImfBUF2oZVyZtaeo0husInagyn/JH85xMSxM0hEk/mbCII5ubLDuqW/Rw==", 231 | "requires": { 232 | "co-body": "^6.0.0", 233 | "copy-to": "^2.0.1" 234 | } 235 | }, 236 | "koa-compose": { 237 | "version": "4.1.0", 238 | "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", 239 | "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==" 240 | }, 241 | "koa-convert": { 242 | "version": "1.2.0", 243 | "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", 244 | "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", 245 | "requires": { 246 | "co": "^4.6.0", 247 | "koa-compose": "^3.0.0" 248 | }, 249 | "dependencies": { 250 | "koa-compose": { 251 | "version": "3.2.1", 252 | "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", 253 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", 254 | "requires": { 255 | "any-promise": "^1.1.0" 256 | } 257 | } 258 | } 259 | }, 260 | "koa-router": { 261 | "version": "7.4.0", 262 | "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-7.4.0.tgz", 263 | "integrity": "sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g==", 264 | "requires": { 265 | "debug": "^3.1.0", 266 | "http-errors": "^1.3.1", 267 | "koa-compose": "^3.0.0", 268 | "methods": "^1.0.1", 269 | "path-to-regexp": "^1.1.1", 270 | "urijs": "^1.19.0" 271 | }, 272 | "dependencies": { 273 | "debug": { 274 | "version": "3.2.6", 275 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 276 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 277 | "requires": { 278 | "ms": "^2.1.1" 279 | } 280 | }, 281 | "koa-compose": { 282 | "version": "3.2.1", 283 | "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", 284 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", 285 | "requires": { 286 | "any-promise": "^1.1.0" 287 | } 288 | } 289 | } 290 | }, 291 | "media-typer": { 292 | "version": "0.3.0", 293 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 294 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 295 | }, 296 | "methods": { 297 | "version": "1.1.2", 298 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 299 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 300 | }, 301 | "mime-db": { 302 | "version": "1.44.0", 303 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 304 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" 305 | }, 306 | "mime-types": { 307 | "version": "2.1.27", 308 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 309 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 310 | "requires": { 311 | "mime-db": "1.44.0" 312 | } 313 | }, 314 | "ms": { 315 | "version": "2.1.2", 316 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 317 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 318 | }, 319 | "negotiator": { 320 | "version": "0.6.2", 321 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 322 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 323 | }, 324 | "on-finished": { 325 | "version": "2.3.0", 326 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 327 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 328 | "requires": { 329 | "ee-first": "1.1.1" 330 | } 331 | }, 332 | "only": { 333 | "version": "0.0.2", 334 | "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", 335 | "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=" 336 | }, 337 | "parseurl": { 338 | "version": "1.3.3", 339 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 340 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 341 | }, 342 | "path-to-regexp": { 343 | "version": "1.8.0", 344 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", 345 | "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", 346 | "requires": { 347 | "isarray": "0.0.1" 348 | } 349 | }, 350 | "qs": { 351 | "version": "6.9.4", 352 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", 353 | "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" 354 | }, 355 | "raw-body": { 356 | "version": "2.4.1", 357 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", 358 | "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", 359 | "requires": { 360 | "bytes": "3.1.0", 361 | "http-errors": "1.7.3", 362 | "iconv-lite": "0.4.24", 363 | "unpipe": "1.0.0" 364 | } 365 | }, 366 | "safe-buffer": { 367 | "version": "5.1.2", 368 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 369 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 370 | }, 371 | "safer-buffer": { 372 | "version": "2.1.2", 373 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 374 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 375 | }, 376 | "setprototypeof": { 377 | "version": "1.1.1", 378 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 379 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 380 | }, 381 | "statuses": { 382 | "version": "1.5.0", 383 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 384 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 385 | }, 386 | "toidentifier": { 387 | "version": "1.0.0", 388 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 389 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 390 | }, 391 | "tsscmp": { 392 | "version": "1.0.6", 393 | "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", 394 | "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" 395 | }, 396 | "type-is": { 397 | "version": "1.6.18", 398 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 399 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 400 | "requires": { 401 | "media-typer": "0.3.0", 402 | "mime-types": "~2.1.24" 403 | } 404 | }, 405 | "unpipe": { 406 | "version": "1.0.0", 407 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 408 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 409 | }, 410 | "urijs": { 411 | "version": "1.19.7", 412 | "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.7.tgz", 413 | "integrity": "sha512-Id+IKjdU0Hx+7Zx717jwLPsPeUqz7rAtuVBRLLs+qn+J2nf9NGITWVCxcijgYxBqe83C7sqsQPs6H1pyz3x9gA==" 414 | }, 415 | "vary": { 416 | "version": "1.1.2", 417 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 418 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 419 | }, 420 | "ylru": { 421 | "version": "1.2.1", 422 | "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz", 423 | "integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==" 424 | } 425 | } 426 | } 427 | --------------------------------------------------------------------------------