pnpm-audit-hook 1.0.1 → 1.0.4
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 +369 -124
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
@@ -10,6 +10,204 @@ pnpm add -D pnpm-audit-hook && pnpm exec pnpm-audit-setup
|
|
|
10
10
|
|
|
11
11
|
Done! Every `pnpm install` will now audit packages before downloading.
|
|
12
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 |
|
|
210
|
+
|
|
13
211
|
## Installation
|
|
14
212
|
|
|
15
213
|
### Per-Project (Recommended)
|
|
@@ -108,30 +306,27 @@ performance:
|
|
|
108
306
|
|
|
109
307
|
cache:
|
|
110
308
|
ttlSeconds: 3600
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
All fields are optional. Set any source to `false` to disable it.
|
|
114
309
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
| Setting | Constraint | Default |
|
|
120
|
-
|---------|------------|---------|
|
|
121
|
-
| `performance.timeoutMs` | 1 to 300,000 ms (5 minutes max) | 15,000 |
|
|
122
|
-
| `cache.ttlSeconds` | 1 to 86,400 seconds (24 hours max) | 3,600 |
|
|
123
|
-
| `staticBaseline.cutoffDate` | Valid ISO date format, must not be in the future | 2025-12-31 |
|
|
124
|
-
|
|
125
|
-
Invalid values are silently replaced with defaults to ensure safe operation.
|
|
310
|
+
staticBaseline:
|
|
311
|
+
enabled: true
|
|
312
|
+
cutoffDate: "2025-12-31"
|
|
313
|
+
```
|
|
126
314
|
|
|
127
|
-
|
|
315
|
+
All fields are optional. Defaults are applied for missing values.
|
|
128
316
|
|
|
129
|
-
|
|
130
|
-
|--------|-------------|------|
|
|
131
|
-
| **GitHub Advisory** | Primary source - GitHub Security Advisory database (GHSA) | Optional |
|
|
132
|
-
| **NVD** | Severity enrichment only - NIST National Vulnerability Database | Optional |
|
|
317
|
+
### Configuration Options
|
|
133
318
|
|
|
134
|
-
|
|
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` |
|
|
135
330
|
|
|
136
331
|
## Allowlist
|
|
137
332
|
|
|
@@ -140,42 +335,78 @@ Suppress specific vulnerabilities or packages:
|
|
|
140
335
|
```yaml
|
|
141
336
|
policy:
|
|
142
337
|
allowlist:
|
|
338
|
+
# By CVE/GHSA ID
|
|
143
339
|
- id: CVE-2024-12345
|
|
144
340
|
reason: "False positive for our use case"
|
|
341
|
+
|
|
342
|
+
# By package name
|
|
145
343
|
- package: legacy-lib
|
|
146
344
|
reason: "Accepted risk"
|
|
147
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"
|
|
148
352
|
```
|
|
149
353
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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 |
|
|
155
361
|
|
|
156
362
|
## Environment Variables
|
|
157
363
|
|
|
158
364
|
| Variable | Description |
|
|
159
365
|
|----------|-------------|
|
|
160
|
-
| `
|
|
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 |
|
|
161
369
|
| `PNPM_AUDIT_DISABLE_GITHUB` | Disable GitHub Advisory source |
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
+
```
|
|
169
388
|
|
|
170
|
-
|
|
389
|
+
### Cache Location
|
|
390
|
+
|
|
391
|
+
```
|
|
392
|
+
.pnpm-audit-cache/
|
|
393
|
+
├── ab/
|
|
394
|
+
│ └── ab1234...def.json # Cached by SHA256 hash
|
|
395
|
+
├── cd/
|
|
396
|
+
│ └── cd5678...ghi.json
|
|
397
|
+
└── ...
|
|
398
|
+
```
|
|
171
399
|
|
|
172
|
-
|
|
173
|
-
2. `.pnpmfile.cjs` hook runs `afterAllResolved()` before downloads
|
|
174
|
-
3. The hook queries GitHub Advisory (and optionally NVD for severity enrichment)
|
|
175
|
-
4. Findings are deduplicated and checked against the severity policy
|
|
176
|
-
5. If any blocking vulnerabilities exist, pnpm aborts the install
|
|
400
|
+
### Dynamic TTL
|
|
177
401
|
|
|
178
|
-
|
|
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 |
|
|
179
410
|
|
|
180
411
|
## CI/CD Integration
|
|
181
412
|
|
|
@@ -207,61 +438,109 @@ The hook runs automatically during `pnpm install` and will fail the job if block
|
|
|
207
438
|
|
|
208
439
|
The hook includes a bundled database of historical vulnerabilities (2020-2025) that enables faster audits and reduced API calls.
|
|
209
440
|
|
|
210
|
-
### How It Works
|
|
211
|
-
|
|
212
|
-
- **Historical vulnerabilities** (before the cutoff date) are served from the bundled static database
|
|
213
|
-
- **New vulnerabilities** (after the cutoff date) are fetched from live APIs
|
|
214
|
-
- This hybrid approach provides offline capability for historical data while ensuring fresh data for recent disclosures
|
|
215
|
-
|
|
216
441
|
### Benefits
|
|
217
442
|
|
|
218
443
|
- **Faster audits**: No API calls needed for known historical vulnerabilities
|
|
219
|
-
- **
|
|
220
|
-
- **
|
|
221
|
-
- **
|
|
222
|
-
|
|
223
|
-
### Configuration
|
|
224
|
-
|
|
225
|
-
Enable or disable the static baseline in `.pnpm-audit.yaml`:
|
|
226
|
-
|
|
227
|
-
```yaml
|
|
228
|
-
staticBaseline:
|
|
229
|
-
enabled: true
|
|
230
|
-
cutoffDate: "2025-12-31"
|
|
231
|
-
dataPath: "node_modules/pnpm-audit-hook/dist/static-db/data" # optional custom path
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
- `enabled` - Whether to use the static database (default: `true`)
|
|
235
|
-
- `cutoffDate` - Vulnerabilities published before this date use the static database (must be valid ISO format, not in future)
|
|
236
|
-
- `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
|
|
237
447
|
|
|
238
448
|
### Updating the Database
|
|
239
449
|
|
|
240
|
-
Update the bundled vulnerability database monthly to capture new disclosures:
|
|
241
|
-
|
|
242
450
|
```bash
|
|
243
|
-
#
|
|
244
|
-
pnpm run update-vuln-db
|
|
245
|
-
|
|
246
|
-
# Incremental update (faster, adds only new vulnerabilities)
|
|
451
|
+
# Incremental update (recommended)
|
|
247
452
|
pnpm run update-vuln-db:incremental
|
|
248
|
-
```
|
|
249
453
|
|
|
250
|
-
|
|
454
|
+
# Full rebuild
|
|
455
|
+
pnpm run update-vuln-db
|
|
251
456
|
|
|
252
|
-
|
|
457
|
+
# Rebuild and commit
|
|
253
458
|
pnpm run build
|
|
254
459
|
git add src/static-db/data/ dist/static-db/data/
|
|
255
460
|
git commit -m "chore: update vulnerability database"
|
|
256
461
|
```
|
|
257
462
|
|
|
258
|
-
|
|
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
|
|
259
524
|
|
|
260
|
-
|
|
261
|
-
2. Optionally extend `cutoffDate` in your config to include newer static data
|
|
262
|
-
3. Commit the updated `data/` directory to your repository
|
|
525
|
+
The hook uses a **fail-closed** security model:
|
|
263
526
|
|
|
264
|
-
|
|
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
|
|
536
|
+
|
|
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
|
|
542
|
+
|
|
543
|
+
## Local Development
|
|
265
544
|
|
|
266
545
|
### Setup
|
|
267
546
|
|
|
@@ -272,29 +551,7 @@ pnpm install
|
|
|
272
551
|
pnpm run build
|
|
273
552
|
```
|
|
274
553
|
|
|
275
|
-
### Test
|
|
276
|
-
|
|
277
|
-
```bash
|
|
278
|
-
# In pnpm-audit-hook directory
|
|
279
|
-
pnpm link --global
|
|
280
|
-
|
|
281
|
-
# In your target project
|
|
282
|
-
pnpm link --global pnpm-audit-hook
|
|
283
|
-
|
|
284
|
-
# Copy the hook file to your project root
|
|
285
|
-
cp node_modules/pnpm-audit-hook/.pnpmfile.cjs .
|
|
286
|
-
|
|
287
|
-
# Edit .pnpmfile.cjs to point to linked package
|
|
288
|
-
# Change: path.join(__dirname, 'dist', 'index.js')
|
|
289
|
-
# To: path.join(__dirname, 'node_modules', 'pnpm-audit-hook', 'dist', 'index.js')
|
|
290
|
-
|
|
291
|
-
# Test it
|
|
292
|
-
pnpm add lodash
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### Test Directly in This Repo
|
|
296
|
-
|
|
297
|
-
The `.pnpmfile.cjs` already points to `./dist`, so you can test directly:
|
|
554
|
+
### Test Directly
|
|
298
555
|
|
|
299
556
|
```bash
|
|
300
557
|
pnpm run build
|
|
@@ -302,33 +559,21 @@ pnpm add lodash # Safe package
|
|
|
302
559
|
pnpm add event-stream@3.3.6 # Vulnerable - should be blocked
|
|
303
560
|
```
|
|
304
561
|
|
|
305
|
-
###
|
|
562
|
+
### Run Tests
|
|
306
563
|
|
|
307
564
|
```bash
|
|
308
|
-
# Make changes to src/
|
|
309
|
-
pnpm run build
|
|
310
|
-
|
|
311
|
-
# Run tests
|
|
312
565
|
pnpm test
|
|
313
|
-
|
|
314
|
-
# Test the hook manually
|
|
315
|
-
pnpm add some-package
|
|
316
566
|
```
|
|
317
567
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
```bash
|
|
321
|
-
# In your target project
|
|
322
|
-
pnpm unlink pnpm-audit-hook
|
|
323
|
-
rm .pnpmfile.cjs
|
|
568
|
+
## Exit Codes
|
|
324
569
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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) |
|
|
328
576
|
|
|
329
|
-
##
|
|
577
|
+
## License
|
|
330
578
|
|
|
331
|
-
|
|
332
|
-
pnpm install
|
|
333
|
-
pnpm run build
|
|
334
|
-
```
|
|
579
|
+
MIT
|
package/package.json
CHANGED