@hoanghainh/komagu 2.4.0 → 2.6.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 (247) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +202 -0
  3. package/README.md +1 -0
  4. package/assess/lsa/examples/eval-run-6/gptoss-a/ai-run-stats.json +87 -0
  5. package/assess/lsa/examples/eval-run-6/gptoss-a/auth-model.md +120 -0
  6. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/index.json +60 -0
  7. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/injection-001.json +383 -0
  8. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/injection-002.json +205 -0
  9. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/privilege-001.json +838 -0
  10. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/privilege-002.json +124 -0
  11. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-001.json +778 -0
  12. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-002.json +546 -0
  13. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-003.json +661 -0
  14. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-004.json +659 -0
  15. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-005.json +612 -0
  16. package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-006.json +106 -0
  17. package/assess/lsa/examples/eval-run-6/gptoss-a/coverage.json +19 -0
  18. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-001.json +516 -0
  19. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-002.json +332 -0
  20. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-003.json +218 -0
  21. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-004.json +561 -0
  22. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-005.json +316 -0
  23. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-006.json +14 -0
  24. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/inj-injection-001.json +782 -0
  25. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/inj-injection-002.json +418 -0
  26. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/priv-privilege-001.json +627 -0
  27. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/priv-privilege-002.json +253 -0
  28. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-1.json +68 -0
  29. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-10.json +68 -0
  30. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-11.json +61 -0
  31. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-12.json +60 -0
  32. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-13.json +60 -0
  33. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-14.json +66 -0
  34. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-15.json +69 -0
  35. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-16.json +60 -0
  36. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-17.json +61 -0
  37. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-18.json +69 -0
  38. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-19.json +64 -0
  39. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-2.json +60 -0
  40. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-20.json +60 -0
  41. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-21.json +61 -0
  42. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-22.json +50 -0
  43. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-3.json +60 -0
  44. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-4.json +60 -0
  45. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-5.json +60 -0
  46. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-6.json +70 -0
  47. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-7.json +60 -0
  48. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-8.json +60 -0
  49. package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-9.json +60 -0
  50. package/assess/lsa/examples/eval-run-6/gptoss-a/findings.json +4857 -0
  51. package/assess/lsa/examples/eval-run-6/gptoss-a/mass-assignment.candidates.json +232 -0
  52. package/assess/lsa/examples/eval-run-6/gptoss-a/report.ja.md +2112 -0
  53. package/assess/lsa/examples/eval-run-6/gptoss-a/report.md +2112 -0
  54. package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-001.json +425 -0
  55. package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-002.json +333 -0
  56. package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-003.json +400 -0
  57. package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-004.json +403 -0
  58. package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-005.json +398 -0
  59. package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-006.json +63 -0
  60. package/assess/lsa/examples/eval-run-6/gptoss-a/score.json +82 -0
  61. package/assess/lsa/examples/eval-run-6/gptoss-a/stack-profile.json +225 -0
  62. package/assess/lsa/examples/eval-run-6/gptoss-b/ai-run-stats.json +91 -0
  63. package/assess/lsa/examples/eval-run-6/gptoss-b/auth-model.md +120 -0
  64. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/index.json +60 -0
  65. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/injection-001.json +383 -0
  66. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/injection-002.json +205 -0
  67. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/privilege-001.json +838 -0
  68. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/privilege-002.json +124 -0
  69. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-001.json +778 -0
  70. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-002.json +546 -0
  71. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-003.json +661 -0
  72. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-004.json +659 -0
  73. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-005.json +612 -0
  74. package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-006.json +106 -0
  75. package/assess/lsa/examples/eval-run-6/gptoss-b/coverage.json +21 -0
  76. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-001.json +593 -0
  77. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-002.json +367 -0
  78. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-003.json +207 -0
  79. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-004.json +477 -0
  80. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-005.json +341 -0
  81. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-006.json +14 -0
  82. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/inj-injection-001.json +821 -0
  83. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/inj-injection-002.json +410 -0
  84. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/priv-privilege-001.json +649 -0
  85. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/priv-privilege-002.json +222 -0
  86. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-1.json +60 -0
  87. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-10.json +67 -0
  88. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-11.json +68 -0
  89. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-12.json +60 -0
  90. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-13.json +60 -0
  91. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-14.json +64 -0
  92. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-15.json +70 -0
  93. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-16.json +60 -0
  94. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-17.json +61 -0
  95. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-18.json +60 -0
  96. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-19.json +65 -0
  97. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-2.json +60 -0
  98. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-20.json +60 -0
  99. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-21.json +62 -0
  100. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-22.json +50 -0
  101. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-3.json +60 -0
  102. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-4.json +60 -0
  103. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-5.json +60 -0
  104. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-6.json +60 -0
  105. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-7.json +64 -0
  106. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-8.json +60 -0
  107. package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-9.json +60 -0
  108. package/assess/lsa/examples/eval-run-6/gptoss-b/findings.json +4966 -0
  109. package/assess/lsa/examples/eval-run-6/gptoss-b/mass-assignment.candidates.json +232 -0
  110. package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-001.json +425 -0
  111. package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-002.json +333 -0
  112. package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-003.json +400 -0
  113. package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-004.json +403 -0
  114. package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-005.json +398 -0
  115. package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-006.json +63 -0
  116. package/assess/lsa/examples/eval-run-6/gptoss-b/score.json +87 -0
  117. package/assess/lsa/examples/eval-run-6/gptoss-b/stack-profile.json +225 -0
  118. package/assess/lsa/examples/eval-run-6/ground-truth.json +851 -0
  119. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/ai-run-stats.json +96 -0
  120. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/auth-model.md +191 -0
  121. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/index.json +60 -0
  122. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/injection-001.json +383 -0
  123. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/injection-002.json +205 -0
  124. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/privilege-001.json +838 -0
  125. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/privilege-002.json +124 -0
  126. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-001.json +778 -0
  127. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-002.json +546 -0
  128. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-003.json +661 -0
  129. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-004.json +659 -0
  130. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-005.json +612 -0
  131. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-006.json +106 -0
  132. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/coverage.json +31 -0
  133. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-001.json +527 -0
  134. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-002.json +568 -0
  135. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-003.json +467 -0
  136. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-004.json +342 -0
  137. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-005.json +693 -0
  138. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-006.json +16 -0
  139. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/inj-injection-001.json +1123 -0
  140. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/inj-injection-002.json +391 -0
  141. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/priv-privilege-001.json +726 -0
  142. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/priv-privilege-002.json +306 -0
  143. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-1.json +137 -0
  144. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-10.json +106 -0
  145. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-11.json +81 -0
  146. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-12.json +135 -0
  147. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-13.json +135 -0
  148. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-14.json +135 -0
  149. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-15.json +110 -0
  150. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-16.json +116 -0
  151. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-17.json +141 -0
  152. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-18.json +135 -0
  153. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-19.json +140 -0
  154. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-2.json +135 -0
  155. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-20.json +82 -0
  156. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-21.json +74 -0
  157. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-22.json +99 -0
  158. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-3.json +140 -0
  159. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-4.json +145 -0
  160. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-5.json +135 -0
  161. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-6.json +135 -0
  162. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-7.json +87 -0
  163. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-8.json +125 -0
  164. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-9.json +135 -0
  165. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings.json +6989 -0
  166. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/mass-assignment.candidates.json +232 -0
  167. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/memory.log +36 -0
  168. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-001.json +425 -0
  169. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-002.json +333 -0
  170. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-003.json +400 -0
  171. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-004.json +403 -0
  172. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-005.json +398 -0
  173. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-006.json +63 -0
  174. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/score.json +106 -0
  175. package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/stack-profile.json +225 -0
  176. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/auth-model.md +517 -0
  177. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-001.json +5 -0
  178. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-002.json +428 -0
  179. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-003.json +388 -0
  180. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-004.json +463 -0
  181. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-005.json +5 -0
  182. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-006.json +67 -0
  183. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/inj-injection-001.json +964 -0
  184. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings.partial.json +1872 -0
  185. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/memory.log +194 -0
  186. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/score.partial.json +108 -0
  187. package/assess/lsa/examples/eval-run-6/qwen-16k-partial/stack-profile.json +225 -0
  188. package/assess/lsa/scripts/detect_stack.py +13 -5
  189. package/assess/lsa/scripts/find_injection.py +35 -2
  190. package/assess/lsa/scripts/java_routes.py +323 -0
  191. package/assess/lsa/scripts/laravel_routes.py +102 -0
  192. package/assess/lsa/scripts/lsa_common.py +72 -2
  193. package/assess/lsa/scripts/map_routes.py +40 -161
  194. package/assess/lsa/scripts/merge_findings.py +2 -0
  195. package/assess/lsa/tests/EVAL-RESULTS.md +126 -0
  196. package/assess/lsa/tests/test_eval_run_6.py +104 -0
  197. package/assess/lsa/tests/test_java_legacy_realistic.py +453 -0
  198. package/assess/lsa/tests/test_laravel_routes.py +95 -0
  199. package/contracts/schemas/persona-suite.schema.json +38 -2
  200. package/examples/member-portal/backend-dotnet/Dockerfile +2 -1
  201. package/examples/member-portal/backend-spring/Dockerfile +2 -0
  202. package/examples/member-portal/docker-compose.yml +1 -1
  203. package/examples/member-portal/frontend/Dockerfile +3 -2
  204. package/examples/member-portal/frontend/package-lock.json +24 -656
  205. package/examples/member-portal/frontend/package.json +1 -1
  206. package/operate/ai/client.py +22 -9
  207. package/operate/ai/runner.py +24 -4
  208. package/operate/cli/__init__.py +1 -1
  209. package/operate/cli/commands/fix.py +4 -0
  210. package/operate/cli/commands/leak_check.py +75 -0
  211. package/operate/cli/commands/protect.py +32 -3
  212. package/operate/cli/commands/scan.py +8 -1
  213. package/operate/cli/commands/test.py +131 -15
  214. package/operate/cli/main.py +5 -3
  215. package/operate/cross_user_tester/persona_matrix.py +118 -25
  216. package/operate/cross_user_tester/runner.py +190 -7
  217. package/operate/cross_user_tester/session_config.py +180 -0
  218. package/operate/cross_user_tester/session_http.py +288 -0
  219. package/operate/devsecops/leak_check.py +314 -0
  220. package/operate/remediator/runner.py +18 -1
  221. package/operate/remediator/strategies.py +2 -2
  222. package/operate/simulate/scenarios.py +2 -2
  223. package/operate/tests/mock_legacy_session_app.py +160 -0
  224. package/operate/tests/test_ai_reasoning_effort.py +65 -0
  225. package/operate/tests/test_ai_route_inventory.py +53 -0
  226. package/operate/tests/test_cross_user_session.py +565 -0
  227. package/operate/tests/test_docker_packaging.py +3 -3
  228. package/operate/tests/test_headless_ai.py +6 -0
  229. package/operate/tests/test_leak_check.py +250 -0
  230. package/operate/tests/test_legacy_session_edge.py +192 -0
  231. package/operate/tests/test_pilot_safeguards.py +245 -0
  232. package/operate/tests/test_remediator_java_legacy.py +330 -0
  233. package/package.json +2 -1
  234. package/remediate/authz/patcher.py +120 -11
  235. package/remediate/authz/tests/test_bola_patcher.py +4 -1
  236. package/remediate/edge/coraza/Caddyfile +1 -1
  237. package/remediate/edge/coraza/Dockerfile +9 -0
  238. package/remediate/edge/coraza/rules/coraza-crs-custom.conf +12 -0
  239. package/remediate/edge/coraza/virtual_patcher.py +24 -0
  240. package/remediate/edge/docker-compose.yml +7 -2
  241. package/remediate/edge/kong/kong-legacy-session.yaml +51 -0
  242. package/remediate/edge/mock-backend/Dockerfile +2 -0
  243. package/remediate/edge/tests/test_edge_security.py +21 -1
  244. package/remediate/resilience/terraform/backup_worm.tf +39 -1
  245. package/remediate/resilience/terraform/main.tf +15 -3
  246. package/remediate/resilience/terraform/variables.tf +11 -0
  247. package/remediate/resilience/tests/test_resilience.py +16 -0
@@ -379,7 +379,7 @@ class IDCFrontierRansomwareScenario(BaseScenario):
379
379
  self.target_dir.mkdir(parents=True, exist_ok=True)
380
380
  test_file.write_text("Komagu Immutable WORM Backup - Read Only", encoding="utf-8")
381
381
  # Mark file read-only (simulating local WORM compliance mode)
382
- os.chmod(str(test_file), 0o444)
382
+ os.chmod(str(test_file), 0o400)
383
383
  except Exception:
384
384
  pass
385
385
 
@@ -416,7 +416,7 @@ class IDCFrontierRansomwareScenario(BaseScenario):
416
416
 
417
417
  # Clean up
418
418
  try:
419
- os.chmod(str(test_file), 0o666)
419
+ os.chmod(str(test_file), 0o600)
420
420
  test_file.unlink(missing_ok=True)
421
421
  except Exception:
422
422
  pass
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env python3
2
+ """Small session-based app that behaves like a JSP / Struts application.
3
+
4
+ Used to rehearse ``komagu test`` on legacy behaviour:
5
+
6
+ - login state lives in a ``JSESSIONID`` cookie;
7
+ - writes are ``application/x-www-form-urlencoded`` and need a single-use Struts token;
8
+ - a successful write answers 302 (post/redirect/get);
9
+ - a denied request is a 200 Shift_JIS error page, a 302 to login, or a 404,
10
+ depending on ``server.denial``;
11
+ - ``server.fixed`` is the ownership check being deployed.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import secrets
17
+ import threading
18
+ from http.server import BaseHTTPRequestHandler, HTTPServer
19
+ from typing import Dict, List, NamedTuple, Optional, Tuple
20
+ from urllib.parse import parse_qs, urlsplit
21
+
22
+ ALICE_COOKIE = "JSESSIONID=sess-alice-0001"
23
+ BOB_COOKIE = "JSESSIONID=sess-bob-0002"
24
+ EXPIRED_COOKIE = "JSESSIONID=sess-expired-0003"
25
+ TOKEN_FIELD = "org.apache.struts.taglib.html.TOKEN"
26
+ DENIED_TEXT = "アクセス権限がありません"
27
+ LOGIN_REDIRECT = "/login.do;jsessionid=sess-rewritten-url-9999"
28
+
29
+
30
+ class Seen(NamedTuple):
31
+ method: str
32
+ path: str
33
+ cookie: Optional[str]
34
+ authorization: Optional[str]
35
+ content_type: Optional[str]
36
+ body: str
37
+
38
+
39
+ class LegacyHandler(BaseHTTPRequestHandler):
40
+ server: "LegacyServer"
41
+
42
+ def log_message(self, format: str, *args: object) -> None: # noqa: A002
43
+ pass
44
+
45
+ def _user(self) -> Optional[str]:
46
+ cookie = self.headers.get("Cookie", "")
47
+ pairs = dict(p.strip().split("=", 1) for p in cookie.split(";") if "=" in p)
48
+ return self.server.sessions.get(pairs.get("JSESSIONID", ""))
49
+
50
+ def _send(self, status: int, body: bytes = b"", charset: str = "UTF-8", location: Optional[str] = None) -> None:
51
+ self.send_response(status)
52
+ self.send_header("Content-Type", f"text/html; charset={charset}")
53
+ self.send_header("Content-Length", str(len(body)))
54
+ if location:
55
+ self.send_header("Location", location)
56
+ self.end_headers()
57
+ self.wfile.write(body)
58
+
59
+ def _to_login(self) -> None:
60
+ self._send(302, location=LOGIN_REDIRECT)
61
+
62
+ def _deny(self) -> None:
63
+ if self.server.denial == "login_redirect":
64
+ self._to_login()
65
+ elif self.server.denial == "not_found":
66
+ self._send(404, b"<html>Not Found</html>")
67
+ else:
68
+ page = f"<html><body><p>{DENIED_TEXT}</p></body></html>"
69
+ self._send(200, page.encode("cp932"), charset="Windows-31J")
70
+
71
+ def _may_access(self, user: str, order_id: str) -> bool:
72
+ owner = self.server.orders.get(order_id)
73
+ if owner is None:
74
+ return False
75
+ return owner == user or not self.server.fixed
76
+
77
+ def _record(self, method: str, body: str = "") -> None:
78
+ self.server.seen.append(Seen(
79
+ method, self.path, self.headers.get("Cookie"), self.headers.get("Authorization"),
80
+ self.headers.get("Content-Type"), body,
81
+ ))
82
+
83
+ def do_GET(self) -> None: # noqa: N802
84
+ self._record("GET")
85
+ url = urlsplit(self.path)
86
+ query = parse_qs(url.query)
87
+ if url.path == "/login.do":
88
+ self._send(200, b"<html>Please log in</html>")
89
+ return
90
+ user = self._user()
91
+ if user is None:
92
+ self._to_login()
93
+ elif url.path == "/home.do":
94
+ self._send(200, f"<html>Welcome {user}</html>".encode())
95
+ elif url.path == "/order/view.do":
96
+ self._view(user, query.get("id", [""])[0])
97
+ elif url.path == "/order/edit.do":
98
+ self._edit_form(user)
99
+ else:
100
+ self._send(404, b"<html>No such action</html>")
101
+
102
+ def _view(self, user: str, order_id: str) -> None:
103
+ if not self._may_access(user, order_id):
104
+ self._deny()
105
+ return
106
+ self._send(200, f"<html>Order detail {order_id}: secret-note</html>".encode())
107
+
108
+ def _edit_form(self, user: str) -> None:
109
+ if self.server.hide_token:
110
+ self._send(200, b"<html><form></form></html>")
111
+ return
112
+ token = secrets.token_hex(8)
113
+ self.server.tokens[user] = token
114
+ # value before name, as some tag libraries render it.
115
+ page = f'<html><form><input value="{token}" type="hidden" name="{TOKEN_FIELD}"></form></html>'
116
+ self._send(200, page.encode())
117
+
118
+ def do_POST(self) -> None: # noqa: N802
119
+ length = int(self.headers.get("Content-Length") or 0)
120
+ raw = self.rfile.read(length).decode("utf-8", "replace")
121
+ self._record("POST", raw)
122
+ user = self._user()
123
+ if user is None:
124
+ self._to_login()
125
+ return
126
+ if self.headers.get("Content-Type", "").split(";")[0] != "application/x-www-form-urlencoded":
127
+ self._send(415, b"<html>Form post expected</html>")
128
+ return
129
+ form = parse_qs(raw)
130
+ if urlsplit(self.path).path != "/order/update.do":
131
+ self._send(404, b"<html>No such action</html>")
132
+ return
133
+ if form.get(TOKEN_FIELD, [""])[0] != self.server.tokens.pop(user, None):
134
+ self._send(400, b"<html>Invalid token</html>")
135
+ return
136
+ order_id = form.get("id", [""])[0]
137
+ if not self._may_access(user, order_id):
138
+ self._deny()
139
+ return
140
+ self.server.updates.append((user, order_id))
141
+ self._send(302, location="/order/list.do")
142
+
143
+
144
+ class LegacyServer(HTTPServer):
145
+ def __init__(self) -> None:
146
+ super().__init__(("127.0.0.1", 0), LegacyHandler)
147
+ self.fixed = False
148
+ self.denial = "error_page"
149
+ self.hide_token = False
150
+ self.orders: Dict[str, str] = {"100": "alice", "200": "bob"}
151
+ self.sessions: Dict[str, str] = {"sess-alice-0001": "alice", "sess-bob-0002": "bob"}
152
+ self.tokens: Dict[str, str] = {}
153
+ self.updates: List[Tuple[str, str]] = []
154
+ self.seen: List[Seen] = []
155
+
156
+
157
+ def start_legacy_app() -> Tuple[LegacyServer, str]:
158
+ server = LegacyServer()
159
+ threading.Thread(target=server.serve_forever, daemon=True).start()
160
+ return server, f"http://127.0.0.1:{server.server_port}"
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env python3
2
+ """`--ai-reasoning-effort` reaches each /chat/completions request and ai-run-stats.json (#382)."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import shutil
9
+ import tempfile
10
+ import unittest
11
+ from pathlib import Path
12
+
13
+ from operate.ai.client import LLMClient
14
+ from operate.ai.runner import HeadlessAIRunner
15
+ from operate.cli.commands.scan import register_subcommand
16
+
17
+ MESSAGES = [{"role": "user", "content": "audit"}]
18
+
19
+
20
+ class TestReasoningEffortPayload(unittest.TestCase):
21
+ def test_not_sent_by_default(self) -> None:
22
+ payload = LLMClient(model="m").build_payload(MESSAGES)
23
+ self.assertEqual(payload, {"model": "m", "messages": MESSAGES, "temperature": 0.1})
24
+
25
+ def test_sent_when_set(self) -> None:
26
+ payload = LLMClient(model="m", reasoning_effort="none").build_payload(MESSAGES, max_tokens=50)
27
+ self.assertEqual(payload["reasoning_effort"], "none")
28
+ self.assertEqual(payload["max_tokens"], 50)
29
+
30
+ def test_unknown_value_is_rejected(self) -> None:
31
+ with self.assertRaises(ValueError):
32
+ LLMClient(reasoning_effort="off")
33
+
34
+
35
+ class TestReasoningEffortCli(unittest.TestCase):
36
+ def parse(self, *argv: str) -> argparse.Namespace:
37
+ parser = argparse.ArgumentParser()
38
+ register_subcommand(parser.add_subparsers(dest="command"))
39
+ return parser.parse_args(["scan", ".", *argv])
40
+
41
+ def test_flag_is_optional(self) -> None:
42
+ self.assertIsNone(self.parse().ai_reasoning_effort)
43
+ self.assertEqual(self.parse("--ai-reasoning-effort", "none").ai_reasoning_effort, "none")
44
+
45
+ def test_flag_rejects_unknown_values(self) -> None:
46
+ with self.assertRaises(SystemExit):
47
+ self.parse("--ai-reasoning-effort", "off")
48
+
49
+
50
+ class TestReasoningEffortStats(unittest.TestCase):
51
+ def setUp(self) -> None:
52
+ self.tmp = Path(tempfile.mkdtemp(prefix="komagu_effort_"))
53
+
54
+ def tearDown(self) -> None:
55
+ shutil.rmtree(self.tmp, ignore_errors=True)
56
+
57
+ def test_value_is_recorded(self) -> None:
58
+ runner = HeadlessAIRunner(self.tmp, self.tmp / "out", LLMClient(model="m", reasoning_effort="low"))
59
+ (self.tmp / "out").mkdir(parents=True, exist_ok=True)
60
+ stats = json.loads(runner.write_run_stats().read_text(encoding="utf-8"))
61
+ self.assertEqual(stats["reasoning_effort"], "low")
62
+
63
+
64
+ if __name__ == "__main__":
65
+ unittest.main()
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python3
2
+ """Route inventory built by the headless runner from Tier 1 route batches (#380)."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ import shutil
8
+ import tempfile
9
+ import unittest
10
+ from pathlib import Path
11
+
12
+ from operate.ai.runner import HeadlessAIRunner
13
+
14
+
15
+ class _NoCallClient:
16
+ model = "none"
17
+ endpoint = "test://"
18
+
19
+ def chat(self, messages, temperature=0.1): # noqa: ANN001
20
+ raise AssertionError("route inventory must not call the model")
21
+
22
+
23
+ class TestRouteInventory(unittest.TestCase):
24
+ def setUp(self) -> None:
25
+ self.tmp = Path(tempfile.mkdtemp(prefix="komagu_inventory_"))
26
+ self.out = self.tmp / "out"
27
+ (self.out / "batches").mkdir(parents=True)
28
+
29
+ def tearDown(self) -> None:
30
+ shutil.rmtree(self.tmp, ignore_errors=True)
31
+
32
+ def inventory(self, candidates: list) -> list:
33
+ (self.out / "batches" / "routes-001.json").write_text(json.dumps({"candidates": candidates}), encoding="utf-8")
34
+ HeadlessAIRunner(self.tmp, self.out, _NoCallClient()).map_routes_inventory()
35
+ return json.loads((self.out / "routes" / "routes-001.json").read_text(encoding="utf-8"))["routes"]
36
+
37
+ def test_route_without_id_params_gets_no_invented_id(self) -> None:
38
+ routes = self.inventory([{"route_id": "R-0001", "method": ["POST"], "path": "/register",
39
+ "handler": {"file": "app/Http/Controllers/AccountController.php", "line": 11},
40
+ "id_params": []}])
41
+ self.assertEqual(routes[0]["id_inputs"], [])
42
+
43
+ def test_detected_id_params_are_kept(self) -> None:
44
+ routes = self.inventory([{"route_id": "R-0001", "method": ["GET"], "path": "/orders/{id}",
45
+ "handler": {"file": "routes/web.php", "line": 3},
46
+ "id_params": [{"name": "id", "source": "path", "is_id_like": True},
47
+ {"name": "orderId", "source": "query"}]}])
48
+ self.assertEqual(routes[0]["id_inputs"], [{"name": "id", "source": "path"},
49
+ {"name": "orderId", "source": "query"}])
50
+
51
+
52
+ if __name__ == "__main__":
53
+ unittest.main()