insa-check-core 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.
Files changed (258) hide show
  1. package/LICENSE +24 -0
  2. package/dist/annex-b.d.ts +6 -0
  3. package/dist/annex-b.d.ts.map +1 -0
  4. package/dist/annex-b.js +152 -0
  5. package/dist/annex-b.js.map +1 -0
  6. package/dist/checks/content/page.d.ts +7 -0
  7. package/dist/checks/content/page.d.ts.map +1 -0
  8. package/dist/checks/content/page.js +133 -0
  9. package/dist/checks/content/page.js.map +1 -0
  10. package/dist/checks/cookies/cookie-flags.d.ts +3 -0
  11. package/dist/checks/cookies/cookie-flags.d.ts.map +1 -0
  12. package/dist/checks/cookies/cookie-flags.js +41 -0
  13. package/dist/checks/cookies/cookie-flags.js.map +1 -0
  14. package/dist/checks/cookies/cookie-scope.d.ts +6 -0
  15. package/dist/checks/cookies/cookie-scope.d.ts.map +1 -0
  16. package/dist/checks/cookies/cookie-scope.js +60 -0
  17. package/dist/checks/cookies/cookie-scope.js.map +1 -0
  18. package/dist/checks/deployment/server-banner.d.ts +4 -0
  19. package/dist/checks/deployment/server-banner.d.ts.map +1 -0
  20. package/dist/checks/deployment/server-banner.js +60 -0
  21. package/dist/checks/deployment/server-banner.js.map +1 -0
  22. package/dist/checks/deployment/trace.d.ts +3 -0
  23. package/dist/checks/deployment/trace.d.ts.map +1 -0
  24. package/dist/checks/deployment/trace.js +30 -0
  25. package/dist/checks/deployment/trace.js.map +1 -0
  26. package/dist/checks/headers/clickjacking.d.ts +5 -0
  27. package/dist/checks/headers/clickjacking.d.ts.map +1 -0
  28. package/dist/checks/headers/clickjacking.js +57 -0
  29. package/dist/checks/headers/clickjacking.js.map +1 -0
  30. package/dist/checks/headers/content-type-options.d.ts +3 -0
  31. package/dist/checks/headers/content-type-options.d.ts.map +1 -0
  32. package/dist/checks/headers/content-type-options.js +17 -0
  33. package/dist/checks/headers/content-type-options.js.map +1 -0
  34. package/dist/checks/headers/cors.d.ts +4 -0
  35. package/dist/checks/headers/cors.d.ts.map +1 -0
  36. package/dist/checks/headers/cors.js +38 -0
  37. package/dist/checks/headers/cors.js.map +1 -0
  38. package/dist/checks/html.d.ts +11 -0
  39. package/dist/checks/html.d.ts.map +1 -0
  40. package/dist/checks/html.js +30 -0
  41. package/dist/checks/html.js.map +1 -0
  42. package/dist/checks/index.d.ts +7 -0
  43. package/dist/checks/index.d.ts.map +1 -0
  44. package/dist/checks/index.js +48 -0
  45. package/dist/checks/index.js.map +1 -0
  46. package/dist/checks/info-disclosure/directory-listing.d.ts +6 -0
  47. package/dist/checks/info-disclosure/directory-listing.d.ts.map +1 -0
  48. package/dist/checks/info-disclosure/directory-listing.js +60 -0
  49. package/dist/checks/info-disclosure/directory-listing.js.map +1 -0
  50. package/dist/checks/info-disclosure/exposed-files.d.ts +4 -0
  51. package/dist/checks/info-disclosure/exposed-files.d.ts.map +1 -0
  52. package/dist/checks/info-disclosure/exposed-files.js +56 -0
  53. package/dist/checks/info-disclosure/exposed-files.js.map +1 -0
  54. package/dist/checks/info-disclosure/more.d.ts +8 -0
  55. package/dist/checks/info-disclosure/more.d.ts.map +1 -0
  56. package/dist/checks/info-disclosure/more.js +186 -0
  57. package/dist/checks/info-disclosure/more.js.map +1 -0
  58. package/dist/checks/tls/certificate.d.ts +3 -0
  59. package/dist/checks/tls/certificate.d.ts.map +1 -0
  60. package/dist/checks/tls/certificate.js +49 -0
  61. package/dist/checks/tls/certificate.js.map +1 -0
  62. package/dist/checks/tls/hsts.d.ts +5 -0
  63. package/dist/checks/tls/hsts.d.ts.map +1 -0
  64. package/dist/checks/tls/hsts.js +35 -0
  65. package/dist/checks/tls/hsts.js.map +1 -0
  66. package/dist/checks/tls/https-redirect.d.ts +3 -0
  67. package/dist/checks/tls/https-redirect.d.ts.map +1 -0
  68. package/dist/checks/tls/https-redirect.js +46 -0
  69. package/dist/checks/tls/https-redirect.js.map +1 -0
  70. package/dist/checks/tls/legacy-protocols.d.ts +3 -0
  71. package/dist/checks/tls/legacy-protocols.d.ts.map +1 -0
  72. package/dist/checks/tls/legacy-protocols.js +27 -0
  73. package/dist/checks/tls/legacy-protocols.js.map +1 -0
  74. package/dist/checks/util.d.ts +22 -0
  75. package/dist/checks/util.d.ts.map +1 -0
  76. package/dist/checks/util.js +63 -0
  77. package/dist/checks/util.js.map +1 -0
  78. package/dist/code/checks/crypto.d.ts +5 -0
  79. package/dist/code/checks/crypto.d.ts.map +1 -0
  80. package/dist/code/checks/crypto.js +100 -0
  81. package/dist/code/checks/crypto.js.map +1 -0
  82. package/dist/code/checks/django.d.ts +14 -0
  83. package/dist/code/checks/django.d.ts.map +1 -0
  84. package/dist/code/checks/django.js +313 -0
  85. package/dist/code/checks/django.js.map +1 -0
  86. package/dist/code/checks/flask.d.ts +6 -0
  87. package/dist/code/checks/flask.d.ts.map +1 -0
  88. package/dist/code/checks/flask.js +100 -0
  89. package/dist/code/checks/flask.js.map +1 -0
  90. package/dist/code/checks/index.d.ts +9 -0
  91. package/dist/code/checks/index.d.ts.map +1 -0
  92. package/dist/code/checks/index.js +126 -0
  93. package/dist/code/checks/index.js.map +1 -0
  94. package/dist/code/checks/injection.d.ts +27 -0
  95. package/dist/code/checks/injection.d.ts.map +1 -0
  96. package/dist/code/checks/injection.js +189 -0
  97. package/dist/code/checks/injection.js.map +1 -0
  98. package/dist/code/checks/javascript-config.d.ts +14 -0
  99. package/dist/code/checks/javascript-config.d.ts.map +1 -0
  100. package/dist/code/checks/javascript-config.js +251 -0
  101. package/dist/code/checks/javascript-config.js.map +1 -0
  102. package/dist/code/checks/javascript.d.ts +34 -0
  103. package/dist/code/checks/javascript.d.ts.map +1 -0
  104. package/dist/code/checks/javascript.js +333 -0
  105. package/dist/code/checks/javascript.js.map +1 -0
  106. package/dist/code/checks/php.d.ts +27 -0
  107. package/dist/code/checks/php.d.ts.map +1 -0
  108. package/dist/code/checks/php.js +433 -0
  109. package/dist/code/checks/php.js.map +1 -0
  110. package/dist/code/checks/secrets.d.ts +10 -0
  111. package/dist/code/checks/secrets.d.ts.map +1 -0
  112. package/dist/code/checks/secrets.js +140 -0
  113. package/dist/code/checks/secrets.js.map +1 -0
  114. package/dist/code/checks/shared.d.ts +25 -0
  115. package/dist/code/checks/shared.d.ts.map +1 -0
  116. package/dist/code/checks/shared.js +57 -0
  117. package/dist/code/checks/shared.js.map +1 -0
  118. package/dist/code/checks/treesitter.d.ts +15 -0
  119. package/dist/code/checks/treesitter.d.ts.map +1 -0
  120. package/dist/code/checks/treesitter.js +322 -0
  121. package/dist/code/checks/treesitter.js.map +1 -0
  122. package/dist/code/checks/xml.d.ts +9 -0
  123. package/dist/code/checks/xml.d.ts.map +1 -0
  124. package/dist/code/checks/xml.js +78 -0
  125. package/dist/code/checks/xml.js.map +1 -0
  126. package/dist/code/context.d.ts +6 -0
  127. package/dist/code/context.d.ts.map +1 -0
  128. package/dist/code/context.js +92 -0
  129. package/dist/code/context.js.map +1 -0
  130. package/dist/code/detect.d.ts +3 -0
  131. package/dist/code/detect.d.ts.map +1 -0
  132. package/dist/code/detect.js +118 -0
  133. package/dist/code/detect.js.map +1 -0
  134. package/dist/code/django/settings.d.ts +46 -0
  135. package/dist/code/django/settings.d.ts.map +1 -0
  136. package/dist/code/django/settings.js +154 -0
  137. package/dist/code/django/settings.js.map +1 -0
  138. package/dist/code/findings.d.ts +18 -0
  139. package/dist/code/findings.d.ts.map +1 -0
  140. package/dist/code/findings.js +63 -0
  141. package/dist/code/findings.js.map +1 -0
  142. package/dist/code/javascript/ast.d.ts +46 -0
  143. package/dist/code/javascript/ast.d.ts.map +1 -0
  144. package/dist/code/javascript/ast.js +166 -0
  145. package/dist/code/javascript/ast.js.map +1 -0
  146. package/dist/code/javascript/index.d.ts +3 -0
  147. package/dist/code/javascript/index.d.ts.map +1 -0
  148. package/dist/code/javascript/index.js +3 -0
  149. package/dist/code/javascript/index.js.map +1 -0
  150. package/dist/code/javascript/module.d.ts +59 -0
  151. package/dist/code/javascript/module.d.ts.map +1 -0
  152. package/dist/code/javascript/module.js +250 -0
  153. package/dist/code/javascript/module.js.map +1 -0
  154. package/dist/code/php/index.d.ts +92 -0
  155. package/dist/code/php/index.d.ts.map +1 -0
  156. package/dist/code/php/index.js +316 -0
  157. package/dist/code/php/index.js.map +1 -0
  158. package/dist/code/project.d.ts +13 -0
  159. package/dist/code/project.d.ts.map +1 -0
  160. package/dist/code/project.js +69 -0
  161. package/dist/code/project.js.map +1 -0
  162. package/dist/code/python/ast.d.ts +47 -0
  163. package/dist/code/python/ast.d.ts.map +1 -0
  164. package/dist/code/python/ast.js +193 -0
  165. package/dist/code/python/ast.js.map +1 -0
  166. package/dist/code/python/index.d.ts +3 -0
  167. package/dist/code/python/index.d.ts.map +1 -0
  168. package/dist/code/python/index.js +3 -0
  169. package/dist/code/python/index.js.map +1 -0
  170. package/dist/code/python/module.d.ts +55 -0
  171. package/dist/code/python/module.d.ts.map +1 -0
  172. package/dist/code/python/module.js +215 -0
  173. package/dist/code/python/module.js.map +1 -0
  174. package/dist/code/scan.d.ts +24 -0
  175. package/dist/code/scan.d.ts.map +1 -0
  176. package/dist/code/scan.js +159 -0
  177. package/dist/code/scan.js.map +1 -0
  178. package/dist/code/treesitter/index.d.ts +83 -0
  179. package/dist/code/treesitter/index.d.ts.map +1 -0
  180. package/dist/code/treesitter/index.js +243 -0
  181. package/dist/code/treesitter/index.js.map +1 -0
  182. package/dist/code/types.d.ts +48 -0
  183. package/dist/code/types.d.ts.map +1 -0
  184. package/dist/code/types.js +2 -0
  185. package/dist/code/types.js.map +1 -0
  186. package/dist/content/en.d.ts +3 -0
  187. package/dist/content/en.d.ts.map +1 -0
  188. package/dist/content/en.js +722 -0
  189. package/dist/content/en.js.map +1 -0
  190. package/dist/content/index.d.ts +15 -0
  191. package/dist/content/index.d.ts.map +1 -0
  192. package/dist/content/index.js +21 -0
  193. package/dist/content/index.js.map +1 -0
  194. package/dist/content/types.d.ts +87 -0
  195. package/dist/content/types.d.ts.map +1 -0
  196. package/dist/content/types.js +2 -0
  197. package/dist/content/types.js.map +1 -0
  198. package/dist/engine.d.ts +52 -0
  199. package/dist/engine.d.ts.map +1 -0
  200. package/dist/engine.js +120 -0
  201. package/dist/engine.js.map +1 -0
  202. package/dist/index.d.ts +12 -0
  203. package/dist/index.d.ts.map +1 -0
  204. package/dist/index.js +11 -0
  205. package/dist/index.js.map +1 -0
  206. package/dist/meta.d.ts +4 -0
  207. package/dist/meta.d.ts.map +1 -0
  208. package/dist/meta.js +4 -0
  209. package/dist/meta.js.map +1 -0
  210. package/dist/net/context.d.ts +9 -0
  211. package/dist/net/context.d.ts.map +1 -0
  212. package/dist/net/context.js +62 -0
  213. package/dist/net/context.js.map +1 -0
  214. package/dist/net/guard.d.ts +16 -0
  215. package/dist/net/guard.d.ts.map +1 -0
  216. package/dist/net/guard.js +70 -0
  217. package/dist/net/guard.js.map +1 -0
  218. package/dist/net/http.d.ts +22 -0
  219. package/dist/net/http.d.ts.map +1 -0
  220. package/dist/net/http.js +114 -0
  221. package/dist/net/http.js.map +1 -0
  222. package/dist/net/tls.d.ts +15 -0
  223. package/dist/net/tls.d.ts.map +1 -0
  224. package/dist/net/tls.js +103 -0
  225. package/dist/net/tls.js.map +1 -0
  226. package/dist/report/html.d.ts +14 -0
  227. package/dist/report/html.d.ts.map +1 -0
  228. package/dist/report/html.js +210 -0
  229. package/dist/report/html.js.map +1 -0
  230. package/dist/report/index.d.ts +10 -0
  231. package/dist/report/index.d.ts.map +1 -0
  232. package/dist/report/index.js +10 -0
  233. package/dist/report/index.js.map +1 -0
  234. package/dist/report/manual.d.ts +62 -0
  235. package/dist/report/manual.d.ts.map +1 -0
  236. package/dist/report/manual.js +190 -0
  237. package/dist/report/manual.js.map +1 -0
  238. package/dist/report/merge.d.ts +8 -0
  239. package/dist/report/merge.d.ts.map +1 -0
  240. package/dist/report/merge.js +135 -0
  241. package/dist/report/merge.js.map +1 -0
  242. package/dist/report/summary.d.ts +10 -0
  243. package/dist/report/summary.d.ts.map +1 -0
  244. package/dist/report/summary.js +27 -0
  245. package/dist/report/summary.js.map +1 -0
  246. package/dist/report/validate.d.ts +3 -0
  247. package/dist/report/validate.d.ts.map +1 -0
  248. package/dist/report/validate.js +78 -0
  249. package/dist/report/validate.js.map +1 -0
  250. package/dist/types.d.ts +244 -0
  251. package/dist/types.d.ts.map +1 -0
  252. package/dist/types.js +2 -0
  253. package/dist/types.js.map +1 -0
  254. package/dist/validate.d.ts +4 -0
  255. package/dist/validate.d.ts.map +1 -0
  256. package/dist/validate.js +24 -0
  257. package/dist/validate.js.map +1 -0
  258. package/package.json +40 -0
@@ -0,0 +1,114 @@
1
+ import http from "node:http";
2
+ import https from "node:https";
3
+ import { assertAllowedLiteral, guardedLookup } from "./guard.js";
4
+ export class HttpError extends Error {
5
+ code;
6
+ url;
7
+ constructor(message, code, url) {
8
+ super(message);
9
+ this.code = code;
10
+ this.url = url;
11
+ this.name = "HttpError";
12
+ }
13
+ }
14
+ const REDIRECT_CODES = new Set([301, 302, 303, 307, 308]);
15
+ /**
16
+ * Minimal HTTP(S) client on node:http. We avoid fetch() because it refuses
17
+ * TRACE/TRACK and hides TLS details. Certificate errors are deliberately not
18
+ * fatal here: the certificate check reports them; other checks still need a
19
+ * response from misconfigured hosts.
20
+ */
21
+ export async function httpRequest(url, opts, client) {
22
+ const followRedirects = opts.followRedirects ?? true;
23
+ const redirects = [];
24
+ let current = new URL(url);
25
+ for (;;) {
26
+ const res = await singleRequest(current, opts, client);
27
+ const location = res.headers["location"];
28
+ if (!followRedirects || !REDIRECT_CODES.has(res.status) || !location) {
29
+ return { ...res, redirects };
30
+ }
31
+ if (redirects.length >= client.maxRedirects) {
32
+ throw new HttpError(`Too many redirects (>${client.maxRedirects})`, "TOO_MANY_REDIRECTS", url);
33
+ }
34
+ const next = new URL(location, current);
35
+ if (next.protocol !== "http:" && next.protocol !== "https:") {
36
+ return { ...res, redirects };
37
+ }
38
+ redirects.push(current.href);
39
+ current = next;
40
+ }
41
+ }
42
+ function singleRequest(url, opts, client) {
43
+ const lib = url.protocol === "https:" ? https : http;
44
+ return new Promise((resolve, reject) => {
45
+ if (client.blockPrivateNetworks) {
46
+ try {
47
+ assertAllowedLiteral(url.hostname);
48
+ }
49
+ catch (err) {
50
+ return reject(err);
51
+ }
52
+ }
53
+ const req = lib.request(url, {
54
+ method: opts.method ?? "GET",
55
+ headers: {
56
+ "user-agent": client.userAgent,
57
+ accept: "text/html,application/xhtml+xml,*/*;q=0.8",
58
+ "accept-encoding": "identity",
59
+ ...opts.headers,
60
+ },
61
+ rejectUnauthorized: false,
62
+ timeout: client.timeoutMs,
63
+ lookup: client.blockPrivateNetworks ? guardedLookup : undefined,
64
+ }, (res) => {
65
+ const chunks = [];
66
+ let size = 0;
67
+ let done = false;
68
+ const finish = () => {
69
+ if (done)
70
+ return;
71
+ done = true;
72
+ const headers = {};
73
+ for (const [name, value] of Object.entries(res.headers)) {
74
+ if (name === "set-cookie" || value === undefined)
75
+ continue;
76
+ headers[name] = Array.isArray(value) ? value.join(", ") : value;
77
+ }
78
+ resolve({
79
+ url: url.href,
80
+ status: res.statusCode ?? 0,
81
+ headers,
82
+ setCookies: res.headers["set-cookie"] ?? [],
83
+ body: Buffer.concat(chunks).toString("utf8"),
84
+ });
85
+ };
86
+ res.on("data", (chunk) => {
87
+ if (size >= client.maxBodyBytes)
88
+ return;
89
+ const room = client.maxBodyBytes - size;
90
+ chunks.push(chunk.length > room ? chunk.subarray(0, room) : chunk);
91
+ size += Math.min(chunk.length, room);
92
+ if (size >= client.maxBodyBytes) {
93
+ // Enough for analysis; stop downloading.
94
+ res.destroy();
95
+ finish();
96
+ }
97
+ });
98
+ res.on("end", finish);
99
+ res.on("error", (err) => reject(toHttpError(err, url)));
100
+ });
101
+ req.on("timeout", () => {
102
+ req.destroy(new HttpError(`Timed out after ${client.timeoutMs} ms`, "ETIMEDOUT", url.href));
103
+ });
104
+ req.on("error", (err) => reject(toHttpError(err, url)));
105
+ req.end();
106
+ });
107
+ }
108
+ function toHttpError(err, url) {
109
+ if (err instanceof HttpError)
110
+ return err;
111
+ const e = err;
112
+ return new HttpError(e.message, e.code, url.href);
113
+ }
114
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/net/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { LegacyTlsVersion, TlsInfo } from "../types.js";
2
+ export interface TlsTarget {
3
+ host: string;
4
+ port: number;
5
+ timeoutMs: number;
6
+ blockPrivateNetworks: boolean;
7
+ }
8
+ /** Handshake with the target and report protocol, cipher, trust and certificate details. */
9
+ export declare function getTlsInfo(target: TlsTarget): Promise<TlsInfo>;
10
+ /**
11
+ * Offer only one legacy protocol version. Resolves true if the server accepts it.
12
+ * SECLEVEL=0 lets the local OpenSSL attempt the old protocol at all.
13
+ */
14
+ export declare function probeLegacyTls(target: TlsTarget, version: LegacyTlsVersion): Promise<boolean>;
15
+ //# sourceMappingURL=tls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls.d.ts","sourceRoot":"","sources":["../../src/net/tls.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG7D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CA+C9D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAwB7F"}
@@ -0,0 +1,103 @@
1
+ import tls from "node:tls";
2
+ import { assertAllowedLiteral, guardedLookup } from "./guard.js";
3
+ /** Handshake with the target and report protocol, cipher, trust and certificate details. */
4
+ export function getTlsInfo(target) {
5
+ return new Promise((resolve, reject) => {
6
+ if (target.blockPrivateNetworks)
7
+ assertAllowedLiteral(target.host);
8
+ const socket = tls.connect({
9
+ host: target.host,
10
+ port: target.port,
11
+ servername: isIp(target.host) ? undefined : target.host,
12
+ // Trust is evaluated and reported, not enforced.
13
+ rejectUnauthorized: false,
14
+ timeout: target.timeoutMs,
15
+ lookup: target.blockPrivateNetworks ? guardedLookup : undefined,
16
+ });
17
+ socket.once("secureConnect", () => {
18
+ const peer = socket.getPeerCertificate();
19
+ const hasCert = peer && Object.keys(peer).length > 0;
20
+ const info = {
21
+ protocol: socket.getProtocol(),
22
+ cipher: socket.getCipher()?.name ?? null,
23
+ authorized: socket.authorized,
24
+ authorizationError: socket.authorizationError
25
+ ? String(socket.authorizationError)
26
+ : undefined,
27
+ cert: hasCert
28
+ ? {
29
+ subject: formatName(peer.subject),
30
+ issuer: formatName(peer.issuer),
31
+ validFrom: peer.valid_from,
32
+ validTo: peer.valid_to,
33
+ daysRemaining: Math.floor((Date.parse(peer.valid_to) - Date.now()) / 86_400_000),
34
+ subjectAltNames: (peer.subjectaltname ?? "")
35
+ .split(",")
36
+ .map((s) => s.trim())
37
+ .filter(Boolean),
38
+ keyType: peer.modulus ? "RSA" : peer.asn1Curve || peer.nistCurve ? "EC" : undefined,
39
+ bits: peer.bits,
40
+ }
41
+ : null,
42
+ };
43
+ socket.end();
44
+ resolve(info);
45
+ });
46
+ socket.once("timeout", () => {
47
+ socket.destroy();
48
+ reject(new Error(`TLS handshake timed out after ${target.timeoutMs} ms`));
49
+ });
50
+ socket.once("error", reject);
51
+ });
52
+ }
53
+ /**
54
+ * Offer only one legacy protocol version. Resolves true if the server accepts it.
55
+ * SECLEVEL=0 lets the local OpenSSL attempt the old protocol at all.
56
+ */
57
+ export function probeLegacyTls(target, version) {
58
+ return new Promise((resolve) => {
59
+ if (target.blockPrivateNetworks && isBlockedLiteral(target.host))
60
+ return resolve(false);
61
+ const socket = tls.connect({
62
+ host: target.host,
63
+ port: target.port,
64
+ servername: isIp(target.host) ? undefined : target.host,
65
+ rejectUnauthorized: false,
66
+ minVersion: version,
67
+ maxVersion: version,
68
+ ciphers: "DEFAULT@SECLEVEL=0",
69
+ timeout: target.timeoutMs,
70
+ lookup: target.blockPrivateNetworks ? guardedLookup : undefined,
71
+ });
72
+ socket.once("secureConnect", () => {
73
+ socket.end();
74
+ resolve(true);
75
+ });
76
+ socket.once("timeout", () => {
77
+ socket.destroy();
78
+ resolve(false);
79
+ });
80
+ socket.once("error", () => resolve(false));
81
+ });
82
+ }
83
+ function formatName(name) {
84
+ if (!name)
85
+ return "";
86
+ return Object.entries(name)
87
+ .filter(([, v]) => v !== undefined)
88
+ .map(([k, v]) => `${k}=${Array.isArray(v) ? v.join("+") : v}`)
89
+ .join(", ");
90
+ }
91
+ function isBlockedLiteral(host) {
92
+ try {
93
+ assertAllowedLiteral(host);
94
+ return false;
95
+ }
96
+ catch {
97
+ return true;
98
+ }
99
+ }
100
+ function isIp(host) {
101
+ return /^[\d.]+$/.test(host) || host.includes(":");
102
+ }
103
+ //# sourceMappingURL=tls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls.js","sourceRoot":"","sources":["../../src/net/tls.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { EvaluatedBy, Report } from "../types.js";
2
+ export declare function escapeHtml(value: string): string;
3
+ export declare const EVALUATED_LABEL: Record<EvaluatedBy, string>;
4
+ export interface RenderOptions {
5
+ /** Omit rows still pending manual review (the readiness summary still counts them). */
6
+ skipUntested?: boolean;
7
+ }
8
+ /** Annex B table as an HTML fragment (summary + one table grouped by section). */
9
+ export declare function renderReportFragment(report: Report, opts?: RenderOptions): string;
10
+ /** Styles for the report fragment. Print-friendly; respects dark mode on screen. */
11
+ export declare const REPORT_CSS = "\n.insa-report { --pass:#1a7f37; --fail:#cf222e; --manual:#6e7781; --error:#9a6700; --na:#0969da; --line:#d0d7de; --muted:#57606a; --section:#f6f8fa;\n font: 14px/1.45 system-ui, -apple-system, \"Segoe UI\", sans-serif; color: inherit; }\n@media (prefers-color-scheme: dark) { .insa-report { --line:#30363d; --muted:#9198a1; --section:#161b22; --pass:#3fb950; --fail:#f85149; --manual:#9198a1; --error:#d29922; --na:#4493f8; } }\n.insa-report h1 { font-size: 1.4rem; margin: 0 0 .5rem; }\n.insa-report .meta { display:grid; grid-template-columns:max-content 1fr; gap:.15rem 1rem; margin:0 0 1rem; }\n.insa-report .meta dt { color: var(--muted); }\n.insa-report .meta dd { margin:0; overflow-wrap:anywhere; }\n.insa-report .summary { display:flex; flex-wrap:wrap; gap:.5rem; list-style:none; padding:0; margin:0 0 .75rem; }\n.insa-report .summary li { border:1px solid var(--line); border-radius:6px; padding:.35rem .75rem; }\n.insa-report .summary strong { font-size:1.15rem; margin-right:.25rem; }\n.insa-report .summary-pass strong { color:var(--pass); } .insa-report .summary-fail strong { color:var(--fail); }\n.insa-report .summary-manual strong { color:var(--manual); } .insa-report .summary-error strong { color:var(--error); }\n.insa-report .disclaimer { color:var(--muted); font-size:.85rem; margin:0 0 1rem; }\n.insa-report table { width:100%; border-collapse:collapse; }\n.insa-report th, .insa-report td { border:1px solid var(--line); padding:.4rem .5rem; text-align:left; vertical-align:top; }\n.insa-report thead th { background:var(--section); }\n.insa-report tr.section th { background:var(--section); font-weight:600; }\n.insa-report td.num { white-space:nowrap; font-variant-numeric:tabular-nums; }\n.insa-report td.result { white-space:nowrap; }\n.insa-report td.detail { overflow-wrap:anywhere; }\n.insa-report .badge { font-weight:600; }\n.insa-report .badge-pass { color:var(--pass); } .insa-report .badge-fail { color:var(--fail); }\n.insa-report .badge-manual { color:var(--manual); } .insa-report .badge-error { color:var(--error); }\n.insa-report .evidence { margin:.25rem 0 0; padding-left:1.1rem; color:var(--muted); font-size:.85rem; }\n.insa-report .by { display:block; color:var(--muted); font-size:.75rem; font-weight:400; }\n.insa-report .notes { margin:0 0 .75rem; padding-left:1.1rem; color:var(--muted); font-size:.85rem; }\n.insa-report .findings { list-style:none; margin:.4rem 0 0; padding:0; }\n.insa-report .finding { border-left:3px solid var(--line); padding:.2rem 0 .2rem .5rem; margin:.3rem 0; font-size:.85rem; }\n.insa-report .finding.conf-high { border-left-color:var(--fail); }\n.insa-report .finding.conf-medium { border-left-color:var(--error); }\n.insa-report .finding.conf-low { border-left-color:var(--manual); }\n.insa-report .conf { font-weight:600; text-transform:uppercase; font-size:.7rem; letter-spacing:.03em; margin-right:.35rem; }\n.insa-report .conf-high .conf { color:var(--fail); } .insa-report .conf-medium .conf { color:var(--error); } .insa-report .conf-low .conf { color:var(--manual); }\n.insa-report .regex { font-size:.7rem; border:1px solid var(--line); border-radius:4px; padding:0 .25rem; color:var(--muted); }\n.insa-report .snippet { margin:.2rem 0; padding:.25rem .4rem; background:var(--section); border-radius:4px; white-space:pre-wrap; overflow-wrap:anywhere; font-size:.8rem; }\n.insa-report .why { color:var(--muted); }\n.insa-report .badge-not-applicable, .insa-report .summary-na strong { color:var(--na); }\n.insa-report .readiness { display:flex; flex-wrap:wrap; gap:.25rem 1rem; align-items:baseline; border:1px solid var(--line); border-left-width:4px; border-radius:6px; padding:.5rem .75rem; margin:0 0 .75rem; }\n.insa-report .readiness-incomplete { border-left-color:var(--error); }\n.insa-report .readiness-failures { border-left-color:var(--fail); }\n.insa-report .readiness-clean { border-left-color:var(--pass); }\n.insa-report .manual { margin-top:.4rem; padding:.3rem .5rem; border-radius:4px; background:var(--section); font-size:.85rem; }\n.insa-report .manual-meta { color:var(--muted); }\n.insa-report .manual-note { margin:.25rem 0 0; white-space:pre-wrap; overflow-wrap:anywhere; }\n.insa-report .evidence-flag { white-space:nowrap; }\n@media print {\n .insa-report { --pass:#1a7f37; --fail:#cf222e; --manual:#57606a; --error:#9a6700; --na:#0969da; --line:#999; --section:#eee; --muted:#444; font-size:10pt; color:#000; }\n .insa-report tr { break-inside: avoid; }\n .insa-report thead { display: table-header-group; }\n}\n";
12
+ /** Self-contained printable HTML document (open in a browser, Print → Save as PDF). */
13
+ export declare function renderHtmlDocument(report: Report, opts?: RenderOptions): string;
14
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/report/html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,WAAW,EAAgB,MAAM,EAAmB,MAAM,aAAa,CAAC;AAInG,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAKvD,CAAC;AAuEF,MAAM,WAAW,aAAa;IAC5B,uFAAuF;IACvF,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAgBD,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CA+CrF;AAED,oFAAoF;AACpF,eAAO,MAAM,UAAU,27IAmDtB,CAAC;AAEF,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAmBnF"}
@@ -0,0 +1,210 @@
1
+ import { catalog, formatText } from "../content/index.js";
2
+ import { readiness } from "./manual.js";
3
+ import { groupBySection, STATUS_LABEL } from "./summary.js";
4
+ export function escapeHtml(value) {
5
+ return value
6
+ .replace(/&/g, "&amp;")
7
+ .replace(/</g, "&lt;")
8
+ .replace(/>/g, "&gt;")
9
+ .replace(/"/g, "&quot;")
10
+ .replace(/'/g, "&#39;");
11
+ }
12
+ export const EVALUATED_LABEL = {
13
+ url: "Automated (URL)",
14
+ code: "Automated (code)",
15
+ "url+code": "Automated (URL + code)",
16
+ manual: "Manual",
17
+ };
18
+ const evaluatedByOf = (r) => r.evaluatedBy ?? (r.status === "manual" ? "manual" : "url");
19
+ function renderFindings(findings) {
20
+ if (!findings?.length)
21
+ return "";
22
+ return `<ul class="findings">${findings
23
+ .map((f) => `<li class="finding conf-${f.confidence}">
24
+ <span class="conf">${f.confidence}</span>
25
+ <code class="loc">${escapeHtml(`${f.file}:${f.line}`)}</code>${f.method === "regex" ? ' <span class="regex" title="Text-pattern match: higher false-positive rate">regex</span>' : ""}
26
+ <pre class="snippet">${escapeHtml(f.snippet)}</pre>
27
+ <span class="why">${escapeHtml(f.why)}</span>
28
+ </li>`)
29
+ .join("")}</ul>`;
30
+ }
31
+ function renderManual(m) {
32
+ if (!m)
33
+ return "";
34
+ const ui = catalog().ui;
35
+ const meta = [
36
+ `${ui.verdictLabel}: ${ui.verdict[m.verdict]}`,
37
+ m.reviewer ? `${ui.reviewer}: ${escapeHtml(m.reviewer)}` : "",
38
+ m.reviewedAt ? `${ui.reviewedAt}: ${escapeHtml(m.reviewedAt.slice(0, 16).replace("T", " "))} UTC` : "",
39
+ m.carriedFrom ? escapeHtml(formatText(ui.carriedFrom, { date: m.carriedFrom.slice(0, 10) })) : "",
40
+ m.history?.length ? escapeHtml(formatText(ui.historyCount, { count: m.history.length })) : "",
41
+ ].filter(Boolean);
42
+ const evidence = [
43
+ m.attachments?.length ? formatText(ui.evidenceAttached, { count: m.attachments.length }) : "",
44
+ m.evidenceText ? ui.evidenceTextAttached : "",
45
+ ].filter(Boolean);
46
+ return `<div class="manual verdict-${m.verdict}">
47
+ <div class="manual-meta">${meta.join(" · ")}${evidence.length ? ` <span class="evidence-flag" title="Evidence recorded">&#128206; ${evidence.join(", ")}</span>` : ""}</div>
48
+ ${m.note ? `<p class="manual-note">${escapeHtml(m.note)}</p>` : ""}
49
+ ${m.evidenceText ? `<pre class="snippet">${escapeHtml(m.evidenceText)}</pre>` : ""}
50
+ </div>`;
51
+ }
52
+ function renderReadiness(report) {
53
+ const r = readiness(report);
54
+ const ui = catalog().ui;
55
+ const headline = r.state === "clean"
56
+ ? ui.readinessClean
57
+ : r.state === "failures"
58
+ ? formatText(ui.readinessFailures, { fail: r.fail })
59
+ : r.pending > 0
60
+ ? formatText(ui.readinessIncomplete, { pending: r.pending })
61
+ : r.error > 0
62
+ ? formatText(ui.readinessErrors, { error: r.error })
63
+ : formatText(ui.readinessNeedsNote, { count: r.needsNote });
64
+ const lines = [
65
+ r.state === "incomplete" && r.pending > 0 ? "" : r.pending ? formatText(ui.readinessPendingLine, { pending: r.pending }) : ui.readinessNonePending,
66
+ r.needsNote && !(r.pending === 0 && r.error === 0) ? formatText(ui.readinessNeedsNoteLine, { count: r.needsNote }) : "",
67
+ r.carried ? formatText(ui.readinessCarriedLine, { count: r.carried }) : "",
68
+ ].filter(Boolean);
69
+ return `<div class="readiness readiness-${r.state}" role="status">
70
+ <strong>${escapeHtml(headline)}</strong>
71
+ ${lines.map((l) => `<span>${escapeHtml(l)}</span>`).join("")}
72
+ </div>
73
+ <ul class="summary">
74
+ <li class="summary-pass"><strong>${r.pass}</strong> Pass</li>
75
+ <li class="summary-fail"><strong>${r.fail}</strong> Fail</li>
76
+ <li class="summary-manual"><strong>${r.pending}</strong> Pending manual review</li>
77
+ <li class="summary-na"><strong>${r.notApplicable}</strong> Not applicable</li>
78
+ <li class="summary-error"><strong>${r.error}</strong> Error</li>
79
+ <li class="summary-total"><strong>${r.total}</strong> Total</li>
80
+ </ul>`;
81
+ }
82
+ function renderSources(report) {
83
+ const s = report.sources;
84
+ const parts = [];
85
+ if (s?.url ?? (!s && report.target))
86
+ parts.push(`<dt>Website</dt><dd>${escapeHtml(s?.url ?? report.target)}</dd>`);
87
+ if (s?.code) {
88
+ const c = s.code;
89
+ const what = [c.language, ...c.frameworks].filter(Boolean).join(", ") || "unknown";
90
+ parts.push(`<dt>Source code</dt><dd>${escapeHtml(c.name)} (${escapeHtml(what)}; ${c.filesAnalyzed} files analysed${c.parseErrors.length ? `, ${c.parseErrors.length} unparseable` : ""})</dd>`);
91
+ }
92
+ return parts.join("");
93
+ }
94
+ /** Annex B table as an HTML fragment (summary + one table grouped by section). */
95
+ export function renderReportFragment(report, opts = {}) {
96
+ const shown = opts.skipUntested ? report.results.filter((r) => r.status !== "manual") : report.results;
97
+ const rows = groupBySection(shown)
98
+ .map((group) => `
99
+ <tr class="section"><th colspan="4">${escapeHtml(group.section)}</th></tr>
100
+ ${group.results
101
+ .map((r) => `
102
+ <tr class="status-${r.status}">
103
+ <td class="num">${escapeHtml(r.id)}</td>
104
+ <td class="title">${escapeHtml(r.title)}</td>
105
+ <td class="result"><span class="badge badge-${r.status}">${STATUS_LABEL[r.status]}</span><span class="by">${EVALUATED_LABEL[evaluatedByOf(r)]}</span></td>
106
+ <td class="detail">${escapeHtml(r.detail)}${r.evidence?.length
107
+ ? `<ul class="evidence">${r.evidence.map((e) => `<li>${escapeHtml(e)}</li>`).join("")}</ul>`
108
+ : ""}${renderFindings(r.findings)}${renderManual(r.manual)}</td>
109
+ </tr>`)
110
+ .join("")}`)
111
+ .join("");
112
+ return `
113
+ <section class="insa-report">
114
+ <header class="report-header">
115
+ <h1>Secure Website Audit — Annex B Checklist</h1>
116
+ <dl class="meta">
117
+ ${renderSources(report)}
118
+ <dt>Standard</dt><dd>${escapeHtml(report.standard)}</dd>
119
+ <dt>Scanned</dt><dd>${escapeHtml(report.startedAt)}</dd>
120
+ <dt>Tool</dt><dd>${escapeHtml(`${report.tool.name} ${report.tool.version}`)}</dd>
121
+ </dl>
122
+ ${renderReadiness(report)}
123
+ ${report.notes?.length ? `<ul class="notes">${report.notes.map((n) => `<li>${escapeHtml(n)}</li>`).join("")}</ul>` : ""}
124
+ <p class="disclaimer">"Pass" means the automated test found no issue; it is not a certification. URL checks are passive and
125
+ cover only what the public site shows. Code analysis reports patterns, not proven vulnerabilities: high/medium-confidence
126
+ findings produce "Fail", low-confidence ones only "Manual review"; regex matches have a higher false-positive rate.
127
+ Items marked "Manual review" are pending: they have no verdict yet and are never counted as passed.
128
+ Manual verdicts are recorded by the named reviewer and reflect their testing.${opts.skipUntested ? " Rows pending manual review are hidden in this view." : ""}</p>
129
+ </header>
130
+ <table class="annex">
131
+ <thead><tr><th>No.</th><th>Test</th><th>Result</th><th>Details</th></tr></thead>
132
+ <tbody>${rows}</tbody>
133
+ </table>
134
+ </section>`;
135
+ }
136
+ /** Styles for the report fragment. Print-friendly; respects dark mode on screen. */
137
+ export const REPORT_CSS = `
138
+ .insa-report { --pass:#1a7f37; --fail:#cf222e; --manual:#6e7781; --error:#9a6700; --na:#0969da; --line:#d0d7de; --muted:#57606a; --section:#f6f8fa;
139
+ font: 14px/1.45 system-ui, -apple-system, "Segoe UI", sans-serif; color: inherit; }
140
+ @media (prefers-color-scheme: dark) { .insa-report { --line:#30363d; --muted:#9198a1; --section:#161b22; --pass:#3fb950; --fail:#f85149; --manual:#9198a1; --error:#d29922; --na:#4493f8; } }
141
+ .insa-report h1 { font-size: 1.4rem; margin: 0 0 .5rem; }
142
+ .insa-report .meta { display:grid; grid-template-columns:max-content 1fr; gap:.15rem 1rem; margin:0 0 1rem; }
143
+ .insa-report .meta dt { color: var(--muted); }
144
+ .insa-report .meta dd { margin:0; overflow-wrap:anywhere; }
145
+ .insa-report .summary { display:flex; flex-wrap:wrap; gap:.5rem; list-style:none; padding:0; margin:0 0 .75rem; }
146
+ .insa-report .summary li { border:1px solid var(--line); border-radius:6px; padding:.35rem .75rem; }
147
+ .insa-report .summary strong { font-size:1.15rem; margin-right:.25rem; }
148
+ .insa-report .summary-pass strong { color:var(--pass); } .insa-report .summary-fail strong { color:var(--fail); }
149
+ .insa-report .summary-manual strong { color:var(--manual); } .insa-report .summary-error strong { color:var(--error); }
150
+ .insa-report .disclaimer { color:var(--muted); font-size:.85rem; margin:0 0 1rem; }
151
+ .insa-report table { width:100%; border-collapse:collapse; }
152
+ .insa-report th, .insa-report td { border:1px solid var(--line); padding:.4rem .5rem; text-align:left; vertical-align:top; }
153
+ .insa-report thead th { background:var(--section); }
154
+ .insa-report tr.section th { background:var(--section); font-weight:600; }
155
+ .insa-report td.num { white-space:nowrap; font-variant-numeric:tabular-nums; }
156
+ .insa-report td.result { white-space:nowrap; }
157
+ .insa-report td.detail { overflow-wrap:anywhere; }
158
+ .insa-report .badge { font-weight:600; }
159
+ .insa-report .badge-pass { color:var(--pass); } .insa-report .badge-fail { color:var(--fail); }
160
+ .insa-report .badge-manual { color:var(--manual); } .insa-report .badge-error { color:var(--error); }
161
+ .insa-report .evidence { margin:.25rem 0 0; padding-left:1.1rem; color:var(--muted); font-size:.85rem; }
162
+ .insa-report .by { display:block; color:var(--muted); font-size:.75rem; font-weight:400; }
163
+ .insa-report .notes { margin:0 0 .75rem; padding-left:1.1rem; color:var(--muted); font-size:.85rem; }
164
+ .insa-report .findings { list-style:none; margin:.4rem 0 0; padding:0; }
165
+ .insa-report .finding { border-left:3px solid var(--line); padding:.2rem 0 .2rem .5rem; margin:.3rem 0; font-size:.85rem; }
166
+ .insa-report .finding.conf-high { border-left-color:var(--fail); }
167
+ .insa-report .finding.conf-medium { border-left-color:var(--error); }
168
+ .insa-report .finding.conf-low { border-left-color:var(--manual); }
169
+ .insa-report .conf { font-weight:600; text-transform:uppercase; font-size:.7rem; letter-spacing:.03em; margin-right:.35rem; }
170
+ .insa-report .conf-high .conf { color:var(--fail); } .insa-report .conf-medium .conf { color:var(--error); } .insa-report .conf-low .conf { color:var(--manual); }
171
+ .insa-report .regex { font-size:.7rem; border:1px solid var(--line); border-radius:4px; padding:0 .25rem; color:var(--muted); }
172
+ .insa-report .snippet { margin:.2rem 0; padding:.25rem .4rem; background:var(--section); border-radius:4px; white-space:pre-wrap; overflow-wrap:anywhere; font-size:.8rem; }
173
+ .insa-report .why { color:var(--muted); }
174
+ .insa-report .badge-not-applicable, .insa-report .summary-na strong { color:var(--na); }
175
+ .insa-report .readiness { display:flex; flex-wrap:wrap; gap:.25rem 1rem; align-items:baseline; border:1px solid var(--line); border-left-width:4px; border-radius:6px; padding:.5rem .75rem; margin:0 0 .75rem; }
176
+ .insa-report .readiness-incomplete { border-left-color:var(--error); }
177
+ .insa-report .readiness-failures { border-left-color:var(--fail); }
178
+ .insa-report .readiness-clean { border-left-color:var(--pass); }
179
+ .insa-report .manual { margin-top:.4rem; padding:.3rem .5rem; border-radius:4px; background:var(--section); font-size:.85rem; }
180
+ .insa-report .manual-meta { color:var(--muted); }
181
+ .insa-report .manual-note { margin:.25rem 0 0; white-space:pre-wrap; overflow-wrap:anywhere; }
182
+ .insa-report .evidence-flag { white-space:nowrap; }
183
+ @media print {
184
+ .insa-report { --pass:#1a7f37; --fail:#cf222e; --manual:#57606a; --error:#9a6700; --na:#0969da; --line:#999; --section:#eee; --muted:#444; font-size:10pt; color:#000; }
185
+ .insa-report tr { break-inside: avoid; }
186
+ .insa-report thead { display: table-header-group; }
187
+ }
188
+ `;
189
+ /** Self-contained printable HTML document (open in a browser, Print → Save as PDF). */
190
+ export function renderHtmlDocument(report, opts = {}) {
191
+ return `<!doctype html>
192
+ <html lang="en">
193
+ <head>
194
+ <meta charset="utf-8">
195
+ <meta name="viewport" content="width=device-width, initial-scale=1">
196
+ <title>Annex B Audit — ${escapeHtml(new URL(report.target).host)}</title>
197
+ <style>
198
+ :root { color-scheme: light dark; }
199
+ body { margin: 0 auto; padding: 24px 16px; max-width: 1100px; background: Canvas; color: CanvasText; }
200
+ @media print { body { padding: 0; max-width: none; background: #fff; color: #000; } }
201
+ ${REPORT_CSS}
202
+ </style>
203
+ </head>
204
+ <body>
205
+ ${renderReportFragment(report, opts)}
206
+ </body>
207
+ </html>
208
+ `;
209
+ }
210
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/report/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export * from "./summary.js";
2
+ export * from "./html.js";
3
+ export * from "./merge.js";
4
+ export * from "./validate.js";
5
+ export * from "./manual.js";
6
+ export { ANNEX_B, STANDARD } from "../annex-b.js";
7
+ export { TOOL_NAME, TOOL_VERSION } from "../meta.js";
8
+ export * from "../content/index.js";
9
+ export type * from "../types.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrD,cAAc,qBAAqB,CAAC;AACpC,mBAAmB,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ // Browser-safe entry point (insa-check-core/report): no Node built-ins may be imported from here.
2
+ export * from "./summary.js";
3
+ export * from "./html.js";
4
+ export * from "./merge.js";
5
+ export * from "./validate.js";
6
+ export * from "./manual.js";
7
+ export { ANNEX_B, STANDARD } from "../annex-b.js";
8
+ export { TOOL_NAME, TOOL_VERSION } from "../meta.js";
9
+ export * from "../content/index.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrD,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,62 @@
1
+ import type { CheckResult, ManualReview, ManualVerdict, Report, Status } from "../types.js";
2
+ /** Browser-safe Tier 3 helpers: guided manual review recorded on the same report rows. */
3
+ export declare const MANUAL_VERDICTS: readonly ManualVerdict[];
4
+ /** Untested stays "manual" (pending), so an unreviewed item can never count as a pass. */
5
+ export declare function verdictStatus(verdict: ManualVerdict): Status;
6
+ /** A row needs (or received) a human verdict when automation left it undecided. */
7
+ export declare function isReviewable(row: CheckResult): boolean;
8
+ /** Attaches an "untested" review to every undecided row. Idempotent; existing verdicts are kept. */
9
+ export declare function startManualReview(report: Report): Report;
10
+ export declare class ReviewError extends Error {
11
+ name: string;
12
+ }
13
+ /** Fail and Not applicable must be justified: a verdict without a note keeps the report incomplete. */
14
+ export declare function needsNote(row: CheckResult): boolean;
15
+ /**
16
+ * Records (part of) a verdict for one item and recomputes the summary.
17
+ * The previous state goes into `history` when the verdict, reviewer or screenshots change, when a
18
+ * carried verdict is re-confirmed, or when note/evidence change more than 10 minutes after the last change.
19
+ * A carried verdict counts as re-confirmed only when a verdict is set; editing just the note keeps the mark.
20
+ */
21
+ export declare function recordVerdict(report: Report, id: string, patch: Partial<ManualReview>, now?: Date): Report;
22
+ export interface ReviewProgress {
23
+ /** Rows needing a human verdict (with or without one). */
24
+ total: number;
25
+ /** Of those, rows with a verdict other than "untested". */
26
+ reviewed: number;
27
+ }
28
+ export declare function reviewProgress(report: Report): ReviewProgress;
29
+ export interface Readiness {
30
+ total: number;
31
+ pass: number;
32
+ fail: number;
33
+ notApplicable: number;
34
+ /** Rows still waiting for a human verdict (status "manual"). */
35
+ pending: number;
36
+ /** Automated checks that did not complete. */
37
+ error: number;
38
+ /** Manual Fail / Not applicable verdicts without a reviewer note. */
39
+ needsNote: number;
40
+ /** Manual verdicts carried from an earlier report and not yet re-confirmed (informational). */
41
+ carried: number;
42
+ /** True only when nothing is pending, nothing errored, and every Fail/N/A verdict has a note. */
43
+ complete: boolean;
44
+ /** incomplete: pending or errors remain; failures: complete with fails; clean: complete, no fails. */
45
+ state: "incomplete" | "failures" | "clean";
46
+ }
47
+ /** Overall readiness across all three tiers. Untested items are counted as pending, never as pass. */
48
+ export declare function readiness(report: Report): Readiness;
49
+ /** A report with every Annex B item pending manual review, for reviewing without any automated scan. */
50
+ export declare function createManualReport(name: string, now?: Date): Report;
51
+ export interface CarryResult {
52
+ report: Report;
53
+ /** Items that received a carried verdict. */
54
+ carried: string[];
55
+ }
56
+ /**
57
+ * Copies recorded manual verdicts from an earlier report of the same target into a newer one.
58
+ * Only rows still pending in the new report are filled; existing verdicts and automated results
59
+ * are never overridden. Carried verdicts are marked (`carriedFrom`) until someone re-records them.
60
+ */
61
+ export declare function carryForwardReviews(previous: Report, next: Report): CarryResult;
62
+ //# sourceMappingURL=manual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual.d.ts","sourceRoot":"","sources":["../../src/report/manual.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAkB,MAAM,EAAE,MAAM,aAAa,CAAC;AAG5G,0FAA0F;AAE1F,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAAmD,CAAC;AAExG,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAE5D;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAEtD;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED,qBAAa,WAAY,SAAQ,KAAK;IAC3B,IAAI,SAAiB;CAC/B;AAeD,uGAAuG;AACvG,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAGnD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,EAC5B,GAAG,GAAE,IAAiB,GACrB,MAAM,CA+BR;AAED,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAG7D;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,+FAA+F;IAC/F,OAAO,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,QAAQ,EAAE,OAAO,CAAC;IAClB,sGAAsG;IACtG,KAAK,EAAE,YAAY,GAAG,UAAU,GAAG,OAAO,CAAC;CAC5C;AAED,sGAAsG;AACtG,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAcnD;AAED,wGAAwG;AACxG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAqB/E;AAWD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CA4C/E"}