1
+ // This is just an example interface of mock data. You can change this to the
2
+ // type of your actual threat feed (or ideally use a good schema validation
3
+ // library to infer your types from).
4
+ interface ThreatFeedItem {
5
+ package : string ;
6
+ range : string ;
7
+ url : string | null ;
8
+ description : string | null ;
9
+ categories : Array < 'protestware' | 'adware' | 'backdoor' | 'malware' | 'botnet' > ;
10
+ }
11
+
12
+ async function fetchThreatFeed ( packages : Bun . Security . Package [ ] ) : Promise < ThreatFeedItem [ ] > {
13
+ // In a real provider you would probably replace this mock data with a
14
+ // fetch() to your threat feed, validating it with Zod or a similar library.
15
+
16
+ const myPretendThreatFeed : ThreatFeedItem [ ] = [
17
+ {
18
+ package : 'event-stream' ,
19
+ range : '>=3.3.6' , // You can use Bun.semver.satisfies to match this
20
+ url : 'https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident' ,
21
+ description : 'event-stream is a malicious package' ,
22
+ categories : [ 'malware' ] ,
23
+ } ,
24
+ ] ;
25
+
26
+ return myPretendThreatFeed . filter ( item => {
27
+ return packages . some (
28
+ p => p . name === item . package && Bun . semver . satisfies ( p . version , item . range )
29
+ ) ;
30
+ } ) ;
31
+ }
32
+
1
33
export const provider : Bun . Security . Provider = {
2
34
version : '1' ,
3
35
async scan ( { packages } ) {
4
- const response = await fetch ( 'https://api.example.com/scan' , {
5
- method : 'POST' ,
6
- body : JSON . stringify ( {
7
- packages : packages . map ( p => ( {
8
- name : p . name ,
9
- version : p . version ,
10
- } ) ) ,
11
- } ) ,
12
- headers : {
13
- 'Content-Type' : 'application/json' ,
14
- } ,
15
- } ) ;
16
-
17
- const json = await response . json ( ) ;
18
- validateThreatFeed ( json ) ;
36
+ const feed = await fetchThreatFeed ( packages ) ;
19
37
20
38
// Iterate over reported threats and return an array of advisories. This
21
39
// could be longer, shorter or equal length of the input packages array.
22
40
// Whatever you return will be shown to the user.
23
41
24
42
const results : Bun . Security . Advisory [ ] = [ ] ;
25
43
26
- for ( const item of json ) {
44
+ for ( const item of feed ) {
27
45
// Advisory levels control installation behavior:
28
46
// - All advisories are always shown to the user regardless of level
29
47
// - Fatal: Installation stops immediately (e.g., backdoors, botnets)
30
48
// - Warning: User prompted in TTY, auto-cancelled in non-TTY (e.g., protestware, adware)
31
49
32
- const isFatal = item . categories . includes ( 'backdoor' ) || item . categories . includes ( 'botnet' ) ;
50
+ const isFatal =
51
+ item . categories . includes ( 'malware' ) ||
52
+ item . categories . includes ( 'backdoor' ) ||
53
+ item . categories . includes ( 'botnet' ) ;
33
54
34
55
const isWarning =
35
56
item . categories . includes ( 'protestware' ) || item . categories . includes ( 'adware' ) ;
@@ -50,43 +71,3 @@ export const provider: Bun.Security.Provider = {
50
71
return results ;
51
72
} ,
52
73
} ;
53
-
54
- type ThreatFeedItemCategory =
55
- | 'protestware'
56
- | 'adware'
57
- | 'backdoor'
58
- | 'botnet' ; /* ...maybe you have some others */
59
-
60
- interface ThreatFeedItem {
61
- package : string ;
62
- version : string ;
63
- url : string | null ;
64
- description : string | null ;
65
- categories : Array < ThreatFeedItemCategory > ;
66
- }
67
-
68
- // You should really use a schema validation library like Zod here to validate
69
- // the feed. This code needs to be defensive rather than fast, so it's sensible
70
- // to check just to be sure.
71
- function validateThreatFeed ( json : unknown ) : asserts json is ThreatFeedItem [ ] {
72
- if ( ! Array . isArray ( json ) ) {
73
- throw new Error ( 'Invalid threat feed' ) ;
74
- }
75
-
76
- for ( const item of json ) {
77
- if (
78
- typeof item !== 'object' ||
79
- item === null ||
80
- ! ( 'package' in item ) ||
81
- ! ( 'version' in item ) ||
82
- ! ( 'url' in item ) ||
83
- ! ( 'description' in item ) ||
84
- typeof item . package !== 'string' ||
85
- typeof item . version !== 'string' ||
86
- ( typeof item . url !== 'string' && item . url !== null ) ||
87
- ( typeof item . description !== 'string' && item . description !== null )
88
- ) {
89
- throw new Error ( 'Invalid threat feed item' ) ;
90
- }
91
- }
92
- }
0 commit comments