pw-sanitizer 0.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.
- package/README.md +415 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +113 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +30 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +173 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +432 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +6 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validator.d.ts +34 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +95 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +190 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +82 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +122 -0
- package/dist/logger.js.map +1 -0
- package/dist/processors/html-report.d.ts +27 -0
- package/dist/processors/html-report.d.ts.map +1 -0
- package/dist/processors/html-report.js +220 -0
- package/dist/processors/html-report.js.map +1 -0
- package/dist/processors/screenshot.d.ts +37 -0
- package/dist/processors/screenshot.d.ts.map +1 -0
- package/dist/processors/screenshot.js +52 -0
- package/dist/processors/screenshot.js.map +1 -0
- package/dist/processors/trace-file.d.ts +29 -0
- package/dist/processors/trace-file.d.ts.map +1 -0
- package/dist/processors/trace-file.js +250 -0
- package/dist/processors/trace-file.js.map +1 -0
- package/dist/redact/json-walker.d.ts +28 -0
- package/dist/redact/json-walker.d.ts.map +1 -0
- package/dist/redact/json-walker.js +164 -0
- package/dist/redact/json-walker.js.map +1 -0
- package/dist/redact/matcher.d.ts +25 -0
- package/dist/redact/matcher.d.ts.map +1 -0
- package/dist/redact/matcher.js +130 -0
- package/dist/redact/matcher.js.map +1 -0
- package/dist/redact/pattern-loader.d.ts +25 -0
- package/dist/redact/pattern-loader.d.ts.map +1 -0
- package/dist/redact/pattern-loader.js +111 -0
- package/dist/redact/pattern-loader.js.map +1 -0
- package/dist/redact/pattern-registry.d.ts +17 -0
- package/dist/redact/pattern-registry.d.ts.map +1 -0
- package/dist/redact/pattern-registry.js +58 -0
- package/dist/redact/pattern-registry.js.map +1 -0
- package/dist/remove/detector.d.ts +22 -0
- package/dist/remove/detector.d.ts.map +1 -0
- package/dist/remove/detector.js +152 -0
- package/dist/remove/detector.js.map +1 -0
- package/dist/remove/remover.d.ts +18 -0
- package/dist/remove/remover.d.ts.map +1 -0
- package/dist/remove/remover.js +72 -0
- package/dist/remove/remover.js.map +1 -0
- package/dist/remove/rule-loader.d.ts +25 -0
- package/dist/remove/rule-loader.d.ts.map +1 -0
- package/dist/remove/rule-loader.js +110 -0
- package/dist/remove/rule-loader.js.map +1 -0
- package/dist/remove/rule-registry.d.ts +17 -0
- package/dist/remove/rule-registry.d.ts.map +1 -0
- package/dist/remove/rule-registry.js +58 -0
- package/dist/remove/rule-registry.js.map +1 -0
- package/dist/remove/timestamp-repair.d.ts +28 -0
- package/dist/remove/timestamp-repair.d.ts.map +1 -0
- package/dist/remove/timestamp-repair.js +157 -0
- package/dist/remove/timestamp-repair.js.map +1 -0
- package/dist/reporter.d.ts +44 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +180 -0
- package/dist/reporter.js.map +1 -0
- package/dist/teardown.d.ts +27 -0
- package/dist/teardown.d.ts.map +1 -0
- package/dist/teardown.js +42 -0
- package/dist/teardown.js.map +1 -0
- package/dist/utils.d.ts +36 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +112 -0
- package/dist/utils.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.processHtmlReport = processHtmlReport;
|
|
37
|
+
const fs = __importStar(require("node:fs"));
|
|
38
|
+
const json_walker_js_1 = require("../redact/json-walker.js");
|
|
39
|
+
const detector_js_1 = require("../remove/detector.js");
|
|
40
|
+
const remover_js_1 = require("../remove/remover.js");
|
|
41
|
+
const timestamp_repair_js_1 = require("../remove/timestamp-repair.js");
|
|
42
|
+
const logger_js_1 = require("../logger.js");
|
|
43
|
+
const utils_js_1 = require("../utils.js");
|
|
44
|
+
/**
|
|
45
|
+
* Regex that locates the embedded JSON blob inside a Playwright HTML report.
|
|
46
|
+
*
|
|
47
|
+
* Playwright injects report data as:
|
|
48
|
+
* `window.__pw_report_data__ = { ... };</script>`
|
|
49
|
+
*
|
|
50
|
+
* The first capture group (`[1]`) contains the raw JSON object literal.
|
|
51
|
+
* The `s` flag allows `.` to match newlines (the blob can be multi-line).
|
|
52
|
+
*/
|
|
53
|
+
const REPORT_DATA_REGEX = /window\.__pw_report_data__\s*=\s*(\{.+?\});\s*<\/script>/s;
|
|
54
|
+
/**
|
|
55
|
+
* Sanitizes a single Playwright HTML report file.
|
|
56
|
+
*
|
|
57
|
+
* Processing pipeline:
|
|
58
|
+
* 1. Read the HTML file from disk.
|
|
59
|
+
* 2. Extract the embedded `window.__pw_report_data__` JSON blob via regex.
|
|
60
|
+
* 3. **Redact phase** (if `config.redact` is set and patterns are loaded):
|
|
61
|
+
* walk the JSON tree with {@link walkAndRedact} and replace matched values.
|
|
62
|
+
* 4. **Remove phase** (if `config.remove` is set and rules are loaded):
|
|
63
|
+
* extract step events, run {@link findStepsToRemove}, then
|
|
64
|
+
* {@link removeSteps} and {@link repairTimestamps}.
|
|
65
|
+
* 5. Re-serialise the JSON and splice it back into the original HTML.
|
|
66
|
+
* 6. Write the output according to `config.output.mode`.
|
|
67
|
+
*
|
|
68
|
+
* On any unrecoverable parse error, the function logs a warning and returns
|
|
69
|
+
* an empty {@link ProcessResult} rather than throwing.
|
|
70
|
+
*
|
|
71
|
+
* @param inputPath - Absolute path to the source HTML report file.
|
|
72
|
+
* @param outputPath - Destination path for the sanitized output.
|
|
73
|
+
* @param config - The full sanitizer configuration.
|
|
74
|
+
* @param patterns - Pre-built list of redact patterns (from {@link buildPatternRegistry}).
|
|
75
|
+
* @param rules - Pre-built list of removal rules (from {@link buildRuleRegistry}).
|
|
76
|
+
* @returns A {@link ProcessResult} with counts and match details for this file.
|
|
77
|
+
*/
|
|
78
|
+
async function processHtmlReport(inputPath, outputPath, config, patterns, rules) {
|
|
79
|
+
const result = {
|
|
80
|
+
file: inputPath,
|
|
81
|
+
redactionsApplied: 0,
|
|
82
|
+
stepsRemoved: 0,
|
|
83
|
+
timestampRepairs: 0,
|
|
84
|
+
redactionMatches: [],
|
|
85
|
+
removalMatches: [],
|
|
86
|
+
};
|
|
87
|
+
const html = fs.readFileSync(inputPath, 'utf-8');
|
|
88
|
+
const match = REPORT_DATA_REGEX.exec(html);
|
|
89
|
+
if (!match?.[1]) {
|
|
90
|
+
logger_js_1.logger.warn(`Could not find embedded report data in ${inputPath}. ` +
|
|
91
|
+
`Expected pattern: window.__pw_report_data__ = {...};`);
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
let reportData;
|
|
95
|
+
try {
|
|
96
|
+
reportData = JSON.parse(match[1]);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
logger_js_1.logger.warn(`Failed to parse embedded JSON in ${inputPath}: ` +
|
|
100
|
+
`${err instanceof Error ? err.message : String(err)}`);
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
let modified = false;
|
|
104
|
+
// Redact phase
|
|
105
|
+
if (config.redact && patterns.length > 0) {
|
|
106
|
+
const walkResult = (0, json_walker_js_1.walkAndRedact)(reportData, patterns, config.redact);
|
|
107
|
+
if (walkResult.count > 0) {
|
|
108
|
+
reportData = walkResult.result;
|
|
109
|
+
result.redactionsApplied = walkResult.count;
|
|
110
|
+
result.redactionMatches = walkResult.matches;
|
|
111
|
+
modified = true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Remove phase
|
|
115
|
+
if (config.remove && rules.length > 0) {
|
|
116
|
+
// The report data typically has a structure with tests/suites containing steps
|
|
117
|
+
const events = extractEventsFromReport(reportData);
|
|
118
|
+
if (events.length > 0) {
|
|
119
|
+
const removalSet = (0, detector_js_1.findStepsToRemove)(events, rules);
|
|
120
|
+
if (removalSet.indices.size > 0) {
|
|
121
|
+
if (config.remove.dryRun) {
|
|
122
|
+
logger_js_1.logger.info(`[DRY RUN] Would remove ${removalSet.indices.size} steps from ${inputPath}`);
|
|
123
|
+
for (const m of removalSet.matches) {
|
|
124
|
+
logger_js_1.logger.info(` - Rule "${m.ruleLabel}": step at index ${m.index} ` +
|
|
125
|
+
`("${m.event.title ?? m.event.action ?? 'unknown'}")`);
|
|
126
|
+
}
|
|
127
|
+
result.removalMatches = removalSet.matches;
|
|
128
|
+
result.stepsRemoved = removalSet.indices.size;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const removedEvents = Array.from(removalSet.indices).map((i) => events[i]);
|
|
132
|
+
const cleaned = (0, remover_js_1.removeSteps)(events, removalSet);
|
|
133
|
+
const strategy = config.remove.timestampStrategy ?? 'absorb-into-prev';
|
|
134
|
+
const repaired = (0, timestamp_repair_js_1.repairTimestamps)(cleaned, removedEvents, strategy);
|
|
135
|
+
replaceEventsInReport(reportData, repaired);
|
|
136
|
+
result.stepsRemoved = removalSet.indices.size;
|
|
137
|
+
result.timestampRepairs = removalSet.indices.size;
|
|
138
|
+
result.removalMatches = removalSet.matches;
|
|
139
|
+
modified = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (!modified && !config.remove?.dryRun) {
|
|
145
|
+
logger_js_1.logger.info(`No changes made to ${inputPath}`);
|
|
146
|
+
}
|
|
147
|
+
// Write output (unless dry-run)
|
|
148
|
+
if (!config.remove?.dryRun) {
|
|
149
|
+
const newJson = JSON.stringify(reportData);
|
|
150
|
+
const newHtml = html.replace(REPORT_DATA_REGEX, `window.__pw_report_data__ = ${newJson};</script>`);
|
|
151
|
+
(0, utils_js_1.writeOutput)(inputPath, outputPath, newHtml, config);
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Flattens the nested Playwright HTML report structure into a single array of
|
|
157
|
+
* step/action events that can be processed by the removal pipeline.
|
|
158
|
+
*
|
|
159
|
+
* Playwright HTML reports nest steps under `suites → tests → results → steps`.
|
|
160
|
+
* This function performs a depth-first traversal, collecting any node that
|
|
161
|
+
* looks like a step (has `startTime`/`endTime`, `title`, or `action` fields)
|
|
162
|
+
* and recursing into known container keys (`steps`, `actions`, `suites`,
|
|
163
|
+
* `tests`, `results`, `attachments`).
|
|
164
|
+
*
|
|
165
|
+
* @param data - The parsed `window.__pw_report_data__` object.
|
|
166
|
+
* @returns A flat array of event-like objects cast to {@link TraceEvent}.
|
|
167
|
+
*/
|
|
168
|
+
function extractEventsFromReport(data) {
|
|
169
|
+
const events = [];
|
|
170
|
+
function traverse(node) {
|
|
171
|
+
if (!node || typeof node !== 'object')
|
|
172
|
+
return;
|
|
173
|
+
if (Array.isArray(node)) {
|
|
174
|
+
for (const item of node) {
|
|
175
|
+
traverse(item);
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const obj = node;
|
|
180
|
+
// Check if this looks like a step/action event
|
|
181
|
+
if (('startTime' in obj && 'endTime' in obj) ||
|
|
182
|
+
'title' in obj ||
|
|
183
|
+
'action' in obj) {
|
|
184
|
+
events.push(obj);
|
|
185
|
+
}
|
|
186
|
+
// Recurse into common containers
|
|
187
|
+
for (const key of ['steps', 'actions', 'suites', 'tests', 'results', 'attachments']) {
|
|
188
|
+
if (key in obj && Array.isArray(obj[key])) {
|
|
189
|
+
traverse(obj[key]);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
traverse(data);
|
|
194
|
+
return events;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Placeholder for post-removal tree reconstruction in HTML reports.
|
|
198
|
+
*
|
|
199
|
+
* In the current implementation, step mutations during the redact walk phase
|
|
200
|
+
* are applied directly to object references within the report tree, which is
|
|
201
|
+
* sufficient for the redaction use-case.
|
|
202
|
+
*
|
|
203
|
+
* Full step-removal support for HTML reports would require rebuilding the
|
|
204
|
+
* nested `steps` arrays in each test result to exclude the removed events —
|
|
205
|
+
* this is tracked as a future enhancement.
|
|
206
|
+
*
|
|
207
|
+
* @param _data - The parsed report data (unused — present for future implementation).
|
|
208
|
+
* @param _repairedEvents - The repaired event array (unused — present for future implementation).
|
|
209
|
+
*/
|
|
210
|
+
function replaceEventsInReport(_data, _repairedEvents) {
|
|
211
|
+
// The events extracted from the report are object references.
|
|
212
|
+
// removeSteps returns a new array but the original tree still contains
|
|
213
|
+
// the old references. For a full implementation, we'd need to rebuild
|
|
214
|
+
// the tree structure. For now, the walked-and-redacted data is sufficient
|
|
215
|
+
// since we modify the objects in place during the walk phase.
|
|
216
|
+
//
|
|
217
|
+
// A more complete implementation would rebuild the steps arrays in the
|
|
218
|
+
// report tree to match the filtered events.
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=html-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-report.js","sourceRoot":"","sources":["../../src/processors/html-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional screenshot redaction module.
|
|
3
|
+
*
|
|
4
|
+
* When `output.redactScreenshots` is `true`, this module is used to blur
|
|
5
|
+
* pixel regions of screenshots captured during a Playwright test run. Regions
|
|
6
|
+
* are identified by mapping CSS selectors from redact patterns to pixel
|
|
7
|
+
* coordinates recorded in the trace.
|
|
8
|
+
*
|
|
9
|
+
* **Current status**: placeholder implementation. The function signature and
|
|
10
|
+
* `sharp` integration skeleton are in place, but the coordinate-mapping logic
|
|
11
|
+
* and blur overlay are not yet implemented. Requires the optional `sharp`
|
|
12
|
+
* peer dependency (`npm install sharp`).
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Applies pixel-level redaction to a screenshot buffer by blurring the
|
|
16
|
+
* specified rectangular regions.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* This is a **placeholder** — the function currently returns the original
|
|
20
|
+
* buffer unchanged. A full implementation would use `sharp` to composite
|
|
21
|
+
* blurred rectangles over the matching coordinates.
|
|
22
|
+
*
|
|
23
|
+
* If `sharp` is not installed, a warning is logged and the original buffer
|
|
24
|
+
* is returned (no-op behaviour).
|
|
25
|
+
*
|
|
26
|
+
* @param _screenshotBuffer - The raw PNG/JPEG screenshot buffer from the trace archive.
|
|
27
|
+
* @param _regions - Pixel-coordinate rectangles to blur (x, y, width, height — all in px).
|
|
28
|
+
* @returns The (potentially blurred) screenshot buffer.
|
|
29
|
+
* Currently always returns `_screenshotBuffer` unchanged.
|
|
30
|
+
*/
|
|
31
|
+
export declare function redactScreenshot(_screenshotBuffer: Buffer, _regions: Array<{
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
}>): Promise<Buffer>;
|
|
37
|
+
//# sourceMappingURL=screenshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/processors/screenshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CACpC,iBAAiB,EAAE,MAAM,EACzB,QAAQ,EAAE,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GACvE,OAAO,CAAC,MAAM,CAAC,CAkBjB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Optional screenshot redaction module.
|
|
4
|
+
*
|
|
5
|
+
* When `output.redactScreenshots` is `true`, this module is used to blur
|
|
6
|
+
* pixel regions of screenshots captured during a Playwright test run. Regions
|
|
7
|
+
* are identified by mapping CSS selectors from redact patterns to pixel
|
|
8
|
+
* coordinates recorded in the trace.
|
|
9
|
+
*
|
|
10
|
+
* **Current status**: placeholder implementation. The function signature and
|
|
11
|
+
* `sharp` integration skeleton are in place, but the coordinate-mapping logic
|
|
12
|
+
* and blur overlay are not yet implemented. Requires the optional `sharp`
|
|
13
|
+
* peer dependency (`npm install sharp`).
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.redactScreenshot = redactScreenshot;
|
|
17
|
+
const logger_js_1 = require("../logger.js");
|
|
18
|
+
/**
|
|
19
|
+
* Applies pixel-level redaction to a screenshot buffer by blurring the
|
|
20
|
+
* specified rectangular regions.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* This is a **placeholder** — the function currently returns the original
|
|
24
|
+
* buffer unchanged. A full implementation would use `sharp` to composite
|
|
25
|
+
* blurred rectangles over the matching coordinates.
|
|
26
|
+
*
|
|
27
|
+
* If `sharp` is not installed, a warning is logged and the original buffer
|
|
28
|
+
* is returned (no-op behaviour).
|
|
29
|
+
*
|
|
30
|
+
* @param _screenshotBuffer - The raw PNG/JPEG screenshot buffer from the trace archive.
|
|
31
|
+
* @param _regions - Pixel-coordinate rectangles to blur (x, y, width, height — all in px).
|
|
32
|
+
* @returns The (potentially blurred) screenshot buffer.
|
|
33
|
+
* Currently always returns `_screenshotBuffer` unchanged.
|
|
34
|
+
*/
|
|
35
|
+
async function redactScreenshot(_screenshotBuffer, _regions) {
|
|
36
|
+
try {
|
|
37
|
+
// Dynamic import to respect optional peer dependency
|
|
38
|
+
// Use a variable to prevent TypeScript from resolving the module at compile time
|
|
39
|
+
const sharpModule = 'sharp';
|
|
40
|
+
await import(sharpModule);
|
|
41
|
+
logger_js_1.logger.verbose('Screenshot redaction: sharp module loaded');
|
|
42
|
+
// Placeholder: actual implementation would overlay blur regions
|
|
43
|
+
// onto the screenshot at the specified pixel coordinates.
|
|
44
|
+
return _screenshotBuffer;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
logger_js_1.logger.warn('Screenshot redaction requires the "sharp" package. ' +
|
|
48
|
+
'Install it with: npm install sharp');
|
|
49
|
+
return _screenshotBuffer;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=screenshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/processors/screenshot.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AAqBH,4CAqBC;AAxCD,4CAAsC;AAEtC;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,UAAU,gBAAgB,CACpC,iBAAyB,EACzB,QAAwE;IAExE,IAAI,CAAC;QACH,qDAAqD;QACrD,iFAAiF;QACjF,MAAM,WAAW,GAAG,OAAO,CAAC;QAC5B,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC1B,kBAAM,CAAC,OAAO,CAAC,2CAA2C,CAAC,CAAC;QAE5D,gEAAgE;QAChE,0DAA0D;QAC1D,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,kBAAM,CAAC,IAAI,CACT,qDAAqD;YACrD,oCAAoC,CACrC,CAAC;QACF,OAAO,iBAAiB,CAAC;IAC3B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SanitizerConfig, RedactPattern, RemoveRule, ProcessResult } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sanitizes a single Playwright trace `.zip` file.
|
|
4
|
+
*
|
|
5
|
+
* Processing pipeline:
|
|
6
|
+
* 1. Read and parse the `.zip` archive with JSZip.
|
|
7
|
+
* 2. Extract `trace.json` (primary event stream) and `network.json` (request log).
|
|
8
|
+
* 3. **Redact phase** (if `config.redact` and patterns are loaded):
|
|
9
|
+
* - Walk and redact `trace.json` events.
|
|
10
|
+
* - Walk and redact `network.json` entries.
|
|
11
|
+
* - Walk and redact `.json` / `.txt` files inside the `resources/` folder.
|
|
12
|
+
* 4. **Remove phase** (if `config.remove` and rules are loaded):
|
|
13
|
+
* - Run {@link findStepsToRemove} on the trace events.
|
|
14
|
+
* - Run {@link removeSteps} and {@link repairTimestamps}.
|
|
15
|
+
* - Remove corresponding `network.json` entries by `requestId`.
|
|
16
|
+
* 5. Write modified `trace.json` and `network.json` back into the archive.
|
|
17
|
+
* 6. Re-generate the `.zip` buffer and write it according to `config.output.mode`.
|
|
18
|
+
*
|
|
19
|
+
* Unreadable files and non-JSON resources are skipped gracefully with warnings.
|
|
20
|
+
*
|
|
21
|
+
* @param inputPath - Absolute path to the source trace `.zip` file.
|
|
22
|
+
* @param outputPath - Destination path for the sanitized output archive.
|
|
23
|
+
* @param config - The full sanitizer configuration.
|
|
24
|
+
* @param patterns - Pre-built list of redact patterns (from {@link buildPatternRegistry}).
|
|
25
|
+
* @param rules - Pre-built list of removal rules (from {@link buildRuleRegistry}).
|
|
26
|
+
* @returns A {@link ProcessResult} with counts and match details for this file.
|
|
27
|
+
*/
|
|
28
|
+
export declare function processTraceFile(inputPath: string, outputPath: string, config: SanitizerConfig, patterns: RedactPattern[], rules: RemoveRule[]): Promise<ProcessResult>;
|
|
29
|
+
//# sourceMappingURL=trace-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-file.d.ts","sourceRoot":"","sources":["../../src/processors/trace-file.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,UAAU,EACV,aAAa,EAEd,MAAM,oBAAoB,CAAC;AAQ5B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,aAAa,EAAE,EACzB,KAAK,EAAE,UAAU,EAAE,GAClB,OAAO,CAAC,aAAa,CAAC,CA8MxB"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.processTraceFile = processTraceFile;
|
|
40
|
+
const fs = __importStar(require("node:fs"));
|
|
41
|
+
const jszip_1 = __importDefault(require("jszip"));
|
|
42
|
+
const json_walker_js_1 = require("../redact/json-walker.js");
|
|
43
|
+
const detector_js_1 = require("../remove/detector.js");
|
|
44
|
+
const remover_js_1 = require("../remove/remover.js");
|
|
45
|
+
const timestamp_repair_js_1 = require("../remove/timestamp-repair.js");
|
|
46
|
+
const logger_js_1 = require("../logger.js");
|
|
47
|
+
const utils_js_1 = require("../utils.js");
|
|
48
|
+
/**
|
|
49
|
+
* Sanitizes a single Playwright trace `.zip` file.
|
|
50
|
+
*
|
|
51
|
+
* Processing pipeline:
|
|
52
|
+
* 1. Read and parse the `.zip` archive with JSZip.
|
|
53
|
+
* 2. Extract `trace.json` (primary event stream) and `network.json` (request log).
|
|
54
|
+
* 3. **Redact phase** (if `config.redact` and patterns are loaded):
|
|
55
|
+
* - Walk and redact `trace.json` events.
|
|
56
|
+
* - Walk and redact `network.json` entries.
|
|
57
|
+
* - Walk and redact `.json` / `.txt` files inside the `resources/` folder.
|
|
58
|
+
* 4. **Remove phase** (if `config.remove` and rules are loaded):
|
|
59
|
+
* - Run {@link findStepsToRemove} on the trace events.
|
|
60
|
+
* - Run {@link removeSteps} and {@link repairTimestamps}.
|
|
61
|
+
* - Remove corresponding `network.json` entries by `requestId`.
|
|
62
|
+
* 5. Write modified `trace.json` and `network.json` back into the archive.
|
|
63
|
+
* 6. Re-generate the `.zip` buffer and write it according to `config.output.mode`.
|
|
64
|
+
*
|
|
65
|
+
* Unreadable files and non-JSON resources are skipped gracefully with warnings.
|
|
66
|
+
*
|
|
67
|
+
* @param inputPath - Absolute path to the source trace `.zip` file.
|
|
68
|
+
* @param outputPath - Destination path for the sanitized output archive.
|
|
69
|
+
* @param config - The full sanitizer configuration.
|
|
70
|
+
* @param patterns - Pre-built list of redact patterns (from {@link buildPatternRegistry}).
|
|
71
|
+
* @param rules - Pre-built list of removal rules (from {@link buildRuleRegistry}).
|
|
72
|
+
* @returns A {@link ProcessResult} with counts and match details for this file.
|
|
73
|
+
*/
|
|
74
|
+
async function processTraceFile(inputPath, outputPath, config, patterns, rules) {
|
|
75
|
+
const result = {
|
|
76
|
+
file: inputPath,
|
|
77
|
+
redactionsApplied: 0,
|
|
78
|
+
stepsRemoved: 0,
|
|
79
|
+
timestampRepairs: 0,
|
|
80
|
+
redactionMatches: [],
|
|
81
|
+
removalMatches: [],
|
|
82
|
+
};
|
|
83
|
+
let zipData;
|
|
84
|
+
try {
|
|
85
|
+
zipData = fs.readFileSync(inputPath);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
logger_js_1.logger.warn(`Could not read trace file ${inputPath}: ` +
|
|
89
|
+
`${err instanceof Error ? err.message : String(err)}`);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
let zip;
|
|
93
|
+
try {
|
|
94
|
+
zip = await jszip_1.default.loadAsync(zipData);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
logger_js_1.logger.warn(`Could not parse trace zip ${inputPath}: ` +
|
|
98
|
+
`${err instanceof Error ? err.message : String(err)}`);
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
let modified = false;
|
|
102
|
+
// Load trace.json
|
|
103
|
+
let traceEvents = null;
|
|
104
|
+
const traceFile = zip.file('trace.json');
|
|
105
|
+
if (traceFile) {
|
|
106
|
+
try {
|
|
107
|
+
const traceContent = await traceFile.async('string');
|
|
108
|
+
traceEvents = JSON.parse(traceContent);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
logger_js_1.logger.warn(`Failed to parse trace.json in ${inputPath}: ` +
|
|
112
|
+
`${err instanceof Error ? err.message : String(err)}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Load network.json
|
|
116
|
+
let networkData = null;
|
|
117
|
+
const networkFile = zip.file('network.json');
|
|
118
|
+
if (networkFile) {
|
|
119
|
+
try {
|
|
120
|
+
const networkContent = await networkFile.async('string');
|
|
121
|
+
networkData = JSON.parse(networkContent);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// network.json might not exist in all traces
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// ── Redact phase ──
|
|
128
|
+
if (config.redact && patterns.length > 0) {
|
|
129
|
+
// Redact trace.json
|
|
130
|
+
if (traceEvents) {
|
|
131
|
+
const traceWalk = (0, json_walker_js_1.walkAndRedact)(traceEvents, patterns, config.redact);
|
|
132
|
+
if (traceWalk.count > 0) {
|
|
133
|
+
traceEvents = traceWalk.result;
|
|
134
|
+
result.redactionsApplied += traceWalk.count;
|
|
135
|
+
result.redactionMatches.push(...traceWalk.matches);
|
|
136
|
+
modified = true;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Redact network.json
|
|
140
|
+
if (networkData) {
|
|
141
|
+
const networkWalk = (0, json_walker_js_1.walkAndRedact)(networkData, patterns, config.redact);
|
|
142
|
+
if (networkWalk.count > 0) {
|
|
143
|
+
networkData = networkWalk.result;
|
|
144
|
+
result.redactionsApplied += networkWalk.count;
|
|
145
|
+
result.redactionMatches.push(...networkWalk.matches);
|
|
146
|
+
modified = true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Redact JSON files in resources/
|
|
150
|
+
const resourceFiles = zip.folder('resources');
|
|
151
|
+
if (resourceFiles) {
|
|
152
|
+
const jsonResources = [];
|
|
153
|
+
resourceFiles.forEach((relativePath, file) => {
|
|
154
|
+
if (!file.dir &&
|
|
155
|
+
(relativePath.endsWith('.json') || relativePath.endsWith('.txt'))) {
|
|
156
|
+
jsonResources.push(`resources/${relativePath}`);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
for (const resPath of jsonResources) {
|
|
160
|
+
const resFile = zip.file(resPath);
|
|
161
|
+
if (resFile) {
|
|
162
|
+
try {
|
|
163
|
+
const content = await resFile.async('string');
|
|
164
|
+
const parsed = JSON.parse(content);
|
|
165
|
+
const resWalk = (0, json_walker_js_1.walkAndRedact)(parsed, patterns, config.redact);
|
|
166
|
+
if (resWalk.count > 0) {
|
|
167
|
+
zip.file(resPath, JSON.stringify(parsed));
|
|
168
|
+
result.redactionsApplied += resWalk.count;
|
|
169
|
+
result.redactionMatches.push(...resWalk.matches);
|
|
170
|
+
modified = true;
|
|
171
|
+
// Update with redacted content
|
|
172
|
+
zip.file(resPath, JSON.stringify(resWalk.result));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Not valid JSON — skip
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// ── Remove phase ──
|
|
183
|
+
if (config.remove && rules.length > 0 && traceEvents) {
|
|
184
|
+
const removalSet = (0, detector_js_1.findStepsToRemove)(traceEvents, rules);
|
|
185
|
+
if (removalSet.indices.size > 0) {
|
|
186
|
+
if (config.remove.dryRun) {
|
|
187
|
+
logger_js_1.logger.info(`[DRY RUN] Would remove ${removalSet.indices.size} steps from ${inputPath}`);
|
|
188
|
+
for (const m of removalSet.matches) {
|
|
189
|
+
logger_js_1.logger.info(` - Rule "${m.ruleLabel}": step at index ${m.index} ` +
|
|
190
|
+
`("${m.event.title ?? m.event.action ?? 'unknown'}")`);
|
|
191
|
+
}
|
|
192
|
+
result.removalMatches = removalSet.matches;
|
|
193
|
+
result.stepsRemoved = removalSet.indices.size;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// Collect removed events before removal
|
|
197
|
+
const removedEvents = Array.from(removalSet.indices).map((i) => traceEvents[i]);
|
|
198
|
+
// Collect requestIds of removed events for network cleanup
|
|
199
|
+
const removedRequestIds = new Set();
|
|
200
|
+
for (const event of removedEvents) {
|
|
201
|
+
if (event.requestId) {
|
|
202
|
+
removedRequestIds.add(event.requestId);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Remove steps
|
|
206
|
+
const cleaned = (0, remover_js_1.removeSteps)(traceEvents, removalSet);
|
|
207
|
+
// Repair timestamps
|
|
208
|
+
const strategy = config.remove.timestampStrategy ?? 'absorb-into-prev';
|
|
209
|
+
traceEvents = (0, timestamp_repair_js_1.repairTimestamps)(cleaned, removedEvents, strategy);
|
|
210
|
+
// Remove corresponding network.json entries
|
|
211
|
+
if (networkData && removedRequestIds.size > 0) {
|
|
212
|
+
networkData = networkData.filter((entry) => {
|
|
213
|
+
if (entry &&
|
|
214
|
+
typeof entry === 'object' &&
|
|
215
|
+
'requestId' in entry) {
|
|
216
|
+
const reqId = entry.requestId;
|
|
217
|
+
return !removedRequestIds.has(reqId);
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
result.stepsRemoved = removalSet.indices.size;
|
|
223
|
+
result.timestampRepairs = removalSet.indices.size;
|
|
224
|
+
result.removalMatches = removalSet.matches;
|
|
225
|
+
modified = true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (!modified && !config.remove?.dryRun) {
|
|
230
|
+
logger_js_1.logger.info(`No changes made to ${inputPath}`);
|
|
231
|
+
}
|
|
232
|
+
// Write output (unless dry-run)
|
|
233
|
+
if (!config.remove?.dryRun) {
|
|
234
|
+
// Update files in the zip
|
|
235
|
+
if (traceEvents) {
|
|
236
|
+
zip.file('trace.json', JSON.stringify(traceEvents));
|
|
237
|
+
}
|
|
238
|
+
if (networkData) {
|
|
239
|
+
zip.file('network.json', JSON.stringify(networkData));
|
|
240
|
+
}
|
|
241
|
+
// Generate zip buffer
|
|
242
|
+
const outputBuffer = await zip.generateAsync({
|
|
243
|
+
type: 'nodebuffer',
|
|
244
|
+
compression: 'DEFLATE',
|
|
245
|
+
});
|
|
246
|
+
(0, utils_js_1.writeOutput)(inputPath, outputPath, outputBuffer, config);
|
|
247
|
+
}
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=trace-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-file.js","sourceRoot":"","sources":["../../src/processors/trace-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RedactConfig, RedactPattern, WalkResult } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Recursively traverses a JSON-like structure and redacts any string values
|
|
4
|
+
* that match the provided patterns.
|
|
5
|
+
*
|
|
6
|
+
* Traversal rules:
|
|
7
|
+
* - **Arrays**: each element is walked with an indexed path (e.g. `items[0].token`).
|
|
8
|
+
* - **Objects**: each property is visited; the key is tested against patterns.
|
|
9
|
+
* - **Strings**: tested via {@link redactValue}. If not redacted, the value is also
|
|
10
|
+
* tested as embedded JSON (a string that is itself a JSON object/array) and, if
|
|
11
|
+
* parseable, the inner structure is walked recursively and re-serialised.
|
|
12
|
+
* - **Base64 JSON bodies**: if an object has a `Content-Type: application/json`
|
|
13
|
+
* sibling and a body-like field containing base64 data, the decoded JSON is
|
|
14
|
+
* walked and the field is re-encoded after redaction.
|
|
15
|
+
* - **Numbers / booleans**: copied through as-is (never redacted).
|
|
16
|
+
* - **`null` / `undefined`**: returned unchanged.
|
|
17
|
+
*
|
|
18
|
+
* The input is **never mutated** — a new tree is produced for each call.
|
|
19
|
+
*
|
|
20
|
+
* @param obj - The JSON value to walk. Typically a parsed `trace.json` array
|
|
21
|
+
* or the `window.__pw_report_data__` object extracted from an HTML report.
|
|
22
|
+
* @param patterns - Ordered list of {@link RedactPattern}s to apply.
|
|
23
|
+
* @param config - The redact config, forwarded to {@link redactValue} for placeholder resolution.
|
|
24
|
+
* @returns A {@link WalkResult} containing the transformed tree, total redaction count,
|
|
25
|
+
* and the list of individual {@link RedactionMatch}es.
|
|
26
|
+
*/
|
|
27
|
+
export declare function walkAndRedact(obj: unknown, patterns: RedactPattern[], config: RedactConfig): WalkResult;
|
|
28
|
+
//# sourceMappingURL=json-walker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-walker.d.ts","sourceRoot":"","sources":["../../src/redact/json-walker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EAEb,UAAU,EACX,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,aAAa,EAAE,EACzB,MAAM,EAAE,YAAY,GACnB,UAAU,CA4FZ"}
|