@elizaos/skills 2.0.0-alpha.3

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 (371) hide show
  1. package/README.md +126 -0
  2. package/package.json +53 -0
  3. package/skills/1password/SKILL.md +70 -0
  4. package/skills/1password/references/cli-examples.md +29 -0
  5. package/skills/1password/references/get-started.md +17 -0
  6. package/skills/apple-notes/SKILL.md +77 -0
  7. package/skills/apple-reminders/SKILL.md +96 -0
  8. package/skills/bear-notes/SKILL.md +107 -0
  9. package/skills/bird/SKILL.md +224 -0
  10. package/skills/blogwatcher/SKILL.md +69 -0
  11. package/skills/blucli/SKILL.md +47 -0
  12. package/skills/bluebubbles/SKILL.md +131 -0
  13. package/skills/camsnap/SKILL.md +45 -0
  14. package/skills/canvas/SKILL.md +203 -0
  15. package/skills/clawhub/SKILL.md +77 -0
  16. package/skills/coding-agent/SKILL.md +284 -0
  17. package/skills/discord/SKILL.md +578 -0
  18. package/skills/eightctl/SKILL.md +50 -0
  19. package/skills/food-order/SKILL.md +48 -0
  20. package/skills/gemini/SKILL.md +43 -0
  21. package/skills/gifgrep/SKILL.md +79 -0
  22. package/skills/github/SKILL.md +77 -0
  23. package/skills/gog/SKILL.md +116 -0
  24. package/skills/goplaces/SKILL.md +52 -0
  25. package/skills/healthcheck/SKILL.md +245 -0
  26. package/skills/himalaya/SKILL.md +257 -0
  27. package/skills/himalaya/references/configuration.md +184 -0
  28. package/skills/himalaya/references/message-composition.md +199 -0
  29. package/skills/imsg/SKILL.md +74 -0
  30. package/skills/local-places/SERVER_README.md +101 -0
  31. package/skills/local-places/SKILL.md +102 -0
  32. package/skills/local-places/pyproject.toml +21 -0
  33. package/skills/local-places/src/local_places/__init__.py +2 -0
  34. package/skills/local-places/src/local_places/google_places.py +314 -0
  35. package/skills/local-places/src/local_places/main.py +65 -0
  36. package/skills/local-places/src/local_places/schemas.py +107 -0
  37. package/skills/mcporter/SKILL.md +61 -0
  38. package/skills/model-usage/SKILL.md +69 -0
  39. package/skills/model-usage/references/codexbar-cli.md +33 -0
  40. package/skills/model-usage/scripts/model_usage.py +310 -0
  41. package/skills/nano-banana-pro/SKILL.md +58 -0
  42. package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
  43. package/skills/nano-pdf/SKILL.md +38 -0
  44. package/skills/notion/SKILL.md +172 -0
  45. package/skills/obsidian/SKILL.md +81 -0
  46. package/skills/openai-image-gen/SKILL.md +89 -0
  47. package/skills/openai-image-gen/scripts/gen.py +240 -0
  48. package/skills/openai-whisper/SKILL.md +38 -0
  49. package/skills/openai-whisper-api/SKILL.md +52 -0
  50. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  51. package/skills/openhue/SKILL.md +51 -0
  52. package/skills/oracle/SKILL.md +125 -0
  53. package/skills/ordercli/SKILL.md +78 -0
  54. package/skills/peekaboo/SKILL.md +190 -0
  55. package/skills/sag/SKILL.md +87 -0
  56. package/skills/security-ask-questions-if-underspecified/.claude-plugin/plugin.json +10 -0
  57. package/skills/security-ask-questions-if-underspecified/README.md +24 -0
  58. package/skills/security-ask-questions-if-underspecified/skills/ask-questions-if-underspecified/SKILL.md +85 -0
  59. package/skills/security-audit-context-building/.claude-plugin/plugin.json +10 -0
  60. package/skills/security-audit-context-building/README.md +58 -0
  61. package/skills/security-audit-context-building/commands/audit-context.md +21 -0
  62. package/skills/security-audit-context-building/skills/audit-context-building/SKILL.md +297 -0
  63. package/skills/security-audit-context-building/skills/audit-context-building/resources/COMPLETENESS_CHECKLIST.md +47 -0
  64. package/skills/security-audit-context-building/skills/audit-context-building/resources/FUNCTION_MICRO_ANALYSIS_EXAMPLE.md +355 -0
  65. package/skills/security-audit-context-building/skills/audit-context-building/resources/OUTPUT_REQUIREMENTS.md +71 -0
  66. package/skills/security-building-secure-contracts/.claude-plugin/plugin.json +10 -0
  67. package/skills/security-building-secure-contracts/README.md +241 -0
  68. package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/SKILL.md +284 -0
  69. package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +405 -0
  70. package/skills/security-building-secure-contracts/skills/audit-prep-assistant/SKILL.md +409 -0
  71. package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/SKILL.md +329 -0
  72. package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +722 -0
  73. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/SKILL.md +218 -0
  74. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/ASSESSMENT_CRITERIA.md +355 -0
  75. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/EXAMPLE_REPORT.md +248 -0
  76. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/REPORT_FORMAT.md +33 -0
  77. package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/SKILL.md +334 -0
  78. package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +740 -0
  79. package/skills/security-building-secure-contracts/skills/guidelines-advisor/SKILL.md +252 -0
  80. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/ASSESSMENT_AREAS.md +329 -0
  81. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/DELIVERABLES.md +118 -0
  82. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/EXAMPLE_REPORT.md +298 -0
  83. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/SKILL.md +161 -0
  84. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/EXAMPLE_REPORT.md +279 -0
  85. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/WORKFLOW_STEPS.md +132 -0
  86. package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/SKILL.md +389 -0
  87. package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +669 -0
  88. package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/SKILL.md +298 -0
  89. package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +791 -0
  90. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/SKILL.md +362 -0
  91. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/ASSESSMENT_CATEGORIES.md +571 -0
  92. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/REPORT_TEMPLATES.md +141 -0
  93. package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/SKILL.md +388 -0
  94. package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +595 -0
  95. package/skills/security-burpsuite-project-parser/.claude-plugin/plugin.json +10 -0
  96. package/skills/security-burpsuite-project-parser/README.md +103 -0
  97. package/skills/security-burpsuite-project-parser/commands/burp-search.md +18 -0
  98. package/skills/security-burpsuite-project-parser/skills/SKILL.md +358 -0
  99. package/skills/security-burpsuite-project-parser/skills/scripts/burp-search.sh +99 -0
  100. package/skills/security-claude-in-chrome-troubleshooting/.claude-plugin/plugin.json +8 -0
  101. package/skills/security-claude-in-chrome-troubleshooting/README.md +31 -0
  102. package/skills/security-claude-in-chrome-troubleshooting/skills/claude-in-chrome-troubleshooting/SKILL.md +251 -0
  103. package/skills/security-constant-time-analysis/.claude-plugin/plugin.json +9 -0
  104. package/skills/security-constant-time-analysis/README.md +381 -0
  105. package/skills/security-constant-time-analysis/commands/ct-check.md +20 -0
  106. package/skills/security-constant-time-analysis/ct_analyzer/__init__.py +49 -0
  107. package/skills/security-constant-time-analysis/ct_analyzer/analyzer.py +1284 -0
  108. package/skills/security-constant-time-analysis/ct_analyzer/script_analyzers.py +3081 -0
  109. package/skills/security-constant-time-analysis/ct_analyzer/tests/__init__.py +1 -0
  110. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_analyzer.py +1397 -0
  111. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/bn_excerpt.js +205 -0
  112. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_constant_time.c +181 -0
  113. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.c +74 -0
  114. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.go +78 -0
  115. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.rs +92 -0
  116. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.cs +174 -0
  117. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.java +161 -0
  118. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.kt +181 -0
  119. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.php +140 -0
  120. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.py +252 -0
  121. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.rb +188 -0
  122. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.swift +199 -0
  123. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.ts +154 -0
  124. package/skills/security-constant-time-analysis/pyproject.toml +52 -0
  125. package/skills/security-constant-time-analysis/skills/constant-time-analysis/README.md +90 -0
  126. package/skills/security-constant-time-analysis/skills/constant-time-analysis/SKILL.md +219 -0
  127. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/compiled.md +129 -0
  128. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/javascript.md +136 -0
  129. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/kotlin.md +252 -0
  130. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/php.md +172 -0
  131. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/python.md +179 -0
  132. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/ruby.md +198 -0
  133. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/swift.md +288 -0
  134. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/vm-compiled.md +354 -0
  135. package/skills/security-constant-time-analysis/uv.lock +8 -0
  136. package/skills/security-culture-index/.claude-plugin/plugin.json +8 -0
  137. package/skills/security-culture-index/README.md +79 -0
  138. package/skills/security-culture-index/skills/interpreting-culture-index/SKILL.md +293 -0
  139. package/skills/security-culture-index/skills/interpreting-culture-index/references/anti-patterns.md +255 -0
  140. package/skills/security-culture-index/skills/interpreting-culture-index/references/conversation-starters.md +408 -0
  141. package/skills/security-culture-index/skills/interpreting-culture-index/references/interview-trait-signals.md +253 -0
  142. package/skills/security-culture-index/skills/interpreting-culture-index/references/motivators.md +158 -0
  143. package/skills/security-culture-index/skills/interpreting-culture-index/references/patterns-archetypes.md +147 -0
  144. package/skills/security-culture-index/skills/interpreting-culture-index/references/primary-traits.md +307 -0
  145. package/skills/security-culture-index/skills/interpreting-culture-index/references/secondary-traits.md +228 -0
  146. package/skills/security-culture-index/skills/interpreting-culture-index/references/team-composition.md +148 -0
  147. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/check_deps.py +108 -0
  148. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/__init__.py +20 -0
  149. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/constants.py +122 -0
  150. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/extract.py +187 -0
  151. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/models.py +16 -0
  152. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/opencv_extractor.py +520 -0
  153. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/extract_pdf.py +237 -0
  154. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/pyproject.toml +18 -0
  155. package/skills/security-culture-index/skills/interpreting-culture-index/templates/burnout-report.md +113 -0
  156. package/skills/security-culture-index/skills/interpreting-culture-index/templates/comparison-report.md +103 -0
  157. package/skills/security-culture-index/skills/interpreting-culture-index/templates/hiring-profile.md +127 -0
  158. package/skills/security-culture-index/skills/interpreting-culture-index/templates/individual-report.md +85 -0
  159. package/skills/security-culture-index/skills/interpreting-culture-index/templates/predicted-profile.md +165 -0
  160. package/skills/security-culture-index/skills/interpreting-culture-index/templates/team-report.md +109 -0
  161. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/analyze-team.md +188 -0
  162. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/coach-manager.md +267 -0
  163. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/compare-profiles.md +188 -0
  164. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/define-hiring-profile.md +220 -0
  165. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/detect-burnout.md +206 -0
  166. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/extract-from-pdf.md +121 -0
  167. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/interpret-individual.md +183 -0
  168. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/interview-debrief.md +234 -0
  169. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/mediate-conflict.md +306 -0
  170. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/plan-onboarding.md +322 -0
  171. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/predict-from-interview.md +250 -0
  172. package/skills/security-differential-review/.claude-plugin/plugin.json +10 -0
  173. package/skills/security-differential-review/README.md +109 -0
  174. package/skills/security-differential-review/commands/diff-review.md +21 -0
  175. package/skills/security-differential-review/skills/differential-review/SKILL.md +220 -0
  176. package/skills/security-differential-review/skills/differential-review/adversarial.md +203 -0
  177. package/skills/security-differential-review/skills/differential-review/methodology.md +234 -0
  178. package/skills/security-differential-review/skills/differential-review/patterns.md +300 -0
  179. package/skills/security-differential-review/skills/differential-review/reporting.md +369 -0
  180. package/skills/security-dwarf-expert/.claude-plugin/plugin.json +10 -0
  181. package/skills/security-dwarf-expert/README.md +38 -0
  182. package/skills/security-dwarf-expert/skills/dwarf-expert/SKILL.md +93 -0
  183. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/coding.md +31 -0
  184. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/dwarfdump.md +50 -0
  185. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/readelf.md +8 -0
  186. package/skills/security-entry-point-analyzer/.claude-plugin/plugin.json +10 -0
  187. package/skills/security-entry-point-analyzer/README.md +74 -0
  188. package/skills/security-entry-point-analyzer/commands/entry-points.md +18 -0
  189. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/SKILL.md +251 -0
  190. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/cosmwasm.md +182 -0
  191. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-aptos.md +107 -0
  192. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-sui.md +87 -0
  193. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solana.md +155 -0
  194. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solidity.md +135 -0
  195. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/ton.md +185 -0
  196. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/vyper.md +141 -0
  197. package/skills/security-firebase-apk-scanner/.claude-plugin/plugin.json +10 -0
  198. package/skills/security-firebase-apk-scanner/README.md +85 -0
  199. package/skills/security-firebase-apk-scanner/commands/scan-apk.md +18 -0
  200. package/skills/security-firebase-apk-scanner/scanner.sh +1408 -0
  201. package/skills/security-firebase-apk-scanner/skills/firebase-apk-scanner/SKILL.md +197 -0
  202. package/skills/security-firebase-apk-scanner/skills/firebase-apk-scanner/references/vulnerabilities.md +803 -0
  203. package/skills/security-fix-review/.claude-plugin/plugin.json +13 -0
  204. package/skills/security-fix-review/README.md +118 -0
  205. package/skills/security-fix-review/commands/fix-review.md +24 -0
  206. package/skills/security-fix-review/skills/fix-review/SKILL.md +264 -0
  207. package/skills/security-fix-review/skills/fix-review/references/bug-detection.md +408 -0
  208. package/skills/security-fix-review/skills/fix-review/references/finding-matching.md +298 -0
  209. package/skills/security-fix-review/skills/fix-review/references/report-parsing.md +398 -0
  210. package/skills/security-insecure-defaults/.claude-plugin/plugin.json +10 -0
  211. package/skills/security-insecure-defaults/README.md +45 -0
  212. package/skills/security-insecure-defaults/skills/insecure-defaults/SKILL.md +117 -0
  213. package/skills/security-insecure-defaults/skills/insecure-defaults/references/examples.md +409 -0
  214. package/skills/security-modern-python/.claude-plugin/plugin.json +10 -0
  215. package/skills/security-modern-python/README.md +58 -0
  216. package/skills/security-modern-python/hooks/hooks.json +16 -0
  217. package/skills/security-modern-python/hooks/intercept-legacy-python.bats +388 -0
  218. package/skills/security-modern-python/hooks/intercept-legacy-python.sh +109 -0
  219. package/skills/security-modern-python/hooks/test_helper.bash +75 -0
  220. package/skills/security-modern-python/skills/modern-python/SKILL.md +333 -0
  221. package/skills/security-modern-python/skills/modern-python/references/dependabot.md +43 -0
  222. package/skills/security-modern-python/skills/modern-python/references/migration-checklist.md +141 -0
  223. package/skills/security-modern-python/skills/modern-python/references/pep723-scripts.md +259 -0
  224. package/skills/security-modern-python/skills/modern-python/references/prek.md +211 -0
  225. package/skills/security-modern-python/skills/modern-python/references/pyproject.md +254 -0
  226. package/skills/security-modern-python/skills/modern-python/references/ruff-config.md +240 -0
  227. package/skills/security-modern-python/skills/modern-python/references/security-setup.md +255 -0
  228. package/skills/security-modern-python/skills/modern-python/references/testing.md +284 -0
  229. package/skills/security-modern-python/skills/modern-python/references/uv-commands.md +200 -0
  230. package/skills/security-modern-python/skills/modern-python/templates/dependabot.yml +36 -0
  231. package/skills/security-modern-python/skills/modern-python/templates/pre-commit-config.yaml +66 -0
  232. package/skills/security-property-based-testing/.claude-plugin/plugin.json +9 -0
  233. package/skills/security-property-based-testing/README.md +47 -0
  234. package/skills/security-property-based-testing/skills/property-based-testing/README.md +88 -0
  235. package/skills/security-property-based-testing/skills/property-based-testing/SKILL.md +109 -0
  236. package/skills/security-property-based-testing/skills/property-based-testing/references/design.md +191 -0
  237. package/skills/security-property-based-testing/skills/property-based-testing/references/generating.md +200 -0
  238. package/skills/security-property-based-testing/skills/property-based-testing/references/libraries.md +130 -0
  239. package/skills/security-property-based-testing/skills/property-based-testing/references/refactoring.md +181 -0
  240. package/skills/security-property-based-testing/skills/property-based-testing/references/reviewing.md +209 -0
  241. package/skills/security-property-based-testing/skills/property-based-testing/references/strategies.md +124 -0
  242. package/skills/semgrep-rule-creator/.claude-plugin/plugin.json +8 -0
  243. package/skills/semgrep-rule-creator/README.md +43 -0
  244. package/skills/semgrep-rule-creator/commands/semgrep-rule.md +26 -0
  245. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/SKILL.md +168 -0
  246. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/quick-reference.md +203 -0
  247. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/workflow.md +240 -0
  248. package/skills/semgrep-rule-variant-creator/.claude-plugin/plugin.json +9 -0
  249. package/skills/semgrep-rule-variant-creator/README.md +86 -0
  250. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/SKILL.md +205 -0
  251. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/applicability-analysis.md +250 -0
  252. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/language-syntax-guide.md +324 -0
  253. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/workflow.md +518 -0
  254. package/skills/session-logs/SKILL.md +115 -0
  255. package/skills/sharp-edges/.claude-plugin/plugin.json +10 -0
  256. package/skills/sharp-edges/README.md +48 -0
  257. package/skills/sharp-edges/skills/sharp-edges/SKILL.md +292 -0
  258. package/skills/sharp-edges/skills/sharp-edges/references/auth-patterns.md +252 -0
  259. package/skills/sharp-edges/skills/sharp-edges/references/case-studies.md +274 -0
  260. package/skills/sharp-edges/skills/sharp-edges/references/config-patterns.md +333 -0
  261. package/skills/sharp-edges/skills/sharp-edges/references/crypto-apis.md +190 -0
  262. package/skills/sharp-edges/skills/sharp-edges/references/lang-c.md +205 -0
  263. package/skills/sharp-edges/skills/sharp-edges/references/lang-csharp.md +285 -0
  264. package/skills/sharp-edges/skills/sharp-edges/references/lang-go.md +270 -0
  265. package/skills/sharp-edges/skills/sharp-edges/references/lang-java.md +263 -0
  266. package/skills/sharp-edges/skills/sharp-edges/references/lang-javascript.md +269 -0
  267. package/skills/sharp-edges/skills/sharp-edges/references/lang-kotlin.md +265 -0
  268. package/skills/sharp-edges/skills/sharp-edges/references/lang-php.md +245 -0
  269. package/skills/sharp-edges/skills/sharp-edges/references/lang-python.md +274 -0
  270. package/skills/sharp-edges/skills/sharp-edges/references/lang-ruby.md +273 -0
  271. package/skills/sharp-edges/skills/sharp-edges/references/lang-rust.md +272 -0
  272. package/skills/sharp-edges/skills/sharp-edges/references/lang-swift.md +287 -0
  273. package/skills/sharp-edges/skills/sharp-edges/references/language-specific.md +588 -0
  274. package/skills/sherpa-onnx-tts/SKILL.md +103 -0
  275. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
  276. package/skills/skill-creator/SKILL.md +370 -0
  277. package/skills/skill-creator/license.txt +202 -0
  278. package/skills/skill-creator/scripts/init_skill.py +378 -0
  279. package/skills/skill-creator/scripts/package_skill.py +111 -0
  280. package/skills/skill-creator/scripts/quick_validate.py +101 -0
  281. package/skills/slack/SKILL.md +144 -0
  282. package/skills/songsee/SKILL.md +49 -0
  283. package/skills/sonoscli/SKILL.md +46 -0
  284. package/skills/spec-to-code-compliance/.claude-plugin/plugin.json +10 -0
  285. package/skills/spec-to-code-compliance/README.md +67 -0
  286. package/skills/spec-to-code-compliance/commands/spec-compliance.md +22 -0
  287. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/SKILL.md +349 -0
  288. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/COMPLETENESS_CHECKLIST.md +69 -0
  289. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/IR_EXAMPLES.md +417 -0
  290. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/OUTPUT_REQUIREMENTS.md +105 -0
  291. package/skills/spotify-player/SKILL.md +64 -0
  292. package/skills/static-analysis/.claude-plugin/plugin.json +8 -0
  293. package/skills/static-analysis/README.md +59 -0
  294. package/skills/static-analysis/skills/codeql/SKILL.md +315 -0
  295. package/skills/static-analysis/skills/sarif-parsing/SKILL.md +479 -0
  296. package/skills/static-analysis/skills/sarif-parsing/resources/jq-queries.md +162 -0
  297. package/skills/static-analysis/skills/sarif-parsing/resources/sarif_helpers.py +331 -0
  298. package/skills/static-analysis/skills/semgrep/SKILL.md +337 -0
  299. package/skills/summarize/SKILL.md +87 -0
  300. package/skills/testing-handbook-skills/.claude-plugin/plugin.json +8 -0
  301. package/skills/testing-handbook-skills/README.md +241 -0
  302. package/skills/testing-handbook-skills/scripts/pyproject.toml +8 -0
  303. package/skills/testing-handbook-skills/scripts/validate-skills.py +657 -0
  304. package/skills/testing-handbook-skills/skills/address-sanitizer/SKILL.md +341 -0
  305. package/skills/testing-handbook-skills/skills/aflpp/SKILL.md +640 -0
  306. package/skills/testing-handbook-skills/skills/atheris/SKILL.md +515 -0
  307. package/skills/testing-handbook-skills/skills/cargo-fuzz/SKILL.md +454 -0
  308. package/skills/testing-handbook-skills/skills/codeql/SKILL.md +549 -0
  309. package/skills/testing-handbook-skills/skills/constant-time-testing/SKILL.md +507 -0
  310. package/skills/testing-handbook-skills/skills/coverage-analysis/SKILL.md +607 -0
  311. package/skills/testing-handbook-skills/skills/fuzzing-dictionary/SKILL.md +297 -0
  312. package/skills/testing-handbook-skills/skills/fuzzing-obstacles/SKILL.md +426 -0
  313. package/skills/testing-handbook-skills/skills/harness-writing/SKILL.md +614 -0
  314. package/skills/testing-handbook-skills/skills/libafl/SKILL.md +625 -0
  315. package/skills/testing-handbook-skills/skills/libfuzzer/SKILL.md +795 -0
  316. package/skills/testing-handbook-skills/skills/ossfuzz/SKILL.md +426 -0
  317. package/skills/testing-handbook-skills/skills/ruzzy/SKILL.md +443 -0
  318. package/skills/testing-handbook-skills/skills/semgrep/SKILL.md +601 -0
  319. package/skills/testing-handbook-skills/skills/testing-handbook-generator/SKILL.md +372 -0
  320. package/skills/testing-handbook-skills/skills/testing-handbook-generator/agent-prompt.md +280 -0
  321. package/skills/testing-handbook-skills/skills/testing-handbook-generator/discovery.md +452 -0
  322. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/domain-skill.md +504 -0
  323. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/fuzzer-skill.md +454 -0
  324. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/technique-skill.md +527 -0
  325. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/tool-skill.md +366 -0
  326. package/skills/testing-handbook-skills/skills/testing-handbook-generator/testing.md +482 -0
  327. package/skills/testing-handbook-skills/skills/wycheproof/SKILL.md +533 -0
  328. package/skills/things-mac/SKILL.md +86 -0
  329. package/skills/tmux/SKILL.md +135 -0
  330. package/skills/tmux/scripts/find-sessions.sh +112 -0
  331. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  332. package/skills/trello/SKILL.md +95 -0
  333. package/skills/variant-analysis/.claude-plugin/plugin.json +8 -0
  334. package/skills/variant-analysis/README.md +41 -0
  335. package/skills/variant-analysis/commands/variants.md +23 -0
  336. package/skills/variant-analysis/skills/variant-analysis/METHODOLOGY.md +327 -0
  337. package/skills/variant-analysis/skills/variant-analysis/SKILL.md +142 -0
  338. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/cpp.ql +119 -0
  339. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/go.ql +69 -0
  340. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/java.ql +71 -0
  341. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/javascript.ql +63 -0
  342. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/python.ql +80 -0
  343. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/cpp.yaml +98 -0
  344. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/go.yaml +63 -0
  345. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/java.yaml +61 -0
  346. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/javascript.yaml +60 -0
  347. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/python.yaml +72 -0
  348. package/skills/variant-analysis/skills/variant-analysis/resources/variant-report-template.md +75 -0
  349. package/skills/video-frames/SKILL.md +46 -0
  350. package/skills/video-frames/scripts/frame.sh +81 -0
  351. package/skills/voice-call/SKILL.md +45 -0
  352. package/skills/wacli/SKILL.md +72 -0
  353. package/skills/weather/SKILL.md +54 -0
  354. package/skills/yara-authoring/.claude-plugin/plugin.json +9 -0
  355. package/skills/yara-authoring/README.md +131 -0
  356. package/skills/yara-authoring/skills/yara-rule-authoring/SKILL.md +645 -0
  357. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_Mac_ProtonRAT_Jan25.yar +99 -0
  358. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_NPM_SupplyChain_Jan25.yar +170 -0
  359. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_Win_Remcos_Jan25.yar +103 -0
  360. package/skills/yara-authoring/skills/yara-rule-authoring/examples/SUSP_CRX_SuspiciousPermissions.yar +134 -0
  361. package/skills/yara-authoring/skills/yara-rule-authoring/examples/SUSP_JS_Obfuscation_Jan25.yar +185 -0
  362. package/skills/yara-authoring/skills/yara-rule-authoring/references/crx-module.md +214 -0
  363. package/skills/yara-authoring/skills/yara-rule-authoring/references/dex-module.md +383 -0
  364. package/skills/yara-authoring/skills/yara-rule-authoring/references/performance.md +333 -0
  365. package/skills/yara-authoring/skills/yara-rule-authoring/references/strings.md +433 -0
  366. package/skills/yara-authoring/skills/yara-rule-authoring/references/style-guide.md +257 -0
  367. package/skills/yara-authoring/skills/yara-rule-authoring/references/testing.md +399 -0
  368. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/atom_analyzer.py +526 -0
  369. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/pyproject.toml +25 -0
  370. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/yara_lint.py +631 -0
  371. package/skills/yara-authoring/skills/yara-rule-authoring/workflows/rule-development.md +493 -0
@@ -0,0 +1,1397 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Unit tests for the constant-time analyzer.
4
+
5
+ These tests verify that the analyzer correctly detects timing side-channel
6
+ vulnerabilities in compiled cryptographic code.
7
+ """
8
+
9
+ import os
10
+ import subprocess
11
+ import sys
12
+ import unittest
13
+ from pathlib import Path
14
+
15
+ # Add parent directory to path for imports
16
+ sys.path.insert(0, str(Path(__file__).parent.parent))
17
+
18
+ from analyzer import (
19
+ DANGEROUS_INSTRUCTIONS,
20
+ AssemblyParser,
21
+ OutputFormat,
22
+ Severity,
23
+ analyze_assembly,
24
+ analyze_source,
25
+ detect_language,
26
+ format_report,
27
+ get_native_arch,
28
+ normalize_arch,
29
+ )
30
+
31
+
32
+ class TestArchitectureNormalization(unittest.TestCase):
33
+ """Test architecture name normalization."""
34
+
35
+ def test_normalize_common_aliases(self):
36
+ self.assertEqual(normalize_arch("amd64"), "x86_64")
37
+ self.assertEqual(normalize_arch("x64"), "x86_64")
38
+ self.assertEqual(normalize_arch("aarch64"), "arm64")
39
+ self.assertEqual(normalize_arch("386"), "i386")
40
+ self.assertEqual(normalize_arch("x86"), "i386")
41
+
42
+ def test_normalize_case_insensitive(self):
43
+ self.assertEqual(normalize_arch("AMD64"), "x86_64")
44
+ self.assertEqual(normalize_arch("AARCH64"), "arm64")
45
+ self.assertEqual(normalize_arch("X86_64"), "x86_64")
46
+
47
+ def test_normalize_passthrough(self):
48
+ self.assertEqual(normalize_arch("x86_64"), "x86_64")
49
+ self.assertEqual(normalize_arch("arm64"), "arm64")
50
+ self.assertEqual(normalize_arch("riscv64"), "riscv64")
51
+
52
+
53
+ class TestLanguageDetection(unittest.TestCase):
54
+ """Test source file language detection."""
55
+
56
+ def test_detect_c(self):
57
+ self.assertEqual(detect_language("foo.c"), "c")
58
+ self.assertEqual(detect_language("foo.h"), "c")
59
+ self.assertEqual(detect_language("/path/to/crypto.c"), "c")
60
+
61
+ def test_detect_cpp(self):
62
+ self.assertEqual(detect_language("foo.cpp"), "cpp")
63
+ self.assertEqual(detect_language("foo.cc"), "cpp")
64
+ self.assertEqual(detect_language("foo.cxx"), "cpp")
65
+ self.assertEqual(detect_language("foo.hpp"), "cpp")
66
+
67
+ def test_detect_go(self):
68
+ self.assertEqual(detect_language("main.go"), "go")
69
+ self.assertEqual(detect_language("/path/to/crypto.go"), "go")
70
+
71
+ def test_detect_rust(self):
72
+ self.assertEqual(detect_language("lib.rs"), "rust")
73
+ self.assertEqual(detect_language("/path/to/crypto.rs"), "rust")
74
+
75
+ def test_detect_python(self):
76
+ self.assertEqual(detect_language("crypto.py"), "python")
77
+ self.assertEqual(detect_language("crypto.pyw"), "python")
78
+ self.assertEqual(detect_language("/path/to/crypto.py"), "python")
79
+
80
+ def test_detect_ruby(self):
81
+ self.assertEqual(detect_language("crypto.rb"), "ruby")
82
+ self.assertEqual(detect_language("/path/to/crypto.rb"), "ruby")
83
+
84
+ def test_detect_java(self):
85
+ self.assertEqual(detect_language("CryptoUtils.java"), "java")
86
+ self.assertEqual(detect_language("/path/to/Crypto.java"), "java")
87
+
88
+ def test_detect_csharp(self):
89
+ self.assertEqual(detect_language("CryptoUtils.cs"), "csharp")
90
+ self.assertEqual(detect_language("/path/to/Crypto.cs"), "csharp")
91
+
92
+ def test_detect_unknown(self):
93
+ self.assertEqual(detect_language("foo.txt"), "unknown")
94
+ self.assertEqual(detect_language("foo.scala"), "unknown")
95
+
96
+
97
+ class TestDangerousInstructions(unittest.TestCase):
98
+ """Test that dangerous instruction lists are properly defined."""
99
+
100
+ def test_all_architectures_have_errors(self):
101
+ for arch in DANGEROUS_INSTRUCTIONS:
102
+ self.assertIn(
103
+ "errors", DANGEROUS_INSTRUCTIONS[arch], f"Architecture {arch} missing 'errors' key"
104
+ )
105
+ self.assertGreater(
106
+ len(DANGEROUS_INSTRUCTIONS[arch]["errors"]),
107
+ 0,
108
+ f"Architecture {arch} has no error instructions",
109
+ )
110
+
111
+ def test_all_architectures_have_division(self):
112
+ """Every architecture should flag some form of division."""
113
+ division_patterns = ["div", "idiv", "udiv", "sdiv", "d", "dr"]
114
+
115
+ for arch, instructions in DANGEROUS_INSTRUCTIONS.items():
116
+ errors = instructions.get("errors", {})
117
+ has_division = any(
118
+ any(pattern in mnemonic.lower() for pattern in division_patterns)
119
+ for mnemonic in errors.keys()
120
+ )
121
+ self.assertTrue(has_division, f"Architecture {arch} should flag division instructions")
122
+
123
+ def test_x86_64_has_known_dangerous(self):
124
+ """x86_64 should flag DIV, IDIV, and their variants."""
125
+ x86 = DANGEROUS_INSTRUCTIONS["x86_64"]["errors"]
126
+ self.assertIn("div", x86)
127
+ self.assertIn("idiv", x86)
128
+ self.assertIn("divq", x86)
129
+ self.assertIn("idivq", x86)
130
+
131
+ def test_arm64_has_known_dangerous(self):
132
+ """ARM64 should flag UDIV and SDIV."""
133
+ arm64 = DANGEROUS_INSTRUCTIONS["arm64"]["errors"]
134
+ self.assertIn("udiv", arm64)
135
+ self.assertIn("sdiv", arm64)
136
+
137
+
138
+ class TestAssemblyParser(unittest.TestCase):
139
+ """Test assembly parsing and violation detection."""
140
+
141
+ def test_parse_x86_64_division(self):
142
+ """Parser should detect x86_64 division instructions."""
143
+ assembly = """
144
+ decompose:
145
+ movq %rdi, %rax
146
+ cqto
147
+ idivq %rsi
148
+ movq %rax, (%rdx)
149
+ movq %rdx, (%rcx)
150
+ ret
151
+ """
152
+
153
+ parser = AssemblyParser("x86_64", "clang")
154
+ functions, violations = parser.parse(assembly)
155
+
156
+ self.assertEqual(len(functions), 1)
157
+ self.assertEqual(functions[0]["name"], "decompose")
158
+
159
+ # Should find the IDIVQ instruction
160
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
161
+ self.assertGreater(len(error_violations), 0, "Should detect IDIVQ")
162
+ self.assertEqual(error_violations[0].mnemonic, "IDIVQ")
163
+
164
+ def test_parse_arm64_division(self):
165
+ """Parser should detect ARM64 division instructions."""
166
+ assembly = """
167
+ decompose:
168
+ sdiv w8, w0, w1
169
+ msub w9, w8, w1, w0
170
+ str w8, [x2]
171
+ str w9, [x3]
172
+ ret
173
+ """
174
+
175
+ parser = AssemblyParser("arm64", "clang")
176
+ functions, violations = parser.parse(assembly)
177
+
178
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
179
+ self.assertGreater(len(error_violations), 0, "Should detect SDIV")
180
+ self.assertEqual(error_violations[0].mnemonic, "SDIV")
181
+
182
+ def test_parse_conditional_branches_as_warnings(self):
183
+ """Parser should detect conditional branches as warnings."""
184
+ assembly = """
185
+ check_value:
186
+ cmpq $0, %rdi
187
+ je .Lzero
188
+ movq $1, %rax
189
+ ret
190
+ .Lzero:
191
+ xorq %rax, %rax
192
+ ret
193
+ """
194
+
195
+ parser = AssemblyParser("x86_64", "clang")
196
+ functions, violations = parser.parse(assembly, include_warnings=True)
197
+
198
+ warning_violations = [v for v in violations if v.severity == Severity.WARNING]
199
+ self.assertGreater(len(warning_violations), 0, "Should detect JE as warning")
200
+
201
+ def test_parse_no_false_positives_on_clean_code(self):
202
+ """Parser should not flag clean constant-time code."""
203
+ assembly = """
204
+ constant_time_select:
205
+ movq %rdx, %rax
206
+ negq %rax
207
+ andq %rdi, %rax
208
+ notq %rdx
209
+ andq %rsi, %rdx
210
+ orq %rdx, %rax
211
+ ret
212
+ """
213
+
214
+ parser = AssemblyParser("x86_64", "clang")
215
+ functions, violations = parser.parse(assembly)
216
+
217
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
218
+ self.assertEqual(len(error_violations), 0, "Clean code should have no violations")
219
+
220
+
221
+ class TestReportFormatting(unittest.TestCase):
222
+ """Test report output formatting."""
223
+
224
+ def test_json_format(self):
225
+ """JSON format should produce valid JSON."""
226
+ import json
227
+
228
+ from analyzer import AnalysisReport
229
+
230
+ report = AnalysisReport(
231
+ architecture="x86_64",
232
+ compiler="clang",
233
+ optimization="O2",
234
+ source_file="test.c",
235
+ total_functions=1,
236
+ total_instructions=10,
237
+ violations=[],
238
+ )
239
+
240
+ output = format_report(report, OutputFormat.JSON)
241
+ parsed = json.loads(output)
242
+
243
+ self.assertEqual(parsed["architecture"], "x86_64")
244
+ self.assertEqual(parsed["passed"], True)
245
+
246
+ def test_text_format_passed(self):
247
+ """Text format should show PASSED for clean code."""
248
+ from analyzer import AnalysisReport
249
+
250
+ report = AnalysisReport(
251
+ architecture="x86_64",
252
+ compiler="clang",
253
+ optimization="O2",
254
+ source_file="test.c",
255
+ total_functions=1,
256
+ total_instructions=10,
257
+ violations=[],
258
+ )
259
+
260
+ output = format_report(report, OutputFormat.TEXT)
261
+ self.assertIn("PASSED", output)
262
+ self.assertIn("No violations found", output)
263
+
264
+ def test_text_format_failed(self):
265
+ """Text format should show FAILED when violations exist."""
266
+ from analyzer import AnalysisReport, Violation
267
+
268
+ report = AnalysisReport(
269
+ architecture="x86_64",
270
+ compiler="clang",
271
+ optimization="O2",
272
+ source_file="test.c",
273
+ total_functions=1,
274
+ total_instructions=10,
275
+ violations=[
276
+ Violation(
277
+ function="decompose",
278
+ file="test.c",
279
+ line=10,
280
+ address="0x1234",
281
+ instruction="idivq %rsi",
282
+ mnemonic="IDIVQ",
283
+ reason="IDIVQ has data-dependent timing",
284
+ severity=Severity.ERROR,
285
+ )
286
+ ],
287
+ )
288
+
289
+ output = format_report(report, OutputFormat.TEXT)
290
+ self.assertIn("FAILED", output)
291
+ self.assertIn("IDIVQ", output)
292
+
293
+
294
+ class TestIntegration(unittest.TestCase):
295
+ """Integration tests that compile actual code.
296
+
297
+ These tests require clang/gcc to be installed and may be skipped
298
+ in environments without compilers.
299
+ """
300
+
301
+ @classmethod
302
+ def setUpClass(cls):
303
+ """Check if compilers are available."""
304
+ cls.samples_dir = Path(__file__).parent / "test_samples"
305
+ cls.has_clang = cls._check_compiler("clang")
306
+ cls.has_gcc = cls._check_compiler("gcc")
307
+
308
+ @staticmethod
309
+ def _check_compiler(name):
310
+ try:
311
+ subprocess.run([name, "--version"], capture_output=True, check=True)
312
+ return True
313
+ except (subprocess.CalledProcessError, FileNotFoundError):
314
+ return False
315
+
316
+ @unittest.skipUnless(lambda self: self.has_clang or self.has_gcc, "No C compiler available")
317
+ def test_vulnerable_c_detected(self):
318
+ """Vulnerable C implementation should be detected."""
319
+ if not (self.has_clang or self.has_gcc):
320
+ self.skipTest("No C compiler available")
321
+
322
+ vulnerable_file = self.samples_dir / "decompose_vulnerable.c"
323
+ if not vulnerable_file.exists():
324
+ self.skipTest("Test sample not found")
325
+
326
+ compiler = "clang" if self.has_clang else "gcc"
327
+
328
+ try:
329
+ report = analyze_source(
330
+ str(vulnerable_file),
331
+ compiler=compiler,
332
+ optimization="O2",
333
+ )
334
+
335
+ # Should detect division instructions
336
+ self.assertFalse(report.passed, "Vulnerable code should fail analysis")
337
+ self.assertGreater(report.error_count, 0, "Should find error-level violations")
338
+
339
+ # Check that we found division-related violations
340
+ div_violations = [v for v in report.violations if "div" in v.mnemonic.lower()]
341
+ self.assertGreater(len(div_violations), 0, "Should detect division instructions")
342
+
343
+ except RuntimeError as e:
344
+ if "Compilation failed" in str(e):
345
+ self.skipTest(f"Compilation failed: {e}")
346
+ raise
347
+
348
+ @unittest.skipUnless(lambda self: self.has_clang or self.has_gcc, "No C compiler available")
349
+ def test_constant_time_c_clean(self):
350
+ """Constant-time C implementation should pass."""
351
+ if not (self.has_clang or self.has_gcc):
352
+ self.skipTest("No C compiler available")
353
+
354
+ ct_file = self.samples_dir / "decompose_constant_time.c"
355
+ if not ct_file.exists():
356
+ self.skipTest("Test sample not found")
357
+
358
+ compiler = "clang" if self.has_clang else "gcc"
359
+
360
+ try:
361
+ report = analyze_source(
362
+ str(ct_file),
363
+ compiler=compiler,
364
+ optimization="O2",
365
+ )
366
+
367
+ # Constant-time implementation should not have division
368
+ div_violations = [
369
+ v
370
+ for v in report.violations
371
+ if "div" in v.mnemonic.lower() and v.severity == Severity.ERROR
372
+ ]
373
+
374
+ # Note: We allow this to be empty OR the compiler might have
375
+ # optimized in unexpected ways
376
+ if div_violations:
377
+ print(f"WARNING: Found {len(div_violations)} division violations")
378
+ print("This may indicate the compiler optimized differently than expected")
379
+
380
+ except RuntimeError as e:
381
+ if "Compilation failed" in str(e):
382
+ self.skipTest(f"Compilation failed: {e}")
383
+ raise
384
+
385
+ def test_multiple_optimization_levels(self):
386
+ """Test that analysis works across optimization levels."""
387
+ if not (self.has_clang or self.has_gcc):
388
+ self.skipTest("No C compiler available")
389
+
390
+ vulnerable_file = self.samples_dir / "decompose_vulnerable.c"
391
+ if not vulnerable_file.exists():
392
+ self.skipTest("Test sample not found")
393
+
394
+ compiler = "clang" if self.has_clang else "gcc"
395
+
396
+ for opt in ["O0", "O1", "O2", "O3"]:
397
+ with self.subTest(optimization=opt):
398
+ try:
399
+ report = analyze_source(
400
+ str(vulnerable_file),
401
+ compiler=compiler,
402
+ optimization=opt,
403
+ )
404
+ # Just verify it runs without error
405
+ self.assertIsNotNone(report)
406
+
407
+ except RuntimeError as e:
408
+ if "Compilation failed" in str(e):
409
+ # Some optimization levels may not work on all systems
410
+ continue
411
+ raise
412
+
413
+
414
+ class TestCrossArchitecture(unittest.TestCase):
415
+ """Test cross-architecture compilation and analysis.
416
+
417
+ These tests verify that the analyzer can handle different target
418
+ architectures, even when cross-compiling from a different host.
419
+ """
420
+
421
+ @classmethod
422
+ def setUpClass(cls):
423
+ cls.samples_dir = Path(__file__).parent / "test_samples"
424
+ cls.has_clang = TestIntegration._check_compiler("clang")
425
+
426
+ @unittest.skipUnless(lambda self: self.has_clang, "Clang required for cross-compilation")
427
+ def test_cross_compile_arm64(self):
428
+ """Test cross-compilation to ARM64."""
429
+ if not self.has_clang:
430
+ self.skipTest("Clang not available")
431
+
432
+ vulnerable_file = self.samples_dir / "decompose_vulnerable.c"
433
+ if not vulnerable_file.exists():
434
+ self.skipTest("Test sample not found")
435
+
436
+ try:
437
+ report = analyze_source(
438
+ str(vulnerable_file),
439
+ arch="arm64",
440
+ compiler="clang",
441
+ optimization="O2",
442
+ )
443
+
444
+ # Should still detect violations, just ARM64 specific ones
445
+ self.assertIsNotNone(report)
446
+ self.assertEqual(report.architecture, "arm64")
447
+
448
+ except RuntimeError as e:
449
+ if "target" in str(e).lower() or "triple" in str(e).lower():
450
+ self.skipTest("ARM64 cross-compilation not supported")
451
+ raise
452
+
453
+
454
+ class TestScriptingLanguageDetection(unittest.TestCase):
455
+ """Test language detection for scripting languages."""
456
+
457
+ def test_detect_php(self):
458
+ self.assertEqual(detect_language("crypto.php"), "php")
459
+ self.assertEqual(detect_language("/path/to/crypto.php"), "php")
460
+
461
+ def test_detect_javascript(self):
462
+ self.assertEqual(detect_language("crypto.js"), "javascript")
463
+ self.assertEqual(detect_language("crypto.mjs"), "javascript")
464
+ self.assertEqual(detect_language("crypto.cjs"), "javascript")
465
+
466
+ def test_detect_typescript(self):
467
+ self.assertEqual(detect_language("crypto.ts"), "typescript")
468
+ self.assertEqual(detect_language("crypto.tsx"), "typescript")
469
+ self.assertEqual(detect_language("crypto.mts"), "typescript")
470
+
471
+
472
+ class TestPHPAnalyzerParsing(unittest.TestCase):
473
+ """Test PHP opcode parsing."""
474
+
475
+ def test_parse_vld_division(self):
476
+ """Parser should detect PHP division opcodes."""
477
+ from script_analyzers import PHPAnalyzer
478
+
479
+ # Sample VLD output with division
480
+ vld_output = """
481
+ Finding entry points
482
+ Branch analysis from position: 0
483
+ filename: /path/to/test.php
484
+ function name: vulnerable_mod
485
+ number of ops: 8
486
+ compiled vars: !0 = $value, !1 = $modulus
487
+ line #* E I O op fetch ext return operands
488
+ -------------------------------------------------------------------------------------
489
+ 5 0 E > RECV !0
490
+ 1 RECV !1
491
+ 6 2 DIV ~2 !0, !1
492
+ 7 3 ASSIGN !2, ~2
493
+ 8 4 MOD ~4 !0, !1
494
+ 5 ASSIGN !3, ~4
495
+ 9 6 RETURN !3
496
+ 10 7 > RETURN null
497
+ """
498
+
499
+ analyzer = PHPAnalyzer()
500
+ functions, violations = analyzer._parse_vld_output(vld_output)
501
+
502
+ # Should find DIV and MOD opcodes
503
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
504
+ self.assertGreater(len(error_violations), 0, "Should detect DIV/MOD opcodes")
505
+
506
+ div_violations = [v for v in error_violations if v.mnemonic in ("DIV", "MOD")]
507
+ self.assertEqual(len(div_violations), 2, "Should find both DIV and MOD")
508
+
509
+ def test_parse_vld_function_call(self):
510
+ """Parser should detect dangerous PHP function calls."""
511
+ from script_analyzers import PHPAnalyzer
512
+
513
+ vld_output = """
514
+ filename: /path/to/test.php
515
+ function name: vulnerable_encode
516
+ number of ops: 5
517
+ compiled vars: !0 = $data
518
+ line #* E I O op fetch ext return operands
519
+ -------------------------------------------------------------------------------------
520
+ 3 0 E > RECV !0
521
+ 4 1 INIT_FCALL 'bin2hex'
522
+ 2 SEND_VAR !0
523
+ 3 DO_ICALL $1
524
+ 5 4 > RETURN $1
525
+ """
526
+
527
+ analyzer = PHPAnalyzer()
528
+ functions, violations = analyzer._parse_vld_output(vld_output)
529
+
530
+ # Should detect bin2hex call
531
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
532
+ self.assertGreater(len(error_violations), 0, "Should detect bin2hex call")
533
+
534
+ bin2hex_violations = [v for v in error_violations if "bin2hex" in v.mnemonic.lower()]
535
+ self.assertEqual(len(bin2hex_violations), 1)
536
+
537
+ def test_parse_vld_mt_rand(self):
538
+ """Parser should detect mt_rand as dangerous."""
539
+ from script_analyzers import PHPAnalyzer
540
+
541
+ vld_output = """
542
+ filename: /path/to/test.php
543
+ function name: generate_token
544
+ line #* E I O op fetch ext return operands
545
+ -------------------------------------------------------------------------------------
546
+ 3 0 E > INIT_FCALL 'mt_rand'
547
+ 1 SEND_VAL 0
548
+ 2 SEND_VAL 100
549
+ 3 DO_ICALL $0
550
+ 4 4 > RETURN $0
551
+ """
552
+
553
+ analyzer = PHPAnalyzer()
554
+ functions, violations = analyzer._parse_vld_output(vld_output)
555
+
556
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
557
+ self.assertGreater(len(error_violations), 0, "Should detect mt_rand")
558
+
559
+
560
+ class TestJavaScriptAnalyzerParsing(unittest.TestCase):
561
+ """Test JavaScript V8 bytecode parsing."""
562
+
563
+ def test_parse_v8_division(self):
564
+ """Parser should detect V8 division bytecodes."""
565
+ from script_analyzers import JavaScriptAnalyzer
566
+
567
+ v8_output = """
568
+ [generated bytecode for function: vulnerableDiv (0x1234)]
569
+ Bytecode length: 20
570
+ Parameter count 3
571
+ Register count 2
572
+ Frame size 16
573
+ 0 : Ldar a0
574
+ 2 : Star0
575
+ 3 : Ldar a1
576
+ 5 : Div r0
577
+ 7 : Star1
578
+ 8 : Ldar r1
579
+ 10 : Return
580
+ """
581
+
582
+ analyzer = JavaScriptAnalyzer()
583
+ functions, violations = analyzer._parse_v8_bytecode(
584
+ v8_output, "test.js", include_warnings=False
585
+ )
586
+
587
+ self.assertEqual(len(functions), 1)
588
+ self.assertEqual(functions[0]["name"], "vulnerableDiv")
589
+
590
+ # Should find Div bytecode
591
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
592
+ self.assertGreater(len(error_violations), 0, "Should detect Div bytecode")
593
+
594
+ def test_parse_v8_modulo(self):
595
+ """Parser should detect V8 modulo bytecodes."""
596
+ from script_analyzers import JavaScriptAnalyzer
597
+
598
+ v8_output = """
599
+ [generated bytecode for function: vulnerableMod (0x5678)]
600
+ Bytecode length: 15
601
+ Parameter count 3
602
+ Register count 1
603
+ Frame size 8
604
+ 0 : Ldar a0
605
+ 2 : Mod a1
606
+ 4 : Return
607
+ """
608
+
609
+ analyzer = JavaScriptAnalyzer()
610
+ functions, violations = analyzer._parse_v8_bytecode(v8_output, "test.js")
611
+
612
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
613
+ self.assertGreater(len(error_violations), 0, "Should detect Mod bytecode")
614
+
615
+ def test_detect_math_sqrt_in_source(self):
616
+ """Should detect Math.sqrt() calls in source."""
617
+ # Create a temp file with Math.sqrt
618
+ import tempfile
619
+
620
+ from script_analyzers import JavaScriptAnalyzer
621
+
622
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".js", delete=False) as f:
623
+ f.write("""
624
+ function vulnerable(x) {
625
+ return Math.sqrt(x);
626
+ }
627
+ """)
628
+ temp_path = f.name
629
+
630
+ try:
631
+ analyzer = JavaScriptAnalyzer()
632
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
633
+
634
+ sqrt_violations = [v for v in violations if "SQRT" in v.mnemonic.upper()]
635
+ self.assertGreater(len(sqrt_violations), 0, "Should detect Math.sqrt()")
636
+ finally:
637
+ os.unlink(temp_path)
638
+
639
+ def test_detect_math_random_in_source(self):
640
+ """Should detect Math.random() calls in source."""
641
+ import tempfile
642
+
643
+ from script_analyzers import JavaScriptAnalyzer
644
+
645
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".js", delete=False) as f:
646
+ f.write("""
647
+ function generateToken() {
648
+ return Math.random().toString(36);
649
+ }
650
+ """)
651
+ temp_path = f.name
652
+
653
+ try:
654
+ analyzer = JavaScriptAnalyzer()
655
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
656
+
657
+ random_violations = [v for v in violations if "RANDOM" in v.mnemonic.upper()]
658
+ self.assertGreater(len(random_violations), 0, "Should detect Math.random()")
659
+ finally:
660
+ os.unlink(temp_path)
661
+
662
+
663
+ class TestPythonAnalyzerParsing(unittest.TestCase):
664
+ """Test Python dis bytecode parsing."""
665
+
666
+ def test_parse_dis_division_python311(self):
667
+ """Parser should detect Python 3.11+ BINARY_OP division."""
668
+ from script_analyzers import PythonAnalyzer
669
+
670
+ # Python 3.11+ dis output format
671
+ dis_output = """
672
+ Disassembly of <code object vulnerable_div at 0x1234>:
673
+ 3 0 RESUME 0
674
+
675
+ 4 2 LOAD_FAST 0 (value)
676
+ 4 LOAD_FAST 1 (modulus)
677
+ 6 BINARY_OP 11 (/)
678
+ 8 STORE_FAST 2 (result)
679
+
680
+ 5 10 LOAD_FAST 0 (value)
681
+ 12 LOAD_FAST 1 (modulus)
682
+ 14 BINARY_OP 6 (%)
683
+ 16 STORE_FAST 3 (remainder)
684
+ 18 RETURN_VALUE
685
+ """
686
+
687
+ analyzer = PythonAnalyzer()
688
+ functions, violations = analyzer._parse_dis_output(dis_output, "test.py")
689
+
690
+ self.assertEqual(len(functions), 1)
691
+ self.assertEqual(functions[0]["name"], "vulnerable_div")
692
+
693
+ # Should find BINARY_OP division and modulo
694
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
695
+ self.assertEqual(len(error_violations), 2, "Should detect both / and % operators")
696
+
697
+ def test_parse_dis_division_python310(self):
698
+ """Parser should detect Python < 3.11 division bytecodes."""
699
+ from script_analyzers import PythonAnalyzer
700
+
701
+ # Python < 3.11 dis output format
702
+ dis_output = """
703
+ Disassembly of <code object vulnerable_div at 0x1234>:
704
+ 3 0 LOAD_FAST 0 (value)
705
+ 2 LOAD_FAST 1 (modulus)
706
+ 4 BINARY_TRUE_DIVIDE
707
+ 6 STORE_FAST 2 (result)
708
+ 8 LOAD_FAST 0 (value)
709
+ 10 LOAD_FAST 1 (modulus)
710
+ 12 BINARY_MODULO
711
+ 14 STORE_FAST 3 (remainder)
712
+ 16 LOAD_CONST 0 (None)
713
+ 18 RETURN_VALUE
714
+ """
715
+
716
+ analyzer = PythonAnalyzer()
717
+ functions, violations = analyzer._parse_dis_output(dis_output, "test.py")
718
+
719
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
720
+ self.assertEqual(
721
+ len(error_violations), 2, "Should detect BINARY_TRUE_DIVIDE and BINARY_MODULO"
722
+ )
723
+
724
+ mnemonics = {v.mnemonic for v in error_violations}
725
+ self.assertIn("BINARY_TRUE_DIVIDE", mnemonics)
726
+ self.assertIn("BINARY_MODULO", mnemonics)
727
+
728
+ def test_detect_random_in_source(self):
729
+ """Should detect random.random() calls in source."""
730
+ import tempfile
731
+
732
+ from script_analyzers import PythonAnalyzer
733
+
734
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
735
+ f.write("""
736
+ import random
737
+
738
+ def generate_token():
739
+ return random.random()
740
+
741
+ def generate_int():
742
+ return random.randint(0, 100)
743
+ """)
744
+ temp_path = f.name
745
+
746
+ try:
747
+ analyzer = PythonAnalyzer()
748
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
749
+
750
+ random_violations = [v for v in violations if "RANDOM" in v.mnemonic.upper()]
751
+ self.assertEqual(
752
+ len(random_violations), 2, "Should detect random.random() and random.randint()"
753
+ )
754
+ finally:
755
+ os.unlink(temp_path)
756
+
757
+ def test_detect_math_sqrt_in_source(self):
758
+ """Should detect math.sqrt() calls in source."""
759
+ import tempfile
760
+
761
+ from script_analyzers import PythonAnalyzer
762
+
763
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
764
+ f.write("""
765
+ import math
766
+
767
+ def vulnerable(x):
768
+ return math.sqrt(x)
769
+ """)
770
+ temp_path = f.name
771
+
772
+ try:
773
+ analyzer = PythonAnalyzer()
774
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
775
+
776
+ sqrt_violations = [v for v in violations if "SQRT" in v.mnemonic.upper()]
777
+ self.assertGreater(len(sqrt_violations), 0, "Should detect math.sqrt()")
778
+ finally:
779
+ os.unlink(temp_path)
780
+
781
+
782
+ class TestRubyAnalyzerParsing(unittest.TestCase):
783
+ """Test Ruby YARV bytecode parsing."""
784
+
785
+ def test_parse_yarv_division(self):
786
+ """Parser should detect Ruby opt_div bytecodes."""
787
+ from script_analyzers import RubyAnalyzer
788
+
789
+ # Ruby YARV output format
790
+ yarv_output = """
791
+ == disasm: #<ISeq:<main>@test.rb:1 (1,0)-(10,3)>
792
+ 0000 putobject 10
793
+ 0002 putobject 3
794
+ 0004 opt_div <calldata!mid:/, argc:1, ARGS_SIMPLE>
795
+ 0006 leave
796
+
797
+ == disasm: #<ISeq:vulnerable_mod@test.rb:5 (5,0)-(8,3)>
798
+ local table (size: 2, argc: 2 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
799
+ [ 2] value@0 [ 1] modulus@1
800
+ 0000 getlocal_WC_0 value@0
801
+ 0002 getlocal_WC_0 modulus@1
802
+ 0004 opt_mod <calldata!mid:%, argc:1, ARGS_SIMPLE>
803
+ 0006 leave
804
+ """
805
+
806
+ analyzer = RubyAnalyzer()
807
+ functions, violations = analyzer._parse_yarv_output(yarv_output, "test.rb")
808
+
809
+ self.assertEqual(len(functions), 2)
810
+ self.assertEqual(functions[0]["name"], "<main>")
811
+ self.assertEqual(functions[1]["name"], "vulnerable_mod")
812
+
813
+ # Should find opt_div and opt_mod
814
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
815
+ self.assertEqual(len(error_violations), 2, "Should detect opt_div and opt_mod")
816
+
817
+ mnemonics = {v.mnemonic for v in error_violations}
818
+ self.assertIn("OPT_DIV", mnemonics)
819
+ self.assertIn("OPT_MOD", mnemonics)
820
+
821
+ def test_parse_yarv_warnings(self):
822
+ """Parser should detect Ruby comparison bytecodes as warnings."""
823
+ from script_analyzers import RubyAnalyzer
824
+
825
+ yarv_output = """
826
+ == disasm: #<ISeq:compare@test.rb:1 (1,0)-(3,3)>
827
+ 0000 getlocal_WC_0 a@0
828
+ 0002 getlocal_WC_0 b@1
829
+ 0004 opt_eq <calldata!mid:==, argc:1, ARGS_SIMPLE>
830
+ 0006 branchif 10
831
+ 0008 putnil
832
+ 0009 leave
833
+ 0010 putobject true
834
+ 0012 leave
835
+ """
836
+
837
+ analyzer = RubyAnalyzer()
838
+ functions, violations = analyzer._parse_yarv_output(
839
+ yarv_output, "test.rb", include_warnings=True
840
+ )
841
+
842
+ warning_violations = [v for v in violations if v.severity == Severity.WARNING]
843
+ self.assertGreater(
844
+ len(warning_violations), 0, "Should detect opt_eq and branchif as warnings"
845
+ )
846
+
847
+ def test_detect_rand_in_source(self):
848
+ """Should detect rand() calls in source."""
849
+ import tempfile
850
+
851
+ from script_analyzers import RubyAnalyzer
852
+
853
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".rb", delete=False) as f:
854
+ f.write("""
855
+ def generate_token
856
+ rand(100)
857
+ end
858
+
859
+ def generate_random
860
+ Random.new.rand
861
+ end
862
+ """)
863
+ temp_path = f.name
864
+
865
+ try:
866
+ analyzer = RubyAnalyzer()
867
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
868
+
869
+ rand_violations = [v for v in violations if "RAND" in v.mnemonic.upper()]
870
+ self.assertGreater(len(rand_violations), 0, "Should detect rand() calls")
871
+ finally:
872
+ os.unlink(temp_path)
873
+
874
+
875
+ class TestJavaAnalyzerParsing(unittest.TestCase):
876
+ """Test Java bytecode parsing."""
877
+
878
+ def test_parse_javap_division(self):
879
+ """Parser should detect Java division bytecodes."""
880
+ from script_analyzers import JavaAnalyzer
881
+
882
+ # Sample javap output with division
883
+ javap_output = """
884
+ public class CryptoUtils {
885
+ public int vulnerableDiv(int, int);
886
+ Code:
887
+ 0: iload_1
888
+ 1: iload_2
889
+ 2: idiv
890
+ 3: istore_3
891
+ 4: iload_1
892
+ 5: iload_2
893
+ 6: irem
894
+ 7: istore 4
895
+ 9: iload_3
896
+ 10: ireturn
897
+ LineNumberTable:
898
+ line 5: 0
899
+ line 6: 4
900
+ line 7: 9
901
+ }
902
+ """
903
+
904
+ analyzer = JavaAnalyzer()
905
+ functions, violations = analyzer._parse_javap_output(javap_output, "CryptoUtils.java")
906
+
907
+ self.assertEqual(len(functions), 1)
908
+ self.assertEqual(functions[0]["name"], "CryptoUtils.vulnerableDiv")
909
+
910
+ # Should find idiv and irem bytecodes
911
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
912
+ self.assertEqual(len(error_violations), 2, "Should detect idiv and irem")
913
+
914
+ mnemonics = {v.mnemonic for v in error_violations}
915
+ self.assertIn("IDIV", mnemonics)
916
+ self.assertIn("IREM", mnemonics)
917
+
918
+ def test_parse_javap_long_division(self):
919
+ """Parser should detect Java long division bytecodes."""
920
+ from script_analyzers import JavaAnalyzer
921
+
922
+ javap_output = """
923
+ public class CryptoUtils {
924
+ public long vulnerableLongDiv(long, long);
925
+ Code:
926
+ 0: lload_1
927
+ 1: lload_3
928
+ 2: ldiv
929
+ 3: lreturn
930
+ }
931
+ """
932
+
933
+ analyzer = JavaAnalyzer()
934
+ functions, violations = analyzer._parse_javap_output(javap_output, "CryptoUtils.java")
935
+
936
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
937
+ self.assertGreater(len(error_violations), 0, "Should detect ldiv")
938
+ self.assertEqual(error_violations[0].mnemonic, "LDIV")
939
+
940
+ def test_parse_javap_float_division(self):
941
+ """Parser should detect Java float division bytecodes."""
942
+ from script_analyzers import JavaAnalyzer
943
+
944
+ javap_output = """
945
+ public class CryptoUtils {
946
+ public double vulnerableFloatDiv(double, double);
947
+ Code:
948
+ 0: dload_1
949
+ 1: dload_3
950
+ 2: ddiv
951
+ 3: dreturn
952
+ }
953
+ """
954
+
955
+ analyzer = JavaAnalyzer()
956
+ functions, violations = analyzer._parse_javap_output(javap_output, "CryptoUtils.java")
957
+
958
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
959
+ self.assertGreater(len(error_violations), 0, "Should detect ddiv")
960
+ self.assertEqual(error_violations[0].mnemonic, "DDIV")
961
+
962
+ def test_parse_javap_warnings(self):
963
+ """Parser should detect Java conditional branches as warnings."""
964
+ from script_analyzers import JavaAnalyzer
965
+
966
+ javap_output = """
967
+ public class CryptoUtils {
968
+ public boolean compare(int, int);
969
+ Code:
970
+ 0: iload_1
971
+ 1: iload_2
972
+ 2: if_icmpne 9
973
+ 5: iconst_1
974
+ 6: goto 10
975
+ 9: iconst_0
976
+ 10: ireturn
977
+ }
978
+ """
979
+
980
+ analyzer = JavaAnalyzer()
981
+ functions, violations = analyzer._parse_javap_output(
982
+ javap_output, "CryptoUtils.java", include_warnings=True
983
+ )
984
+
985
+ warning_violations = [v for v in violations if v.severity == Severity.WARNING]
986
+ self.assertGreater(len(warning_violations), 0, "Should detect if_icmpne as warning")
987
+
988
+ def test_detect_java_random_in_source(self):
989
+ """Should detect new Random() calls in Java source."""
990
+ import tempfile
991
+
992
+ from script_analyzers import JavaAnalyzer
993
+
994
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".java", delete=False) as f:
995
+ f.write("""
996
+ public class Test {
997
+ public int generate() {
998
+ Random rand = new Random();
999
+ return rand.nextInt(100);
1000
+ }
1001
+ }
1002
+ """)
1003
+ temp_path = f.name
1004
+
1005
+ try:
1006
+ analyzer = JavaAnalyzer()
1007
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
1008
+
1009
+ random_violations = [v for v in violations if "RANDOM" in v.mnemonic.upper()]
1010
+ self.assertGreater(len(random_violations), 0, "Should detect new Random()")
1011
+ finally:
1012
+ os.unlink(temp_path)
1013
+
1014
+ def test_detect_math_sqrt_in_java_source(self):
1015
+ """Should detect Math.sqrt() calls in Java source."""
1016
+ import tempfile
1017
+
1018
+ from script_analyzers import JavaAnalyzer
1019
+
1020
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".java", delete=False) as f:
1021
+ f.write("""
1022
+ public class Test {
1023
+ public double calculate(double x) {
1024
+ return Math.sqrt(x);
1025
+ }
1026
+ }
1027
+ """)
1028
+ temp_path = f.name
1029
+
1030
+ try:
1031
+ analyzer = JavaAnalyzer()
1032
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
1033
+
1034
+ sqrt_violations = [v for v in violations if "SQRT" in v.mnemonic.upper()]
1035
+ self.assertGreater(len(sqrt_violations), 0, "Should detect Math.sqrt()")
1036
+ finally:
1037
+ os.unlink(temp_path)
1038
+
1039
+
1040
+ class TestCSharpAnalyzerParsing(unittest.TestCase):
1041
+ """Test C# IL bytecode parsing."""
1042
+
1043
+ def test_parse_il_division(self):
1044
+ """Parser should detect C# division IL opcodes."""
1045
+ from script_analyzers import CSharpAnalyzer
1046
+
1047
+ # Sample IL output with division
1048
+ il_output = """
1049
+ .method public hidebysig instance int32 VulnerableDiv(int32, int32) cil managed
1050
+ {
1051
+ .maxstack 2
1052
+ .locals init (int32 V_0)
1053
+ IL_0000: ldarg.1
1054
+ IL_0001: ldarg.2
1055
+ IL_0002: div
1056
+ IL_0003: stloc.0
1057
+ IL_0004: ldarg.1
1058
+ IL_0005: ldarg.2
1059
+ IL_0006: rem
1060
+ IL_0007: stloc.1
1061
+ IL_0008: ldloc.0
1062
+ IL_0009: ret
1063
+ }
1064
+ """
1065
+
1066
+ analyzer = CSharpAnalyzer()
1067
+ functions, violations = analyzer._parse_il_output(il_output, "CryptoUtils.cs")
1068
+
1069
+ self.assertEqual(len(functions), 1)
1070
+ self.assertEqual(functions[0]["name"], "VulnerableDiv")
1071
+
1072
+ # Should find div and rem opcodes
1073
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
1074
+ self.assertEqual(len(error_violations), 2, "Should detect div and rem")
1075
+
1076
+ mnemonics = {v.mnemonic for v in error_violations}
1077
+ self.assertIn("DIV", mnemonics)
1078
+ self.assertIn("REM", mnemonics)
1079
+
1080
+ def test_parse_il_unsigned_division(self):
1081
+ """Parser should detect C# unsigned division IL opcodes."""
1082
+ from script_analyzers import CSharpAnalyzer
1083
+
1084
+ il_output = """
1085
+ .method public hidebysig static uint32 UnsignedDiv(uint32, uint32) cil managed
1086
+ {
1087
+ .maxstack 2
1088
+ IL_0000: ldarg.0
1089
+ IL_0001: ldarg.1
1090
+ IL_0002: div.un
1091
+ IL_0003: ret
1092
+ }
1093
+ """
1094
+
1095
+ analyzer = CSharpAnalyzer()
1096
+ functions, violations = analyzer._parse_il_output(il_output, "CryptoUtils.cs")
1097
+
1098
+ error_violations = [v for v in violations if v.severity == Severity.ERROR]
1099
+ self.assertGreater(len(error_violations), 0, "Should detect div.un")
1100
+ self.assertEqual(error_violations[0].mnemonic, "DIV.UN")
1101
+
1102
+ def test_parse_il_warnings(self):
1103
+ """Parser should detect C# conditional branches as warnings."""
1104
+ from script_analyzers import CSharpAnalyzer
1105
+
1106
+ il_output = """
1107
+ .method public hidebysig instance bool Compare(int32, int32) cil managed
1108
+ {
1109
+ .maxstack 2
1110
+ IL_0000: ldarg.1
1111
+ IL_0001: ldarg.2
1112
+ IL_0002: beq.s IL_0006
1113
+ IL_0004: ldc.i4.0
1114
+ IL_0005: ret
1115
+ IL_0006: ldc.i4.1
1116
+ IL_0007: ret
1117
+ }
1118
+ """
1119
+
1120
+ analyzer = CSharpAnalyzer()
1121
+ functions, violations = analyzer._parse_il_output(
1122
+ il_output, "CryptoUtils.cs", include_warnings=True
1123
+ )
1124
+
1125
+ warning_violations = [v for v in violations if v.severity == Severity.WARNING]
1126
+ self.assertGreater(len(warning_violations), 0, "Should detect beq.s as warning")
1127
+
1128
+ def test_detect_csharp_random_in_source(self):
1129
+ """Should detect new Random() calls in C# source."""
1130
+ import tempfile
1131
+
1132
+ from script_analyzers import CSharpAnalyzer
1133
+
1134
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".cs", delete=False) as f:
1135
+ f.write("""
1136
+ public class Test {
1137
+ public int Generate() {
1138
+ Random rand = new Random();
1139
+ return rand.Next(100);
1140
+ }
1141
+ }
1142
+ """)
1143
+ temp_path = f.name
1144
+
1145
+ try:
1146
+ analyzer = CSharpAnalyzer()
1147
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
1148
+
1149
+ random_violations = [v for v in violations if "RANDOM" in v.mnemonic.upper()]
1150
+ self.assertGreater(len(random_violations), 0, "Should detect new Random()")
1151
+ finally:
1152
+ os.unlink(temp_path)
1153
+
1154
+ def test_detect_math_sqrt_in_csharp_source(self):
1155
+ """Should detect Math.Sqrt() calls in C# source."""
1156
+ import tempfile
1157
+
1158
+ from script_analyzers import CSharpAnalyzer
1159
+
1160
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".cs", delete=False) as f:
1161
+ f.write("""
1162
+ public class Test {
1163
+ public double Calculate(double x) {
1164
+ return Math.Sqrt(x);
1165
+ }
1166
+ }
1167
+ """)
1168
+ temp_path = f.name
1169
+
1170
+ try:
1171
+ analyzer = CSharpAnalyzer()
1172
+ violations = analyzer._detect_dangerous_function_calls(temp_path)
1173
+
1174
+ sqrt_violations = [v for v in violations if "SQRT" in v.mnemonic.upper()]
1175
+ self.assertGreater(len(sqrt_violations), 0, "Should detect Math.Sqrt()")
1176
+ finally:
1177
+ os.unlink(temp_path)
1178
+
1179
+ def test_source_only_fallback(self):
1180
+ """Source-only analysis should detect division operators."""
1181
+ import tempfile
1182
+
1183
+ from script_analyzers import CSharpAnalyzer
1184
+
1185
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".cs", delete=False) as f:
1186
+ f.write("""
1187
+ public class Test {
1188
+ public int Divide(int a, int b) {
1189
+ return a / b;
1190
+ }
1191
+ public int Modulo(int a, int b) {
1192
+ return a % b;
1193
+ }
1194
+ }
1195
+ """)
1196
+ temp_path = f.name
1197
+
1198
+ try:
1199
+ analyzer = CSharpAnalyzer()
1200
+ report = analyzer._analyze_source_only(temp_path)
1201
+
1202
+ # Should detect division and modulo operators
1203
+ div_violations = [v for v in report.violations if "DIV" in v.mnemonic]
1204
+ mod_violations = [v for v in report.violations if "REM" in v.mnemonic]
1205
+
1206
+ self.assertGreater(len(div_violations), 0, "Should detect / operator")
1207
+ self.assertGreater(len(mod_violations), 0, "Should detect % operator")
1208
+ finally:
1209
+ os.unlink(temp_path)
1210
+
1211
+
1212
+ class TestScriptAnalyzerIntegration(unittest.TestCase):
1213
+ """Integration tests for scripting language analyzers.
1214
+
1215
+ These tests require PHP/Node.js/Python/Ruby to be installed.
1216
+ """
1217
+
1218
+ @classmethod
1219
+ def setUpClass(cls):
1220
+ cls.samples_dir = Path(__file__).parent / "test_samples"
1221
+ cls.has_php = cls._check_runtime("php")
1222
+ cls.has_node = cls._check_runtime("node")
1223
+ cls.has_python = cls._check_runtime("python3")
1224
+ cls.has_ruby = cls._check_runtime("ruby")
1225
+
1226
+ @staticmethod
1227
+ def _check_runtime(name):
1228
+ try:
1229
+ subprocess.run([name, "--version"], capture_output=True, check=True)
1230
+ return True
1231
+ except (subprocess.CalledProcessError, FileNotFoundError):
1232
+ return False
1233
+
1234
+ def test_php_vulnerable_detected(self):
1235
+ """Vulnerable PHP code should be detected."""
1236
+ if not self.has_php:
1237
+ self.skipTest("PHP not available")
1238
+
1239
+ vulnerable_file = self.samples_dir / "vulnerable.php"
1240
+ if not vulnerable_file.exists():
1241
+ self.skipTest("PHP test sample not found")
1242
+
1243
+ try:
1244
+ report = analyze_source(str(vulnerable_file), include_warnings=False)
1245
+
1246
+ # Should detect dangerous operations
1247
+ self.assertIsNotNone(report)
1248
+ self.assertEqual(report.architecture, "zend")
1249
+
1250
+ # Check for expected violations (div, mod, or dangerous functions)
1251
+ if report.error_count > 0:
1252
+ self.assertFalse(report.passed, "Should fail with violations")
1253
+
1254
+ except RuntimeError as e:
1255
+ if "VLD" in str(e) or "opcache" in str(e).lower():
1256
+ # VLD/opcache may not produce output for simple files
1257
+ pass
1258
+ else:
1259
+ raise
1260
+
1261
+ def test_javascript_vulnerable_detected(self):
1262
+ """Vulnerable JavaScript code should be detected."""
1263
+ if not self.has_node:
1264
+ self.skipTest("Node.js not available")
1265
+
1266
+ # Create a simple vulnerable JS file for testing
1267
+ import tempfile
1268
+
1269
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".js", delete=False) as f:
1270
+ f.write("""
1271
+ function vulnerableDiv(a, b) {
1272
+ return a / b;
1273
+ }
1274
+
1275
+ function vulnerableRandom() {
1276
+ return Math.random();
1277
+ }
1278
+
1279
+ // Call functions to ensure they're compiled
1280
+ console.log(vulnerableDiv(10, 3));
1281
+ console.log(vulnerableRandom());
1282
+ """)
1283
+ temp_path = f.name
1284
+
1285
+ try:
1286
+ report = analyze_source(temp_path, include_warnings=False)
1287
+
1288
+ self.assertIsNotNone(report)
1289
+ self.assertEqual(report.architecture, "v8")
1290
+
1291
+ # Should detect Math.random at minimum (via source analysis)
1292
+ # V8 bytecode detection depends on function being compiled
1293
+
1294
+ except RuntimeError as e:
1295
+ if "bytecode" in str(e).lower():
1296
+ # V8 bytecode output can be tricky
1297
+ pass
1298
+ else:
1299
+ raise
1300
+ finally:
1301
+ os.unlink(temp_path)
1302
+
1303
+ def test_python_vulnerable_detected(self):
1304
+ """Vulnerable Python code should be detected."""
1305
+ if not self.has_python:
1306
+ self.skipTest("Python not available")
1307
+
1308
+ vulnerable_file = self.samples_dir / "vulnerable.py"
1309
+ if not vulnerable_file.exists():
1310
+ self.skipTest("Python test sample not found")
1311
+
1312
+ try:
1313
+ report = analyze_source(str(vulnerable_file), include_warnings=False)
1314
+
1315
+ # Should detect dangerous operations
1316
+ self.assertIsNotNone(report)
1317
+ self.assertEqual(report.architecture, "cpython")
1318
+
1319
+ # Should detect division operations and dangerous functions
1320
+ if report.error_count > 0:
1321
+ self.assertFalse(report.passed, "Should fail with violations")
1322
+
1323
+ # Check for expected violation types
1324
+ div_violations = [
1325
+ v
1326
+ for v in report.violations
1327
+ if "DIV" in v.mnemonic.upper() or "MODULO" in v.mnemonic.upper()
1328
+ ]
1329
+ func_violations = [
1330
+ v
1331
+ for v in report.violations
1332
+ if "RANDOM" in v.mnemonic.upper() or "SQRT" in v.mnemonic.upper()
1333
+ ]
1334
+
1335
+ # Should detect at least some violations
1336
+ self.assertGreater(
1337
+ len(div_violations) + len(func_violations),
1338
+ 0,
1339
+ "Should detect division or dangerous function calls",
1340
+ )
1341
+
1342
+ except RuntimeError as e:
1343
+ if "dis" in str(e).lower():
1344
+ # dis module issues
1345
+ pass
1346
+ else:
1347
+ raise
1348
+
1349
+ def test_ruby_vulnerable_detected(self):
1350
+ """Vulnerable Ruby code should be detected."""
1351
+ if not self.has_ruby:
1352
+ self.skipTest("Ruby not available")
1353
+
1354
+ vulnerable_file = self.samples_dir / "vulnerable.rb"
1355
+ if not vulnerable_file.exists():
1356
+ self.skipTest("Ruby test sample not found")
1357
+
1358
+ try:
1359
+ report = analyze_source(str(vulnerable_file), include_warnings=False)
1360
+
1361
+ # Should detect dangerous operations
1362
+ self.assertIsNotNone(report)
1363
+ self.assertEqual(report.architecture, "yarv")
1364
+
1365
+ # Should detect division operations and dangerous functions
1366
+ if report.error_count > 0:
1367
+ self.assertFalse(report.passed, "Should fail with violations")
1368
+
1369
+ # Check for expected violation types
1370
+ div_violations = [
1371
+ v
1372
+ for v in report.violations
1373
+ if "DIV" in v.mnemonic.upper() or "MOD" in v.mnemonic.upper()
1374
+ ]
1375
+ func_violations = [
1376
+ v
1377
+ for v in report.violations
1378
+ if "RAND" in v.mnemonic.upper() or "SQRT" in v.mnemonic.upper()
1379
+ ]
1380
+
1381
+ # Should detect at least some violations
1382
+ self.assertGreater(
1383
+ len(div_violations) + len(func_violations),
1384
+ 0,
1385
+ "Should detect division or dangerous function calls",
1386
+ )
1387
+
1388
+ except RuntimeError as e:
1389
+ if "yarv" in str(e).lower() or "dump" in str(e).lower():
1390
+ # Ruby YARV issues
1391
+ pass
1392
+ else:
1393
+ raise
1394
+
1395
+
1396
+ if __name__ == "__main__":
1397
+ unittest.main(verbosity=2)