pompelmi 0.35.5 → 1.1.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.
Files changed (135) hide show
  1. package/.claude/settings.local.json +45 -0
  2. package/LICENSE +12 -18
  3. package/README.md +174 -181
  4. package/eslint.config.mjs +8 -0
  5. package/package.json +26 -251
  6. package/src/ClamAVDatabaseUpdater.js +48 -0
  7. package/src/ClamAVInstaller.js +49 -0
  8. package/src/ClamAVScanner.js +37 -0
  9. package/src/ClamdScanner.js +81 -0
  10. package/src/InstallerCommand.js +11 -0
  11. package/src/config.js +22 -0
  12. package/src/constants.js +3 -0
  13. package/src/favicon.ico +0 -0
  14. package/src/grapefruit.png +0 -0
  15. package/src/index.js +5 -0
  16. package/test_out.txt +74 -0
  17. package/CHANGELOG.md +0 -71
  18. package/dist/pompelmi.audit.cjs +0 -128
  19. package/dist/pompelmi.audit.cjs.map +0 -1
  20. package/dist/pompelmi.audit.esm.js +0 -107
  21. package/dist/pompelmi.audit.esm.js.map +0 -1
  22. package/dist/pompelmi.browser.cjs +0 -1549
  23. package/dist/pompelmi.browser.cjs.map +0 -1
  24. package/dist/pompelmi.browser.esm.js +0 -1523
  25. package/dist/pompelmi.browser.esm.js.map +0 -1
  26. package/dist/pompelmi.cjs +0 -2591
  27. package/dist/pompelmi.cjs.map +0 -1
  28. package/dist/pompelmi.esm.js +0 -2525
  29. package/dist/pompelmi.esm.js.map +0 -1
  30. package/dist/pompelmi.hooks.cjs +0 -75
  31. package/dist/pompelmi.hooks.cjs.map +0 -1
  32. package/dist/pompelmi.hooks.esm.js +0 -72
  33. package/dist/pompelmi.hooks.esm.js.map +0 -1
  34. package/dist/pompelmi.policy-packs.cjs +0 -240
  35. package/dist/pompelmi.policy-packs.cjs.map +0 -1
  36. package/dist/pompelmi.policy-packs.esm.js +0 -232
  37. package/dist/pompelmi.policy-packs.esm.js.map +0 -1
  38. package/dist/pompelmi.quarantine.cjs +0 -317
  39. package/dist/pompelmi.quarantine.cjs.map +0 -1
  40. package/dist/pompelmi.quarantine.esm.js +0 -293
  41. package/dist/pompelmi.quarantine.esm.js.map +0 -1
  42. package/dist/pompelmi.react.cjs +0 -1580
  43. package/dist/pompelmi.react.cjs.map +0 -1
  44. package/dist/pompelmi.react.esm.js +0 -1553
  45. package/dist/pompelmi.react.esm.js.map +0 -1
  46. package/dist/types/audit.d.ts +0 -84
  47. package/dist/types/browser-index.d.ts +0 -29
  48. package/dist/types/config.d.ts +0 -143
  49. package/dist/types/engines/dynamic-taint.d.ts +0 -102
  50. package/dist/types/engines/hybrid-orchestrator.d.ts +0 -65
  51. package/dist/types/engines/hybrid-taint-integration.d.ts +0 -129
  52. package/dist/types/engines/taint-policies.d.ts +0 -84
  53. package/dist/types/hipaa-compliance.d.ts +0 -110
  54. package/dist/types/hooks.d.ts +0 -89
  55. package/dist/types/index.d.ts +0 -29
  56. package/dist/types/magic.d.ts +0 -7
  57. package/dist/types/node/scanDir.d.ts +0 -30
  58. package/dist/types/policy-packs.d.ts +0 -98
  59. package/dist/types/policy.d.ts +0 -12
  60. package/dist/types/presets.d.ts +0 -72
  61. package/dist/types/quarantine/index.d.ts +0 -18
  62. package/dist/types/quarantine/storage.d.ts +0 -77
  63. package/dist/types/quarantine/types.d.ts +0 -78
  64. package/dist/types/quarantine/workflow.d.ts +0 -97
  65. package/dist/types/react-index.d.ts +0 -13
  66. package/dist/types/risk.d.ts +0 -18
  67. package/dist/types/scan/remote.d.ts +0 -12
  68. package/dist/types/scan.d.ts +0 -17
  69. package/dist/types/scanners/common-heuristics.d.ts +0 -14
  70. package/dist/types/scanners/zip-bomb-guard.d.ts +0 -9
  71. package/dist/types/scanners/zipTraversalGuard.d.ts +0 -19
  72. package/dist/types/src/audit.d.ts +0 -84
  73. package/dist/types/src/browser-index.d.ts +0 -29
  74. package/dist/types/src/config.d.ts +0 -143
  75. package/dist/types/src/engines/dynamic-taint.d.ts +0 -102
  76. package/dist/types/src/engines/hybrid-orchestrator.d.ts +0 -65
  77. package/dist/types/src/engines/hybrid-taint-integration.d.ts +0 -129
  78. package/dist/types/src/engines/taint-policies.d.ts +0 -84
  79. package/dist/types/src/hipaa-compliance.d.ts +0 -110
  80. package/dist/types/src/hooks.d.ts +0 -89
  81. package/dist/types/src/index.d.ts +0 -29
  82. package/dist/types/src/magic.d.ts +0 -7
  83. package/dist/types/src/node/scanDir.d.ts +0 -30
  84. package/dist/types/src/policy-packs.d.ts +0 -98
  85. package/dist/types/src/policy.d.ts +0 -12
  86. package/dist/types/src/presets.d.ts +0 -72
  87. package/dist/types/src/quarantine/index.d.ts +0 -18
  88. package/dist/types/src/quarantine/storage.d.ts +0 -77
  89. package/dist/types/src/quarantine/types.d.ts +0 -78
  90. package/dist/types/src/quarantine/workflow.d.ts +0 -97
  91. package/dist/types/src/react-index.d.ts +0 -13
  92. package/dist/types/src/risk.d.ts +0 -18
  93. package/dist/types/src/scan/remote.d.ts +0 -12
  94. package/dist/types/src/scan.d.ts +0 -17
  95. package/dist/types/src/scanners/common-heuristics.d.ts +0 -14
  96. package/dist/types/src/scanners/zip-bomb-guard.d.ts +0 -11
  97. package/dist/types/src/scanners/zipTraversalGuard.d.ts +0 -19
  98. package/dist/types/src/stream.d.ts +0 -10
  99. package/dist/types/src/types/decompilation.d.ts +0 -96
  100. package/dist/types/src/types/taint-tracking.d.ts +0 -495
  101. package/dist/types/src/types.d.ts +0 -48
  102. package/dist/types/src/useFileScanner.d.ts +0 -15
  103. package/dist/types/src/utils/advanced-detection.d.ts +0 -21
  104. package/dist/types/src/utils/batch-scanner.d.ts +0 -62
  105. package/dist/types/src/utils/cache-manager.d.ts +0 -95
  106. package/dist/types/src/utils/export.d.ts +0 -51
  107. package/dist/types/src/utils/performance-metrics.d.ts +0 -68
  108. package/dist/types/src/utils/threat-intelligence.d.ts +0 -96
  109. package/dist/types/src/validate.d.ts +0 -7
  110. package/dist/types/src/verdict.d.ts +0 -2
  111. package/dist/types/src/yara/browser.d.ts +0 -7
  112. package/dist/types/src/yara/index.d.ts +0 -17
  113. package/dist/types/src/yara/node.d.ts +0 -2
  114. package/dist/types/src/yara/remote.d.ts +0 -10
  115. package/dist/types/src/yara-bridge.d.ts +0 -3
  116. package/dist/types/src/zip.d.ts +0 -13
  117. package/dist/types/stream.d.ts +0 -10
  118. package/dist/types/types/decompilation.d.ts +0 -96
  119. package/dist/types/types/taint-tracking.d.ts +0 -495
  120. package/dist/types/types.d.ts +0 -48
  121. package/dist/types/useFileScanner.d.ts +0 -15
  122. package/dist/types/utils/advanced-detection.d.ts +0 -21
  123. package/dist/types/utils/batch-scanner.d.ts +0 -62
  124. package/dist/types/utils/cache-manager.d.ts +0 -95
  125. package/dist/types/utils/export.d.ts +0 -51
  126. package/dist/types/utils/performance-metrics.d.ts +0 -68
  127. package/dist/types/utils/threat-intelligence.d.ts +0 -96
  128. package/dist/types/validate.d.ts +0 -7
  129. package/dist/types/verdict.d.ts +0 -2
  130. package/dist/types/yara/browser.d.ts +0 -7
  131. package/dist/types/yara/index.d.ts +0 -17
  132. package/dist/types/yara/node.d.ts +0 -2
  133. package/dist/types/yara/remote.d.ts +0 -10
  134. package/dist/types/yara-bridge.d.ts +0 -3
  135. package/dist/types/zip.d.ts +0 -13
package/CHANGELOG.md DELETED
@@ -1,71 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## Unreleased (main)
9
-
10
- ### Highlights
11
-
12
- - Fixed `@pompelmi/fastify-plugin` multipart dependency wiring and removed an unnecessary promise hop.
13
- - Refined the root README layout for faster first-run onboarding and clearer repo entry points.
14
- - Refreshed README badges and demo media so the public repo surface is easier to scan quickly.
15
- - Added verified mention badges to strengthen the top-level trust signals around adoption.
16
- - Tightened onboarding copy across the repo surfaces to make the docs-and-examples path easier to follow.
17
-
18
- ### Notes
19
-
20
- This section summarizes changes since the last tag: `v0.34.8`.
21
- Post-tag activity is currently limited, so the highlights above also surface the most recent user-visible commits from the current `v0.34.x` line for context.
22
- For full details, see GitHub Releases / tag diffs.
23
-
24
- ## [0.27.1] - 2026-01-26
25
-
26
- ### Security
27
- - 🔐 **Critical Security Fixes**: Fixed 89 vulnerabilities (6 critical, 36 high, 35 moderate, 12 low)
28
- - 🔐 **Dependency Updates**: Updated 26 package overrides including esbuild, vite, astro, next, body-parser, qs, lodash
29
- - 🔐 **CVE Fixes**: Patched multiple CVEs in dependencies
30
-
31
- ### Fixed
32
- - 🐛 Fixed GitHub Actions workflow with correct pnpm/action-setup SHA
33
- - 🐛 Resolved CI/CD pipeline execution errors
34
-
35
- ## [0.27.0] - 2026-01-26
36
-
37
- ### Added
38
- - 🚀 **Enhanced Performance Monitoring**: Added detailed performance metrics tracking for scan operations
39
- - 🔒 **Advanced Threat Detection**: Improved heuristics engine with better polyglot file detection
40
- - 📊 **Scan Statistics API**: New utility functions to aggregate and analyze scan results
41
- - 🛡️ **Enhanced ZIP Bomb Protection**: Improved nested archive detection with configurable depth limits
42
- - 🔍 **Content Analysis**: Advanced content inspection for embedded scripts and obfuscated code
43
- - 📝 **Better TypeScript Types**: Enhanced type definitions for improved developer experience
44
- - ⚡ **Async Performance**: Optimized async operations for better throughput
45
- - 🎯 **Scan Context Enrichment**: Enhanced metadata collection during file scanning
46
-
47
- ### Improved
48
- - 🔧 **Error Handling**: More descriptive error messages with actionable suggestions
49
- - 📈 **Memory Efficiency**: Reduced memory footprint for large file operations
50
- - 🚦 **CI/CD Pipeline**: Enhanced GitHub Actions workflows with better caching
51
- - 📚 **Documentation**: Updated examples and API documentation
52
- - 🧪 **Test Coverage**: Added comprehensive test cases for new features
53
-
54
- ### Fixed
55
- - 🐛 Fixed edge cases in MIME type detection
56
- - 🐛 Resolved memory leaks in stream processing
57
- - 🐛 Corrected verdict mapping for multi-threaded scenarios
58
-
59
- ### Security
60
- - 🔐 Updated dependencies to patch known vulnerabilities
61
- - 🔐 Enhanced input validation for all public APIs
62
- - 🔐 Improved sanitization for file metadata
63
-
64
- ## [0.26.0] - 2025-12-15
65
-
66
- ### Added
67
- - Initial stable release with core scanning functionality
68
- - YARA integration support
69
- - ZIP bomb protection
70
- - Framework adapters (Express, Koa, Fastify, Next.js)
71
- - Browser and Node.js support
@@ -1,128 +0,0 @@
1
- 'use strict';
2
-
3
- var fs = require('fs');
4
-
5
- function _interopNamespaceDefault(e) {
6
- var n = Object.create(null);
7
- if (e) {
8
- Object.keys(e).forEach(function (k) {
9
- if (k !== 'default') {
10
- var d = Object.getOwnPropertyDescriptor(e, k);
11
- Object.defineProperty(n, k, d.get ? d : {
12
- enumerable: true,
13
- get: function () { return e[k]; }
14
- });
15
- }
16
- });
17
- }
18
- n.default = e;
19
- return Object.freeze(n);
20
- }
21
-
22
- var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
23
-
24
- /**
25
- * Audit trail for Pompelmi scan and quarantine events.
26
- *
27
- * Produces structured, append-only audit records suitable for:
28
- * - compliance logging (HIPAA, SOC 2, ISO 27001)
29
- * - SIEM ingestion
30
- * - operational dashboards
31
- * - incident response
32
- *
33
- * Usage:
34
- * ```ts
35
- * import { AuditTrail } from 'pompelmi/audit';
36
- *
37
- * const audit = new AuditTrail({ dest: 'file', path: './audit.jsonl' });
38
- * audit.logScanComplete({ filename: 'upload.zip', verdict: 'suspicious', ... });
39
- * audit.logQuarantine({ entryId: '...', sha256: '...', ... });
40
- * ```
41
- *
42
- * @module audit
43
- */
44
- // ── AuditTrail ────────────────────────────────────────────────────────────────
45
- class AuditTrail {
46
- constructor(options = {}) {
47
- this.options = {
48
- output: options.output ?? { dest: "console" },
49
- pretty: options.pretty ?? false,
50
- };
51
- }
52
- /** Log a completed scan. */
53
- logScanComplete(report, extra) {
54
- const record = {
55
- timestamp: new Date().toISOString(),
56
- event: report.verdict !== "clean" ? "threat.detected" : "scan.complete",
57
- verdict: report.verdict,
58
- matchCount: report.matches?.length ?? 0,
59
- durationMs: report.durationMs,
60
- engine: report.engine,
61
- mimeType: report.file?.mimeType,
62
- ...extra,
63
- };
64
- void this.write(record);
65
- }
66
- /** Log a scan error. */
67
- logScanError(error, extra) {
68
- const record = {
69
- timestamp: new Date().toISOString(),
70
- event: "scan.error",
71
- verdict: "clean", // unknown at this point
72
- matchCount: 0,
73
- error: error instanceof Error ? error.message : String(error),
74
- ...extra,
75
- };
76
- void this.write(record);
77
- }
78
- /** Log a new quarantine entry. */
79
- logQuarantine(entry, correlationId) {
80
- const record = {
81
- timestamp: new Date().toISOString(),
82
- event: "quarantine.created",
83
- quarantineId: entry.id,
84
- filename: entry.file.originalName,
85
- sha256: entry.file.sha256,
86
- uploadedBy: entry.file.uploadedBy,
87
- correlationId,
88
- };
89
- void this.write(record);
90
- }
91
- /** Log a quarantine resolution (promote or delete). */
92
- logQuarantineResolved(entry, correlationId) {
93
- const record = {
94
- timestamp: new Date().toISOString(),
95
- event: entry.status === "deleted" ? "quarantine.deleted" : "quarantine.resolved",
96
- quarantineId: entry.id,
97
- filename: entry.file.originalName,
98
- sha256: entry.file.sha256,
99
- decision: entry.status === "promoted" ? "promote" : "delete",
100
- reviewedBy: entry.reviewedBy,
101
- reviewNote: entry.reviewNote,
102
- correlationId,
103
- };
104
- void this.write(record);
105
- }
106
- async write(record) {
107
- const line = this.options.pretty ? JSON.stringify(record, null, 2) : JSON.stringify(record);
108
- const { output } = this.options;
109
- try {
110
- if (output.dest === "console") {
111
- process.stdout.write(line + "\n");
112
- }
113
- else if (output.dest === "file") {
114
- // Append a newline-delimited JSON (NDJSON) record.
115
- await fs__namespace.promises.appendFile(output.path, line + "\n", "utf8");
116
- }
117
- else if (output.dest === "custom") {
118
- await output.write(record);
119
- }
120
- }
121
- catch {
122
- // Audit failures must never interrupt the upload pipeline.
123
- }
124
- }
125
- }
126
-
127
- exports.AuditTrail = AuditTrail;
128
- //# sourceMappingURL=pompelmi.audit.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pompelmi.audit.cjs","sources":["../../src/audit.ts"],"sourcesContent":["/**\n * Audit trail for Pompelmi scan and quarantine events.\n *\n * Produces structured, append-only audit records suitable for:\n * - compliance logging (HIPAA, SOC 2, ISO 27001)\n * - SIEM ingestion\n * - operational dashboards\n * - incident response\n *\n * Usage:\n * ```ts\n * import { AuditTrail } from 'pompelmi/audit';\n *\n * const audit = new AuditTrail({ dest: 'file', path: './audit.jsonl' });\n * audit.logScanComplete({ filename: 'upload.zip', verdict: 'suspicious', ... });\n * audit.logQuarantine({ entryId: '...', sha256: '...', ... });\n * ```\n *\n * @module audit\n */\n\nimport * as fs from \"fs\";\nimport type { QuarantineEntry } from \"./quarantine/types\";\nimport type { ScanReport } from \"./types\";\n\n// ── Record types ──────────────────────────────────────────────────────────────\n\nexport type AuditEventType =\n | \"scan.complete\"\n | \"scan.error\"\n | \"threat.detected\"\n | \"quarantine.created\"\n | \"quarantine.resolved\"\n | \"quarantine.deleted\";\n\ninterface BaseAuditRecord {\n /** ISO-8601 timestamp. */\n timestamp: string;\n /** Event type for structured log routing. */\n event: AuditEventType;\n /** Application-assigned session or request id for correlation. */\n correlationId?: string;\n /** Uploader identity. */\n uploadedBy?: string;\n}\n\nexport interface ScanAuditRecord extends BaseAuditRecord {\n event: \"scan.complete\" | \"scan.error\" | \"threat.detected\";\n filename?: string;\n mimeType?: string;\n sizeBytes?: number;\n sha256?: string;\n verdict: ScanReport[\"verdict\"];\n matchCount: number;\n durationMs?: number;\n engine?: string;\n error?: string;\n}\n\nexport interface QuarantineAuditRecord extends BaseAuditRecord {\n event: \"quarantine.created\" | \"quarantine.resolved\" | \"quarantine.deleted\";\n quarantineId: string;\n filename?: string;\n sha256: string;\n decision?: \"promote\" | \"delete\";\n reviewedBy?: string;\n reviewNote?: string;\n}\n\nexport type AuditRecord = ScanAuditRecord | QuarantineAuditRecord;\n\n// ── Destination ───────────────────────────────────────────────────────────────\n\nexport type AuditDest =\n | { dest: \"console\" }\n | { dest: \"file\"; path: string }\n | { dest: \"custom\"; write: (record: AuditRecord) => void | Promise<void> };\n\nexport interface AuditTrailOptions {\n /** Where to write audit records. Default: 'console'. */\n output?: AuditDest;\n /** If true, pretty-print JSON. Useful for debugging. Default: false. */\n pretty?: boolean;\n}\n\n// ── AuditTrail ────────────────────────────────────────────────────────────────\n\nexport class AuditTrail {\n private readonly options: Required<AuditTrailOptions>;\n\n constructor(options: AuditTrailOptions = {}) {\n this.options = {\n output: options.output ?? { dest: \"console\" },\n pretty: options.pretty ?? false,\n };\n }\n\n /** Log a completed scan. */\n logScanComplete(\n report: ScanReport,\n extra?: Pick<\n ScanAuditRecord,\n \"filename\" | \"sizeBytes\" | \"sha256\" | \"correlationId\" | \"uploadedBy\"\n >,\n ): void {\n const record: ScanAuditRecord = {\n timestamp: new Date().toISOString(),\n event: report.verdict !== \"clean\" ? \"threat.detected\" : \"scan.complete\",\n verdict: report.verdict,\n matchCount: report.matches?.length ?? 0,\n durationMs: report.durationMs,\n engine: report.engine,\n mimeType: report.file?.mimeType,\n ...extra,\n };\n void this.write(record);\n }\n\n /** Log a scan error. */\n logScanError(\n error: unknown,\n extra?: Pick<ScanAuditRecord, \"filename\" | \"correlationId\" | \"uploadedBy\">,\n ): void {\n const record: ScanAuditRecord = {\n timestamp: new Date().toISOString(),\n event: \"scan.error\",\n verdict: \"clean\", // unknown at this point\n matchCount: 0,\n error: error instanceof Error ? error.message : String(error),\n ...extra,\n };\n void this.write(record);\n }\n\n /** Log a new quarantine entry. */\n logQuarantine(entry: QuarantineEntry, correlationId?: string): void {\n const record: QuarantineAuditRecord = {\n timestamp: new Date().toISOString(),\n event: \"quarantine.created\",\n quarantineId: entry.id,\n filename: entry.file.originalName,\n sha256: entry.file.sha256,\n uploadedBy: entry.file.uploadedBy,\n correlationId,\n };\n void this.write(record);\n }\n\n /** Log a quarantine resolution (promote or delete). */\n logQuarantineResolved(entry: QuarantineEntry, correlationId?: string): void {\n const record: QuarantineAuditRecord = {\n timestamp: new Date().toISOString(),\n event: entry.status === \"deleted\" ? \"quarantine.deleted\" : \"quarantine.resolved\",\n quarantineId: entry.id,\n filename: entry.file.originalName,\n sha256: entry.file.sha256,\n decision: entry.status === \"promoted\" ? \"promote\" : \"delete\",\n reviewedBy: entry.reviewedBy,\n reviewNote: entry.reviewNote,\n correlationId,\n };\n void this.write(record);\n }\n\n private async write(record: AuditRecord): Promise<void> {\n const line = this.options.pretty ? JSON.stringify(record, null, 2) : JSON.stringify(record);\n\n const { output } = this.options;\n\n try {\n if (output.dest === \"console\") {\n process.stdout.write(line + \"\\n\");\n } else if (output.dest === \"file\") {\n // Append a newline-delimited JSON (NDJSON) record.\n await fs.promises.appendFile(output.path, line + \"\\n\", \"utf8\");\n } else if (output.dest === \"custom\") {\n await output.write(record);\n }\n } catch {\n // Audit failures must never interrupt the upload pipeline.\n }\n }\n}\n"],"names":["fs"],"mappings":"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"}
@@ -1,107 +0,0 @@
1
- import * as fs from 'fs';
2
-
3
- /**
4
- * Audit trail for Pompelmi scan and quarantine events.
5
- *
6
- * Produces structured, append-only audit records suitable for:
7
- * - compliance logging (HIPAA, SOC 2, ISO 27001)
8
- * - SIEM ingestion
9
- * - operational dashboards
10
- * - incident response
11
- *
12
- * Usage:
13
- * ```ts
14
- * import { AuditTrail } from 'pompelmi/audit';
15
- *
16
- * const audit = new AuditTrail({ dest: 'file', path: './audit.jsonl' });
17
- * audit.logScanComplete({ filename: 'upload.zip', verdict: 'suspicious', ... });
18
- * audit.logQuarantine({ entryId: '...', sha256: '...', ... });
19
- * ```
20
- *
21
- * @module audit
22
- */
23
- // ── AuditTrail ────────────────────────────────────────────────────────────────
24
- class AuditTrail {
25
- constructor(options = {}) {
26
- this.options = {
27
- output: options.output ?? { dest: "console" },
28
- pretty: options.pretty ?? false,
29
- };
30
- }
31
- /** Log a completed scan. */
32
- logScanComplete(report, extra) {
33
- const record = {
34
- timestamp: new Date().toISOString(),
35
- event: report.verdict !== "clean" ? "threat.detected" : "scan.complete",
36
- verdict: report.verdict,
37
- matchCount: report.matches?.length ?? 0,
38
- durationMs: report.durationMs,
39
- engine: report.engine,
40
- mimeType: report.file?.mimeType,
41
- ...extra,
42
- };
43
- void this.write(record);
44
- }
45
- /** Log a scan error. */
46
- logScanError(error, extra) {
47
- const record = {
48
- timestamp: new Date().toISOString(),
49
- event: "scan.error",
50
- verdict: "clean", // unknown at this point
51
- matchCount: 0,
52
- error: error instanceof Error ? error.message : String(error),
53
- ...extra,
54
- };
55
- void this.write(record);
56
- }
57
- /** Log a new quarantine entry. */
58
- logQuarantine(entry, correlationId) {
59
- const record = {
60
- timestamp: new Date().toISOString(),
61
- event: "quarantine.created",
62
- quarantineId: entry.id,
63
- filename: entry.file.originalName,
64
- sha256: entry.file.sha256,
65
- uploadedBy: entry.file.uploadedBy,
66
- correlationId,
67
- };
68
- void this.write(record);
69
- }
70
- /** Log a quarantine resolution (promote or delete). */
71
- logQuarantineResolved(entry, correlationId) {
72
- const record = {
73
- timestamp: new Date().toISOString(),
74
- event: entry.status === "deleted" ? "quarantine.deleted" : "quarantine.resolved",
75
- quarantineId: entry.id,
76
- filename: entry.file.originalName,
77
- sha256: entry.file.sha256,
78
- decision: entry.status === "promoted" ? "promote" : "delete",
79
- reviewedBy: entry.reviewedBy,
80
- reviewNote: entry.reviewNote,
81
- correlationId,
82
- };
83
- void this.write(record);
84
- }
85
- async write(record) {
86
- const line = this.options.pretty ? JSON.stringify(record, null, 2) : JSON.stringify(record);
87
- const { output } = this.options;
88
- try {
89
- if (output.dest === "console") {
90
- process.stdout.write(line + "\n");
91
- }
92
- else if (output.dest === "file") {
93
- // Append a newline-delimited JSON (NDJSON) record.
94
- await fs.promises.appendFile(output.path, line + "\n", "utf8");
95
- }
96
- else if (output.dest === "custom") {
97
- await output.write(record);
98
- }
99
- }
100
- catch {
101
- // Audit failures must never interrupt the upload pipeline.
102
- }
103
- }
104
- }
105
-
106
- export { AuditTrail };
107
- //# sourceMappingURL=pompelmi.audit.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pompelmi.audit.esm.js","sources":["../../src/audit.ts"],"sourcesContent":["/**\n * Audit trail for Pompelmi scan and quarantine events.\n *\n * Produces structured, append-only audit records suitable for:\n * - compliance logging (HIPAA, SOC 2, ISO 27001)\n * - SIEM ingestion\n * - operational dashboards\n * - incident response\n *\n * Usage:\n * ```ts\n * import { AuditTrail } from 'pompelmi/audit';\n *\n * const audit = new AuditTrail({ dest: 'file', path: './audit.jsonl' });\n * audit.logScanComplete({ filename: 'upload.zip', verdict: 'suspicious', ... });\n * audit.logQuarantine({ entryId: '...', sha256: '...', ... });\n * ```\n *\n * @module audit\n */\n\nimport * as fs from \"fs\";\nimport type { QuarantineEntry } from \"./quarantine/types\";\nimport type { ScanReport } from \"./types\";\n\n// ── Record types ──────────────────────────────────────────────────────────────\n\nexport type AuditEventType =\n | \"scan.complete\"\n | \"scan.error\"\n | \"threat.detected\"\n | \"quarantine.created\"\n | \"quarantine.resolved\"\n | \"quarantine.deleted\";\n\ninterface BaseAuditRecord {\n /** ISO-8601 timestamp. */\n timestamp: string;\n /** Event type for structured log routing. */\n event: AuditEventType;\n /** Application-assigned session or request id for correlation. */\n correlationId?: string;\n /** Uploader identity. */\n uploadedBy?: string;\n}\n\nexport interface ScanAuditRecord extends BaseAuditRecord {\n event: \"scan.complete\" | \"scan.error\" | \"threat.detected\";\n filename?: string;\n mimeType?: string;\n sizeBytes?: number;\n sha256?: string;\n verdict: ScanReport[\"verdict\"];\n matchCount: number;\n durationMs?: number;\n engine?: string;\n error?: string;\n}\n\nexport interface QuarantineAuditRecord extends BaseAuditRecord {\n event: \"quarantine.created\" | \"quarantine.resolved\" | \"quarantine.deleted\";\n quarantineId: string;\n filename?: string;\n sha256: string;\n decision?: \"promote\" | \"delete\";\n reviewedBy?: string;\n reviewNote?: string;\n}\n\nexport type AuditRecord = ScanAuditRecord | QuarantineAuditRecord;\n\n// ── Destination ───────────────────────────────────────────────────────────────\n\nexport type AuditDest =\n | { dest: \"console\" }\n | { dest: \"file\"; path: string }\n | { dest: \"custom\"; write: (record: AuditRecord) => void | Promise<void> };\n\nexport interface AuditTrailOptions {\n /** Where to write audit records. Default: 'console'. */\n output?: AuditDest;\n /** If true, pretty-print JSON. Useful for debugging. Default: false. */\n pretty?: boolean;\n}\n\n// ── AuditTrail ────────────────────────────────────────────────────────────────\n\nexport class AuditTrail {\n private readonly options: Required<AuditTrailOptions>;\n\n constructor(options: AuditTrailOptions = {}) {\n this.options = {\n output: options.output ?? { dest: \"console\" },\n pretty: options.pretty ?? false,\n };\n }\n\n /** Log a completed scan. */\n logScanComplete(\n report: ScanReport,\n extra?: Pick<\n ScanAuditRecord,\n \"filename\" | \"sizeBytes\" | \"sha256\" | \"correlationId\" | \"uploadedBy\"\n >,\n ): void {\n const record: ScanAuditRecord = {\n timestamp: new Date().toISOString(),\n event: report.verdict !== \"clean\" ? \"threat.detected\" : \"scan.complete\",\n verdict: report.verdict,\n matchCount: report.matches?.length ?? 0,\n durationMs: report.durationMs,\n engine: report.engine,\n mimeType: report.file?.mimeType,\n ...extra,\n };\n void this.write(record);\n }\n\n /** Log a scan error. */\n logScanError(\n error: unknown,\n extra?: Pick<ScanAuditRecord, \"filename\" | \"correlationId\" | \"uploadedBy\">,\n ): void {\n const record: ScanAuditRecord = {\n timestamp: new Date().toISOString(),\n event: \"scan.error\",\n verdict: \"clean\", // unknown at this point\n matchCount: 0,\n error: error instanceof Error ? error.message : String(error),\n ...extra,\n };\n void this.write(record);\n }\n\n /** Log a new quarantine entry. */\n logQuarantine(entry: QuarantineEntry, correlationId?: string): void {\n const record: QuarantineAuditRecord = {\n timestamp: new Date().toISOString(),\n event: \"quarantine.created\",\n quarantineId: entry.id,\n filename: entry.file.originalName,\n sha256: entry.file.sha256,\n uploadedBy: entry.file.uploadedBy,\n correlationId,\n };\n void this.write(record);\n }\n\n /** Log a quarantine resolution (promote or delete). */\n logQuarantineResolved(entry: QuarantineEntry, correlationId?: string): void {\n const record: QuarantineAuditRecord = {\n timestamp: new Date().toISOString(),\n event: entry.status === \"deleted\" ? \"quarantine.deleted\" : \"quarantine.resolved\",\n quarantineId: entry.id,\n filename: entry.file.originalName,\n sha256: entry.file.sha256,\n decision: entry.status === \"promoted\" ? \"promote\" : \"delete\",\n reviewedBy: entry.reviewedBy,\n reviewNote: entry.reviewNote,\n correlationId,\n };\n void this.write(record);\n }\n\n private async write(record: AuditRecord): Promise<void> {\n const line = this.options.pretty ? JSON.stringify(record, null, 2) : JSON.stringify(record);\n\n const { output } = this.options;\n\n try {\n if (output.dest === \"console\") {\n process.stdout.write(line + \"\\n\");\n } else if (output.dest === \"file\") {\n // Append a newline-delimited JSON (NDJSON) record.\n await fs.promises.appendFile(output.path, line + \"\\n\", \"utf8\");\n } else if (output.dest === \"custom\") {\n await output.write(record);\n }\n } catch {\n // Audit failures must never interrupt the upload pipeline.\n }\n }\n}\n"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;;;;;;;AAmBG;AAkEH;MAEa,UAAU,CAAA;AAGrB,IAAA,WAAA,CAAY,UAA6B,EAAE,EAAA;QACzC,IAAI,CAAC,OAAO,GAAG;YACb,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;AAC7C,YAAA,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;SAChC;IACH;;IAGA,eAAe,CACb,MAAkB,EAClB,KAGC,EAAA;AAED,QAAA,MAAM,MAAM,GAAoB;AAC9B,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACnC,YAAA,KAAK,EAAE,MAAM,CAAC,OAAO,KAAK,OAAO,GAAG,iBAAiB,GAAG,eAAe;YACvE,OAAO,EAAE,MAAM,CAAC,OAAO;AACvB,YAAA,UAAU,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;YACvC,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;AACrB,YAAA,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ;AAC/B,YAAA,GAAG,KAAK;SACT;AACD,QAAA,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IACzB;;IAGA,YAAY,CACV,KAAc,EACd,KAA0E,EAAA;AAE1E,QAAA,MAAM,MAAM,GAAoB;AAC9B,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACnC,YAAA,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,OAAO;AAChB,YAAA,UAAU,EAAE,CAAC;AACb,YAAA,KAAK,EAAE,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;AAC7D,YAAA,GAAG,KAAK;SACT;AACD,QAAA,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IACzB;;IAGA,aAAa,CAAC,KAAsB,EAAE,aAAsB,EAAA;AAC1D,QAAA,MAAM,MAAM,GAA0B;AACpC,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACnC,YAAA,KAAK,EAAE,oBAAoB;YAC3B,YAAY,EAAE,KAAK,CAAC,EAAE;AACtB,YAAA,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY;AACjC,YAAA,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM;AACzB,YAAA,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU;YACjC,aAAa;SACd;AACD,QAAA,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IACzB;;IAGA,qBAAqB,CAAC,KAAsB,EAAE,aAAsB,EAAA;AAClE,QAAA,MAAM,MAAM,GAA0B;AACpC,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACnC,YAAA,KAAK,EAAE,KAAK,CAAC,MAAM,KAAK,SAAS,GAAG,oBAAoB,GAAG,qBAAqB;YAChF,YAAY,EAAE,KAAK,CAAC,EAAE;AACtB,YAAA,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY;AACjC,YAAA,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM;AACzB,YAAA,QAAQ,EAAE,KAAK,CAAC,MAAM,KAAK,UAAU,GAAG,SAAS,GAAG,QAAQ;YAC5D,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,aAAa;SACd;AACD,QAAA,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IACzB;IAEQ,MAAM,KAAK,CAAC,MAAmB,EAAA;AACrC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;AAE3F,QAAA,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO;AAE/B,QAAA,IAAI;AACF,YAAA,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE;gBAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;YACnC;AAAO,iBAAA,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE;;AAEjC,gBAAA,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,CAAC;YAChE;AAAO,iBAAA,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE;AACnC,gBAAA,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;YAC5B;QACF;AAAE,QAAA,MAAM;;QAER;IACF;AACD;;;;"}