npq 3.11.3 → 3.11.5

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.
@@ -19,48 +19,49 @@ class Marshall extends BaseMarshall {
19
19
  return 'Checking package maturity'
20
20
  }
21
21
 
22
- validate(pkg) {
23
- let packageData = null
24
- return this.packageRepoUtils
25
- .getPackageInfo(pkg.packageName)
26
- .then((data) => {
27
- if (data && data.time && data.time.created) {
28
- packageData = data
29
- const pkgCreatedDate = data.time.created
30
- const dateDiff = Date.now() - Date.parse(pkgCreatedDate)
22
+ async validate(pkg) {
23
+ const data = await this.packageRepoUtils.getPackageInfo(pkg.packageName)
31
24
 
32
- if (dateDiff < PACKAGE_AGE_THRESHOLD) {
33
- throw new Error(
34
- `Detected a newly published package (created < ${PACKAGE_AGE_THRESHOLD} days) act carefully`
35
- )
36
- }
25
+ if (!data || !data.time || !data.time.created) {
26
+ throw new Warning('Could not determine package age')
27
+ }
37
28
 
38
- return pkg
39
- } else {
40
- throw new Warning('Could not determine package age')
41
- }
42
- })
43
- .then((pkg) => {
44
- return this.packageRepoUtils.getSemVer(pkg.packageName, pkg.packageVersion)
45
- })
46
- .then((versionResolved) => {
47
- const versionReleaseDate = packageData.time[versionResolved]
48
- const versionDateDiff = new Date() - new Date(versionReleaseDate)
29
+ const pkgCreatedDate = data.time.created
30
+ const dateDiff = Date.now() - Date.parse(pkgCreatedDate)
31
+ const thresholdMs = PACKAGE_AGE_THRESHOLD * 24 * 60 * 60 * 1000
49
32
 
50
- const versionDateDiffInDays = Math.round(versionDateDiff / (1000 * 60 * 60 * 24))
33
+ if (dateDiff < thresholdMs) {
34
+ throw new Error(
35
+ `Detected a newly published package (created < ${PACKAGE_AGE_THRESHOLD} days) act carefully`
36
+ )
37
+ }
51
38
 
52
- let timeAgoText = 'days'
53
- let timeAgoNumber = versionDateDiffInDays
39
+ const packageVersion = await this.resolvePackageVersion(
40
+ pkg.packageName,
41
+ pkg.packageVersion,
42
+ data
43
+ )
54
44
 
55
- if (versionDateDiffInDays >= 365) {
56
- timeAgoText = 'years'
57
- timeAgoNumber = Math.floor(versionDateDiffInDays / 365)
58
- }
45
+ if (!packageVersion || !data.time[packageVersion]) {
46
+ throw new Warning('Could not determine package version release date')
47
+ }
59
48
 
60
- if (versionDateDiffInDays >= PACKAGE_AGE_UNMAINTAINED_RISK) {
61
- throw new Warning(`Detected an old package (created ${timeAgoNumber} ${timeAgoText} ago)`)
62
- }
63
- })
49
+ const versionReleaseDate = data.time[packageVersion]
50
+ const versionDateDiff = Date.now() - Date.parse(versionReleaseDate)
51
+ const versionDateDiffInDays = Math.round(versionDateDiff / (1000 * 60 * 60 * 24))
52
+ const unmaintainedThresholdMs = PACKAGE_AGE_UNMAINTAINED_RISK * 24 * 60 * 60 * 1000
53
+
54
+ let timeAgoText = 'days'
55
+ let timeAgoNumber = versionDateDiffInDays
56
+
57
+ if (versionDateDiffInDays >= 365) {
58
+ timeAgoText = 'years'
59
+ timeAgoNumber = Math.floor(versionDateDiffInDays / 365)
60
+ }
61
+
62
+ if (versionDateDiff >= unmaintainedThresholdMs) {
63
+ throw new Warning(`Detected an old package (created ${timeAgoNumber} ${timeAgoText} ago)`)
64
+ }
64
65
  }
65
66
  }
66
67
 
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const semver = require('semver')
3
4
  const util = require('node:util')
4
5
  const Warning = require('../helpers/warning')
5
6
  const { marshallCategories } = require('./constants')
@@ -67,6 +68,38 @@ class BaseMarshall {
67
68
  message: msg.message
68
69
  })
69
70
  }
71
+
72
+ /**
73
+ * Resolves a package version string to an actual semver version
74
+ * Handles dist-tags (latest, beta, etc.) and direct semver versions
75
+ * @param {string} packageName - The package name
76
+ * @param {string} versionSpec - The version specification (could be dist-tag or semver)
77
+ * @param {Object} packageData - Optional package data to avoid re-fetching
78
+ * @returns {Promise<string|null>} - The resolved semver version or null if not found
79
+ */
80
+
81
+ async resolvePackageVersion(packageName, versionSpec, packageData) {
82
+ if (typeof versionSpec !== 'string' || versionSpec.trim() === '') return null
83
+ const data = packageData || (await this.packageRepoUtils.getPackageInfo(packageName))
84
+
85
+ if (!data) return null
86
+
87
+ // Handle dist-tags first
88
+ if (data['dist-tags'] && data['dist-tags'][versionSpec]) {
89
+ return data['dist-tags'][versionSpec]
90
+ }
91
+
92
+ // Handle semver ranges and exact versions using all available versions
93
+ if (data.versions) {
94
+ const availableVersions = Object.keys(data.versions)
95
+ const resolved = semver.maxSatisfying(availableVersions, versionSpec)
96
+ if (resolved) return resolved
97
+ }
98
+
99
+ // Fallback for simple parsing if range resolution fails
100
+ const parsed = this.packageRepoUtils.parsePackageVersion(versionSpec)
101
+ return parsed ? parsed.version : null
102
+ }
70
103
  }
71
104
 
72
105
  module.exports = BaseMarshall
@@ -16,27 +16,32 @@ class Marshall extends BaseMarshall {
16
16
  return 'Checking package for deprecation flag'
17
17
  }
18
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
- })
19
+ async validate(pkg) {
20
+ const data = await this.packageRepoUtils.getPackageInfo(pkg.packageName)
21
+
22
+ if (!data) {
23
+ return true
24
+ }
25
+
26
+ const packageVersion = await this.resolvePackageVersion(
27
+ pkg.packageName,
28
+ pkg.packageVersion,
29
+ data
30
+ )
31
+
32
+ if (!packageVersion) {
33
+ return true
34
+ }
35
+
36
+ const packageDeprecated =
37
+ data &&
38
+ data.versions &&
39
+ data.versions[packageVersion] &&
40
+ data.versions[packageVersion].deprecated
41
+
42
+ if (packageDeprecated) {
43
+ throw new Error(`Package deprecated: ${packageDeprecated}`)
44
+ }
40
45
  }
41
46
  }
42
47
 
@@ -25,9 +25,10 @@ class NewBinMarshall extends BaseMarshall {
25
25
  return
26
26
  }
27
27
 
28
- const targetVersionString = await this.packageRepoUtils.getSemVer(
28
+ const targetVersionString = await this.resolvePackageVersion(
29
29
  pkg.packageName,
30
- pkg.packageVersion
30
+ pkg.packageVersion,
31
+ fullPackageInfo
31
32
  )
32
33
 
33
34
  if (!targetVersionString || !fullPackageInfo.versions[targetVersionString]) {
@@ -22,6 +22,8 @@ class Marshall extends BaseMarshall {
22
22
  validate(pkg) {
23
23
  const validationMetadata = {}
24
24
 
25
+ // removed debug log
26
+
25
27
  return (
26
28
  this.packageRepoUtils
27
29
  .getPackageInfo(pkg.packageName)
@@ -16,40 +16,46 @@ class Marshall extends BaseMarshall {
16
16
  return 'Checking package for pre/post install scripts'
17
17
  }
18
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
- }
19
+ async validate(pkg) {
20
+ const data = await this.packageRepoUtils.getPackageInfo(pkg.packageName)
21
+
22
+ if (!data) {
23
+ return true
24
+ }
29
25
 
30
- const packageScripts =
31
- data &&
32
- data.versions &&
33
- data.versions[packageVersion] &&
34
- data.versions[packageVersion].scripts
35
-
36
- // blacklisted scripts due to possible malicious intent:
37
- const blacklistScripts = ['install', 'preinstall', 'postinstall']
38
-
39
- blacklistScripts.forEach((scriptName) => {
40
- if (
41
- packageScripts &&
42
- Object.prototype.hasOwnProperty.call(packageScripts, scriptName) &&
43
- packageScripts[scriptName].length > 0
44
- ) {
45
- throw new Error(
46
- `Detected a possible malicious intent script, audit required: ${scriptName}: ${packageScripts[scriptName]}`
47
- )
48
- }
49
- })
26
+ const packageVersion = await this.resolvePackageVersion(
27
+ pkg.packageName,
28
+ pkg.packageVersion,
29
+ data
30
+ )
50
31
 
32
+ if (!packageVersion) {
51
33
  return true
34
+ }
35
+
36
+ const packageScripts =
37
+ data &&
38
+ data.versions &&
39
+ data.versions[packageVersion] &&
40
+ data.versions[packageVersion].scripts
41
+
42
+ // blacklisted scripts due to possible malicious intent:
43
+ const blacklistScripts = ['install', 'preinstall', 'postinstall']
44
+
45
+ blacklistScripts.forEach((scriptName) => {
46
+ if (
47
+ packageScripts &&
48
+ packageScripts[scriptName] &&
49
+ String(packageScripts[scriptName]).length > 0
50
+ ) {
51
+ const scriptContent = packageScripts[scriptName]
52
+ throw new Error(
53
+ `Detected a possible malicious intent script, audit required: ${scriptName}: ${scriptContent}`
54
+ )
55
+ }
52
56
  })
57
+
58
+ return true
53
59
  }
54
60
  }
55
61
 
@@ -17,50 +17,45 @@ class Marshall extends BaseMarshall {
17
17
  return 'Checking version maturity'
18
18
  }
19
19
 
20
- validate(pkg) {
21
- let packageData = null
22
- return this.packageRepoUtils
23
- .getPackageInfo(pkg.packageName)
24
- .then((data) => {
25
- if (data && data.time) {
26
- packageData = data
27
- return pkg
28
- } else {
29
- throw new Error('Could not determine package version information')
30
- }
31
- })
32
- .then((pkg) => {
33
- return this.packageRepoUtils.getSemVer(pkg.packageName, pkg.packageVersion)
34
- })
35
- .then((versionResolved) => {
36
- const versionReleaseDate = packageData.time[versionResolved]
37
-
38
- if (!versionReleaseDate) {
39
- throw new Error(`Could not determine release date for version ${versionResolved}`)
40
- }
41
-
42
- const versionDateDiff = new Date() - new Date(versionReleaseDate)
43
- const versionDateDiffInDays = Math.round(versionDateDiff / (1000 * 60 * 60 * 24))
44
-
45
- if (versionDateDiffInDays < VERSION_AGE_THRESHOLD) {
46
- let timeAgoText = 'days'
47
- let timeAgoNumber = versionDateDiffInDays
48
-
49
- if (versionDateDiffInDays === 0) {
50
- timeAgoText = 'hours'
51
- const versionDateDiffInHours = Math.round(versionDateDiff / (1000 * 60 * 60))
52
- timeAgoNumber = versionDateDiffInHours
53
- } else if (versionDateDiffInDays === 1) {
54
- timeAgoText = 'day'
55
- }
56
-
57
- throw new Error(
58
- `Detected a recently published version (published ${timeAgoNumber} ${timeAgoText} ago) - consider waiting for community review`
59
- )
60
- }
61
-
62
- return pkg
63
- })
20
+ async validate(pkg) {
21
+ const data = await this.packageRepoUtils.getPackageInfo(pkg.packageName)
22
+
23
+ if (!data || !data.time) {
24
+ throw new Error('Could not determine package version information')
25
+ }
26
+
27
+ const packageVersion = await this.resolvePackageVersion(
28
+ pkg.packageName,
29
+ pkg.packageVersion,
30
+ data
31
+ )
32
+
33
+ if (!packageVersion || !Object.prototype.hasOwnProperty.call(data.time, packageVersion)) {
34
+ throw new Error(`Could not determine release date for version ${packageVersion}`)
35
+ }
36
+
37
+ const versionReleaseDate = data.time[packageVersion]
38
+ const versionDateDiff = new Date() - new Date(versionReleaseDate)
39
+ const versionDateDiffInDays = Math.round(versionDateDiff / (1000 * 60 * 60 * 24))
40
+
41
+ if (versionDateDiffInDays < VERSION_AGE_THRESHOLD) {
42
+ let timeAgoText = 'days'
43
+ let timeAgoNumber = versionDateDiffInDays
44
+
45
+ if (versionDateDiffInDays === 0) {
46
+ timeAgoText = 'hours'
47
+ const versionDateDiffInHours = Math.round(versionDateDiff / (1000 * 60 * 60))
48
+ timeAgoNumber = versionDateDiffInHours
49
+ } else if (versionDateDiffInDays === 1) {
50
+ timeAgoText = 'day'
51
+ }
52
+
53
+ throw new Error(
54
+ `Detected a recently published version (published ${timeAgoNumber} ${timeAgoText} ago) - consider waiting for community review`
55
+ )
56
+ }
57
+
58
+ return pkg
64
59
  }
65
60
  }
66
61
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "npq",
3
- "version": "3.11.3",
3
+ "version": "3.11.5",
4
4
  "description": "marshall your npm/npm package installs with high quality and class 🎖",
5
5
  "bin": {
6
6
  "npq": "./bin/npq.js",