@involvex/bun-scanner 1.0.0 → 2.0.1
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/FUNDING.yml +9 -0
- package/README.md +249 -64
- package/dist/index.js +4297 -0
- package/package.json +19 -3
- package/scanner.test.ts +108 -45
- package/src/index.ts +389 -59
- package/tsconfig.json +2 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@involvex/bun-scanner",
|
|
3
|
-
"description": "Bun security scanner ",
|
|
4
|
-
"version": "
|
|
3
|
+
"description": "Enhanced Bun security scanner with real-time vulnerability detection, automated dependency auditing, and AI-driven anomaly detection",
|
|
4
|
+
"version": "2.0.1",
|
|
5
5
|
"author": "involvex",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
@@ -15,11 +15,27 @@
|
|
|
15
15
|
"keywords": [
|
|
16
16
|
"bun",
|
|
17
17
|
"security",
|
|
18
|
-
"
|
|
18
|
+
"scanner",
|
|
19
|
+
"vulnerability",
|
|
20
|
+
"dependency",
|
|
21
|
+
"audit",
|
|
22
|
+
"threat",
|
|
23
|
+
"detection"
|
|
19
24
|
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "bun test",
|
|
27
|
+
"prebuild": "bunx prettier . --write && tsc --noEmit",
|
|
28
|
+
"build": "bun build src/index.ts --outdir dist"
|
|
29
|
+
},
|
|
20
30
|
"devDependencies": {
|
|
21
31
|
"@types/bun": "^1.3.5",
|
|
22
32
|
"prettier": "^3.7.4",
|
|
23
33
|
"typescript": "^5.9.3"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"zod": "^3.22.4",
|
|
37
|
+
"axios": "^1.6.2",
|
|
38
|
+
"lodash": "^4.17.21",
|
|
39
|
+
"semver": "^7.5.4"
|
|
24
40
|
}
|
|
25
41
|
}
|
package/scanner.test.ts
CHANGED
|
@@ -1,34 +1,24 @@
|
|
|
1
1
|
import {expect, test} from 'bun:test';
|
|
2
2
|
import {scanner} from './src/index.ts';
|
|
3
3
|
|
|
4
|
-
/////////////////////////////////////////////////////////////////////////////////////
|
|
5
|
-
// This test file is mostly just here to get you up and running quickly. It's
|
|
6
|
-
// likely you'd want to improve or remove this, and add more coverage for your
|
|
7
|
-
// own code.
|
|
8
|
-
/////////////////////////////////////////////////////////////////////////////////////
|
|
9
|
-
|
|
10
4
|
test('Scanner should warn about known malicious packages', async () => {
|
|
11
5
|
const advisories = await scanner.scan({
|
|
12
6
|
packages: [
|
|
13
7
|
{
|
|
14
8
|
name: 'event-stream',
|
|
15
|
-
version: '3.3.6',
|
|
9
|
+
version: '3.3.6',
|
|
16
10
|
requestedRange: '^3.3.0',
|
|
17
11
|
tarball: 'https://registry.npmjs.org/event-stream/-/event-stream-3.3.6.tgz',
|
|
12
|
+
license: 'MIT',
|
|
18
13
|
},
|
|
19
14
|
],
|
|
20
15
|
});
|
|
21
16
|
|
|
22
17
|
expect(advisories.length).toBeGreaterThan(0);
|
|
23
|
-
const advisory = advisories[0]!;
|
|
24
|
-
expect(advisory).toBeDefined();
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
url: expect.any(String),
|
|
30
|
-
description: expect.any(String),
|
|
31
|
-
});
|
|
19
|
+
const eventStreamAdvisory = advisories.find(a => a.package === 'event-stream');
|
|
20
|
+
expect(eventStreamAdvisory).toBeDefined();
|
|
21
|
+
expect(eventStreamAdvisory?.level).toBe('fatal');
|
|
32
22
|
});
|
|
33
23
|
|
|
34
24
|
test('There should be no advisories if no packages are being installed', async () => {
|
|
@@ -36,80 +26,153 @@ test('There should be no advisories if no packages are being installed', async (
|
|
|
36
26
|
expect(advisories.length).toBe(0);
|
|
37
27
|
});
|
|
38
28
|
|
|
39
|
-
test('
|
|
29
|
+
test('Should handle packages without specified licenses', async () => {
|
|
40
30
|
const advisories = await scanner.scan({
|
|
41
31
|
packages: [
|
|
42
32
|
{
|
|
43
|
-
name: '
|
|
44
|
-
version: '
|
|
45
|
-
requestedRange: '^
|
|
46
|
-
tarball: 'https://registry.npmjs.org/
|
|
33
|
+
name: 'unlicensed-package',
|
|
34
|
+
version: '1.0.0',
|
|
35
|
+
requestedRange: '^1.0.0',
|
|
36
|
+
tarball: 'https://registry.npmjs.org/unlicensed-package/-/unlicensed-package-1.0.0.tgz',
|
|
47
37
|
},
|
|
48
38
|
],
|
|
49
39
|
});
|
|
50
|
-
|
|
40
|
+
|
|
41
|
+
const licenseAdvisory = advisories.find(a =>
|
|
42
|
+
a.description?.includes('Package has no specified license'),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
expect(licenseAdvisory).toBeDefined();
|
|
46
|
+
expect(licenseAdvisory?.level).toBe('warn');
|
|
51
47
|
});
|
|
52
48
|
|
|
53
|
-
test('Should handle
|
|
49
|
+
test('Should handle scoped packages correctly', async () => {
|
|
54
50
|
const advisories = await scanner.scan({
|
|
55
51
|
packages: [
|
|
56
52
|
{
|
|
57
|
-
name: '
|
|
58
|
-
version: '
|
|
59
|
-
requestedRange: '^
|
|
60
|
-
tarball: 'https://registry.npmjs.org/
|
|
53
|
+
name: '@types/node',
|
|
54
|
+
version: '20.0.0',
|
|
55
|
+
requestedRange: '^20.0.0',
|
|
56
|
+
tarball: 'https://registry.npmjs.org/@types/node/-/node-20.0.0.tgz',
|
|
57
|
+
license: 'MIT',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const licenseAdvisories = advisories.filter(a =>
|
|
63
|
+
a.description?.includes('Package has no specified license'),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
expect(licenseAdvisories.length).toBe(0);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('Should detect vulnerabilities in lodash versions before 4.17.21', async () => {
|
|
70
|
+
const advisories = await scanner.scan({
|
|
71
|
+
packages: [
|
|
72
|
+
{
|
|
73
|
+
name: 'lodash',
|
|
74
|
+
version: '4.17.20',
|
|
75
|
+
requestedRange: '^4.17.0',
|
|
76
|
+
tarball: 'https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz',
|
|
77
|
+
license: 'MIT',
|
|
61
78
|
},
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const lodashAdvisory = advisories.find(a => a.package === 'lodash');
|
|
83
|
+
expect(lodashAdvisory).toBeDefined();
|
|
84
|
+
expect(lodashAdvisory?.level).toBe('warn');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('Should not detect vulnerabilities in lodash 4.17.21 or later', async () => {
|
|
88
|
+
const advisories = await scanner.scan({
|
|
89
|
+
packages: [
|
|
62
90
|
{
|
|
63
91
|
name: 'lodash',
|
|
64
|
-
version: '4.17.21',
|
|
92
|
+
version: '4.17.21',
|
|
65
93
|
requestedRange: '^4.17.0',
|
|
66
94
|
tarball: 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz',
|
|
95
|
+
license: 'MIT',
|
|
67
96
|
},
|
|
68
97
|
],
|
|
69
98
|
});
|
|
70
99
|
|
|
71
|
-
|
|
72
|
-
expect(
|
|
100
|
+
const lodashAdvisory = advisories.find(a => a.package === 'lodash');
|
|
101
|
+
expect(lodashAdvisory).toBeUndefined();
|
|
73
102
|
});
|
|
74
103
|
|
|
75
|
-
test('Should
|
|
76
|
-
const
|
|
104
|
+
test('Should prioritize critical vulnerabilities first', async () => {
|
|
105
|
+
const advisories = await scanner.scan({
|
|
77
106
|
packages: [
|
|
78
107
|
{
|
|
79
108
|
name: 'event-stream',
|
|
80
|
-
version: '3.3.6',
|
|
81
|
-
requestedRange: '3.3.
|
|
109
|
+
version: '3.3.6',
|
|
110
|
+
requestedRange: '^3.3.0',
|
|
82
111
|
tarball: 'https://registry.npmjs.org/event-stream/-/event-stream-3.3.6.tgz',
|
|
112
|
+
license: 'MIT',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'lodash',
|
|
116
|
+
version: '4.17.20',
|
|
117
|
+
requestedRange: '^4.17.0',
|
|
118
|
+
tarball: 'https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz',
|
|
119
|
+
license: 'MIT',
|
|
83
120
|
},
|
|
84
121
|
],
|
|
85
122
|
});
|
|
86
123
|
|
|
87
|
-
|
|
124
|
+
expect(advisories.length).toBeGreaterThan(1);
|
|
125
|
+
expect(advisories[0]?.level).toBe('fatal');
|
|
126
|
+
expect(advisories[0]?.package).toBe('event-stream');
|
|
127
|
+
expect(advisories[1]?.level).toBe('warn');
|
|
128
|
+
expect(advisories[1]?.package).toBe('lodash');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('Should return advisories with detailed information', async () => {
|
|
132
|
+
const advisories = await scanner.scan({
|
|
88
133
|
packages: [
|
|
89
134
|
{
|
|
90
135
|
name: 'event-stream',
|
|
91
|
-
version: '
|
|
92
|
-
requestedRange: '
|
|
93
|
-
tarball: 'https://registry.npmjs.org/event-stream/-/event-stream-
|
|
136
|
+
version: '3.3.6',
|
|
137
|
+
requestedRange: '^3.3.0',
|
|
138
|
+
tarball: 'https://registry.npmjs.org/event-stream/-/event-stream-3.3.6.tgz',
|
|
139
|
+
license: 'MIT',
|
|
94
140
|
},
|
|
95
141
|
],
|
|
96
142
|
});
|
|
97
143
|
|
|
98
|
-
|
|
99
|
-
expect(
|
|
144
|
+
const advisory = advisories[0];
|
|
145
|
+
expect(advisory).toBeDefined();
|
|
146
|
+
expect(advisory?.package).toBe('event-stream');
|
|
147
|
+
expect(advisory?.description).toBeDefined();
|
|
148
|
+
expect(advisory?.url).toBeDefined();
|
|
100
149
|
});
|
|
101
150
|
|
|
102
|
-
test('Should handle
|
|
151
|
+
test('Should handle multiple packages with mixed security status', async () => {
|
|
103
152
|
const advisories = await scanner.scan({
|
|
104
153
|
packages: [
|
|
105
154
|
{
|
|
106
|
-
name: '
|
|
107
|
-
version: '
|
|
108
|
-
requestedRange: '^
|
|
109
|
-
tarball: 'https://registry.npmjs.org
|
|
155
|
+
name: 'event-stream',
|
|
156
|
+
version: '3.3.6',
|
|
157
|
+
requestedRange: '^3.3.0',
|
|
158
|
+
tarball: 'https://registry.npmjs.org/event-stream/-/event-stream-3.3.6.tgz',
|
|
159
|
+
license: 'MIT',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'lodash',
|
|
163
|
+
version: '4.17.21',
|
|
164
|
+
requestedRange: '^4.17.0',
|
|
165
|
+
tarball: 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz',
|
|
166
|
+
license: 'MIT',
|
|
110
167
|
},
|
|
111
168
|
],
|
|
112
169
|
});
|
|
113
170
|
|
|
114
|
-
expect(advisories.length).
|
|
171
|
+
expect(advisories.length).toBeGreaterThan(0);
|
|
172
|
+
|
|
173
|
+
const eventStreamAdvisory = advisories.find(a => a.package === 'event-stream');
|
|
174
|
+
expect(eventStreamAdvisory).toBeDefined();
|
|
175
|
+
|
|
176
|
+
const lodashAdvisory = advisories.find(a => a.package === 'lodash');
|
|
177
|
+
expect(lodashAdvisory).toBeUndefined();
|
|
115
178
|
});
|