@xera-ai/web 0.2.0 → 0.3.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/dist/executor/index.d.ts +1 -0
- package/dist/executor/playwright-args.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +26 -66
- package/package.json +2 -2
- package/src/executor/index.ts +2 -0
- package/src/executor/playwright-args.ts +6 -1
- package/src/index.ts +13 -1
- package/src/trace-normalizer/scrub.ts +1 -1
- package/dist/trace-normalizer/scrub-rules.d.ts +0 -11
- package/src/trace-normalizer/scrub-rules.ts +0 -69
package/dist/executor/index.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { CREDIT_CARD_RE, EMAIL_RE, EMAIL_RE_G, JWT_RE, PHONE_RE, PHONE_RE_G, SENSITIVE_BODY_KEYS, SENSITIVE_HEADERS, scrubBodyJson, scrubFreeText, scrubHeaders, } from '@xera-ai/core';
|
|
1
2
|
export * from './adapter';
|
|
2
3
|
export * from './auth-setup/define';
|
|
3
4
|
export * from './auth-setup/playwright-state';
|
|
@@ -13,5 +14,4 @@ export * from './generator/typecheck';
|
|
|
13
14
|
export * from './trace-normalizer/normalize';
|
|
14
15
|
export * from './trace-normalizer/parse';
|
|
15
16
|
export * from './trace-normalizer/scrub';
|
|
16
|
-
export * from './trace-normalizer/scrub-rules';
|
|
17
17
|
export * from './trace-normalizer/unzip';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
+
// src/index.ts
|
|
5
|
+
import {
|
|
6
|
+
CREDIT_CARD_RE,
|
|
7
|
+
EMAIL_RE,
|
|
8
|
+
EMAIL_RE_G,
|
|
9
|
+
JWT_RE,
|
|
10
|
+
PHONE_RE,
|
|
11
|
+
PHONE_RE_G,
|
|
12
|
+
SENSITIVE_BODY_KEYS,
|
|
13
|
+
SENSITIVE_HEADERS,
|
|
14
|
+
scrubBodyJson as scrubBodyJson2,
|
|
15
|
+
scrubFreeText as scrubFreeText2,
|
|
16
|
+
scrubHeaders as scrubHeaders2
|
|
17
|
+
} from "@xera-ai/core";
|
|
18
|
+
|
|
4
19
|
// src/adapter.ts
|
|
5
20
|
import { join as join3 } from "path";
|
|
6
21
|
|
|
@@ -9,7 +24,7 @@ import { join } from "path";
|
|
|
9
24
|
|
|
10
25
|
// src/executor/playwright-args.ts
|
|
11
26
|
function buildPlaywrightArgs(input) {
|
|
12
|
-
|
|
27
|
+
const args = [
|
|
13
28
|
"test",
|
|
14
29
|
input.specPath,
|
|
15
30
|
`--config=${input.configPath}`,
|
|
@@ -17,6 +32,10 @@ function buildPlaywrightArgs(input) {
|
|
|
17
32
|
`--output=${input.outputDir}`,
|
|
18
33
|
"--trace=on"
|
|
19
34
|
];
|
|
35
|
+
if (input.grep) {
|
|
36
|
+
args.push("--grep", input.grep);
|
|
37
|
+
}
|
|
38
|
+
return args;
|
|
20
39
|
}
|
|
21
40
|
|
|
22
41
|
// src/executor/index.ts
|
|
@@ -29,7 +48,8 @@ async function runPlaywright(input) {
|
|
|
29
48
|
const args = buildPlaywrightArgs({
|
|
30
49
|
specPath: input.specPath,
|
|
31
50
|
configPath: input.configPath,
|
|
32
|
-
outputDir: input.outputDir
|
|
51
|
+
outputDir: input.outputDir,
|
|
52
|
+
...input.grep && { grep: input.grep }
|
|
33
53
|
});
|
|
34
54
|
const spawn = input.spawn ?? defaultSpawn;
|
|
35
55
|
const { exitCode } = await spawn("npx", ["playwright", ...args], {
|
|
@@ -81,68 +101,8 @@ function parsePlaywrightReport(report, runId) {
|
|
|
81
101
|
};
|
|
82
102
|
}
|
|
83
103
|
|
|
84
|
-
// src/trace-normalizer/scrub-rules.ts
|
|
85
|
-
var SENSITIVE_HEADERS = [
|
|
86
|
-
"authorization",
|
|
87
|
-
"cookie",
|
|
88
|
-
"set-cookie",
|
|
89
|
-
"x-api-key",
|
|
90
|
-
"x-auth-token",
|
|
91
|
-
"x-csrf-token",
|
|
92
|
-
"proxy-authorization"
|
|
93
|
-
];
|
|
94
|
-
var SENSITIVE_BODY_KEYS = [
|
|
95
|
-
/password/i,
|
|
96
|
-
/passwd/i,
|
|
97
|
-
/token/i,
|
|
98
|
-
/secret/i,
|
|
99
|
-
/api[-_]?key/i,
|
|
100
|
-
/access[-_]?key/i,
|
|
101
|
-
/private[-_]?key/i,
|
|
102
|
-
/authorization/i,
|
|
103
|
-
/credit[-_]?card/i,
|
|
104
|
-
/card[-_]?number/i,
|
|
105
|
-
/cvv/i
|
|
106
|
-
];
|
|
107
|
-
var JWT_RE = /\beyJ[A-Za-z0-9_-]{7,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{5,}\b/;
|
|
108
|
-
var CREDIT_CARD_RE = /\b(?:\d{4}[-\s]?){3}\d{4}\b/;
|
|
109
|
-
var EMAIL_RE = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/;
|
|
110
|
-
var PHONE_RE = /(?:\+?\d[\d\s().-]{6,}\d)/;
|
|
111
|
-
var JWT_RE_G = new RegExp(JWT_RE.source, "g");
|
|
112
|
-
var CREDIT_CARD_RE_G = new RegExp(CREDIT_CARD_RE.source, "g");
|
|
113
|
-
var EMAIL_RE_G = new RegExp(EMAIL_RE.source, "g");
|
|
114
|
-
var PHONE_RE_G = new RegExp(PHONE_RE.source, "g");
|
|
115
|
-
var REDACTED = "[REDACTED]";
|
|
116
|
-
function scrubHeaders(headers) {
|
|
117
|
-
const out = {};
|
|
118
|
-
for (const [k, v] of Object.entries(headers)) {
|
|
119
|
-
out[k] = SENSITIVE_HEADERS.includes(k.toLowerCase()) ? REDACTED : v;
|
|
120
|
-
}
|
|
121
|
-
return out;
|
|
122
|
-
}
|
|
123
|
-
function scrubBodyJson(body) {
|
|
124
|
-
if (Array.isArray(body))
|
|
125
|
-
return body.map(scrubBodyJson);
|
|
126
|
-
if (body && typeof body === "object") {
|
|
127
|
-
const out = {};
|
|
128
|
-
for (const [k, v] of Object.entries(body)) {
|
|
129
|
-
if (SENSITIVE_BODY_KEYS.some((re) => re.test(k))) {
|
|
130
|
-
out[k] = REDACTED;
|
|
131
|
-
} else {
|
|
132
|
-
out[k] = scrubBodyJson(v);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return out;
|
|
136
|
-
}
|
|
137
|
-
if (typeof body === "string")
|
|
138
|
-
return scrubFreeText(body);
|
|
139
|
-
return body;
|
|
140
|
-
}
|
|
141
|
-
function scrubFreeText(s) {
|
|
142
|
-
return s.replace(JWT_RE_G, REDACTED).replace(CREDIT_CARD_RE_G, REDACTED).replace(EMAIL_RE_G, REDACTED).replace(PHONE_RE_G, REDACTED);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
104
|
// src/trace-normalizer/scrub.ts
|
|
105
|
+
import { scrubBodyJson, scrubFreeText, scrubHeaders } from "@xera-ai/core";
|
|
146
106
|
function countScrubbed(before, after) {
|
|
147
107
|
if (typeof before === "string" && typeof after === "string")
|
|
148
108
|
return before !== after ? 1 : 0;
|
|
@@ -527,9 +487,9 @@ export {
|
|
|
527
487
|
unzipTrace,
|
|
528
488
|
typecheckTicket,
|
|
529
489
|
stagePlaywrightState,
|
|
530
|
-
scrubHeaders,
|
|
531
|
-
scrubFreeText,
|
|
532
|
-
scrubBodyJson,
|
|
490
|
+
scrubHeaders2 as scrubHeaders,
|
|
491
|
+
scrubFreeText2 as scrubFreeText,
|
|
492
|
+
scrubBodyJson2 as scrubBodyJson,
|
|
533
493
|
scrub,
|
|
534
494
|
scanSharedPoms,
|
|
535
495
|
runPlaywright,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xera-ai/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@cucumber/gherkin": "39.1.0",
|
|
24
24
|
"@cucumber/messages": "32.3.1",
|
|
25
25
|
"@playwright/test": "1.60.0",
|
|
26
|
-
"@xera-ai/core": "^0.
|
|
26
|
+
"@xera-ai/core": "^0.5.0",
|
|
27
27
|
"fflate": "0.8.3"
|
|
28
28
|
}
|
|
29
29
|
}
|
package/src/executor/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface RunPlaywrightInput {
|
|
|
10
10
|
specPath: string;
|
|
11
11
|
configPath: string;
|
|
12
12
|
outputDir: string;
|
|
13
|
+
grep?: string;
|
|
13
14
|
env?: NodeJS.ProcessEnv;
|
|
14
15
|
spawn?: SpawnFn;
|
|
15
16
|
}
|
|
@@ -31,6 +32,7 @@ export async function runPlaywright(input: RunPlaywrightInput): Promise<RunPlayw
|
|
|
31
32
|
specPath: input.specPath,
|
|
32
33
|
configPath: input.configPath,
|
|
33
34
|
outputDir: input.outputDir,
|
|
35
|
+
...(input.grep && { grep: input.grep }),
|
|
34
36
|
});
|
|
35
37
|
const spawn = input.spawn ?? defaultSpawn;
|
|
36
38
|
const { exitCode } = await spawn('npx', ['playwright', ...args], {
|
|
@@ -2,10 +2,11 @@ export interface PlaywrightArgsInput {
|
|
|
2
2
|
specPath: string;
|
|
3
3
|
outputDir: string;
|
|
4
4
|
configPath: string;
|
|
5
|
+
grep?: string;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
export function buildPlaywrightArgs(input: PlaywrightArgsInput): string[] {
|
|
8
|
-
|
|
9
|
+
const args = [
|
|
9
10
|
'test',
|
|
10
11
|
input.specPath,
|
|
11
12
|
`--config=${input.configPath}`,
|
|
@@ -13,4 +14,8 @@ export function buildPlaywrightArgs(input: PlaywrightArgsInput): string[] {
|
|
|
13
14
|
`--output=${input.outputDir}`,
|
|
14
15
|
'--trace=on',
|
|
15
16
|
];
|
|
17
|
+
if (input.grep) {
|
|
18
|
+
args.push('--grep', input.grep);
|
|
19
|
+
}
|
|
20
|
+
return args;
|
|
16
21
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
CREDIT_CARD_RE,
|
|
3
|
+
EMAIL_RE,
|
|
4
|
+
EMAIL_RE_G,
|
|
5
|
+
JWT_RE,
|
|
6
|
+
PHONE_RE,
|
|
7
|
+
PHONE_RE_G,
|
|
8
|
+
SENSITIVE_BODY_KEYS,
|
|
9
|
+
SENSITIVE_HEADERS,
|
|
10
|
+
scrubBodyJson,
|
|
11
|
+
scrubFreeText,
|
|
12
|
+
scrubHeaders,
|
|
13
|
+
} from '@xera-ai/core';
|
|
1
14
|
export * from './adapter';
|
|
2
15
|
export * from './auth-setup/define';
|
|
3
16
|
export * from './auth-setup/playwright-state';
|
|
@@ -13,5 +26,4 @@ export * from './generator/typecheck';
|
|
|
13
26
|
export * from './trace-normalizer/normalize';
|
|
14
27
|
export * from './trace-normalizer/parse';
|
|
15
28
|
export * from './trace-normalizer/scrub';
|
|
16
|
-
export * from './trace-normalizer/scrub-rules';
|
|
17
29
|
export * from './trace-normalizer/unzip';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export declare const SENSITIVE_HEADERS: readonly string[];
|
|
2
|
-
export declare const SENSITIVE_BODY_KEYS: readonly RegExp[];
|
|
3
|
-
export declare const JWT_RE: RegExp;
|
|
4
|
-
export declare const CREDIT_CARD_RE: RegExp;
|
|
5
|
-
export declare const EMAIL_RE: RegExp;
|
|
6
|
-
export declare const PHONE_RE: RegExp;
|
|
7
|
-
export declare const EMAIL_RE_G: RegExp;
|
|
8
|
-
export declare const PHONE_RE_G: RegExp;
|
|
9
|
-
export declare function scrubHeaders(headers: Record<string, string>): Record<string, string>;
|
|
10
|
-
export declare function scrubBodyJson(body: unknown): unknown;
|
|
11
|
-
export declare function scrubFreeText(s: string): string;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
export const SENSITIVE_HEADERS: readonly string[] = [
|
|
2
|
-
'authorization',
|
|
3
|
-
'cookie',
|
|
4
|
-
'set-cookie',
|
|
5
|
-
'x-api-key',
|
|
6
|
-
'x-auth-token',
|
|
7
|
-
'x-csrf-token',
|
|
8
|
-
'proxy-authorization',
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
export const SENSITIVE_BODY_KEYS: readonly RegExp[] = [
|
|
12
|
-
/password/i,
|
|
13
|
-
/passwd/i,
|
|
14
|
-
/token/i,
|
|
15
|
-
/secret/i,
|
|
16
|
-
/api[-_]?key/i,
|
|
17
|
-
/access[-_]?key/i,
|
|
18
|
-
/private[-_]?key/i,
|
|
19
|
-
/authorization/i,
|
|
20
|
-
/credit[-_]?card/i,
|
|
21
|
-
/card[-_]?number/i,
|
|
22
|
-
/cvv/i,
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
export const JWT_RE = /\beyJ[A-Za-z0-9_-]{7,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{5,}\b/;
|
|
26
|
-
export const CREDIT_CARD_RE = /\b(?:\d{4}[-\s]?){3}\d{4}\b/;
|
|
27
|
-
export const EMAIL_RE = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/;
|
|
28
|
-
// E.164-ish phone with optional + and separators. Conservative: require at least 7 digits.
|
|
29
|
-
export const PHONE_RE = /(?:\+?\d[\d\s().-]{6,}\d)/;
|
|
30
|
-
|
|
31
|
-
const JWT_RE_G = new RegExp(JWT_RE.source, 'g');
|
|
32
|
-
const CREDIT_CARD_RE_G = new RegExp(CREDIT_CARD_RE.source, 'g');
|
|
33
|
-
export const EMAIL_RE_G = new RegExp(EMAIL_RE.source, 'g');
|
|
34
|
-
export const PHONE_RE_G = new RegExp(PHONE_RE.source, 'g');
|
|
35
|
-
|
|
36
|
-
const REDACTED = '[REDACTED]';
|
|
37
|
-
|
|
38
|
-
export function scrubHeaders(headers: Record<string, string>): Record<string, string> {
|
|
39
|
-
const out: Record<string, string> = {};
|
|
40
|
-
for (const [k, v] of Object.entries(headers)) {
|
|
41
|
-
out[k] = SENSITIVE_HEADERS.includes(k.toLowerCase()) ? REDACTED : v;
|
|
42
|
-
}
|
|
43
|
-
return out;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function scrubBodyJson(body: unknown): unknown {
|
|
47
|
-
if (Array.isArray(body)) return body.map(scrubBodyJson);
|
|
48
|
-
if (body && typeof body === 'object') {
|
|
49
|
-
const out: Record<string, unknown> = {};
|
|
50
|
-
for (const [k, v] of Object.entries(body)) {
|
|
51
|
-
if (SENSITIVE_BODY_KEYS.some((re) => re.test(k))) {
|
|
52
|
-
out[k] = REDACTED;
|
|
53
|
-
} else {
|
|
54
|
-
out[k] = scrubBodyJson(v);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return out;
|
|
58
|
-
}
|
|
59
|
-
if (typeof body === 'string') return scrubFreeText(body);
|
|
60
|
-
return body;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function scrubFreeText(s: string): string {
|
|
64
|
-
return s
|
|
65
|
-
.replace(JWT_RE_G, REDACTED)
|
|
66
|
-
.replace(CREDIT_CARD_RE_G, REDACTED)
|
|
67
|
-
.replace(EMAIL_RE_G, REDACTED)
|
|
68
|
-
.replace(PHONE_RE_G, REDACTED);
|
|
69
|
-
}
|