pompelmi 0.31.0 → 0.32.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/README.md +7 -1
- package/dist/pompelmi.cjs +90 -1
- package/dist/pompelmi.cjs.map +1 -1
- package/dist/pompelmi.esm.js +90 -1
- package/dist/pompelmi.esm.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/presets.d.ts +55 -2
- package/dist/types/types.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -287,11 +287,17 @@ Get secure file scanning running in under 5 minutes with pompelmi's zero-config
|
|
|
287
287
|
|
|
288
288
|
### Step 1: Create Security Policy
|
|
289
289
|
|
|
290
|
-
Create a reusable security policy and scanner configuration
|
|
290
|
+
Create a reusable security policy and scanner configuration.
|
|
291
|
+
|
|
292
|
+
> **`composeScanners` API** — two supported forms:
|
|
293
|
+
> - **Named-scanner array** *(recommended)*: `composeScanners([["name", scanner], ...], opts?)` — supports `parallel`, `stopOn`, `timeoutMsPerScanner`, and `tagSourceName` options.
|
|
294
|
+
> - **Variadic** *(backward-compatible)*: `composeScanners(scannerA, scannerB, ...)` — runs scanners sequentially, no options.
|
|
291
295
|
|
|
292
296
|
```ts
|
|
293
297
|
// lib/security.ts
|
|
294
298
|
import { CommonHeuristicsScanner, createZipBombGuard, composeScanners } from 'pompelmi';
|
|
299
|
+
// Optional: import types for explicit annotation
|
|
300
|
+
// import type { NamedScanner, ComposeScannerOptions } from 'pompelmi';
|
|
295
301
|
|
|
296
302
|
export const policy = {
|
|
297
303
|
includeExtensions: ['zip', 'png', 'jpg', 'jpeg', 'pdf', 'txt'],
|
package/dist/pompelmi.cjs
CHANGED
|
@@ -28,7 +28,96 @@ var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
|
28
28
|
function toScanFn(s) {
|
|
29
29
|
return (typeof s === "function" ? s : s.scan);
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
/** Map a Match's severity field to a Verdict for stopOn comparison. */
|
|
32
|
+
function matchToVerdict(m) {
|
|
33
|
+
const s = m.severity;
|
|
34
|
+
if (s === "critical" || s === "high" || s === "malicious")
|
|
35
|
+
return "malicious";
|
|
36
|
+
if (s === "medium" || s === "low" || s === "suspicious" || s === "info")
|
|
37
|
+
return "suspicious";
|
|
38
|
+
return "clean";
|
|
39
|
+
}
|
|
40
|
+
/** Highest verdict across all matches in the list. */
|
|
41
|
+
function highestSeverity(matches) {
|
|
42
|
+
if (matches.length === 0)
|
|
43
|
+
return null;
|
|
44
|
+
if (matches.some((m) => matchToVerdict(m) === "malicious"))
|
|
45
|
+
return "malicious";
|
|
46
|
+
if (matches.some((m) => matchToVerdict(m) === "suspicious"))
|
|
47
|
+
return "suspicious";
|
|
48
|
+
return "clean";
|
|
49
|
+
}
|
|
50
|
+
const SEVERITY_RANK = { malicious: 2, suspicious: 1, clean: 0 };
|
|
51
|
+
function shouldStop(matches, stopOn) {
|
|
52
|
+
if (!stopOn)
|
|
53
|
+
return false;
|
|
54
|
+
const highest = highestSeverity(matches);
|
|
55
|
+
if (!highest)
|
|
56
|
+
return false;
|
|
57
|
+
return SEVERITY_RANK[highest] >= SEVERITY_RANK[stopOn];
|
|
58
|
+
}
|
|
59
|
+
async function runWithTimeout(fn, timeoutMs) {
|
|
60
|
+
if (!timeoutMs)
|
|
61
|
+
return fn();
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const timer = setTimeout(() => reject(new Error("scanner timeout")), timeoutMs);
|
|
64
|
+
fn().then((v) => { clearTimeout(timer); resolve(v); }, (e) => { clearTimeout(timer); reject(e); });
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
function composeScanners(...args) {
|
|
69
|
+
const first = args[0];
|
|
70
|
+
const rest = args.slice(1);
|
|
71
|
+
// ── Named-scanner array form ──────────────────────────────────────────────
|
|
72
|
+
if (Array.isArray(first) &&
|
|
73
|
+
(first.length === 0 || (Array.isArray(first[0]) && typeof first[0][0] === "string"))) {
|
|
74
|
+
const entries = first;
|
|
75
|
+
const opts = rest.length > 0 && !Array.isArray(rest[0]) && typeof rest[0] !== "function" &&
|
|
76
|
+
!(typeof rest[0] === "object" && rest[0] !== null && "scan" in rest[0])
|
|
77
|
+
? rest[0]
|
|
78
|
+
: {};
|
|
79
|
+
return async (input, ctx) => {
|
|
80
|
+
const all = [];
|
|
81
|
+
if (opts.parallel) {
|
|
82
|
+
// Parallel execution — collect all results then return
|
|
83
|
+
const results = await Promise.allSettled(entries.map(([name, scanner]) => runWithTimeout(() => toScanFn(scanner)(input, ctx), opts.timeoutMsPerScanner)));
|
|
84
|
+
for (let i = 0; i < results.length; i++) {
|
|
85
|
+
const result = results[i];
|
|
86
|
+
if (result.status === "fulfilled" && Array.isArray(result.value)) {
|
|
87
|
+
const matches = opts.tagSourceName
|
|
88
|
+
? result.value.map((m) => ({
|
|
89
|
+
...m,
|
|
90
|
+
meta: { ...m.meta, _sourceName: entries[i][0] },
|
|
91
|
+
}))
|
|
92
|
+
: result.value;
|
|
93
|
+
all.push(...matches);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// Sequential execution with optional stopOn short-circuit
|
|
99
|
+
for (const [name, scanner] of entries) {
|
|
100
|
+
try {
|
|
101
|
+
const out = await runWithTimeout(() => toScanFn(scanner)(input, ctx), opts.timeoutMsPerScanner);
|
|
102
|
+
if (Array.isArray(out)) {
|
|
103
|
+
const matches = opts.tagSourceName
|
|
104
|
+
? out.map((m) => ({ ...m, meta: { ...m.meta, _sourceName: name } }))
|
|
105
|
+
: out;
|
|
106
|
+
all.push(...matches);
|
|
107
|
+
if (shouldStop(all, opts.stopOn))
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// individual scanner failure is non-fatal
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return all;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// ── Variadic form (backward-compatible) ───────────────────────────────────
|
|
120
|
+
const scanners = [first, ...rest].filter(Boolean);
|
|
32
121
|
return async (input, ctx) => {
|
|
33
122
|
const all = [];
|
|
34
123
|
for (const s of scanners) {
|