@waratahlabs/canopy 0.5.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 (319) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +323 -0
  3. package/SKILL.md +97 -0
  4. package/demo/data/openclaw-demo.tc.json +397 -0
  5. package/demo/data/openclaw-nemoclaw-demo.tc.json +475 -0
  6. package/demo/index.html +556 -0
  7. package/dist/adapters/a2a.d.ts +82 -0
  8. package/dist/adapters/a2a.d.ts.map +1 -0
  9. package/dist/adapters/a2a.js +215 -0
  10. package/dist/adapters/a2a.js.map +1 -0
  11. package/dist/adapters/a2a.test.d.ts +2 -0
  12. package/dist/adapters/a2a.test.d.ts.map +1 -0
  13. package/dist/adapters/a2a.test.js +196 -0
  14. package/dist/adapters/a2a.test.js.map +1 -0
  15. package/dist/adapters/langfuse.d.ts +28 -0
  16. package/dist/adapters/langfuse.d.ts.map +1 -0
  17. package/dist/adapters/langfuse.js +192 -0
  18. package/dist/adapters/langfuse.js.map +1 -0
  19. package/dist/adapters/n8n.d.ts +4 -0
  20. package/dist/adapters/n8n.d.ts.map +1 -0
  21. package/dist/adapters/n8n.js +89 -0
  22. package/dist/adapters/n8n.js.map +1 -0
  23. package/dist/adapters/openclaw.d.ts +58 -0
  24. package/dist/adapters/openclaw.d.ts.map +1 -0
  25. package/dist/adapters/openclaw.js +275 -0
  26. package/dist/adapters/openclaw.js.map +1 -0
  27. package/dist/adapters/types.d.ts +33 -0
  28. package/dist/adapters/types.d.ts.map +1 -0
  29. package/dist/adapters/types.js +2 -0
  30. package/dist/adapters/types.js.map +1 -0
  31. package/dist/aivss/atlas/coverage-matrix.d.ts +12 -0
  32. package/dist/aivss/atlas/coverage-matrix.d.ts.map +1 -0
  33. package/dist/aivss/atlas/coverage-matrix.js +272 -0
  34. package/dist/aivss/atlas/coverage-matrix.js.map +1 -0
  35. package/dist/aivss/atlas/loader.d.ts +28 -0
  36. package/dist/aivss/atlas/loader.d.ts.map +1 -0
  37. package/dist/aivss/atlas/loader.js +126 -0
  38. package/dist/aivss/atlas/loader.js.map +1 -0
  39. package/dist/aivss/atlas/loader.test.d.ts +11 -0
  40. package/dist/aivss/atlas/loader.test.d.ts.map +1 -0
  41. package/dist/aivss/atlas/loader.test.js +111 -0
  42. package/dist/aivss/atlas/loader.test.js.map +1 -0
  43. package/dist/aivss/atlas/resolve-path.d.ts +34 -0
  44. package/dist/aivss/atlas/resolve-path.d.ts.map +1 -0
  45. package/dist/aivss/atlas/resolve-path.js +58 -0
  46. package/dist/aivss/atlas/resolve-path.js.map +1 -0
  47. package/dist/aivss/batch/batch-builder.d.ts +11 -0
  48. package/dist/aivss/batch/batch-builder.d.ts.map +1 -0
  49. package/dist/aivss/batch/batch-builder.js +75 -0
  50. package/dist/aivss/batch/batch-builder.js.map +1 -0
  51. package/dist/aivss/index.d.ts +21 -0
  52. package/dist/aivss/index.d.ts.map +1 -0
  53. package/dist/aivss/index.js +19 -0
  54. package/dist/aivss/index.js.map +1 -0
  55. package/dist/aivss/knowledge-base/kb-client.d.ts +9 -0
  56. package/dist/aivss/knowledge-base/kb-client.d.ts.map +1 -0
  57. package/dist/aivss/knowledge-base/kb-client.js +139 -0
  58. package/dist/aivss/knowledge-base/kb-client.js.map +1 -0
  59. package/dist/aivss/knowledge-base/kb-types.d.ts +21 -0
  60. package/dist/aivss/knowledge-base/kb-types.d.ts.map +1 -0
  61. package/dist/aivss/knowledge-base/kb-types.js +2 -0
  62. package/dist/aivss/knowledge-base/kb-types.js.map +1 -0
  63. package/dist/aivss/knowledge-base/search-builder.d.ts +7 -0
  64. package/dist/aivss/knowledge-base/search-builder.d.ts.map +1 -0
  65. package/dist/aivss/knowledge-base/search-builder.js +119 -0
  66. package/dist/aivss/knowledge-base/search-builder.js.map +1 -0
  67. package/dist/aivss/metrics/aa.d.ts +3 -0
  68. package/dist/aivss/metrics/aa.d.ts.map +1 -0
  69. package/dist/aivss/metrics/aa.js +26 -0
  70. package/dist/aivss/metrics/aa.js.map +1 -0
  71. package/dist/aivss/metrics/ad.d.ts +3 -0
  72. package/dist/aivss/metrics/ad.d.ts.map +1 -0
  73. package/dist/aivss/metrics/ad.js +30 -0
  74. package/dist/aivss/metrics/ad.js.map +1 -0
  75. package/dist/aivss/metrics/cs.d.ts +3 -0
  76. package/dist/aivss/metrics/cs.d.ts.map +1 -0
  77. package/dist/aivss/metrics/cs.js +50 -0
  78. package/dist/aivss/metrics/cs.js.map +1 -0
  79. package/dist/aivss/metrics/dc.d.ts +3 -0
  80. package/dist/aivss/metrics/dc.d.ts.map +1 -0
  81. package/dist/aivss/metrics/dc.js +30 -0
  82. package/dist/aivss/metrics/dc.js.map +1 -0
  83. package/dist/aivss/metrics/ds.d.ts +3 -0
  84. package/dist/aivss/metrics/ds.d.ts.map +1 -0
  85. package/dist/aivss/metrics/ds.js +26 -0
  86. package/dist/aivss/metrics/ds.js.map +1 -0
  87. package/dist/aivss/metrics/ei.d.ts +3 -0
  88. package/dist/aivss/metrics/ei.d.ts.map +1 -0
  89. package/dist/aivss/metrics/ei.js +30 -0
  90. package/dist/aivss/metrics/ei.js.map +1 -0
  91. package/dist/aivss/metrics/gv.d.ts +3 -0
  92. package/dist/aivss/metrics/gv.d.ts.map +1 -0
  93. package/dist/aivss/metrics/gv.js +34 -0
  94. package/dist/aivss/metrics/gv.js.map +1 -0
  95. package/dist/aivss/metrics/ll.d.ts +3 -0
  96. package/dist/aivss/metrics/ll.d.ts.map +1 -0
  97. package/dist/aivss/metrics/ll.js +30 -0
  98. package/dist/aivss/metrics/ll.js.map +1 -0
  99. package/dist/aivss/metrics/mr.d.ts +3 -0
  100. package/dist/aivss/metrics/mr.d.ts.map +1 -0
  101. package/dist/aivss/metrics/mr.js +26 -0
  102. package/dist/aivss/metrics/mr.js.map +1 -0
  103. package/dist/aivss/metrics/shared.d.ts +22 -0
  104. package/dist/aivss/metrics/shared.d.ts.map +1 -0
  105. package/dist/aivss/metrics/shared.js +70 -0
  106. package/dist/aivss/metrics/shared.js.map +1 -0
  107. package/dist/aivss/prompts/base-system-prompt.d.ts +2 -0
  108. package/dist/aivss/prompts/base-system-prompt.d.ts.map +1 -0
  109. package/dist/aivss/prompts/base-system-prompt.js +31 -0
  110. package/dist/aivss/prompts/base-system-prompt.js.map +1 -0
  111. package/dist/aivss/prompts/prompt-composer.d.ts +13 -0
  112. package/dist/aivss/prompts/prompt-composer.d.ts.map +1 -0
  113. package/dist/aivss/prompts/prompt-composer.js +21 -0
  114. package/dist/aivss/prompts/prompt-composer.js.map +1 -0
  115. package/dist/aivss/scoring/a2a-corpus.test.d.ts +28 -0
  116. package/dist/aivss/scoring/a2a-corpus.test.d.ts.map +1 -0
  117. package/dist/aivss/scoring/a2a-corpus.test.js +109 -0
  118. package/dist/aivss/scoring/a2a-corpus.test.js.map +1 -0
  119. package/dist/aivss/scoring/determinism.test.d.ts +16 -0
  120. package/dist/aivss/scoring/determinism.test.d.ts.map +1 -0
  121. package/dist/aivss/scoring/determinism.test.js +169 -0
  122. package/dist/aivss/scoring/determinism.test.js.map +1 -0
  123. package/dist/aivss/scoring/heuristic-scorer.d.ts +21 -0
  124. package/dist/aivss/scoring/heuristic-scorer.d.ts.map +1 -0
  125. package/dist/aivss/scoring/heuristic-scorer.js +299 -0
  126. package/dist/aivss/scoring/heuristic-scorer.js.map +1 -0
  127. package/dist/aivss/scoring/heuristic-scorer.test.d.ts +8 -0
  128. package/dist/aivss/scoring/heuristic-scorer.test.d.ts.map +1 -0
  129. package/dist/aivss/scoring/heuristic-scorer.test.js +150 -0
  130. package/dist/aivss/scoring/heuristic-scorer.test.js.map +1 -0
  131. package/dist/aivss/scoring/scoring-mode.d.ts +48 -0
  132. package/dist/aivss/scoring/scoring-mode.d.ts.map +1 -0
  133. package/dist/aivss/scoring/scoring-mode.js +64 -0
  134. package/dist/aivss/scoring/scoring-mode.js.map +1 -0
  135. package/dist/aivss/scoring/v4-engine.d.ts +15 -0
  136. package/dist/aivss/scoring/v4-engine.d.ts.map +1 -0
  137. package/dist/aivss/scoring/v4-engine.js +84 -0
  138. package/dist/aivss/scoring/v4-engine.js.map +1 -0
  139. package/dist/aivss/scoring/v4-engine.test.d.ts +16 -0
  140. package/dist/aivss/scoring/v4-engine.test.d.ts.map +1 -0
  141. package/dist/aivss/scoring/v4-engine.test.js +156 -0
  142. package/dist/aivss/scoring/v4-engine.test.js.map +1 -0
  143. package/dist/aivss/types.d.ts +92 -0
  144. package/dist/aivss/types.d.ts.map +1 -0
  145. package/dist/aivss/types.js +25 -0
  146. package/dist/aivss/types.js.map +1 -0
  147. package/dist/baseline/baseline.test.d.ts +2 -0
  148. package/dist/baseline/baseline.test.d.ts.map +1 -0
  149. package/dist/baseline/baseline.test.js +219 -0
  150. package/dist/baseline/baseline.test.js.map +1 -0
  151. package/dist/baseline/diff.d.ts +42 -0
  152. package/dist/baseline/diff.d.ts.map +1 -0
  153. package/dist/baseline/diff.js +124 -0
  154. package/dist/baseline/diff.js.map +1 -0
  155. package/dist/baseline/store.d.ts +51 -0
  156. package/dist/baseline/store.d.ts.map +1 -0
  157. package/dist/baseline/store.js +92 -0
  158. package/dist/baseline/store.js.map +1 -0
  159. package/dist/batch/anthropic-batch-runner.d.ts +50 -0
  160. package/dist/batch/anthropic-batch-runner.d.ts.map +1 -0
  161. package/dist/batch/anthropic-batch-runner.js +91 -0
  162. package/dist/batch/anthropic-batch-runner.js.map +1 -0
  163. package/dist/batch/bedrock-batch-runner.d.ts +90 -0
  164. package/dist/batch/bedrock-batch-runner.d.ts.map +1 -0
  165. package/dist/batch/bedrock-batch-runner.js +199 -0
  166. package/dist/batch/bedrock-batch-runner.js.map +1 -0
  167. package/dist/batch/providers/anthropic.d.ts +55 -0
  168. package/dist/batch/providers/anthropic.d.ts.map +1 -0
  169. package/dist/batch/providers/anthropic.js +103 -0
  170. package/dist/batch/providers/anthropic.js.map +1 -0
  171. package/dist/batch/providers/bedrock.d.ts +31 -0
  172. package/dist/batch/providers/bedrock.d.ts.map +1 -0
  173. package/dist/batch/providers/bedrock.js +42 -0
  174. package/dist/batch/providers/bedrock.js.map +1 -0
  175. package/dist/batch/providers/harness.d.ts +36 -0
  176. package/dist/batch/providers/harness.d.ts.map +1 -0
  177. package/dist/batch/providers/harness.js +65 -0
  178. package/dist/batch/providers/harness.js.map +1 -0
  179. package/dist/batch/providers/harness.test.d.ts +7 -0
  180. package/dist/batch/providers/harness.test.d.ts.map +1 -0
  181. package/dist/batch/providers/harness.test.js +84 -0
  182. package/dist/batch/providers/harness.test.js.map +1 -0
  183. package/dist/batch/providers/index.d.ts +82 -0
  184. package/dist/batch/providers/index.d.ts.map +1 -0
  185. package/dist/batch/providers/index.js +82 -0
  186. package/dist/batch/providers/index.js.map +1 -0
  187. package/dist/batch/providers/ollama.d.ts +68 -0
  188. package/dist/batch/providers/ollama.d.ts.map +1 -0
  189. package/dist/batch/providers/ollama.js +108 -0
  190. package/dist/batch/providers/ollama.js.map +1 -0
  191. package/dist/batch/response-parser.d.ts +45 -0
  192. package/dist/batch/response-parser.d.ts.map +1 -0
  193. package/dist/batch/response-parser.js +161 -0
  194. package/dist/batch/response-parser.js.map +1 -0
  195. package/dist/batch/types.d.ts +87 -0
  196. package/dist/batch/types.d.ts.map +1 -0
  197. package/dist/batch/types.js +8 -0
  198. package/dist/batch/types.js.map +1 -0
  199. package/dist/cli.d.ts +15 -0
  200. package/dist/cli.d.ts.map +1 -0
  201. package/dist/cli.js +1037 -0
  202. package/dist/cli.js.map +1 -0
  203. package/dist/examples/a2a-assessment.d.ts +20 -0
  204. package/dist/examples/a2a-assessment.d.ts.map +1 -0
  205. package/dist/examples/a2a-assessment.js +115 -0
  206. package/dist/examples/a2a-assessment.js.map +1 -0
  207. package/dist/examples/batch-assessment.d.ts +18 -0
  208. package/dist/examples/batch-assessment.d.ts.map +1 -0
  209. package/dist/examples/batch-assessment.js +112 -0
  210. package/dist/examples/batch-assessment.js.map +1 -0
  211. package/dist/examples/batch-submission-flow.d.ts +2 -0
  212. package/dist/examples/batch-submission-flow.d.ts.map +1 -0
  213. package/dist/examples/batch-submission-flow.js +279 -0
  214. package/dist/examples/batch-submission-flow.js.map +1 -0
  215. package/dist/examples/demo-agent-definition.json +58 -0
  216. package/dist/examples/langfuse-assessment.d.ts +2 -0
  217. package/dist/examples/langfuse-assessment.d.ts.map +1 -0
  218. package/dist/examples/langfuse-assessment.js +46 -0
  219. package/dist/examples/langfuse-assessment.js.map +1 -0
  220. package/dist/examples/model-eval.d.ts +25 -0
  221. package/dist/examples/model-eval.d.ts.map +1 -0
  222. package/dist/examples/model-eval.js +94 -0
  223. package/dist/examples/model-eval.js.map +1 -0
  224. package/dist/examples/openclaw-assessment.d.ts +17 -0
  225. package/dist/examples/openclaw-assessment.d.ts.map +1 -0
  226. package/dist/examples/openclaw-assessment.js +79 -0
  227. package/dist/examples/openclaw-assessment.js.map +1 -0
  228. package/dist/examples/simple-assessment.d.ts +2 -0
  229. package/dist/examples/simple-assessment.d.ts.map +1 -0
  230. package/dist/examples/simple-assessment.js +146 -0
  231. package/dist/examples/simple-assessment.js.map +1 -0
  232. package/dist/examples/threat-model-demo.d.ts +2 -0
  233. package/dist/examples/threat-model-demo.d.ts.map +1 -0
  234. package/dist/examples/threat-model-demo.js +103 -0
  235. package/dist/examples/threat-model-demo.js.map +1 -0
  236. package/dist/index.d.ts +60 -0
  237. package/dist/index.d.ts.map +1 -0
  238. package/dist/index.js +155 -0
  239. package/dist/index.js.map +1 -0
  240. package/dist/output/likec4-generator.d.ts +43 -0
  241. package/dist/output/likec4-generator.d.ts.map +1 -0
  242. package/dist/output/likec4-generator.js +287 -0
  243. package/dist/output/likec4-generator.js.map +1 -0
  244. package/dist/output/slot-filler.d.ts +6 -0
  245. package/dist/output/slot-filler.d.ts.map +1 -0
  246. package/dist/output/slot-filler.js +71 -0
  247. package/dist/output/slot-filler.js.map +1 -0
  248. package/dist/output/tc-assembler.d.ts +30 -0
  249. package/dist/output/tc-assembler.d.ts.map +1 -0
  250. package/dist/output/tc-assembler.js +227 -0
  251. package/dist/output/tc-assembler.js.map +1 -0
  252. package/dist/output/tc-types.d.ts +41 -0
  253. package/dist/output/tc-types.d.ts.map +1 -0
  254. package/dist/output/tc-types.js +5 -0
  255. package/dist/output/tc-types.js.map +1 -0
  256. package/dist/output/tc-validator.test.d.ts +9 -0
  257. package/dist/output/tc-validator.test.d.ts.map +1 -0
  258. package/dist/output/tc-validator.test.js +194 -0
  259. package/dist/output/tc-validator.test.js.map +1 -0
  260. package/dist/providers/anthropic.d.ts +9 -0
  261. package/dist/providers/anthropic.d.ts.map +1 -0
  262. package/dist/providers/anthropic.js +30 -0
  263. package/dist/providers/anthropic.js.map +1 -0
  264. package/dist/providers/bedrock.d.ts +9 -0
  265. package/dist/providers/bedrock.d.ts.map +1 -0
  266. package/dist/providers/bedrock.js +38 -0
  267. package/dist/providers/bedrock.js.map +1 -0
  268. package/dist/providers/index.d.ts +6 -0
  269. package/dist/providers/index.d.ts.map +1 -0
  270. package/dist/providers/index.js +14 -0
  271. package/dist/providers/index.js.map +1 -0
  272. package/dist/providers/types.d.ts +12 -0
  273. package/dist/providers/types.d.ts.map +1 -0
  274. package/dist/providers/types.js +5 -0
  275. package/dist/providers/types.js.map +1 -0
  276. package/dist/references/acsc-risks.d.ts +18 -0
  277. package/dist/references/acsc-risks.d.ts.map +1 -0
  278. package/dist/references/acsc-risks.js +232 -0
  279. package/dist/references/acsc-risks.js.map +1 -0
  280. package/dist/references/aicm.d.ts +41 -0
  281. package/dist/references/aicm.d.ts.map +1 -0
  282. package/dist/references/aicm.js +447 -0
  283. package/dist/references/aicm.js.map +1 -0
  284. package/dist/references/dstg-meaid.d.ts +59 -0
  285. package/dist/references/dstg-meaid.d.ts.map +1 -0
  286. package/dist/references/dstg-meaid.js +352 -0
  287. package/dist/references/dstg-meaid.js.map +1 -0
  288. package/dist/references/index.d.ts +20 -0
  289. package/dist/references/index.d.ts.map +1 -0
  290. package/dist/references/index.js +31 -0
  291. package/dist/references/index.js.map +1 -0
  292. package/dist/references/nemoclaw.d.ts +48 -0
  293. package/dist/references/nemoclaw.d.ts.map +1 -0
  294. package/dist/references/nemoclaw.js +140 -0
  295. package/dist/references/nemoclaw.js.map +1 -0
  296. package/dist/references/nist-ai-rmf.d.ts +31 -0
  297. package/dist/references/nist-ai-rmf.d.ts.map +1 -0
  298. package/dist/references/nist-ai-rmf.js +627 -0
  299. package/dist/references/nist-ai-rmf.js.map +1 -0
  300. package/dist/references/owasp-agentic-top10.d.ts +50 -0
  301. package/dist/references/owasp-agentic-top10.d.ts.map +1 -0
  302. package/dist/references/owasp-agentic-top10.js +202 -0
  303. package/dist/references/owasp-agentic-top10.js.map +1 -0
  304. package/dist/references/registry-parity.test.d.ts +17 -0
  305. package/dist/references/registry-parity.test.d.ts.map +1 -0
  306. package/dist/references/registry-parity.test.js +87 -0
  307. package/dist/references/registry-parity.test.js.map +1 -0
  308. package/dist/references/registry.d.ts +90 -0
  309. package/dist/references/registry.d.ts.map +1 -0
  310. package/dist/references/registry.js +29 -0
  311. package/dist/references/registry.js.map +1 -0
  312. package/dist/tools/model-eval.d.ts +97 -0
  313. package/dist/tools/model-eval.d.ts.map +1 -0
  314. package/dist/tools/model-eval.js +307 -0
  315. package/dist/tools/model-eval.js.map +1 -0
  316. package/package.json +105 -0
  317. package/schemas/threat-composer-v1.schema.json +966 -0
  318. package/vendor/atlas-release/ATLAS-2026.07.yaml +17877 -0
  319. package/vendor/atlas-release/README.md +41 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Waratah Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,323 @@
1
+ # Canopy
2
+
3
+ **Threat model your agentic AI systems. No API key required.**
4
+
5
+ Canopy scores an agent system against [OWASP AIVSS V4](https://aivss.owasp.org), maps every finding to [MITRE ATLAS](https://atlas.mitre.org) adversary techniques, annotates it against six risk frameworks, and writes an [AWS Threat Composer](https://github.com/awslabs/threat-composer) `.tc.json` you can open, edit, and hand to your security team.
6
+
7
+ It runs offline, deterministically, with no credentials — so you can try it on your own system in about a minute and get a number you can actually defend.
8
+
9
+ ```bash
10
+ npm install -g @waratahlabs/canopy
11
+ ```
12
+
13
+ Or run it without installing:
14
+
15
+ ```bash
16
+ npx @waratahlabs/canopy schema
17
+ ```
18
+
19
+ ---
20
+
21
+ ## Getting started
22
+
23
+ ### 1. Get the input shape
24
+
25
+ ```bash
26
+ npx @waratahlabs/canopy schema > canopy-schema.json
27
+ ```
28
+
29
+ This prints the `AgentDefinition` JSON schema plus a worked example. One entry per agent or autonomous process in your system.
30
+
31
+ ### 2. Describe your system
32
+
33
+ Create `my-agents.json`. Describe what your agent actually is — what model, what tools, what it's allowed to touch:
34
+
35
+ ```json
36
+ {
37
+ "applicationName": "Sales Data Pipeline",
38
+ "agents": [
39
+ {
40
+ "id": "reporting-agent-01",
41
+ "name": "reporting-agent",
42
+ "model": "claude-sonnet-4-6",
43
+ "systemPrompt": "Retrieve sales data via the reporting API. Fall back to direct DB query only if the API is unavailable.",
44
+ "tools": [
45
+ { "name": "call_reporting_api", "description": "Fetch sales data via the authorised HTTP API.", "dangerous": false },
46
+ { "name": "query_database", "description": "Execute SQL directly against the sales database.", "dangerous": true }
47
+ ],
48
+ "permissions": ["read:reporting_api", "read:postgres_salesdb", "write:audit_log"],
49
+ "deploymentContext": "FinancialServices",
50
+ "modelComplexity": "Simple",
51
+ "mitigationMultiplier": 1.0,
52
+ "finetuned": false,
53
+ "dependencies": ["reporting-api:8080", "postgres:5432"],
54
+ "secretManagement": "Environment variables, no rotation.",
55
+ "deployment": "Docker container",
56
+ "autonomyLevel": "semi-autonomous",
57
+ "objectives": ["Retrieve monthly sales data"],
58
+ "externalApiCount": 1
59
+ }
60
+ ],
61
+ "handoffs": []
62
+ }
63
+ ```
64
+
65
+ The fields that move the score most: `tools[].dangerous`, `permissions`, `autonomyLevel`, `deploymentContext`, and `secretManagement`. Be honest about them — an assessment of an idealised system tells you nothing.
66
+
67
+ ### 3. Assess it
68
+
69
+ ```bash
70
+ npx @waratahlabs/canopy assess --input my-agents.json --deterministic --out threat-model.tc.json
71
+ ```
72
+
73
+ ```
74
+ ✓ 35 threats · 29 mitigations → threat-model.tc.json
75
+ ```
76
+
77
+ No API key. No account. No network call. Open the result at [threat-composer.awslabs.dev](https://awslabs.github.io/threat-composer/).
78
+
79
+ ### 4. Gate it in CI
80
+
81
+ ```bash
82
+ canopy assess --input my-agents.json --deterministic --diff
83
+ ```
84
+
85
+ Saves a baseline and diffs against the previous run. **Exits non-zero when severities regress**, so a change that makes your agent riskier fails the build.
86
+
87
+ ---
88
+
89
+ ## Running inside a coding agent
90
+
91
+ Canopy can use the LLM you're already talking to as its inference engine — no API key, no subprocess, no extra model call.
92
+
93
+ ```bash
94
+ canopy assess --input my-agents.json --harness --out threat-model.tc.json
95
+ ```
96
+
97
+ The first run writes the assessment prompts to `canopy-batch-requests.json` and exits with instructions. Your coding agent (Claude Code, Cursor, or anything driving a shell) reads that file, answers each prompt with its own reasoning, writes `canopy-batch-responses.json`, and you re-run. Two runs, one round trip, zero network calls Canopy has to authenticate.
98
+
99
+ `SKILL.md` in this package is a ready-made skill file for that workflow — point your agent at it.
100
+
101
+ ---
102
+
103
+ ## Scoring modes — know where your number came from
104
+
105
+ A score you cannot reproduce is not evidence. Canopy always records which mode produced a finding, stamped on every threat as `scoring-mode` and in the artifact's audit trail.
106
+
107
+ | Mode | Flag | Reproducible | Credentials | Use it for |
108
+ |---|---|---|---|---|
109
+ | **Deterministic** | `--deterministic` | **Yes** — byte-identical across runs and machines | None | CI gating, audit trails, anything you have to defend |
110
+ | **Harness** | `--harness` | No — depends on the driving model | None | Exploring a new system interactively |
111
+ | **Model** | *(default with `ANTHROPIC_API_KEY`)* | No — varies with model version | Provider key | Richer reasoning on threat prose |
112
+
113
+ Deterministic mode is a pure function of the agent definition. Every rule is readable in [`src/aivss/scoring/heuristic-scorer.ts`](src/aivss/scoring/heuristic-scorer.ts) — you can trace any severity back to the condition that produced it, which is the property CVSS vectors and OpenSSF Scorecard checks earn their trust from.
114
+
115
+ Changing emitted scores is treated as a breaking change requiring a major version bump. Your baselines stay meaningful.
116
+
117
+ ---
118
+
119
+ ## Registered frameworks
120
+
121
+ Assess once, map many — one assessment engine, findings annotated against every registered framework:
122
+
123
+ | Framework | Risks | Type |
124
+ |---|---|---|
125
+ | ASD/ACSC — Careful Adoption of Agentic AI Services (Five Eyes, 2025) | 15 | security |
126
+ | CSA AI Controls Matrix (AICM) | 32 | compliance |
127
+ | DSTG — A Method for Ethical AI in Defence (MEAID) | 21 | ethical / compliance |
128
+ | NIST AI Risk Management Framework 1.0 | 52 | compliance |
129
+ | OWASP Top 10 for Agentic Applications 2026 | 10 | security |
130
+ | NeMo Claw — Security Wrapper for OpenClaw | 5 | security |
131
+
132
+ Adding a framework is one file plus one registration line — see [CONTRIBUTING.md](CONTRIBUTING.md). This table is asserted against the live registry by `src/references/registry-parity.test.ts`: a framework advertised here but not registered fails the build.
133
+
134
+ ---
135
+
136
+ ## What you get
137
+
138
+ Every threat in the `.tc.json` carries:
139
+
140
+ - **Threat Composer slots** — `threatSource`, `prerequisites`, `threatAction`, `threatImpact`, `impactedGoal[]`, `impactedAssets[]`, `statement`
141
+ - **AIVSS metadata** — metric code (MR/DS/EI/DC/AD/AA/LL/GV/CS), sub-category, severity, score
142
+ - **ATLAS metadata** — technique ID (e.g. `AML.T0051`), technique name, tactic
143
+ - **Framework annotations** — risk ID, category, and risk type from each registered framework
144
+ - **Provenance** — `scoring-mode`, deployment context, and version stamps for Canopy, AIVSS, and both ATLAS version fields
145
+
146
+ Agent-to-agent handoffs are surfaced as first-class threats (`AML.T0080.000` — implicit trust grants), because the trust boundary between two agents is where the interesting failures live.
147
+
148
+ ---
149
+
150
+ ## Library usage
151
+
152
+ ### Assess agent definitions
153
+
154
+ ```typescript
155
+ import { assessWorkflow } from "@waratahlabs/canopy";
156
+ import type { AgentDefinition } from "@waratahlabs/canopy";
157
+
158
+ const agents: AgentDefinition[] = [
159
+ {
160
+ id: "agent-001",
161
+ name: "Mortgage Assistant",
162
+ model: "claude-sonnet-4-6",
163
+ systemPrompt: "You are a mortgage application assistant...",
164
+ tools: [
165
+ { name: "retrieve_document", description: "Fetch a stored document by ID", dangerous: false },
166
+ { name: "credit_check", description: "Query credit bureau API", dangerous: true },
167
+ ],
168
+ permissions: ["read:applications", "write:notes"],
169
+ deploymentContext: "FinancialServices",
170
+ modelComplexity: "Moderate",
171
+ mitigationMultiplier: 1.1,
172
+ finetuned: false,
173
+ dependencies: ["document-store", "credit-api"],
174
+ secretManagement: "AWS Secrets Manager",
175
+ deployment: "AWS ECS Fargate",
176
+ },
177
+ ];
178
+
179
+ const tcFormat = await assessWorkflow({
180
+ input: { type: "agents", agents },
181
+ applicationName: "Mortgage Platform",
182
+ });
183
+ ```
184
+
185
+ ### Input adapters
186
+
187
+ Canopy can derive `AgentDefinition[]` from systems you already run:
188
+
189
+ ```typescript
190
+ // N8N workflow export
191
+ await assessWorkflow({ input: { type: "n8n", workflow }, applicationName: "My Workflow" });
192
+
193
+ // A2A agent cards — fetches /.well-known/agent.json and walks the delegation graph
194
+ import { walkA2AGraph } from "@waratahlabs/canopy";
195
+ const { agents, handoffs } = await walkA2AGraph({ urls: ["https://agent.example.com"], maxHops: 2 });
196
+
197
+ // Live OpenClaw install — reads ~/.openclaw/openclaw.json and workspace/skills/
198
+ import { parseOpenClawConfig } from "@waratahlabs/canopy";
199
+ const { agents, handoffs, undeclaredSkills } = parseOpenClawConfig();
200
+ ```
201
+
202
+ Where a system declares less than it can do, Canopy names the gap rather than papering over it — `undeclaredSkills` and `UNDECLARED_CAPABILITY_RISK` exist because a declared tool schema is not the same as actual behaviour.
203
+
204
+ ### Langfuse traces
205
+
206
+ Traces don't carry system prompts, tool declarations, or permissions, so you supply those through a config overlay — a YAML file mapping agent name patterns to the fields traces can't provide.
207
+
208
+ ```typescript
209
+ import { assessWorkflow, parseLangfuseTraces, loadOverlaysFromYaml } from "@waratahlabs/canopy";
210
+
211
+ const overlays = loadOverlaysFromYaml("./langfuse-overlay.yaml");
212
+ const { agents, handoffs } = await parseLangfuseTraces(
213
+ {
214
+ host: process.env.LANGFUSE_HOST!,
215
+ secretKey: process.env.LANGFUSE_SECRET_KEY!,
216
+ publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
217
+ limit: 100,
218
+ },
219
+ overlays,
220
+ );
221
+ ```
222
+
223
+ Trace metadata only — no prompt or completion content leaves your environment. No Langfuse SDK required; the adapter uses `fetch` with HTTP Basic auth.
224
+
225
+ ---
226
+
227
+ ## Model-inferred severity
228
+
229
+ For richer threat prose, wire in a `BatchProvider`. Note this trades reproducibility for reasoning — the artifact will be stamped `scoring-mode: model`.
230
+
231
+ ```typescript
232
+ import { assessWorkflow, createBatchProvider } from "@waratahlabs/canopy";
233
+
234
+ // Anthropic Messages Batches
235
+ await assessWorkflow({
236
+ input: { type: "agents", agents },
237
+ batchProvider: createBatchProvider({ type: "anthropic", model: "claude-haiku-4-5-20251001" }),
238
+ });
239
+
240
+ // Amazon Bedrock Batch Inference
241
+ await assessWorkflow({
242
+ input: { type: "agents", agents },
243
+ batchProvider: createBatchProvider({
244
+ type: "bedrock",
245
+ region: "us-east-1",
246
+ s3InputUri: "s3://my-bucket/canopy-input/",
247
+ s3OutputUri: "s3://my-bucket/canopy-output/",
248
+ }),
249
+ });
250
+
251
+ // Ollama — local or cloud
252
+ await assessWorkflow({
253
+ input: { type: "agents", agents },
254
+ batchProvider: createBatchProvider({ type: "ollama", model: "llama3.2" }),
255
+ });
256
+ ```
257
+
258
+ Custom backends implement one interface:
259
+
260
+ ```typescript
261
+ import type { BatchProvider } from "@waratahlabs/canopy";
262
+
263
+ const myProvider: BatchProvider = {
264
+ name: "my-provider",
265
+ async runBatch(agents, options) {
266
+ // return MetricAssessmentResponse[]
267
+ },
268
+ };
269
+ ```
270
+
271
+ **Choosing a local model:** `runModelEval()` runs several Ollama models over the same agent set and reports parse success rate, finding coverage by metric, pairwise agreement, and a written verdict — worth doing before committing to a full batch run.
272
+
273
+ ---
274
+
275
+ ## CLI reference
276
+
277
+ ```
278
+ canopy assess [options]
279
+ --input <file> Input JSON (default: stdin)
280
+ --out <file> Output .tc.json (default: stdout)
281
+ --deterministic Heuristic scorer — reproducible, no credentials
282
+ --harness Let the calling LLM agent answer the assessment prompts
283
+ --diagram Also write a LikeC4 architecture diagram
284
+ --save Save a baseline snapshot
285
+ --diff Save and diff against the previous run; exit 1 on regressions
286
+
287
+ canopy a2a-assess Walk an A2A delegation graph and assess it
288
+ canopy schema Print the AgentDefinition input schema
289
+ canopy diff Compare the two most recent baselines
290
+ canopy batch-submit Submit a provider batch job for model-inferred severity
291
+ canopy batch-fetch Collect a completed batch job into a .tc.json
292
+ canopy demo Serve the interactive threat model explorer
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Standards and sources
298
+
299
+ **OWASP AIVSS v0.8** — scoring methodology: 9 AI-specific metrics, 39 sub-categories, the V4 formula, and 7 deployment-context weight profiles. [aivss.owasp.org](https://aivss.owasp.org)
300
+
301
+ **MITRE ATLAS™** (format-6.0.0, content 2026.07) — 16 tactics, 178 technique-level items, 37 mitigations, 68 case studies. ATLAS techniques are injected into metric prompts as test specifications, so each threat is grounded in a documented attack pattern rather than asserted. MITRE ships monthly calendar-versioned content releases decoupled from rarer schema bumps; Canopy tracks both fields separately and pins deliberately. [atlas.mitre.org](https://atlas.mitre.org)
302
+
303
+ **ASD/ACSC — Careful adoption of agentic AI services** (2025) — joint guidance from ASD/ACSC, CISA, NSA, Cyber Centre (CA), NCSC-NZ, and NCSC-UK. Five risk families cross-referenced to AIVSS metrics and ATLAS techniques. [cyber.gov.au](https://www.cyber.gov.au/business-government/secure-design/artificial-intelligence/careful-adoption-of-agentic-ai-services)
304
+
305
+ **CSA AI Controls Matrix (AICM) v1.1.1** — Canopy maps the 31 controls CSA tags "AI-Specific" (agent boundaries, sandboxing, data poisoning, model hardening, explainability, human oversight); the remaining "Cloud & AI Related" controls are general cloud hygiene outside this adapter's scope. [cloudsecurityalliance.org](https://cloudsecurityalliance.org/artifacts/ai-controls-matrix)
306
+
307
+ **DSTG — A Method for Ethical AI in Defence (MEAID)** — ethical and compliance risk that the CIA triad does not capture. Staff using AI outside its sanctioned purpose is not a confidentiality breach, but it is a real risk; MEAID surfaces that class. [dst.defence.gov.au](https://www.dst.defence.gov.au/publication/ethical-ai)
308
+
309
+ **AWS Threat Composer** — the output format. `.tc.json` opens directly for collaborative modelling. [github.com/awslabs/threat-composer](https://github.com/awslabs/threat-composer)
310
+
311
+ **LikeC4** — `--diagram` emits an architecture model alongside the threat model: agents, tools, data stores, handoff relationships, dangerous tools highlighted. [likec4.dev](https://likec4.dev)
312
+
313
+ ---
314
+
315
+ ## Contributing
316
+
317
+ Framework adapters are the contribution most wanted — one file plus one registration line. See [CONTRIBUTING.md](CONTRIBUTING.md) for the `FrameworkAdapter` contract, the conventions, and the score-stability policy.
318
+
319
+ Security issues: please use private disclosure rather than a public issue — see [SECURITY.md](SECURITY.md).
320
+
321
+ ## License
322
+
323
+ MIT — Waratah Labs
package/SKILL.md ADDED
@@ -0,0 +1,97 @@
1
+ # Canopy — AI Threat Modelling Skill
2
+
3
+ Use this skill to generate a multi-framework threat model for any agentic AI system in the current codebase. Produces a `.tc.json` file openable in AWS Threat Composer and a LikeC4 architecture diagram.
4
+
5
+ ## When to invoke
6
+
7
+ - User asks to "threat model", "assess", or "generate a security assessment" for agents in the codebase
8
+ - A new agent, tool, or handoff is added to the system
9
+ - Preparing for a security review, compliance audit, or workshop
10
+ - CI pipeline needs a threat model artifact
11
+
12
+ ## How to invoke
13
+
14
+ ### Step 1 — get the input schema
15
+
16
+ ```bash
17
+ bunx @waratahlabs/canopy schema
18
+ ```
19
+
20
+ This prints the `AgentDefinition` JSON schema and a complete example. Read it before constructing input.
21
+
22
+ ### Step 2 — read the codebase and construct input JSON
23
+
24
+ Read the agent source files (system prompts, tool definitions, environment config, docker-compose or k8s manifests for secrets/deployment context). Construct a `canopy-input.json` matching the schema:
25
+
26
+ ```json
27
+ {
28
+ "applicationName": "My System",
29
+ "agents": [ ...AgentDefinition[] ],
30
+ "handoffs": [ ...HandoffEdge[] ]
31
+ }
32
+ ```
33
+
34
+ **Key fields to get right:**
35
+ - `tools[].dangerous` — mark any tool that can exfiltrate data, execute SQL/shell, write files, or call external APIs as `true`. This drives the AIVSS MR/AA/DC metrics.
36
+ - `secretManagement` — be specific. "env vars, no rotation" scores differently from "Vault, 24h TTL".
37
+ - `deploymentContext` — use `FinancialServices` for fintech/banking, `Healthcare` for health data, `General` for everything else. Drives AIVSS weight profiles.
38
+ - `mitigationMultiplier` — start at `1.0` (no mitigations). Reduce toward `0.5` only if guardrails, prompt shields, or tool-call validation are demonstrably deployed.
39
+ - `handoffs` — every agent-to-agent message passing edge is a potential context-injection surface. Include all of them.
40
+
41
+ ### Step 3 — run the assessment
42
+
43
+ ```bash
44
+ bunx @waratahlabs/canopy assess \
45
+ --input canopy-input.json \
46
+ --deterministic \
47
+ --diagram \
48
+ --out threat-model.tc.json
49
+ ```
50
+
51
+ `--deterministic` skips a separate LLM API call — the calling agent (you) is the intelligence. The AIVSS scoring and ATLAS technique mapping are deterministic; only the threat statement prose uses stub fills. The structural threat model is complete and accurate regardless.
52
+
53
+ ### Step 4 — augment with your own reasoning (optional but recommended)
54
+
55
+ Read the generated `threat-model.tc.json` alongside the reference examples in `demo/data/`:
56
+
57
+ ```
58
+ demo/data/openclaw-demo.tc.json — personal AI assistant threat model
59
+ demo/data/openclaw-nemoclaw-demo.tc.json — sandboxed vs baseline comparison
60
+ ```
61
+
62
+ Use these as few-shot references to understand threat statement quality and depth. Then augment the generated output with your own analysis:
63
+
64
+ - **Slot-fill prose** — replace stub `threatSource` / `threatAction` / `threatImpact` fields with context-specific language derived from reading the actual agent code (system prompt wording, tool descriptions, deployment topology)
65
+ - **Additional threats** — reason about threats the AIVSS/ATLAS engine doesn't surface: business logic abuse, data exfiltration paths specific to this system's data model, trust boundary violations between services you observed in the codebase
66
+ - **MEAID ethical findings** — for agents with `EI` or `GV` metric findings, articulate the specific ethical risk in terms of this system: who is affected, what accountability gap exists, whether BAU misappropriation is plausible given the agent's permissions
67
+ - **Severity uplift** — if you have strong evidence a finding should be Critical or High (e.g. a `dangerous: true` tool with no guardrails handling PII), note it; the mock severity is Medium across the board
68
+
69
+ When adding threats, match the existing TC schema shape exactly — copy a threat entry from the output and modify it. The `id` field must be a fresh UUID.
70
+
71
+ ### Step 5 — report findings
72
+
73
+ After running, read the output and summarise:
74
+ - Total threats by severity (Critical / High / Medium / Low)
75
+ - Top 3 ATLAS techniques by frequency
76
+ - Any `dangerous: true` tools and their associated MR/AA findings
77
+ - MEAID ethical/compliance findings on `EI` and `GV` metrics (audience: legal/ethics teams)
78
+ - Handoff threats (AML.T0080.000) — one per agent-to-agent edge
79
+
80
+ Tell the user where the files were written and how to open them:
81
+ ```
82
+ Threat Composer: open threat-model.tc.json at https://awslabs.github.io/threat-composer
83
+ Architecture: npx likec4 serve <diagram>.c4
84
+ ```
85
+
86
+ ## What Canopy produces
87
+
88
+ Each threat is annotated with:
89
+ - `aivss-metric` + `aivss-score` — OWASP AIVSS V4 scoring
90
+ - `atlas-technique-id` — MITRE ATLAS adversary TTP
91
+ - `acsc-risk-id` — ASD/ACSC Five Eyes agentic AI risk category
92
+ - `dstg-meaid-risk-id` — DSTG MEAID ethical/compliance risk (where applicable)
93
+ - `agent-name`, `deployment-context`, `priority`
94
+
95
+ ## Adding frameworks
96
+
97
+ New risk frameworks are added by contributing to `src/references/` — one file per framework implementing `FrameworkAdapter`, registered in `src/references/index.ts`. No changes to the CLI or assembler required.