js7-client-python 2.0.1__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 (389) hide show
  1. js7/__init__.py +8 -0
  2. js7/api/joc/http/v_2_8_2/agent/cluster/confirm_node_loss.py +36 -0
  3. js7/api/joc/http/v_2_8_2/agent/cluster/switchover.py +36 -0
  4. js7/api/joc/http/v_2_8_2/agent/delete.py +36 -0
  5. js7/api/joc/http/v_2_8_2/agents/agents.py +36 -0
  6. js7/api/joc/http/v_2_8_2/agents/cluster/delete.py +36 -0
  7. js7/api/joc/http/v_2_8_2/agents/cluster/deploy.py +36 -0
  8. js7/api/joc/http/v_2_8_2/agents/cluster/revoke.py +36 -0
  9. js7/api/joc/http/v_2_8_2/agents/cluster/store.py +36 -0
  10. js7/api/joc/http/v_2_8_2/agents/export.py +36 -0
  11. js7/api/joc/http/v_2_8_2/agents/import.py +74 -0
  12. js7/api/joc/http/v_2_8_2/agents/inventory/cluster/deploy.py +36 -0
  13. js7/api/joc/http/v_2_8_2/agents/inventory/cluster/revoke.py +36 -0
  14. js7/api/joc/http/v_2_8_2/agents/inventory/cluster/store.py +36 -0
  15. js7/api/joc/http/v_2_8_2/agents/inventory/cluster/subagents/delete.py +36 -0
  16. js7/api/joc/http/v_2_8_2/agents/inventory/cluster/subagents/disable.py +36 -0
  17. js7/api/joc/http/v_2_8_2/agents/inventory/cluster/subagents/enable.py +36 -0
  18. js7/api/joc/http/v_2_8_2/agents/inventory/cluster/subagents/reset.py +36 -0
  19. js7/api/joc/http/v_2_8_2/agents/inventory/cluster/subagents/store.py +36 -0
  20. js7/api/joc/http/v_2_8_2/agents/inventory/deploy.py +36 -0
  21. js7/api/joc/http/v_2_8_2/agents/inventory/disable.py +36 -0
  22. js7/api/joc/http/v_2_8_2/agents/inventory/enable.py +36 -0
  23. js7/api/joc/http/v_2_8_2/agents/inventory/revoke.py +36 -0
  24. js7/api/joc/http/v_2_8_2/agents/inventory/store.py +36 -0
  25. js7/api/joc/http/v_2_8_2/agents/reset.py +36 -0
  26. js7/api/joc/http/v_2_8_2/authentication/auth.py +32 -0
  27. js7/api/joc/http/v_2_8_2/authentication/joc_cockpit_permissions.py +28 -0
  28. js7/api/joc/http/v_2_8_2/authentication/login.py +35 -0
  29. js7/api/joc/http/v_2_8_2/authentication/logout.py +28 -0
  30. js7/api/joc/http/v_2_8_2/configuration/configuration.py +36 -0
  31. js7/api/joc/http/v_2_8_2/configuration/save.py +36 -0
  32. js7/api/joc/http/v_2_8_2/controller/abort.py +36 -0
  33. js7/api/joc/http/v_2_8_2/controller/abort_and_restart.py +36 -0
  34. js7/api/joc/http/v_2_8_2/controller/cluster/appoint_nodes.py +36 -0
  35. js7/api/joc/http/v_2_8_2/controller/cluster/confirm_node_loss.py +36 -0
  36. js7/api/joc/http/v_2_8_2/controller/cluster/switchover.py +36 -0
  37. js7/api/joc/http/v_2_8_2/controller/components.py +36 -0
  38. js7/api/joc/http/v_2_8_2/controller/controller.py +36 -0
  39. js7/api/joc/http/v_2_8_2/controller/register.py +42 -0
  40. js7/api/joc/http/v_2_8_2/controller/restart.py +36 -0
  41. js7/api/joc/http/v_2_8_2/controller/terminate.py +36 -0
  42. js7/api/joc/http/v_2_8_2/controller/test.py +36 -0
  43. js7/api/joc/http/v_2_8_2/controller/unregister.py +36 -0
  44. js7/api/joc/http/v_2_8_2/daily_plan/orders/cancel.py +36 -0
  45. js7/api/joc/http/v_2_8_2/daily_plan/orders/copy.py +36 -0
  46. js7/api/joc/http/v_2_8_2/daily_plan/orders/delete.py +36 -0
  47. js7/api/joc/http/v_2_8_2/daily_plan/orders/generate.py +36 -0
  48. js7/api/joc/http/v_2_8_2/daily_plan/orders/modify.py +36 -0
  49. js7/api/joc/http/v_2_8_2/daily_plan/orders/orders.py +36 -0
  50. js7/api/joc/http/v_2_8_2/daily_plan/orders/submit.py +36 -0
  51. js7/api/joc/http/v_2_8_2/daily_plan/projections/calendar.py +36 -0
  52. js7/api/joc/http/v_2_8_2/daily_plan/projections/dates.py +36 -0
  53. js7/api/joc/http/v_2_8_2/daily_plan/projections/recreate.py +28 -0
  54. js7/api/joc/http/v_2_8_2/daily_plan/submissions/delete.py +36 -0
  55. js7/api/joc/http/v_2_8_2/iam/account/change_password.py +36 -0
  56. js7/api/joc/http/v_2_8_2/iam/account/permissions.py +36 -0
  57. js7/api/joc/http/v_2_8_2/iam/account/rename.py +36 -0
  58. js7/api/joc/http/v_2_8_2/iam/account/store.py +36 -0
  59. js7/api/joc/http/v_2_8_2/iam/accounts/accounts.py +36 -0
  60. js7/api/joc/http/v_2_8_2/iam/accounts/delete.py +36 -0
  61. js7/api/joc/http/v_2_8_2/iam/accounts/disable.py +36 -0
  62. js7/api/joc/http/v_2_8_2/iam/accounts/enable.py +36 -0
  63. js7/api/joc/http/v_2_8_2/iam/accounts/reset_password.py +36 -0
  64. js7/api/joc/http/v_2_8_2/iam/blocked_account/store.py +36 -0
  65. js7/api/joc/http/v_2_8_2/iam/blocked_accounts/blocked_accounts.py +36 -0
  66. js7/api/joc/http/v_2_8_2/iam/blocked_accounts/delete.py +36 -0
  67. js7/api/joc/http/v_2_8_2/iam/folder/folder.py +36 -0
  68. js7/api/joc/http/v_2_8_2/iam/folder/rename.py +36 -0
  69. js7/api/joc/http/v_2_8_2/iam/folders/delete.py +36 -0
  70. js7/api/joc/http/v_2_8_2/iam/folders/folders.py +36 -0
  71. js7/api/joc/http/v_2_8_2/iam/folders/store.py +36 -0
  72. js7/api/joc/http/v_2_8_2/iam/identity_service/delete.py +36 -0
  73. js7/api/joc/http/v_2_8_2/iam/identity_service/identity_service.py +36 -0
  74. js7/api/joc/http/v_2_8_2/iam/identity_service/rename.py +36 -0
  75. js7/api/joc/http/v_2_8_2/iam/identity_service/store.py +42 -0
  76. js7/api/joc/http/v_2_8_2/iam/identity_services/identity_services.py +36 -0
  77. js7/api/joc/http/v_2_8_2/iam/permission/permission.py +36 -0
  78. js7/api/joc/http/v_2_8_2/iam/permission/rename.py +36 -0
  79. js7/api/joc/http/v_2_8_2/iam/permissions/delete.py +36 -0
  80. js7/api/joc/http/v_2_8_2/iam/permissions/permissions.py +36 -0
  81. js7/api/joc/http/v_2_8_2/iam/permissions/store.py +36 -0
  82. js7/api/joc/http/v_2_8_2/iam/role/rename.py +36 -0
  83. js7/api/joc/http/v_2_8_2/iam/role/role.py +36 -0
  84. js7/api/joc/http/v_2_8_2/iam/role/store.py +36 -0
  85. js7/api/joc/http/v_2_8_2/iam/roles/delete.py +36 -0
  86. js7/api/joc/http/v_2_8_2/iam/roles/roles.py +36 -0
  87. js7/api/joc/http/v_2_8_2/inventory/changes/changes.py +36 -0
  88. js7/api/joc/http/v_2_8_2/inventory/dependencies.py +33 -0
  89. js7/api/joc/http/v_2_8_2/inventory/deployment/deploy.py +36 -0
  90. js7/api/joc/http/v_2_8_2/inventory/deployment/import_deploy.py +66 -0
  91. js7/api/joc/http/v_2_8_2/inventory/deployment/revoke.py +36 -0
  92. js7/api/joc/http/v_2_8_2/inventory/export/export.py +36 -0
  93. js7/api/joc/http/v_2_8_2/inventory/export/folder.py +36 -0
  94. js7/api/joc/http/v_2_8_2/inventory/import_objects.py +88 -0
  95. js7/api/joc/http/v_2_8_2/inventory/releasables/recall/folder.py +36 -0
  96. js7/api/joc/http/v_2_8_2/inventory/releasables/recall/recall.py +36 -0
  97. js7/api/joc/http/v_2_8_2/inventory/release.py +36 -0
  98. js7/api/joc/http/v_2_8_2/inventory/remove/folder.py +36 -0
  99. js7/api/joc/http/v_2_8_2/inventory/remove/remove.py +36 -0
  100. js7/api/joc/http/v_2_8_2/inventory/repository/delete.py +36 -0
  101. js7/api/joc/http/v_2_8_2/inventory/repository/git/add.py +36 -0
  102. js7/api/joc/http/v_2_8_2/inventory/repository/git/checkout.py +36 -0
  103. js7/api/joc/http/v_2_8_2/inventory/repository/git/clone.py +36 -0
  104. js7/api/joc/http/v_2_8_2/inventory/repository/git/commit.py +36 -0
  105. js7/api/joc/http/v_2_8_2/inventory/repository/git/credentials/add.py +36 -0
  106. js7/api/joc/http/v_2_8_2/inventory/repository/git/credentials/credentials.py +28 -0
  107. js7/api/joc/http/v_2_8_2/inventory/repository/git/credentials/remove.py +36 -0
  108. js7/api/joc/http/v_2_8_2/inventory/repository/git/pull.py +36 -0
  109. js7/api/joc/http/v_2_8_2/inventory/repository/git/push.py +36 -0
  110. js7/api/joc/http/v_2_8_2/inventory/repository/read.py +36 -0
  111. js7/api/joc/http/v_2_8_2/inventory/repository/store.py +36 -0
  112. js7/api/joc/http/v_2_8_2/inventory/repository/update.py +36 -0
  113. js7/api/joc/http/v_2_8_2/inventory/revalidate/folder.py +36 -0
  114. js7/api/joc/http/v_2_8_2/inventory/store.py +36 -0
  115. js7/api/joc/http/v_2_8_2/inventory/trash/delete/delete.py +36 -0
  116. js7/api/joc/http/v_2_8_2/inventory/trash/delete/folder.py +36 -0
  117. js7/api/joc/http/v_2_8_2/inventory/trash/restore.py +36 -0
  118. js7/api/joc/http/v_2_8_2/inventory/validate.py +42 -0
  119. js7/api/joc/http/v_2_8_2/joc/cluster/restart.py +36 -0
  120. js7/api/joc/http/v_2_8_2/joc/cluster/run.py +36 -0
  121. js7/api/joc/http/v_2_8_2/joc/cluster/switch_member.py +36 -0
  122. js7/api/joc/http/v_2_8_2/joc/license.py +28 -0
  123. js7/api/joc/http/v_2_8_2/joc/proxies/restart.py +36 -0
  124. js7/api/joc/http/v_2_8_2/joc/version.py +28 -0
  125. js7/api/joc/http/v_2_8_2/joc/versions.py +36 -0
  126. js7/api/joc/http/v_2_8_2/orders/add.py +33 -0
  127. js7/api/joc/http/v_2_8_2/orders/cancel.py +33 -0
  128. js7/api/joc/http/v_2_8_2/orders/confirm.py +36 -0
  129. js7/api/joc/http/v_2_8_2/orders/continue.py +36 -0
  130. js7/api/joc/http/v_2_8_2/orders/history.py +36 -0
  131. js7/api/joc/http/v_2_8_2/orders/orders.py +36 -0
  132. js7/api/joc/http/v_2_8_2/orders/remove_when_terminated.py +33 -0
  133. js7/api/joc/http/v_2_8_2/orders/resume.py +36 -0
  134. js7/api/joc/http/v_2_8_2/orders/suspend.py +36 -0
  135. js7/api/joc/http/v_2_8_2/settings/settings.py +28 -0
  136. js7/api/joc/http/v_2_8_2/settings/store.py +36 -0
  137. js7/api/joc/http/v_2_8_2/tasks/history.py +36 -0
  138. js7/api/joc/http/v_2_8_2/workflow/transition.py +36 -0
  139. js7/api/joc/http/v_2_8_2/workflow/workflow.py +36 -0
  140. js7/api/joc/http/v_2_8_2/workflows/resume.py +36 -0
  141. js7/api/joc/http/v_2_8_2/workflows/skip.py +36 -0
  142. js7/api/joc/http/v_2_8_2/workflows/stop.py +36 -0
  143. js7/api/joc/http/v_2_8_2/workflows/suspend.py +36 -0
  144. js7/api/joc/http/v_2_8_2/workflows/unskip.py +36 -0
  145. js7/api/joc/http/v_2_8_2/workflows/unstop.py +36 -0
  146. js7/api/joc/http/v_2_8_2/workflows/workflows.py +36 -0
  147. js7/api/joc/interface/dispatcher.py +76 -0
  148. js7/api/joc/interface/interface.py +8 -0
  149. js7/api/joc/interface/resolver.py +75 -0
  150. js7/client/action/agent/confirm_node_loss_agent_action.py +75 -0
  151. js7/client/action/agent/delete_subagent_action.py +77 -0
  152. js7/client/action/agent/delete_subagent_clusters_action.py +75 -0
  153. js7/client/action/agent/deploy_cluster_agents_action.py +75 -0
  154. js7/client/action/agent/deploy_standalone_agents_action.py +75 -0
  155. js7/client/action/agent/deploy_subagent_clusters_action.py +75 -0
  156. js7/client/action/agent/disable_standalone_agents_action.py +75 -0
  157. js7/client/action/agent/disable_subagents_action.py +75 -0
  158. js7/client/action/agent/enable_standalone_agents_action.py +75 -0
  159. js7/client/action/agent/enable_subagents_action.py +75 -0
  160. js7/client/action/agent/export_agents_action.py +101 -0
  161. js7/client/action/agent/get_agents_status_action.py +55 -0
  162. js7/client/action/agent/import_agents_action.py +139 -0
  163. js7/client/action/agent/remove_agent_action.py +79 -0
  164. js7/client/action/agent/reset_agents_action.py +79 -0
  165. js7/client/action/agent/reset_subagent_action.py +79 -0
  166. js7/client/action/agent/revoke_cluster_agents_action.py +75 -0
  167. js7/client/action/agent/revoke_standalone_agents_action.py +75 -0
  168. js7/client/action/agent/revoke_subagent_clusters_action.py +75 -0
  169. js7/client/action/agent/store_cluster_agents_action.py +99 -0
  170. js7/client/action/agent/store_standalone_agents_action.py +87 -0
  171. js7/client/action/agent/store_subagent_clusters_action.py +83 -0
  172. js7/client/action/agent/store_subagents_action.py +97 -0
  173. js7/client/action/agent/switchover_agent_action.py +75 -0
  174. js7/client/action/controller/appoint_nodes_controller_action.py +67 -0
  175. js7/client/action/controller/cancel_and_restart_controller_action.py +72 -0
  176. js7/client/action/controller/cancel_controller_action.py +71 -0
  177. js7/client/action/controller/confirm_cluster_node_loss_action.py +68 -0
  178. js7/client/action/controller/get_controller_components_action.py +41 -0
  179. js7/client/action/controller/get_controller_status_action.py +72 -0
  180. js7/client/action/controller/register_controller_action.py +93 -0
  181. js7/client/action/controller/restart_controller_action.py +72 -0
  182. js7/client/action/controller/switchover_controller_cluster_action.py +67 -0
  183. js7/client/action/controller/terminate_controller_action.py +72 -0
  184. js7/client/action/controller/test_controller_instance_action.py +65 -0
  185. js7/client/action/controller/unregister_controller_action.py +68 -0
  186. js7/client/action/daily_plan/cancel_orders_action.py +59 -0
  187. js7/client/action/daily_plan/copy_orders_action.py +108 -0
  188. js7/client/action/daily_plan/create_projections_action.py +24 -0
  189. js7/client/action/daily_plan/delete_orders_action.py +80 -0
  190. js7/client/action/daily_plan/delete_submissions_action.py +83 -0
  191. js7/client/action/daily_plan/generate_orders_action.py +121 -0
  192. js7/client/action/daily_plan/get_calendar_projections_action.py +59 -0
  193. js7/client/action/daily_plan/get_orders_action.py +70 -0
  194. js7/client/action/daily_plan/get_projection_dates_action.py +59 -0
  195. js7/client/action/daily_plan/modify_orders_action.py +130 -0
  196. js7/client/action/daily_plan/submit_orders_action.py +79 -0
  197. js7/client/action/helper/decrypt_action.py +82 -0
  198. js7/client/action/helper/encrypt_action.py +87 -0
  199. js7/client/action/iam/block_account_action.py +71 -0
  200. js7/client/action/iam/change_account_password_action.py +96 -0
  201. js7/client/action/iam/disable_accounts_action.py +75 -0
  202. js7/client/action/iam/enable_accounts_action.py +75 -0
  203. js7/client/action/iam/get_account_permissions_action.py +75 -0
  204. js7/client/action/iam/get_accounts_action.py +76 -0
  205. js7/client/action/iam/get_blocked_accounts_action.py +76 -0
  206. js7/client/action/iam/get_folder_permissions_action.py +112 -0
  207. js7/client/action/iam/get_identity_service_settings_action.py +70 -0
  208. js7/client/action/iam/get_identity_services_action.py +102 -0
  209. js7/client/action/iam/get_permissions_action.py +113 -0
  210. js7/client/action/iam/get_roles_action.py +57 -0
  211. js7/client/action/iam/remove_accounts_action.py +75 -0
  212. js7/client/action/iam/remove_folder_permissions_action.py +91 -0
  213. js7/client/action/iam/remove_identity_service_action.py +67 -0
  214. js7/client/action/iam/remove_permissions_action.py +88 -0
  215. js7/client/action/iam/remove_roles_action.py +75 -0
  216. js7/client/action/iam/rename_account_action.py +83 -0
  217. js7/client/action/iam/rename_folder_permissions_action.py +100 -0
  218. js7/client/action/iam/rename_identity_service_action.py +75 -0
  219. js7/client/action/iam/rename_permission_action.py +103 -0
  220. js7/client/action/iam/rename_role_action.py +83 -0
  221. js7/client/action/iam/reset_account_passwords_action.py +75 -0
  222. js7/client/action/iam/set_folder_permissions_action.py +96 -0
  223. js7/client/action/iam/set_permissions_action.py +91 -0
  224. js7/client/action/iam/store_account_action.py +69 -0
  225. js7/client/action/iam/store_identity_service_action.py +75 -0
  226. js7/client/action/iam/store_identity_service_settings_action.py +74 -0
  227. js7/client/action/iam/store_role_action.py +79 -0
  228. js7/client/action/iam/unblock_accounts_action.py +67 -0
  229. js7/client/action/inventory/deploy_configurations_action.py +138 -0
  230. js7/client/action/inventory/export_configurations_action.py +203 -0
  231. js7/client/action/inventory/export_folders_action.py +160 -0
  232. js7/client/action/inventory/get_change_dependencies_action.py +161 -0
  233. js7/client/action/inventory/get_changes_action.py +59 -0
  234. js7/client/action/inventory/get_git_credentials_action.py +29 -0
  235. js7/client/action/inventory/git_add_action.py +72 -0
  236. js7/client/action/inventory/git_checkout_action.py +88 -0
  237. js7/client/action/inventory/git_clone_action.py +84 -0
  238. js7/client/action/inventory/git_commit_action.py +80 -0
  239. js7/client/action/inventory/git_pull_action.py +72 -0
  240. js7/client/action/inventory/git_push_action.py +76 -0
  241. js7/client/action/inventory/import_configurations_action.py +153 -0
  242. js7/client/action/inventory/import_deploy_configurations_action.py +188 -0
  243. js7/client/action/inventory/read_from_local_repository_action.py +67 -0
  244. js7/client/action/inventory/recall_folder_action.py +89 -0
  245. js7/client/action/inventory/recall_released_configuration_action.py +75 -0
  246. js7/client/action/inventory/release_configuartions_action.py +89 -0
  247. js7/client/action/inventory/remove_configurations_action.py +77 -0
  248. js7/client/action/inventory/remove_configurations_from_trash_action.py +80 -0
  249. js7/client/action/inventory/remove_folder_action.py +67 -0
  250. js7/client/action/inventory/remove_folder_from_trash_action.py +69 -0
  251. js7/client/action/inventory/remove_git_credentials_action.py +53 -0
  252. js7/client/action/inventory/remove_repository_configuration_action.py +84 -0
  253. js7/client/action/inventory/restore_configuration_from_trash_action.py +84 -0
  254. js7/client/action/inventory/revalidate_folder_action.py +46 -0
  255. js7/client/action/inventory/revoke_configurations_action.py +86 -0
  256. js7/client/action/inventory/store_configuration_action.py +79 -0
  257. js7/client/action/inventory/store_git_credentials_action.py +99 -0
  258. js7/client/action/inventory/store_repository_configuration_action.py +124 -0
  259. js7/client/action/inventory/update_repository_configuration_action.py +85 -0
  260. js7/client/action/inventory/validate_configuration_action.py +58 -0
  261. js7/client/action/joc/get_components_versions_action.py +57 -0
  262. js7/client/action/joc/get_license_info_action.py +22 -0
  263. js7/client/action/joc/get_settings_action.py +19 -0
  264. js7/client/action/joc/get_version_action.py +17 -0
  265. js7/client/action/joc/restart_proxies_action.py +50 -0
  266. js7/client/action/joc/restart_service_action.py +74 -0
  267. js7/client/action/joc/run_service_action.py +74 -0
  268. js7/client/action/joc/store_settings_action.py +62 -0
  269. js7/client/action/joc/switch_over_action.py +89 -0
  270. js7/client/action/order/add_orders_action.py +115 -0
  271. js7/client/action/order/cancel_orders_action.py +93 -0
  272. js7/client/action/order/confirm_orders_action.py +86 -0
  273. js7/client/action/order/continue_orders_action.py +86 -0
  274. js7/client/action/order/get_order_history_action.py +84 -0
  275. js7/client/action/order/get_orders_action.py +83 -0
  276. js7/client/action/order/remove_terminated_orders_action.py +86 -0
  277. js7/client/action/order/resume_orders_action.py +102 -0
  278. js7/client/action/order/suspend_orders_action.py +97 -0
  279. js7/client/action/task/get_task_history_info_action.py +88 -0
  280. js7/client/action/workflow/get_workflow_versions_action.py +131 -0
  281. js7/client/action/workflow/resume_workflows_action.py +76 -0
  282. js7/client/action/workflow/set_workflow_version_as_current_action.py +86 -0
  283. js7/client/action/workflow/skip_job_instructions_action.py +83 -0
  284. js7/client/action/workflow/stop_job_instructions_action.py +83 -0
  285. js7/client/action/workflow/suspend_workflows_action.py +76 -0
  286. js7/client/action/workflow/unskip_job_instructions_action.py +83 -0
  287. js7/client/action/workflow/unstop_job_instructions_action.py +79 -0
  288. js7/client/auth/auth_provider.py +109 -0
  289. js7/client/auth/login.py +34 -0
  290. js7/client/auth/logout.py +22 -0
  291. js7/client/client.py +250 -0
  292. js7/client/context.py +40 -0
  293. js7/client/feature/agent/agent.py +26 -0
  294. js7/client/feature/agent/deploy.py +134 -0
  295. js7/client/feature/agent/manage.py +363 -0
  296. js7/client/feature/agent/operate.py +577 -0
  297. js7/client/feature/controller/controller.py +19 -0
  298. js7/client/feature/controller/manage.py +214 -0
  299. js7/client/feature/controller/operate.py +274 -0
  300. js7/client/feature/daily_plan/daily_plan.py +14 -0
  301. js7/client/feature/daily_plan/manage.py +179 -0
  302. js7/client/feature/daily_plan/operate.py +354 -0
  303. js7/client/feature/iam/iam.py +14 -0
  304. js7/client/feature/iam/manage.py +1311 -0
  305. js7/client/feature/inventory/inventory.py +13 -0
  306. js7/client/feature/inventory/manage.py +943 -0
  307. js7/client/feature/inventory/manage_repository.py +533 -0
  308. js7/client/feature/joc/joc.py +18 -0
  309. js7/client/feature/joc/manage.py +102 -0
  310. js7/client/feature/joc/operate.py +185 -0
  311. js7/client/feature/order/manage.py +79 -0
  312. js7/client/feature/order/operate.py +346 -0
  313. js7/client/feature/order/order.py +18 -0
  314. js7/client/feature/task/task.py +54 -0
  315. js7/client/feature/workflow/manage.py +54 -0
  316. js7/client/feature/workflow/operate.py +336 -0
  317. js7/client/feature/workflow/workflow.py +19 -0
  318. js7/java/lib/3rd-party/bcpg-jdk15to18-1.78.1.jar +0 -0
  319. js7/java/lib/3rd-party/bcpkix-jdk15to18-1.78.1.jar +0 -0
  320. js7/java/lib/3rd-party/bcprov-jdk15to18-1.78.1.jar +0 -0
  321. js7/java/lib/3rd-party/bcutil-jdk15to18-1.78.1.jar +0 -0
  322. js7/java/lib/3rd-party/commons-io-2.15.1.jar +0 -0
  323. js7/java/lib/3rd-party/commons-lang3-3.14.0.jar +0 -0
  324. js7/java/lib/3rd-party/jackson-core-2.14.2.jar +0 -0
  325. js7/java/lib/3rd-party/jackson-databind-2.14.2.jar +0 -0
  326. js7/java/lib/3rd-party/jackson-dataformat-xml-2.14.2.jar +0 -0
  327. js7/java/lib/3rd-party/jakarta.annotation-api-2.1.1.jar +0 -0
  328. js7/java/lib/3rd-party/javax.activation-api-1.2.0.jar +0 -0
  329. js7/java/lib/3rd-party/jaxb-api-2.4.0-b180830.0359.jar +0 -0
  330. js7/java/lib/3rd-party/org.apache.logging.log4j.log4j-api-2.23.1.jar +0 -0
  331. js7/java/lib/3rd-party/org.apache.logging.log4j.log4j-core-2.23.1.jar +0 -0
  332. js7/java/lib/3rd-party/org.apache.logging.log4j.log4j-slf4j2-impl-2.23.1.jar +0 -0
  333. js7/java/lib/3rd-party/org.slf4j.slf4j-api-2.0.13.jar +0 -0
  334. js7/java/lib/3rd-party/stax2-api-4.2.1.jar +0 -0
  335. js7/java/lib/3rd-party/woodstox-core-6.5.0.jar +0 -0
  336. js7/java/lib/sos/sos-commons-encryption-2.7.3.jar +0 -0
  337. js7/java/lib/sos/sos-commons-exception-2.7.3.jar +0 -0
  338. js7/java/lib/sos/sos-commons-sign-2.7.3.jar +0 -0
  339. js7/java/lib/sos/sos-webservices-json-2.7.3.jar +0 -0
  340. js7/model/__init__.py +132 -0
  341. js7/model/configuration/auth_configuration.py +24 -0
  342. js7/model/configuration/client_configuration.py +6 -0
  343. js7/model/configuration/http_configuration.py +10 -0
  344. js7/model/error/http/joc_exceptions.py +151 -0
  345. js7/model/private/api/endpoint.py +30 -0
  346. js7/model/private/http/joc/joc_v_2_8_2.py +3666 -0
  347. js7/model/public/client/common/__init__.py +27 -0
  348. js7/model/public/client/common/accounts.py +21 -0
  349. js7/model/public/client/common/audit_log.py +8 -0
  350. js7/model/public/client/common/changes.py +18 -0
  351. js7/model/public/client/common/configurations.py +53 -0
  352. js7/model/public/client/common/cycle.py +12 -0
  353. js7/model/public/client/common/git_credentials.py +12 -0
  354. js7/model/public/client/common/identity_service.py +14 -0
  355. js7/model/public/client/common/schedule_time.py +50 -0
  356. js7/model/public/client/common/store_agents.py +96 -0
  357. js7/model/public/client/enum/__init__.py +19 -0
  358. js7/model/public/client/enum/object_types.py +48 -0
  359. js7/model/public/client/enum/operation_type.py +11 -0
  360. js7/model/public/client/enum/order_priority.py +9 -0
  361. js7/model/public/client/filter/__init__.py +35 -0
  362. js7/model/public/client/filter/daily_plan_order_filters.py +255 -0
  363. js7/model/public/client/filter/element/__init__.py +3 -0
  364. js7/model/public/client/filter/element/folder.py +6 -0
  365. js7/model/public/client/filter/element/workflow_id.py +10 -0
  366. js7/model/public/client/filter/export_filter.py +52 -0
  367. js7/model/public/client/filter/export_folders_filter.py +34 -0
  368. js7/model/public/client/filter/get_order_filter.py +59 -0
  369. js7/model/public/client/filter/order_history_filter.py +113 -0
  370. js7/model/public/client/filter/resume_order_filter.py +45 -0
  371. js7/model/public/client/filter/suspend_order_filter.py +44 -0
  372. js7/model/public/client/filter/tasks_filter.py +50 -0
  373. js7/model/public/client/input/__init__.py +2 -0
  374. js7/model/public/client/input/add_order.py +50 -0
  375. js7/service/http_service.py +206 -0
  376. js7/util/bytes_converter/bytes_to_archive_bytes.py +52 -0
  377. js7/util/bytes_converter/bytes_to_file.py +12 -0
  378. js7/util/bytes_converter/files_to_bytes.py +52 -0
  379. js7/util/bytes_converter/read_bytes_archive_files_to_bytes.py +69 -0
  380. js7/util/bytes_converter/sign_to_bytes.py +106 -0
  381. js7/util/check_matching_version.py +20 -0
  382. js7/util/detect_archive_type.py +37 -0
  383. js7/util/str_converter/order_id_to_order_name.py +5 -0
  384. js7/validator/http/joc_http_status_validator.py +155 -0
  385. js7_client_python-2.0.1.0.dist-info/LICENSE +674 -0
  386. js7_client_python-2.0.1.0.dist-info/METADATA +763 -0
  387. js7_client_python-2.0.1.0.dist-info/RECORD +389 -0
  388. js7_client_python-2.0.1.0.dist-info/WHEEL +5 -0
  389. js7_client_python-2.0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,50 @@
1
+ from datetime import datetime
2
+ from typing import List, Literal, Optional
3
+ from pydantic import BaseModel
4
+
5
+ from .....model.public.client.filter.element.folder import Folder
6
+
7
+
8
+ class TasksFilter(BaseModel):
9
+ date_from: Optional[datetime] = None
10
+ """Filters items starting from a date."""
11
+
12
+ date_to: Optional[datetime] = None
13
+ """Filters items ending before a date."""
14
+
15
+ completed_date_from: Optional[datetime] = None
16
+ """Filters items starting from a date."""
17
+
18
+ completed_date_to: Optional[datetime] = None
19
+ """Filters items ending before a date."""
20
+
21
+ job_name: Optional[str] = None
22
+ """
23
+ Limits result to a specified glob pattern of a Job name that supports '*' and '?' as wildcards where
24
+ - '*' : match zero or more characters
25
+ - '?' : match any single character
26
+ """
27
+
28
+ workflow_name: Optional[str] = None
29
+ """
30
+ Limits result to a specified glob pattern of a Workflow name that supports '*' and '?' as wildcards where
31
+ - '*' : match zero or more characters
32
+ - '?' : match any single character
33
+ """
34
+
35
+ workflow_paths: Optional[str] = None
36
+ """
37
+ Limits result to a specified glob pattern of a Workflow path that supports '*' and '?' as wildcards where
38
+ - '*' : match zero or more characters
39
+ - '?' : match any single character
40
+ """
41
+
42
+ folders: Optional[List[Folder]] = None
43
+ """Limits the result to a collection of folders."""
44
+
45
+ history_states: Optional[List[Literal["FAILED", "INCOMPLETE", "SUCCESSFUL"]]] = None
46
+ """Limits result to specified states."""
47
+
48
+ criticalities: Optional[List[Literal["CRITICAL", "NORMAL"]]] = None
49
+ """Possible values are NORMAL and NORMAL Only records with these criticalities are responsed."""
50
+
@@ -0,0 +1,2 @@
1
+ from .add_order import Order, PlanID
2
+ __all__ = ["Order", "PlanID"]
@@ -0,0 +1,50 @@
1
+ from typing import Any, Dict, List, Optional, Union
2
+ from pydantic import BaseModel
3
+
4
+ from .....model.public.client.common.schedule_time import ScheduleTime
5
+
6
+ from ..enum.order_priority import OrderPriority
7
+
8
+
9
+ class PlanID(BaseModel):
10
+ notice_space_key: str
11
+ """Schema ID of a plan, e.g. 'DailyPlan'."""
12
+
13
+ plan_schema_id: str
14
+ """Plan key of the plan."""
15
+
16
+
17
+ class Order(BaseModel):
18
+ arguments: Optional[Dict[str, Any]] = None
19
+ """An object with key-value pairs. The value can be a string, number or boolean."""
20
+
21
+ block_position: Optional[Union[List[Union[int, str]], str]] = None
22
+ """The order runs only inside the specified block instruction. The position can also be specified by the label of the block instruction."""
23
+
24
+ end_positions: Optional[List[Union[List[Union[int, str]], str]]] = None
25
+ """The order ends on one of these positions. The position can also be specified by the label of the instruction."""
26
+
27
+ force_job_admission: bool = False
28
+ """If true then any admission times at a Job instruction will be ignored."""
29
+
30
+ open_closed_plan: bool = False
31
+ """If true then a closed plan will be reopen automatically."""
32
+
33
+ order_name: Optional[str]
34
+ """`order_name` is only a part of the `order_id` in the form "#<date>#T<uniqueId>-<orderName>"."""
35
+
36
+ plan_id: Optional[PlanID] = None
37
+
38
+ priority: Optional[Union[OrderPriority, int]] = None
39
+ """Priority of the order."""
40
+
41
+ scheduled_for: Optional[ScheduleTime] = None
42
+ """Sets the start time of the order execution."""
43
+
44
+ start_position: Optional[Union[List[Union[int, str]], str]] = None
45
+ """The order starts with the first instruction per default. The position can also be specified by the label of the instruction."""
46
+
47
+ tags: Optional[List[str]] = None
48
+
49
+ workflow_path: str
50
+ """e. g. `/folder/my-workflow`"""
@@ -0,0 +1,206 @@
1
+ import gzip
2
+ import mimetypes
3
+ from pathlib import Path
4
+ import http.client, ssl, time
5
+ from typing import Callable, Optional, Union, Dict
6
+ from ssl import SSLContext
7
+ import uuid
8
+
9
+ from ..model.configuration.http_configuration import HTTPConfiguration
10
+
11
+
12
+ class HTTPService:
13
+ """
14
+ Functionality:
15
+ - Uses `time.monotonic` to obtain a monotonically increasing time source and
16
+ avoid issues caused by system time changes (e.g. daylight saving time)
17
+ - Closes the connection to the server after 30 seconds of inactivity and reopen the connection after the next use again.
18
+ """
19
+
20
+ IDLE_TIMEOUT = 30 # Reconnects after 30 seconds of inactivity
21
+
22
+ def __init__(
23
+ self,
24
+ *,
25
+ configuration: HTTPConfiguration,
26
+ response_validator: Optional[Callable[[str, int, bytes], None]] = None
27
+ ):
28
+
29
+ self._config = configuration
30
+ self._response_validator = response_validator
31
+
32
+ self._conn: Union[http.client.HTTPSConnection, http.client.HTTPConnection, None] = None
33
+ self._https_ctx: Optional[SSLContext] = None
34
+ self._last_used: float = 0.0
35
+
36
+ # These variables can be modified at runtime by other methods to adjust the SSL context
37
+ self.auth_certfile_path: Optional[Union[Path, str]] = None
38
+ self.auth_keyfile_path: Optional[Union[Path, str]] = None
39
+
40
+ def __enter__(self):
41
+ self._ensure_connection()
42
+ return self
43
+
44
+ def __exit__(self, exc_type, exc_val, exc_tb): # type: ignore
45
+ if exc_type is not None:
46
+ self.close()
47
+
48
+ def _ensure_connection(self):
49
+ now = time.monotonic()
50
+ if self._conn is None or (now - self._last_used) > self.IDLE_TIMEOUT:
51
+ self._open_connection()
52
+
53
+ # Creates the context for the ssl connection
54
+ def _create_ssl_context(self) -> SSLContext:
55
+ if self._https_ctx:
56
+ return self._https_ctx
57
+
58
+ ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
59
+
60
+ # Sets fixed tls version
61
+ ctx.minimum_version = ssl.TLSVersion.TLSv1_2
62
+
63
+ # Optional: Server Certificate
64
+ if self._config.cafile_path:
65
+ ctx.load_verify_locations(cafile=self._config.cafile_path)
66
+
67
+ # Optional: Client certificate
68
+ if self.auth_certfile_path and not self.auth_keyfile_path:
69
+ raise ValueError("client certificate provided without private key")
70
+
71
+ if self.auth_certfile_path and self.auth_keyfile_path:
72
+ ctx.load_cert_chain(
73
+ certfile=self.auth_certfile_path,
74
+ keyfile=self.auth_keyfile_path
75
+ )
76
+
77
+ # Ensures security
78
+ ctx.verify_mode = ssl.CERT_REQUIRED
79
+ ctx.check_hostname = True
80
+ self._https_ctx = ctx
81
+ return self._https_ctx
82
+
83
+ def _open_connection(self):
84
+ self.close()
85
+
86
+ if self._config.ssl:
87
+ self._conn = http.client.HTTPSConnection(
88
+ host=self._config.host,
89
+ port=self._config.port,
90
+ timeout=30,
91
+ context=self._create_ssl_context()
92
+ )
93
+ else:
94
+ self._conn = http.client.HTTPConnection(
95
+ host=self._config.host,
96
+ port=self._config.port,
97
+ timeout=30
98
+ )
99
+
100
+ self._last_used = time.monotonic()
101
+
102
+ def _request(self, method: str, path: str, headers: Dict[str, str], body: Optional[str]) -> http.client.HTTPResponse:
103
+ self._ensure_connection()
104
+
105
+ conn = self._conn
106
+ if conn is None:
107
+ raise RuntimeError("Connection not initialized.")
108
+
109
+ response: Optional[http.client.HTTPResponse] = None
110
+
111
+ # Reconnects and retries the request once on connection failure
112
+ try:
113
+ conn.request(method=method, url=path, body=body, headers=headers)
114
+ response = conn.getresponse()
115
+ except (BrokenPipeError, ConnectionResetError, TimeoutError):
116
+ self.close()
117
+
118
+ time.sleep(3) # Waits for 3 seconds
119
+
120
+ self._open_connection()
121
+ conn = self._conn
122
+ if conn is None:
123
+ raise RuntimeError("Connection not initialized after reconnect.")
124
+ conn.request(method=method, url=path, body=body, headers=headers)
125
+ response = conn.getresponse()
126
+
127
+ return response
128
+
129
+ def _decode_response(self, path:str, response: http.client.HTTPResponse) -> bytes:
130
+ raw_bytes = response.read()
131
+
132
+ # Raises a error for the given statuscode
133
+ if self._response_validator:
134
+ self._response_validator(path, response.status, raw_bytes)
135
+
136
+ if "gzip" in (response.headers.get("Content-Encoding", "")).lower():
137
+ return gzip.decompress(raw_bytes)
138
+
139
+ return raw_bytes
140
+
141
+ # (i) close method
142
+ def close(self):
143
+ if self._conn:
144
+ self._conn.close()
145
+ self._conn = None
146
+ self._https_ctx = None
147
+
148
+ # (i) POST method
149
+ def post(self, path: str, body: Optional[str], headers: Dict[str, str]) -> bytes:
150
+ response = self._request("POST", path, headers, body)
151
+ return self._decode_response(path, response)
152
+
153
+ # (i) GET method
154
+ def get(self, path: str, headers: Dict[str, str]) -> bytes:
155
+ response = self._request(method="GET", path=path, headers=headers, body=None)
156
+ return self._decode_response(path, response)
157
+
158
+ # (i) Upload file
159
+ def upload_file(self, path: str, access_token: str, file: bytes, filename: str, form_fields: Optional[Dict[str, str]] = None) -> bytes:
160
+ self._ensure_connection()
161
+ conn = self._conn
162
+ if conn is None:
163
+ raise RuntimeError("Connection not initialized.")
164
+
165
+ boundary = "----Boundary" + uuid.uuid4().hex
166
+ content_type = mimetypes.guess_type(filename)[0] or "application/octet-stream"
167
+
168
+ body = bytearray()
169
+
170
+ def add_field(name: str, value: str) -> None:
171
+ body.extend(f"--{boundary}\r\n".encode())
172
+ body.extend(
173
+ f'Content-Disposition: form-data; name="{name}"\r\n\r\n'.encode()
174
+ )
175
+ body.extend(value.encode("utf-8"))
176
+ body.extend(b"\r\n")
177
+
178
+ # optional form fields first
179
+ if form_fields:
180
+ for k, v in form_fields.items():
181
+ add_field(k, v)
182
+
183
+ # file part
184
+ body.extend(f"--{boundary}\r\n".encode())
185
+ body.extend(
186
+ (
187
+ f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'
188
+ f"Content-Type: {content_type}\r\n\r\n"
189
+ ).encode()
190
+ )
191
+ body.extend(file)
192
+ body.extend(b"\r\n")
193
+
194
+ # closing boundary
195
+ body.extend(f"--{boundary}--\r\n".encode())
196
+
197
+ headers = {
198
+ "Content-Type": f"multipart/form-data; boundary={boundary}",
199
+ "Content-Length": str(len(body)),
200
+ "X-Access-Token": access_token,
201
+ }
202
+
203
+ conn.request("POST", path, body=body, headers=headers)
204
+ response = conn.getresponse()
205
+
206
+ return self._decode_response(path=path, response=response)
@@ -0,0 +1,52 @@
1
+ from typing import List, Literal, Tuple
2
+ from io import BytesIO
3
+ import zipfile
4
+ import tarfile
5
+ import posixpath
6
+
7
+
8
+ def bytes_to_archive_bytes(
9
+ *,
10
+ archive_format: Literal["ZIP", "TAR_GZ"],
11
+ files: List[Tuple[str, bytes]], # path, content bytes
12
+ ) -> bytes:
13
+
14
+ # Validate: archive_format
15
+ if archive_format not in ("ZIP", "TAR_GZ"):
16
+ raise ValueError("'archive_format' must be 'ZIP' or 'TAR_GZ'.")
17
+
18
+ # Validate: files
19
+ if not files:
20
+ raise ValueError("'files' is required.")
21
+
22
+ for path, content in files:
23
+ if not path:
24
+ raise ValueError("File path must not be empty.")
25
+
26
+ if not content:
27
+ raise ValueError("File content must not be empty.")
28
+
29
+ # Normalize paths (no leading slash, POSIX-style)
30
+ normalized_files = [
31
+ (posixpath.normpath(path.lstrip("/")), bytes(content))
32
+ for path, content in files
33
+ ]
34
+
35
+ buffer = BytesIO()
36
+
37
+ # Build: ZIP
38
+ if archive_format == "ZIP":
39
+ with zipfile.ZipFile(buffer, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
40
+ for path, content in normalized_files:
41
+ zf.writestr(path, content)
42
+
43
+ # Build: TAR.GZ
44
+ elif archive_format == "TAR_GZ":
45
+ with tarfile.open(fileobj=buffer, mode="w:gz") as tf:
46
+ for path, content in normalized_files:
47
+ info = tarfile.TarInfo(name=path)
48
+ info.size = len(content)
49
+ tf.addfile(info, BytesIO(content))
50
+
51
+ buffer.seek(0)
52
+ return buffer.read()
@@ -0,0 +1,12 @@
1
+ from pathlib import Path
2
+
3
+
4
+ def bytes_to_file(*, data: bytes, out_path: Path) -> bool:
5
+ """out_path: /my-file.zip"""
6
+
7
+ try:
8
+ out_path.parent.mkdir(parents=True, exist_ok=True)
9
+ out_path.write_bytes(data)
10
+ return True
11
+ except OSError:
12
+ return False
@@ -0,0 +1,52 @@
1
+ from pathlib import Path
2
+ from typing import List, Optional, Tuple
3
+
4
+
5
+ def files_to_bytes(
6
+ *,
7
+ file_path: Path,
8
+ filter_suffixes: Optional[List[str]] = None,
9
+ ) -> List[Tuple[str, bytes]]:
10
+ """
11
+ Reads a file or directory into memory.
12
+
13
+ Input:
14
+ - file: File or directory to read from.
15
+ - filter_suffixes: If set, only files with one of these suffixes (e.g. [".json", ".yaml"]) are included.
16
+
17
+ Result:
18
+ - List of (relative_posix_path, file_content_bytes).
19
+ """
20
+
21
+ if not file_path.exists():
22
+ raise ValueError(f"File path does not exist: {file_path}")
23
+
24
+ # Normalize filter suffixes
25
+ suffixes: Optional[Tuple[str, ...]] = (
26
+ tuple(filter_suffixes) if filter_suffixes else None
27
+ )
28
+
29
+ result: List[Tuple[str, bytes]] = []
30
+
31
+ def is_allowed(path: Path) -> bool:
32
+ return suffixes is None or path.name.endswith(suffixes)
33
+
34
+ if file_path.is_dir():
35
+ for p in file_path.rglob("*"):
36
+ if not p.is_file():
37
+ continue
38
+
39
+ if not is_allowed(p):
40
+ continue
41
+
42
+ relative_path = p.relative_to(file_path).as_posix()
43
+ result.append((relative_path, p.read_bytes()))
44
+
45
+ elif file_path.is_file():
46
+ if is_allowed(file_path):
47
+ result.append((file_path.name, file_path.read_bytes()))
48
+
49
+ else:
50
+ raise ValueError(f"Invalid file input: {file_path}")
51
+
52
+ return result
@@ -0,0 +1,69 @@
1
+ from typing import List, Optional, Tuple
2
+ import zipfile
3
+ import tarfile
4
+ from io import BytesIO
5
+
6
+ from ..detect_archive_type import detect_archive_type
7
+
8
+
9
+ def read_bytes_archive_files_to_bytes(
10
+ file: bytes,
11
+ filter_suffixes: Optional[List[str]] = None
12
+ ) -> Optional[List[Tuple[str, bytes]]]:
13
+ """Returns POSIX path and file as bytes or None if not an archive or no files found."""
14
+
15
+ if not file:
16
+ return None
17
+
18
+ archive_type = detect_archive_type(file)
19
+ if archive_type is None:
20
+ return None
21
+
22
+ # Normalize suffix filter
23
+ suffixes = None
24
+ if filter_suffixes:
25
+ suffixes = tuple(s.lower() for s in filter_suffixes)
26
+
27
+ result: List[Tuple[str, bytes]] = []
28
+
29
+ # ZIP
30
+ if archive_type == "ZIP":
31
+ try:
32
+ with zipfile.ZipFile(BytesIO(file), "r") as zf:
33
+ for info in zf.infolist():
34
+ if info.is_dir():
35
+ continue
36
+
37
+ posix_path = info.filename.replace("\\", "/")
38
+
39
+ if suffixes and not posix_path.lower().endswith(suffixes):
40
+ continue
41
+
42
+ data = zf.read(info)
43
+ result.append((posix_path, data))
44
+ except (zipfile.BadZipFile, OSError):
45
+ return None
46
+
47
+ # TAR.GZ
48
+ elif archive_type == "TAR_GZ":
49
+ try:
50
+ with tarfile.open(fileobj=BytesIO(file), mode="r:gz") as tf:
51
+ for member in tf.getmembers():
52
+ if not member.isfile():
53
+ continue
54
+
55
+ posix_path = member.name.replace("\\", "/")
56
+
57
+ if suffixes and not posix_path.lower().endswith(suffixes):
58
+ continue
59
+
60
+ extracted = tf.extractfile(member)
61
+ if extracted is None:
62
+ continue
63
+
64
+ data = extracted.read()
65
+ result.append((posix_path, data))
66
+ except (tarfile.TarError, OSError):
67
+ return None
68
+
69
+ return result or None
@@ -0,0 +1,106 @@
1
+ from pathlib import Path
2
+ from typing import List, Optional, Tuple, Union
3
+ import base64
4
+
5
+ from cryptography.hazmat.primitives import hashes, serialization
6
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa, ec
7
+ from cryptography.exceptions import InvalidSignature
8
+ from cryptography.hazmat.primitives.asymmetric.types import PublicKeyTypes
9
+
10
+ from cryptography.hazmat.backends import default_backend
11
+
12
+
13
+ def _verify_signature(
14
+ *,
15
+ data: bytes,
16
+ signature: bytes,
17
+ public_key: Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey],
18
+ hash_alg: hashes.HashAlgorithm,
19
+ ) -> bool:
20
+ try:
21
+ if isinstance(public_key, rsa.RSAPublicKey):
22
+ public_key.verify(
23
+ signature,
24
+ data,
25
+ padding.PKCS1v15(),
26
+ hash_alg,
27
+ )
28
+ else:
29
+ public_key.verify(
30
+ signature,
31
+ data,
32
+ ec.ECDSA(hash_alg),
33
+ )
34
+ return True
35
+ except InvalidSignature:
36
+ return False
37
+
38
+ def sign_to_bytes(
39
+ *,
40
+ files: List[Tuple[str, bytes]],
41
+ private_key_file: Path,
42
+ public_key_file: Optional[Path],
43
+ key_password: Optional[bytes],
44
+ hash_alg: hashes.HashAlgorithm
45
+ ) -> List[Tuple[str, bytes]]:
46
+
47
+ if not private_key_file or not hash_alg:
48
+ raise ValueError("'private_key_file' and 'hash_alg' is required")
49
+
50
+ # ---- load private key ----
51
+ with open(private_key_file, "rb") as f:
52
+ private_key = serialization.load_pem_private_key(
53
+ f.read(),
54
+ password=key_password,
55
+ backend=default_backend(),
56
+ )
57
+
58
+ if not isinstance(private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey)):
59
+ raise TypeError("Only RSA and ECDSA private keys are supported")
60
+
61
+ # ---- load public key ----
62
+ public_key: Optional[PublicKeyTypes] = None
63
+
64
+ if public_key_file:
65
+ with open(public_key_file, "rb") as f:
66
+ public_key = serialization.load_pem_public_key(
67
+ f.read(),
68
+ backend=default_backend(),
69
+ )
70
+
71
+ if not isinstance(public_key, (rsa.RSAPublicKey, ec.EllipticCurvePublicKey)):
72
+ raise TypeError("Unsupported public key type.")
73
+
74
+ # ---- sign ----
75
+ result: List[Tuple[str, bytes]] = []
76
+
77
+ for path, data in files:
78
+ if isinstance(private_key, rsa.RSAPrivateKey):
79
+ signature = private_key.sign(
80
+ data,
81
+ padding.PKCS1v15(),
82
+ hash_alg,
83
+ )
84
+ else:
85
+ signature = private_key.sign(
86
+ data,
87
+ ec.ECDSA(hash_alg),
88
+ )
89
+
90
+ signature_b64_bytes = base64.b64encode(signature)
91
+
92
+ sig_path = f"{path}.sig"
93
+
94
+ # ---- optional verification ----
95
+ if public_key:
96
+ if not _verify_signature(
97
+ data=data,
98
+ signature=signature,
99
+ public_key=public_key,
100
+ hash_alg=hash_alg,
101
+ ):
102
+ raise ValueError(f"Signature verification failed for '{sig_path}'")
103
+
104
+ result.append((sig_path, signature_b64_bytes))
105
+
106
+ return result
@@ -0,0 +1,20 @@
1
+ from typing import Tuple
2
+
3
+
4
+ def _version_to_tuple(input: str) -> Tuple[int, int, int]:
5
+ try:
6
+ ep_major, ep_minor, ep_patch = input.split(".")
7
+ return int(ep_major), int(ep_minor), int(ep_patch)
8
+ except Exception as e:
9
+ raise ValueError(f"Invalid version string '{input}'. Error: {e}")
10
+
11
+ def check_matching_version(*, min: str, max: str, check: str) -> bool:
12
+ # Normalize to MAJOR.MINOR.PATCH
13
+ check = check.split("-", 1)[0]
14
+ check = ".".join(check.split(".")[:3])
15
+
16
+ min_version: Tuple[int, int, int] = _version_to_tuple(min)
17
+ max_version: Tuple[int, int, int] = _version_to_tuple(max)
18
+ check_version: Tuple[int, int, int] = _version_to_tuple(check)
19
+
20
+ return min_version <= check_version <= max_version
@@ -0,0 +1,37 @@
1
+ from pathlib import Path
2
+ from typing import Literal, Optional, Union
3
+
4
+
5
+ def _detect_from_bytes(data: bytes) -> Optional[Literal["ZIP", "TAR_GZ"]]:
6
+ if len(data) < 4:
7
+ return None
8
+
9
+ # ZIP
10
+ if data.startswith((b"PK\x03\x04", b"PK\x05\x06", b"PK\x07\x08")):
11
+ return "ZIP"
12
+
13
+ # GZIP (tar.gz)
14
+ if data.startswith(b"\x1f\x8b"):
15
+ return "TAR_GZ"
16
+
17
+ return None
18
+
19
+
20
+ def detect_archive_type(file: Union[bytes, Path]) -> Optional[Literal["ZIP", "TAR_GZ"]]:
21
+ """Detect archive type from raw bytes or file path using magic bytes."""
22
+
23
+ if isinstance(file, bytes):
24
+ return _detect_from_bytes(file)
25
+
26
+ if isinstance(file, Path):
27
+ if not file.exists() or not file.is_file():
28
+ return None
29
+
30
+ try:
31
+ with file.open("rb") as f:
32
+ head = f.read(4)
33
+ return _detect_from_bytes(head)
34
+ except OSError:
35
+ return None
36
+
37
+ return None
@@ -0,0 +1,5 @@
1
+ from typing import Optional
2
+
3
+
4
+ def order_id_to_order_name(s: Optional[str]) -> Optional[str]:
5
+ return s.rsplit("#", 1)[-1].split("-", 1)[1] if s and "-" in s else None