From 27dd88aa01a4a0b533f233417571bd8ee419f379 Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Fri, 21 Jun 2024 16:44:27 +0300 Subject: [PATCH 01/15] Add action tester script --- poetry.lock | 173 ++++++++++++++++++-- pyproject.toml | 1 + sekoia_automation/scripts/action_runner.py | 179 +++++++++++++++++++++ 3 files changed, 340 insertions(+), 13 deletions(-) create mode 100644 sekoia_automation/scripts/action_runner.py diff --git a/poetry.lock b/poetry.lock index 40af06f..a77c4a2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiobotocore" @@ -1234,6 +1234,41 @@ files = [ {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, ] +[[package]] +name = "jsonschema" +version = "4.22.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, + {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + [[package]] name = "keyring" version = "24.3.1" @@ -1374,7 +1409,6 @@ files = [ {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:9e2addd2d1866fe112bc6f80117bcc6bc25191c5ed1bfbcf9f1386a884252ae8"}, {file = "lxml-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:f51969bac61441fd31f028d7b3b45962f3ecebf691a510495e5d2cd8c8092dbd"}, {file = "lxml-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b0b58fbfa1bf7367dde8a557994e3b1637294be6cf2169810375caf8571a085c"}, - {file = "lxml-5.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3e183c6e3298a2ed5af9d7a356ea823bccaab4ec2349dc9ed83999fd289d14d5"}, {file = "lxml-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:804f74efe22b6a227306dd890eecc4f8c59ff25ca35f1f14e7482bbce96ef10b"}, {file = "lxml-5.2.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08802f0c56ed150cc6885ae0788a321b73505d2263ee56dad84d200cab11c07a"}, {file = "lxml-5.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f8c09ed18ecb4ebf23e02b8e7a22a05d6411911e6fabef3a36e4f371f4f2585"}, @@ -2288,7 +2322,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -2296,15 +2329,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -2321,7 +2347,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -2329,7 +2354,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -2437,6 +2461,21 @@ files = [ [package.extras] full = ["numpy"] +[[package]] +name = "referencing" +version = "0.35.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + [[package]] name = "requests" version = "2.31.0" @@ -2507,6 +2546,114 @@ pygments = ">=2.6.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] +[[package]] +name = "rpds-py" +version = "0.18.1" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, + {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, + {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, + {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, + {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, + {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, + {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, + {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, + {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, + {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, + {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, + {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, +] + [[package]] name = "ruff" version = "0.4.1" @@ -3185,4 +3332,4 @@ logging = ["loguru"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "5da756d4f9441f5838049df54b381f938ef72816a277843250beef10ee66957c" +content-hash = "ce02cd52ab2e6ad2bf4cc46badd311150deeecc0c5f27f4c02e560572776c19a" diff --git a/pyproject.toml b/pyproject.toml index 7f63841..f741a48 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,7 @@ types-requests = "^2.31.0.1" types-pyyaml = "^6.0.12.10" types-python-slugify = "^8.0.0.2" pre-commit = "^3.3.3" +jsonschema = "^4.22.0" [tool.poetry.extras] all = [ diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py new file mode 100644 index 0000000..3d33a43 --- /dev/null +++ b/sekoia_automation/scripts/action_runner.py @@ -0,0 +1,179 @@ +import ast +import importlib.util +import json +import sys +from pathlib import Path + +from jsonschema import validate + +from sekoia_automation.module import Module + + +class ModuleItemRunner: + def __init__(self, class_name: str, module_path: str): + self.__class_name = class_name + self.__module_path = ( + module_path if isinstance(module_path, Path) else Path(module_path) + ).resolve() + + @staticmethod + def load_class_from_path(path: Path | str, class_name: str): + """ + @todo having issues with relative imports in modules (e.g. metrics) + """ + if isinstance(path, Path): + path = str(path) + + # Add the directory containing the module to sys.path + module_dir = "/".join(path.split("/")[:-1]) + if module_dir not in sys.path: + sys.path.append(module_dir) + + # Load the module + module_name = path.split("/")[-1].split(".")[0] + spec = importlib.util.spec_from_file_location(module_name, path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + # Get the class from the module + cls = getattr(module, class_name) + return cls + + def find_file_with_module_item_class(self): + for file_path in self.__module_path.rglob("*.py"): + with open(file_path, "r") as f: + try: + tree = ast.parse(f.read(), filename=str(file_path)) + except SyntaxError: + continue # Skip files with syntax errors + for node in ast.walk(tree): + if ( + isinstance(node, ast.ClassDef) + and node.name == self.__class_name + ): + return file_path + + return None + + def find_file_with_child_class( + self, parent_class_to_find: str + ) -> (str | None, Path | None): + for file_path in self.__module_path.rglob("*.py"): + with open(file_path, "r") as f: + try: + tree = ast.parse(f.read()) + except SyntaxError: + continue # Skip files with syntax errors + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef): + parent_classes = { + base.id for base in node.bases if hasattr(base, "id") + } + if parent_class_to_find in parent_classes: + return node.name, file_path + + return None, None + + def get_docker_params_from_main_py(self) -> dict: + from _ast import AST + + main_py_path = self.__module_path / "main.py" + with open(main_py_path, "rt") as file: + content = file.read() + + tree = ast.parse(content) + + module_item_to_docker_param = {} + + node: AST + for node in ast.walk(tree): + if ( + hasattr(node, "func") + and isinstance(node.func, ast.Attribute) + and node.func.attr == "register" + ): + action_class = ( + node.args[0].id if isinstance(node.args[0], ast.Name) else None + ) + + docker_param: str | None = None + if len(node.args) > 1 and isinstance(node.args[1], ast.Str): + # provided as positional arg + docker_param = node.args[1].s + + elif len(node.keywords) > 0: + # provided as keyword arg + docker_param = node.keywords[0].value.s + + module_item_to_docker_param[action_class] = docker_param + + return module_item_to_docker_param + + def get_manifest_by_docker_param( + self, prefix: str, docker_param: str + ) -> dict | None: + manifests = self.__module_path.glob(f"{prefix}*.json") + for manifest_path in manifests: + with open(manifest_path, "rt") as file: + manifest = json.load(file) + + if manifest.get("docker_parameters") == docker_param: + return manifest + + def run(self, args: dict, module_conf: dict = None) -> dict: + cls_to_docker = self.get_docker_params_from_main_py() + docker_param = cls_to_docker[self.__class_name] + manifest = self.get_manifest_by_docker_param( + docker_param=docker_param, prefix="" + ) + + arguments_schema = manifest.get("arguments") + results_schema = manifest.get( + "results", {} + ) # no `results` schema for connectors + + # check inputs + validate(instance=args, schema=arguments_schema) + + # find and load Module class + module_class_name, module_class_path = self.find_file_with_child_class( + parent_class_to_find="Module" + ) + + if module_class_name is None: + module = Module() + + else: + module_cls = self.load_class_from_path(module_class_path, module_class_name) + + # Prepare module configuration + module_annotations = module_cls.__annotations__ + module_config_cls = module_annotations["configuration"] + conf_args = module_conf if module_conf else {} + module_conf = module_config_cls(**conf_args) + + module = module_cls() + module.configuration = module_conf + + file_path = self.find_file_with_module_item_class() + module_item_cls = self.load_class_from_path( + path=file_path, class_name=self.__class_name + ) + module_item = module_item_cls( + module=module, data_path=Path(".") + ) # @todo set custom path? + + results = module_item.run(args) + + # check result + validate(instance=results, schema=results_schema) + return results + + +if __name__ == "__main__": + class_name = "RequestAction" + module_name = "HTTP" + args = {"method": "get", "url": "https://dummyjson.com/test"} + + c = ModuleItemRunner(module_path=module_name, class_name=class_name) + print(c.run(args=args)) From 546c449832735bf3edbf4a569437632170b14fad Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Fri, 21 Jun 2024 17:25:44 +0300 Subject: [PATCH 02/15] Fix import issues --- sekoia_automation/scripts/action_runner.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index 3d33a43..47fedf7 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -10,27 +10,25 @@ class ModuleItemRunner: - def __init__(self, class_name: str, module_path: str): + def __init__(self, class_name: str, module_path: str | Path): self.__class_name = class_name self.__module_path = ( module_path if isinstance(module_path, Path) else Path(module_path) ).resolve() + self.__root_path = self.__module_path.parent - @staticmethod - def load_class_from_path(path: Path | str, class_name: str): - """ - @todo having issues with relative imports in modules (e.g. metrics) - """ - if isinstance(path, Path): - path = str(path) - + def load_class_from_path(self, path: Path | str, class_name: str): # Add the directory containing the module to sys.path - module_dir = "/".join(path.split("/")[:-1]) + module_dir = "/".join(str(path).split("/")[:-1]) if module_dir not in sys.path: sys.path.append(module_dir) # Load the module - module_name = path.split("/")[-1].split(".")[0] + module_name = ( + str(Path(path).resolve().relative_to(self.__root_path)) + .replace("/", ".") + .rstrip(".py") + ) spec = importlib.util.spec_from_file_location(module_name, path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) @@ -172,7 +170,7 @@ def run(self, args: dict, module_conf: dict = None) -> dict: if __name__ == "__main__": class_name = "RequestAction" - module_name = "HTTP" + module_name = Path("~/PycharmProjects/automation-library/HTTP").expanduser() args = {"method": "get", "url": "https://dummyjson.com/test"} c = ModuleItemRunner(module_path=module_name, class_name=class_name) From eb6337fabf0f922f0ff36e146bc76371b9d182e6 Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Tue, 2 Jul 2024 16:42:09 +0300 Subject: [PATCH 03/15] Add support of Triggers/Connectors --- sekoia_automation/scripts/action_runner.py | 46 +++++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index 47fedf7..deb7947 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -118,6 +118,30 @@ def get_manifest_by_docker_param( if manifest.get("docker_parameters") == docker_param: return manifest + @staticmethod + def get_module_item_type(cls): + def __iter_all_parents(c): + result = [] + parent_cls = c.__bases__ + + result.extend(parent_cls) + for parent in parent_cls: + result.extend(__iter_all_parents(parent)) + + return result + + parents_labels = {item.__name__: item for item in __iter_all_parents(cls)} + if "Connector" in parents_labels: + return "Connector" + + elif "Action" in parents_labels: + return "Action" + + elif "Trigger" in parents_labels: + return "Trigger" + + raise ValueError("Incorrect class") + def run(self, args: dict, module_conf: dict = None) -> dict: cls_to_docker = self.get_docker_params_from_main_py() docker_param = cls_to_docker[self.__class_name] @@ -157,21 +181,33 @@ def run(self, args: dict, module_conf: dict = None) -> dict: module_item_cls = self.load_class_from_path( path=file_path, class_name=self.__class_name ) + module_item = module_item_cls( module=module, data_path=Path(".") ) # @todo set custom path? - results = module_item.run(args) + module_item_type = self.get_module_item_type(module_item_cls) + if module_item_type == "Action": + results = module_item.run(args) + + # check result + validate(instance=results, schema=results_schema) + return results + + else: + module_item_annotations = module_item_cls.__annotations__ + module_item_config_cls = module_item_annotations["configuration"] + module_item_conf = module_item_config_cls(**args) - # check result - validate(instance=results, schema=results_schema) - return results + module_item.configuration = module_item_conf + module_item.run() if __name__ == "__main__": class_name = "RequestAction" module_name = Path("~/PycharmProjects/automation-library/HTTP").expanduser() + module_conf = {} args = {"method": "get", "url": "https://dummyjson.com/test"} c = ModuleItemRunner(module_path=module_name, class_name=class_name) - print(c.run(args=args)) + print(c.run(args=args, module_conf=module_conf)) From 1d6f6057d325f4b0d797912612fa8ae483b37033 Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Tue, 2 Jul 2024 16:57:01 +0300 Subject: [PATCH 04/15] Fix linting --- sekoia_automation/scripts/action_runner.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index deb7947..2c035ca 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -39,7 +39,7 @@ def load_class_from_path(self, path: Path | str, class_name: str): def find_file_with_module_item_class(self): for file_path in self.__module_path.rglob("*.py"): - with open(file_path, "r") as f: + with open(file_path) as f: try: tree = ast.parse(f.read(), filename=str(file_path)) except SyntaxError: @@ -57,7 +57,7 @@ def find_file_with_child_class( self, parent_class_to_find: str ) -> (str | None, Path | None): for file_path in self.__module_path.rglob("*.py"): - with open(file_path, "r") as f: + with open(file_path) as f: try: tree = ast.parse(f.read()) except SyntaxError: @@ -76,7 +76,7 @@ def get_docker_params_from_main_py(self) -> dict: from _ast import AST main_py_path = self.__module_path / "main.py" - with open(main_py_path, "rt") as file: + with open(main_py_path) as file: content = file.read() tree = ast.parse(content) @@ -112,7 +112,7 @@ def get_manifest_by_docker_param( ) -> dict | None: manifests = self.__module_path.glob(f"{prefix}*.json") for manifest_path in manifests: - with open(manifest_path, "rt") as file: + with open(manifest_path) as file: manifest = json.load(file) if manifest.get("docker_parameters") == docker_param: @@ -142,7 +142,7 @@ def __iter_all_parents(c): raise ValueError("Incorrect class") - def run(self, args: dict, module_conf: dict = None) -> dict: + def run(self, args: dict, module_conf: dict | None = None) -> dict: cls_to_docker = self.get_docker_params_from_main_py() docker_param = cls_to_docker[self.__class_name] manifest = self.get_manifest_by_docker_param( From a9d5d990ac1de1566780bf365beb7a1ca75bc80f Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Tue, 2 Jul 2024 17:27:29 +0300 Subject: [PATCH 05/15] Fix linting --- sekoia_automation/scripts/action_runner.py | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index 2c035ca..0e32ab9 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -3,7 +3,9 @@ import json import sys from pathlib import Path +from typing import Tuple, Any +import typing from jsonschema import validate from sekoia_automation.module import Module @@ -17,7 +19,7 @@ def __init__(self, class_name: str, module_path: str | Path): ).resolve() self.__root_path = self.__module_path.parent - def load_class_from_path(self, path: Path | str, class_name: str): + def load_class_from_path(self, path: Path | str, class_name: str) -> typing.Type: # Add the directory containing the module to sys.path module_dir = "/".join(str(path).split("/")[:-1]) if module_dir not in sys.path: @@ -29,15 +31,15 @@ def load_class_from_path(self, path: Path | str, class_name: str): .replace("/", ".") .rstrip(".py") ) - spec = importlib.util.spec_from_file_location(module_name, path) - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) + spec = importlib.util.spec_from_file_location(module_name, path) # type: ignore + module = importlib.util.module_from_spec(spec) # type: ignore + spec.loader.exec_module(module) # type: ignore # Get the class from the module cls = getattr(module, class_name) return cls - def find_file_with_module_item_class(self): + def find_file_with_module_item_class(self) -> Path: for file_path in self.__module_path.rglob("*.py"): with open(file_path) as f: try: @@ -51,11 +53,11 @@ def find_file_with_module_item_class(self): ): return file_path - return None + raise FileNotFoundError(f"No file with class `{self.__class_name}`") def find_file_with_child_class( self, parent_class_to_find: str - ) -> (str | None, Path | None): + ) -> Tuple[str | None, Path | None]: for file_path in self.__module_path.rglob("*.py"): with open(file_path) as f: try: @@ -83,7 +85,7 @@ def get_docker_params_from_main_py(self) -> dict: module_item_to_docker_param = {} - node: AST + node: Any for node in ast.walk(tree): if ( hasattr(node, "func") @@ -107,9 +109,7 @@ def get_docker_params_from_main_py(self) -> dict: return module_item_to_docker_param - def get_manifest_by_docker_param( - self, prefix: str, docker_param: str - ) -> dict | None: + def get_manifest_by_docker_param(self, prefix: str, docker_param: str) -> dict: manifests = self.__module_path.glob(f"{prefix}*.json") for manifest_path in manifests: with open(manifest_path) as file: @@ -118,6 +118,8 @@ def get_manifest_by_docker_param( if manifest.get("docker_parameters") == docker_param: return manifest + return {} + @staticmethod def get_module_item_type(cls): def __iter_all_parents(c): @@ -142,10 +144,10 @@ def __iter_all_parents(c): raise ValueError("Incorrect class") - def run(self, args: dict, module_conf: dict | None = None) -> dict: + def run(self, args: dict, module_conf: dict | None = None) -> dict | None: cls_to_docker = self.get_docker_params_from_main_py() docker_param = cls_to_docker[self.__class_name] - manifest = self.get_manifest_by_docker_param( + manifest: dict = self.get_manifest_by_docker_param( docker_param=docker_param, prefix="" ) @@ -162,7 +164,7 @@ def run(self, args: dict, module_conf: dict | None = None) -> dict: parent_class_to_find="Module" ) - if module_class_name is None: + if module_class_name is None or module_class_path is None: module = Module() else: @@ -202,12 +204,13 @@ def run(self, args: dict, module_conf: dict | None = None) -> dict: module_item.configuration = module_item_conf module_item.run() + return None + if __name__ == "__main__": class_name = "RequestAction" module_name = Path("~/PycharmProjects/automation-library/HTTP").expanduser() - module_conf = {} args = {"method": "get", "url": "https://dummyjson.com/test"} c = ModuleItemRunner(module_path=module_name, class_name=class_name) - print(c.run(args=args, module_conf=module_conf)) + print(c.run(args=args, module_conf={})) From 2c3b8882cf26f1922cd9608131427b8488764888 Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Tue, 2 Jul 2024 17:27:49 +0300 Subject: [PATCH 06/15] Fix linting --- sekoia_automation/scripts/action_runner.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index 0e32ab9..fddaf68 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -75,8 +75,6 @@ def find_file_with_child_class( return None, None def get_docker_params_from_main_py(self) -> dict: - from _ast import AST - main_py_path = self.__module_path / "main.py" with open(main_py_path) as file: content = file.read() From 67890f9935f6723194a57b81eae1575bdc751a2f Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Tue, 2 Jul 2024 17:54:51 +0300 Subject: [PATCH 07/15] Add proper CLI --- sekoia_automation/cli.py | 17 +++++++++++++++++ sekoia_automation/scripts/action_runner.py | 21 +++++---------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/sekoia_automation/cli.py b/sekoia_automation/cli.py index 84d2247..611ac2e 100644 --- a/sekoia_automation/cli.py +++ b/sekoia_automation/cli.py @@ -12,6 +12,7 @@ from sekoia_automation.scripts.openapi import OpenApiToModule from sekoia_automation.scripts.sync_library import SyncLibrary from sekoia_automation.scripts.update_sdk_version import SDKUpdater +from sekoia_automation.scripts.action_runner import ModuleItemRunner app = typer.Typer( help="Sekoia.io's automation helper to generate playbook modules", @@ -185,5 +186,21 @@ def update_sekoia_library( SDKUpdater(modules_path=modules_path).update_sdk_version() +@app.command(name="run-action") +def run_action( + modules_path: Path = typer.Option(".", help="Path to the playbook modules"), + module_name: str = typer.Option(..., help="Name of the module to test"), + class_name: str = typer.Option(..., help="Class name of the action to test"), + args: list[str] = typer.Argument(None, help="Module/Action configuration fields"), +): + kwargs = { + arg.split("=", maxsplit=1)[0]: arg.split("=", maxsplit=1)[1] for arg in args + } + module_runner = ModuleItemRunner( + module_name=module_name, class_name=class_name, root_path=modules_path + ) + print(module_runner.run(args=kwargs)) + + if __name__ == "__main__": app() diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index fddaf68..f6634a8 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -12,12 +12,10 @@ class ModuleItemRunner: - def __init__(self, class_name: str, module_path: str | Path): + def __init__(self, class_name: str, module_name: str, root_path: Path): self.__class_name = class_name - self.__module_path = ( - module_path if isinstance(module_path, Path) else Path(module_path) - ).resolve() - self.__root_path = self.__module_path.parent + self.__root_path = root_path # `automation-library` folder by default + self.__module_path = (root_path / module_name).resolve() def load_class_from_path(self, path: Path | str, class_name: str) -> typing.Type: # Add the directory containing the module to sys.path @@ -142,7 +140,7 @@ def __iter_all_parents(c): raise ValueError("Incorrect class") - def run(self, args: dict, module_conf: dict | None = None) -> dict | None: + def run(self, args: dict) -> dict | None: cls_to_docker = self.get_docker_params_from_main_py() docker_param = cls_to_docker[self.__class_name] manifest: dict = self.get_manifest_by_docker_param( @@ -171,7 +169,7 @@ def run(self, args: dict, module_conf: dict | None = None) -> dict | None: # Prepare module configuration module_annotations = module_cls.__annotations__ module_config_cls = module_annotations["configuration"] - conf_args = module_conf if module_conf else {} + conf_args = {key: args.get(key) for key in module_config_cls.__fields__} module_conf = module_config_cls(**conf_args) module = module_cls() @@ -203,12 +201,3 @@ def run(self, args: dict, module_conf: dict | None = None) -> dict | None: module_item.run() return None - - -if __name__ == "__main__": - class_name = "RequestAction" - module_name = Path("~/PycharmProjects/automation-library/HTTP").expanduser() - args = {"method": "get", "url": "https://dummyjson.com/test"} - - c = ModuleItemRunner(module_path=module_name, class_name=class_name) - print(c.run(args=args, module_conf={})) From 8534461ab3ff9dd24182ff713a7430f6891d09da Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Wed, 3 Jul 2024 09:15:11 +0300 Subject: [PATCH 08/15] Fixes and improvements --- sekoia_automation/cli.py | 11 ++++++----- sekoia_automation/scripts/action_runner.py | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sekoia_automation/cli.py b/sekoia_automation/cli.py index 611ac2e..de28e49 100644 --- a/sekoia_automation/cli.py +++ b/sekoia_automation/cli.py @@ -186,8 +186,13 @@ def update_sekoia_library( SDKUpdater(modules_path=modules_path).update_sdk_version() +if __name__ == "__main__": + app() + + @app.command(name="run-action") def run_action( + data_path: Path = typer.Option(".", help="Path to the context data"), modules_path: Path = typer.Option(".", help="Path to the playbook modules"), module_name: str = typer.Option(..., help="Name of the module to test"), class_name: str = typer.Option(..., help="Class name of the action to test"), @@ -197,10 +202,6 @@ def run_action( arg.split("=", maxsplit=1)[0]: arg.split("=", maxsplit=1)[1] for arg in args } module_runner = ModuleItemRunner( - module_name=module_name, class_name=class_name, root_path=modules_path + module_name=module_name, class_name=class_name, root_path=modules_path, data_path=data_path ) print(module_runner.run(args=kwargs)) - - -if __name__ == "__main__": - app() diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index f6634a8..61bb548 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -12,10 +12,11 @@ class ModuleItemRunner: - def __init__(self, class_name: str, module_name: str, root_path: Path): + def __init__(self, class_name: str, module_name: str, root_path: Path, data_path: Path = Path(".")): self.__class_name = class_name self.__root_path = root_path # `automation-library` folder by default self.__module_path = (root_path / module_name).resolve() + self.__data_path = data_path def load_class_from_path(self, path: Path | str, class_name: str) -> typing.Type: # Add the directory containing the module to sys.path @@ -181,8 +182,8 @@ def run(self, args: dict) -> dict | None: ) module_item = module_item_cls( - module=module, data_path=Path(".") - ) # @todo set custom path? + module=module, data_path=self.__data_path + ) module_item_type = self.get_module_item_type(module_item_cls) if module_item_type == "Action": From 039c328b456f6b1515947cc4386eaa0d13be2509 Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Wed, 3 Jul 2024 09:15:55 +0300 Subject: [PATCH 09/15] Fixes and improvements --- sekoia_automation/cli.py | 13 ++++++++----- sekoia_automation/scripts/action_runner.py | 12 ++++++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/sekoia_automation/cli.py b/sekoia_automation/cli.py index de28e49..a29ab39 100644 --- a/sekoia_automation/cli.py +++ b/sekoia_automation/cli.py @@ -186,10 +186,6 @@ def update_sekoia_library( SDKUpdater(modules_path=modules_path).update_sdk_version() -if __name__ == "__main__": - app() - - @app.command(name="run-action") def run_action( data_path: Path = typer.Option(".", help="Path to the context data"), @@ -202,6 +198,13 @@ def run_action( arg.split("=", maxsplit=1)[0]: arg.split("=", maxsplit=1)[1] for arg in args } module_runner = ModuleItemRunner( - module_name=module_name, class_name=class_name, root_path=modules_path, data_path=data_path + module_name=module_name, + class_name=class_name, + root_path=modules_path, + data_path=data_path, ) print(module_runner.run(args=kwargs)) + + +if __name__ == "__main__": + app() diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index 61bb548..6c791b2 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -12,7 +12,13 @@ class ModuleItemRunner: - def __init__(self, class_name: str, module_name: str, root_path: Path, data_path: Path = Path(".")): + def __init__( + self, + class_name: str, + module_name: str, + root_path: Path, + data_path: Path = Path("."), + ): self.__class_name = class_name self.__root_path = root_path # `automation-library` folder by default self.__module_path = (root_path / module_name).resolve() @@ -181,9 +187,7 @@ def run(self, args: dict) -> dict | None: path=file_path, class_name=self.__class_name ) - module_item = module_item_cls( - module=module, data_path=self.__data_path - ) + module_item = module_item_cls(module=module, data_path=self.__data_path) module_item_type = self.get_module_item_type(module_item_cls) if module_item_type == "Action": From 115ee8dce3de7cf2f82cfe92ae5c30b4212f5c9a Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Wed, 3 Jul 2024 12:42:45 +0300 Subject: [PATCH 10/15] Fix linting --- sekoia_automation/cli.py | 2 +- sekoia_automation/scripts/action_runner.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sekoia_automation/cli.py b/sekoia_automation/cli.py index a29ab39..178b36f 100644 --- a/sekoia_automation/cli.py +++ b/sekoia_automation/cli.py @@ -5,6 +5,7 @@ import typer from cookiecutter.main import cookiecutter +from sekoia_automation.scripts.action_runner import ModuleItemRunner from sekoia_automation.scripts.documentation.generate import ( DocumentationGenerator, ) @@ -12,7 +13,6 @@ from sekoia_automation.scripts.openapi import OpenApiToModule from sekoia_automation.scripts.sync_library import SyncLibrary from sekoia_automation.scripts.update_sdk_version import SDKUpdater -from sekoia_automation.scripts.action_runner import ModuleItemRunner app = typer.Typer( help="Sekoia.io's automation helper to generate playbook modules", diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index 6c791b2..810f5c5 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -2,10 +2,10 @@ import importlib.util import json import sys +import typing from pathlib import Path -from typing import Tuple, Any +from typing import Any, Tuple -import typing from jsonschema import validate from sekoia_automation.module import Module From 628205124c1afaf89fb707ed52ee27d938335e76 Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Wed, 3 Jul 2024 13:04:00 +0300 Subject: [PATCH 11/15] Fixes and improvements --- sekoia_automation/cli.py | 8 +++++--- sekoia_automation/scripts/action_runner.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sekoia_automation/cli.py b/sekoia_automation/cli.py index 178b36f..f892f9e 100644 --- a/sekoia_automation/cli.py +++ b/sekoia_automation/cli.py @@ -194,9 +194,11 @@ def run_action( class_name: str = typer.Option(..., help="Class name of the action to test"), args: list[str] = typer.Argument(None, help="Module/Action configuration fields"), ): - kwargs = { - arg.split("=", maxsplit=1)[0]: arg.split("=", maxsplit=1)[1] for arg in args - } + kwargs = ( + {arg.split("=", maxsplit=1)[0]: arg.split("=", maxsplit=1)[1] for arg in args} + if args + else {} + ) module_runner = ModuleItemRunner( module_name=module_name, class_name=class_name, diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index 810f5c5..e0467aa 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -20,7 +20,7 @@ def __init__( data_path: Path = Path("."), ): self.__class_name = class_name - self.__root_path = root_path # `automation-library` folder by default + self.__root_path = root_path.resolve() # `automation-library` folder by default self.__module_path = (root_path / module_name).resolve() self.__data_path = data_path From 494851cdab3ba3860f87ff8140dcb140fea3a2cc Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Thu, 11 Jul 2024 14:16:52 +0300 Subject: [PATCH 12/15] Fix import path --- sekoia_automation/scripts/action_runner.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index e0467aa..d8839a8 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -24,12 +24,11 @@ def __init__( self.__module_path = (root_path / module_name).resolve() self.__data_path = data_path - def load_class_from_path(self, path: Path | str, class_name: str) -> typing.Type: # Add the directory containing the module to sys.path - module_dir = "/".join(str(path).split("/")[:-1]) - if module_dir not in sys.path: - sys.path.append(module_dir) + if str(self.__module_path) not in sys.path: + sys.path.append(str(self.__module_path)) + def load_class_from_path(self, path: Path | str, class_name: str) -> typing.Type: # Load the module module_name = ( str(Path(path).resolve().relative_to(self.__root_path)) From c3e6f8c036393cec1eb4df738de0af1e32d1f14a Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia Date: Thu, 11 Jul 2024 15:35:19 +0300 Subject: [PATCH 13/15] Fix configuration for a default Module --- sekoia_automation/scripts/action_runner.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index d8839a8..192b2b2 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -122,6 +122,13 @@ def get_manifest_by_docker_param(self, prefix: str, docker_param: str) -> dict: return {} + def get_module_configuration_schema(self) -> dict: + manifest = self.__module_path / "manifest.json" + with open(manifest, "rt") as file: + manifest = json.load(file) + + return manifest.get("configuration", {}) + @staticmethod def get_module_item_type(cls): def __iter_all_parents(c): @@ -169,6 +176,14 @@ def run(self, args: dict) -> dict | None: if module_class_name is None or module_class_path is None: module = Module() + module_conf_schema = self.get_module_configuration_schema() + module_args = { + k: args.get(k) for k in module_conf_schema.get("properties", []) + } + if len(module_args) > 0: + validate(instance=module_args, schema=module_conf_schema) + module.configuration = module_args + else: module_cls = self.load_class_from_path(module_class_path, module_class_name) From 69681cc28957ee99eae8c6d32a9983421bedd397 Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia <135212489+lvoloshyn-sekoia@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:30:37 +0300 Subject: [PATCH 14/15] Remove redundant arg --- sekoia_automation/scripts/action_runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index 192b2b2..ee42a47 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -124,7 +124,7 @@ def get_manifest_by_docker_param(self, prefix: str, docker_param: str) -> dict: def get_module_configuration_schema(self) -> dict: manifest = self.__module_path / "manifest.json" - with open(manifest, "rt") as file: + with open(manifest) as file: manifest = json.load(file) return manifest.get("configuration", {}) From fe1700c0ce85361565f70717d8d589ed9b487ab3 Mon Sep 17 00:00:00 2001 From: lvoloshyn-sekoia <135212489+lvoloshyn-sekoia@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:33:11 +0300 Subject: [PATCH 15/15] Mypy fix --- sekoia_automation/scripts/action_runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sekoia_automation/scripts/action_runner.py b/sekoia_automation/scripts/action_runner.py index ee42a47..dad770e 100644 --- a/sekoia_automation/scripts/action_runner.py +++ b/sekoia_automation/scripts/action_runner.py @@ -123,8 +123,8 @@ def get_manifest_by_docker_param(self, prefix: str, docker_param: str) -> dict: return {} def get_module_configuration_schema(self) -> dict: - manifest = self.__module_path / "manifest.json" - with open(manifest) as file: + manifest_path = self.__module_path / "manifest.json" + with open(manifest_path) as file: manifest = json.load(file) return manifest.get("configuration", {})