pnpm-audit-hook 1.0.0 → 1.0.2
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/README.md +408 -137
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,30 +1,234 @@
|
|
|
1
1
|
# pnpm-audit-hook
|
|
2
2
|
|
|
3
|
-
A pnpm hook that audits dependencies for vulnerabilities **before packages are downloaded**. It queries the GitHub Advisory Database
|
|
3
|
+
A pnpm hook that audits dependencies for vulnerabilities **before packages are downloaded**. It queries the GitHub Advisory Database and uses a bundled static vulnerability database, blocking installs when critical or high severity issues are found.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D pnpm-audit-hook && pnpm exec pnpm-audit-setup
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Done! Every `pnpm install` will now audit packages before downloading.
|
|
12
|
+
|
|
13
|
+
## How It Works
|
|
14
|
+
|
|
15
|
+
### Overview
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart LR
|
|
19
|
+
A[pnpm install] --> B[Resolve Dependencies]
|
|
20
|
+
B --> C[.pnpmfile.cjs Hook]
|
|
21
|
+
C --> D{Audit Packages}
|
|
22
|
+
D -->|Safe| E[Download & Install]
|
|
23
|
+
D -->|Vulnerable| F[Block Install]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
When you run `pnpm install`, the hook intercepts the process **after dependency resolution but before downloading**. This means vulnerable packages are blocked without ever being downloaded to your machine.
|
|
27
|
+
|
|
28
|
+
### Detailed Flow
|
|
29
|
+
|
|
30
|
+
```mermaid
|
|
31
|
+
flowchart TD
|
|
32
|
+
subgraph PNPM["pnpm install"]
|
|
33
|
+
A[Start] --> B[Resolve dependency graph]
|
|
34
|
+
B --> C[Generate lockfile]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
subgraph HOOK["pnpm-audit-hook"]
|
|
38
|
+
C --> D[".pnpmfile.cjs<br/>afterAllResolved()"]
|
|
39
|
+
D --> E[Extract packages from lockfile]
|
|
40
|
+
E --> F[Load config from .pnpm-audit.yaml]
|
|
41
|
+
F --> G{Check cache}
|
|
42
|
+
G -->|Cache hit| H[Use cached results]
|
|
43
|
+
G -->|Cache miss| I[Query vulnerability sources]
|
|
44
|
+
|
|
45
|
+
subgraph SOURCES["Vulnerability Sources"]
|
|
46
|
+
I --> J[Static DB<br/>Historical vulns]
|
|
47
|
+
I --> K[GitHub Advisory API<br/>Recent vulns]
|
|
48
|
+
J --> L[Merge & deduplicate]
|
|
49
|
+
K --> L
|
|
50
|
+
L --> M{Unknown severity?}
|
|
51
|
+
M -->|Yes| N[Enrich from NVD]
|
|
52
|
+
M -->|No| O[Continue]
|
|
53
|
+
N --> O
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
H --> P[Apply policy rules]
|
|
57
|
+
O --> P
|
|
58
|
+
P --> Q{Check allowlist}
|
|
59
|
+
Q -->|Allowed| R[Skip]
|
|
60
|
+
Q -->|Not allowed| S{Severity check}
|
|
61
|
+
S -->|critical/high| T[BLOCK]
|
|
62
|
+
S -->|medium/low| U[WARN]
|
|
63
|
+
S -->|unknown| U
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
subgraph RESULT["Result"]
|
|
67
|
+
T --> V[Throw error<br/>Abort install]
|
|
68
|
+
U --> W[Log warnings]
|
|
69
|
+
R --> W
|
|
70
|
+
W --> X[Continue install]
|
|
71
|
+
X --> Y[Download packages]
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Installation Changes
|
|
76
|
+
|
|
77
|
+
When you run `pnpm exec pnpm-audit-setup`, these files are created in your project:
|
|
78
|
+
|
|
79
|
+
| File | Purpose |
|
|
80
|
+
|------|---------|
|
|
81
|
+
| `.pnpmfile.cjs` | pnpm hook entry point - intercepts `pnpm install` |
|
|
82
|
+
| `.pnpm-audit.yaml` | Optional configuration file (created if missing) |
|
|
83
|
+
| `.pnpm-audit-cache/` | Cache directory (created automatically at runtime) |
|
|
84
|
+
|
|
85
|
+
### File Structure After Installation
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
your-project/
|
|
89
|
+
├── .pnpmfile.cjs # Hook that pnpm loads automatically
|
|
90
|
+
├── .pnpm-audit.yaml # Your security policy config (optional)
|
|
91
|
+
├── .pnpm-audit-cache/ # Cached vulnerability data (auto-created)
|
|
92
|
+
├── node_modules/
|
|
93
|
+
│ └── pnpm-audit-hook/ # The installed package
|
|
94
|
+
│ ├── dist/ # Compiled audit logic
|
|
95
|
+
│ └── .pnpmfile.cjs # Template hook file
|
|
96
|
+
├── package.json
|
|
97
|
+
└── pnpm-lock.yaml
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Vulnerability Sources
|
|
101
|
+
|
|
102
|
+
```mermaid
|
|
103
|
+
flowchart TD
|
|
104
|
+
subgraph PRIMARY["Primary Source"]
|
|
105
|
+
A[Static Database] --> C[Merged Results]
|
|
106
|
+
B[GitHub Advisory API] --> C
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
subgraph ENRICHMENT["Severity Enrichment"]
|
|
110
|
+
C --> D{Severity = unknown?}
|
|
111
|
+
D -->|Yes| E[Query NVD API]
|
|
112
|
+
D -->|No| F[Final Results]
|
|
113
|
+
E --> F
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
style A fill:#90EE90
|
|
117
|
+
style B fill:#87CEEB
|
|
118
|
+
style E fill:#FFE4B5
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Source | Type | Description | Rate Limits |
|
|
122
|
+
|--------|------|-------------|-------------|
|
|
123
|
+
| **Static DB** | Bundled | Historical vulnerabilities (2020-2025), works offline | None |
|
|
124
|
+
| **GitHub Advisory** | API | Real-time vulnerability data from GHSA | 60/hr (no token), 5000/hr (with token) |
|
|
125
|
+
| **NVD** | API | Severity enrichment only (CVSS scores) | 5/30s (no key), 50/30s (with key) |
|
|
126
|
+
|
|
127
|
+
### Query Strategy
|
|
128
|
+
|
|
129
|
+
```mermaid
|
|
130
|
+
sequenceDiagram
|
|
131
|
+
participant H as Hook
|
|
132
|
+
participant C as Cache
|
|
133
|
+
participant S as Static DB
|
|
134
|
+
participant G as GitHub API
|
|
135
|
+
participant N as NVD API
|
|
136
|
+
|
|
137
|
+
H->>C: Check cache for package@version
|
|
138
|
+
alt Cache hit (not expired)
|
|
139
|
+
C-->>H: Return cached vulnerabilities
|
|
140
|
+
else Cache miss
|
|
141
|
+
H->>S: Query historical vulns (before cutoff)
|
|
142
|
+
S-->>H: Historical findings
|
|
143
|
+
H->>G: Query recent vulns (after cutoff)
|
|
144
|
+
G-->>H: Recent findings
|
|
145
|
+
H->>H: Merge & deduplicate
|
|
146
|
+
|
|
147
|
+
opt Has unknown severity
|
|
148
|
+
H->>N: Enrich severity data
|
|
149
|
+
N-->>H: CVSS scores
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
H->>C: Cache results (TTL based on severity)
|
|
153
|
+
end
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Blocking Policy
|
|
157
|
+
|
|
158
|
+
### Default Policy
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
policy:
|
|
162
|
+
block: # Abort install if found
|
|
163
|
+
- critical
|
|
164
|
+
- high
|
|
165
|
+
warn: # Log warning but continue
|
|
166
|
+
- medium
|
|
167
|
+
- low
|
|
168
|
+
- unknown
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Policy Decision Flow
|
|
172
|
+
|
|
173
|
+
```mermaid
|
|
174
|
+
flowchart TD
|
|
175
|
+
A[Vulnerability Found] --> B{In allowlist?}
|
|
176
|
+
B -->|Yes, not expired| C[ALLOW - Skip]
|
|
177
|
+
B -->|No or expired| D{Severity level?}
|
|
178
|
+
|
|
179
|
+
D -->|critical| E[BLOCK]
|
|
180
|
+
D -->|high| E
|
|
181
|
+
D -->|medium| F[WARN]
|
|
182
|
+
D -->|low| F
|
|
183
|
+
D -->|unknown| F
|
|
184
|
+
|
|
185
|
+
E --> G[Collect all blocks]
|
|
186
|
+
F --> H[Collect all warnings]
|
|
187
|
+
C --> I[Continue]
|
|
188
|
+
|
|
189
|
+
G --> J{Any blocks?}
|
|
190
|
+
J -->|Yes| K[Throw Error<br/>Abort pnpm install]
|
|
191
|
+
J -->|No| L[Log warnings]
|
|
192
|
+
H --> L
|
|
193
|
+
L --> M[Continue install]
|
|
194
|
+
|
|
195
|
+
style E fill:#FF6B6B
|
|
196
|
+
style F fill:#FFE66D
|
|
197
|
+
style C fill:#90EE90
|
|
198
|
+
style K fill:#FF6B6B
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Severity Levels
|
|
202
|
+
|
|
203
|
+
| Severity | CVSS Score | Default Action | Example |
|
|
204
|
+
|----------|------------|----------------|---------|
|
|
205
|
+
| **critical** | 9.0 - 10.0 | Block | Remote code execution |
|
|
206
|
+
| **high** | 7.0 - 8.9 | Block | Authentication bypass |
|
|
207
|
+
| **medium** | 4.0 - 6.9 | Warn | Information disclosure |
|
|
208
|
+
| **low** | 0.1 - 3.9 | Warn | Minor information leak |
|
|
209
|
+
| **unknown** | N/A | Warn | Severity not determined |
|
|
4
210
|
|
|
5
211
|
## Installation
|
|
6
212
|
|
|
7
|
-
###
|
|
213
|
+
### Per-Project (Recommended)
|
|
8
214
|
|
|
9
215
|
```bash
|
|
10
|
-
# Install
|
|
216
|
+
# 1. Install
|
|
11
217
|
pnpm add -D pnpm-audit-hook
|
|
12
218
|
|
|
13
|
-
#
|
|
219
|
+
# 2. Setup (creates .pnpmfile.cjs in your project)
|
|
14
220
|
pnpm exec pnpm-audit-setup
|
|
15
221
|
```
|
|
16
222
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
### Global Setup (All Projects)
|
|
223
|
+
### Global (All Projects)
|
|
20
224
|
|
|
21
|
-
|
|
225
|
+
Enable vulnerability auditing for all pnpm projects on your machine:
|
|
22
226
|
|
|
23
227
|
```bash
|
|
24
228
|
# Install globally
|
|
25
229
|
pnpm add -g pnpm-audit-hook
|
|
26
230
|
|
|
27
|
-
# Create global hooks directory
|
|
231
|
+
# Create global hooks directory and copy files
|
|
28
232
|
mkdir -p ~/.pnpm-hooks
|
|
29
233
|
cp $(pnpm root -g)/pnpm-audit-hook/dist ~/.pnpm-hooks/ -r
|
|
30
234
|
cp $(pnpm root -g)/pnpm-audit-hook/.pnpmfile.cjs ~/.pnpm-hooks/
|
|
@@ -33,7 +237,7 @@ cp $(pnpm root -g)/pnpm-audit-hook/.pnpmfile.cjs ~/.pnpm-hooks/
|
|
|
33
237
|
pnpm config set global-pnpmfile ~/.pnpm-hooks/.pnpmfile.cjs
|
|
34
238
|
```
|
|
35
239
|
|
|
36
|
-
###
|
|
240
|
+
### From Source
|
|
37
241
|
|
|
38
242
|
```bash
|
|
39
243
|
git clone https://github.com/asx8678/pnpm-audit-hook.git
|
|
@@ -45,14 +249,34 @@ cp -r dist /path/to/your/project/
|
|
|
45
249
|
cp .pnpmfile.cjs /path/to/your/project/
|
|
46
250
|
```
|
|
47
251
|
|
|
48
|
-
##
|
|
252
|
+
## Verify Installation
|
|
49
253
|
|
|
50
254
|
```bash
|
|
51
|
-
|
|
52
|
-
pnpm add
|
|
255
|
+
# This should work (safe package)
|
|
256
|
+
pnpm add lodash
|
|
257
|
+
|
|
258
|
+
# This should be BLOCKED (known vulnerable)
|
|
259
|
+
pnpm add event-stream@3.3.6
|
|
53
260
|
```
|
|
54
261
|
|
|
55
|
-
If vulnerabilities are found, install fails before any packages are downloaded.
|
|
262
|
+
If vulnerabilities are found, the install fails **before** any packages are downloaded.
|
|
263
|
+
|
|
264
|
+
## Uninstall
|
|
265
|
+
|
|
266
|
+
### Per-Project
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
rm .pnpmfile.cjs
|
|
270
|
+
pnpm remove pnpm-audit-hook
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Global
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
pnpm config delete global-pnpmfile
|
|
277
|
+
rm -rf ~/.pnpm-hooks
|
|
278
|
+
pnpm remove -g pnpm-audit-hook
|
|
279
|
+
```
|
|
56
280
|
|
|
57
281
|
## Configuration
|
|
58
282
|
|
|
@@ -82,30 +306,27 @@ performance:
|
|
|
82
306
|
|
|
83
307
|
cache:
|
|
84
308
|
ttlSeconds: 3600
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
All fields are optional. Set any source to `false` to disable it.
|
|
88
|
-
|
|
89
|
-
### Configuration Constraints
|
|
90
|
-
|
|
91
|
-
The following validation rules are applied to configuration values:
|
|
92
|
-
|
|
93
|
-
| Setting | Constraint | Default |
|
|
94
|
-
|---------|------------|---------|
|
|
95
|
-
| `performance.timeoutMs` | 1 to 300,000 ms (5 minutes max) | 15,000 |
|
|
96
|
-
| `cache.ttlSeconds` | 1 to 86,400 seconds (24 hours max) | 3,600 |
|
|
97
|
-
| `staticBaseline.cutoffDate` | Valid ISO date format, must not be in the future | 2025-12-31 |
|
|
98
309
|
|
|
99
|
-
|
|
310
|
+
staticBaseline:
|
|
311
|
+
enabled: true
|
|
312
|
+
cutoffDate: "2025-12-31"
|
|
313
|
+
```
|
|
100
314
|
|
|
101
|
-
|
|
315
|
+
All fields are optional. Defaults are applied for missing values.
|
|
102
316
|
|
|
103
|
-
|
|
104
|
-
|--------|-------------|------|
|
|
105
|
-
| **GitHub Advisory** | Primary source - GitHub Security Advisory database (GHSA) | Optional |
|
|
106
|
-
| **NVD** | Severity enrichment only - NIST National Vulnerability Database | Optional |
|
|
317
|
+
### Configuration Options
|
|
107
318
|
|
|
108
|
-
|
|
319
|
+
| Option | Description | Default |
|
|
320
|
+
|--------|-------------|---------|
|
|
321
|
+
| `policy.block` | Severities that abort install | `["critical", "high"]` |
|
|
322
|
+
| `policy.warn` | Severities that log warnings | `["medium", "low", "unknown"]` |
|
|
323
|
+
| `policy.allowlist` | Exceptions to skip | `[]` |
|
|
324
|
+
| `sources.github` | Enable GitHub Advisory | `true` |
|
|
325
|
+
| `sources.nvd` | Enable NVD enrichment | `true` |
|
|
326
|
+
| `performance.timeoutMs` | API timeout (1-300,000) | `15000` |
|
|
327
|
+
| `cache.ttlSeconds` | Cache duration (1-86,400) | `3600` |
|
|
328
|
+
| `staticBaseline.enabled` | Use bundled vuln database | `true` |
|
|
329
|
+
| `staticBaseline.cutoffDate` | Static DB coverage date | `2025-12-31` |
|
|
109
330
|
|
|
110
331
|
## Allowlist
|
|
111
332
|
|
|
@@ -114,42 +335,78 @@ Suppress specific vulnerabilities or packages:
|
|
|
114
335
|
```yaml
|
|
115
336
|
policy:
|
|
116
337
|
allowlist:
|
|
338
|
+
# By CVE/GHSA ID
|
|
117
339
|
- id: CVE-2024-12345
|
|
118
340
|
reason: "False positive for our use case"
|
|
341
|
+
|
|
342
|
+
# By package name
|
|
119
343
|
- package: legacy-lib
|
|
120
344
|
reason: "Accepted risk"
|
|
121
345
|
expires: "2025-06-01"
|
|
346
|
+
|
|
347
|
+
# Scoped: specific CVE in specific package
|
|
348
|
+
- id: CVE-2024-12345
|
|
349
|
+
package: affected-pkg
|
|
350
|
+
version: ">=1.0.0 <2.0.0" # Optional version constraint
|
|
351
|
+
reason: "Only affects unused feature"
|
|
122
352
|
```
|
|
123
353
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
354
|
+
| Field | Required | Description |
|
|
355
|
+
|-------|----------|-------------|
|
|
356
|
+
| `id` | One of id/package | CVE or GHSA identifier (case-insensitive) |
|
|
357
|
+
| `package` | One of id/package | Package name to ignore (case-insensitive) |
|
|
358
|
+
| `version` | No | Semver range constraint |
|
|
359
|
+
| `reason` | No | Audit trail documentation |
|
|
360
|
+
| `expires` | No | ISO date when entry expires |
|
|
129
361
|
|
|
130
362
|
## Environment Variables
|
|
131
363
|
|
|
132
364
|
| Variable | Description |
|
|
133
365
|
|----------|-------------|
|
|
134
|
-
| `
|
|
366
|
+
| `GITHUB_TOKEN` / `GH_TOKEN` | GitHub API token (higher rate limits) |
|
|
367
|
+
| `NVD_API_KEY` / `NIST_NVD_API_KEY` | NVD API key (higher rate limits) |
|
|
368
|
+
| `PNPM_AUDIT_CONFIG_PATH` | Custom config file location |
|
|
135
369
|
| `PNPM_AUDIT_DISABLE_GITHUB` | Disable GitHub Advisory source |
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
370
|
+
| `PNPM_AUDIT_QUIET` | Suppress info/warn output |
|
|
371
|
+
| `PNPM_AUDIT_DEBUG` | Enable debug logging |
|
|
372
|
+
| `PNPM_AUDIT_JSON` | JSON output format |
|
|
373
|
+
|
|
374
|
+
## Caching
|
|
375
|
+
|
|
376
|
+
```mermaid
|
|
377
|
+
flowchart LR
|
|
378
|
+
A[Package Query] --> B{Cache exists?}
|
|
379
|
+
B -->|Yes| C{Expired?}
|
|
380
|
+
C -->|No| D[Return cached]
|
|
381
|
+
C -->|Yes| E[Query APIs]
|
|
382
|
+
B -->|No| E
|
|
383
|
+
E --> F[Cache with TTL]
|
|
384
|
+
F --> G[Return results]
|
|
385
|
+
|
|
386
|
+
style D fill:#90EE90
|
|
387
|
+
```
|
|
143
388
|
|
|
144
|
-
|
|
389
|
+
### Cache Location
|
|
145
390
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
391
|
+
```
|
|
392
|
+
.pnpm-audit-cache/
|
|
393
|
+
├── ab/
|
|
394
|
+
│ └── ab1234...def.json # Cached by SHA256 hash
|
|
395
|
+
├── cd/
|
|
396
|
+
│ └── cd5678...ghi.json
|
|
397
|
+
└── ...
|
|
398
|
+
```
|
|
151
399
|
|
|
152
|
-
|
|
400
|
+
### Dynamic TTL
|
|
401
|
+
|
|
402
|
+
Cache duration varies by severity to balance freshness and performance:
|
|
403
|
+
|
|
404
|
+
| Severity | TTL | Reason |
|
|
405
|
+
|----------|-----|--------|
|
|
406
|
+
| Critical | 15 min | Need fast response for active threats |
|
|
407
|
+
| High | 30 min | Important but less urgent |
|
|
408
|
+
| Medium | 1 hour | Standard caching |
|
|
409
|
+
| Low/Unknown | Config TTL | Use configured default |
|
|
153
410
|
|
|
154
411
|
## CI/CD Integration
|
|
155
412
|
|
|
@@ -181,61 +438,109 @@ The hook runs automatically during `pnpm install` and will fail the job if block
|
|
|
181
438
|
|
|
182
439
|
The hook includes a bundled database of historical vulnerabilities (2020-2025) that enables faster audits and reduced API calls.
|
|
183
440
|
|
|
184
|
-
### How It Works
|
|
185
|
-
|
|
186
|
-
- **Historical vulnerabilities** (before the cutoff date) are served from the bundled static database
|
|
187
|
-
- **New vulnerabilities** (after the cutoff date) are fetched from live APIs
|
|
188
|
-
- This hybrid approach provides offline capability for historical data while ensuring fresh data for recent disclosures
|
|
189
|
-
|
|
190
441
|
### Benefits
|
|
191
442
|
|
|
192
443
|
- **Faster audits**: No API calls needed for known historical vulnerabilities
|
|
193
|
-
- **
|
|
194
|
-
- **
|
|
195
|
-
- **
|
|
196
|
-
|
|
197
|
-
### Configuration
|
|
198
|
-
|
|
199
|
-
Enable or disable the static baseline in `.pnpm-audit.yaml`:
|
|
200
|
-
|
|
201
|
-
```yaml
|
|
202
|
-
staticBaseline:
|
|
203
|
-
enabled: true
|
|
204
|
-
cutoffDate: "2025-12-31"
|
|
205
|
-
dataPath: "node_modules/pnpm-audit-hook/dist/static-db/data" # optional custom path
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
- `enabled` - Whether to use the static database (default: `true`)
|
|
209
|
-
- `cutoffDate` - Vulnerabilities published before this date use the static database (must be valid ISO format, not in future)
|
|
210
|
-
- `dataPath` - Optional custom path to static data directory (default: bundled data)
|
|
444
|
+
- **Offline capability**: Historical vulnerability checks work without internet
|
|
445
|
+
- **Rate limit friendly**: Minimizes API usage
|
|
446
|
+
- **Reliable**: Not affected by API outages for historical data
|
|
211
447
|
|
|
212
448
|
### Updating the Database
|
|
213
449
|
|
|
214
|
-
Update the bundled vulnerability database monthly to capture new disclosures:
|
|
215
|
-
|
|
216
450
|
```bash
|
|
217
|
-
#
|
|
218
|
-
pnpm run update-vuln-db
|
|
219
|
-
|
|
220
|
-
# Incremental update (faster, adds only new vulnerabilities)
|
|
451
|
+
# Incremental update (recommended)
|
|
221
452
|
pnpm run update-vuln-db:incremental
|
|
222
|
-
```
|
|
223
453
|
|
|
224
|
-
|
|
454
|
+
# Full rebuild
|
|
455
|
+
pnpm run update-vuln-db
|
|
225
456
|
|
|
226
|
-
|
|
457
|
+
# Rebuild and commit
|
|
227
458
|
pnpm run build
|
|
228
459
|
git add src/static-db/data/ dist/static-db/data/
|
|
229
460
|
git commit -m "chore: update vulnerability database"
|
|
230
461
|
```
|
|
231
462
|
|
|
232
|
-
|
|
463
|
+
## Architecture
|
|
464
|
+
|
|
465
|
+
```mermaid
|
|
466
|
+
classDiagram
|
|
467
|
+
class PnpmHook {
|
|
468
|
+
+afterAllResolved(lockfile, context)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
class AuditEngine {
|
|
472
|
+
+runAudit(lockfile, runtime)
|
|
473
|
+
-extractPackages(lockfile)
|
|
474
|
+
-aggregateVulnerabilities(packages)
|
|
475
|
+
-evaluatePolicies(findings)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
class VulnerabilitySource {
|
|
479
|
+
<<interface>>
|
|
480
|
+
+query(packageName, version)
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
class StaticDatabase {
|
|
484
|
+
+query(packageName, version)
|
|
485
|
+
-loadShard(packageName)
|
|
486
|
+
-bloomFilter
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
class GitHubAdvisory {
|
|
490
|
+
+query(packageName, version)
|
|
491
|
+
-fetchFromAPI()
|
|
492
|
+
-rateLimiter
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
class NVDEnricher {
|
|
496
|
+
+enrichSeverity(findings)
|
|
497
|
+
-fetchCVSS(cveId)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
class PolicyEngine {
|
|
501
|
+
+evaluate(findings, config)
|
|
502
|
+
-checkAllowlist(finding)
|
|
503
|
+
-checkSeverity(finding)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
class FileCache {
|
|
507
|
+
+get(key)
|
|
508
|
+
+set(key, value, ttl)
|
|
509
|
+
+prune()
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
PnpmHook --> AuditEngine
|
|
513
|
+
AuditEngine --> VulnerabilitySource
|
|
514
|
+
AuditEngine --> PolicyEngine
|
|
515
|
+
AuditEngine --> FileCache
|
|
516
|
+
VulnerabilitySource <|.. StaticDatabase
|
|
517
|
+
VulnerabilitySource <|.. GitHubAdvisory
|
|
518
|
+
GitHubAdvisory --> NVDEnricher
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
## Security Model
|
|
522
|
+
|
|
523
|
+
### Fail-Closed Design
|
|
524
|
+
|
|
525
|
+
The hook uses a **fail-closed** security model:
|
|
526
|
+
|
|
527
|
+
| Condition | Behavior |
|
|
528
|
+
|-----------|----------|
|
|
529
|
+
| API failure | Block install (configurable) |
|
|
530
|
+
| Invalid allowlist entry | Entry ignored (treated as not allowed) |
|
|
531
|
+
| Expired allowlist | Entry ignored |
|
|
532
|
+
| Unknown severity | Treated as "warn" (configurable) |
|
|
533
|
+
| Invalid semver in vuln data | Treated as potentially affected |
|
|
534
|
+
|
|
535
|
+
### Security Features
|
|
233
536
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
537
|
+
- **Pre-download blocking**: Vulnerable code never reaches your machine
|
|
538
|
+
- **No credential storage**: API keys only from environment variables
|
|
539
|
+
- **Path traversal protection**: Validates all file paths
|
|
540
|
+
- **Symlink attack prevention**: Detects symlinks in cache
|
|
541
|
+
- **Atomic cache writes**: Prevents partial/corrupted cache files
|
|
237
542
|
|
|
238
|
-
## Local Development
|
|
543
|
+
## Local Development
|
|
239
544
|
|
|
240
545
|
### Setup
|
|
241
546
|
|
|
@@ -246,29 +551,7 @@ pnpm install
|
|
|
246
551
|
pnpm run build
|
|
247
552
|
```
|
|
248
553
|
|
|
249
|
-
### Test
|
|
250
|
-
|
|
251
|
-
```bash
|
|
252
|
-
# In pnpm-audit-hook directory
|
|
253
|
-
pnpm link --global
|
|
254
|
-
|
|
255
|
-
# In your target project
|
|
256
|
-
pnpm link --global pnpm-audit-hook
|
|
257
|
-
|
|
258
|
-
# Copy the hook file to your project root
|
|
259
|
-
cp node_modules/pnpm-audit-hook/.pnpmfile.cjs .
|
|
260
|
-
|
|
261
|
-
# Edit .pnpmfile.cjs to point to linked package
|
|
262
|
-
# Change: path.join(__dirname, 'dist', 'index.js')
|
|
263
|
-
# To: path.join(__dirname, 'node_modules', 'pnpm-audit-hook', 'dist', 'index.js')
|
|
264
|
-
|
|
265
|
-
# Test it
|
|
266
|
-
pnpm add lodash
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Test Directly in This Repo
|
|
270
|
-
|
|
271
|
-
The `.pnpmfile.cjs` already points to `./dist`, so you can test directly:
|
|
554
|
+
### Test Directly
|
|
272
555
|
|
|
273
556
|
```bash
|
|
274
557
|
pnpm run build
|
|
@@ -276,33 +559,21 @@ pnpm add lodash # Safe package
|
|
|
276
559
|
pnpm add event-stream@3.3.6 # Vulnerable - should be blocked
|
|
277
560
|
```
|
|
278
561
|
|
|
279
|
-
###
|
|
562
|
+
### Run Tests
|
|
280
563
|
|
|
281
564
|
```bash
|
|
282
|
-
# Make changes to src/
|
|
283
|
-
pnpm run build
|
|
284
|
-
|
|
285
|
-
# Run tests
|
|
286
565
|
pnpm test
|
|
287
|
-
|
|
288
|
-
# Test the hook manually
|
|
289
|
-
pnpm add some-package
|
|
290
566
|
```
|
|
291
567
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
# In your target project
|
|
296
|
-
pnpm unlink pnpm-audit-hook
|
|
297
|
-
rm .pnpmfile.cjs
|
|
568
|
+
## Exit Codes
|
|
298
569
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
570
|
+
| Code | Meaning |
|
|
571
|
+
|------|---------|
|
|
572
|
+
| 0 | Success - no blocking vulnerabilities |
|
|
573
|
+
| 1 | Blocked - critical/high vulnerabilities found |
|
|
574
|
+
| 2 | Warnings - medium/low vulnerabilities found |
|
|
575
|
+
| 3 | Source error - API failure (fail-closed) |
|
|
302
576
|
|
|
303
|
-
##
|
|
577
|
+
## License
|
|
304
578
|
|
|
305
|
-
|
|
306
|
-
pnpm install
|
|
307
|
-
pnpm run build
|
|
308
|
-
```
|
|
579
|
+
MIT
|
package/package.json
CHANGED