decnet 1.0.0__py3-none-any.whl

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 (786) hide show
  1. decnet/__init__.py +13 -0
  2. decnet/agent/__init__.py +8 -0
  3. decnet/agent/app.py +366 -0
  4. decnet/agent/executor.py +317 -0
  5. decnet/agent/heartbeat.py +210 -0
  6. decnet/agent/server.py +71 -0
  7. decnet/agent/topology_ops.py +220 -0
  8. decnet/agent/topology_store.py +215 -0
  9. decnet/archetypes.py +171 -0
  10. decnet/artifacts/__init__.py +1 -0
  11. decnet/artifacts/paths.py +86 -0
  12. decnet/artifacts/shards.py +129 -0
  13. decnet/asn/__init__.py +93 -0
  14. decnet/asn/base.py +34 -0
  15. decnet/asn/factory.py +40 -0
  16. decnet/asn/iptoasn/__init__.py +10 -0
  17. decnet/asn/iptoasn/fetch.py +64 -0
  18. decnet/asn/iptoasn/parse.py +79 -0
  19. decnet/asn/iptoasn/provider.py +84 -0
  20. decnet/asn/lookup.py +143 -0
  21. decnet/asn/paths.py +19 -0
  22. decnet/bus/__init__.py +19 -0
  23. decnet/bus/app.py +93 -0
  24. decnet/bus/base.py +206 -0
  25. decnet/bus/factory.py +86 -0
  26. decnet/bus/fake.py +184 -0
  27. decnet/bus/protocol.py +145 -0
  28. decnet/bus/publish.py +212 -0
  29. decnet/bus/topics.py +653 -0
  30. decnet/bus/unix_client.py +269 -0
  31. decnet/bus/unix_server.py +310 -0
  32. decnet/bus/worker.py +122 -0
  33. decnet/canary/__init__.py +38 -0
  34. decnet/canary/_obfuscate_helper.js +19 -0
  35. decnet/canary/base.py +152 -0
  36. decnet/canary/cultivator.py +193 -0
  37. decnet/canary/dns_server.py +208 -0
  38. decnet/canary/factory.py +154 -0
  39. decnet/canary/fingerprint_payload.js +292 -0
  40. decnet/canary/generators/__init__.py +8 -0
  41. decnet/canary/generators/aws_creds.py +87 -0
  42. decnet/canary/generators/env_file.py +57 -0
  43. decnet/canary/generators/fingerprint_html.py +141 -0
  44. decnet/canary/generators/fingerprint_svg.py +89 -0
  45. decnet/canary/generators/git_config.py +54 -0
  46. decnet/canary/generators/honeydoc.py +62 -0
  47. decnet/canary/generators/honeydoc_docx.py +134 -0
  48. decnet/canary/generators/honeydoc_pdf.py +128 -0
  49. decnet/canary/generators/mysql_dump.py +191 -0
  50. decnet/canary/generators/ssh_key.py +69 -0
  51. decnet/canary/instrumenters/__init__.py +5 -0
  52. decnet/canary/instrumenters/docx.py +148 -0
  53. decnet/canary/instrumenters/html.py +46 -0
  54. decnet/canary/instrumenters/image.py +73 -0
  55. decnet/canary/instrumenters/passthrough.py +38 -0
  56. decnet/canary/instrumenters/pdf.py +77 -0
  57. decnet/canary/instrumenters/plain.py +80 -0
  58. decnet/canary/instrumenters/xlsx.py +96 -0
  59. decnet/canary/obfuscator.py +178 -0
  60. decnet/canary/package.json +10 -0
  61. decnet/canary/paths.py +87 -0
  62. decnet/canary/planter.py +307 -0
  63. decnet/canary/storage.py +90 -0
  64. decnet/canary/worker.py +421 -0
  65. decnet/cli/__init__.py +92 -0
  66. decnet/cli/agent.py +65 -0
  67. decnet/cli/api.py +54 -0
  68. decnet/cli/bus.py +46 -0
  69. decnet/cli/canary.py +104 -0
  70. decnet/cli/db.py +142 -0
  71. decnet/cli/deploy.py +308 -0
  72. decnet/cli/forwarder.py +75 -0
  73. decnet/cli/gating.py +78 -0
  74. decnet/cli/geoip.py +60 -0
  75. decnet/cli/init.py +864 -0
  76. decnet/cli/inventory.py +53 -0
  77. decnet/cli/lifecycle.py +148 -0
  78. decnet/cli/listener.py +58 -0
  79. decnet/cli/orchestrator.py +56 -0
  80. decnet/cli/profiler.py +35 -0
  81. decnet/cli/realism.py +112 -0
  82. decnet/cli/reconciler.py +63 -0
  83. decnet/cli/sniffer.py +32 -0
  84. decnet/cli/swarm.py +347 -0
  85. decnet/cli/swarmctl.py +142 -0
  86. decnet/cli/topology.py +349 -0
  87. decnet/cli/ttp.py +310 -0
  88. decnet/cli/updater.py +47 -0
  89. decnet/cli/utils.py +243 -0
  90. decnet/cli/web.py +154 -0
  91. decnet/cli/webhook.py +36 -0
  92. decnet/cli/workers.py +369 -0
  93. decnet/clustering/__init__.py +2 -0
  94. decnet/clustering/base.py +84 -0
  95. decnet/clustering/campaign/__init__.py +6 -0
  96. decnet/clustering/campaign/base.py +67 -0
  97. decnet/clustering/campaign/factory.py +32 -0
  98. decnet/clustering/campaign/impl/__init__.py +1 -0
  99. decnet/clustering/campaign/impl/connected_components.py +386 -0
  100. decnet/clustering/campaign/impl/similarity.py +479 -0
  101. decnet/clustering/campaign/worker.py +192 -0
  102. decnet/clustering/factory.py +47 -0
  103. decnet/clustering/impl/__init__.py +7 -0
  104. decnet/clustering/impl/connected_components.py +421 -0
  105. decnet/clustering/impl/similarity.py +314 -0
  106. decnet/clustering/ukc.py +203 -0
  107. decnet/clustering/worker.py +181 -0
  108. decnet/collector/__init__.py +14 -0
  109. decnet/collector/worker.py +913 -0
  110. decnet/composer.py +128 -0
  111. decnet/config.py +153 -0
  112. decnet/config_ini.py +211 -0
  113. decnet/correlation/__init__.py +14 -0
  114. decnet/correlation/attribution/__init__.py +22 -0
  115. decnet/correlation/attribution/_thresholds.py +63 -0
  116. decnet/correlation/attribution/aggregate.py +419 -0
  117. decnet/correlation/attribution_worker.py +395 -0
  118. decnet/correlation/engine.py +355 -0
  119. decnet/correlation/event_kinds.py +114 -0
  120. decnet/correlation/fingerprint_rotation.py +161 -0
  121. decnet/correlation/graph.py +148 -0
  122. decnet/correlation/parser.py +203 -0
  123. decnet/correlation/reuse_worker.py +154 -0
  124. decnet/custom_service.py +42 -0
  125. decnet/decky_io/__init__.py +40 -0
  126. decnet/decky_io/resolve.py +73 -0
  127. decnet/decky_io/write.py +125 -0
  128. decnet/distros.py +147 -0
  129. decnet/engine/__init__.py +16 -0
  130. decnet/engine/deployer.py +1230 -0
  131. decnet/engine/reaper.py +172 -0
  132. decnet/engine/services_live.py +693 -0
  133. decnet/env.py +330 -0
  134. decnet/fleet/__init__.py +186 -0
  135. decnet/fleet/reconciler.py +230 -0
  136. decnet/fleet/reconciler_worker.py +87 -0
  137. decnet/geoip/__init__.py +96 -0
  138. decnet/geoip/base.py +35 -0
  139. decnet/geoip/factory.py +48 -0
  140. decnet/geoip/lookup.py +122 -0
  141. decnet/geoip/paths.py +20 -0
  142. decnet/geoip/ptr.py +88 -0
  143. decnet/geoip/rir/__init__.py +10 -0
  144. decnet/geoip/rir/fetch.py +63 -0
  145. decnet/geoip/rir/parse.py +71 -0
  146. decnet/geoip/rir/provider.py +75 -0
  147. decnet/ini_loader.py +181 -0
  148. decnet/intel/__init__.py +11 -0
  149. decnet/intel/abuseipdb.py +117 -0
  150. decnet/intel/base.py +111 -0
  151. decnet/intel/factory.py +108 -0
  152. decnet/intel/feodo.py +114 -0
  153. decnet/intel/greynoise.py +122 -0
  154. decnet/intel/mal_hash.py +196 -0
  155. decnet/intel/threatfox.py +122 -0
  156. decnet/intel/worker.py +276 -0
  157. decnet/lifecycle/__init__.py +16 -0
  158. decnet/lifecycle/events.py +44 -0
  159. decnet/lifecycle/runner.py +97 -0
  160. decnet/lifecycle/strategies.py +377 -0
  161. decnet/logging/__init__.py +93 -0
  162. decnet/logging/file_handler.py +73 -0
  163. decnet/logging/forwarder.py +40 -0
  164. decnet/logging/inode_aware_handler.py +61 -0
  165. decnet/logging/syslog_formatter.py +87 -0
  166. decnet/models.py +124 -0
  167. decnet/mutator/__init__.py +4 -0
  168. decnet/mutator/engine.py +523 -0
  169. decnet/mutator/events.py +109 -0
  170. decnet/mutator/ops.py +1109 -0
  171. decnet/net/__init__.py +8 -0
  172. decnet/net/http.py +60 -0
  173. decnet/network.py +514 -0
  174. decnet/orchestrator/__init__.py +10 -0
  175. decnet/orchestrator/drivers/__init__.py +75 -0
  176. decnet/orchestrator/drivers/base.py +93 -0
  177. decnet/orchestrator/drivers/email.py +291 -0
  178. decnet/orchestrator/drivers/smtp_relay.py +81 -0
  179. decnet/orchestrator/drivers/ssh.py +271 -0
  180. decnet/orchestrator/emailgen/__init__.py +21 -0
  181. decnet/orchestrator/emailgen/events.py +50 -0
  182. decnet/orchestrator/emailgen/scheduler.py +256 -0
  183. decnet/orchestrator/emailgen/threads.py +76 -0
  184. decnet/orchestrator/events.py +69 -0
  185. decnet/orchestrator/scheduler.py +346 -0
  186. decnet/orchestrator/worker.py +629 -0
  187. decnet/os_fingerprint.py +114 -0
  188. decnet/privdrop.py +68 -0
  189. decnet/prober/__init__.py +14 -0
  190. decnet/prober/base.py +89 -0
  191. decnet/prober/hassh.py +253 -0
  192. decnet/prober/icmp6_error.py +314 -0
  193. decnet/prober/icmp_error.py +305 -0
  194. decnet/prober/ipv6_leak.py +131 -0
  195. decnet/prober/jarm.py +507 -0
  196. decnet/prober/osfp/__init__.py +28 -0
  197. decnet/prober/osfp/base.py +60 -0
  198. decnet/prober/osfp/factory.py +88 -0
  199. decnet/prober/osfp/p0f/__init__.py +7 -0
  200. decnet/prober/osfp/p0f/format.py +244 -0
  201. decnet/prober/osfp/p0f/provider.py +110 -0
  202. decnet/prober/osfp/p0f/signature.py +288 -0
  203. decnet/prober/probes/__init__.py +9 -0
  204. decnet/prober/probes/hassh.py +44 -0
  205. decnet/prober/probes/icmp6_error_probe.py +79 -0
  206. decnet/prober/probes/icmp_error_probe.py +73 -0
  207. decnet/prober/probes/ipv6_leak_probe.py +63 -0
  208. decnet/prober/probes/jarm.py +35 -0
  209. decnet/prober/probes/tcpfp.py +53 -0
  210. decnet/prober/probes/tlscert_probe.py +53 -0
  211. decnet/prober/tcpfp.py +240 -0
  212. decnet/prober/tlscert.py +132 -0
  213. decnet/prober/worker.py +499 -0
  214. decnet/profiler/__init__.py +6 -0
  215. decnet/profiler/behave_shell/__init__.py +26 -0
  216. decnet/profiler/behave_shell/_ctx.py +574 -0
  217. decnet/profiler/behave_shell/_features/__init__.py +107 -0
  218. decnet/profiler/behave_shell/_features/_emit.py +33 -0
  219. decnet/profiler/behave_shell/_features/cognitive.py +594 -0
  220. decnet/profiler/behave_shell/_features/emotional_valence.py +224 -0
  221. decnet/profiler/behave_shell/_features/environmental.py +353 -0
  222. decnet/profiler/behave_shell/_features/motor.py +489 -0
  223. decnet/profiler/behave_shell/_features/operational.py +219 -0
  224. decnet/profiler/behave_shell/_features/temporal.py +238 -0
  225. decnet/profiler/behave_shell/_handler.py +236 -0
  226. decnet/profiler/behave_shell/_intent.py +116 -0
  227. decnet/profiler/behave_shell/_parse.py +273 -0
  228. decnet/profiler/behave_shell/_thresholds.py +428 -0
  229. decnet/profiler/behave_shell/extract.py +52 -0
  230. decnet/profiler/behavioral.py +108 -0
  231. decnet/profiler/classify.py +58 -0
  232. decnet/profiler/fingerprint.py +297 -0
  233. decnet/profiler/identity_rollup.py +114 -0
  234. decnet/profiler/phases.py +69 -0
  235. decnet/profiler/timing.py +83 -0
  236. decnet/profiler/tools.py +180 -0
  237. decnet/profiler/worker.py +614 -0
  238. decnet/realism/__init__.py +28 -0
  239. decnet/realism/bodies.py +430 -0
  240. decnet/realism/diurnal.py +153 -0
  241. decnet/realism/llm/__init__.py +18 -0
  242. decnet/realism/llm/base.py +48 -0
  243. decnet/realism/llm/circuit.py +100 -0
  244. decnet/realism/llm/config.py +130 -0
  245. decnet/realism/llm/factory.py +61 -0
  246. decnet/realism/llm/impl/__init__.py +7 -0
  247. decnet/realism/llm/impl/fake.py +51 -0
  248. decnet/realism/llm/impl/ollama.py +175 -0
  249. decnet/realism/naming.py +187 -0
  250. decnet/realism/personas.py +144 -0
  251. decnet/realism/personas_pool.py +154 -0
  252. decnet/realism/planner.py +390 -0
  253. decnet/realism/prompts/__init__.py +10 -0
  254. decnet/realism/prompts/_style.py +40 -0
  255. decnet/realism/prompts/email.py +155 -0
  256. decnet/realism/prompts/filebody.py +92 -0
  257. decnet/realism/taxonomy.py +153 -0
  258. decnet/rpki/__init__.py +44 -0
  259. decnet/rpki/base.py +39 -0
  260. decnet/rpki/cache.py +74 -0
  261. decnet/rpki/factory.py +40 -0
  262. decnet/rpki/paths.py +19 -0
  263. decnet/rpki/ripestat/__init__.py +1 -0
  264. decnet/rpki/ripestat/validator.py +90 -0
  265. decnet/services/__init__.py +1 -0
  266. decnet/services/base.py +178 -0
  267. decnet/services/conpot.py +37 -0
  268. decnet/services/dns.py +127 -0
  269. decnet/services/docker_api.py +26 -0
  270. decnet/services/elasticsearch.py +29 -0
  271. decnet/services/ftp.py +28 -0
  272. decnet/services/http.py +99 -0
  273. decnet/services/https.py +125 -0
  274. decnet/services/imap.py +64 -0
  275. decnet/services/k8s.py +26 -0
  276. decnet/services/ldap.py +27 -0
  277. decnet/services/llmnr.py +33 -0
  278. decnet/services/mongodb.py +26 -0
  279. decnet/services/mqtt.py +26 -0
  280. decnet/services/mssql.py +26 -0
  281. decnet/services/mysql.py +43 -0
  282. decnet/services/pop3.py +52 -0
  283. decnet/services/postgres.py +26 -0
  284. decnet/services/rdp.py +45 -0
  285. decnet/services/redis.py +52 -0
  286. decnet/services/registry.py +52 -0
  287. decnet/services/sip.py +26 -0
  288. decnet/services/smb.py +29 -0
  289. decnet/services/smtp.py +66 -0
  290. decnet/services/smtp_relay.py +110 -0
  291. decnet/services/sniffer.py +43 -0
  292. decnet/services/snmp.py +26 -0
  293. decnet/services/ssh.py +121 -0
  294. decnet/services/telnet.py +117 -0
  295. decnet/services/tftp.py +26 -0
  296. decnet/services/vnc.py +26 -0
  297. decnet/sniffer/__init__.py +12 -0
  298. decnet/sniffer/fingerprint.py +1649 -0
  299. decnet/sniffer/p0f.py +239 -0
  300. decnet/sniffer/seq_class.py +64 -0
  301. decnet/sniffer/syslog.py +72 -0
  302. decnet/sniffer/worker.py +290 -0
  303. decnet/swarm/__init__.py +8 -0
  304. decnet/swarm/bundle_builder.py +210 -0
  305. decnet/swarm/client.py +342 -0
  306. decnet/swarm/log_forwarder.py +328 -0
  307. decnet/swarm/log_listener.py +220 -0
  308. decnet/swarm/pki.py +324 -0
  309. decnet/swarm/tar_tree.py +127 -0
  310. decnet/swarm/updater_client.py +205 -0
  311. decnet/tarpit/__init__.py +4 -0
  312. decnet/tarpit/worker.py +209 -0
  313. decnet/telemetry.py +309 -0
  314. decnet/templates/_caddy_modules/decnetfp/go.mod +130 -0
  315. decnet/templates/_caddy_modules/decnetfp/go.sum +491 -0
  316. decnet/templates/_caddy_modules/decnetfp/h1_test.go +150 -0
  317. decnet/templates/_caddy_modules/decnetfp/h2_test.go +206 -0
  318. decnet/templates/_caddy_modules/decnetfp/h3_tracer_test.go +170 -0
  319. decnet/templates/_caddy_modules/decnetfp/h3conn.go +117 -0
  320. decnet/templates/_caddy_modules/decnetfp/module.go +674 -0
  321. decnet/templates/_shared/auth-helper/auth-helper.c +190 -0
  322. decnet/templates/_shared/ntlmssp.py +133 -0
  323. decnet/templates/_shared/sessrec/Makefile +28 -0
  324. decnet/templates/_shared/sessrec/sessrec.c +564 -0
  325. decnet/templates/conpot/Dockerfile +28 -0
  326. decnet/templates/conpot/entrypoint.py +148 -0
  327. decnet/templates/conpot/instance_seed.py +121 -0
  328. decnet/templates/conpot/syslog_bridge.py +403 -0
  329. decnet/templates/cowrie/Dockerfile +22 -0
  330. decnet/templates/cowrie/cowrie.cfg.j2 +30 -0
  331. decnet/templates/cowrie/entrypoint.sh +34 -0
  332. decnet/templates/cowrie/honeyfs/etc/group +62 -0
  333. decnet/templates/cowrie/honeyfs/etc/hostname +1 -0
  334. decnet/templates/cowrie/honeyfs/etc/hosts +5 -0
  335. decnet/templates/cowrie/honeyfs/etc/issue +2 -0
  336. decnet/templates/cowrie/honeyfs/etc/issue.net +1 -0
  337. decnet/templates/cowrie/honeyfs/etc/motd +26 -0
  338. decnet/templates/cowrie/honeyfs/etc/os-release +12 -0
  339. decnet/templates/cowrie/honeyfs/etc/passwd +36 -0
  340. decnet/templates/cowrie/honeyfs/etc/resolv.conf +4 -0
  341. decnet/templates/cowrie/honeyfs/etc/shadow +36 -0
  342. decnet/templates/cowrie/honeyfs/var/log/auth.log +12 -0
  343. decnet/templates/dns/Dockerfile +26 -0
  344. decnet/templates/dns/entrypoint.sh +4 -0
  345. decnet/templates/dns/instance_seed.py +121 -0
  346. decnet/templates/dns/server.py +977 -0
  347. decnet/templates/dns/syslog_bridge.py +402 -0
  348. decnet/templates/docker_api/Dockerfile +26 -0
  349. decnet/templates/docker_api/entrypoint.sh +4 -0
  350. decnet/templates/docker_api/instance_seed.py +121 -0
  351. decnet/templates/docker_api/server.py +125 -0
  352. decnet/templates/docker_api/syslog_bridge.py +403 -0
  353. decnet/templates/elasticsearch/Dockerfile +24 -0
  354. decnet/templates/elasticsearch/entrypoint.sh +4 -0
  355. decnet/templates/elasticsearch/instance_seed.py +121 -0
  356. decnet/templates/elasticsearch/server.py +196 -0
  357. decnet/templates/elasticsearch/syslog_bridge.py +403 -0
  358. decnet/templates/ftp/Dockerfile +27 -0
  359. decnet/templates/ftp/entrypoint.sh +4 -0
  360. decnet/templates/ftp/instance_seed.py +121 -0
  361. decnet/templates/ftp/server.py +150 -0
  362. decnet/templates/ftp/syslog_bridge.py +403 -0
  363. decnet/templates/http/Dockerfile +44 -0
  364. decnet/templates/http/_caddy_modules/decnetfp/go.mod +130 -0
  365. decnet/templates/http/_caddy_modules/decnetfp/go.sum +491 -0
  366. decnet/templates/http/_caddy_modules/decnetfp/h1_test.go +150 -0
  367. decnet/templates/http/_caddy_modules/decnetfp/h2_test.go +206 -0
  368. decnet/templates/http/_caddy_modules/decnetfp/h3_tracer_test.go +170 -0
  369. decnet/templates/http/_caddy_modules/decnetfp/h3conn.go +117 -0
  370. decnet/templates/http/_caddy_modules/decnetfp/module.go +674 -0
  371. decnet/templates/http/entrypoint.sh +56 -0
  372. decnet/templates/http/instance_seed.py +121 -0
  373. decnet/templates/http/server.py +172 -0
  374. decnet/templates/http/syslog_bridge.py +403 -0
  375. decnet/templates/https/Dockerfile +45 -0
  376. decnet/templates/https/_caddy_modules/decnetfp/go.mod +130 -0
  377. decnet/templates/https/_caddy_modules/decnetfp/go.sum +491 -0
  378. decnet/templates/https/_caddy_modules/decnetfp/h1_test.go +150 -0
  379. decnet/templates/https/_caddy_modules/decnetfp/h2_test.go +206 -0
  380. decnet/templates/https/_caddy_modules/decnetfp/h3_tracer_test.go +170 -0
  381. decnet/templates/https/_caddy_modules/decnetfp/h3conn.go +117 -0
  382. decnet/templates/https/_caddy_modules/decnetfp/module.go +674 -0
  383. decnet/templates/https/entrypoint.sh +89 -0
  384. decnet/templates/https/instance_seed.py +121 -0
  385. decnet/templates/https/server.py +170 -0
  386. decnet/templates/https/syslog_bridge.py +403 -0
  387. decnet/templates/imap/Dockerfile +23 -0
  388. decnet/templates/imap/entrypoint.sh +4 -0
  389. decnet/templates/imap/instance_seed.py +121 -0
  390. decnet/templates/imap/server.py +772 -0
  391. decnet/templates/imap/syslog_bridge.py +403 -0
  392. decnet/templates/instance_seed.py +121 -0
  393. decnet/templates/k8s/Dockerfile +26 -0
  394. decnet/templates/k8s/entrypoint.sh +4 -0
  395. decnet/templates/k8s/instance_seed.py +121 -0
  396. decnet/templates/k8s/server.py +136 -0
  397. decnet/templates/k8s/syslog_bridge.py +403 -0
  398. decnet/templates/ldap/Dockerfile +24 -0
  399. decnet/templates/ldap/entrypoint.sh +4 -0
  400. decnet/templates/ldap/instance_seed.py +121 -0
  401. decnet/templates/ldap/server.py +215 -0
  402. decnet/templates/ldap/syslog_bridge.py +403 -0
  403. decnet/templates/llmnr/Dockerfile +24 -0
  404. decnet/templates/llmnr/entrypoint.sh +4 -0
  405. decnet/templates/llmnr/instance_seed.py +121 -0
  406. decnet/templates/llmnr/server.py +114 -0
  407. decnet/templates/llmnr/syslog_bridge.py +403 -0
  408. decnet/templates/mongodb/Dockerfile +24 -0
  409. decnet/templates/mongodb/entrypoint.sh +4 -0
  410. decnet/templates/mongodb/instance_seed.py +121 -0
  411. decnet/templates/mongodb/server.py +362 -0
  412. decnet/templates/mongodb/syslog_bridge.py +403 -0
  413. decnet/templates/mqtt/Dockerfile +24 -0
  414. decnet/templates/mqtt/entrypoint.sh +4 -0
  415. decnet/templates/mqtt/instance_seed.py +121 -0
  416. decnet/templates/mqtt/server.py +347 -0
  417. decnet/templates/mqtt/syslog_bridge.py +403 -0
  418. decnet/templates/mssql/Dockerfile +24 -0
  419. decnet/templates/mssql/entrypoint.sh +4 -0
  420. decnet/templates/mssql/instance_seed.py +121 -0
  421. decnet/templates/mssql/server.py +226 -0
  422. decnet/templates/mssql/syslog_bridge.py +403 -0
  423. decnet/templates/mysql/Dockerfile +24 -0
  424. decnet/templates/mysql/entrypoint.sh +4 -0
  425. decnet/templates/mysql/instance_seed.py +121 -0
  426. decnet/templates/mysql/server.py +174 -0
  427. decnet/templates/mysql/syslog_bridge.py +403 -0
  428. decnet/templates/pop3/Dockerfile +23 -0
  429. decnet/templates/pop3/entrypoint.sh +4 -0
  430. decnet/templates/pop3/instance_seed.py +121 -0
  431. decnet/templates/pop3/server.py +576 -0
  432. decnet/templates/pop3/syslog_bridge.py +403 -0
  433. decnet/templates/postgres/Dockerfile +24 -0
  434. decnet/templates/postgres/entrypoint.sh +4 -0
  435. decnet/templates/postgres/instance_seed.py +121 -0
  436. decnet/templates/postgres/server.py +191 -0
  437. decnet/templates/postgres/syslog_bridge.py +403 -0
  438. decnet/templates/rdp/Dockerfile +27 -0
  439. decnet/templates/rdp/entrypoint.sh +21 -0
  440. decnet/templates/rdp/instance_seed.py +121 -0
  441. decnet/templates/rdp/ntlmssp.py +133 -0
  442. decnet/templates/rdp/server.py +401 -0
  443. decnet/templates/rdp/syslog_bridge.py +403 -0
  444. decnet/templates/redis/Dockerfile +24 -0
  445. decnet/templates/redis/entrypoint.sh +4 -0
  446. decnet/templates/redis/instance_seed.py +121 -0
  447. decnet/templates/redis/server.py +339 -0
  448. decnet/templates/redis/syslog_bridge.py +403 -0
  449. decnet/templates/sip/Dockerfile +24 -0
  450. decnet/templates/sip/entrypoint.sh +4 -0
  451. decnet/templates/sip/instance_seed.py +121 -0
  452. decnet/templates/sip/server.py +155 -0
  453. decnet/templates/sip/syslog_bridge.py +403 -0
  454. decnet/templates/smb/Dockerfile +25 -0
  455. decnet/templates/smb/entrypoint.sh +4 -0
  456. decnet/templates/smb/instance_seed.py +121 -0
  457. decnet/templates/smb/ntlmssp.py +133 -0
  458. decnet/templates/smb/server.py +298 -0
  459. decnet/templates/smb/syslog_bridge.py +403 -0
  460. decnet/templates/smtp/Dockerfile +26 -0
  461. decnet/templates/smtp/entrypoint.sh +13 -0
  462. decnet/templates/smtp/instance_seed.py +121 -0
  463. decnet/templates/smtp/server.py +838 -0
  464. decnet/templates/smtp/syslog_bridge.py +403 -0
  465. decnet/templates/sniffer/Dockerfile +12 -0
  466. decnet/templates/sniffer/__pycache__/server.cpython-311.pyc +0 -0
  467. decnet/templates/sniffer/server.py +1053 -0
  468. decnet/templates/sniffer/syslog_bridge.py +403 -0
  469. decnet/templates/snmp/Dockerfile +23 -0
  470. decnet/templates/snmp/entrypoint.sh +4 -0
  471. decnet/templates/snmp/instance_seed.py +121 -0
  472. decnet/templates/snmp/server.py +273 -0
  473. decnet/templates/snmp/syslog_bridge.py +403 -0
  474. decnet/templates/ssh/Dockerfile +173 -0
  475. decnet/templates/ssh/_build_stealth.py +90 -0
  476. decnet/templates/ssh/argv_zap.c +65 -0
  477. decnet/templates/ssh/auth-helper/auth-helper.c +190 -0
  478. decnet/templates/ssh/capture.sh +266 -0
  479. decnet/templates/ssh/emit_capture.py +85 -0
  480. decnet/templates/ssh/entrypoint.sh +111 -0
  481. decnet/templates/ssh/instance_seed.py +121 -0
  482. decnet/templates/ssh/sessrec/Makefile +28 -0
  483. decnet/templates/ssh/sessrec/sessrec.c +564 -0
  484. decnet/templates/ssh/syslog_bridge.py +403 -0
  485. decnet/templates/syslog_bridge.py +403 -0
  486. decnet/templates/telnet/Dockerfile +109 -0
  487. decnet/templates/telnet/auth-helper/auth-helper.c +190 -0
  488. decnet/templates/telnet/entrypoint.sh +68 -0
  489. decnet/templates/telnet/instance_seed.py +121 -0
  490. decnet/templates/telnet/sessrec/Makefile +28 -0
  491. decnet/templates/telnet/sessrec/sessrec.c +564 -0
  492. decnet/templates/telnet/syslog_bridge.py +403 -0
  493. decnet/templates/tftp/Dockerfile +23 -0
  494. decnet/templates/tftp/entrypoint.sh +4 -0
  495. decnet/templates/tftp/instance_seed.py +121 -0
  496. decnet/templates/tftp/server.py +85 -0
  497. decnet/templates/tftp/syslog_bridge.py +403 -0
  498. decnet/templates/vnc/Dockerfile +23 -0
  499. decnet/templates/vnc/entrypoint.sh +4 -0
  500. decnet/templates/vnc/instance_seed.py +121 -0
  501. decnet/templates/vnc/server.py +110 -0
  502. decnet/templates/vnc/syslog_bridge.py +403 -0
  503. decnet/topology/__init__.py +24 -0
  504. decnet/topology/allocator.py +162 -0
  505. decnet/topology/compose.py +174 -0
  506. decnet/topology/config.py +114 -0
  507. decnet/topology/generator.py +260 -0
  508. decnet/topology/hashing.py +66 -0
  509. decnet/topology/persistence.py +226 -0
  510. decnet/topology/repository.py +30 -0
  511. decnet/topology/status.py +107 -0
  512. decnet/topology/validate.py +429 -0
  513. decnet/ttp/__init__.py +8 -0
  514. decnet/ttp/attack_catalog.py +20 -0
  515. decnet/ttp/attack_stix.py +576 -0
  516. decnet/ttp/attack_version.py +59 -0
  517. decnet/ttp/base.py +185 -0
  518. decnet/ttp/data/__init__.py +7 -0
  519. decnet/ttp/data/intel/__init__.py +9 -0
  520. decnet/ttp/data/intel_loader.py +230 -0
  521. decnet/ttp/factory.py +194 -0
  522. decnet/ttp/impl/__init__.py +7 -0
  523. decnet/ttp/impl/_emit.py +71 -0
  524. decnet/ttp/impl/_rule_index.py +190 -0
  525. decnet/ttp/impl/_state.py +56 -0
  526. decnet/ttp/impl/behavioral_lifter.py +276 -0
  527. decnet/ttp/impl/canary_fingerprint_lifter.py +160 -0
  528. decnet/ttp/impl/credential_lifter.py +186 -0
  529. decnet/ttp/impl/email_lifter.py +474 -0
  530. decnet/ttp/impl/http_fingerprint_lifter.py +127 -0
  531. decnet/ttp/impl/identity_lifter.py +115 -0
  532. decnet/ttp/impl/intel_lifter.py +374 -0
  533. decnet/ttp/impl/ipv6_leak_lifter.py +75 -0
  534. decnet/ttp/impl/rule_engine.py +439 -0
  535. decnet/ttp/misp_export.py +120 -0
  536. decnet/ttp/stix_custom.py +101 -0
  537. decnet/ttp/stix_export.py +518 -0
  538. decnet/ttp/store/__init__.py +26 -0
  539. decnet/ttp/store/base.py +150 -0
  540. decnet/ttp/store/factory.py +48 -0
  541. decnet/ttp/store/impl/__init__.py +2 -0
  542. decnet/ttp/store/impl/database.py +615 -0
  543. decnet/ttp/store/impl/filesystem.py +553 -0
  544. decnet/ttp/worker.py +657 -0
  545. decnet/updater/__init__.py +11 -0
  546. decnet/updater/app.py +219 -0
  547. decnet/updater/executor.py +771 -0
  548. decnet/updater/server.py +91 -0
  549. decnet/util/__init__.py +2 -0
  550. decnet/util/simhash.py +66 -0
  551. decnet/vectorstore/__init__.py +28 -0
  552. decnet/vectorstore/base.py +115 -0
  553. decnet/vectorstore/factory.py +74 -0
  554. decnet/vectorstore/fake.py +132 -0
  555. decnet/vectorstore/sqlite_vec.py +286 -0
  556. decnet/web/_mtls.py +127 -0
  557. decnet/web/_uvicorn_tls_scope.py +73 -0
  558. decnet/web/api.py +451 -0
  559. decnet/web/auth.py +71 -0
  560. decnet/web/db/factory.py +35 -0
  561. decnet/web/db/migrate.py +38 -0
  562. decnet/web/db/migrations/env.py +90 -0
  563. decnet/web/db/migrations/versions/4a914b1d62a0_baseline_schema.py +1109 -0
  564. decnet/web/db/models/__init__.py +417 -0
  565. decnet/web/db/models/_base.py +24 -0
  566. decnet/web/db/models/attachments.py +77 -0
  567. decnet/web/db/models/attacker_intel.py +163 -0
  568. decnet/web/db/models/attackers.py +353 -0
  569. decnet/web/db/models/attribution_state.py +79 -0
  570. decnet/web/db/models/auth.py +128 -0
  571. decnet/web/db/models/campaigns.py +84 -0
  572. decnet/web/db/models/canary.py +260 -0
  573. decnet/web/db/models/common.py +16 -0
  574. decnet/web/db/models/decky.py +131 -0
  575. decnet/web/db/models/decky_lifecycle.py +88 -0
  576. decnet/web/db/models/deploy.py +43 -0
  577. decnet/web/db/models/fleet.py +73 -0
  578. decnet/web/db/models/health.py +15 -0
  579. decnet/web/db/models/logs.py +238 -0
  580. decnet/web/db/models/observations.py +81 -0
  581. decnet/web/db/models/orchestrator.py +112 -0
  582. decnet/web/db/models/realism.py +108 -0
  583. decnet/web/db/models/swarm.py +232 -0
  584. decnet/web/db/models/tarpit.py +45 -0
  585. decnet/web/db/models/topology.py +455 -0
  586. decnet/web/db/models/ttp.py +469 -0
  587. decnet/web/db/models/updater.py +74 -0
  588. decnet/web/db/models/webhooks.py +163 -0
  589. decnet/web/db/models/workers.py +51 -0
  590. decnet/web/db/mysql/__init__.py +1 -0
  591. decnet/web/db/mysql/database.py +101 -0
  592. decnet/web/db/mysql/repository.py +116 -0
  593. decnet/web/db/repository.py +1776 -0
  594. decnet/web/db/secrets.py +44 -0
  595. decnet/web/db/sqlite/database.py +66 -0
  596. decnet/web/db/sqlite/repository.py +69 -0
  597. decnet/web/db/sqlmodel_repo/__init__.py +215 -0
  598. decnet/web/db/sqlmodel_repo/_helpers.py +160 -0
  599. decnet/web/db/sqlmodel_repo/attacker_intel.py +102 -0
  600. decnet/web/db/sqlmodel_repo/attackers/__init__.py +31 -0
  601. decnet/web/db/sqlmodel_repo/attackers/_core.py +136 -0
  602. decnet/web/db/sqlmodel_repo/attackers/activity.py +229 -0
  603. decnet/web/db/sqlmodel_repo/attackers/behavior.py +110 -0
  604. decnet/web/db/sqlmodel_repo/attackers/smtp.py +72 -0
  605. decnet/web/db/sqlmodel_repo/attribution.py +216 -0
  606. decnet/web/db/sqlmodel_repo/auth.py +104 -0
  607. decnet/web/db/sqlmodel_repo/bounties.py +189 -0
  608. decnet/web/db/sqlmodel_repo/campaigns.py +179 -0
  609. decnet/web/db/sqlmodel_repo/canary.py +207 -0
  610. decnet/web/db/sqlmodel_repo/credentials/__init__.py +21 -0
  611. decnet/web/db/sqlmodel_repo/credentials/_core.py +234 -0
  612. decnet/web/db/sqlmodel_repo/credentials/reuse.py +279 -0
  613. decnet/web/db/sqlmodel_repo/deckies.py +94 -0
  614. decnet/web/db/sqlmodel_repo/decky_lifecycle.py +107 -0
  615. decnet/web/db/sqlmodel_repo/fleet.py +166 -0
  616. decnet/web/db/sqlmodel_repo/identities.py +191 -0
  617. decnet/web/db/sqlmodel_repo/logs.py +226 -0
  618. decnet/web/db/sqlmodel_repo/observations.py +261 -0
  619. decnet/web/db/sqlmodel_repo/observed_attachments.py +109 -0
  620. decnet/web/db/sqlmodel_repo/orchestrator.py +235 -0
  621. decnet/web/db/sqlmodel_repo/realism.py +160 -0
  622. decnet/web/db/sqlmodel_repo/swarm.py +74 -0
  623. decnet/web/db/sqlmodel_repo/tarpit.py +73 -0
  624. decnet/web/db/sqlmodel_repo/topology/__init__.py +33 -0
  625. decnet/web/db/sqlmodel_repo/topology/_core.py +249 -0
  626. decnet/web/db/sqlmodel_repo/topology/deckies.py +142 -0
  627. decnet/web/db/sqlmodel_repo/topology/edges.py +84 -0
  628. decnet/web/db/sqlmodel_repo/topology/lans.py +129 -0
  629. decnet/web/db/sqlmodel_repo/topology/mutations.py +174 -0
  630. decnet/web/db/sqlmodel_repo/ttp.py +538 -0
  631. decnet/web/db/sqlmodel_repo/webhooks.py +137 -0
  632. decnet/web/dependencies.py +428 -0
  633. decnet/web/ingester.py +1568 -0
  634. decnet/web/limiter.py +89 -0
  635. decnet/web/router/__init__.py +220 -0
  636. decnet/web/router/artifacts/__init__.py +0 -0
  637. decnet/web/router/artifacts/api_get_artifact.py +60 -0
  638. decnet/web/router/attackers/__init__.py +1 -0
  639. decnet/web/router/attackers/_guards.py +28 -0
  640. decnet/web/router/attackers/api_events.py +235 -0
  641. decnet/web/router/attackers/api_export_attacker_misp.py +107 -0
  642. decnet/web/router/attackers/api_export_attacker_stix.py +111 -0
  643. decnet/web/router/attackers/api_export_attackers.py +101 -0
  644. decnet/web/router/attackers/api_export_attackers_misp.py +68 -0
  645. decnet/web/router/attackers/api_export_attackers_stix.py +78 -0
  646. decnet/web/router/attackers/api_get_attacker_artifacts.py +35 -0
  647. decnet/web/router/attackers/api_get_attacker_attribution.py +93 -0
  648. decnet/web/router/attackers/api_get_attacker_commands.py +43 -0
  649. decnet/web/router/attackers/api_get_attacker_detail.py +54 -0
  650. decnet/web/router/attackers/api_get_attacker_intel.py +39 -0
  651. decnet/web/router/attackers/api_get_attacker_mail.py +38 -0
  652. decnet/web/router/attackers/api_get_attacker_smtp_targets.py +37 -0
  653. decnet/web/router/attackers/api_get_attacker_transcripts.py +35 -0
  654. decnet/web/router/attackers/api_get_attackers.py +85 -0
  655. decnet/web/router/auth/api_change_pass.py +43 -0
  656. decnet/web/router/auth/api_login.py +66 -0
  657. decnet/web/router/auth/api_logout.py +36 -0
  658. decnet/web/router/auth/api_sse_ticket.py +39 -0
  659. decnet/web/router/bounty/api_get_bounties.py +81 -0
  660. decnet/web/router/campaigns/__init__.py +1 -0
  661. decnet/web/router/campaigns/api_events.py +125 -0
  662. decnet/web/router/campaigns/api_get_campaign_detail.py +41 -0
  663. decnet/web/router/campaigns/api_list_campaign_identities.py +42 -0
  664. decnet/web/router/campaigns/api_list_campaigns.py +36 -0
  665. decnet/web/router/canary/__init__.py +24 -0
  666. decnet/web/router/canary/api_blobs.py +173 -0
  667. decnet/web/router/canary/api_tokens.py +371 -0
  668. decnet/web/router/config/__init__.py +1 -0
  669. decnet/web/router/config/api_get_config.py +125 -0
  670. decnet/web/router/config/api_manage_users.py +154 -0
  671. decnet/web/router/config/api_reinit.py +30 -0
  672. decnet/web/router/config/api_update_config.py +51 -0
  673. decnet/web/router/credential_reuse/__init__.py +1 -0
  674. decnet/web/router/credential_reuse/api_get_credential_reuse.py +75 -0
  675. decnet/web/router/credentials/__init__.py +1 -0
  676. decnet/web/router/credentials/api_get_credentials.py +104 -0
  677. decnet/web/router/deckies/__init__.py +34 -0
  678. decnet/web/router/deckies/api_file_drop.py +127 -0
  679. decnet/web/router/deckies/api_services.py +314 -0
  680. decnet/web/router/deckies/api_tarpit.py +235 -0
  681. decnet/web/router/fleet/api_deploy_deckies.py +281 -0
  682. decnet/web/router/fleet/api_get_deckies.py +49 -0
  683. decnet/web/router/fleet/api_lifecycle.py +42 -0
  684. decnet/web/router/fleet/api_mutate_decky.py +102 -0
  685. decnet/web/router/fleet/api_mutate_interval.py +46 -0
  686. decnet/web/router/fleet/api_teardown_decky.py +92 -0
  687. decnet/web/router/health/__init__.py +1 -0
  688. decnet/web/router/health/api_get_health.py +156 -0
  689. decnet/web/router/identities/__init__.py +1 -0
  690. decnet/web/router/identities/api_events.py +145 -0
  691. decnet/web/router/identities/api_get_identity_detail.py +45 -0
  692. decnet/web/router/identities/api_list_identities.py +36 -0
  693. decnet/web/router/identities/api_list_identity_observations.py +49 -0
  694. decnet/web/router/logs/api_get_histogram.py +69 -0
  695. decnet/web/router/logs/api_get_logs.py +76 -0
  696. decnet/web/router/orchestrator/__init__.py +1 -0
  697. decnet/web/router/orchestrator/api_event_stats.py +100 -0
  698. decnet/web/router/orchestrator/api_events.py +124 -0
  699. decnet/web/router/orchestrator/api_list_events.py +88 -0
  700. decnet/web/router/realism/__init__.py +1 -0
  701. decnet/web/router/realism/api_config.py +127 -0
  702. decnet/web/router/realism/api_llm.py +177 -0
  703. decnet/web/router/realism/api_personas.py +144 -0
  704. decnet/web/router/realism/api_synthetic_files.py +100 -0
  705. decnet/web/router/stats/api_get_stats.py +51 -0
  706. decnet/web/router/stream/api_stream_events.py +152 -0
  707. decnet/web/router/swarm/__init__.py +48 -0
  708. decnet/web/router/swarm/_mtls.py +75 -0
  709. decnet/web/router/swarm/api_check_hosts.py +76 -0
  710. decnet/web/router/swarm/api_decommission_host.py +75 -0
  711. decnet/web/router/swarm/api_deploy_swarm.py +173 -0
  712. decnet/web/router/swarm/api_enroll_host.py +113 -0
  713. decnet/web/router/swarm/api_get_host.py +34 -0
  714. decnet/web/router/swarm/api_get_swarm_health.py +12 -0
  715. decnet/web/router/swarm/api_heartbeat.py +276 -0
  716. decnet/web/router/swarm/api_list_deckies.py +67 -0
  717. decnet/web/router/swarm/api_list_hosts.py +33 -0
  718. decnet/web/router/swarm/api_teardown_swarm.py +66 -0
  719. decnet/web/router/swarm_mgmt/__init__.py +27 -0
  720. decnet/web/router/swarm_mgmt/api_decommission_host.py +72 -0
  721. decnet/web/router/swarm_mgmt/api_enroll_bundle.py +272 -0
  722. decnet/web/router/swarm_mgmt/api_list_deckies.py +59 -0
  723. decnet/web/router/swarm_mgmt/api_list_hosts.py +61 -0
  724. decnet/web/router/swarm_mgmt/api_teardown_host.py +151 -0
  725. decnet/web/router/swarm_updates/__init__.py +24 -0
  726. decnet/web/router/swarm_updates/api_list_host_releases.py +88 -0
  727. decnet/web/router/swarm_updates/api_push_update.py +168 -0
  728. decnet/web/router/swarm_updates/api_push_update_self.py +102 -0
  729. decnet/web/router/swarm_updates/api_rollback_host.py +78 -0
  730. decnet/web/router/system/__init__.py +7 -0
  731. decnet/web/router/system/api_deployment_mode.py +48 -0
  732. decnet/web/router/topology/__init__.py +58 -0
  733. decnet/web/router/topology/_guards.py +53 -0
  734. decnet/web/router/topology/_target_host.py +67 -0
  735. decnet/web/router/topology/api_catalog.py +184 -0
  736. decnet/web/router/topology/api_create_blank_topology.py +130 -0
  737. decnet/web/router/topology/api_create_topology.py +80 -0
  738. decnet/web/router/topology/api_decky_crud.py +137 -0
  739. decnet/web/router/topology/api_delete_topology.py +52 -0
  740. decnet/web/router/topology/api_deploy_topology.py +77 -0
  741. decnet/web/router/topology/api_edge_crud.py +111 -0
  742. decnet/web/router/topology/api_events.py +201 -0
  743. decnet/web/router/topology/api_get_topology.py +69 -0
  744. decnet/web/router/topology/api_lan_crud.py +153 -0
  745. decnet/web/router/topology/api_list_topologies.py +40 -0
  746. decnet/web/router/topology/api_mutations.py +128 -0
  747. decnet/web/router/topology/api_personas.py +132 -0
  748. decnet/web/router/topology/api_reap_orphans.py +49 -0
  749. decnet/web/router/topology/api_tarpit.py +210 -0
  750. decnet/web/router/topology/api_teardown_topology.py +80 -0
  751. decnet/web/router/transcripts/__init__.py +7 -0
  752. decnet/web/router/transcripts/api_get_transcript.py +181 -0
  753. decnet/web/router/ttp/__init__.py +7 -0
  754. decnet/web/router/ttp/api_export_navigator.py +71 -0
  755. decnet/web/router/ttp/api_get_by_attacker.py +36 -0
  756. decnet/web/router/ttp/api_get_by_campaign.py +32 -0
  757. decnet/web/router/ttp/api_get_by_identity.py +36 -0
  758. decnet/web/router/ttp/api_get_by_session.py +32 -0
  759. decnet/web/router/ttp/api_get_groups_for_technique.py +51 -0
  760. decnet/web/router/ttp/api_get_rules.py +155 -0
  761. decnet/web/router/ttp/api_get_tag_details.py +83 -0
  762. decnet/web/router/ttp/api_get_techniques.py +35 -0
  763. decnet/web/router/webhooks/__init__.py +19 -0
  764. decnet/web/router/webhooks/api_manage_webhooks.py +255 -0
  765. decnet/web/router/webhooks/api_test_webhook.py +61 -0
  766. decnet/web/router/workers/__init__.py +1 -0
  767. decnet/web/router/workers/api_control_worker.py +77 -0
  768. decnet/web/router/workers/api_list_workers.py +36 -0
  769. decnet/web/router/workers/api_start_all_workers.py +104 -0
  770. decnet/web/router/workers/api_start_worker.py +73 -0
  771. decnet/web/services/__init__.py +1 -0
  772. decnet/web/services/systemd_control.py +137 -0
  773. decnet/web/sse_limits.py +66 -0
  774. decnet/web/swarm_api.py +68 -0
  775. decnet/web/worker_registry.py +212 -0
  776. decnet/webhook/__init__.py +5 -0
  777. decnet/webhook/client.py +249 -0
  778. decnet/webhook/enums.py +55 -0
  779. decnet/webhook/ssrf.py +151 -0
  780. decnet/webhook/worker.py +313 -0
  781. decnet-1.0.0.dist-info/METADATA +935 -0
  782. decnet-1.0.0.dist-info/RECORD +786 -0
  783. decnet-1.0.0.dist-info/WHEEL +5 -0
  784. decnet-1.0.0.dist-info/entry_points.txt +2 -0
  785. decnet-1.0.0.dist-info/licenses/LICENSE +661 -0
  786. decnet-1.0.0.dist-info/top_level.txt +1 -0
decnet/__init__.py ADDED
@@ -0,0 +1,13 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ """DECNET — honeypot deception-network framework.
3
+
4
+ This __init__ runs once, on the first `import decnet.*`. It seeds
5
+ os.environ from /etc/decnet/decnet.ini (if present) so that later
6
+ module-level reads in decnet.env pick up the INI values as if they had
7
+ been exported by the shell. Real env vars always win via setdefault().
8
+
9
+ Kept minimal on purpose — any heavier work belongs in a submodule.
10
+ """
11
+ from decnet.config_ini import load_ini_config as _load_ini_config
12
+
13
+ _load_ini_config()
@@ -0,0 +1,8 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ """DECNET worker agent — runs on every SWARM worker host.
3
+
4
+ Exposes an mTLS-protected FastAPI service the master's SWARM controller
5
+ calls to deploy, mutate, and tear down deckies locally. The agent reuses
6
+ the existing `decnet.engine.deployer` code path unchanged, so a worker runs
7
+ deckies the same way `decnet deploy --mode unihost` does today.
8
+ """
decnet/agent/app.py ADDED
@@ -0,0 +1,366 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ """Worker-side FastAPI app.
3
+
4
+ Protected by mTLS at the ASGI/uvicorn transport layer: uvicorn is started
5
+ with ``--ssl-ca-certs`` + ``--ssl-cert-reqs 2`` (CERT_REQUIRED), so any
6
+ client that cannot prove a cert signed by the DECNET CA is rejected before
7
+ reaching a handler. Once past the TLS handshake, all peers are trusted
8
+ equally (the only entity holding a CA-signed cert is the master
9
+ controller).
10
+
11
+ Endpoints mirror the existing unihost CLI verbs:
12
+
13
+ * ``POST /deploy`` — body: serialized ``DecnetConfig``
14
+ * ``POST /teardown`` — body: optional ``{"decky_id": "..."}``
15
+ * ``POST /mutate`` — body: ``{"decky_id": "...", "services": [...]}``
16
+ * ``GET /status`` — deployment snapshot
17
+ * ``GET /health`` — liveness probe, does NOT require mTLS? No — mTLS
18
+ still required; master pings it with its cert.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import asyncio
23
+ import os
24
+ import pathlib
25
+ from contextlib import asynccontextmanager
26
+ from typing import Any, Optional
27
+
28
+ from fastapi import FastAPI, HTTPException
29
+ from fastapi.responses import JSONResponse
30
+ from pydantic import BaseModel, Field
31
+
32
+ import contextlib
33
+
34
+ from decnet.agent import executor as _exec
35
+ from decnet.agent import heartbeat as _heartbeat
36
+ from decnet.agent import topology_ops as _topology_ops
37
+ from decnet.bus.factory import get_bus
38
+ from decnet.bus.publish import run_health_heartbeat
39
+ from decnet.swarm.pki import DEFAULT_AGENT_DIR
40
+ from decnet.agent.topology_store import AlreadyApplied, TopologyStore
41
+ from decnet.config import DecnetConfig
42
+ from decnet.logging import get_logger
43
+ from decnet.topology.validate import ValidationError
44
+
45
+ log = get_logger("agent.app")
46
+
47
+
48
+ def _resolve_agent_dir() -> pathlib.Path:
49
+ env = os.environ.get("DECNET_AGENT_DIR")
50
+ if env:
51
+ return pathlib.Path(env)
52
+ system = pathlib.Path("/etc/decnet/agent")
53
+ if system.exists():
54
+ return system
55
+ return DEFAULT_AGENT_DIR
56
+
57
+
58
+ # Module-level singleton. Created lazily on first use so tests can
59
+ # monkeypatch DECNET_AGENT_DIR before the store binds to a path.
60
+ _topology_store: Optional[TopologyStore] = None
61
+
62
+
63
+ def _store() -> TopologyStore:
64
+ global _topology_store
65
+ if _topology_store is None:
66
+ _topology_store = TopologyStore(_resolve_agent_dir() / "topology.db")
67
+ return _topology_store
68
+
69
+
70
+ _collector_task: Optional[asyncio.Task] = None
71
+
72
+
73
+ def _ensure_collector_started() -> None:
74
+ """Spawn the log collector on demand — called from /topology/apply
75
+ after a successful materialise. We must NOT start this in the
76
+ lifespan hook: the agent's boot invariant is "never touch docker
77
+ until master tells us to" (see tests/swarm/test_agent_no_auto_restore.py).
78
+
79
+ The collector watches ``decnet.topology.service=true`` labels via
80
+ docker events, writing RFC 5424 lines to ``DECNET_AGENT_LOG_FILE``
81
+ which the forwarder ships to the master over syslog-TLS. Idempotent:
82
+ subsequent calls while the task is still running are no-ops.
83
+ """
84
+ global _collector_task
85
+ if _collector_task is not None and not _collector_task.done():
86
+ return
87
+ from decnet.env import DECNET_AGENT_LOG_FILE
88
+
89
+ try:
90
+ from decnet.collector.worker import log_collector_worker
91
+ except Exception: # noqa: BLE001 — docker may be unavailable on dev
92
+ log.warning(
93
+ "agent log collector not starting — collector worker import failed",
94
+ exc_info=True,
95
+ )
96
+ return
97
+ _collector_task = asyncio.create_task(
98
+ log_collector_worker(DECNET_AGENT_LOG_FILE),
99
+ name="agent-log-collector",
100
+ )
101
+ log.info("agent log collector started log_file=%s", DECNET_AGENT_LOG_FILE)
102
+
103
+
104
+ _bus_heartbeat_task: Optional[asyncio.Task] = None
105
+
106
+
107
+ @asynccontextmanager
108
+ async def _lifespan(app: FastAPI):
109
+ # Best-effort: if identity/bundle plumbing isn't configured (e.g. dev
110
+ # runs or non-enrolled hosts), heartbeat.start() is a silent no-op.
111
+ _heartbeat.start()
112
+
113
+ # Host-local bus heartbeat (system.agent.health). Separate channel
114
+ # from the mTLS master-facing heartbeat above; this one lets peers on
115
+ # the same host (dashboard, updater) see the agent is alive without
116
+ # hitting its HTTPS endpoint. Bus-disabled path is a no-op loop.
117
+ bus = None
118
+ try:
119
+ bus = get_bus(client_name="agent")
120
+ await bus.connect()
121
+ except Exception as exc: # noqa: BLE001
122
+ log.warning("agent: bus unavailable, skipping health heartbeat: %s", exc)
123
+ bus = None
124
+
125
+ global _bus_heartbeat_task
126
+ _bus_heartbeat_task = asyncio.create_task(
127
+ run_health_heartbeat(bus, "agent"),
128
+ name="agent-bus-heartbeat",
129
+ )
130
+
131
+ try:
132
+ yield
133
+ finally:
134
+ await _heartbeat.stop()
135
+ if _bus_heartbeat_task is not None:
136
+ _bus_heartbeat_task.cancel()
137
+ with contextlib.suppress(asyncio.CancelledError, Exception):
138
+ await _bus_heartbeat_task
139
+ _bus_heartbeat_task = None
140
+ if bus is not None:
141
+ with contextlib.suppress(Exception):
142
+ await bus.close()
143
+ global _collector_task
144
+ if _collector_task is not None and not _collector_task.done():
145
+ _collector_task.cancel()
146
+ try:
147
+ await _collector_task
148
+ except (asyncio.CancelledError, Exception): # noqa: BLE001
149
+ pass
150
+ _collector_task = None
151
+ global _topology_store
152
+ if _topology_store is not None:
153
+ _topology_store.close()
154
+ _topology_store = None
155
+
156
+
157
+ app = FastAPI(
158
+ title="DECNET SWARM Agent",
159
+ version="0.1.0",
160
+ docs_url=None, # no interactive docs on worker — narrow attack surface
161
+ redoc_url=None,
162
+ openapi_url=None,
163
+ lifespan=_lifespan,
164
+ responses={
165
+ 400: {"description": "Malformed request body"},
166
+ 500: {"description": "Executor error"},
167
+ },
168
+ )
169
+
170
+
171
+ # ------------------------------------------------------------------ schemas
172
+
173
+ class DeployRequest(BaseModel):
174
+ config: DecnetConfig = Field(..., description="Full DecnetConfig to materialise on this worker")
175
+ dry_run: bool = False
176
+ no_cache: bool = False
177
+
178
+
179
+ class TeardownRequest(BaseModel):
180
+ decky_id: Optional[str] = None
181
+
182
+
183
+ class MutateRequest(BaseModel):
184
+ decky_id: str
185
+ services: list[str]
186
+ dry_run: bool = False
187
+
188
+
189
+ # ------------------------------------------------------------------ routes
190
+
191
+ @app.get("/health")
192
+ async def health() -> dict[str, str]:
193
+ return {"status": "ok"}
194
+
195
+
196
+ @app.get("/status")
197
+ async def status() -> dict:
198
+ return await _exec.status()
199
+
200
+
201
+ @app.post(
202
+ "/deploy",
203
+ status_code=202,
204
+ responses={202: {"description": "Deploy accepted; runs in background; lifecycle deltas pushed via heartbeat"}},
205
+ )
206
+ async def deploy(req: DeployRequest) -> dict:
207
+ """Spawn the deploy in the background and return 202 immediately.
208
+
209
+ The master tracks per-decky completion via lifecycle deltas pushed on
210
+ the next heartbeat (one immediate push on completion, plus the
211
+ scheduled 30 s ticks as a fallback). Holding the request open across
212
+ a multi-minute compose build was the previous source of the wizard
213
+ API-hang."""
214
+ asyncio.create_task(
215
+ _exec.deploy_async(req.config, dry_run=req.dry_run, no_cache=req.no_cache),
216
+ name=f"deploy-{id(req)}",
217
+ )
218
+ return {"status": "accepted", "deckies": [d.name for d in req.config.deckies]}
219
+
220
+
221
+ @app.post(
222
+ "/teardown",
223
+ responses={500: {"description": "Teardown raised an exception"}},
224
+ )
225
+ async def teardown(req: TeardownRequest) -> dict:
226
+ try:
227
+ await _exec.teardown(req.decky_id)
228
+ except Exception as exc:
229
+ log.exception("agent.teardown failed")
230
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
231
+ return {"status": "torn_down", "decky_id": req.decky_id}
232
+
233
+
234
+ @app.post(
235
+ "/self-destruct",
236
+ responses={500: {"description": "Reaper could not be scheduled"}},
237
+ )
238
+ async def self_destruct() -> dict:
239
+ """Stop all DECNET services on this worker and delete the install
240
+ footprint. Called by the master during decommission. Logs under
241
+ /var/log/decnet* are preserved. Fire-and-forget — returns 202 before
242
+ the reaper starts deleting files."""
243
+ try:
244
+ await _exec.self_destruct()
245
+ except Exception as exc:
246
+ log.exception("agent.self_destruct failed")
247
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
248
+ return {"status": "self_destruct_scheduled"}
249
+
250
+
251
+ # ------------------------------------------------------- topology endpoints
252
+
253
+
254
+ class ApplyTopologyRequest(BaseModel):
255
+ hydrated: dict[str, Any] = Field(
256
+ ..., description="Hydrated topology dict from master.persistence.hydrate()"
257
+ )
258
+ version_hash: str = Field(
259
+ ..., description="Master's canonical_hash(hydrated); must match ours"
260
+ )
261
+
262
+
263
+ class TeardownTopologyRequest(BaseModel):
264
+ topology_id: str = Field(..., description="Topology UUID to dismantle")
265
+
266
+
267
+ @app.post(
268
+ "/topology/apply",
269
+ responses={
270
+ 400: {"description": "Malformed hydrated topology or hash mismatch"},
271
+ 409: {"description": "A different topology is already applied"},
272
+ 500: {"description": "Docker or compose raised while applying"},
273
+ },
274
+ )
275
+ async def topology_apply(req: ApplyTopologyRequest) -> dict:
276
+ store = _store()
277
+ try:
278
+ await _topology_ops.apply(req.hydrated, req.version_hash, store)
279
+ except _topology_ops.HashMismatch as exc:
280
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
281
+ except ValidationError as exc:
282
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
283
+ except AlreadyApplied as exc:
284
+ raise HTTPException(status_code=409, detail=str(exc)) from exc
285
+ except Exception as exc:
286
+ log.exception("agent.topology_apply failed")
287
+ topology_id = (req.hydrated.get("topology") or {}).get("id")
288
+ if topology_id:
289
+ try:
290
+ store.record_error(
291
+ str(topology_id), str(exc)[:500], hydrated=req.hydrated,
292
+ )
293
+ except Exception: # noqa: BLE001 — don't mask original failure
294
+ log.exception("failed to record apply error")
295
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
296
+ _ensure_collector_started()
297
+ return {"status": "applied", "version_hash": req.version_hash}
298
+
299
+
300
+ @app.post(
301
+ "/topology/teardown",
302
+ responses={500: {"description": "Docker or compose raised while tearing down"}},
303
+ )
304
+ async def topology_teardown(req: TeardownTopologyRequest) -> dict:
305
+ try:
306
+ await _topology_ops.teardown(req.topology_id, _store())
307
+ except Exception as exc:
308
+ log.exception("agent.topology_teardown failed")
309
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
310
+ return {"status": "torn_down", "topology_id": req.topology_id}
311
+
312
+
313
+ @app.get("/topology/state")
314
+ async def topology_state() -> dict:
315
+ return _topology_ops.state(_store())
316
+
317
+
318
+ @app.post(
319
+ "/mutate",
320
+ status_code=202,
321
+ responses={
322
+ 202: {"description": "Mutate accepted; runs in background; lifecycle delta pushed via heartbeat"},
323
+ 404: {"description": "No active deployment, or unknown decky_id (dry_run validation only)"},
324
+ },
325
+ )
326
+ async def mutate(req: MutateRequest) -> Any:
327
+ """Spawn the mutate in the background and return 202 immediately.
328
+
329
+ Master tracks completion via a lifecycle delta pushed on the next
330
+ heartbeat (immediate push on completion). ``dry_run`` is still
331
+ synchronous — it validates against the worker's current state and
332
+ returns the would-be services without spawning a task or touching
333
+ docker, so the wizard's preview path stays cheap."""
334
+ if req.dry_run:
335
+ from decnet.config import load_state
336
+ state = load_state()
337
+ if state is None:
338
+ raise HTTPException(
339
+ status_code=404,
340
+ detail="no active deployment on this worker",
341
+ )
342
+ cfg, _ = state
343
+ decky = next((d for d in cfg.deckies if d.name == req.decky_id), None)
344
+ if decky is None:
345
+ raise HTTPException(
346
+ status_code=404,
347
+ detail=f"decky {req.decky_id!r} not found in worker state",
348
+ )
349
+ return JSONResponse(
350
+ status_code=200,
351
+ content={
352
+ "status": "dry_run",
353
+ "decky_id": req.decky_id,
354
+ "services": list(req.services),
355
+ },
356
+ )
357
+
358
+ asyncio.create_task(
359
+ _exec.mutate_async(req.decky_id, list(req.services)),
360
+ name=f"mutate-{req.decky_id}",
361
+ )
362
+ return {
363
+ "status": "accepted",
364
+ "decky_id": req.decky_id,
365
+ "services": list(req.services),
366
+ }