$ date
--- stdout ---
Fri Jun 2 12:14:42 UTC 2023
--- end ---
$ git clone file:///srv/git/mediawiki-services-ipoid.git repo --depth=1 -b master
--- stderr ---
Cloning into 'repo'...
--- stdout ---
--- end ---
$ git config user.name libraryupgrader
--- stdout ---
--- end ---
$ git config user.email tools.libraryupgrader@tools.wmflabs.org
--- stdout ---
--- end ---
$ git submodule update --init
--- stdout ---
--- end ---
$ grr init
--- stdout ---
Installed commit-msg hook.
--- end ---
$ git show-ref refs/heads/master
--- stdout ---
24ad2a40aa6f2e673d275b052337ec9ff79bc158 refs/heads/master
--- end ---
$ /usr/bin/npm audit --json --legacy-peer-deps
--- stdout ---
{
"auditReportVersion": 2,
"vulnerabilities": {
"ansi-regex": {
"name": "ansi-regex",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1091189,
"name": "ansi-regex",
"dependency": "ansi-regex",
"title": "Inefficient Regular Expression Complexity in chalk/ansi-regex",
"url": "https://github.com/advisories/GHSA-93q8-gq69-wqmw",
"severity": "high",
"cwe": [
"CWE-697",
"CWE-1333"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": ">=4.0.0 <4.1.1"
}
],
"effects": [],
"range": "4.0.0 - 4.1.0",
"nodes": [
"node_modules/cliui/node_modules/ansi-regex",
"node_modules/service-runner/node_modules/ansi-regex",
"node_modules/wrap-ansi/node_modules/ansi-regex",
"node_modules/yargs/node_modules/ansi-regex"
],
"fixAvailable": true
},
"body-parser": {
"name": "body-parser",
"severity": "high",
"isDirect": true,
"via": [
"qs"
],
"effects": [],
"range": "1.19.0",
"nodes": [
"node_modules/body-parser"
],
"fixAvailable": true
},
"express": {
"name": "express",
"severity": "high",
"isDirect": true,
"via": [
"body-parser",
"qs"
],
"effects": [],
"range": "4.17.0 - 4.17.1 || 5.0.0-alpha.1 - 5.0.0-alpha.8",
"nodes": [
"node_modules/express"
],
"fixAvailable": true
},
"got": {
"name": "got",
"severity": "moderate",
"isDirect": false,
"via": [
{
"source": 1088948,
"name": "got",
"dependency": "got",
"title": "Got allows a redirect to a UNIX socket",
"url": "https://github.com/advisories/GHSA-pfrx-2q88-qq97",
"severity": "moderate",
"cwe": [],
"cvss": {
"score": 5.3,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"
},
"range": "<11.8.5"
}
],
"effects": [
"package-json"
],
"range": "<11.8.5",
"nodes": [
"node_modules/got"
],
"fixAvailable": true
},
"http-cache-semantics": {
"name": "http-cache-semantics",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1091807,
"name": "http-cache-semantics",
"dependency": "http-cache-semantics",
"title": "http-cache-semantics vulnerable to Regular Expression Denial of Service",
"url": "https://github.com/advisories/GHSA-rc47-6667-2j5j",
"severity": "high",
"cwe": [
"CWE-1333"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<4.1.1"
}
],
"effects": [],
"range": "<4.1.1",
"nodes": [
"node_modules/http-cache-semantics"
],
"fixAvailable": true
},
"ini": {
"name": "ini",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1091252,
"name": "ini",
"dependency": "ini",
"title": "ini before 1.3.6 vulnerable to Prototype Pollution via ini.parse",
"url": "https://github.com/advisories/GHSA-qqgx-2p2h-9c37",
"severity": "high",
"cwe": [
"CWE-1321"
],
"cvss": {
"score": 7.3,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L"
},
"range": "<1.3.6"
}
],
"effects": [],
"range": "<1.3.6",
"nodes": [
"node_modules/gc-stats/node_modules/ini"
],
"fixAvailable": true
},
"json-schema": {
"name": "json-schema",
"severity": "critical",
"isDirect": false,
"via": [
{
"source": 1091472,
"name": "json-schema",
"dependency": "json-schema",
"title": "json-schema is vulnerable to Prototype Pollution",
"url": "https://github.com/advisories/GHSA-896r-f27r-55mw",
"severity": "critical",
"cwe": [
"CWE-915",
"CWE-1321"
],
"cvss": {
"score": 9.8,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
},
"range": "<0.4.0"
}
],
"effects": [
"jsprim"
],
"range": "<0.4.0",
"nodes": [
"node_modules/json-schema"
],
"fixAvailable": true
},
"jsprim": {
"name": "jsprim",
"severity": "critical",
"isDirect": false,
"via": [
"json-schema"
],
"effects": [],
"range": "0.3.0 - 1.4.1 || 2.0.0 - 2.0.1",
"nodes": [
"node_modules/jsprim"
],
"fixAvailable": true
},
"latest-version": {
"name": "latest-version",
"severity": "moderate",
"isDirect": false,
"via": [
"package-json"
],
"effects": [
"update-notifier"
],
"range": "0.2.0 - 5.1.0",
"nodes": [
"node_modules/latest-version"
],
"fixAvailable": true
},
"limitation": {
"name": "limitation",
"severity": "moderate",
"isDirect": false,
"via": [
"wikimedia-kad-fork"
],
"effects": [],
"range": ">=0.2.3",
"nodes": [
"node_modules/limitation"
],
"fixAvailable": true
},
"minimatch": {
"name": "minimatch",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1091174,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch ReDoS vulnerability",
"url": "https://github.com/advisories/GHSA-f8q6-p94x-37v3",
"severity": "high",
"cwe": [
"CWE-400"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<3.0.5"
}
],
"effects": [
"mocha"
],
"range": "<3.0.5",
"nodes": [
"node_modules/gc-stats/node_modules/minimatch",
"node_modules/minimatch"
],
"fixAvailable": {
"name": "mocha",
"version": "10.2.0",
"isSemVerMajor": true
}
},
"minimist": {
"name": "minimist",
"severity": "critical",
"isDirect": false,
"via": [
{
"source": 1090097,
"name": "minimist",
"dependency": "minimist",
"title": "Prototype Pollution in minimist",
"url": "https://github.com/advisories/GHSA-vh95-rmgr-6w4m",
"severity": "moderate",
"cwe": [
"CWE-1321"
],
"cvss": {
"score": 5.6,
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L"
},
"range": ">=1.0.0 <1.2.3"
},
{
"source": 1090098,
"name": "minimist",
"dependency": "minimist",
"title": "Prototype Pollution in minimist",
"url": "https://github.com/advisories/GHSA-vh95-rmgr-6w4m",
"severity": "moderate",
"cwe": [
"CWE-1321"
],
"cvss": {
"score": 5.6,
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L"
},
"range": "<0.2.1"
},
{
"source": 1091172,
"name": "minimist",
"dependency": "minimist",
"title": "Prototype Pollution in minimist",
"url": "https://github.com/advisories/GHSA-xvch-5gv4-984h",
"severity": "critical",
"cwe": [
"CWE-1321"
],
"cvss": {
"score": 9.8,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
},
"range": "<0.2.4"
},
{
"source": 1091173,
"name": "minimist",
"dependency": "minimist",
"title": "Prototype Pollution in minimist",
"url": "https://github.com/advisories/GHSA-xvch-5gv4-984h",
"severity": "critical",
"cwe": [
"CWE-1321"
],
"cvss": {
"score": 9.8,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
},
"range": ">=1.0.0 <1.2.6"
}
],
"effects": [
"mkdirp"
],
"range": "<=0.2.3 || 1.0.0 - 1.2.5",
"nodes": [
"node_modules/gc-stats/node_modules/minimist",
"node_modules/gc-stats/node_modules/rc/node_modules/minimist",
"node_modules/minimist"
],
"fixAvailable": {
"name": "mocha",
"version": "10.2.0",
"isSemVerMajor": true
}
},
"mkdirp": {
"name": "mkdirp",
"severity": "critical",
"isDirect": false,
"via": [
"minimist"
],
"effects": [
"mocha"
],
"range": "0.4.1 - 0.5.1",
"nodes": [
"node_modules/gc-stats/node_modules/mkdirp",
"node_modules/mkdirp"
],
"fixAvailable": {
"name": "mocha",
"version": "10.2.0",
"isSemVerMajor": true
}
},
"mocha": {
"name": "mocha",
"severity": "critical",
"isDirect": true,
"via": [
"minimatch",
"mkdirp"
],
"effects": [],
"range": "1.21.5 - 9.2.1",
"nodes": [
"node_modules/mocha"
],
"fixAvailable": {
"name": "mocha",
"version": "10.2.0",
"isSemVerMajor": true
}
},
"moment": {
"name": "moment",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1091430,
"name": "moment",
"dependency": "moment",
"title": "Path Traversal: 'dir/../../filename' in moment.locale",
"url": "https://github.com/advisories/GHSA-8hfj-j24r-96c4",
"severity": "high",
"cwe": [
"CWE-22",
"CWE-27"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
},
"range": "<2.29.2"
},
{
"source": 1091441,
"name": "moment",
"dependency": "moment",
"title": "Moment.js vulnerable to Inefficient Regular Expression Complexity",
"url": "https://github.com/advisories/GHSA-wc69-rhjr-hc9g",
"severity": "high",
"cwe": [
"CWE-400",
"CWE-1333"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": ">=2.18.0 <2.29.4"
}
],
"effects": [],
"range": "<=2.29.3",
"nodes": [
"node_modules/moment"
],
"fixAvailable": true
},
"moment-timezone": {
"name": "moment-timezone",
"severity": "moderate",
"isDirect": false,
"via": [
{
"source": 1088402,
"name": "moment-timezone",
"dependency": "moment-timezone",
"title": "Command Injection in moment-timezone",
"url": "https://github.com/advisories/GHSA-56x4-j7p9-fcf9",
"severity": "low",
"cwe": [],
"cvss": {
"score": 0,
"vectorString": null
},
"range": ">=0.1.0 <0.5.35"
},
{
"source": 1088403,
"name": "moment-timezone",
"dependency": "moment-timezone",
"title": "Cleartext Transmission of Sensitive Information in moment-timezone",
"url": "https://github.com/advisories/GHSA-v78c-4p63-2j6c",
"severity": "moderate",
"cwe": [
"CWE-319"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": ">=0.1.0 <0.5.35"
}
],
"effects": [],
"range": "0.1.0 - 0.5.34",
"nodes": [
"node_modules/moment-timezone"
],
"fixAvailable": true
},
"ms": {
"name": "ms",
"severity": "moderate",
"isDirect": false,
"via": [
{
"source": 1088818,
"name": "ms",
"dependency": "ms",
"title": "Vercel ms Inefficient Regular Expression Complexity vulnerability",
"url": "https://github.com/advisories/GHSA-w9mr-4mfr-499f",
"severity": "moderate",
"cwe": [
"CWE-1333"
],
"cvss": {
"score": 5.3,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L"
},
"range": "<2.0.0"
}
],
"effects": [
"wikimedia-kad-fork"
],
"range": "<2.0.0",
"nodes": [
"node_modules/wikimedia-kad-fork/node_modules/ms"
],
"fixAvailable": true
},
"nodemon": {
"name": "nodemon",
"severity": "moderate",
"isDirect": true,
"via": [
"update-notifier"
],
"effects": [],
"range": "1.3.5 - 2.0.16 || 2.0.18",
"nodes": [
"node_modules/nodemon"
],
"fixAvailable": true
},
"package-json": {
"name": "package-json",
"severity": "moderate",
"isDirect": false,
"via": [
"got"
],
"effects": [
"latest-version"
],
"range": "<=6.5.0",
"nodes": [
"node_modules/package-json"
],
"fixAvailable": true
},
"preq": {
"name": "preq",
"severity": "high",
"isDirect": true,
"via": [
"request",
"requestretry"
],
"effects": [],
"range": "*",
"nodes": [
"node_modules/preq"
],
"fixAvailable": false
},
"qs": {
"name": "qs",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1090135,
"name": "qs",
"dependency": "qs",
"title": "qs vulnerable to Prototype Pollution",
"url": "https://github.com/advisories/GHSA-hrpp-h998-j3pp",
"severity": "high",
"cwe": [
"CWE-1321"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": ">=6.5.0 <6.5.3"
},
{
"source": 1090137,
"name": "qs",
"dependency": "qs",
"title": "qs vulnerable to Prototype Pollution",
"url": "https://github.com/advisories/GHSA-hrpp-h998-j3pp",
"severity": "high",
"cwe": [
"CWE-1321"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": ">=6.7.0 <6.7.3"
}
],
"effects": [
"body-parser",
"express"
],
"range": "6.5.0 - 6.5.2 || 6.7.0 - 6.7.2",
"nodes": [
"node_modules/qs",
"node_modules/request/node_modules/qs"
],
"fixAvailable": true
},
"request": {
"name": "request",
"severity": "moderate",
"isDirect": false,
"via": [
{
"source": 1091725,
"name": "request",
"dependency": "request",
"title": "Server-Side Request Forgery in Request",
"url": "https://github.com/advisories/GHSA-p8p7-x288-28g6",
"severity": "moderate",
"cwe": [
"CWE-918"
],
"cvss": {
"score": 6.1,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"
},
"range": "<=2.88.2"
}
],
"effects": [
"preq"
],
"range": "*",
"nodes": [
"node_modules/request"
],
"fixAvailable": false
},
"requestretry": {
"name": "requestretry",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1090420,
"name": "requestretry",
"dependency": "requestretry",
"title": "Cookie exposure in requestretry",
"url": "https://github.com/advisories/GHSA-hjp8-2cm3-cc45",
"severity": "high",
"cwe": [
"CWE-200"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
},
"range": "<7.0.0"
}
],
"effects": [
"preq"
],
"range": "<7.0.0",
"nodes": [
"node_modules/requestretry"
],
"fixAvailable": false
},
"swagger-ui-dist": {
"name": "swagger-ui-dist",
"severity": "moderate",
"isDirect": true,
"via": [
{
"source": 1085394,
"name": "swagger-ui-dist",
"dependency": "swagger-ui-dist",
"title": "Server side request forgery in SwaggerUI",
"url": "https://github.com/advisories/GHSA-qrmm-w75w-3wpx",
"severity": "moderate",
"cwe": [
"CWE-918"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": "<4.1.3"
},
{
"source": 1088759,
"name": "swagger-ui-dist",
"dependency": "swagger-ui-dist",
"title": "Spoofing attack in swagger-ui-dist",
"url": "https://github.com/advisories/GHSA-6c9x-mj3g-h47x",
"severity": "moderate",
"cwe": [
"CWE-1021"
],
"cvss": {
"score": 6.1,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"
},
"range": "<4.1.3"
}
],
"effects": [],
"range": "<=4.1.2",
"nodes": [
"node_modules/swagger-ui-dist"
],
"fixAvailable": {
"name": "swagger-ui-dist",
"version": "4.19.0",
"isSemVerMajor": true
}
},
"tar": {
"name": "tar",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1089684,
"name": "tar",
"dependency": "tar",
"title": "Arbitrary File Creation/Overwrite due to insufficient absolute path sanitization",
"url": "https://github.com/advisories/GHSA-3jfq-g458-7qm9",
"severity": "high",
"cwe": [
"CWE-22"
],
"cvss": {
"score": 8.2,
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N"
},
"range": ">=4.0.0 <4.4.14"
},
{
"source": 1091313,
"name": "tar",
"dependency": "tar",
"title": "Arbitrary File Creation/Overwrite via insufficient symlink protection due to directory cache poisoning",
"url": "https://github.com/advisories/GHSA-r628-mhmh-qjhw",
"severity": "high",
"cwe": [
"CWE-22",
"CWE-23",
"CWE-59"
],
"cvss": {
"score": 8.2,
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N"
},
"range": ">=4.0.0 <4.4.15"
},
{
"source": 1091343,
"name": "tar",
"dependency": "tar",
"title": "Arbitrary File Creation/Overwrite via insufficient symlink protection due to directory cache poisoning using symbolic links",
"url": "https://github.com/advisories/GHSA-9r2w-394v-53qc",
"severity": "high",
"cwe": [
"CWE-22",
"CWE-59"
],
"cvss": {
"score": 8.2,
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N"
},
"range": "<4.4.16"
},
{
"source": 1091346,
"name": "tar",
"dependency": "tar",
"title": "Arbitrary File Creation/Overwrite on Windows via insufficient relative path sanitization",
"url": "https://github.com/advisories/GHSA-5955-9wpr-37jh",
"severity": "high",
"cwe": [
"CWE-22"
],
"cvss": {
"score": 8.2,
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N"
},
"range": "<4.4.18"
},
{
"source": 1091349,
"name": "tar",
"dependency": "tar",
"title": "Arbitrary File Creation/Overwrite via insufficient symlink protection due to directory cache poisoning using symbolic links",
"url": "https://github.com/advisories/GHSA-qq89-hq3f-393p",
"severity": "high",
"cwe": [
"CWE-22",
"CWE-59"
],
"cvss": {
"score": 8.2,
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N"
},
"range": "<4.4.18"
}
],
"effects": [],
"range": "<=4.4.17",
"nodes": [
"node_modules/gc-stats/node_modules/tar"
],
"fixAvailable": true
},
"update-notifier": {
"name": "update-notifier",
"severity": "moderate",
"isDirect": false,
"via": [
"latest-version"
],
"effects": [
"nodemon"
],
"range": "0.2.0 - 5.1.0",
"nodes": [
"node_modules/update-notifier"
],
"fixAvailable": true
},
"wikimedia-kad-fork": {
"name": "wikimedia-kad-fork",
"severity": "moderate",
"isDirect": false,
"via": [
"ms"
],
"effects": [
"limitation"
],
"range": "*",
"nodes": [
"node_modules/wikimedia-kad-fork"
],
"fixAvailable": true
}
},
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 0,
"moderate": 11,
"high": 11,
"critical": 5,
"total": 27
},
"dependencies": {
"prod": 205,
"dev": 380,
"optional": 79,
"peer": 0,
"peerOptional": 0,
"total": 662
}
}
}
--- end ---
Upgrading n:eslint-config-wikimedia from 0.20.0 -> 0.25.0
$ /usr/bin/npm install
--- stderr ---
npm WARN deprecated kad-fs@0.0.4: This package is no longer maintained.
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated kad-memstore@0.0.1: This package is no longer maintained.
npm WARN deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
npm WARN deprecated mkdirp@0.5.1: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
--- stdout ---
added 636 packages, and audited 703 packages in 9s
56 packages are looking for funding
run `npm fund` for details
27 vulnerabilities (11 moderate, 11 high, 5 critical)
To address issues that do not require attention, run:
npm audit fix
To address all issues possible (including breaking changes), run:
npm audit fix --force
Some issues need review, and may require choosing
a different dependency.
Run `npm audit` for details.
--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json
--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json
--- end ---
$ ./node_modules/.bin/eslint . --fix
--- stdout ---
/src/repo/app.js
63:37 warning Found non-literal argument to RegExp Constructor security/detect-non-literal-regexp
150:31 warning Found non-literal argument in require security/detect-non-literal-require
/src/repo/config.dev.yaml
21:1 error Empty mapping values are forbidden yml/no-empty-mapping-value
/src/repo/config.yaml
21:1 error Empty mapping values are forbidden yml/no-empty-mapping-value
/src/repo/init-db.js
137:31 warning Found createReadStream from package "fs" with non literal argument at index 0 security/detect-non-literal-fs-filename
/src/repo/server.js
1:1 error ES2023 Hashbang comments are forbidden es-x/no-hashbang
/src/repo/test/features/app/spec.js
154:13 warning Found non-literal argument to RegExp Constructor security/detect-non-literal-regexp
✖ 7 problems (3 errors, 4 warnings)
--- end ---
$ ./node_modules/.bin/eslint . -f json
--- stdout ---
[{"filePath":"/src/repo/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/.travis.yml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/app.js","messages":[{"ruleId":"security/detect-non-literal-regexp","severity":1,"message":"Found non-literal argument to RegExp Constructor","line":63,"column":37,"nodeType":"NewExpression","endLine":65,"endColumn":27},{"ruleId":"security/detect-non-literal-require","severity":1,"message":"Found non-literal argument in require","line":150,"column":31,"nodeType":"CallExpression","endLine":150,"endColumn":57}],"suppressedMessages":[{"ruleId":"max-len","severity":1,"message":"This line has a length of 107. Maximum allowed is 100.","line":36,"column":1,"nodeType":"Program","messageId":"max","endLine":36,"endColumn":108,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use strict';\n\nconst http = require('http');\nconst BBPromise = require('bluebird');\nconst express = require('express');\nconst compression = require('compression');\nconst bodyParser = require('body-parser');\nconst fs = BBPromise.promisifyAll(require('fs'));\nconst sUtil = require('./lib/util');\nconst apiUtil = require('./lib/api-util');\nconst packageInfo = require('./package.json');\nconst yaml = require('js-yaml');\nconst addShutdown = require('http-shutdown');\nconst path = require('path');\n\n/**\n * Creates an express app and initialises it\n *\n * @param {Object} options the options to initialise the app with\n * @return {bluebird} the promise resolving to the app object\n */\nasync function initApp(options) {\n // the main application object\n const app = express();\n\n // get the options and make them available in the app\n app.logger = options.logger; // the logging device\n app.metrics = options.metrics; // the metrics\n app.conf = options.config; // this app's config options\n app.info = packageInfo; // this app's package info\n\n // ensure some sane defaults\n app.conf.port = app.conf.port || 8888;\n app.conf.interface = app.conf.interface || '0.0.0.0';\n // eslint-disable-next-line max-len\n app.conf.compression_level = app.conf.compression_level === undefined ? 3 : app.conf.compression_level;\n app.conf.cors = app.conf.cors === undefined ? '*' : app.conf.cors;\n if (app.conf.csp === undefined) {\n app.conf.csp = \"default-src 'self'; object-src 'none'; media-src 'none'; img-src 'none'; style-src 'none'; base-uri 'self'; frame-ancestors 'self'\";\n }\n\n // set outgoing proxy\n if (app.conf.proxy) {\n process.env.HTTP_PROXY = app.conf.proxy;\n // if there is a list of domains which should\n // not be proxied, set it\n if (app.conf.no_proxy_list) {\n if (Array.isArray(app.conf.no_proxy_list)) {\n process.env.NO_PROXY = app.conf.no_proxy_list.join(',');\n } else {\n process.env.NO_PROXY = app.conf.no_proxy_list;\n }\n }\n }\n\n // set up header whitelisting for logging\n if (!app.conf.log_header_whitelist) {\n app.conf.log_header_whitelist = [\n 'cache-control', 'content-type', 'content-length', 'if-match',\n 'user-agent', 'x-request-id'\n ];\n }\n app.conf.log_header_whitelist = new RegExp(`^(?:${app.conf.log_header_whitelist.map((item) => {\n return item.trim();\n }).join('|')})$`, 'i');\n\n // set up the request templates for the APIs\n apiUtil.setupApiTemplates(app);\n\n // set up the spec\n if (!app.conf.spec) {\n app.conf.spec = `${__dirname}/spec.yaml`;\n }\n if (app.conf.spec.constructor !== Object) {\n try {\n app.conf.spec = yaml.safeLoad(fs.readFileSync(app.conf.spec));\n } catch (e) {\n app.logger.log('warn/spec', `Could not load the spec: ${e}`);\n app.conf.spec = {};\n }\n }\n if (!app.conf.spec.openapi) {\n app.conf.spec.openapi = '3.0.0';\n }\n if (!app.conf.spec.info) {\n app.conf.spec.info = {\n version: app.info.version,\n title: app.info.name,\n description: app.info.description\n };\n }\n app.conf.spec.info.version = app.info.version;\n if (!app.conf.spec.paths) {\n app.conf.spec.paths = {};\n }\n\n // set the CORS and CSP headers\n app.all('*', (req, res, next) => {\n if (app.conf.cors !== false) {\n res.header('access-control-allow-origin', app.conf.cors);\n res.header('access-control-allow-headers', 'accept, x-requested-with, content-type');\n res.header('access-control-expose-headers', 'etag');\n }\n if (app.conf.csp !== false) {\n res.header('x-xss-protection', '1; mode=block');\n res.header('x-content-type-options', 'nosniff');\n res.header('x-frame-options', 'SAMEORIGIN');\n res.header('content-security-policy', app.conf.csp);\n }\n sUtil.initAndLogRequest(req, app);\n next();\n });\n\n // set up the user agent header string to use for requests\n app.conf.user_agent = app.conf.user_agent || app.info.name;\n\n // disable the X-Powered-By header\n app.set('x-powered-by', false);\n // disable the ETag header - users should provide them!\n app.set('etag', false);\n // enable compression\n app.use(compression({ level: app.conf.compression_level }));\n // use the JSON body parser\n app.use(bodyParser.json({ limit: app.conf.max_body_size || '100kb' }));\n // use the application/x-www-form-urlencoded parser\n app.use(bodyParser.urlencoded({ extended: true }));\n\n return BBPromise.resolve(app);\n\n}\n\n/**\n * Loads all routes declared in routes/ into the app\n *\n * @param {Application} app the application object to load routes into\n * @param {string} dir routes folder\n * @return {bluebird} a promise resolving to the app object\n */\nfunction loadRoutes(app, dir) {\n\n // recursively load routes from .js files under routes/\n return fs.readdirAsync(dir).map((fname) => {\n return BBPromise.try(() => {\n const resolvedPath = path.resolve(dir, fname);\n const isDirectory = fs.statSync(resolvedPath).isDirectory();\n if (isDirectory) {\n loadRoutes(app, resolvedPath);\n } else if (/\\.js$/.test(fname)) {\n // import the route file\n const route = require(`${dir}/${fname}`);\n return route(app);\n }\n }).then((route) => {\n if (route === undefined) {\n return undefined;\n }\n // check that the route exports the object we need\n if (route.constructor !== Object || !route.path || !route.router ||\n !(route.api_version || route.skip_domain)) {\n throw new TypeError(`routes/${fname} does not export the correct object!`);\n }\n // normalise the path to be used as the mount point\n if (route.path[0] !== '/') {\n route.path = `/${route.path}`;\n }\n if (route.path[route.path.length - 1] !== '/') {\n route.path = `${route.path}/`;\n }\n if (!route.skip_domain) {\n route.path = `/:domain/v${route.api_version}${route.path}`;\n }\n // wrap the route handlers with Promise.try() blocks\n sUtil.wrapRouteHandlers(route, app);\n // all good, use that route\n app.use(route.path, route.router);\n });\n }).then(() => {\n // catch errors\n sUtil.setErrorHandler(app);\n // route loading is now complete, return the app object\n return BBPromise.resolve(app);\n });\n\n}\n\n/**\n * Creates and start the service's web server\n *\n * @param {Application} app the app object to use in the service\n * @return {bluebird} a promise creating the web server\n */\nfunction createServer(app) {\n\n // return a promise which creates an HTTP server,\n // attaches the app to it, and starts accepting\n // incoming client requests\n let server;\n return new BBPromise((resolve) => {\n server = http.createServer(app).listen(\n app.conf.port,\n app.conf.interface,\n resolve\n );\n server = addShutdown(server);\n }).then(() => {\n app.logger.log('info',\n `Worker ${process.pid} listening on ${app.conf.interface || '*'}:${app.conf.port}`);\n\n // Don't delay incomplete packets for 40ms (Linux default) on\n // pipelined HTTP sockets. We write in large chunks or buffers, so\n // lack of coalescing should not be an issue here.\n server.on('connection', (socket) => {\n socket.setNoDelay(true);\n });\n\n return server;\n });\n\n}\n\n/**\n * The service's entry point. It takes over the configuration\n * options and the logger- and metrics-reporting objects from\n * service-runner and starts an HTTP server, attaching the application\n * object to it.\n *\n * @param {Object} options the options to initialise the app with\n * @return {bluebird} HTTP server\n */\nmodule.exports = (options) => {\n\n return initApp(options)\n .then((app) => loadRoutes(app, `${__dirname}/routes`))\n .then((app) => {\n // serve static files from static/\n app.use('/static', express.static(`${__dirname}/static`));\n return app;\n })\n .then(createServer);\n\n};\n","usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/config.dev.yaml","messages":[{"ruleId":"yml/no-empty-mapping-value","severity":2,"message":"Empty mapping values are forbidden.","line":21,"column":1,"nodeType":"YAMLPair","messageId":"unexpectedEmpty","endLine":21,"endColumn":9}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"# Number of worker processes to spawn.\n# Set to 0 to run everything in a single process without clustering.\n# Use 'ncpu' to run as many workers as there are CPU units\nnum_workers: 0\n\n# Log error messages and gracefully restart a worker if v8 reports that it\n# uses more heap (note: not RSS) than this many mb.\nworker_heap_limit_mb: 250\n\n# Logger info\nlogging:\n level: trace\n# name: <your app name>\n# streams:\n# - type: syslog\n# host: localhost\n# port: 10514\n# prefix: '@cee: '\n# name: node\n\nmetrics:\n# - type: prometheus\n# port: 9000\n# Statsd metrics reporter\n# - type: statsd\n# host: localhost\n# port: 8125\n\nservices:\n - name: ipoid\n # a relative path or the name of an npm package, if different from name\n module: ./app.js\n # optionally, a version constraint of the npm package\n # version: ^0.4.0\n # per-service config\n conf:\n port: 6927\n # interface: localhost # uncomment to only listen on localhost\n # more per-service config settings\n # the location of the spec, defaults to spec.yaml if not specified\n spec: ./spec.template.yaml\n # allow cross-domain requests to the API (default '*')\n cors: \"*\"\n # to disable use:\n # cors: false\n # to restrict to a particular domain, use:\n # cors: restricted.domain.org\n # content for the CSP headers\n # csp: false # uncomment this line to disable sending them\n # URL of the outbound proxy to use (complete with protocol)\n # proxy: http://my.proxy.org:8080\n # the list of domains for which not to use the proxy defined above\n # no_proxy_list:\n # - domain1.com\n # - domain2.org\n # the list of incoming request headers that can be logged; if left empty,\n # the following headers are allowed: cache-control, content-length,\n # content-type, if-match, user-agent, x-request-id\n # log_header_whitelist:\n # - cache-control\n # - content-length\n # - content-type\n # - if-match\n # - user-agent\n # - x-request-id\n # the user agent to use when issuing requests\n # user_agent: service-template-node\n # max JSON POST body size limit\n # max_body_size: 100kb\n # the template used for contacting the MW API\n mwapi_req:\n method: post\n uri: https://{{domain}}/w/api.php\n headers:\n user-agent: \"{{user-agent}}\"\n body: \"{{ default(request.query, {}) }}\"\n # the template used for contacting RESTBase\n restbase_req:\n method: \"{{request.method}}\"\n uri: https://{{domain}}/api/rest_v1/{+path}\n query: \"{{ default(request.query, {}) }}\"\n headers: \"{{request.headers}}\"\n body: \"{{request.body}}\"\n","usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/config.prod.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/config.yaml","messages":[{"ruleId":"yml/no-empty-mapping-value","severity":2,"message":"Empty mapping values are forbidden.","line":21,"column":1,"nodeType":"YAMLPair","messageId":"unexpectedEmpty","endLine":21,"endColumn":9}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"# Number of worker processes to spawn.\n# Set to 0 to run everything in a single process without clustering.\n# Use 'ncpu' to run as many workers as there are CPU units\nnum_workers: 0\n\n# Log error messages and gracefully restart a worker if v8 reports that it\n# uses more heap (note: not RSS) than this many mb.\nworker_heap_limit_mb: 250\n\n# Logger info\nlogging:\n level: trace\n# name: <your app name>\n# streams:\n# - type: syslog\n# host: localhost\n# port: 10514\n# prefix: '@cee: '\n# name: node\n\nmetrics:\n# - type: prometheus\n# port: 9000\n# Statsd metrics reporter\n# - type: statsd\n# host: localhost\n# port: 8125\n\nservices:\n - name: ipoid\n # a relative path or the name of an npm package, if different from name\n module: ./app.js\n # optionally, a version constraint of the npm package\n # version: ^0.4.0\n # per-service config\n conf:\n port: 6927\n # interface: localhost # uncomment to only listen on localhost\n # more per-service config settings\n # the location of the spec, defaults to spec.yaml if not specified\n spec: ./spec.template.yaml\n # allow cross-domain requests to the API (default '*')\n cors: \"*\"\n # to disable use:\n # cors: false\n # to restrict to a particular domain, use:\n # cors: restricted.domain.org\n # content for the CSP headers\n # csp: false # uncomment this line to disable sending them\n # URL of the outbound proxy to use (complete with protocol)\n # proxy: http://my.proxy.org:8080\n # the list of domains for which not to use the proxy defined above\n # no_proxy_list:\n # - domain1.com\n # - domain2.org\n # the list of incoming request headers that can be logged; if left empty,\n # the following headers are allowed: cache-control, content-length,\n # content-type, if-match, user-agent, x-request-id\n # log_header_whitelist:\n # - cache-control\n # - content-length\n # - content-type\n # - if-match\n # - user-agent\n # - x-request-id\n # the user agent to use when issuing requests\n # user_agent: service-template-node\n # max JSON POST body size limit\n # max_body_size: 100kb\n # the template used for contacting the MW API\n mwapi_req:\n method: post\n uri: https://{{domain}}/w/api.php\n headers:\n user-agent: \"{{user-agent}}\"\n body: \"{{ default(request.query, {}) }}\"\n # the template used for contacting RESTBase\n restbase_req:\n method: \"{{request.method}}\"\n uri: https://{{domain}}/api/rest_v1/{+path}\n query: \"{{ default(request.query, {}) }}\"\n headers: \"{{request.headers}}\"\n body: \"{{request.body}}\"\n","usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/docker-compose.yml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/init-db.js","messages":[{"ruleId":"security/detect-non-literal-fs-filename","severity":1,"message":"Found createReadStream from package \"fs\" with non literal argument at index 0","line":137,"column":31,"nodeType":"CallExpression","endLine":137,"endColumn":73}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use strict';\n\nconst fs = require('fs');\nconst mariadb = require('mariadb');\nconst zlib = require('zlib');\nconst byline = require('byline');\n\nasync function getConnection() {\n return await mariadb.createConnection({\n host: process.env.HOST,\n user: process.env.MYSQL_ROOT_USER,\n password: process.env.MYSQL_ROOT_PASSWORD,\n database: process.env.MYSQL_DATABASE,\n port: process.env.MYSQL_PORT,\n multipleStatements: true\n });\n}\n\nasync function clearDb(connection) {\n await connection.query(`DELETE FROM actor_data;\n DELETE FROM behaviors; DELETE FROM actor_data_behaviors;\n DELETE FROM proxies; DELETE FROM actor_data_proxies;\n DELETE FROM tunnels; DELETE FROM actor_data_tunnels;`);\n}\n\nasync function addTables(connection) {\n const schema = fs.readFileSync('./schema.sql', 'utf8');\n await connection.query('DROP TABLE actor_data;');\n await connection.query(schema);\n}\n\nconst entityTypes = {\n UNKNOWN: 0,\n DESKTOP: 1,\n HEADLESS: 2,\n IOT: 3,\n MOBILE: 4\n};\n\nfunction getEntityTypes(types) {\n // Assume only one in array\n return entityTypes[types[0]];\n}\n\nconst riskTypes = {\n UNKNOWN: 0,\n CALLBACK_PROXY: 1,\n GEO_MISMATCH: 2,\n LOGIN_BRUTEFORCE: 3,\n TUNNEL: 4,\n WEB_SCRAPING: 5\n};\n\nfunction getEntityRisks(risks) {\n // Assume only one in array\n return riskTypes[risks[0]];\n}\n\nconst behaviorPkids = {};\nconst proxyPkids = {};\nconst tunnelPkids = {};\n\nlet entryCount = 0;\nlet processedEntries = 0;\n\nasync function writeEntityToDb(connection, entity) {\n // Add to actor_data\n const pkid = await connection.query(\n `INSERT INTO\n actor_data (${Object.keys(entity.actor_data).toString()})\n VALUES\n ( ${JSON.stringify(Object.values(entity.actor_data)).slice(1, -1)} )`\n );\n\n // Add to behaviors\n entity.behaviors.forEach(async (behavior) => {\n const behaviorPkid = await connection.query(\n 'INSERT IGNORE INTO behaviors (behavior) VALUES (?);', [behavior]\n );\n if (behaviorPkid.insertId) {\n behaviorPkids[behavior] = behaviorPkid.insertId;\n }\n await connection.query(\n `INSERT INTO\n actor_data_behaviors (actor_data_id,behavior_id)\n VALUES\n (${pkid.insertId}, ${behaviorPkids[behavior]})`\n );\n });\n\n // Add to proxies\n entity.proxies.forEach(async (proxy) => {\n const proxyPkid = await connection.query(\n 'INSERT IGNORE INTO proxies (proxy) VALUES (?);', [proxy]\n );\n if (proxyPkid.insertId) {\n proxyPkids[proxy] = proxyPkid.insertId;\n }\n await connection.query(\n `INSERT INTO\n actor_data_proxies (actor_data_id,proxy_id)\n VALUES\n (${pkid.insertId}, ${proxyPkids[proxy]})`\n );\n });\n\n // Add to tunnels\n entity.tunnels.forEach(async (tunnel) => {\n const tunnelPkid = await connection.query(\n 'INSERT IGNORE INTO tunnels (tunnel) VALUES (?);', [tunnel]\n );\n if (tunnelPkid.insertId) {\n tunnelPkids[tunnel] = tunnelPkid.insertId;\n }\n await connection.query(\n `INSERT INTO\n actor_data_tunnels (actor_data_id,tunnel_id)\n VALUES\n (${pkid.insertId}, ${tunnelPkids[tunnel]})`\n );\n });\n\n processedEntries += 1;\n}\n\nasync function closeConnectionWhenDone(connection) {\n if (processedEntries === entryCount) {\n await connection.end();\n } else {\n setTimeout(function () {\n closeConnectionWhenDone(connection);\n }, 1000);\n }\n}\n\nasync function importData(connection) {\n const lineReader = byline(fs.createReadStream(process.env.FEED_PATH).pipe(zlib.createGunzip()));\n\n lineReader.on('data', async (line) => {\n entryCount += 1;\n const entity = JSON.parse(line);\n const queryObj = {\n actor_data: {\n ip: entity.ip,\n org: entity.organization,\n client_count: entity.client.count || 0,\n types: entity.client.types ?\n getEntityTypes(entity.client.types) : entityTypes.UNKNOWN,\n conc_geohash:\n entity.client.concentration && entity.client.concentration.geohash ? entity.client.concentration.geohash : '',\n conc_city:\n entity.client.concentration && entity.client.concentration.city ? entity.client.concentration.city : '',\n conc_state:\n entity.client.concentration && entity.client.concentration.state ? entity.client.concentration.state : '',\n conc_country:\n entity.client.concentration && entity.client.concentration.country ? entity.client.concentration.country : '',\n conc_skew:\n entity.client.concentration && entity.client.concentration.skew ?\n entity.client.concentration.skew : 0,\n conc_density:\n entity.client.concentration && entity.client.concentration.density ?\n entity.client.concentration.density : 0,\n countries: entity.client.countries || 0,\n location_country: entity.location.country || '',\n risks: entity.risks ? getEntityRisks(entity.risks) : riskTypes.UNKNOWN\n },\n behaviors: entity.client.behaviors || [],\n proxies: entity.client.proxies || [],\n tunnels: entity.tunnels || []\n };\n\n writeEntityToDb(connection, queryObj);\n });\n\n lineReader.on('end', () => {\n closeConnectionWhenDone(connection);\n });\n}\n\nasync function init() {\n const connection = await getConnection();\n await clearDb(connection);\n await addTables(connection);\n await importData(connection);\n}\n\ninit();\n","usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/lib/api-util.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/lib/feed-util.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/lib/swagger-ui.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/lib/util.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/package-lock.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/package.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/routes/feed/v1.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/routes/info.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/routes/root.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/server.js","messages":[{"ruleId":"es-x/no-hashbang","severity":2,"message":"ES2023 Hashbang comments are forbidden.","line":1,"column":1,"nodeType":"Shebang","messageId":"forbidden","endLine":1,"endColumn":20}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"#!/usr/bin/env node\n\n'use strict';\n\n// Service entry point. Try node server --help for commandline options.\n\n// Start the service by running service-runner, which in turn loads the config\n// (config.yaml by default, specify other path with -c). It requires the\n// module(s) specified in the config 'services' section (app.js in this\n// example).\nconst ServiceRunner = require('service-runner');\nnew ServiceRunner().start();\n","usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/spec.template.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/test/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/test/features/app/app.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/test/features/app/spec.js","messages":[{"ruleId":"security/detect-non-literal-regexp","severity":1,"message":"Found non-literal argument to RegExp Constructor","line":154,"column":13,"nodeType":"NewExpression","endLine":154,"endColumn":46}],"suppressedMessages":[{"ruleId":"max-statements-per-line","severity":2,"message":"This line has 2 statements. Maximum allowed is 1.","line":196,"column":21,"nodeType":"ReturnStatement","messageId":"exceed","endLine":196,"endColumn":33,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"max-statements-per-line","severity":2,"message":"This line has 2 statements. Maximum allowed is 1.","line":197,"column":21,"nodeType":"ReturnStatement","messageId":"exceed","endLine":197,"endColumn":34,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-prototype-builtins","severity":2,"message":"Do not access Object.prototype method 'hasOwnProperty' from target object.","line":213,"column":38,"nodeType":"CallExpression","messageId":"prototypeBuildIn","endLine":213,"endColumn":52,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"block-spacing","severity":2,"message":"Requires a space after '{'.","line":235,"column":41,"nodeType":"BlockStatement","messageId":"missing","endLine":235,"endColumn":42,"fix":{"range":[7420,7420],"text":" "},"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"max-statements-per-line","severity":2,"message":"This line has 2 statements. Maximum allowed is 1.","line":235,"column":42,"nodeType":"ReturnStatement","messageId":"exceed","endLine":235,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-prototype-builtins","severity":2,"message":"Do not access Object.prototype method 'hasOwnProperty' from target object.","line":240,"column":38,"nodeType":"CallExpression","messageId":"prototypeBuildIn","endLine":240,"endColumn":52,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mocha/no-sibling-hooks","severity":2,"message":"Unexpected use of duplicate Mocha `before` hook","line":268,"column":17,"nodeType":"Identifier","endLine":268,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mocha/no-sibling-hooks","severity":2,"message":"Unexpected use of duplicate Mocha `after` hook","line":270,"column":17,"nodeType":"Identifier","endLine":270,"endColumn":22,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mocha/no-nested-tests","severity":2,"message":"Unexpected test nested within another test.","line":274,"column":21,"nodeType":"Identifier","endLine":274,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mocha/handle-done-callback","severity":2,"message":"Expected \"done\" callback to be handled.","line":274,"column":50,"nodeType":"Identifier","endLine":274,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mocha/no-return-and-callback","severity":2,"message":"Unexpected use of `return` in a test with callback","line":276,"column":25,"nodeType":"ReturnStatement","endLine":283,"endColumn":28,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use strict';\n\nconst parallel = require('mocha.parallel');\nconst preq = require('preq');\nconst assert = require('../../utils/assert.js');\nconst Server = require('../../utils/server.js');\nconst URI = require('swagger-router').URI;\nconst OpenAPISchemaValidator = require('openapi-schema-validator').default;\nconst validator = new OpenAPISchemaValidator({ version: 3 });\n\nlet spec = null;\nlet baseUrl = null;\nconst server = new Server();\n\nfunction validateExamples(pathStr, defParams, mSpec) {\n\n const uri = new URI(pathStr, {}, true);\n\n if (!mSpec) {\n try {\n uri.expand(defParams);\n return true;\n } catch (e) {\n throw new Error(`Missing parameter for route ${pathStr} : ${e.message}`);\n }\n }\n\n if (!Array.isArray(mSpec)) {\n throw new Error(`Route ${pathStr} : x-amples must be an array!`);\n }\n\n mSpec.forEach((ex, idx) => {\n if (!ex.title) {\n throw new Error(`Route ${pathStr}, example ${idx}: title missing!`);\n }\n ex.request = ex.request || {};\n try {\n uri.expand(Object.assign({}, defParams, ex.request.params || {}));\n } catch (e) {\n throw new Error(\n `Route ${pathStr}, example ${idx} (${ex.title}): missing parameter: ${e.message}`\n );\n }\n });\n\n return true;\n\n}\n\nfunction constructTestCase(title, path, method, request, response) {\n return {\n title,\n request: {\n uri: (baseUrl || server.config.uri) + (path[0] === '/' ? path.slice(1) : path),\n method,\n headers: request.headers || {},\n query: request.query,\n body: request.body,\n followRedirect: false\n },\n response: {\n status: response.status || 200,\n headers: response.headers || {},\n body: response.body\n }\n };\n\n}\n\nfunction constructTests(spec) {\n const ret = [];\n const paths = spec.paths;\n const defParams = spec['x-default-params'] || {};\n\n Object.keys(paths).forEach((pathStr) => {\n Object.keys(paths[pathStr]).forEach((method) => {\n const p = paths[pathStr][method];\n if ({}.hasOwnProperty.call(p, 'x-monitor') && !p['x-monitor']) {\n return;\n }\n const uri = new URI(pathStr, {}, true);\n if (!p['x-amples']) {\n ret.push(constructTestCase(\n pathStr,\n uri.toString({ params: defParams }),\n method,\n {},\n {}\n ));\n return;\n }\n p['x-amples'].forEach((ex) => {\n ex.request = ex.request || {};\n ret.push(constructTestCase(\n ex.title,\n uri.toString({\n params: Object.assign({},\n defParams,\n ex.request.params || {})\n }),\n method,\n ex.request,\n ex.response || {}\n ));\n });\n });\n });\n\n return ret;\n}\n\nfunction cmp(result, expected, errMsg) {\n\n if (expected === null || expected === undefined) {\n // nothing to expect, so we can return\n return true;\n }\n if (result === null || result === undefined) {\n result = '';\n }\n\n if (expected.constructor === Object) {\n Object.keys(expected).forEach((key) => {\n const val = expected[key];\n assert.deepEqual({}.hasOwnProperty.call(result, key), true,\n `Body field ${key} not found in response!`);\n cmp(result[key], val, `${key} body field mismatch!`);\n });\n return true;\n } else if (expected.constructor === Array) {\n if (result.constructor !== Array) {\n assert.deepEqual(result, expected, errMsg);\n return true;\n }\n // only one item in expected - compare them all\n if (expected.length === 1 && result.length > 1) {\n result.forEach((item) => {\n cmp(item, expected[0], errMsg);\n });\n return true;\n }\n // more than one item expected, check them one by one\n if (expected.length !== result.length) {\n assert.deepEqual(result, expected, errMsg);\n return true;\n }\n expected.forEach((item, idx) => {\n cmp(result[idx], item, errMsg);\n });\n return true;\n }\n\n if (expected.length > 1 && expected[0] === '/' && expected[expected.length - 1] === '/') {\n if (new RegExp(expected.slice(1, -1)).test(result)) {\n return true;\n }\n } else if (expected.length === 0 && result.length === 0) {\n return true;\n } else if (result === expected || result.startsWith(expected)) {\n return true;\n }\n\n assert.deepEqual(result, expected, errMsg);\n return true;\n\n}\n\nfunction validateArray(val, resVal, key) {\n assert.deepEqual(Array.isArray(resVal), true, `Body field ${key} is not an array!`);\n let arrVal;\n if (val.length === 1) {\n // special case: we have specified only one item in the expected body,\n // but what we really want is to check all of the returned items so\n // fill the expected array with as many items as the returned one\n if (resVal.length < 1) {\n throw new assert.AssertionError({\n message: `Expected more then one element in the field: ${key}`\n });\n }\n arrVal = [];\n while (arrVal.length < resVal.length) {\n arrVal.push(val[0]);\n }\n } else {\n arrVal = val;\n }\n assert.deepEqual(arrVal.length, resVal.length,\n `Different size of array for field ${key}, expected ${arrVal.length\n } actual ${resVal.length}`);\n arrVal.forEach((item, index) => {\n validateBody(resVal[index], item);\n });\n}\n\nfunction validateBody(resBody, expBody) {\n if (!expBody) { return true; } // eslint-disable-line\n if (!resBody) { return false; } // eslint-disable-line\n\n if (Buffer.isBuffer(resBody)) {\n resBody = resBody.toString();\n }\n if (expBody.constructor !== resBody.constructor) {\n if (expBody.constructor === String) {\n resBody = JSON.stringify(resBody);\n } else {\n resBody = JSON.parse(resBody);\n }\n }\n if (expBody.constructor === Object) {\n Object.keys(expBody).forEach((key) => {\n const val = expBody[key];\n // eslint-disable-next-line\n assert.deepEqual(resBody.hasOwnProperty(key), true, `Body field ${key} not found in response!`);\n if (val.constructor === Object) {\n validateBody(resBody[key], val);\n } else if (val.constructor === Array) {\n validateArray(val, resBody[key], key);\n } else {\n cmp(resBody[key], val, `${key} body field mismatch!`);\n }\n });\n } else if (Array.isArray(expBody)) {\n validateArray(expBody, resBody, 'body');\n } else {\n cmp(resBody, expBody, 'Body mismatch!');\n }\n return true;\n}\n\nfunction validateTestResponse(testCase, res) {\n const expRes = testCase.response;\n\n assert.deepEqual(res.status, expRes.status);\n\n if (expRes.headers && !res.headers) {return false; } // eslint-disable-line\n\n Object.keys(expRes.headers).forEach((key) => {\n const val = expRes.headers[key];\n // eslint-disable-next-line\n assert.deepEqual(res.headers.hasOwnProperty(key), true, `Header ${key} not found in response!`);\n cmp(res.headers[key], val, `${key} header mismatch!`);\n });\n\n validateBody(res.body || '', expRes.body);\n}\n\ndescribe('Swagger spec', function () {\n\n this.timeout(20000);\n\n before(() => server.start());\n after(() => server.stop());\n\n it('get the spec', () => {\n baseUrl = server.config.uri;\n return preq.get(`${baseUrl}?spec`)\n .then((res) => {\n assert.status(200);\n assert.contentType(res, 'application/json');\n assert.notDeepEqual(res.body, undefined, 'No body received!');\n // save a copy\n spec = res.body;\n return spec;\n })\n .then((spec) => {\n const routeTests = () => {\n // eslint-disable-next-line mocha/no-sibling-hooks\n before(() => server.start());\n // eslint-disable-next-line mocha/no-sibling-hooks\n after(() => server.stop());\n\n constructTests(spec).forEach((testCase) => {\n // eslint-disable-next-line mocha/handle-done-callback, mocha/no-nested-tests\n it(testCase.title, function (done) {\n // eslint-disable-next-line mocha/no-return-and-callback\n return preq(testCase.request)\n .then((res) => {\n assert.status(res, testCase.response.status);\n validateTestResponse(testCase, res);\n }, (err) => {\n assert.status(err, testCase.response.status);\n validateTestResponse(testCase, err);\n });\n });\n });\n };\n parallel('Monitoring routes', routeTests);\n });\n });\n\n it('should expose valid OpenAPI spec', () => {\n return preq.get({ uri: `${server.config.uri}?spec` })\n .then((res) => {\n assert.deepEqual({ errors: [] }, validator.validate(res.body), 'Spec must have no validation errors');\n });\n });\n\n it('spec validation', () => {\n // check the high-level attributes\n [ 'info', 'openapi', 'paths' ].forEach((prop) => {\n assert.deepEqual(!!spec[prop], true, `No ${prop} field present!`);\n });\n // no paths - no love\n assert.deepEqual(!!Object.keys(spec.paths), true, 'No paths given in the spec!');\n // now check each path\n Object.keys(spec.paths).forEach((pathStr) => {\n assert.deepEqual(!!pathStr, true, 'A path cannot have a length of zero!');\n const path = spec.paths[pathStr];\n assert.deepEqual(!!Object.keys(path), true, `No methods defined for path: ${pathStr}`);\n Object.keys(path).forEach((method) => {\n const mSpec = path[method];\n if ({}.hasOwnProperty.call(mSpec, 'x-monitor') && !mSpec['x-monitor']) {\n return;\n }\n validateExamples(pathStr, spec['x-default-params'] || {}, mSpec['x-amples']);\n });\n });\n });\n});\n","usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/test/features/info/info.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/test/utils/assert.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/test/utils/server.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]}]
--- end ---
$ /usr/bin/npm ci --legacy-peer-deps
--- stderr ---
npm WARN deprecated kad-fs@0.0.4: This package is no longer maintained.
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated kad-memstore@0.0.1: This package is no longer maintained.
npm WARN deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
npm WARN deprecated mkdirp@0.5.1: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
--- stdout ---
added 636 packages, and audited 703 packages in 9s
56 packages are looking for funding
run `npm fund` for details
27 vulnerabilities (11 moderate, 11 high, 5 critical)
To address issues that do not require attention, run:
npm audit fix
To address all issues possible (including breaking changes), run:
npm audit fix --force
Some issues need review, and may require choosing
a different dependency.
Run `npm audit` for details.
--- end ---
$ /usr/bin/npm test
--- stderr ---
ESLint found too many warnings (maximum: 0).
--- stdout ---
> ipoid@0.1.0 test
> npm run lint && PREQ_CONNECT_TIMEOUT=15 mocha
> ipoid@0.1.0 lint
> eslint --max-warnings 0 --ext .js --ext .json .
/src/repo/app.js
63:37 warning Found non-literal argument to RegExp Constructor security/detect-non-literal-regexp
150:31 warning Found non-literal argument in require security/detect-non-literal-require
/src/repo/init-db.js
137:31 warning Found createReadStream from package "fs" with non literal argument at index 0 security/detect-non-literal-fs-filename
/src/repo/server.js
1:1 warning ES2023 Hashbang comments are forbidden es-x/no-hashbang
/src/repo/test/features/app/spec.js
154:13 warning Found non-literal argument to RegExp Constructor security/detect-non-literal-regexp
✖ 5 problems (0 errors, 5 warnings)
--- end ---
Traceback (most recent call last):
File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/__init__.py", line 1400, in main
libup.run(args.repo, args.output, args.branch)
File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/__init__.py", line 1338, in run
self.npm_upgrade(plan)
File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/__init__.py", line 1049, in npm_upgrade
self.npm_test()
File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/__init__.py", line 287, in npm_test
self.check_call(['npm', 'test'])
File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/shell2.py", line 54, in check_call
res.check_returncode()
File "/usr/lib/python3.9/subprocess.py", line 460, in check_returncode
raise CalledProcessError(self.returncode, self.args, self.stdout,
subprocess.CalledProcessError: Command '['/usr/bin/npm', 'test']' returned non-zero exit status 1.