npq 3.10.1 → 3.11.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/package.json +27 -20
- package/.editorconfig +0 -49
- package/.github/ISSUE_TEMPLATE.md +0 -32
- package/.github/Logo Horizontal.png +0 -0
- package/.github/Logo Vertical.png +0 -0
- package/.github/Logo.png +0 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -35
- package/.github/npq-demo-1.gif +0 -0
- package/.github/npq-demo-1.png +0 -0
- package/.github/npq-demo.gif +0 -0
- package/.github/npq.mov +0 -0
- package/.github/npq.mp4 +0 -0
- package/.github/npq.png +0 -0
- package/.github/workflows/automerge.yml +0 -39
- package/.github/workflows/main.yml +0 -58
- package/.husky/commit-msg +0 -4
- package/.husky/post-merge +0 -4
- package/.husky/pre-commit +0 -4
- package/.husky/pre-push +0 -4
- package/.prettierrc.js +0 -9
- package/CHANGELOG.md +0 -27
- package/CODE_OF_CONDUCT.md +0 -73
- package/CONTRIBUTING.md +0 -55
- package/SECURITY.md +0 -23
- package/__tests__/__fixtures__/test.marshall.js +0 -58
- package/__tests__/cli.parser.test.js +0 -121
- package/__tests__/cli.test.js +0 -110
- package/__tests__/cliPrompt.test.js +0 -409
- package/__tests__/env-var-integration.test.js +0 -109
- package/__tests__/marshalls.base.test.js +0 -113
- package/__tests__/marshalls.classMethods.test.js +0 -34
- package/__tests__/marshalls.expiredDomains.test.js +0 -100
- package/__tests__/marshalls.newBin.test.js +0 -441
- package/__tests__/marshalls.provenance.test.js +0 -383
- package/__tests__/marshalls.repo.test.js +0 -126
- package/__tests__/marshalls.signatures.test.js +0 -132
- package/__tests__/marshalls.snyk.test.js +0 -294
- package/__tests__/marshalls.tasks.test.js +0 -130
- package/__tests__/marshalls.typosquatting.test.js +0 -76
- package/__tests__/marshalls.version-maturity.test.js +0 -194
- package/__tests__/mocks/registryPackageOk.mock.json +0 -146
- package/__tests__/mocks/registryPackageUnpublished.mock.json +0 -31
- package/__tests__/packageManager.test.js +0 -93
- package/__tests__/packageRepoUtils.test.js +0 -251
- package/__tests__/reportResults.test.js +0 -772
- package/__tests__/scripts.test.js +0 -146
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// __tests__/env-var-integration.test.js
|
|
2
|
-
|
|
3
|
-
// Test the NPQ_PKG_MGR environment variable functionality
|
|
4
|
-
// This tests the key logic change: process.env.NPQ_PKG_MGR || values.packageManager || values.pkgMgr || 'npm'
|
|
5
|
-
|
|
6
|
-
const packageManager = require('../lib/packageManager')
|
|
7
|
-
|
|
8
|
-
const childProcess = require('child_process')
|
|
9
|
-
|
|
10
|
-
jest.mock('child_process', () => {
|
|
11
|
-
return {
|
|
12
|
-
spawn: jest.fn((cmd, options) => {
|
|
13
|
-
return { pid: 12345 }
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
describe('NPQ_PKG_MGR Environment Variable Integration', () => {
|
|
19
|
-
let originalNPQ_PKG_MGR
|
|
20
|
-
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
originalNPQ_PKG_MGR = process.env.NPQ_PKG_MGR
|
|
23
|
-
delete process.env.NPQ_PKG_MGR
|
|
24
|
-
childProcess.spawn.mockClear()
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
afterEach(() => {
|
|
28
|
-
if (originalNPQ_PKG_MGR !== undefined) {
|
|
29
|
-
process.env.NPQ_PKG_MGR = originalNPQ_PKG_MGR
|
|
30
|
-
} else {
|
|
31
|
-
delete process.env.NPQ_PKG_MGR
|
|
32
|
-
}
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('package manager process should handle pnpm correctly', async () => {
|
|
36
|
-
process.argv = ['node', 'npq', 'install', 'fastify']
|
|
37
|
-
|
|
38
|
-
// Test that the package manager can spawn pnpm (which would be passed from CLI parsing)
|
|
39
|
-
await packageManager.process('pnpm')
|
|
40
|
-
|
|
41
|
-
expect(childProcess.spawn).toHaveBeenCalledWith('pnpm install fastify', {
|
|
42
|
-
stdio: 'inherit',
|
|
43
|
-
shell: true
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('package manager process should handle yarn correctly', async () => {
|
|
48
|
-
process.argv = ['node', 'npq', 'install', 'express', 'lodash']
|
|
49
|
-
|
|
50
|
-
await packageManager.process('yarn')
|
|
51
|
-
|
|
52
|
-
expect(childProcess.spawn).toHaveBeenCalledWith('yarn install express lodash', {
|
|
53
|
-
stdio: 'inherit',
|
|
54
|
-
shell: true
|
|
55
|
-
})
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('package manager process should handle various package managers', async () => {
|
|
59
|
-
const packageManagers = ['npm', 'yarn', 'pnpm', 'bun']
|
|
60
|
-
|
|
61
|
-
for (const pm of packageManagers) {
|
|
62
|
-
process.argv = ['node', 'npq', 'install', 'test-package']
|
|
63
|
-
|
|
64
|
-
await packageManager.process(pm)
|
|
65
|
-
|
|
66
|
-
expect(childProcess.spawn).toHaveBeenCalledWith(`${pm} install test-package`, {
|
|
67
|
-
stdio: 'inherit',
|
|
68
|
-
shell: true
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
childProcess.spawn.mockClear()
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test('should demonstrate NPQ_PKG_MGR environment variable precedence logic', () => {
|
|
76
|
-
// This test documents the specific logic that was implemented:
|
|
77
|
-
// packageManager: process.env.NPQ_PKG_MGR || values.packageManager || values.pkgMgr || 'npm'
|
|
78
|
-
|
|
79
|
-
// Test 1: Environment variable takes precedence
|
|
80
|
-
process.env.NPQ_PKG_MGR = 'pnpm'
|
|
81
|
-
const values1 = { packageManager: 'yarn', pkgMgr: 'npm' }
|
|
82
|
-
const result1 = process.env.NPQ_PKG_MGR || values1.packageManager || values1.pkgMgr || 'npm'
|
|
83
|
-
expect(result1).toBe('pnpm')
|
|
84
|
-
|
|
85
|
-
// Test 2: Falls back to packageManager when env var not set
|
|
86
|
-
delete process.env.NPQ_PKG_MGR
|
|
87
|
-
const values2 = { packageManager: 'yarn', pkgMgr: 'npm' }
|
|
88
|
-
const result2 = process.env.NPQ_PKG_MGR || values2.packageManager || values2.pkgMgr || 'npm'
|
|
89
|
-
expect(result2).toBe('yarn')
|
|
90
|
-
|
|
91
|
-
// Test 3: Falls back to pkgMgr when env var and packageManager not set
|
|
92
|
-
delete process.env.NPQ_PKG_MGR
|
|
93
|
-
const values3 = { pkgMgr: 'pnpm' }
|
|
94
|
-
const result3 = process.env.NPQ_PKG_MGR || values3.packageManager || values3.pkgMgr || 'npm'
|
|
95
|
-
expect(result3).toBe('pnpm')
|
|
96
|
-
|
|
97
|
-
// Test 4: Falls back to npm default when nothing is set
|
|
98
|
-
delete process.env.NPQ_PKG_MGR
|
|
99
|
-
const values4 = {}
|
|
100
|
-
const result4 = process.env.NPQ_PKG_MGR || values4.packageManager || values4.pkgMgr || 'npm'
|
|
101
|
-
expect(result4).toBe('npm')
|
|
102
|
-
|
|
103
|
-
// Test 5: Empty string environment variable falls back to CLI options
|
|
104
|
-
process.env.NPQ_PKG_MGR = ''
|
|
105
|
-
const values5 = { packageManager: 'yarn' }
|
|
106
|
-
const result5 = process.env.NPQ_PKG_MGR || values5.packageManager || values5.pkgMgr || 'npm'
|
|
107
|
-
expect(result5).toBe('yarn')
|
|
108
|
-
})
|
|
109
|
-
})
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
const TestMarshall = require('./__fixtures__/test.marshall')
|
|
2
|
-
const TEST_MARSHALL_NAME = 'test.marshall'
|
|
3
|
-
const BaseMarshall = require('../lib/marshalls/baseMarshall')
|
|
4
|
-
|
|
5
|
-
test('base marshall implemented isEnabled', async () => {
|
|
6
|
-
const testMarshall = new TestMarshall({
|
|
7
|
-
packageRepoUtils: null
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
expect(testMarshall.isEnabled()).toBeTruthy()
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
test('checkPackage returns validation data if it was a success', async () => {
|
|
14
|
-
const testMarshall = new TestMarshall({
|
|
15
|
-
packageRepoUtils: null
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
const ctx = {
|
|
19
|
-
marshalls: {
|
|
20
|
-
[TEST_MARSHALL_NAME]: {
|
|
21
|
-
data: {}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const result = await testMarshall.checkPackage({ packageName: 'express' }, ctx, {})
|
|
27
|
-
expect(result).toEqual('validation-result')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('checkPackage sets the error property if the validation failed', async () => {
|
|
31
|
-
const testMarshall = new TestMarshall({
|
|
32
|
-
packageRepoUtils: null
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const pkg = {
|
|
36
|
-
packageString: 'trojan'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const ctx = {
|
|
40
|
-
marshalls: {
|
|
41
|
-
[TEST_MARSHALL_NAME]: {
|
|
42
|
-
data: {}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
testMarshall.init(ctx)
|
|
48
|
-
await testMarshall.checkPackage(pkg, ctx, {})
|
|
49
|
-
expect(ctx.marshalls[TEST_MARSHALL_NAME].errors[0].pkg).toEqual(pkg.packageString)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('setError sets the errors properly', () => {
|
|
53
|
-
const testMarshall = new TestMarshall({
|
|
54
|
-
packageRepoUtils: null
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
const ctx = {
|
|
58
|
-
marshalls: {
|
|
59
|
-
[TEST_MARSHALL_NAME]: {
|
|
60
|
-
data: {}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const err = {
|
|
65
|
-
pkg: 'test',
|
|
66
|
-
message: 'error message'
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
testMarshall.init(ctx)
|
|
70
|
-
testMarshall.setMessage(err)
|
|
71
|
-
expect(ctx.marshalls[TEST_MARSHALL_NAME].errors.length).toEqual(1)
|
|
72
|
-
expect(ctx.marshalls[TEST_MARSHALL_NAME].errors[0]).toEqual(err)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test('setWarning sets the warnings properly', () => {
|
|
76
|
-
const testMarshall = new TestMarshall({
|
|
77
|
-
packageRepoUtils: null
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
const ctx = {
|
|
81
|
-
marshalls: {
|
|
82
|
-
[TEST_MARSHALL_NAME]: {
|
|
83
|
-
data: {}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
const warn = {
|
|
88
|
-
pkg: 'test',
|
|
89
|
-
message: 'warning message'
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
testMarshall.init(ctx)
|
|
93
|
-
|
|
94
|
-
testMarshall.setMessage(warn, true)
|
|
95
|
-
expect(ctx.marshalls[TEST_MARSHALL_NAME].warnings.length).toEqual(1)
|
|
96
|
-
expect(ctx.marshalls[TEST_MARSHALL_NAME].warnings[0]).toEqual(warn)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
test('base marshall implemented isEnabled', async () => {
|
|
100
|
-
const testMarshall = new BaseMarshall({
|
|
101
|
-
packageRepoUtils: null
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
testMarshall.validate = jest.fn(() => {
|
|
105
|
-
return Promise.reject(new Error('some mock error'))
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
const ctx = { pkgs: ['pkg1'], marshalls: {} }
|
|
109
|
-
const task = {}
|
|
110
|
-
testMarshall.init(ctx, task)
|
|
111
|
-
const result = await testMarshall.run(ctx, task)
|
|
112
|
-
expect(result).toStrictEqual([undefined])
|
|
113
|
-
})
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
beforeEach(() => {
|
|
2
|
-
jest.resetModules()
|
|
3
|
-
})
|
|
4
|
-
|
|
5
|
-
test('collecting marshalls resolves with files array', async () => {
|
|
6
|
-
const marshalls = require('../lib/marshalls')
|
|
7
|
-
|
|
8
|
-
const marshallFiles = await marshalls.collectMarshalls()
|
|
9
|
-
expect(marshallFiles.length).toBeGreaterThan(0)
|
|
10
|
-
expect(marshallFiles.every((file) => file.endsWith('.marshall.js'))).toBe(true)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
test('collecting marshalls handles directory read errors', async () => {
|
|
14
|
-
const fs = require('node:fs')
|
|
15
|
-
const marshalls = require('../lib/marshalls')
|
|
16
|
-
|
|
17
|
-
// Mock fs.promises.readdir to throw an error
|
|
18
|
-
const originalReaddir = fs.promises.readdir
|
|
19
|
-
fs.promises.readdir = jest.fn().mockRejectedValue(new Error('Directory read error'))
|
|
20
|
-
|
|
21
|
-
await expect(marshalls.collectMarshalls()).rejects.toThrow('Directory read error')
|
|
22
|
-
|
|
23
|
-
// Restore original function
|
|
24
|
-
fs.promises.readdir = originalReaddir
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
test('build marshalls without any should throw error', () => {
|
|
28
|
-
const marshalls = require('../lib/marshalls')
|
|
29
|
-
|
|
30
|
-
expect(marshalls.buildMarshallTasks([])).rejects.toEqual(expect.any(Error))
|
|
31
|
-
expect(marshalls.buildMarshallTasks({})).rejects.toEqual(expect.any(Error))
|
|
32
|
-
expect(marshalls.buildMarshallTasks(5)).rejects.toEqual(expect.any(Error))
|
|
33
|
-
expect(marshalls.buildMarshallTasks('something')).rejects.toEqual(expect.any(Error))
|
|
34
|
-
})
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
const ExpiredDomainsMarshall = require('../lib/marshalls/expiredDomains.marshall')
|
|
2
|
-
|
|
3
|
-
const testMarshall = new ExpiredDomainsMarshall({
|
|
4
|
-
packageRepoUtils: {
|
|
5
|
-
getPackageInfo: (pkgInfo) => {
|
|
6
|
-
return new Promise((resolve) => {
|
|
7
|
-
resolve(pkgInfo)
|
|
8
|
-
})
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
describe('Expired domains test suites', () => {
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
jest.clearAllMocks()
|
|
16
|
-
jest.resetAllMocks()
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('has the right title', async () => {
|
|
20
|
-
expect(testMarshall.title()).toEqual('Detecting expired domains for authors account...')
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('throws the right error when an email domain cant be verified', async () => {
|
|
24
|
-
const nonExistentEmailAddress =
|
|
25
|
-
'liran.tal+test1234@somenonexistentdomainongoogle109dubv98g39ujasdasda.com'
|
|
26
|
-
const pkgData = {
|
|
27
|
-
packageName: {
|
|
28
|
-
'dist-tags': {
|
|
29
|
-
latest: '1.0.0'
|
|
30
|
-
},
|
|
31
|
-
versions: {
|
|
32
|
-
'1.0.0': {
|
|
33
|
-
maintainers: [
|
|
34
|
-
{ name: 'lirantal', email: 'liran.tal@gmail.com' },
|
|
35
|
-
{
|
|
36
|
-
name: 'lirantal_test_user',
|
|
37
|
-
email: nonExistentEmailAddress
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
await expect(testMarshall.validate(pkgData)).rejects.toThrow(
|
|
46
|
-
/Detected expired domain can be abused for account takeover/
|
|
47
|
-
)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('if email hostname is empty then show an unknown message', async () => {
|
|
51
|
-
const nonExistentEmailAddress = ''
|
|
52
|
-
const pkgData = {
|
|
53
|
-
packageName: {
|
|
54
|
-
'dist-tags': {
|
|
55
|
-
latest: '1.0.0'
|
|
56
|
-
},
|
|
57
|
-
versions: {
|
|
58
|
-
'1.0.0': {
|
|
59
|
-
maintainers: [
|
|
60
|
-
{ name: 'lirantal', email: 'liran.tal@gmail.com' },
|
|
61
|
-
{
|
|
62
|
-
name: 'lirantal_test_user',
|
|
63
|
-
email: nonExistentEmailAddress
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
await expect(testMarshall.validate(pkgData)).rejects.toThrow(
|
|
72
|
-
/Detected expired domain can be abused for account takeover: <unknown>/
|
|
73
|
-
)
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('does not throw any errors if the domain resolves well', async () => {
|
|
77
|
-
jest.setTimeout(15000)
|
|
78
|
-
|
|
79
|
-
const pkgData = {
|
|
80
|
-
packageName: {
|
|
81
|
-
'dist-tags': {
|
|
82
|
-
latest: '1.0.0'
|
|
83
|
-
},
|
|
84
|
-
versions: {
|
|
85
|
-
'1.0.0': {
|
|
86
|
-
maintainers: [
|
|
87
|
-
{ name: 'lirantal', email: 'liran.tal@gmail.com' },
|
|
88
|
-
{
|
|
89
|
-
name: 'lirantal_test_user',
|
|
90
|
-
email: 'liran.tal@gmail.com'
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
await expect(testMarshall.validate(pkgData)).resolves.toEqual(expect.anything())
|
|
99
|
-
})
|
|
100
|
-
})
|