@avi770/testteam 1.2.0 → 3.0.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 (324) hide show
  1. package/CHANGELOG.md +53 -1
  2. package/README.md +72 -7
  3. package/agents/15-regression-sentinel.ts +3 -2
  4. package/agents/24-signup-onboarding-tester.ts +429 -0
  5. package/agents/25-crud-flow-tester.ts +302 -0
  6. package/agents/26-form-validator.ts +297 -0
  7. package/agents/27-search-filter-tester.ts +326 -0
  8. package/agents/28-navigation-routing-tester.ts +425 -0
  9. package/agents/29-responsive-interaction-tester.ts +350 -0
  10. package/agents/30-multi-user-scenario-tester.ts +319 -0
  11. package/agents/31-load-tester.ts +134 -0
  12. package/agents/32-memory-leak-detector.ts +194 -0
  13. package/agents/33-bundle-analyzer.ts +132 -0
  14. package/agents/34-xss-scanner.ts +191 -0
  15. package/agents/35-csrf-tester.ts +82 -0
  16. package/agents/36-auth-fuzzer.ts +194 -0
  17. package/agents/37-dependency-scanner.ts +176 -0
  18. package/agents/38-secrets-scanner.ts +137 -0
  19. package/agents/39-api-contract-tester.ts +199 -0
  20. package/agents/40-rate-limit-tester.ts +94 -0
  21. package/agents/41-api-pagination-tester.ts +97 -0
  22. package/agents/42-graphql-tester.ts +222 -0
  23. package/agents/43-data-consistency-checker.ts +205 -0
  24. package/agents/44-backup-recovery-tester.ts +152 -0
  25. package/agents/45-data-privacy-scanner.ts +125 -0
  26. package/agents/46-seo-auditor.ts +294 -0
  27. package/agents/47-social-preview-tester.ts +232 -0
  28. package/agents/48-lighthouse-auditor.ts +213 -0
  29. package/agents/49-i18n-tester.ts +198 -0
  30. package/agents/50-timezone-tester.ts +173 -0
  31. package/agents/51-error-recovery-tester.ts +155 -0
  32. package/agents/52-offline-mode-tester.ts +180 -0
  33. package/agents/53-graceful-degradation-tester.ts +156 -0
  34. package/agents/54-websocket-tester.ts +151 -0
  35. package/agents/55-realtime-sync-tester.ts +194 -0
  36. package/agents/56-file-upload-tester.ts +194 -0
  37. package/agents/57-export-tester.ts +174 -0
  38. package/agents/58-payment-flow-tester.ts +183 -0
  39. package/agents/59-ssl-tls-auditor.ts +141 -0
  40. package/agents/60-dns-cdn-tester.ts +117 -0
  41. package/agents/61-docker-health-checker.ts +111 -0
  42. package/agents/62-env-config-validator.ts +152 -0
  43. package/agents/63-log-quality-auditor.ts +136 -0
  44. package/agents/64-analytics-tracker-tester.ts +165 -0
  45. package/agents/65-gdpr-compliance-tester.ts +215 -0
  46. package/agents/66-soc2-control-validator.ts +210 -0
  47. package/agents/67-wcag-aaa-tester.ts +241 -0
  48. package/agents/68-dead-code-detector.ts +135 -0
  49. package/agents/69-type-safety-auditor.ts +164 -0
  50. package/agents/70-complexity-analyzer.ts +179 -0
  51. package/agents/__tests__/24-signup-onboarding-tester.test.ts +274 -0
  52. package/agents/__tests__/25-crud-flow-tester.test.ts +322 -0
  53. package/agents/__tests__/26-form-validator.test.ts +345 -0
  54. package/agents/__tests__/27-search-filter-tester.test.ts +311 -0
  55. package/agents/__tests__/28-navigation-routing-tester.test.ts +328 -0
  56. package/agents/__tests__/29-responsive-interaction-tester.test.ts +297 -0
  57. package/agents/__tests__/30-multi-user-scenario-tester.test.ts +328 -0
  58. package/agents/__tests__/31-load-tester.test.ts +189 -0
  59. package/agents/__tests__/32-memory-leak-detector.test.ts +251 -0
  60. package/agents/__tests__/33-bundle-analyzer.test.ts +237 -0
  61. package/agents/__tests__/34-xss-scanner.test.ts +258 -0
  62. package/agents/__tests__/35-csrf-tester.test.ts +200 -0
  63. package/agents/__tests__/36-auth-fuzzer.test.ts +214 -0
  64. package/agents/__tests__/37-dependency-scanner.test.ts +266 -0
  65. package/agents/__tests__/38-secrets-scanner.test.ts +224 -0
  66. package/agents/__tests__/39-api-contract-tester.test.ts +312 -0
  67. package/agents/__tests__/40-rate-limit-tester.test.ts +192 -0
  68. package/agents/__tests__/41-api-pagination-tester.test.ts +198 -0
  69. package/agents/__tests__/42-graphql-tester.test.ts +252 -0
  70. package/agents/__tests__/43-data-consistency-checker.test.ts +232 -0
  71. package/agents/__tests__/44-backup-recovery-tester.test.ts +222 -0
  72. package/agents/__tests__/45-data-privacy-scanner.test.ts +223 -0
  73. package/agents/__tests__/46-seo-auditor.test.ts +261 -0
  74. package/agents/__tests__/47-social-preview-tester.test.ts +245 -0
  75. package/agents/__tests__/48-lighthouse-auditor.test.ts +276 -0
  76. package/agents/__tests__/49-i18n-tester.test.ts +201 -0
  77. package/agents/__tests__/50-timezone-tester.test.ts +172 -0
  78. package/agents/__tests__/51-error-recovery-tester.test.ts +162 -0
  79. package/agents/__tests__/52-offline-mode-tester.test.ts +164 -0
  80. package/agents/__tests__/53-graceful-degradation-tester.test.ts +168 -0
  81. package/agents/__tests__/54-websocket-tester.test.ts +157 -0
  82. package/agents/__tests__/55-realtime-sync-tester.test.ts +181 -0
  83. package/agents/__tests__/56-file-upload-tester.test.ts +172 -0
  84. package/agents/__tests__/57-export-tester.test.ts +169 -0
  85. package/agents/__tests__/58-payment-flow-tester.test.ts +182 -0
  86. package/agents/__tests__/59-ssl-tls-auditor.test.ts +179 -0
  87. package/agents/__tests__/60-dns-cdn-tester.test.ts +176 -0
  88. package/agents/__tests__/61-docker-health-checker.test.ts +150 -0
  89. package/agents/__tests__/62-env-config-validator.test.ts +166 -0
  90. package/agents/__tests__/63-log-quality-auditor.test.ts +175 -0
  91. package/agents/__tests__/64-analytics-tracker-tester.test.ts +158 -0
  92. package/agents/__tests__/65-gdpr-compliance-tester.test.ts +174 -0
  93. package/agents/__tests__/66-soc2-control-validator.test.ts +183 -0
  94. package/agents/__tests__/67-wcag-aaa-tester.test.ts +190 -0
  95. package/agents/__tests__/68-dead-code-detector.test.ts +174 -0
  96. package/agents/__tests__/69-type-safety-auditor.test.ts +173 -0
  97. package/agents/__tests__/70-complexity-analyzer.test.ts +177 -0
  98. package/agents/__tests__/registry.test.ts +13 -13
  99. package/agents/base-agent.ts +8 -0
  100. package/agents/registry.ts +171 -28
  101. package/core/__tests__/integration.test.ts +4 -4
  102. package/core/__tests__/orchestrator.test.ts +17 -16
  103. package/core/cli.ts +128 -6
  104. package/core/license.ts +208 -211
  105. package/core/orchestrator.ts +78 -5
  106. package/dist/agents/15-regression-sentinel.d.ts +2 -1
  107. package/dist/agents/15-regression-sentinel.d.ts.map +1 -1
  108. package/dist/agents/15-regression-sentinel.js +2 -2
  109. package/dist/agents/15-regression-sentinel.js.map +1 -1
  110. package/dist/agents/24-signup-onboarding-tester.d.ts +35 -0
  111. package/dist/agents/24-signup-onboarding-tester.d.ts.map +1 -0
  112. package/dist/agents/24-signup-onboarding-tester.js +357 -0
  113. package/dist/agents/24-signup-onboarding-tester.js.map +1 -0
  114. package/dist/agents/25-crud-flow-tester.d.ts +11 -0
  115. package/dist/agents/25-crud-flow-tester.d.ts.map +1 -0
  116. package/dist/agents/25-crud-flow-tester.js +253 -0
  117. package/dist/agents/25-crud-flow-tester.js.map +1 -0
  118. package/dist/agents/26-form-validator.d.ts +12 -0
  119. package/dist/agents/26-form-validator.d.ts.map +1 -0
  120. package/dist/agents/26-form-validator.js +257 -0
  121. package/dist/agents/26-form-validator.js.map +1 -0
  122. package/dist/agents/27-search-filter-tester.d.ts +20 -0
  123. package/dist/agents/27-search-filter-tester.d.ts.map +1 -0
  124. package/dist/agents/27-search-filter-tester.js +267 -0
  125. package/dist/agents/27-search-filter-tester.js.map +1 -0
  126. package/dist/agents/28-navigation-routing-tester.d.ts +32 -0
  127. package/dist/agents/28-navigation-routing-tester.d.ts.map +1 -0
  128. package/dist/agents/28-navigation-routing-tester.js +363 -0
  129. package/dist/agents/28-navigation-routing-tester.js.map +1 -0
  130. package/dist/agents/29-responsive-interaction-tester.d.ts +26 -0
  131. package/dist/agents/29-responsive-interaction-tester.d.ts.map +1 -0
  132. package/dist/agents/29-responsive-interaction-tester.js +272 -0
  133. package/dist/agents/29-responsive-interaction-tester.js.map +1 -0
  134. package/dist/agents/30-multi-user-scenario-tester.d.ts +24 -0
  135. package/dist/agents/30-multi-user-scenario-tester.d.ts.map +1 -0
  136. package/dist/agents/30-multi-user-scenario-tester.js +254 -0
  137. package/dist/agents/30-multi-user-scenario-tester.js.map +1 -0
  138. package/dist/agents/31-load-tester.d.ts +12 -0
  139. package/dist/agents/31-load-tester.d.ts.map +1 -0
  140. package/dist/agents/31-load-tester.js +110 -0
  141. package/dist/agents/31-load-tester.js.map +1 -0
  142. package/dist/agents/32-memory-leak-detector.d.ts +12 -0
  143. package/dist/agents/32-memory-leak-detector.d.ts.map +1 -0
  144. package/dist/agents/32-memory-leak-detector.js +167 -0
  145. package/dist/agents/32-memory-leak-detector.js.map +1 -0
  146. package/dist/agents/33-bundle-analyzer.d.ts +10 -0
  147. package/dist/agents/33-bundle-analyzer.d.ts.map +1 -0
  148. package/dist/agents/33-bundle-analyzer.js +111 -0
  149. package/dist/agents/33-bundle-analyzer.js.map +1 -0
  150. package/dist/agents/34-xss-scanner.d.ts +11 -0
  151. package/dist/agents/34-xss-scanner.d.ts.map +1 -0
  152. package/dist/agents/34-xss-scanner.js +164 -0
  153. package/dist/agents/34-xss-scanner.js.map +1 -0
  154. package/dist/agents/35-csrf-tester.d.ts +11 -0
  155. package/dist/agents/35-csrf-tester.d.ts.map +1 -0
  156. package/dist/agents/35-csrf-tester.js +70 -0
  157. package/dist/agents/35-csrf-tester.js.map +1 -0
  158. package/dist/agents/36-auth-fuzzer.d.ts +13 -0
  159. package/dist/agents/36-auth-fuzzer.d.ts.map +1 -0
  160. package/dist/agents/36-auth-fuzzer.js +163 -0
  161. package/dist/agents/36-auth-fuzzer.js.map +1 -0
  162. package/dist/agents/37-dependency-scanner.d.ts +11 -0
  163. package/dist/agents/37-dependency-scanner.d.ts.map +1 -0
  164. package/dist/agents/37-dependency-scanner.js +139 -0
  165. package/dist/agents/37-dependency-scanner.js.map +1 -0
  166. package/dist/agents/38-secrets-scanner.d.ts +11 -0
  167. package/dist/agents/38-secrets-scanner.d.ts.map +1 -0
  168. package/dist/agents/38-secrets-scanner.js +116 -0
  169. package/dist/agents/38-secrets-scanner.js.map +1 -0
  170. package/dist/agents/39-api-contract-tester.d.ts +12 -0
  171. package/dist/agents/39-api-contract-tester.d.ts.map +1 -0
  172. package/dist/agents/39-api-contract-tester.js +142 -0
  173. package/dist/agents/39-api-contract-tester.js.map +1 -0
  174. package/dist/agents/40-rate-limit-tester.d.ts +12 -0
  175. package/dist/agents/40-rate-limit-tester.d.ts.map +1 -0
  176. package/dist/agents/40-rate-limit-tester.js +79 -0
  177. package/dist/agents/40-rate-limit-tester.js.map +1 -0
  178. package/dist/agents/41-api-pagination-tester.d.ts +12 -0
  179. package/dist/agents/41-api-pagination-tester.d.ts.map +1 -0
  180. package/dist/agents/41-api-pagination-tester.js +79 -0
  181. package/dist/agents/41-api-pagination-tester.js.map +1 -0
  182. package/dist/agents/42-graphql-tester.d.ts +13 -0
  183. package/dist/agents/42-graphql-tester.d.ts.map +1 -0
  184. package/dist/agents/42-graphql-tester.js +187 -0
  185. package/dist/agents/42-graphql-tester.js.map +1 -0
  186. package/dist/agents/43-data-consistency-checker.d.ts +11 -0
  187. package/dist/agents/43-data-consistency-checker.d.ts.map +1 -0
  188. package/dist/agents/43-data-consistency-checker.js +176 -0
  189. package/dist/agents/43-data-consistency-checker.js.map +1 -0
  190. package/dist/agents/44-backup-recovery-tester.d.ts +11 -0
  191. package/dist/agents/44-backup-recovery-tester.d.ts.map +1 -0
  192. package/dist/agents/44-backup-recovery-tester.js +128 -0
  193. package/dist/agents/44-backup-recovery-tester.js.map +1 -0
  194. package/dist/agents/45-data-privacy-scanner.d.ts +11 -0
  195. package/dist/agents/45-data-privacy-scanner.d.ts.map +1 -0
  196. package/dist/agents/45-data-privacy-scanner.js +100 -0
  197. package/dist/agents/45-data-privacy-scanner.js.map +1 -0
  198. package/dist/agents/46-seo-auditor.d.ts +12 -0
  199. package/dist/agents/46-seo-auditor.d.ts.map +1 -0
  200. package/dist/agents/46-seo-auditor.js +275 -0
  201. package/dist/agents/46-seo-auditor.js.map +1 -0
  202. package/dist/agents/47-social-preview-tester.d.ts +11 -0
  203. package/dist/agents/47-social-preview-tester.d.ts.map +1 -0
  204. package/dist/agents/47-social-preview-tester.js +219 -0
  205. package/dist/agents/47-social-preview-tester.js.map +1 -0
  206. package/dist/agents/48-lighthouse-auditor.d.ts +11 -0
  207. package/dist/agents/48-lighthouse-auditor.d.ts.map +1 -0
  208. package/dist/agents/48-lighthouse-auditor.js +192 -0
  209. package/dist/agents/48-lighthouse-auditor.js.map +1 -0
  210. package/dist/agents/49-i18n-tester.d.ts +13 -0
  211. package/dist/agents/49-i18n-tester.d.ts.map +1 -0
  212. package/dist/agents/49-i18n-tester.js +172 -0
  213. package/dist/agents/49-i18n-tester.js.map +1 -0
  214. package/dist/agents/50-timezone-tester.d.ts +11 -0
  215. package/dist/agents/50-timezone-tester.d.ts.map +1 -0
  216. package/dist/agents/50-timezone-tester.js +152 -0
  217. package/dist/agents/50-timezone-tester.js.map +1 -0
  218. package/dist/agents/51-error-recovery-tester.d.ts +11 -0
  219. package/dist/agents/51-error-recovery-tester.d.ts.map +1 -0
  220. package/dist/agents/51-error-recovery-tester.js +134 -0
  221. package/dist/agents/51-error-recovery-tester.js.map +1 -0
  222. package/dist/agents/52-offline-mode-tester.d.ts +12 -0
  223. package/dist/agents/52-offline-mode-tester.d.ts.map +1 -0
  224. package/dist/agents/52-offline-mode-tester.js +161 -0
  225. package/dist/agents/52-offline-mode-tester.js.map +1 -0
  226. package/dist/agents/53-graceful-degradation-tester.d.ts +12 -0
  227. package/dist/agents/53-graceful-degradation-tester.d.ts.map +1 -0
  228. package/dist/agents/53-graceful-degradation-tester.js +130 -0
  229. package/dist/agents/53-graceful-degradation-tester.js.map +1 -0
  230. package/dist/agents/54-websocket-tester.d.ts +10 -0
  231. package/dist/agents/54-websocket-tester.d.ts.map +1 -0
  232. package/dist/agents/54-websocket-tester.js +132 -0
  233. package/dist/agents/54-websocket-tester.js.map +1 -0
  234. package/dist/agents/55-realtime-sync-tester.d.ts +11 -0
  235. package/dist/agents/55-realtime-sync-tester.d.ts.map +1 -0
  236. package/dist/agents/55-realtime-sync-tester.js +175 -0
  237. package/dist/agents/55-realtime-sync-tester.js.map +1 -0
  238. package/dist/agents/56-file-upload-tester.d.ts +12 -0
  239. package/dist/agents/56-file-upload-tester.d.ts.map +1 -0
  240. package/dist/agents/56-file-upload-tester.js +166 -0
  241. package/dist/agents/56-file-upload-tester.js.map +1 -0
  242. package/dist/agents/57-export-tester.d.ts +11 -0
  243. package/dist/agents/57-export-tester.d.ts.map +1 -0
  244. package/dist/agents/57-export-tester.js +155 -0
  245. package/dist/agents/57-export-tester.js.map +1 -0
  246. package/dist/agents/58-payment-flow-tester.d.ts +11 -0
  247. package/dist/agents/58-payment-flow-tester.d.ts.map +1 -0
  248. package/dist/agents/58-payment-flow-tester.js +159 -0
  249. package/dist/agents/58-payment-flow-tester.js.map +1 -0
  250. package/dist/agents/59-ssl-tls-auditor.d.ts +10 -0
  251. package/dist/agents/59-ssl-tls-auditor.d.ts.map +1 -0
  252. package/dist/agents/59-ssl-tls-auditor.js +132 -0
  253. package/dist/agents/59-ssl-tls-auditor.js.map +1 -0
  254. package/dist/agents/60-dns-cdn-tester.d.ts +10 -0
  255. package/dist/agents/60-dns-cdn-tester.d.ts.map +1 -0
  256. package/dist/agents/60-dns-cdn-tester.js +105 -0
  257. package/dist/agents/60-dns-cdn-tester.js.map +1 -0
  258. package/dist/agents/61-docker-health-checker.d.ts +10 -0
  259. package/dist/agents/61-docker-health-checker.d.ts.map +1 -0
  260. package/dist/agents/61-docker-health-checker.js +95 -0
  261. package/dist/agents/61-docker-health-checker.js.map +1 -0
  262. package/dist/agents/62-env-config-validator.d.ts +10 -0
  263. package/dist/agents/62-env-config-validator.d.ts.map +1 -0
  264. package/dist/agents/62-env-config-validator.js +132 -0
  265. package/dist/agents/62-env-config-validator.js.map +1 -0
  266. package/dist/agents/63-log-quality-auditor.d.ts +9 -0
  267. package/dist/agents/63-log-quality-auditor.d.ts.map +1 -0
  268. package/dist/agents/63-log-quality-auditor.js +121 -0
  269. package/dist/agents/63-log-quality-auditor.js.map +1 -0
  270. package/dist/agents/64-analytics-tracker-tester.d.ts +10 -0
  271. package/dist/agents/64-analytics-tracker-tester.d.ts.map +1 -0
  272. package/dist/agents/64-analytics-tracker-tester.js +146 -0
  273. package/dist/agents/64-analytics-tracker-tester.js.map +1 -0
  274. package/dist/agents/65-gdpr-compliance-tester.d.ts +13 -0
  275. package/dist/agents/65-gdpr-compliance-tester.d.ts.map +1 -0
  276. package/dist/agents/65-gdpr-compliance-tester.js +186 -0
  277. package/dist/agents/65-gdpr-compliance-tester.js.map +1 -0
  278. package/dist/agents/66-soc2-control-validator.d.ts +14 -0
  279. package/dist/agents/66-soc2-control-validator.d.ts.map +1 -0
  280. package/dist/agents/66-soc2-control-validator.js +178 -0
  281. package/dist/agents/66-soc2-control-validator.js.map +1 -0
  282. package/dist/agents/67-wcag-aaa-tester.d.ts +13 -0
  283. package/dist/agents/67-wcag-aaa-tester.d.ts.map +1 -0
  284. package/dist/agents/67-wcag-aaa-tester.js +207 -0
  285. package/dist/agents/67-wcag-aaa-tester.js.map +1 -0
  286. package/dist/agents/68-dead-code-detector.d.ts +9 -0
  287. package/dist/agents/68-dead-code-detector.d.ts.map +1 -0
  288. package/dist/agents/68-dead-code-detector.js +116 -0
  289. package/dist/agents/68-dead-code-detector.js.map +1 -0
  290. package/dist/agents/69-type-safety-auditor.d.ts +9 -0
  291. package/dist/agents/69-type-safety-auditor.d.ts.map +1 -0
  292. package/dist/agents/69-type-safety-auditor.js +148 -0
  293. package/dist/agents/69-type-safety-auditor.js.map +1 -0
  294. package/dist/agents/70-complexity-analyzer.d.ts +10 -0
  295. package/dist/agents/70-complexity-analyzer.d.ts.map +1 -0
  296. package/dist/agents/70-complexity-analyzer.js +154 -0
  297. package/dist/agents/70-complexity-analyzer.js.map +1 -0
  298. package/dist/agents/base-agent.d.ts +3 -1
  299. package/dist/agents/base-agent.d.ts.map +1 -1
  300. package/dist/agents/base-agent.js +7 -1
  301. package/dist/agents/base-agent.js.map +1 -1
  302. package/dist/agents/registry.d.ts +5 -4
  303. package/dist/agents/registry.d.ts.map +1 -1
  304. package/dist/agents/registry.js +170 -29
  305. package/dist/agents/registry.js.map +1 -1
  306. package/dist/clients/agent-mvp.d.ts +66 -0
  307. package/dist/clients/agent-mvp.d.ts.map +1 -0
  308. package/dist/clients/agent-mvp.js +91 -0
  309. package/dist/clients/agent-mvp.js.map +1 -0
  310. package/dist/clients/total-recall.d.ts +37 -0
  311. package/dist/clients/total-recall.d.ts.map +1 -0
  312. package/dist/clients/total-recall.js +224 -0
  313. package/dist/clients/total-recall.js.map +1 -0
  314. package/dist/core/cli.d.ts +3 -0
  315. package/dist/core/cli.d.ts.map +1 -1
  316. package/dist/core/cli.js +122 -6
  317. package/dist/core/cli.js.map +1 -1
  318. package/dist/core/license.js +2 -5
  319. package/dist/core/license.js.map +1 -1
  320. package/dist/core/orchestrator.d.ts +10 -1
  321. package/dist/core/orchestrator.d.ts.map +1 -1
  322. package/dist/core/orchestrator.js +66 -5
  323. package/dist/core/orchestrator.js.map +1 -1
  324. package/package.json +2 -2
@@ -0,0 +1,210 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import type { Browser } from 'playwright';
4
+ import type { Finding } from '../core/types';
5
+ import { BaseAgent } from './base-agent';
6
+ import { resolveEnvironment } from '../helpers/env-resolver';
7
+
8
+ /** Glob-like manual scan for .ts files under src/. */
9
+ function findTsFiles(dir: string, results: string[] = []): string[] {
10
+ if (!fs.existsSync(dir)) return results;
11
+
12
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
13
+ for (const entry of entries) {
14
+ const fullPath = path.join(dir, entry.name);
15
+ if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== '.git') {
16
+ findTsFiles(fullPath, results);
17
+ } else if (entry.isFile() && entry.name.endsWith('.ts')) {
18
+ results.push(fullPath);
19
+ }
20
+ }
21
+ return results;
22
+ }
23
+
24
+ export class Soc2ControlValidatorAgent extends BaseAgent {
25
+ readonly agentId = 66;
26
+ readonly agentName = 'SOC2 Control Validator';
27
+ private baseUrl = '';
28
+
29
+ protected async preFlight(): Promise<void> {
30
+ const { env } = await resolveEnvironment(this.config, this.phase);
31
+ this.baseUrl = env.baseUrl;
32
+ }
33
+
34
+ protected async execute(): Promise<Finding[]> {
35
+ const findings: Finding[] = [];
36
+
37
+ const projectRoot = this.config.projectRoot ?? process.cwd();
38
+ const srcDir = path.join(projectRoot, 'src');
39
+
40
+ // Check 1: Audit logging evidence
41
+ const auditFindings = this.checkAuditLogging(srcDir);
42
+ findings.push(...auditFindings);
43
+
44
+ // Check 2: Session timeout
45
+ const sessionFindings = this.checkSessionTimeout(srcDir);
46
+ findings.push(...sessionFindings);
47
+
48
+ // Check 3: MFA UI
49
+ const mfaFindings = await this.checkMfaUI();
50
+ findings.push(...mfaFindings);
51
+
52
+ // Check 4: Role-based access
53
+ const rbacFindings = this.checkRoleBasedAccess(srcDir);
54
+ findings.push(...rbacFindings);
55
+
56
+ return findings;
57
+ }
58
+
59
+ private checkAuditLogging(srcDir: string): Finding[] {
60
+ const findings: Finding[] = [];
61
+
62
+ if (!fs.existsSync(srcDir)) {
63
+ findings.push({
64
+ id: `${this.agentId}-no-src`,
65
+ type: 'infra-issue',
66
+ severity: 'low',
67
+ agentId: this.agentId,
68
+ module: 'soc2-control-validator',
69
+ description: 'No src/ directory found — cannot check for audit logging',
70
+ });
71
+ return findings;
72
+ }
73
+
74
+ const tsFiles = findTsFiles(srcDir);
75
+ let hasAuditLogging = false;
76
+
77
+ for (const filePath of tsFiles) {
78
+ const content = fs.readFileSync(filePath, 'utf-8');
79
+ if (/audit/i.test(content) && (/log/i.test(content) || /trail/i.test(content) || /event/i.test(content))) {
80
+ hasAuditLogging = true;
81
+ this.addEvidence({
82
+ type: 'log',
83
+ path: filePath,
84
+ description: 'Audit logging evidence found',
85
+ });
86
+ break;
87
+ }
88
+ }
89
+
90
+ if (!hasAuditLogging) {
91
+ findings.push({
92
+ id: `${this.agentId}-no-audit-logging`,
93
+ type: 'code-bug-security',
94
+ severity: 'medium',
95
+ agentId: this.agentId,
96
+ module: 'soc2-control-validator',
97
+ description: 'No audit logging evidence found in source code',
98
+ suggestedFix: 'Implement audit logging for security-relevant events',
99
+ });
100
+ }
101
+
102
+ return findings;
103
+ }
104
+
105
+ private checkSessionTimeout(srcDir: string): Finding[] {
106
+ const findings: Finding[] = [];
107
+
108
+ if (!fs.existsSync(srcDir)) return findings;
109
+
110
+ const tsFiles = findTsFiles(srcDir);
111
+ let hasSessionTimeout = false;
112
+
113
+ for (const filePath of tsFiles) {
114
+ const content = fs.readFileSync(filePath, 'utf-8');
115
+ if (/sessionTimeout/i.test(content) || /session.*timeout/i.test(content) || /setTimeout.*session/i.test(content) || /idle.*timeout/i.test(content)) {
116
+ hasSessionTimeout = true;
117
+ break;
118
+ }
119
+ }
120
+
121
+ if (!hasSessionTimeout) {
122
+ findings.push({
123
+ id: `${this.agentId}-no-session-timeout`,
124
+ type: 'code-bug-security',
125
+ severity: 'medium',
126
+ agentId: this.agentId,
127
+ module: 'soc2-control-validator',
128
+ description: 'No session timeout configuration found in source code',
129
+ suggestedFix: 'Implement session timeout to auto-logout inactive users',
130
+ });
131
+ }
132
+
133
+ return findings;
134
+ }
135
+
136
+ private async checkMfaUI(): Promise<Finding[]> {
137
+ const findings: Finding[] = [];
138
+
139
+ try {
140
+ const { chromium } = await import('playwright');
141
+ let browser: Browser | null = null;
142
+
143
+ try {
144
+ browser = await chromium.launch({ headless: true });
145
+ const page = await browser.newPage();
146
+
147
+ await page.goto(this.baseUrl, { waitUntil: 'domcontentloaded', timeout: 10_000 });
148
+
149
+ const bodyText = await page.evaluate(() => document.body.innerText.toLowerCase());
150
+
151
+ const hasMfaUI = bodyText.includes('two-factor') ||
152
+ bodyText.includes('2fa') ||
153
+ bodyText.includes('mfa') ||
154
+ bodyText.includes('multi-factor') ||
155
+ bodyText.includes('authenticator');
156
+
157
+ if (!hasMfaUI) {
158
+ findings.push({
159
+ id: `${this.agentId}-no-mfa`,
160
+ type: 'code-bug-security',
161
+ severity: 'medium',
162
+ agentId: this.agentId,
163
+ module: 'soc2-control-validator',
164
+ description: 'No MFA/2FA UI elements detected',
165
+ suggestedFix: 'Implement multi-factor authentication for SOC2 compliance',
166
+ });
167
+ }
168
+
169
+ await page.close().catch(() => undefined);
170
+ } finally {
171
+ if (browser) await browser.close().catch(() => undefined);
172
+ }
173
+ } catch {
174
+ // Playwright not available — skip MFA UI check
175
+ }
176
+
177
+ return findings;
178
+ }
179
+
180
+ private checkRoleBasedAccess(srcDir: string): Finding[] {
181
+ const findings: Finding[] = [];
182
+
183
+ if (!fs.existsSync(srcDir)) return findings;
184
+
185
+ const tsFiles = findTsFiles(srcDir);
186
+ let hasRbac = false;
187
+
188
+ for (const filePath of tsFiles) {
189
+ const content = fs.readFileSync(filePath, 'utf-8');
190
+ if (/role/i.test(content) && (/guard/i.test(content) || /permission/i.test(content) || /authorize/i.test(content) || /access/i.test(content))) {
191
+ hasRbac = true;
192
+ break;
193
+ }
194
+ }
195
+
196
+ if (!hasRbac) {
197
+ findings.push({
198
+ id: `${this.agentId}-no-rbac`,
199
+ type: 'code-bug-security',
200
+ severity: 'medium',
201
+ agentId: this.agentId,
202
+ module: 'soc2-control-validator',
203
+ description: 'No role-based access control evidence found in source code',
204
+ suggestedFix: 'Implement RBAC with role checks on protected resources',
205
+ });
206
+ }
207
+
208
+ return findings;
209
+ }
210
+ }
@@ -0,0 +1,241 @@
1
+ import type { Browser, Page } from 'playwright';
2
+ import type { Finding } from '../core/types';
3
+ import { BaseAgent } from './base-agent';
4
+ import { resolveEnvironment } from '../helpers/env-resolver';
5
+ import { login } from '../helpers/navigation';
6
+
7
+ export class WcagAaaTesterAgent extends BaseAgent {
8
+ readonly agentId = 67;
9
+ readonly agentName = 'WCAG AAA Tester';
10
+ private baseUrl = '';
11
+
12
+ protected async preFlight(): Promise<void> {
13
+ if (!this.config.modules || this.config.modules.length === 0) {
14
+ throw new Error('WcagAaaTesterAgent requires at least one module in config.modules');
15
+ }
16
+
17
+ const { env } = await resolveEnvironment(this.config, this.phase);
18
+ this.baseUrl = env.baseUrl;
19
+ }
20
+
21
+ protected async execute(): Promise<Finding[]> {
22
+ const findings: Finding[] = [];
23
+
24
+ const rawLoginUrl = this.config.auth.loginUrl ?? '/login';
25
+ const loginUrl = rawLoginUrl.startsWith('http') ? rawLoginUrl : `${this.baseUrl}${rawLoginUrl}`;
26
+ const credentials =
27
+ this.config.auth.credentials?.['admin'] ??
28
+ Object.values(this.config.auth.credentials ?? {})[0];
29
+
30
+ const { chromium } = await import('playwright');
31
+
32
+ let browser: Browser | null = null;
33
+
34
+ try {
35
+ browser = await chromium.launch({ headless: true });
36
+ const page = await browser.newPage();
37
+
38
+ if (credentials) {
39
+ try {
40
+ await login(page, credentials, loginUrl);
41
+ } catch {
42
+ findings.push({
43
+ id: `${this.agentId}-login-failed`,
44
+ type: 'infra-issue',
45
+ severity: 'medium',
46
+ agentId: this.agentId,
47
+ module: 'wcag-aaa-tester',
48
+ description: 'Login failed — continuing anonymously',
49
+ });
50
+ }
51
+ }
52
+
53
+ for (const mod of this.config.modules) {
54
+ const fullUrl = mod.route.startsWith('http')
55
+ ? mod.route
56
+ : `${this.baseUrl}${mod.route}`;
57
+
58
+ try {
59
+ await page.goto(fullUrl, { waitUntil: 'domcontentloaded', timeout: 10_000 });
60
+ } catch {
61
+ continue;
62
+ }
63
+
64
+ // Test 1: Text contrast ratio >= 7:1 (AAA)
65
+ const contrastFindings = await this.checkContrast(page, mod.id);
66
+ findings.push(...contrastFindings);
67
+
68
+ // Test 2: Text resizable to 200%
69
+ const resizeFindings = await this.checkTextResize(page, mod.id);
70
+ findings.push(...resizeFindings);
71
+
72
+ // Test 3: Keyboard navigation
73
+ const keyboardFindings = await this.checkKeyboardNavigation(page, mod.id);
74
+ findings.push(...keyboardFindings);
75
+ }
76
+
77
+ await page.close().catch(() => undefined);
78
+ } catch (playwrightError) {
79
+ findings.push({
80
+ id: `${this.agentId}-playwright-failure`,
81
+ type: 'infra-issue',
82
+ severity: 'medium',
83
+ agentId: this.agentId,
84
+ module: 'wcag-aaa-tester',
85
+ description: `Playwright execution failed: ${playwrightError instanceof Error ? playwrightError.message.split('\n')[0] : String(playwrightError)}`,
86
+ });
87
+ } finally {
88
+ if (browser) await browser.close().catch(() => undefined);
89
+ }
90
+
91
+ return findings;
92
+ }
93
+
94
+ private async checkContrast(page: Page, moduleId: string): Promise<Finding[]> {
95
+ const findings: Finding[] = [];
96
+
97
+ try {
98
+ const lowContrastCount = await page.evaluate(() => {
99
+ function getLuminance(r: number, g: number, b: number): number {
100
+ const sRGB = [r, g, b].map(c => {
101
+ const s = c / 255;
102
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
103
+ });
104
+ return 0.2126 * sRGB[0] + 0.7152 * sRGB[1] + 0.0722 * sRGB[2];
105
+ }
106
+
107
+ function parseColor(color: string): [number, number, number] | null {
108
+ const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
109
+ if (match) return [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])];
110
+ return null;
111
+ }
112
+
113
+ const elements = document.querySelectorAll('p, span, a, h1, h2, h3, h4, h5, h6, li, td, th, label');
114
+ let lowContrast = 0;
115
+
116
+ for (const el of Array.from(elements).slice(0, 50)) {
117
+ const style = window.getComputedStyle(el);
118
+ const fg = parseColor(style.color);
119
+ const bg = parseColor(style.backgroundColor);
120
+
121
+ if (fg && bg) {
122
+ const fgLum = getLuminance(...fg);
123
+ const bgLum = getLuminance(...bg);
124
+ const ratio = (Math.max(fgLum, bgLum) + 0.05) / (Math.min(fgLum, bgLum) + 0.05);
125
+
126
+ if (ratio < 7) {
127
+ lowContrast++;
128
+ }
129
+ }
130
+ }
131
+
132
+ return lowContrast;
133
+ });
134
+
135
+ if (lowContrastCount > 0) {
136
+ findings.push({
137
+ id: `${this.agentId}-low-contrast-${moduleId}`,
138
+ type: 'test-bug',
139
+ severity: 'medium',
140
+ agentId: this.agentId,
141
+ module: moduleId,
142
+ description: `${lowContrastCount} element(s) have contrast ratio below 7:1 (WCAG AAA requirement)`,
143
+ });
144
+ }
145
+ } catch {
146
+ // Contrast check failed — non-critical
147
+ }
148
+
149
+ return findings;
150
+ }
151
+
152
+ private async checkTextResize(page: Page, moduleId: string): Promise<Finding[]> {
153
+ const findings: Finding[] = [];
154
+
155
+ try {
156
+ const hasOverflow = await page.evaluate(() => {
157
+ document.documentElement.style.fontSize = '200%';
158
+
159
+ // Wait a tick for reflow
160
+ const body = document.body;
161
+ const hasHorizontalOverflow = body.scrollWidth > window.innerWidth;
162
+
163
+ // Reset
164
+ document.documentElement.style.fontSize = '';
165
+
166
+ return hasHorizontalOverflow;
167
+ });
168
+
169
+ if (hasOverflow) {
170
+ findings.push({
171
+ id: `${this.agentId}-text-resize-overflow-${moduleId}`,
172
+ type: 'test-bug',
173
+ severity: 'medium',
174
+ agentId: this.agentId,
175
+ module: moduleId,
176
+ description: `Content overflows horizontally when text is resized to 200% in ${moduleId}`,
177
+ });
178
+ }
179
+ } catch {
180
+ // Resize check failed — non-critical
181
+ }
182
+
183
+ return findings;
184
+ }
185
+
186
+ private async checkKeyboardNavigation(page: Page, moduleId: string): Promise<Finding[]> {
187
+ const findings: Finding[] = [];
188
+
189
+ try {
190
+ // Tab through elements and check focus visibility
191
+ const focusableCount = await page.evaluate(() => {
192
+ const focusable = document.querySelectorAll('a, button, input, select, textarea, [tabindex]');
193
+ return focusable.length;
194
+ });
195
+
196
+ if (focusableCount === 0) {
197
+ findings.push({
198
+ id: `${this.agentId}-no-focusable-${moduleId}`,
199
+ type: 'test-bug',
200
+ severity: 'medium',
201
+ agentId: this.agentId,
202
+ module: moduleId,
203
+ description: `No focusable elements found in ${moduleId} — keyboard navigation may not work`,
204
+ });
205
+ return findings;
206
+ }
207
+
208
+ // Press Tab a few times and check if focus is visible
209
+ for (let i = 0; i < Math.min(5, focusableCount); i++) {
210
+ await page.keyboard.press('Tab');
211
+ }
212
+
213
+ const hasFocusIndicator = await page.evaluate(() => {
214
+ const focused = document.activeElement;
215
+ if (!focused || focused === document.body) return false;
216
+
217
+ const style = window.getComputedStyle(focused);
218
+ const hasOutline = style.outlineStyle !== 'none' && style.outlineWidth !== '0px';
219
+ const hasBoxShadow = style.boxShadow !== 'none';
220
+ const hasBorder = style.borderColor !== style.backgroundColor;
221
+
222
+ return hasOutline || hasBoxShadow || hasBorder;
223
+ });
224
+
225
+ if (!hasFocusIndicator) {
226
+ findings.push({
227
+ id: `${this.agentId}-no-focus-indicator-${moduleId}`,
228
+ type: 'test-bug',
229
+ severity: 'medium',
230
+ agentId: this.agentId,
231
+ module: moduleId,
232
+ description: `Focus indicator not visible during keyboard navigation in ${moduleId}`,
233
+ });
234
+ }
235
+ } catch {
236
+ // Keyboard nav check failed — non-critical
237
+ }
238
+
239
+ return findings;
240
+ }
241
+ }
@@ -0,0 +1,135 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import type { Finding } from '../core/types';
4
+ import { BaseAgent } from './base-agent';
5
+
6
+ /** Find all .ts files under a directory (excluding tests and node_modules). */
7
+ function findTsFiles(dir: string, results: string[] = []): string[] {
8
+ if (!fs.existsSync(dir)) return results;
9
+
10
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
11
+ for (const entry of entries) {
12
+ const fullPath = path.join(dir, entry.name);
13
+ if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== '.git' && entry.name !== 'dist') {
14
+ findTsFiles(fullPath, results);
15
+ } else if (entry.isFile() && entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts') && !entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.d.ts')) {
16
+ results.push(fullPath);
17
+ }
18
+ }
19
+ return results;
20
+ }
21
+
22
+ /** Extract exported identifiers from a file. */
23
+ function extractExports(content: string): string[] {
24
+ const exports: string[] = [];
25
+
26
+ // export function/class/const/let/var/type/interface/enum
27
+ const exportPattern = /export\s+(?:async\s+)?(?:function|class|const|let|var|type|interface|enum)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
28
+ let match: RegExpExecArray | null;
29
+ while ((match = exportPattern.exec(content)) !== null) {
30
+ exports.push(match[1]);
31
+ }
32
+
33
+ // export { ... }
34
+ const namedExportPattern = /export\s*\{([^}]+)\}/g;
35
+ while ((match = namedExportPattern.exec(content)) !== null) {
36
+ const names = match[1].split(',').map(n => n.trim().split(/\s+as\s+/)[0].trim());
37
+ exports.push(...names.filter(n => n.length > 0));
38
+ }
39
+
40
+ return exports;
41
+ }
42
+
43
+ export class DeadCodeDetectorAgent extends BaseAgent {
44
+ readonly agentId = 68;
45
+ readonly agentName = 'Dead Code Detector';
46
+
47
+ protected async preFlight(): Promise<void> {
48
+ // File-based agent
49
+ }
50
+
51
+ protected async execute(): Promise<Finding[]> {
52
+ const findings: Finding[] = [];
53
+
54
+ const projectRoot = this.config.projectRoot ?? process.cwd();
55
+ const srcDir = path.join(projectRoot, 'src');
56
+
57
+ if (!fs.existsSync(srcDir)) {
58
+ findings.push({
59
+ id: `${this.agentId}-no-src-dir`,
60
+ type: 'infra-issue',
61
+ severity: 'low',
62
+ agentId: this.agentId,
63
+ module: 'dead-code-detector',
64
+ description: 'No src/ directory found in project root',
65
+ });
66
+ return findings;
67
+ }
68
+
69
+ const tsFiles = findTsFiles(srcDir);
70
+
71
+ // Phase 1: Collect all exports
72
+ const exportMap: Map<string, { file: string; name: string }[]> = new Map();
73
+ const allContents: Map<string, string> = new Map();
74
+
75
+ for (const filePath of tsFiles) {
76
+ const content = fs.readFileSync(filePath, 'utf-8');
77
+ allContents.set(filePath, content);
78
+
79
+ const fileExports = extractExports(content);
80
+ for (const exp of fileExports) {
81
+ const existing = exportMap.get(exp) ?? [];
82
+ existing.push({ file: filePath, name: exp });
83
+ exportMap.set(exp, existing);
84
+ }
85
+ }
86
+
87
+ // Phase 2: Check which exports are imported somewhere
88
+ const allContent = Array.from(allContents.values()).join('\n');
89
+ let unusedCount = 0;
90
+
91
+ for (const [name, locations] of exportMap) {
92
+ // Skip common/expected exports
93
+ if (['default', 'main', 'App', 'bootstrap', 'configure'].includes(name)) continue;
94
+
95
+ // Count occurrences across all files
96
+ const fromPattern = new RegExp(`\\b${name}\\b`, 'g');
97
+ const totalOccurrences = (allContent.match(fromPattern) ?? []).length;
98
+
99
+ // If the name only appears in its own export(s), it's unused
100
+ if (totalOccurrences <= locations.length) {
101
+ unusedCount++;
102
+ if (unusedCount <= 10) {
103
+ findings.push({
104
+ id: `${this.agentId}-unused-export-${unusedCount}`,
105
+ type: 'test-bug',
106
+ severity: 'low',
107
+ agentId: this.agentId,
108
+ module: 'dead-code-detector',
109
+ file: locations[0].file,
110
+ description: `Unused export: "${name}" in ${path.relative(projectRoot, locations[0].file)}`,
111
+ });
112
+ }
113
+ }
114
+ }
115
+
116
+ if (unusedCount > 10) {
117
+ findings.push({
118
+ id: `${this.agentId}-unused-export-summary`,
119
+ type: 'test-bug',
120
+ severity: 'low',
121
+ agentId: this.agentId,
122
+ module: 'dead-code-detector',
123
+ description: `${unusedCount} total unused exports found (showing first 10)`,
124
+ });
125
+ }
126
+
127
+ this.addEvidence({
128
+ type: 'log',
129
+ path: '',
130
+ description: `Scanned ${tsFiles.length} files, found ${exportMap.size} exports, ${unusedCount} potentially unused`,
131
+ });
132
+
133
+ return findings;
134
+ }
135
+ }