npq 3.8.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/npq.mov +0 -0
- package/.github/npq.mp4 +0 -0
- package/.github/npq.png +0 -0
- package/.github/workflows/main.yml +2 -2
- package/README.md +18 -9
- package/__tests__/__fixtures__/test.marshall.js +5 -6
- package/__tests__/cli.test.js +110 -0
- package/__tests__/cliPrompt.test.js +409 -0
- package/__tests__/marshalls.base.test.js +1 -1
- package/__tests__/marshalls.classMethods.test.js +11 -14
- package/__tests__/marshalls.expiredDomains.test.js +2 -2
- package/__tests__/marshalls.provenance.test.js +181 -4
- package/__tests__/marshalls.repo.test.js +6 -6
- package/__tests__/marshalls.signatures.test.js +0 -4
- package/__tests__/marshalls.snyk.test.js +294 -0
- package/__tests__/marshalls.tasks.test.js +48 -24
- package/__tests__/marshalls.typosquatting.test.js +16 -9
- package/__tests__/marshalls.version-maturity.test.js +6 -6
- package/__tests__/packageRepoUtils.test.js +4 -4
- package/__tests__/reportResults.test.js +772 -0
- package/__tests__/scripts.test.js +2 -2
- package/bin/npq-hero.js +70 -20
- package/bin/npq.js +113 -21
- package/lib/cli.js +127 -24
- package/lib/helpers/cliPrompt.js +97 -0
- package/lib/helpers/cliSpinner.js +104 -0
- package/lib/helpers/cliSupportHandler.js +50 -7
- package/lib/helpers/packageRepoUtils.js +7 -2
- package/lib/helpers/promiseThrottler.js +96 -0
- package/lib/helpers/reportResults.js +304 -0
- package/lib/helpers/sourcePackages.js +36 -0
- package/lib/marshall.js +42 -65
- package/lib/marshalls/age.marshall.js +4 -3
- package/lib/marshalls/author.marshall.js +38 -9
- package/lib/marshalls/baseMarshall.js +9 -17
- package/lib/marshalls/deprecation.marshall.js +43 -0
- package/lib/marshalls/downloads.marshall.js +3 -3
- package/lib/marshalls/expiredDomains.marshall.js +7 -5
- package/lib/marshalls/index.js +110 -80
- package/lib/marshalls/license.marshall.js +3 -3
- package/lib/marshalls/newbin.marshall.js +1 -2
- package/lib/marshalls/provenance.marshall.js +152 -33
- package/lib/marshalls/repo.marshall.js +8 -7
- package/lib/marshalls/scripts.marshall.js +1 -1
- package/lib/marshalls/signatures.marshall.js +26 -2
- package/lib/marshalls/snyk.marshall.js +61 -15
- package/lib/marshalls/typosquatting.marshall.js +8 -5
- package/lib/marshalls/version-maturity.marshall.js +4 -4
- package/lib/marshallsDecomissioned/readme.marshall.js +2 -2
- package/package.json +16 -19
- package/scripts/postinstall.js +10 -11
- package/lib/cliCommons.js +0 -80
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const BaseMarshall = require('./baseMarshall')
|
|
4
|
+
const Warning = require('../helpers/warning')
|
|
4
5
|
const { marshallCategories } = require('./constants')
|
|
5
6
|
|
|
6
7
|
const MARSHALL_NAME = 'age'
|
|
@@ -32,13 +33,13 @@ class Marshall extends BaseMarshall {
|
|
|
32
33
|
ageDateDiff = dateDiff
|
|
33
34
|
if (dateDiff < PACKAGE_AGE_THRESHOLD) {
|
|
34
35
|
throw new Error(
|
|
35
|
-
`
|
|
36
|
+
`Detected a newly published package (created < ${PACKAGE_AGE_THRESHOLD} days) act carefully`
|
|
36
37
|
)
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
return pkg
|
|
40
41
|
} else {
|
|
41
|
-
throw new
|
|
42
|
+
throw new Warning('Could not determine package age')
|
|
42
43
|
}
|
|
43
44
|
})
|
|
44
45
|
.then((pkg) => {
|
|
@@ -59,7 +60,7 @@ class Marshall extends BaseMarshall {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
if (versionDateDiffInDays >= PACKAGE_AGE_UNMAINTAINED_RISK) {
|
|
62
|
-
throw new
|
|
63
|
+
throw new Warning(`Detected an old package (created ${timeAgoNumber} ${timeAgoText} ago)`)
|
|
63
64
|
}
|
|
64
65
|
})
|
|
65
66
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const BaseMarshall = require('./baseMarshall')
|
|
4
|
-
const
|
|
4
|
+
const Warning = require('../helpers/warning')
|
|
5
5
|
const { marshallCategories } = require('./constants')
|
|
6
6
|
|
|
7
7
|
const MARSHALL_NAME = 'author'
|
|
@@ -43,11 +43,14 @@ class Marshall extends BaseMarshall {
|
|
|
43
43
|
// for dis-tags (latest)
|
|
44
44
|
const npmUser = pakument.versions[packageVersion]._npmUser
|
|
45
45
|
if (!npmUser || !npmUser.email) {
|
|
46
|
-
throw new Error('
|
|
46
|
+
throw new Error('Could not determine publishing user for this package version')
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// Agree with Colin on keeping email regex simple: https://colinhacks.com/essays/reasonable-email-regex
|
|
50
|
+
const emailRegex =
|
|
51
|
+
/^(?!\.)(?!.*\.\.)([a-z0-9_'+\-\.]*)[a-z0-9_'+\-]@([a-z0-9][a-z0-9\-]*\.)+[a-z]{2,}$/i
|
|
52
|
+
if (!emailRegex.test(npmUser.email)) {
|
|
53
|
+
throw new Error('The publishing user has no valid email address')
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
let firstVersionForUser = null
|
|
@@ -60,9 +63,29 @@ class Marshall extends BaseMarshall {
|
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
if (!firstVersionForUser || firstVersionForUser.version === packageVersion) {
|
|
63
|
-
throw
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
// Only throw the error if also the `packageVersion` was published less than 21 days ago:
|
|
67
|
+
if (versionPublishedDateString) {
|
|
68
|
+
const dateDiffInMs = new Date() - new Date(versionPublishedDateString)
|
|
69
|
+
let dateDiffInDays = 0
|
|
70
|
+
|
|
71
|
+
if (dateDiffInMs > 0) {
|
|
72
|
+
dateDiffInDays = Math.round(dateDiffInMs / (1000 * 60 * 60 * 24))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (dateDiffInDays <= 21) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`The user ${npmUser.name} <${npmUser.email}> published this package for the first time only ${dateDiffInDays} days ago`
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// otherwise, there's no point in throwing an error
|
|
83
|
+
// because this version already exists for a while. for e.g: package `ncp` latest version
|
|
84
|
+
// is from 10 years ago which was the first version published by the user, but that's
|
|
85
|
+
// hardly a risk at this point being 10 years old, so we don't throw the following error:
|
|
86
|
+
// throw new Error(
|
|
87
|
+
// `This is the first version the user ${npmUser.name} <${npmUser.email}> published this package`
|
|
88
|
+
// )
|
|
66
89
|
}
|
|
67
90
|
|
|
68
91
|
const firstPublishedDateString = pakument.time[firstVersionForUser.version]
|
|
@@ -82,9 +105,15 @@ class Marshall extends BaseMarshall {
|
|
|
82
105
|
dateDiffInDays = Math.round(dateDiffInMs / (1000 * 60 * 60 * 24))
|
|
83
106
|
}
|
|
84
107
|
|
|
85
|
-
if (dateDiffInDays <=
|
|
108
|
+
if (dateDiffInDays <= 7) {
|
|
86
109
|
throw new Error(
|
|
87
|
-
`The user ${npmUser.name} <${npmUser.email}> published this package for the first time only ${dateDiffInDays} days
|
|
110
|
+
`The user ${npmUser.name} <${npmUser.email}> published this package for the first time only ${dateDiffInDays} days ago`
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (dateDiffInDays <= 30) {
|
|
115
|
+
throw new Warning(
|
|
116
|
+
`The user ${npmUser.name} <${npmUser.email}> published this package for the first time only ${dateDiffInDays} days ago`
|
|
88
117
|
)
|
|
89
118
|
}
|
|
90
119
|
}
|
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const util = require('node:util')
|
|
3
4
|
const Warning = require('../helpers/warning')
|
|
4
5
|
const { marshallCategories } = require('./constants')
|
|
5
6
|
|
|
6
7
|
class BaseMarshall {
|
|
7
8
|
constructor(options) {
|
|
9
|
+
this.debug = util.debuglog('npq')
|
|
8
10
|
this.packageRepoUtils = options.packageRepoUtils
|
|
9
11
|
this.categoryId = marshallCategories.PackageHealth.id
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
init(ctx
|
|
14
|
+
init(ctx) {
|
|
13
15
|
this.ctx = ctx
|
|
14
|
-
this.task = task
|
|
15
16
|
|
|
16
17
|
ctx.marshalls[this.name] = {
|
|
17
18
|
status: null,
|
|
18
19
|
errors: [],
|
|
19
20
|
warnings: [],
|
|
20
|
-
data: {}
|
|
21
|
+
data: {},
|
|
22
|
+
marshall: this.name,
|
|
23
|
+
categoryId: this.categoryId
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
run(ctx
|
|
27
|
+
run(ctx) {
|
|
25
28
|
const tasks = ctx.pkgs.reduce((prevPkg, currPkg) => {
|
|
26
|
-
return prevPkg.concat(this.checkPackage(currPkg, ctx
|
|
29
|
+
return prevPkg.concat(this.checkPackage(currPkg, ctx))
|
|
27
30
|
}, [])
|
|
28
31
|
|
|
29
32
|
return Promise.all(tasks)
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
checkPackage(pkg, ctx
|
|
35
|
+
checkPackage(pkg, ctx) {
|
|
33
36
|
return this.validate(pkg)
|
|
34
37
|
.then((data) => {
|
|
35
|
-
task.output = `querying ${pkg.packageString}...`
|
|
36
38
|
ctx.marshalls[this.name].data[pkg.packageString] = data
|
|
37
39
|
|
|
38
40
|
// not explicitly required, but a task can return its results
|
|
@@ -65,16 +67,6 @@ class BaseMarshall {
|
|
|
65
67
|
message: msg.message
|
|
66
68
|
})
|
|
67
69
|
}
|
|
68
|
-
|
|
69
|
-
handleMessages() {
|
|
70
|
-
const errors = this.ctx.marshalls[this.name].errors
|
|
71
|
-
const warnings = this.ctx.marshalls[this.name].warnings
|
|
72
|
-
if ((errors && errors.length) || (warnings && warnings.length)) {
|
|
73
|
-
throw new Error()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return Promise.resolve()
|
|
77
|
-
}
|
|
78
70
|
}
|
|
79
71
|
|
|
80
72
|
module.exports = BaseMarshall
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const BaseMarshall = require('./baseMarshall')
|
|
4
|
+
const { marshallCategories } = require('./constants')
|
|
5
|
+
|
|
6
|
+
const MARSHALL_NAME = 'deprecation'
|
|
7
|
+
|
|
8
|
+
class Marshall extends BaseMarshall {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options)
|
|
11
|
+
this.name = MARSHALL_NAME
|
|
12
|
+
this.categoryId = marshallCategories.PackageHealth.id
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
title() {
|
|
16
|
+
return 'Checking package for deprecation flag'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
validate(pkg) {
|
|
20
|
+
return this.packageRepoUtils.getPackageInfo(pkg.packageName).then((data) => {
|
|
21
|
+
const packageVersion =
|
|
22
|
+
pkg.packageVersion === 'latest'
|
|
23
|
+
? data['dist-tags'] && data['dist-tags'].latest
|
|
24
|
+
: this.packageRepoUtils.parsePackageVersion(pkg.packageVersion).version
|
|
25
|
+
|
|
26
|
+
if (!packageVersion) {
|
|
27
|
+
return true
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const packageDeprecated =
|
|
31
|
+
data &&
|
|
32
|
+
data.versions &&
|
|
33
|
+
data.versions[packageVersion] &&
|
|
34
|
+
data.versions[packageVersion].deprecated
|
|
35
|
+
|
|
36
|
+
if (packageDeprecated) {
|
|
37
|
+
throw new Error(`Package deprecated: ${packageDeprecated}`)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = Marshall
|
|
@@ -12,7 +12,7 @@ class Marshall extends BaseMarshall {
|
|
|
12
12
|
constructor(options) {
|
|
13
13
|
super(options)
|
|
14
14
|
this.name = MARSHALL_NAME
|
|
15
|
-
this.categoryId = marshallCategories.
|
|
15
|
+
this.categoryId = marshallCategories.PackageHealth.id
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
title() {
|
|
@@ -23,13 +23,13 @@ class Marshall extends BaseMarshall {
|
|
|
23
23
|
return this.packageRepoUtils.getDownloadInfo(pkg.packageName).then((downloadCount) => {
|
|
24
24
|
if (downloadCount < DOWNLOAD_COUNT_THRESHOLD) {
|
|
25
25
|
throw new Error(
|
|
26
|
-
`
|
|
26
|
+
`Detected a low download-count package (downloads last month < ${DOWNLOAD_COUNT_THRESHOLD})`
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
if (downloadCount < DOWNLOAD_COUNT_UPPER_THRESHOLD) {
|
|
31
31
|
throw new Warning(
|
|
32
|
-
`
|
|
32
|
+
`Detected a low relatively low download-count package (${downloadCount} downloads last month)`
|
|
33
33
|
)
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
const BaseMarshall = require('./baseMarshall')
|
|
4
4
|
const { marshallCategories } = require('./constants')
|
|
5
|
-
const
|
|
5
|
+
const { Resolver } = require('dns/promises')
|
|
6
6
|
|
|
7
|
+
const dns = new Resolver()
|
|
8
|
+
dns.setServers(['1.1.1.1', '8.8.8.8'])
|
|
7
9
|
const MARSHALL_NAME = 'maintainers_expired_emails'
|
|
8
10
|
|
|
9
11
|
class Marshall extends BaseMarshall {
|
|
10
12
|
constructor(options) {
|
|
11
13
|
super(options)
|
|
12
14
|
this.name = MARSHALL_NAME
|
|
13
|
-
this.categoryId = marshallCategories.
|
|
15
|
+
this.categoryId = marshallCategories.PackageHealth.id
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
title() {
|
|
@@ -30,16 +32,16 @@ class Marshall extends BaseMarshall {
|
|
|
30
32
|
for (const maintainerInfo of maintainersAccounts) {
|
|
31
33
|
const maintainerEmail = maintainerInfo.email
|
|
32
34
|
const emailDomain = maintainerEmail.split('@')[1]
|
|
33
|
-
testEmails.push(dns.resolve(emailDomain))
|
|
35
|
+
testEmails.push(dns.resolve(emailDomain, 'NS'))
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
return Promise.all(testEmails)
|
|
37
39
|
})
|
|
38
40
|
.catch((error) => {
|
|
39
41
|
const emailHostname = error.hostname ? error.hostname : '<unknown>'
|
|
42
|
+
this.debug('\nDetected error resolving domain for maintainer e-mail: %s', emailHostname)
|
|
40
43
|
throw new Error(
|
|
41
|
-
'
|
|
42
|
-
emailHostname
|
|
44
|
+
'Detected expired domain can be abused for account takeover: ' + emailHostname
|
|
43
45
|
)
|
|
44
46
|
})
|
|
45
47
|
}
|
package/lib/marshalls/index.js
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const { marshallCategories } = require('./constants')
|
|
3
|
+
const fs = require('node:fs')
|
|
4
|
+
const path = require('node:path')
|
|
6
5
|
|
|
7
6
|
class Marshalls {
|
|
8
7
|
static async collectMarshalls() {
|
|
9
|
-
const files = await
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const files = await fs.promises.readdir(__dirname)
|
|
9
|
+
|
|
10
|
+
const matchingFiles = files
|
|
11
|
+
.filter((file) => file.endsWith('.marshall.js'))
|
|
12
|
+
.map((file) => path.resolve(__dirname, file))
|
|
13
13
|
|
|
14
|
-
return
|
|
14
|
+
return matchingFiles
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
static async buildMarshallTasks(marshalls,
|
|
17
|
+
static async buildMarshallTasks(marshalls, options) {
|
|
18
18
|
if (!marshalls || !Array.isArray(marshalls) || marshalls.length === 0) {
|
|
19
19
|
return Promise.reject(new Error('unable to collect marshalls, or no marshalls found'))
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
const config = {
|
|
23
|
+
packageRepoUtils: options.packageRepoUtils
|
|
24
|
+
}
|
|
25
|
+
|
|
22
26
|
const marshallTasks = marshalls.reduce((prev, curr) => {
|
|
23
27
|
// eslint-disable-next-line security/detect-non-literal-require
|
|
24
28
|
const Marshall = require(curr)
|
|
@@ -27,79 +31,114 @@ class Marshalls {
|
|
|
27
31
|
return prev.concat({
|
|
28
32
|
title: marshall.title(),
|
|
29
33
|
categoryId: marshall.categoryId,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
execute: async (options) => {
|
|
35
|
+
const ctx = {
|
|
36
|
+
pkgs: options.pkgs,
|
|
37
|
+
marshalls: {}
|
|
38
|
+
}
|
|
39
|
+
marshall.init(ctx)
|
|
40
|
+
await marshall.run(ctx)
|
|
41
|
+
return ctx
|
|
36
42
|
}
|
|
37
43
|
})
|
|
38
44
|
}, [])
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
const category = marshallCategories[categoryId]
|
|
42
|
-
const filteredMarshallTasks = marshallTasks.filter((marshall) => {
|
|
43
|
-
return marshall.categoryId === category.id
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
const marshallsInCategory = {
|
|
47
|
-
title: category.title,
|
|
48
|
-
enabled: true,
|
|
49
|
-
task: () => {
|
|
50
|
-
return new Listr(filteredMarshallTasks, {
|
|
51
|
-
exitOnError: false,
|
|
52
|
-
concurrent: true,
|
|
53
|
-
rendererOptions: { collapseSubtasks: false }
|
|
54
|
-
})
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return marshallsInCategory
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
return new Listr(allMarshallTasksByCategories, {
|
|
61
|
-
exitOnError: false,
|
|
62
|
-
concurrent: true,
|
|
63
|
-
rendererOptions: { collapseSubtasks: false }
|
|
64
|
-
})
|
|
46
|
+
return marshallTasks
|
|
65
47
|
}
|
|
66
48
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Executes security and health audits on npm packages using registered marshalls
|
|
51
|
+
*
|
|
52
|
+
* @param {Object} options - Configuration object containing packages and utilities
|
|
53
|
+
* @param {Array<Object>} options.pkgs - Array of package objects with packageName, packageVersion, and packageString properties
|
|
54
|
+
* @param {PackageRepoUtils} options.packageRepoUtils - Instance for fetching package information from registry
|
|
55
|
+
* @param {Object} [progressManager] - Optional progress manager for displaying audit progress updates
|
|
56
|
+
* @returns {Promise<Array<Object>>} Array of marshall results containing audit findings for each package
|
|
57
|
+
*/
|
|
58
|
+
static async tasks(options, progressManager) {
|
|
59
|
+
const marshallResults = []
|
|
60
|
+
|
|
61
|
+
// @TODO handle throw error because fetch didn't work due to network issues
|
|
62
|
+
// currently, errors here with fetch fail like this:
|
|
63
|
+
// TypeError: fetch failed
|
|
64
|
+
// at node:internal/deps/undici/undici:13502:13
|
|
65
|
+
// at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
|
|
66
|
+
// at async Promise.all (index 0)
|
|
67
|
+
// [cause]: Error: getaddrinfo ENOTFOUND registry.npmjs.org
|
|
68
|
+
// at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:120:26) {
|
|
69
|
+
// errno: -3008,
|
|
70
|
+
// code: 'ENOTFOUND',
|
|
71
|
+
// syscall: 'getaddrinfo',
|
|
72
|
+
// hostname: 'registry.npmjs.org'
|
|
73
|
+
// }
|
|
74
|
+
// }
|
|
75
|
+
const packagesDataList = await Marshalls.warmUpPackagesCache(options)
|
|
76
|
+
|
|
77
|
+
// handle error in case we get just one package and it is not found
|
|
78
|
+
// if (packagesDataList && packagesDataList.length === 1) {
|
|
79
|
+
// if (packagesDataList[0].error && packagesDataList[0].error === 'Not found') {
|
|
80
|
+
// }
|
|
81
|
+
// }
|
|
82
|
+
|
|
83
|
+
// handle error in case we get more than one package and at least one is not found
|
|
84
|
+
// in which we case we simply remove the package from the `options` array
|
|
85
|
+
// which lists objects (each have a property of packageName)
|
|
86
|
+
if (packagesDataList && packagesDataList.length > 0) {
|
|
87
|
+
options.pkgs = options.pkgs.filter((pkg, index) => {
|
|
88
|
+
if (packagesDataList[index].error && packagesDataList[index].error === 'Not found') {
|
|
89
|
+
const errorResult = {
|
|
90
|
+
['not_found']: {
|
|
91
|
+
marshall: 'not_found',
|
|
92
|
+
status: null,
|
|
93
|
+
errors: [{ pkg: options.pkgs[index].packageName, message: 'Package not found' }],
|
|
94
|
+
warnings: [],
|
|
95
|
+
data: {},
|
|
96
|
+
categoryId: 'PackageHealth'
|
|
97
|
+
}
|
|
76
98
|
}
|
|
77
|
-
}
|
|
78
99
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// which lists objects (each have a property of packageName)
|
|
82
|
-
if (packagesDataList && packagesDataList.length > 1) {
|
|
83
|
-
options.pkgs = options.pkgs.filter((pkg, index) => {
|
|
84
|
-
return !packagesDataList[index].error || packagesDataList[index].error !== 'Not found'
|
|
85
|
-
})
|
|
100
|
+
marshallResults.push(errorResult)
|
|
101
|
+
return false
|
|
86
102
|
}
|
|
103
|
+
|
|
104
|
+
return true
|
|
87
105
|
})
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return { error: true, message: err.message }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const marshalls = await Marshalls.collectMarshalls()
|
|
109
|
+
|
|
110
|
+
if (progressManager && options.pkgs && options.pkgs.length > 0) {
|
|
111
|
+
const packageList = options.pkgs.map((pkg) => pkg.packageString).join(', ')
|
|
112
|
+
progressManager.update(`Auditing packages: ${packageList}`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const packagesToProcess = options.pkgs
|
|
116
|
+
if (packagesToProcess.length > 0) {
|
|
117
|
+
const marshallTasks = await Marshalls.buildMarshallTasks(marshalls, {
|
|
118
|
+
packageRepoUtils: options.packageRepoUtils
|
|
102
119
|
})
|
|
120
|
+
|
|
121
|
+
for (const marshall of marshallTasks) {
|
|
122
|
+
try {
|
|
123
|
+
const res = await marshall.execute({
|
|
124
|
+
pkgs: options.pkgs,
|
|
125
|
+
marshalls: {}
|
|
126
|
+
})
|
|
127
|
+
marshallResults.push(res.marshalls)
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error(`Error running task ${marshall.title}:`, error)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return marshallResults
|
|
135
|
+
|
|
136
|
+
// .catch((err) => {
|
|
137
|
+
// // console.error('Error:', err.message)
|
|
138
|
+
// // avoid implementing a custom error message for a not found package
|
|
139
|
+
// // because the package manager will yield its own error message
|
|
140
|
+
// return { error: true, message: err.message }
|
|
141
|
+
// })
|
|
103
142
|
}
|
|
104
143
|
|
|
105
144
|
static warmUpPackagesCache(options) {
|
|
@@ -112,15 +151,6 @@ class Marshalls {
|
|
|
112
151
|
|
|
113
152
|
return Promise.all(fetchPackagesInfoPromises)
|
|
114
153
|
}
|
|
115
|
-
|
|
116
|
-
static runTasks(tasks, options) {
|
|
117
|
-
return tasks.run({
|
|
118
|
-
pkgs: options.pkgs,
|
|
119
|
-
marshalls: {}
|
|
120
|
-
})
|
|
121
|
-
}
|
|
122
154
|
}
|
|
123
155
|
|
|
124
|
-
Marshalls.GLOB_MARSHALLS = '*.marshall.js'
|
|
125
|
-
|
|
126
156
|
module.exports = Marshalls
|
|
@@ -9,7 +9,7 @@ class Marshall extends BaseMarshall {
|
|
|
9
9
|
constructor(options) {
|
|
10
10
|
super(options)
|
|
11
11
|
this.name = MARSHALL_NAME
|
|
12
|
-
this.categoryId = marshallCategories.
|
|
12
|
+
this.categoryId = marshallCategories.SupplyChainSecurity.id
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
title() {
|
|
@@ -19,11 +19,11 @@ class Marshall extends BaseMarshall {
|
|
|
19
19
|
validate(pkg) {
|
|
20
20
|
return this.packageRepoUtils.getLicenseInfo(pkg.packageName).then((licenseContents) => {
|
|
21
21
|
if (!licenseContents || licenseContents === 'ERROR: No LICENSE data found!') {
|
|
22
|
-
throw new Error('
|
|
22
|
+
throw new Error('Package has no LICENSE file available')
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
if (licenseContents && licenseContents.indexOf('# Security holding package') === 0) {
|
|
26
|
-
throw new Error('
|
|
26
|
+
throw new Error('Package flagged for security issues and served as place-holder')
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
return licenseContents
|
|
@@ -11,8 +11,7 @@ class NewBinMarshall extends BaseMarshall {
|
|
|
11
11
|
constructor(options) {
|
|
12
12
|
super(options)
|
|
13
13
|
this.name = MARSHALL_NAME
|
|
14
|
-
|
|
15
|
-
this.categoryId = marshallCategories.PackageHealth.id
|
|
14
|
+
this.categoryId = marshallCategories.SupplyChainSecurity.id
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
title() {
|