@intutic/cli 1.9.0 → 1.10.1

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 (357) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.js +868 -30
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/attenuate.d.ts +39 -0
  5. package/dist/commands/attenuate.d.ts.map +1 -0
  6. package/dist/commands/attenuate.js +98 -0
  7. package/dist/commands/attenuate.js.map +1 -0
  8. package/dist/commands/budget.d.ts +80 -0
  9. package/dist/commands/budget.d.ts.map +1 -1
  10. package/dist/commands/budget.js +119 -3
  11. package/dist/commands/budget.js.map +1 -1
  12. package/dist/commands/connect.d.ts +10 -0
  13. package/dist/commands/connect.d.ts.map +1 -1
  14. package/dist/commands/connect.js +358 -48
  15. package/dist/commands/connect.js.map +1 -1
  16. package/dist/commands/credentials.d.ts +31 -0
  17. package/dist/commands/credentials.d.ts.map +1 -0
  18. package/dist/commands/credentials.js +134 -0
  19. package/dist/commands/credentials.js.map +1 -0
  20. package/dist/commands/decision.d.ts +37 -0
  21. package/dist/commands/decision.d.ts.map +1 -0
  22. package/dist/commands/decision.js +56 -0
  23. package/dist/commands/decision.js.map +1 -0
  24. package/dist/commands/doctor.d.ts +38 -1
  25. package/dist/commands/doctor.d.ts.map +1 -1
  26. package/dist/commands/doctor.js +228 -18
  27. package/dist/commands/doctor.js.map +1 -1
  28. package/dist/commands/enforce.d.ts +33 -0
  29. package/dist/commands/enforce.d.ts.map +1 -0
  30. package/dist/commands/enforce.js +150 -0
  31. package/dist/commands/enforce.js.map +1 -0
  32. package/dist/commands/enterprise.d.ts +29 -0
  33. package/dist/commands/enterprise.d.ts.map +1 -0
  34. package/dist/commands/enterprise.js +141 -0
  35. package/dist/commands/enterprise.js.map +1 -0
  36. package/dist/commands/env.d.ts +7 -0
  37. package/dist/commands/env.d.ts.map +1 -0
  38. package/dist/commands/env.js +55 -0
  39. package/dist/commands/env.js.map +1 -0
  40. package/dist/commands/exec.d.ts +38 -2
  41. package/dist/commands/exec.d.ts.map +1 -1
  42. package/dist/commands/exec.js +247 -10
  43. package/dist/commands/exec.js.map +1 -1
  44. package/dist/commands/findings.d.ts +84 -0
  45. package/dist/commands/findings.d.ts.map +1 -0
  46. package/dist/commands/findings.js +329 -0
  47. package/dist/commands/findings.js.map +1 -0
  48. package/dist/commands/gateway.d.ts +62 -0
  49. package/dist/commands/gateway.d.ts.map +1 -0
  50. package/dist/commands/gateway.js +298 -0
  51. package/dist/commands/gateway.js.map +1 -0
  52. package/dist/commands/guardrails.d.ts +81 -0
  53. package/dist/commands/guardrails.d.ts.map +1 -0
  54. package/dist/commands/guardrails.js +735 -0
  55. package/dist/commands/guardrails.js.map +1 -0
  56. package/dist/commands/init.d.ts +8 -0
  57. package/dist/commands/init.d.ts.map +1 -1
  58. package/dist/commands/init.js +14 -2
  59. package/dist/commands/init.js.map +1 -1
  60. package/dist/commands/install-daemon.d.ts +70 -3
  61. package/dist/commands/install-daemon.d.ts.map +1 -1
  62. package/dist/commands/install-daemon.js +482 -47
  63. package/dist/commands/install-daemon.js.map +1 -1
  64. package/dist/commands/integrity.d.ts +205 -0
  65. package/dist/commands/integrity.d.ts.map +1 -0
  66. package/dist/commands/integrity.js +620 -0
  67. package/dist/commands/integrity.js.map +1 -0
  68. package/dist/commands/judge.d.ts +31 -0
  69. package/dist/commands/judge.d.ts.map +1 -0
  70. package/dist/commands/judge.js +118 -0
  71. package/dist/commands/judge.js.map +1 -0
  72. package/dist/commands/org.d.ts +31 -0
  73. package/dist/commands/org.d.ts.map +1 -0
  74. package/dist/commands/org.js +159 -0
  75. package/dist/commands/org.js.map +1 -0
  76. package/dist/commands/policy.d.ts +138 -4
  77. package/dist/commands/policy.d.ts.map +1 -1
  78. package/dist/commands/policy.js +538 -97
  79. package/dist/commands/policy.js.map +1 -1
  80. package/dist/commands/predict-cost.d.ts +45 -0
  81. package/dist/commands/predict-cost.d.ts.map +1 -0
  82. package/dist/commands/predict-cost.js +123 -0
  83. package/dist/commands/predict-cost.js.map +1 -0
  84. package/dist/commands/rollback.d.ts +5 -0
  85. package/dist/commands/rollback.d.ts.map +1 -0
  86. package/dist/commands/rollback.js +142 -0
  87. package/dist/commands/rollback.js.map +1 -0
  88. package/dist/commands/routing.d.ts +62 -0
  89. package/dist/commands/routing.d.ts.map +1 -0
  90. package/dist/commands/routing.js +121 -0
  91. package/dist/commands/routing.js.map +1 -0
  92. package/dist/commands/setup.d.ts +62 -0
  93. package/dist/commands/setup.d.ts.map +1 -0
  94. package/dist/commands/setup.js +238 -0
  95. package/dist/commands/setup.js.map +1 -0
  96. package/dist/commands/skill.d.ts +268 -1
  97. package/dist/commands/skill.d.ts.map +1 -1
  98. package/dist/commands/skill.js +744 -39
  99. package/dist/commands/skill.js.map +1 -1
  100. package/dist/commands/sops.d.ts +95 -0
  101. package/dist/commands/sops.d.ts.map +1 -1
  102. package/dist/commands/sops.js +334 -34
  103. package/dist/commands/sops.js.map +1 -1
  104. package/dist/commands/start.d.ts.map +1 -1
  105. package/dist/commands/start.js +1 -18
  106. package/dist/commands/start.js.map +1 -1
  107. package/dist/commands/status.d.ts.map +1 -1
  108. package/dist/commands/status.js +44 -1
  109. package/dist/commands/status.js.map +1 -1
  110. package/dist/commands/team.d.ts +38 -0
  111. package/dist/commands/team.d.ts.map +1 -0
  112. package/dist/commands/team.js +140 -0
  113. package/dist/commands/team.js.map +1 -0
  114. package/dist/commands/traces.d.ts +8 -1
  115. package/dist/commands/traces.d.ts.map +1 -1
  116. package/dist/commands/traces.js +114 -15
  117. package/dist/commands/traces.js.map +1 -1
  118. package/dist/commands/whoami.d.ts.map +1 -1
  119. package/dist/commands/whoami.js +2 -1
  120. package/dist/commands/whoami.js.map +1 -1
  121. package/dist/config/keychain.d.ts +10 -2
  122. package/dist/config/keychain.d.ts.map +1 -1
  123. package/dist/config/keychain.js +83 -14
  124. package/dist/config/keychain.js.map +1 -1
  125. package/dist/config/paths.d.ts +27 -0
  126. package/dist/config/paths.d.ts.map +1 -1
  127. package/dist/config/paths.js +37 -6
  128. package/dist/config/paths.js.map +1 -1
  129. package/dist/config/store.d.ts.map +1 -1
  130. package/dist/config/store.js +19 -3
  131. package/dist/config/store.js.map +1 -1
  132. package/dist/harness/ag2.d.ts +22 -0
  133. package/dist/harness/ag2.d.ts.map +1 -0
  134. package/dist/harness/ag2.js +34 -0
  135. package/dist/harness/ag2.js.map +1 -0
  136. package/dist/harness/agentcore.d.ts +55 -0
  137. package/dist/harness/agentcore.d.ts.map +1 -0
  138. package/dist/harness/agentcore.js +119 -0
  139. package/dist/harness/agentcore.js.map +1 -0
  140. package/dist/harness/agenticOrchestrator.d.ts +52 -0
  141. package/dist/harness/agenticOrchestrator.d.ts.map +1 -0
  142. package/dist/harness/agenticOrchestrator.js +115 -0
  143. package/dist/harness/agenticOrchestrator.js.map +1 -0
  144. package/dist/harness/aiSdkHarness.d.ts +30 -0
  145. package/dist/harness/aiSdkHarness.d.ts.map +1 -0
  146. package/dist/harness/aiSdkHarness.js +51 -0
  147. package/dist/harness/aiSdkHarness.js.map +1 -0
  148. package/dist/harness/aiSdkWorkflow.d.ts +26 -0
  149. package/dist/harness/aiSdkWorkflow.d.ts.map +1 -0
  150. package/dist/harness/aiSdkWorkflow.js +39 -0
  151. package/dist/harness/aiSdkWorkflow.js.map +1 -0
  152. package/dist/harness/autogen.d.ts +24 -0
  153. package/dist/harness/autogen.d.ts.map +1 -0
  154. package/dist/harness/autogen.js +36 -0
  155. package/dist/harness/autogen.js.map +1 -0
  156. package/dist/harness/base.js.map +1 -1
  157. package/dist/harness/continue.d.ts.map +1 -1
  158. package/dist/harness/continue.js +2 -1
  159. package/dist/harness/continue.js.map +1 -1
  160. package/dist/harness/crewai.d.ts +15 -0
  161. package/dist/harness/crewai.d.ts.map +1 -0
  162. package/dist/harness/crewai.js +26 -0
  163. package/dist/harness/crewai.js.map +1 -0
  164. package/dist/harness/detector.d.ts +1 -1
  165. package/dist/harness/detector.d.ts.map +1 -1
  166. package/dist/harness/detector.js +47 -1
  167. package/dist/harness/detector.js.map +1 -1
  168. package/dist/harness/dsh.d.ts +19 -0
  169. package/dist/harness/dsh.d.ts.map +1 -0
  170. package/dist/harness/dsh.js +93 -0
  171. package/dist/harness/dsh.js.map +1 -0
  172. package/dist/harness/eve.d.ts +40 -0
  173. package/dist/harness/eve.d.ts.map +1 -0
  174. package/dist/harness/eve.js +67 -0
  175. package/dist/harness/eve.js.map +1 -0
  176. package/dist/harness/googleAdk.d.ts +18 -0
  177. package/dist/harness/googleAdk.d.ts.map +1 -0
  178. package/dist/harness/googleAdk.js +29 -0
  179. package/dist/harness/googleAdk.js.map +1 -0
  180. package/dist/harness/goose.d.ts.map +1 -1
  181. package/dist/harness/goose.js +5 -1
  182. package/dist/harness/goose.js.map +1 -1
  183. package/dist/harness/grok.d.ts +16 -0
  184. package/dist/harness/grok.d.ts.map +1 -0
  185. package/dist/harness/grok.js +78 -0
  186. package/dist/harness/grok.js.map +1 -0
  187. package/dist/harness/jsSdkGatedAdapter.d.ts +102 -0
  188. package/dist/harness/jsSdkGatedAdapter.d.ts.map +1 -0
  189. package/dist/harness/jsSdkGatedAdapter.js +139 -0
  190. package/dist/harness/jsSdkGatedAdapter.js.map +1 -0
  191. package/dist/harness/langchain.d.ts +22 -0
  192. package/dist/harness/langchain.d.ts.map +1 -0
  193. package/dist/harness/langchain.js +33 -0
  194. package/dist/harness/langchain.js.map +1 -0
  195. package/dist/harness/langgraph.d.ts +22 -0
  196. package/dist/harness/langgraph.d.ts.map +1 -0
  197. package/dist/harness/langgraph.js +80 -0
  198. package/dist/harness/langgraph.js.map +1 -0
  199. package/dist/harness/mastra.d.ts +21 -0
  200. package/dist/harness/mastra.d.ts.map +1 -0
  201. package/dist/harness/mastra.js +33 -0
  202. package/dist/harness/mastra.js.map +1 -0
  203. package/dist/harness/muse.d.ts +22 -0
  204. package/dist/harness/muse.d.ts.map +1 -0
  205. package/dist/harness/muse.js +92 -0
  206. package/dist/harness/muse.js.map +1 -0
  207. package/dist/harness/n8n.d.ts.map +1 -1
  208. package/dist/harness/n8n.js +36 -11
  209. package/dist/harness/n8n.js.map +1 -1
  210. package/dist/harness/openaiAgents.d.ts +40 -0
  211. package/dist/harness/openaiAgents.d.ts.map +1 -0
  212. package/dist/harness/openaiAgents.js +107 -0
  213. package/dist/harness/openaiAgents.js.map +1 -0
  214. package/dist/harness/opencode.d.ts +24 -0
  215. package/dist/harness/opencode.d.ts.map +1 -0
  216. package/dist/harness/opencode.js +97 -0
  217. package/dist/harness/opencode.js.map +1 -0
  218. package/dist/harness/pydanticAi.d.ts +19 -0
  219. package/dist/harness/pydanticAi.d.ts.map +1 -0
  220. package/dist/harness/pydanticAi.js +30 -0
  221. package/dist/harness/pydanticAi.js.map +1 -0
  222. package/dist/harness/sdkGatedAdapter.d.ts +55 -0
  223. package/dist/harness/sdkGatedAdapter.d.ts.map +1 -0
  224. package/dist/harness/sdkGatedAdapter.js +85 -0
  225. package/dist/harness/sdkGatedAdapter.js.map +1 -0
  226. package/dist/harness/smolagents.d.ts +22 -0
  227. package/dist/harness/smolagents.d.ts.map +1 -0
  228. package/dist/harness/smolagents.js +33 -0
  229. package/dist/harness/smolagents.js.map +1 -0
  230. package/dist/harness/strands.d.ts +22 -0
  231. package/dist/harness/strands.d.ts.map +1 -0
  232. package/dist/harness/strands.js +35 -0
  233. package/dist/harness/strands.js.map +1 -0
  234. package/dist/harness/trueforge.d.ts +25 -0
  235. package/dist/harness/trueforge.d.ts.map +1 -0
  236. package/dist/harness/trueforge.js +40 -0
  237. package/dist/harness/trueforge.js.map +1 -0
  238. package/dist/harness/types.d.ts.map +1 -1
  239. package/dist/harness/types.js +70 -0
  240. package/dist/harness/types.js.map +1 -1
  241. package/dist/harness/vercelAiSdk.d.ts +31 -0
  242. package/dist/harness/vercelAiSdk.d.ts.map +1 -0
  243. package/dist/harness/vercelAiSdk.js +44 -0
  244. package/dist/harness/vercelAiSdk.js.map +1 -0
  245. package/dist/harness/xirp.d.ts +43 -0
  246. package/dist/harness/xirp.d.ts.map +1 -0
  247. package/dist/harness/xirp.js +95 -0
  248. package/dist/harness/xirp.js.map +1 -0
  249. package/dist/lib/api.d.ts +68 -0
  250. package/dist/lib/api.d.ts.map +1 -1
  251. package/dist/lib/api.js +108 -67
  252. package/dist/lib/api.js.map +1 -1
  253. package/dist/lib/authMessages.d.ts +19 -0
  254. package/dist/lib/authMessages.d.ts.map +1 -0
  255. package/dist/lib/authMessages.js +20 -0
  256. package/dist/lib/authMessages.js.map +1 -0
  257. package/dist/lib/binaryChecksum.d.ts +12 -0
  258. package/dist/lib/binaryChecksum.d.ts.map +1 -0
  259. package/dist/lib/binaryChecksum.js +45 -0
  260. package/dist/lib/binaryChecksum.js.map +1 -0
  261. package/dist/lib/binaryOnPath.d.ts +24 -0
  262. package/dist/lib/binaryOnPath.d.ts.map +1 -0
  263. package/dist/lib/binaryOnPath.js +31 -0
  264. package/dist/lib/binaryOnPath.js.map +1 -0
  265. package/dist/lib/caTrust.d.ts +69 -0
  266. package/dist/lib/caTrust.d.ts.map +1 -0
  267. package/dist/lib/caTrust.js +169 -0
  268. package/dist/lib/caTrust.js.map +1 -0
  269. package/dist/lib/ciscoScanner.d.ts +178 -0
  270. package/dist/lib/ciscoScanner.d.ts.map +1 -0
  271. package/dist/lib/ciscoScanner.js +292 -0
  272. package/dist/lib/ciscoScanner.js.map +1 -0
  273. package/dist/lib/decisionsLogRefresh.d.ts +28 -0
  274. package/dist/lib/decisionsLogRefresh.d.ts.map +1 -0
  275. package/dist/lib/decisionsLogRefresh.js +54 -0
  276. package/dist/lib/decisionsLogRefresh.js.map +1 -0
  277. package/dist/lib/deviceReport.d.ts +26 -0
  278. package/dist/lib/deviceReport.d.ts.map +1 -0
  279. package/dist/lib/deviceReport.js +55 -0
  280. package/dist/lib/deviceReport.js.map +1 -0
  281. package/dist/lib/elevation.d.ts +58 -0
  282. package/dist/lib/elevation.d.ts.map +1 -0
  283. package/dist/lib/elevation.js +83 -0
  284. package/dist/lib/elevation.js.map +1 -0
  285. package/dist/lib/enforcementState.d.ts +69 -0
  286. package/dist/lib/enforcementState.d.ts.map +1 -0
  287. package/dist/lib/enforcementState.js +113 -0
  288. package/dist/lib/enforcementState.js.map +1 -0
  289. package/dist/lib/ensureValkey.d.ts.map +1 -1
  290. package/dist/lib/ensureValkey.js +2 -2
  291. package/dist/lib/ensureValkey.js.map +1 -1
  292. package/dist/lib/envInjector.d.ts.map +1 -1
  293. package/dist/lib/envInjector.js +22 -4
  294. package/dist/lib/envInjector.js.map +1 -1
  295. package/dist/lib/gitHooks.d.ts +7 -2
  296. package/dist/lib/gitHooks.d.ts.map +1 -1
  297. package/dist/lib/gitHooks.js +180 -13
  298. package/dist/lib/gitHooks.js.map +1 -1
  299. package/dist/lib/gracefulShutdown.d.ts +37 -0
  300. package/dist/lib/gracefulShutdown.d.ts.map +1 -0
  301. package/dist/lib/gracefulShutdown.js +57 -0
  302. package/dist/lib/gracefulShutdown.js.map +1 -0
  303. package/dist/lib/graphIdentity.d.ts +80 -0
  304. package/dist/lib/graphIdentity.d.ts.map +1 -0
  305. package/dist/lib/graphIdentity.js +120 -0
  306. package/dist/lib/graphIdentity.js.map +1 -0
  307. package/dist/lib/localTraces.d.ts +61 -0
  308. package/dist/lib/localTraces.d.ts.map +1 -0
  309. package/dist/lib/localTraces.js +173 -0
  310. package/dist/lib/localTraces.js.map +1 -0
  311. package/dist/lib/mdmManifest.d.ts +73 -0
  312. package/dist/lib/mdmManifest.d.ts.map +1 -0
  313. package/dist/lib/mdmManifest.js +190 -0
  314. package/dist/lib/mdmManifest.js.map +1 -0
  315. package/dist/lib/onboarding.d.ts.map +1 -1
  316. package/dist/lib/onboarding.js +60 -1
  317. package/dist/lib/onboarding.js.map +1 -1
  318. package/dist/lib/otelPropagation.d.ts +26 -0
  319. package/dist/lib/otelPropagation.d.ts.map +1 -0
  320. package/dist/lib/otelPropagation.js +40 -0
  321. package/dist/lib/otelPropagation.js.map +1 -0
  322. package/dist/lib/policySnapshot.d.ts +92 -0
  323. package/dist/lib/policySnapshot.d.ts.map +1 -0
  324. package/dist/lib/policySnapshot.js +173 -0
  325. package/dist/lib/policySnapshot.js.map +1 -0
  326. package/dist/lib/process.d.ts.map +1 -1
  327. package/dist/lib/process.js +60 -0
  328. package/dist/lib/process.js.map +1 -1
  329. package/dist/lib/providerProbe.d.ts +28 -0
  330. package/dist/lib/providerProbe.d.ts.map +1 -0
  331. package/dist/lib/providerProbe.js +57 -0
  332. package/dist/lib/providerProbe.js.map +1 -0
  333. package/dist/lib/proxyBinary.d.ts +19 -0
  334. package/dist/lib/proxyBinary.d.ts.map +1 -0
  335. package/dist/lib/proxyBinary.js +30 -0
  336. package/dist/lib/proxyBinary.js.map +1 -0
  337. package/dist/lib/sandbox/firecracker.d.ts +89 -0
  338. package/dist/lib/sandbox/firecracker.d.ts.map +1 -0
  339. package/dist/lib/sandbox/firecracker.js +135 -0
  340. package/dist/lib/sandbox/firecracker.js.map +1 -0
  341. package/dist/lib/sandbox/index.d.ts +34 -0
  342. package/dist/lib/sandbox/index.d.ts.map +1 -0
  343. package/dist/lib/sandbox/index.js +54 -0
  344. package/dist/lib/sandbox/index.js.map +1 -0
  345. package/dist/lib/sandbox/oci.d.ts +38 -0
  346. package/dist/lib/sandbox/oci.d.ts.map +1 -0
  347. package/dist/lib/sandbox/oci.js +108 -0
  348. package/dist/lib/sandbox/oci.js.map +1 -0
  349. package/dist/lib/sandbox/types.d.ts +48 -0
  350. package/dist/lib/sandbox/types.d.ts.map +1 -0
  351. package/dist/lib/sandbox/types.js +12 -0
  352. package/dist/lib/sandbox/types.js.map +1 -0
  353. package/dist/lib/sopFrontMatter.d.ts +50 -0
  354. package/dist/lib/sopFrontMatter.d.ts.map +1 -0
  355. package/dist/lib/sopFrontMatter.js +129 -0
  356. package/dist/lib/sopFrontMatter.js.map +1 -0
  357. package/package.json +11 -6
@@ -0,0 +1,169 @@
1
+ /**
2
+ * OS trust-store injection for the Intutic proxy CA certificate.
3
+ *
4
+ * Two trust scopes:
5
+ * - `'user'` — per-user, non-elevated. Already shipping today via
6
+ * `commands/connect.ts` (macOS login keychain, Windows `certutil`), run
7
+ * silently on every `intutic connect`.
8
+ * - `'system'` — machine-wide, requires root/admin. New here — this is the
9
+ * half `enterprise install` (`commands/enterprise.ts`) needs and the
10
+ * deleted `enterprise-install.ts` (commit `8481b5d9`) used to provide.
11
+ *
12
+ * `caTrustCommandFor` is exported specifically so `doctor.ts`'s remediation
13
+ * strings can be generated from the same source as what actually runs here,
14
+ * rather than hand-duplicated — which is exactly how they already drifted
15
+ * once (the check there looks in three Linux cert-anchor directories; the
16
+ * remediation only ever names one).
17
+ *
18
+ * @module
19
+ */
20
+ import { execFile } from 'node:child_process';
21
+ import { promisify } from 'node:util';
22
+ import { copyFile, readFile } from 'node:fs/promises';
23
+ const execFileAsync = promisify(execFile);
24
+ const LINUX_DEBIAN_DEST = '/usr/local/share/ca-certificates/intutic-ca.crt';
25
+ const LINUX_RHEL_DEST = '/etc/pki/ca-trust/source/anchors/intutic-ca.crt';
26
+ /**
27
+ * The command(s) that trust `caCertPath` at the given scope, for the given
28
+ * platform. Pure — no I/O — so it doubles as the source of truth for
29
+ * `doctor.ts`'s remediation text.
30
+ *
31
+ * Linux `'user'` scope returns `null`: there is no single per-user NSS/OS
32
+ * trust-store equivalent worth building (each browser/runtime keeps its
33
+ * own), unlike macOS (login keychain) and Windows (`certutil`, which is
34
+ * elevation-agnostic — the same command works either way).
35
+ *
36
+ * Linux returns TWO commands (copy, then update) rather than one, since
37
+ * `execFile` can't run a shell pipeline — callers must run both in order.
38
+ */
39
+ export function caTrustCommandFor(platform, scope, caCertPath) {
40
+ if (platform === 'darwin') {
41
+ const keychain = scope === 'system' ? '/Library/Keychains/System.keychain' : '~/Library/Keychains/login.keychain-db';
42
+ return [{
43
+ step: `Trust the CA cert in the macOS ${scope === 'system' ? 'System' : 'login'} keychain`,
44
+ cmd: 'security',
45
+ args: ['add-trusted-cert', '-d', '-r', 'trustRoot', '-k', keychain, caCertPath],
46
+ }];
47
+ }
48
+ if (platform === 'win32') {
49
+ return [{
50
+ step: 'Trust the CA cert in the Windows Root certificate store',
51
+ cmd: 'certutil',
52
+ args: ['-addstore', 'Root', caCertPath],
53
+ }];
54
+ }
55
+ if (platform === 'linux') {
56
+ if (scope === 'user')
57
+ return null;
58
+ // Debian/Ubuntu style is tried first by installCaTrust (most common);
59
+ // this function returns both possibilities so a caller (or doctor.ts)
60
+ // can describe either without probing which tool is actually present.
61
+ return [
62
+ { step: 'Copy the CA cert into the system trust anchor directory (Debian/Ubuntu)', cmd: 'cp', args: [caCertPath, LINUX_DEBIAN_DEST] },
63
+ { step: 'Rebuild the system CA bundle', cmd: 'update-ca-certificates', args: [] },
64
+ ];
65
+ }
66
+ return null;
67
+ }
68
+ async function commandExists(cmd) {
69
+ try {
70
+ await execFileAsync('which', [cmd]);
71
+ return true;
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ }
77
+ async function installLinuxSystemCaTrust(caCertPath) {
78
+ // Debian/Ubuntu is tried first (more common in practice); RHEL/Fedora's
79
+ // update-ca-trust is the fallback. Neither present -> fail loudly rather
80
+ // than silently doing nothing, matching this function's contract that a
81
+ // false `installed` always carries the real reason in `detail`.
82
+ if (await commandExists('update-ca-certificates')) {
83
+ await copyFile(caCertPath, LINUX_DEBIAN_DEST);
84
+ await execFileAsync('update-ca-certificates', []);
85
+ return { installed: true, scope: 'system', mechanism: 'update-ca-certificates', detail: `Installed to ${LINUX_DEBIAN_DEST}` };
86
+ }
87
+ if (await commandExists('update-ca-trust')) {
88
+ await copyFile(caCertPath, LINUX_RHEL_DEST);
89
+ await execFileAsync('update-ca-trust', ['extract']);
90
+ return { installed: true, scope: 'system', mechanism: 'update-ca-trust', detail: `Installed to ${LINUX_RHEL_DEST}` };
91
+ }
92
+ return {
93
+ installed: false,
94
+ scope: 'system',
95
+ mechanism: 'none',
96
+ detail: 'Neither update-ca-certificates (Debian/Ubuntu) nor update-ca-trust (RHEL/Fedora) is available on this system.',
97
+ };
98
+ }
99
+ /**
100
+ * Installs `caCertPath` into the OS trust store at `scope`.
101
+ *
102
+ * Uses `execFile` with array arguments throughout — never `execSync` with
103
+ * string interpolation, which `connect.ts`'s existing per-user calls use and
104
+ * which is unsafe if a path ever contained a shell metacharacter. Does not
105
+ * throw on a failed underlying command; surfaces it as `installed: false`
106
+ * with the OS error text in `detail`, so a caller (e.g. `enterprise install`)
107
+ * can report it and continue rather than crashing the whole run over one
108
+ * platform-specific step.
109
+ */
110
+ export async function installCaTrust(caCertPath, scope) {
111
+ const platform = process.platform;
112
+ if (platform === 'linux' && scope === 'system') {
113
+ try {
114
+ return await installLinuxSystemCaTrust(caCertPath);
115
+ }
116
+ catch (err) {
117
+ return { installed: false, scope, mechanism: 'linux', detail: err instanceof Error ? err.message : String(err) };
118
+ }
119
+ }
120
+ const commands = caTrustCommandFor(platform, scope, caCertPath);
121
+ if (!commands) {
122
+ return {
123
+ installed: false,
124
+ scope,
125
+ mechanism: 'none',
126
+ detail: `No ${scope}-scope CA trust mechanism is implemented for ${platform}.`,
127
+ };
128
+ }
129
+ try {
130
+ for (const c of commands) {
131
+ await execFileAsync(c.cmd, c.args);
132
+ }
133
+ const mechanism = platform === 'darwin' ? 'security' : platform === 'win32' ? 'certutil' : commands[commands.length - 1].cmd;
134
+ return { installed: true, scope, mechanism, detail: `Trusted via ${mechanism}` };
135
+ }
136
+ catch (err) {
137
+ return { installed: false, scope, mechanism: platform, detail: err instanceof Error ? err.message : String(err) };
138
+ }
139
+ }
140
+ /**
141
+ * Best-effort check for whether `caCertPath` is already trusted — read-only,
142
+ * never installs anything. Used to skip a redundant (and log-noisy)
143
+ * re-install. Only implemented where a cheap, real check exists (macOS
144
+ * `security verify-cert`); returns `false` elsewhere rather than guessing,
145
+ * so a caller falls through to attempting installation, which is itself
146
+ * idempotent.
147
+ */
148
+ export async function verifyCaTrust(caCertPath) {
149
+ if (process.platform === 'darwin') {
150
+ try {
151
+ await execFileAsync('security', ['verify-cert', '-c', caCertPath]);
152
+ return true;
153
+ }
154
+ catch {
155
+ return false;
156
+ }
157
+ }
158
+ if (process.platform === 'linux') {
159
+ try {
160
+ const installed = await readFile(LINUX_DEBIAN_DEST, 'utf-8').catch(() => readFile(LINUX_RHEL_DEST, 'utf-8'));
161
+ return installed.length > 0;
162
+ }
163
+ catch {
164
+ return false;
165
+ }
166
+ }
167
+ return false;
168
+ }
169
+ //# sourceMappingURL=caTrust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caTrust.js","sourceRoot":"","sources":["../../src/lib/caTrust.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Cisco `skill-scanner` integration — OPTIONAL, opt-in shell-out to
3
+ * `cisco-ai-defense/skill-scanner`, a Cisco AI Defense open-source CLI that
4
+ * does static YARA/pattern detection, Python bytecode integrity checks,
5
+ * command-pipeline taint analysis, and (with `--use-behavioral`) full
6
+ * AST/dataflow analysis of skill content — genuinely deeper than this
7
+ * codebase's own regex-genre scanning (`packages/shared-types/src/scriptScan.ts`,
8
+ * Phase S2). TD-356 (`docs/TECH_DEBT.md`) named this integration as the
9
+ * follow-up to that phase's deliberately-scoped pattern matching.
10
+ *
11
+ * # Why a shell-out, not a dependency
12
+ *
13
+ * `apps/docs/guide/skill-scanning.md` previously declined adopting a Python
14
+ * runtime dependency for this codebase — that decision stands. This module
15
+ * does not embed, vendor, or depend on `skill-scanner`; it shells out to it
16
+ * via `execFile` when the operator has separately installed it (`pipx
17
+ * install cisco-ai-skill-scanner`), and degrades gracefully — never throws,
18
+ * never silently passes — when it is absent. OUR runtime stays Python-free;
19
+ * the binary is entirely the operator's own installation.
20
+ *
21
+ * # CLI invocation shape — VERIFIED against the real published tool
22
+ *
23
+ * This integration was written against the actual Cisco tool: PyPI package
24
+ * `cisco-ai-skill-scanner` (installs a binary named `skill-scanner` on
25
+ * PATH — same binary name as a DIFFERENT, unrelated PyPI package also
26
+ * called `skill-scanner`; see the correction note below), installed via
27
+ * `pipx install cisco-ai-skill-scanner` and inspected with `--help` and by
28
+ * reading its installed source, not guessed from a "typical SARIF scanner"
29
+ * shape:
30
+ *
31
+ * skill-scanner scan <dir> --use-behavioral --format sarif --output-sarif <file>
32
+ *
33
+ * Load-bearing details confirmed from the installed 2.0.13 source
34
+ * (`skill_scanner/core/models.py`, `skill_scanner/cli/cli.py`) and by
35
+ * actually running the binary against test fixtures:
36
+ * - `skill_directory` is a POSITIONAL argument, not a `--path` flag, and
37
+ * takes exactly one directory — {@link runCiscoScan} therefore invokes
38
+ * the binary ONCE PER skill directory, exactly the shape this phase's
39
+ * caller (`commands/skill.ts`) already iterates in.
40
+ * - `static_analyzer`, `bytecode_analyzer`, and `pipeline_analyzer` run BY
41
+ * DEFAULT, no flag or API key required. `--use-behavioral` additionally
42
+ * enables `behavioral_analyzer` (AST + taint tracking) — still fully
43
+ * offline, no key — which is the analyzer this integration wants for the
44
+ * "genuinely deeper than regex" claim, so it is always passed.
45
+ * `--use-llm`, `--use-virustotal`, and `--use-aidefense` each require a
46
+ * separately-configured API key and are NEVER passed by this module —
47
+ * this integration only exercises skill-scanner's offline analyzers.
48
+ * - Each SARIF `result` carries `properties.category` (one of an 18-value
49
+ * enum — `prompt_injection`, `command_injection`, `data_exfiltration`,
50
+ * `unauthorized_tool_use`, `obfuscation`, `hardcoded_secrets`,
51
+ * `social_engineering`, `resource_abuse`, `policy_violation`, `malware`,
52
+ * `harmful_content`, `skill_discovery_abuse`, `transitive_trust_abuse`,
53
+ * `autonomy_abuse`, `tool_chaining_abuse`, `unicode_steganography`,
54
+ * `supply_chain_attack` — `skill_scanner/core/models.py`'s
55
+ * `ThreatCategory` enum) and `properties.severity` DIRECTLY, not encoded
56
+ * into `ruleId` — `ruleId` is a plain identifier like
57
+ * `PIPELINE_TAINT_FLOW`, not `skill-scanner/<category>`. `mapCiscoCategory`
58
+ * in `commands/skill.ts` maps from this real taxonomy, not a guess.
59
+ * - `artifactLocation.uri` is RELATIVE to the scanned directory (e.g.
60
+ * `"SKILL.md"`, with `uriBaseId: "%SRCROOT%"` signalling exactly that) —
61
+ * NOT absolute, confirmed by actually running the binary. {@link
62
+ * scanOneDir} joins it against `dir` before returning it, honoring this
63
+ * module's own `CiscoScanFinding.filePath` contract ("ABSOLUTE").
64
+ * - A `--fail-on-severity`/`--fail-on-findings` threshold crossing still
65
+ * exits non-zero WHILE writing a valid SARIF file — confirmed
66
+ * empirically — so {@link scanOneDir} always attempts to read the output
67
+ * file first and only reports `ok: false` when that file is absent or
68
+ * unparseable.
69
+ *
70
+ * # Correction: an earlier version of this integration shelled out to the
71
+ * # WRONG package
72
+ *
73
+ * `skill-scanner` is claimed on PyPI's generic namespace by an unrelated,
74
+ * unaffiliated project (`thedevappsecguy/skill-scanner`, MIT-licensed, no
75
+ * Cisco affiliation) that requires an LLM or VirusTotal API key to do
76
+ * anything at all — it has no offline analysis path. `pipx install
77
+ * skill-scanner` installs THAT package, not Cisco's. The real Cisco tool
78
+ * publishes under `cisco-ai-skill-scanner` on PyPI
79
+ * (github.com/cisco-ai-defense/skill-scanner, Apache 2.0, Cisco Systems
80
+ * Inc.) — install it with `pipx install cisco-ai-skill-scanner`. Once
81
+ * installed, its binary is ALSO named `skill-scanner` on PATH, so no other
82
+ * part of this integration (binary-name detection, doctor check) needed to
83
+ * change — only the install instructions and this module's invocation
84
+ * shape/category taxonomy, which were verified against the wrong package.
85
+ *
86
+ * @module
87
+ */
88
+ /** The binary name this integration shells out to. Matches the doctor-check
89
+ * remediation (`pipx install cisco-ai-skill-scanner`) — the PyPI package
90
+ * name differs from the binary name it installs; see this module's doc
91
+ * comment. */
92
+ export declare const CISCO_SCANNER_BINARY = "skill-scanner";
93
+ /**
94
+ * Bounded timeout per scanned directory. Generous relative to every other
95
+ * shell-out in this codebase (`elevation.ts`'s `net session` probe: 3s;
96
+ * `process.ts`'s `ps`/`tasklist`: 5s) because `--use-behavioral` runs a
97
+ * full AST/dataflow pass, not a fast pattern match — 60s is a floor meant
98
+ * to catch a genuinely hung process, not a tight budget for a fast local
99
+ * check.
100
+ */
101
+ export declare const CISCO_SCAN_TIMEOUT_MS = 60000;
102
+ /** Resolves `true` iff the `skill-scanner` binary is present on PATH. */
103
+ export declare function ciscoScannerOnPath(): Promise<boolean>;
104
+ /**
105
+ * `skill-scanner --version`'s stdout, trimmed, or `null` if the binary is
106
+ * absent or the invocation itself fails. Used only by the doctor check —
107
+ * never assumed non-null by any caller that gates on {@link ciscoScannerOnPath}.
108
+ */
109
+ export declare function ciscoScannerVersion(): Promise<string | null>;
110
+ /** One parsed SARIF result from a `skill-scanner` run, flattened out of
111
+ * `runs[].results` for the internal finding-merge path. Bounded fields
112
+ * only — never the tool's full result object — matching this codebase's
113
+ * own findings' "never carry more than a caller needs" discipline. */
114
+ export interface CiscoScanFinding {
115
+ /** The tool's own `ruleId`, e.g. `PIPELINE_TAINT_FLOW`. Not itself a
116
+ * category — see {@link category}. */
117
+ ruleId: string;
118
+ level: string;
119
+ message: string;
120
+ /** The tool's own `properties.category` on this result, e.g.
121
+ * `command_injection` — one of the `ThreatCategory` enum values
122
+ * documented in this module's doc comment. Absent only for a
123
+ * malformed/unexpected result shape. */
124
+ category?: string;
125
+ /** SARIF `artifactLocation.uri` — the tool's own path, ABSOLUTE (whatever
126
+ * form `runCiscoScan`'s caller passed as the scanned directory), not yet
127
+ * relativized to a workspace root. */
128
+ filePath?: string;
129
+ line?: number;
130
+ }
131
+ /** Result of scanning ONE directory with `skill-scanner`. */
132
+ export interface CiscoDirScanResult {
133
+ /** The directory that was scanned — echoes the caller's input. */
134
+ dir: string;
135
+ /** `false` means this directory produced no usable result — binary
136
+ * absent, timed out, or exited without a parseable SARIF file. Refusal-
137
+ * not-pass: never treat `!ok` as "clean". */
138
+ ok: boolean;
139
+ /** Populated only when `!ok`. Human-readable — safe to log or surface to
140
+ * the user directly. */
141
+ error?: string;
142
+ /** The RAW SARIF `runs[]` entries this invocation produced, exactly as
143
+ * the tool emitted them — for verbatim passthrough into `--sarif` output.
144
+ * Usually zero or one entry per directory; never edited or re-shaped. */
145
+ sarifRuns: unknown[];
146
+ /** Findings flattened out of `sarifRuns[].results`, for the internal
147
+ * `SkillScanFinding` merge path (`commands/skill.ts`). */
148
+ findings: CiscoScanFinding[];
149
+ }
150
+ /**
151
+ * Scan each of `skillDirs` with `skill-scanner`, one invocation per
152
+ * directory (see this module's doc comment for why the tool takes exactly
153
+ * one directory per invocation). Directories are ABSOLUTE paths — callers
154
+ * resolve against the workspace root before calling, the same convention
155
+ * `oci.ts`/`firecracker.ts` use for the paths they hand external tools.
156
+ *
157
+ * Never throws: every failure mode (binary absent, timeout, unparseable
158
+ * output) is reported per-directory via `CiscoDirScanResult.ok`/`.error`,
159
+ * so one skill's scan failing does not abort the rest.
160
+ */
161
+ export declare function runCiscoScan(skillDirs: readonly string[]): Promise<CiscoDirScanResult[]>;
162
+ /**
163
+ * Combine the raw SARIF `runs[0]`-shaped objects from multiple
164
+ * `skill-scanner` invocations (one per scanned skill directory) into a
165
+ * SINGLE run, so `skill audit --sarif` appends Cisco's output as one
166
+ * additional entry in `runs[]`, not one per skill scanned — the multiple
167
+ * invocations are an artifact of this integration's own per-directory
168
+ * invocation strategy, not something the SARIF consumer should see.
169
+ *
170
+ * Only the CONTAINER is merged: rule catalogs are de-duplicated by `id`,
171
+ * results are concatenated. Every individual rule/result object is passed
172
+ * through unmodified — never rewritten — preserving the "append verbatim"
173
+ * contract this integration promises for `--sarif` output.
174
+ *
175
+ * Returns `null` when given no runs (nothing to append).
176
+ */
177
+ export declare function combineCiscoSarifRuns(runs: readonly unknown[]): unknown | null;
178
+ //# sourceMappingURL=ciscoScanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ciscoScanner.d.ts","sourceRoot":"","sources":["../../src/lib/ciscoScanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AAYH;;;eAGe;AACf,eAAO,MAAM,oBAAoB,kBAAkB,CAAA;AAEnD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAA;AAE3C,yEAAyE;AACzE,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CAErD;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQlE;AAED;;;uEAGuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B;2CACuC;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf;;;6CAGyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;2CAEuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,6DAA6D;AAC7D,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAA;IACX;;kDAE8C;IAC9C,EAAE,EAAE,OAAO,CAAA;IACX;6BACyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;8EAE0E;IAC1E,SAAS,EAAE,OAAO,EAAE,CAAA;IACpB;+DAC2D;IAC3D,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAkID;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAM9F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,GAAG,IAAI,CAyB9E"}
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Cisco `skill-scanner` integration — OPTIONAL, opt-in shell-out to
3
+ * `cisco-ai-defense/skill-scanner`, a Cisco AI Defense open-source CLI that
4
+ * does static YARA/pattern detection, Python bytecode integrity checks,
5
+ * command-pipeline taint analysis, and (with `--use-behavioral`) full
6
+ * AST/dataflow analysis of skill content — genuinely deeper than this
7
+ * codebase's own regex-genre scanning (`packages/shared-types/src/scriptScan.ts`,
8
+ * Phase S2). TD-356 (`docs/TECH_DEBT.md`) named this integration as the
9
+ * follow-up to that phase's deliberately-scoped pattern matching.
10
+ *
11
+ * # Why a shell-out, not a dependency
12
+ *
13
+ * `apps/docs/guide/skill-scanning.md` previously declined adopting a Python
14
+ * runtime dependency for this codebase — that decision stands. This module
15
+ * does not embed, vendor, or depend on `skill-scanner`; it shells out to it
16
+ * via `execFile` when the operator has separately installed it (`pipx
17
+ * install cisco-ai-skill-scanner`), and degrades gracefully — never throws,
18
+ * never silently passes — when it is absent. OUR runtime stays Python-free;
19
+ * the binary is entirely the operator's own installation.
20
+ *
21
+ * # CLI invocation shape — VERIFIED against the real published tool
22
+ *
23
+ * This integration was written against the actual Cisco tool: PyPI package
24
+ * `cisco-ai-skill-scanner` (installs a binary named `skill-scanner` on
25
+ * PATH — same binary name as a DIFFERENT, unrelated PyPI package also
26
+ * called `skill-scanner`; see the correction note below), installed via
27
+ * `pipx install cisco-ai-skill-scanner` and inspected with `--help` and by
28
+ * reading its installed source, not guessed from a "typical SARIF scanner"
29
+ * shape:
30
+ *
31
+ * skill-scanner scan <dir> --use-behavioral --format sarif --output-sarif <file>
32
+ *
33
+ * Load-bearing details confirmed from the installed 2.0.13 source
34
+ * (`skill_scanner/core/models.py`, `skill_scanner/cli/cli.py`) and by
35
+ * actually running the binary against test fixtures:
36
+ * - `skill_directory` is a POSITIONAL argument, not a `--path` flag, and
37
+ * takes exactly one directory — {@link runCiscoScan} therefore invokes
38
+ * the binary ONCE PER skill directory, exactly the shape this phase's
39
+ * caller (`commands/skill.ts`) already iterates in.
40
+ * - `static_analyzer`, `bytecode_analyzer`, and `pipeline_analyzer` run BY
41
+ * DEFAULT, no flag or API key required. `--use-behavioral` additionally
42
+ * enables `behavioral_analyzer` (AST + taint tracking) — still fully
43
+ * offline, no key — which is the analyzer this integration wants for the
44
+ * "genuinely deeper than regex" claim, so it is always passed.
45
+ * `--use-llm`, `--use-virustotal`, and `--use-aidefense` each require a
46
+ * separately-configured API key and are NEVER passed by this module —
47
+ * this integration only exercises skill-scanner's offline analyzers.
48
+ * - Each SARIF `result` carries `properties.category` (one of an 18-value
49
+ * enum — `prompt_injection`, `command_injection`, `data_exfiltration`,
50
+ * `unauthorized_tool_use`, `obfuscation`, `hardcoded_secrets`,
51
+ * `social_engineering`, `resource_abuse`, `policy_violation`, `malware`,
52
+ * `harmful_content`, `skill_discovery_abuse`, `transitive_trust_abuse`,
53
+ * `autonomy_abuse`, `tool_chaining_abuse`, `unicode_steganography`,
54
+ * `supply_chain_attack` — `skill_scanner/core/models.py`'s
55
+ * `ThreatCategory` enum) and `properties.severity` DIRECTLY, not encoded
56
+ * into `ruleId` — `ruleId` is a plain identifier like
57
+ * `PIPELINE_TAINT_FLOW`, not `skill-scanner/<category>`. `mapCiscoCategory`
58
+ * in `commands/skill.ts` maps from this real taxonomy, not a guess.
59
+ * - `artifactLocation.uri` is RELATIVE to the scanned directory (e.g.
60
+ * `"SKILL.md"`, with `uriBaseId: "%SRCROOT%"` signalling exactly that) —
61
+ * NOT absolute, confirmed by actually running the binary. {@link
62
+ * scanOneDir} joins it against `dir` before returning it, honoring this
63
+ * module's own `CiscoScanFinding.filePath` contract ("ABSOLUTE").
64
+ * - A `--fail-on-severity`/`--fail-on-findings` threshold crossing still
65
+ * exits non-zero WHILE writing a valid SARIF file — confirmed
66
+ * empirically — so {@link scanOneDir} always attempts to read the output
67
+ * file first and only reports `ok: false` when that file is absent or
68
+ * unparseable.
69
+ *
70
+ * # Correction: an earlier version of this integration shelled out to the
71
+ * # WRONG package
72
+ *
73
+ * `skill-scanner` is claimed on PyPI's generic namespace by an unrelated,
74
+ * unaffiliated project (`thedevappsecguy/skill-scanner`, MIT-licensed, no
75
+ * Cisco affiliation) that requires an LLM or VirusTotal API key to do
76
+ * anything at all — it has no offline analysis path. `pipx install
77
+ * skill-scanner` installs THAT package, not Cisco's. The real Cisco tool
78
+ * publishes under `cisco-ai-skill-scanner` on PyPI
79
+ * (github.com/cisco-ai-defense/skill-scanner, Apache 2.0, Cisco Systems
80
+ * Inc.) — install it with `pipx install cisco-ai-skill-scanner`. Once
81
+ * installed, its binary is ALSO named `skill-scanner` on PATH, so no other
82
+ * part of this integration (binary-name detection, doctor check) needed to
83
+ * change — only the install instructions and this module's invocation
84
+ * shape/category taxonomy, which were verified against the wrong package.
85
+ *
86
+ * @module
87
+ */
88
+ import { execFile } from 'node:child_process';
89
+ import { promisify } from 'node:util';
90
+ import * as fs from 'node:fs/promises';
91
+ import { tmpdir } from 'node:os';
92
+ import { isAbsolute, join } from 'node:path';
93
+ import { randomBytes } from 'node:crypto';
94
+ import { binaryOnPath } from './binaryOnPath.js';
95
+ const execFileAsync = promisify(execFile);
96
+ /** The binary name this integration shells out to. Matches the doctor-check
97
+ * remediation (`pipx install cisco-ai-skill-scanner`) — the PyPI package
98
+ * name differs from the binary name it installs; see this module's doc
99
+ * comment. */
100
+ export const CISCO_SCANNER_BINARY = 'skill-scanner';
101
+ /**
102
+ * Bounded timeout per scanned directory. Generous relative to every other
103
+ * shell-out in this codebase (`elevation.ts`'s `net session` probe: 3s;
104
+ * `process.ts`'s `ps`/`tasklist`: 5s) because `--use-behavioral` runs a
105
+ * full AST/dataflow pass, not a fast pattern match — 60s is a floor meant
106
+ * to catch a genuinely hung process, not a tight budget for a fast local
107
+ * check.
108
+ */
109
+ export const CISCO_SCAN_TIMEOUT_MS = 60_000;
110
+ /** Resolves `true` iff the `skill-scanner` binary is present on PATH. */
111
+ export function ciscoScannerOnPath() {
112
+ return binaryOnPath(CISCO_SCANNER_BINARY);
113
+ }
114
+ /**
115
+ * `skill-scanner --version`'s stdout, trimmed, or `null` if the binary is
116
+ * absent or the invocation itself fails. Used only by the doctor check —
117
+ * never assumed non-null by any caller that gates on {@link ciscoScannerOnPath}.
118
+ */
119
+ export async function ciscoScannerVersion() {
120
+ try {
121
+ const { stdout } = await execFileAsync(CISCO_SCANNER_BINARY, ['--version'], { timeout: 5_000 });
122
+ const trimmed = stdout.trim();
123
+ return trimmed.length > 0 ? trimmed : null;
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ }
129
+ function friendlyMissingBinaryError() {
130
+ return (`'${CISCO_SCANNER_BINARY}' not found on PATH. Install it with ` +
131
+ '`pipx install cisco-ai-skill-scanner`, or drop `--engine cisco` / ' +
132
+ "disable the 'ciscoSkillScannerEnabled' workspace setting to use native " +
133
+ 'scanning only.');
134
+ }
135
+ /**
136
+ * Scan ONE directory with `skill-scanner`, writing SARIF to a scratch file
137
+ * (`--output-sarif`) rather than parsing stdout — stdout carries a
138
+ * human-readable summary this integration never needs to parse, and the
139
+ * SARIF exporter writes plain JSON to the file regardless of `--format`
140
+ * also being requested for stdout.
141
+ *
142
+ * A non-zero exit is NOT immediately treated as failure: `--fail-on-*`
143
+ * deliberately exits non-zero when a finding crosses a severity threshold
144
+ * while still writing a valid SARIF file (verified empirically), so this
145
+ * function always attempts to read the output file first and only reports
146
+ * `ok: false` when that file is absent or unparseable.
147
+ */
148
+ async function scanOneDir(dir) {
149
+ const outFile = join(tmpdir(), `intutic-cisco-scan-${randomBytes(8).toString('hex')}.sarif.json`);
150
+ let execError;
151
+ try {
152
+ await execFileAsync(CISCO_SCANNER_BINARY, ['scan', dir, '--use-behavioral', '--format', 'sarif', '--output-sarif', outFile], { timeout: CISCO_SCAN_TIMEOUT_MS });
153
+ }
154
+ catch (err) {
155
+ const nodeErr = err;
156
+ if (nodeErr.code === 'ENOENT') {
157
+ return { dir, ok: false, sarifRuns: [], findings: [], error: friendlyMissingBinaryError() };
158
+ }
159
+ if (nodeErr.killed || nodeErr.signal) {
160
+ return {
161
+ dir,
162
+ ok: false,
163
+ sarifRuns: [],
164
+ findings: [],
165
+ error: `cisco skill-scanner timed out after ${CISCO_SCAN_TIMEOUT_MS}ms scanning ${dir}`,
166
+ };
167
+ }
168
+ // Any other non-zero exit — fall through and try the output file before
169
+ // giving up (see doc comment: --fail-on-* exits non-zero on real findings).
170
+ execError = nodeErr;
171
+ }
172
+ let raw;
173
+ try {
174
+ raw = await fs.readFile(outFile, 'utf8');
175
+ }
176
+ catch {
177
+ const stderrHint = execError?.stderr?.trim();
178
+ return {
179
+ dir,
180
+ ok: false,
181
+ sarifRuns: [],
182
+ findings: [],
183
+ error: `cisco skill-scanner produced no output scanning ${dir}` +
184
+ (stderrHint ? `: ${stderrHint}` : ' — the scan did not complete.'),
185
+ };
186
+ }
187
+ finally {
188
+ await fs.rm(outFile, { force: true });
189
+ }
190
+ let parsed;
191
+ try {
192
+ parsed = JSON.parse(raw);
193
+ }
194
+ catch {
195
+ return {
196
+ dir,
197
+ ok: false,
198
+ sarifRuns: [],
199
+ findings: [],
200
+ error: `cisco skill-scanner output for ${dir} was not valid JSON`,
201
+ };
202
+ }
203
+ const runs = Array.isArray(parsed.runs) ? parsed.runs : [];
204
+ const findings = [];
205
+ for (const run of runs) {
206
+ const results = run?.results;
207
+ if (!Array.isArray(results))
208
+ continue;
209
+ for (const result of results) {
210
+ const r = result;
211
+ const location = r.locations?.[0]?.physicalLocation;
212
+ const uri = typeof location?.artifactLocation?.uri === 'string' ? location.artifactLocation.uri : undefined;
213
+ // The tool's own URIs are RELATIVE to the scanned directory (verified
214
+ // empirically: `artifactLocation.uri` is `"SKILL.md"`, not an
215
+ // absolute path, with `uriBaseId: "%SRCROOT%"` signalling exactly
216
+ // that) — join against `dir` so this module's own contract
217
+ // ("filePath is ABSOLUTE") holds regardless of what the tool emits.
218
+ // Already-absolute URIs (a future tool version, or a result with no
219
+ // location at all) pass through unchanged.
220
+ const filePath = uri === undefined ? undefined : isAbsolute(uri) ? uri : join(dir, uri);
221
+ findings.push({
222
+ ruleId: typeof r.ruleId === 'string' ? r.ruleId : 'unknown',
223
+ level: typeof r.level === 'string' ? r.level : 'warning',
224
+ message: typeof r.message?.text === 'string' ? r.message.text : '',
225
+ category: typeof r.properties?.category === 'string' ? r.properties.category : undefined,
226
+ filePath,
227
+ line: typeof location?.region?.startLine === 'number' ? location.region.startLine : undefined,
228
+ });
229
+ }
230
+ }
231
+ return { dir, ok: true, sarifRuns: runs, findings };
232
+ }
233
+ /**
234
+ * Scan each of `skillDirs` with `skill-scanner`, one invocation per
235
+ * directory (see this module's doc comment for why the tool takes exactly
236
+ * one directory per invocation). Directories are ABSOLUTE paths — callers
237
+ * resolve against the workspace root before calling, the same convention
238
+ * `oci.ts`/`firecracker.ts` use for the paths they hand external tools.
239
+ *
240
+ * Never throws: every failure mode (binary absent, timeout, unparseable
241
+ * output) is reported per-directory via `CiscoDirScanResult.ok`/`.error`,
242
+ * so one skill's scan failing does not abort the rest.
243
+ */
244
+ export async function runCiscoScan(skillDirs) {
245
+ const results = [];
246
+ for (const dir of skillDirs) {
247
+ results.push(await scanOneDir(dir));
248
+ }
249
+ return results;
250
+ }
251
+ /**
252
+ * Combine the raw SARIF `runs[0]`-shaped objects from multiple
253
+ * `skill-scanner` invocations (one per scanned skill directory) into a
254
+ * SINGLE run, so `skill audit --sarif` appends Cisco's output as one
255
+ * additional entry in `runs[]`, not one per skill scanned — the multiple
256
+ * invocations are an artifact of this integration's own per-directory
257
+ * invocation strategy, not something the SARIF consumer should see.
258
+ *
259
+ * Only the CONTAINER is merged: rule catalogs are de-duplicated by `id`,
260
+ * results are concatenated. Every individual rule/result object is passed
261
+ * through unmodified — never rewritten — preserving the "append verbatim"
262
+ * contract this integration promises for `--sarif` output.
263
+ *
264
+ * Returns `null` when given no runs (nothing to append).
265
+ */
266
+ export function combineCiscoSarifRuns(runs) {
267
+ if (runs.length === 0)
268
+ return null;
269
+ const base = runs[0];
270
+ const rulesById = new Map();
271
+ const results = [];
272
+ for (const run of runs) {
273
+ const r = run;
274
+ for (const rule of r.tool?.driver?.rules ?? []) {
275
+ const id = rule?.id;
276
+ if (typeof id === 'string')
277
+ rulesById.set(id, rule);
278
+ }
279
+ if (Array.isArray(r.results))
280
+ results.push(...r.results);
281
+ }
282
+ return {
283
+ tool: {
284
+ driver: {
285
+ name: typeof base.tool?.driver?.name === 'string' ? base.tool.driver.name : CISCO_SCANNER_BINARY,
286
+ rules: [...rulesById.values()],
287
+ },
288
+ },
289
+ results,
290
+ };
291
+ }
292
+ //# sourceMappingURL=ciscoScanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ciscoScanner.js","sourceRoot":"","sources":["../../src/lib/ciscoScanner.ts"],"names":[],"mappings":"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"}