@tracelane/report 0.1.0-alpha.17 → 0.1.0-alpha.18

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 (45) hide show
  1. package/dist/_security/detectors/insecure-cookies.d.ts +4 -0
  2. package/dist/_security/detectors/insecure-cookies.d.ts.map +1 -0
  3. package/dist/_security/detectors/insecure-cookies.js +32 -0
  4. package/dist/_security/detectors/insecure-cookies.js.map +1 -0
  5. package/dist/_security/detectors/missing-headers.d.ts +4 -0
  6. package/dist/_security/detectors/missing-headers.d.ts.map +1 -0
  7. package/dist/_security/detectors/missing-headers.js +36 -0
  8. package/dist/_security/detectors/missing-headers.js.map +1 -0
  9. package/dist/_security/detectors/mixed-content.d.ts +5 -0
  10. package/dist/_security/detectors/mixed-content.d.ts.map +1 -0
  11. package/dist/_security/detectors/mixed-content.js +74 -0
  12. package/dist/_security/detectors/mixed-content.js.map +1 -0
  13. package/dist/_security/detectors/reverse-tabnabbing.d.ts +10 -0
  14. package/dist/_security/detectors/reverse-tabnabbing.d.ts.map +1 -0
  15. package/dist/_security/detectors/reverse-tabnabbing.js +44 -0
  16. package/dist/_security/detectors/reverse-tabnabbing.js.map +1 -0
  17. package/dist/_security/index.d.ts +29 -0
  18. package/dist/_security/index.d.ts.map +1 -0
  19. package/dist/_security/index.js +36 -0
  20. package/dist/_security/index.js.map +1 -0
  21. package/dist/_security/response-meta.d.ts +28 -0
  22. package/dist/_security/response-meta.d.ts.map +1 -0
  23. package/dist/_security/response-meta.js +50 -0
  24. package/dist/_security/response-meta.js.map +1 -0
  25. package/dist/_security/serialized-dom.d.ts +20 -0
  26. package/dist/_security/serialized-dom.d.ts.map +1 -0
  27. package/dist/_security/serialized-dom.js +32 -0
  28. package/dist/_security/serialized-dom.js.map +1 -0
  29. package/dist/_security/suppress.d.ts +7 -0
  30. package/dist/_security/suppress.d.ts.map +1 -0
  31. package/dist/_security/suppress.js +8 -0
  32. package/dist/_security/suppress.js.map +1 -0
  33. package/dist/build-report.d.ts +1 -1
  34. package/dist/build-report.d.ts.map +1 -1
  35. package/dist/build-report.js +1 -1
  36. package/dist/build-report.js.map +1 -1
  37. package/dist/index.d.ts +1 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/markdown.d.ts +1 -1
  40. package/dist/markdown.d.ts.map +1 -1
  41. package/dist/report-writer.d.ts +1 -1
  42. package/dist/report-writer.d.ts.map +1 -1
  43. package/dist/template.d.ts +1 -1
  44. package/dist/template.d.ts.map +1 -1
  45. package/package.json +7 -7
@@ -0,0 +1,4 @@
1
+ import type { SecurityFinding } from '../index.js';
2
+ import type { ResponseMeta } from '../response-meta.js';
3
+ export declare function detectInsecureCookies(metas: readonly ResponseMeta[]): SecurityFinding[];
4
+ //# sourceMappingURL=insecure-cookies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insecure-cookies.d.ts","sourceRoot":"","sources":["../../../src/_security/detectors/insecure-cookies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAQxD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,eAAe,EAAE,CAuBvF"}
@@ -0,0 +1,32 @@
1
+ const FLAGS = [
2
+ { key: 'secure', label: 'Secure', severity: 'medium' },
3
+ { key: 'httpOnly', label: 'HttpOnly', severity: 'low' },
4
+ { key: 'sameSite', label: 'SameSite', severity: 'low' },
5
+ ];
6
+ export function detectInsecureCookies(metas) {
7
+ const out = [];
8
+ const seen = new Set();
9
+ for (const m of metas) {
10
+ for (const c of m.setCookies) {
11
+ for (const f of FLAGS) {
12
+ if (c[f.key])
13
+ continue;
14
+ const id = `insecure-cookie:${c.name}:${f.label}`;
15
+ if (seen.has(id))
16
+ continue;
17
+ seen.add(id);
18
+ out.push({
19
+ id,
20
+ signal: 'insecure-cookie',
21
+ severity: f.severity,
22
+ title: `Cookie '${c.name}' missing ${f.label}`,
23
+ detail: `Set-Cookie '${c.name}' did not set the ${f.label} attribute.`,
24
+ evidence: `${c.name}:${f.label}`,
25
+ advisory: true,
26
+ });
27
+ }
28
+ }
29
+ }
30
+ return out;
31
+ }
32
+ //# sourceMappingURL=insecure-cookies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insecure-cookies.js","sourceRoot":"","sources":["../../../src/_security/detectors/insecure-cookies.ts"],"names":[],"mappings":"AAGA,MAAM,KAAK,GAAqF;IAC9F,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE;IACtD,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE;IACvD,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE;CACxD,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,KAA8B;IAClE,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;YAC7B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACtB,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;oBAAE,SAAS;gBACvB,MAAM,EAAE,GAAG,mBAAmB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBAClD,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBAAE,SAAS;gBAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACb,GAAG,CAAC,IAAI,CAAC;oBACP,EAAE;oBACF,MAAM,EAAE,iBAAiB;oBACzB,QAAQ,EAAE,CAAC,CAAC,QAAQ;oBACpB,KAAK,EAAE,WAAW,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,KAAK,EAAE;oBAC9C,MAAM,EAAE,eAAe,CAAC,CAAC,IAAI,qBAAqB,CAAC,CAAC,KAAK,aAAa;oBACtE,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE;oBAChC,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { SecurityFinding } from '../index.js';
2
+ import type { ResponseMeta } from '../response-meta.js';
3
+ export declare function detectMissingHeaders(metas: readonly ResponseMeta[]): SecurityFinding[];
4
+ //# sourceMappingURL=missing-headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-headers.d.ts","sourceRoot":"","sources":["../../../src/_security/detectors/missing-headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAcxD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,eAAe,EAAE,CAoBtF"}
@@ -0,0 +1,36 @@
1
+ const HEADERS = [
2
+ { name: 'content-security-policy', severity: 'high', label: 'Content-Security-Policy' },
3
+ {
4
+ name: 'strict-transport-security',
5
+ severity: 'medium',
6
+ label: 'Strict-Transport-Security (HSTS)',
7
+ },
8
+ { name: 'x-frame-options', severity: 'medium', label: 'X-Frame-Options' },
9
+ { name: 'x-content-type-options', severity: 'medium', label: 'X-Content-Type-Options' },
10
+ { name: 'referrer-policy', severity: 'low', label: 'Referrer-Policy' },
11
+ ];
12
+ export function detectMissingHeaders(metas) {
13
+ const main = metas.find((m) => m.isMainDocument);
14
+ if (!main)
15
+ return [];
16
+ // HTTPS gate: header/HSTS checks are moot + noisy on non-HTTPS (localhost/non-prod).
17
+ if (!main.url.startsWith('https://'))
18
+ return [];
19
+ const present = new Set(main.presentSecurityHeaders.map((h) => h.toLowerCase()));
20
+ const out = [];
21
+ for (const h of HEADERS) {
22
+ if (present.has(h.name))
23
+ continue;
24
+ out.push({
25
+ id: `missing-security-header:${h.name}`,
26
+ signal: 'missing-security-header',
27
+ severity: h.severity,
28
+ title: `Missing ${h.label} header`,
29
+ detail: `The main document response did not set the ${h.label} header.`,
30
+ evidence: h.name,
31
+ advisory: true,
32
+ });
33
+ }
34
+ return out;
35
+ }
36
+ //# sourceMappingURL=missing-headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-headers.js","sourceRoot":"","sources":["../../../src/_security/detectors/missing-headers.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,GAA0D;IACrE,EAAE,IAAI,EAAE,yBAAyB,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,yBAAyB,EAAE;IACvF;QACE,IAAI,EAAE,2BAA2B;QACjC,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,kCAAkC;KAC1C;IACD,EAAE,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACzE,EAAE,IAAI,EAAE,wBAAwB,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,wBAAwB,EAAE;IACvF,EAAE,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE;CACvE,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,KAA8B;IACjE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;IACjD,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,qFAAqF;IACrF,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACjF,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,2BAA2B,CAAC,CAAC,IAAI,EAAE;YACvC,MAAM,EAAE,yBAAyB;YACjC,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,KAAK,EAAE,WAAW,CAAC,CAAC,KAAK,SAAS;YAClC,MAAM,EAAE,8CAA8C,CAAC,CAAC,KAAK,UAAU;YACvE,QAAQ,EAAE,CAAC,CAAC,IAAI;YAChB,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { eventWithTime } from '@cubenest/rrweb-core';
2
+ import type { SecurityFinding } from '../index.js';
3
+ import type { ResponseMeta } from '../response-meta.js';
4
+ export declare function detectMixedContent(events: readonly eventWithTime[], metas: readonly ResponseMeta[]): SecurityFinding[];
5
+ //# sourceMappingURL=mixed-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mixed-content.d.ts","sourceRoot":"","sources":["../../../src/_security/detectors/mixed-content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA0CxD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,KAAK,EAAE,SAAS,YAAY,EAAE,GAC7B,eAAe,EAAE,CA8BnB"}
@@ -0,0 +1,74 @@
1
+ import { collectRoots, walk } from '../serialized-dom.js';
2
+ /**
3
+ * Walks rrweb serialized DOM snapshots for subresource-loading attributes that
4
+ * point at `http://` on an HTTPS page — the mixed-content risk. Re-sourced from
5
+ * the DOM (like reverse-tabnabbing) because the capture layer only emits a
6
+ * `[tracelane.sec]` meta for the MAIN DOCUMENT, so subresource URLs never reach
7
+ * the meta stream. The HTTPS gate comes from the main-document meta.
8
+ *
9
+ * Scope (kept tight to limit false positives for the MVP):
10
+ * - the `src` attribute on ANY element (img, script, iframe, video, audio,
11
+ * source, …),
12
+ * - the `href` attribute ONLY on a `<link>` whose `rel` actually fetches a
13
+ * subresource (stylesheet/preload/icon/…). A `<link rel="canonical">` or
14
+ * `<a href>` is a navigation/metadata hint, not a subresource, so it is NOT
15
+ * flagged.
16
+ * - `srcset` is not parsed.
17
+ * Dedupes by url; advisory, never an audit result.
18
+ */
19
+ // `<link rel>` values that actually fetch a resource over the wire (so an
20
+ // `http://` href is genuine mixed content). Excludes metadata/hint rels like
21
+ // canonical, alternate, author, license, and the connection-only hints
22
+ // dns-prefetch/preconnect (which establish a connection but load no content).
23
+ const SUBRESOURCE_LINK_RELS = new Set([
24
+ 'stylesheet',
25
+ 'preload',
26
+ 'modulepreload',
27
+ 'prefetch',
28
+ 'prerender',
29
+ 'icon',
30
+ 'manifest',
31
+ ]);
32
+ function linkLoadsSubresource(rel) {
33
+ if (typeof rel !== 'string')
34
+ return false;
35
+ return rel
36
+ .toLowerCase()
37
+ .split(/\s+/)
38
+ .some((token) => SUBRESOURCE_LINK_RELS.has(token));
39
+ }
40
+ export function detectMixedContent(events, metas) {
41
+ const main = metas.find((mt) => mt.isMainDocument);
42
+ // Mixed content is only meaningful on an HTTPS page.
43
+ if (!main || !main.url.startsWith('https://'))
44
+ return [];
45
+ const out = [];
46
+ const seen = new Set();
47
+ for (const root of collectRoots(events)) {
48
+ for (const n of walk(root)) {
49
+ if (n.type !== 2)
50
+ continue;
51
+ const attrs = n.attributes ?? {};
52
+ const tag = n.tagName?.toLowerCase();
53
+ const urls = [attrs.src];
54
+ if (tag === 'link' && linkLoadsSubresource(attrs.rel))
55
+ urls.push(attrs.href);
56
+ for (const u of urls) {
57
+ if (typeof u !== 'string' || !u.startsWith('http://') || seen.has(u))
58
+ continue;
59
+ seen.add(u);
60
+ out.push({
61
+ id: `mixed-content:${u}`,
62
+ signal: 'mixed-content',
63
+ severity: 'high',
64
+ title: 'Mixed content (HTTP resource on an HTTPS page)',
65
+ detail: `An HTTP resource (${u}) was loaded by the HTTPS page ${main.url}.`,
66
+ evidence: u,
67
+ advisory: true,
68
+ });
69
+ }
70
+ }
71
+ }
72
+ return out;
73
+ }
74
+ //# sourceMappingURL=mixed-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mixed-content.js","sourceRoot":"","sources":["../../../src/_security/detectors/mixed-content.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;;;;;;;;;;;;;GAgBG;AAEH,0EAA0E;AAC1E,6EAA6E;AAC7E,uEAAuE;AACvE,8EAA8E;AAC9E,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,YAAY;IACZ,SAAS;IACT,eAAe;IACf,UAAU;IACV,WAAW;IACX,MAAM;IACN,UAAU;CACX,CAAC,CAAC;AAEH,SAAS,oBAAoB,CAAC,GAAY;IACxC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC1C,OAAO,GAAG;SACP,WAAW,EAAE;SACb,KAAK,CAAC,KAAK,CAAC;SACZ,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD,CAAC;AACD,MAAM,UAAU,kBAAkB,CAChC,MAAgC,EAChC,KAA8B;IAE9B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;IACnD,qDAAqD;IACrD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,CAAC;IAEzD,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QACxC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC;gBAAE,SAAS;YAC3B,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;YACrC,MAAM,IAAI,GAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,GAAG,KAAK,MAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,GAAG,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC7E,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACrB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,SAAS;gBAC/E,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACZ,GAAG,CAAC,IAAI,CAAC;oBACP,EAAE,EAAE,iBAAiB,CAAC,EAAE;oBACxB,MAAM,EAAE,eAAe;oBACvB,QAAQ,EAAE,MAAM;oBAChB,KAAK,EAAE,gDAAgD;oBACvD,MAAM,EAAE,qBAAqB,CAAC,kCAAkC,IAAI,CAAC,GAAG,GAAG;oBAC3E,QAAQ,EAAE,CAAC;oBACX,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { eventWithTime } from '@cubenest/rrweb-core';
2
+ import type { SecurityFinding } from '../index.js';
3
+ /**
4
+ * Walks rrweb serialized DOM snapshots (FullSnapshot trees + IncrementalSnapshot
5
+ * `adds`) for `<a target="_blank">` links lacking a `rel` of `noopener`/
6
+ * `noreferrer` — the classic reverse-tabnabbing risk. Pure over plain serialized
7
+ * node objects; no DOM API. Dedupes by href; advisory, never an audit result.
8
+ */
9
+ export declare function detectReverseTabnabbing(events: readonly eventWithTime[]): SecurityFinding[];
10
+ //# sourceMappingURL=reverse-tabnabbing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reverse-tabnabbing.d.ts","sourceRoot":"","sources":["../../../src/_security/detectors/reverse-tabnabbing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AASnD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,eAAe,EAAE,CA0B3F"}
@@ -0,0 +1,44 @@
1
+ import { collectRoots, walk } from '../serialized-dom.js';
2
+ function relIsSafe(rel) {
3
+ if (typeof rel !== 'string')
4
+ return false;
5
+ const tokens = rel.toLowerCase().split(/\s+/);
6
+ return tokens.includes('noopener') || tokens.includes('noreferrer');
7
+ }
8
+ /**
9
+ * Walks rrweb serialized DOM snapshots (FullSnapshot trees + IncrementalSnapshot
10
+ * `adds`) for `<a target="_blank">` links lacking a `rel` of `noopener`/
11
+ * `noreferrer` — the classic reverse-tabnabbing risk. Pure over plain serialized
12
+ * node objects; no DOM API. Dedupes by href; advisory, never an audit result.
13
+ */
14
+ export function detectReverseTabnabbing(events) {
15
+ const roots = collectRoots(events);
16
+ const out = [];
17
+ const seen = new Set();
18
+ for (const root of roots) {
19
+ for (const n of walk(root)) {
20
+ if (n.type !== 2 || n.tagName?.toLowerCase() !== 'a')
21
+ continue;
22
+ const attrs = n.attributes ?? {};
23
+ const target = typeof attrs.target === 'string' ? attrs.target.toLowerCase() : '';
24
+ if (target !== '_blank' || relIsSafe(attrs.rel))
25
+ continue;
26
+ const href = typeof attrs.href === 'string' ? attrs.href : '(no href)';
27
+ const id = `reverse-tabnabbing:${href}`;
28
+ if (seen.has(id))
29
+ continue;
30
+ seen.add(id);
31
+ out.push({
32
+ id,
33
+ signal: 'reverse-tabnabbing',
34
+ severity: 'medium',
35
+ title: 'Reverse tabnabbing risk (target="_blank" without rel="noopener")',
36
+ detail: `An <a target="_blank"> link (${href}) is missing rel="noopener"/"noreferrer".`,
37
+ evidence: href,
38
+ advisory: true,
39
+ });
40
+ }
41
+ }
42
+ return out;
43
+ }
44
+ //# sourceMappingURL=reverse-tabnabbing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reverse-tabnabbing.js","sourceRoot":"","sources":["../../../src/_security/detectors/reverse-tabnabbing.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE1D,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AACtE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAgC;IACtE,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,GAAG;gBAAE,SAAS;YAC/D,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClF,IAAI,MAAM,KAAK,QAAQ,IAAI,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC1D,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;YACvE,MAAM,EAAE,GAAG,sBAAsB,IAAI,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,SAAS;YAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACb,GAAG,CAAC,IAAI,CAAC;gBACP,EAAE;gBACF,MAAM,EAAE,oBAAoB;gBAC5B,QAAQ,EAAE,QAAQ;gBAClB,KAAK,EAAE,kEAAkE;gBACzE,MAAM,EAAE,gCAAgC,IAAI,2CAA2C;gBACvF,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { eventWithTime } from '@cubenest/rrweb-core';
2
+ import { type Suppression } from './suppress.js';
3
+ export type { Suppression };
4
+ /** console.error prefix the capture layer uses for privacy-safe response metadata. */
5
+ export declare const SEC_CONSOLE_PREFIX = "[tracelane.sec]";
6
+ /** rrweb Custom event tag the capture layer uses for privacy-safe response metadata. */
7
+ export declare const SEC_EVENT_TAG = "tracelane.sec";
8
+ export type SecuritySignal = 'missing-security-header' | 'mixed-content' | 'insecure-cookie' | 'reverse-tabnabbing';
9
+ export type Severity = 'low' | 'medium' | 'high';
10
+ export interface SecurityFinding {
11
+ /** stable id, e.g. `${signal}:${evidence}` */
12
+ readonly id: string;
13
+ readonly signal: SecuritySignal;
14
+ readonly severity: Severity;
15
+ readonly title: string;
16
+ readonly detail: string;
17
+ readonly evidence: string;
18
+ /** framing invariant — always true; these are advisory, not audit results */
19
+ readonly advisory: true;
20
+ }
21
+ /**
22
+ * Derive advisory security-hygiene findings from a captured event stream.
23
+ * Pure + total: never throws (a failing detector contributes nothing). Findings
24
+ * are advisory only — NOT a security audit/scan/guarantee.
25
+ */
26
+ export declare function analyze(events: readonly eventWithTime[], opts?: {
27
+ suppress?: readonly Suppression[];
28
+ }): SecurityFinding[];
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/_security/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAO1D,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,eAAe,CAAC;AAEpE,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B,sFAAsF;AACtF,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AAEpD,wFAAwF;AACxF,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,MAAM,MAAM,cAAc,GACtB,yBAAyB,GACzB,eAAe,GACf,iBAAiB,GACjB,oBAAoB,CAAC;AAEzB,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;CACzB;AAYD;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;CAAO,GAC/C,eAAe,EAAE,CAanB"}
@@ -0,0 +1,36 @@
1
+ import { detectInsecureCookies } from './detectors/insecure-cookies.js';
2
+ import { detectMissingHeaders } from './detectors/missing-headers.js';
3
+ import { detectMixedContent } from './detectors/mixed-content.js';
4
+ import { detectReverseTabnabbing } from './detectors/reverse-tabnabbing.js';
5
+ import { scrapeResponseMeta } from './response-meta.js';
6
+ import { applySuppressions } from './suppress.js';
7
+ /** console.error prefix the capture layer uses for privacy-safe response metadata. */
8
+ export const SEC_CONSOLE_PREFIX = '[tracelane.sec]';
9
+ /** rrweb Custom event tag the capture layer uses for privacy-safe response metadata. */
10
+ export const SEC_EVENT_TAG = 'tracelane.sec';
11
+ const SEVERITY_RANK = { high: 0, medium: 1, low: 2 };
12
+ function safe(fn, fallback) {
13
+ try {
14
+ return fn();
15
+ }
16
+ catch {
17
+ return fallback;
18
+ }
19
+ }
20
+ /**
21
+ * Derive advisory security-hygiene findings from a captured event stream.
22
+ * Pure + total: never throws (a failing detector contributes nothing). Findings
23
+ * are advisory only — NOT a security audit/scan/guarantee.
24
+ */
25
+ export function analyze(events, opts = {}) {
26
+ const metas = safe(() => scrapeResponseMeta(events), []);
27
+ const findings = [
28
+ ...safe(() => detectMissingHeaders(metas), []),
29
+ ...safe(() => detectMixedContent(events, metas), []),
30
+ ...safe(() => detectInsecureCookies(metas), []),
31
+ ...safe(() => detectReverseTabnabbing(events), []),
32
+ ];
33
+ const kept = applySuppressions(findings, opts.suppress ?? []);
34
+ return [...kept].sort((a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity] || a.signal.localeCompare(b.signal));
35
+ }
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/_security/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAE5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAoB,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAIpE,sFAAsF;AACtF,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAEpD,wFAAwF;AACxF,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAsB7C,MAAM,aAAa,GAA6B,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAE/E,SAAS,IAAI,CAAI,EAAW,EAAE,QAAW;IACvC,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CACrB,MAAgC,EAChC,OAA8C,EAAE;IAEhD,MAAM,KAAK,GAAG,IAAI,CAAiB,GAAG,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAsB;QAClC,GAAG,IAAI,CAAoB,GAAG,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QACjE,GAAG,IAAI,CAAoB,GAAG,EAAE,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;QACvE,GAAG,IAAI,CAAoB,GAAG,EAAE,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QAClE,GAAG,IAAI,CAAoB,GAAG,EAAE,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;KACtE,CAAC;IACF,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CACnB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAC5F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { eventWithTime } from '@cubenest/rrweb-core';
2
+ /**
3
+ * Privacy-safe response metadata recovered from a `tracelane.sec` Custom event.
4
+ * Carries only header NAMES (never values), per-cookie flag presence
5
+ * booleans, and the cookie name — never header values or cookie values.
6
+ */
7
+ export interface ResponseMeta {
8
+ url: string;
9
+ status: number;
10
+ isMainDocument: boolean;
11
+ /** lowercased header NAMES that were present (never values) */
12
+ presentSecurityHeaders: string[];
13
+ /** per-cookie flag presence (never names/values beyond the cookie name) */
14
+ setCookies: {
15
+ name: string;
16
+ secure: boolean;
17
+ httpOnly: boolean;
18
+ sameSite: boolean;
19
+ }[];
20
+ }
21
+ /**
22
+ * Read privacy-safe response metadata out of the rrweb Custom events the
23
+ * capture layer injects (tag `tracelane.sec`, payload = the meta object).
24
+ * Replaces the old console-scrape channel, which raced navigation. Malformed
25
+ * payloads are skipped.
26
+ */
27
+ export declare function scrapeResponseMeta(events: readonly eventWithTime[]): ResponseMeta[];
28
+ //# sourceMappingURL=response-meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-meta.d.ts","sourceRoot":"","sources":["../../src/_security/response-meta.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,+DAA+D;IAC/D,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,2EAA2E;IAC3E,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CACvF;AAkCD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,YAAY,EAAE,CASnF"}
@@ -0,0 +1,50 @@
1
+ import { EventType } from '@cubenest/rrweb-core';
2
+ import { SEC_EVENT_TAG } from './index.js';
3
+ function isCookieFlags(c) {
4
+ if (!c || typeof c !== 'object')
5
+ return false;
6
+ const k = c;
7
+ return (typeof k.name === 'string' &&
8
+ typeof k.secure === 'boolean' &&
9
+ typeof k.httpOnly === 'boolean' &&
10
+ typeof k.sameSite === 'boolean');
11
+ }
12
+ /**
13
+ * Full structural validation of a `tracelane.sec` Custom-event payload, including
14
+ * array ELEMENT types. A page can't forge a Node-side Custom event, but a
15
+ * shape-malformed object (e.g. `presentSecurityHeaders: [123]` or
16
+ * `setCookies: [{}]`) must still be rejected to honor the "malformed payloads
17
+ * are skipped" contract and protect downstream consumers from runtime errors.
18
+ */
19
+ function isResponseMeta(parsed) {
20
+ if (!parsed || typeof parsed !== 'object')
21
+ return false;
22
+ const m = parsed;
23
+ return (typeof m.url === 'string' &&
24
+ typeof m.status === 'number' &&
25
+ typeof m.isMainDocument === 'boolean' &&
26
+ Array.isArray(m.presentSecurityHeaders) &&
27
+ m.presentSecurityHeaders.every((h) => typeof h === 'string') &&
28
+ Array.isArray(m.setCookies) &&
29
+ m.setCookies.every(isCookieFlags));
30
+ }
31
+ /**
32
+ * Read privacy-safe response metadata out of the rrweb Custom events the
33
+ * capture layer injects (tag `tracelane.sec`, payload = the meta object).
34
+ * Replaces the old console-scrape channel, which raced navigation. Malformed
35
+ * payloads are skipped.
36
+ */
37
+ export function scrapeResponseMeta(events) {
38
+ const out = [];
39
+ for (const e of events) {
40
+ if (e.type !== EventType.Custom)
41
+ continue;
42
+ const data = e.data;
43
+ if (data.tag !== SEC_EVENT_TAG)
44
+ continue;
45
+ if (isResponseMeta(data.payload))
46
+ out.push(data.payload);
47
+ }
48
+ return out;
49
+ }
50
+ //# sourceMappingURL=response-meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-meta.js","sourceRoot":"","sources":["../../src/_security/response-meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAiB3C,SAAS,aAAa,CAAC,CAAU;IAC/B,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9C,MAAM,CAAC,GAAG,CAA4B,CAAC;IACvC,OAAO,CACL,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;QAC1B,OAAO,CAAC,CAAC,MAAM,KAAK,SAAS;QAC7B,OAAO,CAAC,CAAC,QAAQ,KAAK,SAAS;QAC/B,OAAO,CAAC,CAAC,QAAQ,KAAK,SAAS,CAChC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,MAAe;IACrC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACxD,MAAM,CAAC,GAAG,MAAiC,CAAC;IAC5C,OAAO,CACL,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ;QACzB,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAC5B,OAAO,CAAC,CAAC,cAAc,KAAK,SAAS;QACrC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC;QACvC,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QAC5D,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;QAC3B,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAClC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAgC;IACjE,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,MAAM;YAAE,SAAS;QAC1C,MAAM,IAAI,GAAG,CAAC,CAAC,IAA4C,CAAC;QAC5D,IAAI,IAAI,CAAC,GAAG,KAAK,aAAa;YAAE,SAAS;QACzC,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { eventWithTime } from '@cubenest/rrweb-core';
2
+ /**
3
+ * Minimal shape of an rrweb serialized DOM node. `type === 2` is an Element.
4
+ * Pure plain-object view — no DOM API, no rrweb internals beyond this shape.
5
+ */
6
+ export interface SNode {
7
+ type?: number;
8
+ tagName?: string;
9
+ attributes?: Record<string, unknown>;
10
+ childNodes?: SNode[];
11
+ }
12
+ /** Depth-first walk: yields `node`, then recurses into `childNodes`. */
13
+ export declare function walk(node: SNode | undefined): Generator<SNode>;
14
+ /**
15
+ * Collect serialized-DOM roots from a captured event stream: the `data.node`
16
+ * tree of each FullSnapshot plus each `data.adds[].node` from an
17
+ * IncrementalSnapshot mutation. Shared by the DOM-walking detectors.
18
+ */
19
+ export declare function collectRoots(events: readonly eventWithTime[]): SNode[];
20
+ //# sourceMappingURL=serialized-dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialized-dom.d.ts","sourceRoot":"","sources":["../../src/_security/serialized-dom.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC;CACtB;AAED,wEAAwE;AACxE,wBAAiB,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAI/D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,KAAK,EAAE,CAatE"}
@@ -0,0 +1,32 @@
1
+ import { EventType } from '@cubenest/rrweb-core';
2
+ /** Depth-first walk: yields `node`, then recurses into `childNodes`. */
3
+ export function* walk(node) {
4
+ if (!node)
5
+ return;
6
+ yield node;
7
+ for (const child of node.childNodes ?? [])
8
+ yield* walk(child);
9
+ }
10
+ /**
11
+ * Collect serialized-DOM roots from a captured event stream: the `data.node`
12
+ * tree of each FullSnapshot plus each `data.adds[].node` from an
13
+ * IncrementalSnapshot mutation. Shared by the DOM-walking detectors.
14
+ */
15
+ export function collectRoots(events) {
16
+ const roots = [];
17
+ for (const e of events) {
18
+ if (e.type === EventType.FullSnapshot) {
19
+ roots.push(e.data.node);
20
+ }
21
+ else if (e.type === EventType.IncrementalSnapshot) {
22
+ const adds = e.data.adds;
23
+ if (Array.isArray(adds)) {
24
+ for (const a of adds)
25
+ if (a.node)
26
+ roots.push(a.node);
27
+ }
28
+ }
29
+ }
30
+ return roots;
31
+ }
32
+ //# sourceMappingURL=serialized-dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialized-dom.js","sourceRoot":"","sources":["../../src/_security/serialized-dom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAcjD,wEAAwE;AACxE,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,IAAuB;IAC3C,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,MAAM,IAAI,CAAC;IACX,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,IAAI,EAAE;QAAE,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAgC;IAC3D,MAAM,KAAK,GAAY,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,YAAY,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAE,CAAC,CAAC,IAAwB,CAAC,IAAI,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,mBAAmB,EAAE,CAAC;YACpD,MAAM,IAAI,GAAI,CAAC,CAAC,IAAsC,CAAC,IAAI,CAAC;YAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,KAAK,MAAM,CAAC,IAAI,IAAI;oBAAE,IAAI,CAAC,CAAC,IAAI;wBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { SecurityFinding, SecuritySignal } from './index.js';
2
+ export interface Suppression {
3
+ signal?: SecuritySignal;
4
+ evidence?: string;
5
+ }
6
+ export declare function applySuppressions(findings: readonly SecurityFinding[], rules: readonly Suppression[]): SecurityFinding[];
7
+ //# sourceMappingURL=suppress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suppress.d.ts","sourceRoot":"","sources":["../../src/_security/suppress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,eAAe,EAAE,EACpC,KAAK,EAAE,SAAS,WAAW,EAAE,GAC5B,eAAe,EAAE,CAWnB"}
@@ -0,0 +1,8 @@
1
+ export function applySuppressions(findings, rules) {
2
+ if (rules.length === 0)
3
+ return [...findings];
4
+ return findings.filter((f) => !rules.some((r) => (r.signal !== undefined || r.evidence !== undefined) &&
5
+ (r.signal === undefined || r.signal === f.signal) &&
6
+ (r.evidence === undefined || r.evidence === f.evidence)));
7
+ }
8
+ //# sourceMappingURL=suppress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suppress.js","sourceRoot":"","sources":["../../src/_security/suppress.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,iBAAiB,CAC/B,QAAoC,EACpC,KAA6B;IAE7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;IAC7C,OAAO,QAAQ,CAAC,MAAM,CACpB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,KAAK,CAAC,IAAI,CACT,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC;QACpD,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAC;QACjD,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC,CAC1D,CACJ,CAAC;AACJ,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { eventWithTime } from '@cubenest/rrweb-core';
2
- import type { Suppression } from '@tracelane/security';
2
+ import type { Suppression } from './_security/index.js';
3
3
  import type { ReportMeta } from './types.js';
4
4
  /** Options for {@link buildReport}. */
5
5
  export interface BuildReportOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"build-report.d.ts","sourceRoot":"","sources":["../src/build-report.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,WAAW,EAAE,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EAAE,EACvB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CA6CR"}
1
+ {"version":3,"file":"build-report.d.ts","sourceRoot":"","sources":["../src/build-report.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAMzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,WAAW,EAAE,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EAAE,EACvB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CA6CR"}
@@ -14,7 +14,7 @@
14
14
  // exceeds the 25 MB budget (ADR-0005); the report renders a banner when a prune
15
15
  // fired so the truncation is visible to the user.
16
16
  import { pruneToSizeBudget } from '@tracelane/core';
17
- import { analyze } from '@tracelane/security';
17
+ import { analyze } from './_security/index.js';
18
18
  import { encodeEventsBlob } from './embed.js';
19
19
  import { buildMarkdown, extractActionLog } from './markdown.js';
20
20
  import { resolveCiMetadata } from './metadata.js';
@@ -1 +1 @@
1
- {"version":3,"file":"build-report.js","sourceRoot":"","sources":["../src/build-report.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,yEAAyE;AACzE,8EAA8E;AAC9E,wCAAwC;AACxC,yEAAyE;AACzE,gEAAgE;AAChE,iEAAiE;AACjE,iEAAiE;AACjE,iEAAiE;AACjE,iDAAiD;AACjD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,kDAAkD;AAGlD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AA8BjD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,MAAuB,EACvB,IAAgB,EAChB,UAA8B,EAAE;IAEhC,MAAM,EACJ,iBAAiB,GAAG,IAAI,EACxB,MAAM,GAAG,IAAI,EACb,QAAQ,GAAG,IAAI,EACf,gBAAgB,GAAG,EAAE,GACtB,GAAG,OAAO,CAAC;IAEZ,2EAA2E;IAC3E,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,iBAAiB;QACjD,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC;QAC3B,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAE9B,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxC,sEAAsE;IACtE,0EAA0E;IAC1E,MAAM,gBAAgB,GAAsB,QAAQ;QAClD,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAChD,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,QAAQ,GAAG,aAAa,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAElG,yEAAyE;IACzE,uEAAuE;IACvE,oEAAoE;IACpE,qEAAqE;IACrE,gEAAgE;IAChE,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,SAAS,IAAI,CAAC,CAAC;IAEvD,OAAO,gBAAgB,CAAC;QACtB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,gBAAgB,CAAC,KAAK,CAAC;QACpC,OAAO,EAAE,WAAW;QACpB,OAAO,EAAE,WAAW;QACpB,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ;QACR,MAAM;QACN,UAAU,EAAE,KAAK,CAAC,MAAM;QACxB,OAAO;QACP,MAAM;QACN,MAAM;KACP,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"build-report.js","sourceRoot":"","sources":["../src/build-report.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,yEAAyE;AACzE,8EAA8E;AAC9E,wCAAwC;AACxC,yEAAyE;AACzE,gEAAgE;AAChE,iEAAiE;AACjE,iEAAiE;AACjE,iEAAiE;AACjE,iDAAiD;AACjD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,kDAAkD;AAGlD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AA8BjD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,MAAuB,EACvB,IAAgB,EAChB,UAA8B,EAAE;IAEhC,MAAM,EACJ,iBAAiB,GAAG,IAAI,EACxB,MAAM,GAAG,IAAI,EACb,QAAQ,GAAG,IAAI,EACf,gBAAgB,GAAG,EAAE,GACtB,GAAG,OAAO,CAAC;IAEZ,2EAA2E;IAC3E,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,iBAAiB;QACjD,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC;QAC3B,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAE9B,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxC,sEAAsE;IACtE,0EAA0E;IAC1E,MAAM,gBAAgB,GAAsB,QAAQ;QAClD,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAChD,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,QAAQ,GAAG,aAAa,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAElG,yEAAyE;IACzE,uEAAuE;IACvE,oEAAoE;IACpE,qEAAqE;IACrE,gEAAgE;IAChE,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,SAAS,IAAI,CAAC,CAAC;IAEvD,OAAO,gBAAgB,CAAC;QACtB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,gBAAgB,CAAC,KAAK,CAAC;QACpC,OAAO,EAAE,WAAW;QACpB,OAAO,EAAE,WAAW;QACpB,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ;QACR,MAAM;QACN,UAAU,EAAE,KAAK,CAAC,MAAM;QACxB,OAAO;QACP,MAAM;QACN,MAAM;KACP,CAAC,CAAC;AACL,CAAC"}
package/dist/index.d.ts CHANGED
@@ -9,4 +9,5 @@ export type { ConsoleEntry, NetworkEntry } from './panels.js';
9
9
  export { resolveCiMetadata } from './metadata.js';
10
10
  export { buildMarkdown, extractActionLog, MAX_CONSOLE_MESSAGES, MAX_ACTIONS } from './markdown.js';
11
11
  export type { ActionEntry } from './markdown.js';
12
+ export type { SecurityFinding, Severity, SecuritySignal, Suppression } from './_security/index.js';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIrE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpF,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGhE,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACnG,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIrE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpF,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGhE,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACnG,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAKjD,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { eventWithTime } from '@cubenest/rrweb-core';
2
- import type { SecurityFinding } from '@tracelane/security';
2
+ import type { SecurityFinding } from './_security/index.js';
3
3
  import type { ConsoleEntry, NetworkEntry } from './panels.js';
4
4
  import type { ReportMeta } from './types.js';
5
5
  /** Max console messages included in the prompt (P1 PRD §F.3: "last 30"). */
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,uEAAuE;AACvE,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAqBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,WAAW,EAAE,CAsBhF;AAMD,+CAA+C;AAC/C,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,WAAW,EAAE,SAAS,YAAY,EAAE,EACpC,WAAW,EAAE,SAAS,YAAY,EAAE,EACpC,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,gBAAgB,GAAE,SAAS,eAAe,EAAO,GAChD,MAAM,CAuDR"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,uEAAuE;AACvE,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAqBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,WAAW,EAAE,CAsBhF;AAMD,+CAA+C;AAC/C,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,WAAW,EAAE,SAAS,YAAY,EAAE,EACpC,WAAW,EAAE,SAAS,YAAY,EAAE,EACpC,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,gBAAgB,GAAE,SAAS,eAAe,EAAO,GAChD,MAAM,CAuDR"}
@@ -1,5 +1,5 @@
1
1
  import type { eventWithTime } from '@cubenest/rrweb-core';
2
- import type { Suppression } from '@tracelane/security';
2
+ import type { Suppression } from './_security/index.js';
3
3
  import type { ReportMeta } from './types.js';
4
4
  /** Inputs for {@link writeReport}. */
5
5
  export interface WriteReportInput {
@@ -1 +1 @@
1
- {"version":3,"file":"report-writer.d.ts","sourceRoot":"","sources":["../src/report-writer.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,sCAAsC;AACtC,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,qHAAqH;IACrH,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,mCAAmC;IACnC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,kEAAkE;IAClE,IAAI,EAAE,UAAU,CAAC;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO7C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAa3D"}
1
+ {"version":3,"file":"report-writer.d.ts","sourceRoot":"","sources":["../src/report-writer.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,sCAAsC;AACtC,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,qHAAqH;IACrH,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,mCAAmC;IACnC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,kEAAkE;IAClE,IAAI,EAAE,UAAU,CAAC;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO7C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAa3D"}
@@ -1,4 +1,4 @@
1
- import type { SecurityFinding } from '@tracelane/security';
1
+ import type { SecurityFinding } from './_security/index.js';
2
2
  import type { ConsoleEntry, NetworkEntry } from './panels.js';
3
3
  import type { ReportMeta } from './types.js';
4
4
  /** Everything `renderReportHtml` needs; build-report.ts prepares it. */
@@ -1 +1 @@
1
- {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAW3D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,wEAAwE;AACxE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,CAAC;IACjB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,gDAAgD;IAChD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB;;;;OAIG;IACH,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,OAAO,CAAC;IAChB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB;yEACqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA86BD,qDAAqD;AACrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAqJjE"}
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAW5D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,wEAAwE;AACxE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,CAAC;IACjB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,gDAAgD;IAChD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB;;;;OAIG;IACH,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,OAAO,CAAC;IAChB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB;yEACqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA86BD,qDAAqD;AACrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAqJjE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tracelane/report",
3
- "version": "0.1.0-alpha.17",
3
+ "version": "0.1.0-alpha.18",
4
4
  "description": "Self-contained, offline HTML report builder for tracelane. Embeds the rrweb player and a gzipped event blob into a single .html file.",
5
5
  "keywords": [
6
6
  "tracelane",
@@ -35,11 +35,11 @@
35
35
  "fflate": "^0.8.2",
36
36
  "rrweb-player": "1.0.0-alpha.4",
37
37
  "@cubenest/rrweb-core": "0.1.0-alpha.6",
38
- "@tracelane/core": "0.1.0-alpha.15",
39
- "@tracelane/security": "0.1.0-alpha.1"
38
+ "@tracelane/core": "0.1.0-alpha.15"
40
39
  },
41
40
  "devDependencies": {
42
- "jsdom": "^25.0.1"
41
+ "jsdom": "^25.0.1",
42
+ "@tracelane/security": "0.1.0-alpha.1"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public",
@@ -58,8 +58,8 @@
58
58
  "node": ">=22"
59
59
  },
60
60
  "scripts": {
61
- "build": "tsc -p tsconfig.json",
62
- "typecheck": "tsc -p tsconfig.json --noEmit",
63
- "test": "vitest run --passWithNoTests"
61
+ "build": "node scripts/vendor-security.mjs && tsc -p tsconfig.json",
62
+ "typecheck": "node scripts/vendor-security.mjs && tsc -p tsconfig.json --noEmit",
63
+ "test": "node scripts/vendor-security.mjs && vitest run --passWithNoTests"
64
64
  }
65
65
  }