From 946a522ee584dad85fc5e11e4673622807cfe332 Mon Sep 17 00:00:00 2001 From: msankows Date: Mon, 11 Aug 2025 14:11:23 +0200 Subject: [PATCH] feat: Rewriting HTTP connector to use SDK BREAKING CHANGE: A core of the application is migrated to use SDK. --- .DS_Store | Bin 0 -> 6148 bytes .pre-commit-config.yaml | 83 +-- http.json | 1427 --------------------------------------- http_connector.py | 927 ------------------------- http_consts.py | 46 -- pyproject.toml | 83 +-- requirements.txt | 3 - src/__init__.py | 3 + src/app.py | 107 +++ tox.ini | 4 + uv.lock | 746 ++++++++++++++++++++ 11 files changed, 872 insertions(+), 2557 deletions(-) create mode 100644 .DS_Store delete mode 100644 http.json delete mode 100644 http_connector.py delete mode 100644 http_consts.py delete mode 100644 requirements.txt create mode 100644 src/__init__.py create mode 100644 src/app.py create mode 100644 tox.ini create mode 100644 uv.lock diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..412b44e1c1a03fcd08a7e4df329e9da0b50ca614 GIT binary patch literal 6148 zcmeHK%}xR_5dMlpAw=cK#blp=#5Y)hjUiDkEq{F8^SJl z@nDRZA)Rk_I@3dHL^n9%9qU_Cr>yoFV_GA6$9x)M#=Zq@(OYJBM;z~ct@d5c z+S7VjL4I!cR*0=~eF<0J!8viu=vwXi==)kbase_url. The action will succeed if given a status code between 200 and 399 (inclusive). Therefore, if the given base URL requires no authentication, this action may pass even if the supplied credentials are incorrect. Alternately, if the given base URL does not point to a valid endpoint, this action could fail even if other actions may succeed with valid location parameters.", - "type": "test", - "read_only": true, - "parameters": {}, - "output": [], - "versions": "EQ(*)" - }, - { - "action": "put data", - "description": "Perform a REST PUT call to the server", - "type": "generic", - "identifier": "http_put", - "read_only": false, - "parameters": { - "location": { - "description": "Location (e.g. path/to/endpoint?query=string)", - "data_type": "string", - "order": 0, - "primary": true, - "contains": [ - "endpoint" - ], - "required": true - }, - "body": { - "description": "PATCH body (query string, JSON, etc.)", - "data_type": "string", - "order": 1, - "required": true - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 2 - }, - "headers": { - "description": "Additional headers (JSON object with headers)", - "data_type": "string", - "order": 3 - } - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.body", - "data_type": "string", - "example_values": [ - "{\"name\": \"Bad IP\"}" - ] - }, - { - "data_path": "action_result.parameter.headers", - "data_type": "string", - "example_values": [ - "{\"Content-Type\": \"application/json\"}" - ] - }, - { - "data_path": "action_result.parameter.location", - "data_type": "string", - "contains": [ - "endpoint" - ], - "example_values": [ - "/rest/assets" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.data.*.location", - "data_type": "string", - "contains": [ - "url" - ], - "example_values": [ - "http://192.168.1.26/rest/assets" - ] - }, - { - "data_path": "action_result.data.*.method", - "data_type": "string", - "example_values": [ - "PUT" - ] - }, - { - "data_path": "action_result.data.*.parsed_response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_headers", - "data_type": "string" - }, - { - "data_path": "action_result.summary.reason", - "data_type": "string", - "example_values": [ - "Not Found" - ] - }, - { - "data_path": "action_result.summary.status_code", - "data_type": "numeric", - "example_values": [ - 404 - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "example_values": [ - "Can't process response from server. Status Code: 404 Data from server: {\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 0 - ] - } - ], - "render": { - "type": "json" - }, - "versions": "EQ(*)" - }, - { - "action": "patch data", - "description": "Perform a REST PATCH call to the server", - "type": "generic", - "identifier": "http_patch", - "read_only": false, - "parameters": { - "location": { - "description": "Location (e.g. path/to/endpoint?query=string)", - "data_type": "string", - "order": 0, - "primary": true, - "contains": [ - "endpoint" - ], - "required": true - }, - "body": { - "description": "PATCH body (query string, JSON, etc.)", - "data_type": "string", - "order": 1 - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 2 - }, - "headers": { - "description": "Additional headers (JSON object with headers)", - "data_type": "string", - "order": 3 - } - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.body", - "data_type": "string", - "example_values": [ - "{\"name\": \"Bad IP\"}" - ] - }, - { - "data_path": "action_result.parameter.headers", - "data_type": "string", - "example_values": [ - "{\"Content-Type\": \"application/json\"}" - ] - }, - { - "data_path": "action_result.parameter.location", - "data_type": "string", - "contains": [ - "endpoint" - ], - "example_values": [ - "/rest/assets" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.data.*.location", - "data_type": "string", - "contains": [ - "url" - ], - "example_values": [ - "http://192.168.1.26/rest/assets" - ] - }, - { - "data_path": "action_result.data.*.method", - "data_type": "string", - "example_values": [ - "PATCH" - ] - }, - { - "data_path": "action_result.data.*.parsed_response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_headers", - "data_type": "string" - }, - { - "data_path": "action_result.summary.reason", - "data_type": "string", - "example_values": [ - "Not Found" - ] - }, - { - "data_path": "action_result.summary.status_code", - "data_type": "numeric", - "example_values": [ - 404 - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "example_values": [ - "Can't process response from server. Status Code: 404 Data from server: {\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 0 - ] - } - ], - "render": { - "type": "json" - }, - "versions": "EQ(*)" - }, - { - "action": "delete data", - "description": "Perform a REST DELETE call to the server", - "type": "generic", - "identifier": "http_delete", - "read_only": false, - "parameters": { - "location": { - "description": "Location (e.g. path/to/endpoint?query=string)", - "data_type": "string", - "order": 0, - "primary": true, - "contains": [ - "endpoint" - ], - "required": true - }, - "body": { - "description": "DELETE body (query string, JSON, etc.)", - "data_type": "string", - "order": 1 - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 2 - }, - "headers": { - "description": "Additional headers (JSON object with headers)", - "data_type": "string", - "order": 3 - } - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.body", - "data_type": "string", - "example_values": [ - "{\"name\": \"Bad IP\"}" - ] - }, - { - "data_path": "action_result.parameter.headers", - "data_type": "string", - "example_values": [ - "{\"Content-Type\": \"application/json\"}" - ] - }, - { - "data_path": "action_result.parameter.location", - "data_type": "string", - "contains": [ - "endpoint" - ], - "example_values": [ - "/rest/assets" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.data.*.location", - "data_type": "string", - "contains": [ - "url" - ], - "example_values": [ - "http://192.168.1.26/rest/assets" - ] - }, - { - "data_path": "action_result.data.*.method", - "data_type": "string", - "example_values": [ - "DELETE" - ] - }, - { - "data_path": "action_result.data.*.parsed_response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_headers", - "data_type": "string" - }, - { - "data_path": "action_result.summary.reason", - "data_type": "string", - "example_values": [ - "Not Found" - ] - }, - { - "data_path": "action_result.summary.status_code", - "data_type": "numeric", - "example_values": [ - 404 - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "example_values": [ - "Can't process response from server. Status Code: 404 Data from server: {\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 0 - ] - } - ], - "render": { - "type": "json" - }, - "versions": "EQ(*)" - }, - { - "action": "get headers", - "description": "Perform a REST HEAD call to the server", - "type": "investigate", - "identifier": "http_head", - "read_only": true, - "parameters": { - "location": { - "description": "Location (e.g. path/to/endpoint?query=string)", - "data_type": "string", - "order": 0, - "primary": true, - "contains": [ - "endpoint" - ], - "required": true - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 1 - }, - "headers": { - "description": "Additional headers (JSON object with headers)", - "data_type": "string", - "order": 2 - } - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.headers", - "data_type": "string", - "example_values": [ - "{\"User-Agent\": \"automation\"}" - ] - }, - { - "data_path": "action_result.parameter.location", - "data_type": "string", - "contains": [ - "endpoint" - ], - "example_values": [ - "/rest/cont" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.data.*.location", - "data_type": "string", - "contains": [ - "url" - ], - "example_values": [ - "http://192.168.1.26/rest/cont" - ] - }, - { - "data_path": "action_result.data.*.method", - "data_type": "string", - "example_values": [ - "HEAD" - ] - }, - { - "data_path": "action_result.data.*.response_headers", - "data_type": "string" - }, - { - "data_path": "action_result.summary.reason", - "data_type": "string", - "example_values": [ - "OK" - ] - }, - { - "data_path": "action_result.summary.status_code", - "data_type": "numeric", - "example_values": [ - 200 - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "example_values": [ - "Status code: 200, Reason: OK" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 1 - ] - } - ], - "render": { - "type": "json" - }, - "versions": "EQ(*)" - }, - { - "action": "get options", - "description": "Perform a REST OPTIONS call to the server", - "type": "investigate", - "identifier": "http_options", - "read_only": true, - "parameters": { - "location": { - "description": "Location (e.g. path/to/endpoint?query=string)", - "data_type": "string", - "order": 0, - "primary": true, - "contains": [ - "endpoint" - ], - "required": true - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 1 - }, - "headers": { - "description": "Additional headers (JSON object with headers)", - "data_type": "string", - "order": 2 - } - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.headers", - "data_type": "string" - }, - { - "data_path": "action_result.parameter.location", - "data_type": "string", - "contains": [ - "endpoint" - ], - "example_values": [ - "/rest/cont" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.data.*.location", - "data_type": "string", - "contains": [ - "url" - ], - "example_values": [ - "http://192.168.1.26/rest/cont" - ] - }, - { - "data_path": "action_result.data.*.method", - "data_type": "string", - "example_values": [ - "OPTIONS" - ] - }, - { - "data_path": "action_result.data.*.parsed_response_body", - "data_type": "string", - "example_values": [ - "GET,HEAD,PUT,POST,DELETE,PATCH" - ] - }, - { - "data_path": "action_result.data.*.response_body", - "data_type": "string", - "example_values": [ - "GET,HEAD,PUT,POST,DELETE,PATCH" - ] - }, - { - "data_path": "action_result.data.*.response_headers", - "data_type": "string" - }, - { - "data_path": "action_result.summary.reason", - "data_type": "string", - "example_values": [ - "OK" - ] - }, - { - "data_path": "action_result.summary.status_code", - "data_type": "numeric", - "example_values": [ - 200 - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "example_values": [ - "Status code: 200, Reason: OK" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 1 - ] - } - ], - "render": { - "type": "json" - }, - "versions": "EQ(*)" - }, - { - "action": "get data", - "description": "Perform a REST GET call to the server", - "type": "investigate", - "identifier": "http_get", - "read_only": true, - "parameters": { - "location": { - "description": "Location (e.g. path/to/endpoint?query=string)", - "data_type": "string", - "order": 0, - "primary": true, - "contains": [ - "endpoint" - ], - "required": true - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 1 - }, - "headers": { - "description": "Additional headers (JSON object with headers)", - "data_type": "string", - "order": 2 - } - }, - "render": { - "type": "json", - "width": 10, - "height": 5, - "title": "GET DATA" - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.headers", - "data_type": "string", - "example_values": [ - "{\"Content-Type\": \"application/json\"}" - ] - }, - { - "data_path": "action_result.parameter.location", - "data_type": "string", - "contains": [ - "endpoint" - ], - "example_values": [ - "/rest/cont" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.data.*.location", - "data_type": "string", - "contains": [ - "url" - ], - "example_values": [ - "http://192.168.1.26/rest/cont" - ] - }, - { - "data_path": "action_result.data.*.method", - "data_type": "string", - "example_values": [ - "GET" - ] - }, - { - "data_path": "action_result.data.*.parsed_response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_headers", - "data_type": "string" - }, - { - "data_path": "action_result.summary.reason", - "data_type": "string", - "example_values": [ - "Not Found" - ] - }, - { - "data_path": "action_result.summary.status_code", - "data_type": "numeric", - "example_values": [ - 404 - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "example_values": [ - "Can't process response from server. Status Code: 404 Data from server: {\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 0 - ] - } - ], - "versions": "EQ(*)" - }, - { - "action": "post data", - "description": "Perform a REST POST call to the server", - "type": "generic", - "identifier": "http_post", - "read_only": false, - "parameters": { - "location": { - "description": "Location (e.g. path/to/endpoint)", - "data_type": "string", - "order": 0, - "primary": true, - "contains": [ - "endpoint" - ], - "required": true - }, - "body": { - "description": "POST body (query string, JSON, etc.)", - "data_type": "string", - "order": 1 - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 2 - }, - "headers": { - "description": "Additional headers (JSON object with headers)", - "data_type": "string", - "order": 3 - } - }, - "render": { - "type": "json", - "width": 10, - "height": 5, - "title": "POST DATA" - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.body", - "data_type": "string", - "example_values": [ - "{\"name\": \"Bad IP\"}" - ] - }, - { - "data_path": "action_result.parameter.headers", - "data_type": "string", - "example_values": [ - "{\"Content-Type\": \"application/json\"}" - ] - }, - { - "data_path": "action_result.parameter.location", - "data_type": "string", - "contains": [ - "endpoint" - ], - "example_values": [ - "/rest/assets" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.data.*.location", - "data_type": "string", - "contains": [ - "url" - ], - "example_values": [ - "http://192.168.1.26/rest/assets" - ] - }, - { - "data_path": "action_result.data.*.method", - "data_type": "string", - "example_values": [ - "POST" - ] - }, - { - "data_path": "action_result.data.*.parsed_response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_body", - "data_type": "string", - "example_values": [ - "{\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "action_result.data.*.response_headers", - "data_type": "string" - }, - { - "data_path": "action_result.summary.reason", - "data_type": "string", - "example_values": [ - "Not Found" - ] - }, - { - "data_path": "action_result.summary.status_code", - "data_type": "numeric", - "example_values": [ - 404 - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "example_values": [ - "Can't process response from server. Status Code: 404 Data from server: {\"failed\": true, \"message\": \"Requested item not found\"}" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 0 - ] - } - ], - "versions": "EQ(*)" - }, - { - "action": "get file", - "description": "Retrieve a file from the endpoint and save it to the vault", - "verbose": "Provide the file path and file name to download into the vault. For example, /web_storage/file.tgz.", - "type": "investigate", - "identifier": "get_file", - "read_only": true, - "parameters": { - "hostname": { - "data_type": "string", - "order": 0, - "description": "Hostname to execute command on", - "contains": [ - "host name" - ], - "primary": true - }, - "file_path": { - "data_type": "string", - "order": 1, - "description": "Path of the file to download (include filename)", - "contains": [ - "file path" - ], - "required": true, - "primary": true - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 2 - } - }, - "render": { - "width": 12, - "title": "Get File", - "type": "table", - "height": 5 - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.file_path", - "data_type": "string", - "contains": [ - "file path" - ], - "example_values": [ - "/web_storage/file.tgz" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.parameter.hostname", - "data_type": "string", - "contains": [ - "host name" - ], - "example_values": [ - "http://192.168.0.1" - ] - }, - { - "data_path": "action_result.data", - "data_type": "string" - }, - { - "data_path": "action_result.summary.exit_status", - "data_type": "numeric", - "example_values": [ - 0 - ] - }, - { - "data_path": "action_result.summary.name", - "data_type": "string", - "example_values": [ - "file.tgz" - ] - }, - { - "data_path": "action_result.summary.size", - "data_type": "numeric", - "example_values": [ - 412 - ] - }, - { - "data_path": "action_result.summary.vault_id", - "data_type": "string", - "contains": [ - "vault id" - ], - "column_order": 1, - "column_name": "Vault ID", - "example_values": [ - "dc871f816c4d179f3a3cea24b4bc81a67562c" - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "column_order": 0, - "column_name": "Result Message", - "example_values": [ - "Transferred file" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 1 - ] - } - ], - "versions": "EQ(*)" - }, - { - "action": "put file", - "description": "Put a file from the vault to another location", - "type": "generic", - "identifier": "put_file", - "verbose": "Provide the path to store the file on the file server. For example, /web_storage/test_repo/.", - "read_only": false, - "parameters": { - "host": { - "data_type": "string", - "order": 0, - "description": "Hostname/IP with port number to execute command on", - "contains": [ - "host name" - ], - "primary": true - }, - "vault_id": { - "data_type": "string", - "order": 1, - "contains": [ - "vault id" - ], - "description": "Vault ID of file", - "required": true, - "primary": true - }, - "file_destination": { - "description": "File destination path (exclude filename)", - "data_type": "string", - "order": 2, - "contains": [ - "file path" - ], - "required": true, - "primary": true - }, - "file_name": { - "description": "Name of the file to be put on endpoint", - "data_type": "string", - "order": 3 - }, - "verify_certificate": { - "description": "Verify certificates (if using HTTPS)", - "data_type": "boolean", - "order": 4 - } - }, - "render": { - "width": 12, - "title": "Put File", - "type": "table", - "height": 5 - }, - "output": [ - { - "data_path": "action_result.status", - "data_type": "string", - "example_values": [ - "success", - "failed" - ] - }, - { - "data_path": "action_result.parameter.file_name", - "data_type": "string", - "example_values": [ - "test.txt" - ] - }, - { - "data_path": "action_result.parameter.file_destination", - "data_type": "string", - "contains": [ - "file path" - ], - "example_values": [ - "/web_storage/test_repo/" - ] - }, - { - "data_path": "action_result.parameter.host", - "data_type": "string", - "contains": [ - "host name" - ], - "example_values": [ - "http://192.168.0.1:8001" - ] - }, - { - "data_path": "action_result.parameter.verify_certificate", - "data_type": "boolean", - "example_values": [ - false, - true - ] - }, - { - "data_path": "action_result.parameter.vault_id", - "data_type": "string", - "contains": [ - "vault id" - ], - "column_order": 0, - "column_name": "Vault ID", - "example_values": [ - "dc871f816c4d179f3a3cea24b4bc81a67562c" - ] - }, - { - "data_path": "action_result.data", - "data_type": "string" - }, - { - "data_path": "action_result.summary.file_sent", - "data_type": "string", - "column_order": 1, - "column_name": "File Transferred", - "contains": [ - "file path" - ], - "example_values": [ - "http://192.168.0.1:8001/web_storage/test_repo/file.tgz" - ] - }, - { - "data_path": "action_result.message", - "data_type": "string", - "column_order": 2, - "column_name": "Result Message", - "example_values": [ - "File sent: http://192.168.0.1:8001/web_storage/test_repo/file.tgz" - ] - }, - { - "data_path": "summary.total_objects", - "data_type": "numeric", - "example_values": [ - 1 - ] - }, - { - "data_path": "summary.total_objects_successful", - "data_type": "numeric", - "example_values": [ - 1 - ] - } - ], - "versions": "EQ(*)" - } - ], - "pip39_dependencies": { - "wheel": [ - { - "module": "validators", - "input_file": "wheels/py3/validators-0.35.0-py3-none-any.whl" - } - ] - }, - "pip313_dependencies": { - "wheel": [ - { - "module": "validators", - "input_file": "wheels/py3/validators-0.35.0-py3-none-any.whl" - } - ] - } -} diff --git a/http_connector.py b/http_connector.py deleted file mode 100644 index a8a4ed2..0000000 --- a/http_connector.py +++ /dev/null @@ -1,927 +0,0 @@ -# File: http_connector.py -# -# Copyright (c) 2016-2025 Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed under -# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific language governing permissions -# and limitations under the License. - -import json -import os -import re -import shutil -import socket -import sys -import uuid -from urllib.parse import quote, unquote_plus, urlparse - -import encryption_helper -import magic -import phantom.app as phantom -import phantom.rules as ph_rules -import requests -import validators -import xmltodict -from bs4 import BeautifulSoup, UnicodeDammit -from phantom.action_result import ActionResult -from phantom.base_connector import BaseConnector -from phantom.vault import Vault as Vault -from requests.auth import HTTPBasicAuth - -from http_consts import * - - -class RetVal(tuple): - def __new__(cls, val1, val2=None): - return tuple.__new__(RetVal, (val1, val2)) - - -class HttpConnector(BaseConnector): - MAGIC_FORMATS = [ - (re.compile("^PE.* Windows"), ["pe file"], ".exe"), - (re.compile("^MS-DOS executable"), ["pe file"], ".exe"), - (re.compile("^PDF "), ["pdf"], ".pdf"), - (re.compile("^MDMP crash"), ["process dump"], ".dmp"), - (re.compile("^Macromedia Flash"), ["flash"], ".flv"), - (re.compile("^tcpdump capture"), ["pcap"], ".pcap"), - ] - - def __init__(self): - super().__init__() - - self._state = None - self._base_url = None - self._test_path = None - self._timeout = None - self._token_name = None - self._token = None - self._username = None - self._password = None - self._oauth_token_url = None - self._client_id = None - self._client_secret = None - self._access_token = None - self.access_token_retry = True - - def encrypt_state(self, encrypt_var, token_name): - """Handle encryption of token. - :param encrypt_var: Variable needs to be encrypted - :return: encrypted variable - """ - self.debug_print(HTTP_ENCRYPT_TOKEN.format(token_name)) # nosemgrep - return encryption_helper.encrypt(encrypt_var, self.get_asset_id()) - - def decrypt_state(self, decrypt_var, token_name): - """Handle decryption of token. - :param decrypt_var: Variable needs to be decrypted - :return: decrypted variable - """ - self.debug_print(HTTP_DECRYPT_TOKEN.format(token_name)) # nosemgrep - return encryption_helper.decrypt(decrypt_var, self.get_asset_id()) - - def _get_error_message_from_exception(self, e): - """This function is used to get appropriate error message from the exception. - :param e: Exception object - :return: error message - """ - error_msg = HTTP_ERR_MSG - error_code = HTTP_ERR_CODE_MSG - try: - if hasattr(e, "args"): - if len(e.args) > 1: - error_code = e.args[0] - error_msg = e.args[1] - elif len(e.args) == 1: - error_code = HTTP_ERR_CODE_MSG - error_msg = e.args[0] - except Exception as ex: - self.error_print("Exception occurred.", ex) - - return f"Error Code: {error_code}. Error Message: {error_msg}" - - def _validate_integers(self, action_result, parameter, key, allow_zero=False): - """This method is to check if the provided input parameter value - is a non-zero positive integer and returns the integer value of the parameter itself. - :param action_result: Action result or BaseConnector object - :param parameter: input parameter - :return: integer value of the parameter or None in case of failure - """ - try: - if not float(parameter).is_integer(): - self.set_status(phantom.APP_ERROR, HTTP_VALIDATE_INTEGER_MSG.format(key=key)) - return None - parameter = int(parameter) - - except Exception as ex: - self.error_print("Exception occurred.", ex) - self.set_status(phantom.APP_ERROR, HTTP_VALIDATE_INTEGER_MSG.format(key=key)) - return None - - if parameter < 0: - self.set_status( - phantom.APP_ERROR, - f"Please provide a valid non-negative integer value in the {key} parameter", - ) - return None - if not allow_zero and parameter == 0: - self.set_status( - phantom.APP_ERROR, - f"Please provide a positive integer value in the {key} parameter", - ) - return None - - return parameter - - def initialize(self): - self._state = self.load_state() - - if not isinstance(self._state, dict): - self.debug_print("Resetting the state file with the default format") - self._state = {"app_version": self.get_app_json().get("app_version")} - - config = self.get_config() - self._base_url = config["base_url"].strip("/") - self._token_name = config.get("auth_token_name", "ph-auth-token") - self._token = config.get("auth_token") - - self._username = config.get("username") - self._password = config.get("password", "") - self._test_http_method = config.get("test_http_method", "get").lower() - - self._oauth_token_url = config.get("oauth_token_url") - if self._oauth_token_url: - self._oauth_token_url = self._oauth_token_url.strip("/") - self._client_id = config.get("client_id") - self._client_secret = config.get("client_secret") - self._access_token = self._state.get(HTTP_JSON_ACCESS_TOKEN) - - if "test_path" in config: - try: - if not config["test_path"].startswith("/"): - self._test_path = "/" + config["test_path"] - else: - self._test_path = config["test_path"] - except Exception as e: - error_message = self._get_error_message_from_exception(e) - return self.set_status( - phantom.APP_ERROR, - f"Given endpoint value is invalid: {error_message}", - ) - - if "timeout" in config: - self._timeout = self._validate_integers(self, config.get("timeout"), "timeout") - if self._timeout is None: - return self.get_status() - - parsed = urlparse(self._base_url) - - if not parsed.scheme or not parsed.hostname: - return self.set_status( - phantom.APP_ERROR, - f'Failed to parse URL ({self._base_url}). Should look like "http(s)://location/optional_path"', - ) - - # Make sure base_url isn't 127.0.0.1 - addr = parsed.hostname - try: - unpacked = socket.gethostbyname(addr) - except Exception as ex: - self.error_print("Exception occurred.", ex) - try: - packed = socket.inet_aton(addr) - unpacked = socket.inet_aton(packed) - except Exception as ex: - self.error_print("Exception occurred.", ex) - # gethostbyname can fail even when the addr is a hostname - # If that happens, I think we can assume that it isn't localhost - unpacked = "" - - if unpacked.startswith("127."): - return self.set_status(phantom.APP_ERROR, "Accessing 127.0.0.1 is not allowed") - - if self._state.get(HTTP_STATE_IS_ENCRYPTED): - try: - if self._access_token: - self._access_token = self.decrypt_state(self._access_token, "access") - except Exception as e: - self.error_print(HTTP_DECRYPTION_ERR, e) - return self.set_status(phantom.APP_ERROR, HTTP_DECRYPTION_ERR) - - return phantom.APP_SUCCESS - - def finalize(self): - try: - if self._access_token: - self._state[HTTP_JSON_ACCESS_TOKEN] = self.encrypt_state(self._access_token, "access") - self._state[HTTP_STATE_IS_ENCRYPTED] = True - except Exception as e: - self.error_print(HTTP_ENCRYPTION_ERR, e) - return self.set_status(phantom.APP_ERROR, HTTP_ENCRYPTION_ERR) - - self.save_state(self._state) - return phantom.APP_SUCCESS - - def _process_empty_reponse(self, response, action_result): - if 200 <= response.status_code < 400: - if response.headers.get("Content-Type") == "application/octet-stream": - return RetVal(phantom.APP_SUCCESS, "Response includes a file") - return RetVal(phantom.APP_SUCCESS, None) - return RetVal( - action_result.set_status(phantom.APP_ERROR, "Empty response and no information in the header"), - None, - ) - - def _process_html_response(self, response, action_result): - status_code = response.status_code - - try: - soup = BeautifulSoup(response.text, "html.parser") - for element in soup(["script", "style", "footer", "nav"]): - element.extract() - error_text = soup.text - split_lines = error_text.split("\n") - split_lines = [x.strip() for x in split_lines if x.strip()] - error_text = "\n".join(split_lines) - except Exception as ex: - self.error_print("Exception occurred.", ex) - error_text = "Cannot parse error details" - - response_data = error_text - if 200 <= response.status_code < 400: - return RetVal(phantom.APP_SUCCESS, response_data) - - message = f"Status Code: {status_code}. Data from server:\n{unquote_plus(error_text)}\n" - - message = message.replace("{", "{{").replace("}", "}}") - - return RetVal(action_result.set_status(phantom.APP_ERROR, message), response_data) - - def _process_json_response(self, response, action_result): - resp_json = {} - try: - if response: - resp_json = response.json() - except Exception as e: - error_message = self._get_error_message_from_exception(e) - self.error_print("Unable to parse the response into a dictionary", error_message) - return RetVal( - action_result.set_status( - phantom.APP_ERROR, - f"Unable to parse JSON response. Error: {error_message}", - ) - ) - - if 200 <= response.status_code < 400: - return RetVal(phantom.APP_SUCCESS, resp_json) - - message_template = "Error from server. Status Code: {0} Data from server: {1}" - message = message_template.format(response.status_code, response.text.replace("{", "{{").replace("}", "}}")) - - error_field_name = "error" - message_field_name = "message" - if error_field_name in resp_json: - error_field = resp_json[error_field_name] - - if isinstance(error_field, dict) and message_field_name in error_field: - error_message = error_field[message_field_name] - else: - error_message = error_field - - message = message_template.format(response.status_code, error_message) - - return RetVal(action_result.set_status(phantom.APP_ERROR, message), resp_json) - - def _process_xml_response(self, r, action_result): - resp_json = None - try: - if r.text: - resp_json = xmltodict.parse(r.text) - except Exception as e: - error_message = self._get_error_message_from_exception(e) - return RetVal( - action_result.set_status( - phantom.APP_ERROR, - f"Unable to parse XML response. Error: {error_message}", - ) - ) - - if 200 <= r.status_code < 400: - return RetVal(phantom.APP_SUCCESS, resp_json) - - message = "Error from server. Status Code: {} Data from server: {}".format(r.status_code, r.text.replace("{", "{{").replace("}", "}}")) - - return RetVal(action_result.set_status(phantom.APP_ERROR, message), resp_json) - - def _process_response(self, r, action_result): - if r.headers.get("Content-Type", "") == "application/octet-stream": - r_text = "" - else: - r_text = r.text - - if hasattr(action_result, "add_debug_data"): - action_result.add_debug_data({"r_status_code": r.status_code}) - action_result.add_debug_data({"r_text": r_text}) - action_result.add_debug_data({"r_headers": r.headers}) - - if not r_text: - return self._process_empty_reponse(r, action_result) - if "xml" in r.headers.get("Content-Type", ""): - return self._process_xml_response(r, action_result) - if "json" in r.headers.get("Content-Type", "") or "javascript" in r.headers.get("Content-Type", ""): - return self._process_json_response(r, action_result) - if "html" in r.headers.get("Content-Type", ""): - return self._process_html_response(r, action_result) - if 200 <= r.status_code < 400: - return RetVal(phantom.APP_SUCCESS, r_text) - - message = "Can't process response from server. Status Code: {} Data from server: {}".format( - r.status_code, r.text.replace("{", "{{").replace("}", "}}") - ) - - return RetVal(action_result.set_status(phantom.APP_ERROR, message), r.text) - - def _make_http_call( - self, - action_result, - endpoint="", - method="get", - headers=None, - params=None, - verify=False, - data=None, - files=None, - use_default_endpoint=False, - ): - auth = None - headers = {} if not headers else headers - access_token = "" - if self._username: - self.save_progress("Using HTTP Basic auth to authenticate") - auth = (self._username, self._password) - elif self._oauth_token_url and self._client_id: - self.save_progress("Using OAuth to authenticate") - access_token = self._generate_api_token(action_result) - if not access_token: - return action_result.get_status(), None - headers["Authorization"] = f"Bearer {access_token}" - elif self._token_name: - self.save_progress("Using provided token to authenticate") - if self._token and self._token_name not in headers: - headers[self._token_name] = self._token - else: - return action_result.set_status(phantom.APP_ERROR, "No authentication method set"), None - - if self.get_action_identifier() == "get_file" or self.get_action_identifier() == "put_file": - url = endpoint - if not use_default_endpoint: - auth = None - else: - url = self._base_url + endpoint - - try: - r = requests.request( - method=method, - url=url, - auth=auth, - params=params, - data=UnicodeDammit(data).unicode_markup.encode("utf-8") if isinstance(data, str) else data, - verify=verify, - headers=headers, - files=files, - timeout=self._timeout, - ) - - except Exception as e: - error_message = self._get_error_message_from_exception(e) - return action_result.set_status( - phantom.APP_ERROR, - f"Error Connecting to server. Details: {error_message}", - ), None - - # fetch new token if old one has expired - if access_token and r.status_code == 401 and self.access_token_retry: - self.save_progress(f"Got error: {r.status_code}") - self._access_token = None - self._state.pop("access_token") - self.access_token_retry = False # make it to false to avoid getting access token after one time (prevents recursive loop) - return self._make_http_call( - action_result, - endpoint=endpoint, - method=method, - headers=headers, - params=params, - verify=verify, - data=data, - files=files, - use_default_endpoint=use_default_endpoint, - ) - - # Return success for get headers action as it returns empty response body - if self.get_action_identifier() == "http_head" and r.status_code == 200: - resp_data = {"method": method.upper(), "location": url} - try: - resp_data["response_headers"] = dict(r.headers) - except Exception: - pass - action_result.add_data(resp_data) - action_result.update_summary({"status_code": r.status_code, "reason": r.reason}) - self.access_token_retry = True - return action_result.set_status(phantom.APP_SUCCESS), None - - ret_val, parsed_body = self._process_response(r, action_result) - - if self.get_action_identifier() == "get_file" or self.get_action_identifier() == "put_file": - return ret_val, r - - content_type = r.headers.get("Content-Type", "") - if "json" not in content_type and "javascript" not in content_type: - response_body = r.text - else: - response_body = parsed_body - - resp_data = { - "method": method.upper(), - "location": url, - "parsed_response_body": parsed_body, - "response_body": response_body, - } - try: - resp_data["response_headers"] = dict(r.headers) - except Exception: - pass - action_result.add_data(resp_data) - action_result.update_summary({"status_code": r.status_code, "reason": r.reason}) - - if self.get_action_identifier() == "test_connectivity": - self.save_progress(f"Got status code {r.status_code}") - - if phantom.is_fail(ret_val): - return ret_val, None - - return action_result.set_status(phantom.APP_SUCCESS), None - - def _get_headers(self, action_result, headers): - # Not to be confused with the action "get headers" - if headers is None: - return RetVal(phantom.APP_SUCCESS) - - if hasattr(headers, "decode"): - headers = headers.decode("utf-8") - - try: - headers = json.loads(headers) - except Exception as e: - error_message = self._get_error_message_from_exception(e) - return RetVal( - action_result.set_status( - phantom.APP_ERROR, - f"Failed to parse headers as JSON object. error: {error_message}, headers: {headers}", - ) - ) - - return RetVal(phantom.APP_SUCCESS, headers) - - def _generate_api_token(self, action_result, new_token=False): - """This function is used to generate token - - :param action_result: object of ActionResult class - :param new_token: boolean. weather to fetch new token or fetch old access token - :return: access token - """ - self.save_progress("Fetching access token") - - if self._access_token and not new_token: - self.save_progress("Using old token") - return self._access_token - - payload = {"grant_type": "client_credentials"} - - self.save_progress("Fetching new token") - # Querying endpoint to generate token - response = requests.post( - self._oauth_token_url, - auth=HTTPBasicAuth(self._client_id, self._client_secret), # nosemgrep - data=payload, - timeout=DEFAULT_REQUEST_TIMEOUT, - ) - if response.status_code not in [200, 201]: - action_result.set_status( - phantom.APP_ERROR, - f"Error fetching token from {self._oauth_token_url}. Server returned {response.status_code}", - ) - return None - - try: - self._access_token = json.loads(response.text).get(HTTP_JSON_ACCESS_TOKEN) - except Exception: - action_result.set_status( - phantom.APP_ERROR, - "Error parsing response from server while fetching token", - ) - return None - - if not self._access_token: - action_result.set_status(phantom.APP_ERROR, "Access token not found in response body") - return None - - self._state[HTTP_JSON_ACCESS_TOKEN] = self._access_token - return self._access_token - - def _handle_test_connectivity(self, param): - self.save_progress(f"In action handler for: {self.get_action_identifier()}") - action_result = self.add_action_result(ActionResult(dict(param))) - test_path = self._test_path - - if test_path: - self.save_progress(f"Querying base url, {self._base_url}{self._test_path}, to test credentials") - ret_val, _ = self._make_http_call(action_result, test_path, method=self._test_http_method) - else: - self.save_progress(f"Querying base url, {self._base_url}, to test credentials") - ret_val, _ = self._make_http_call(action_result, method=self._test_http_method) - - if phantom.is_fail(ret_val): - self.save_progress("Test Connectivity Failed") - else: - self.save_progress("Test Connectivity Passed") - - return ret_val - - def _verb(self, param, method): - # These three are all the same thing except for the 'method' - self.save_progress(f"In action handler for: {self.get_action_identifier()}") - action_result = self.add_action_result(ActionResult(dict(param))) - - location = param["location"] - body = param.get("body") - - if not location.startswith("/"): - location = "/" + location - - if hasattr(location, "decode"): - location = location.decode("utf-8") - - ret_val, headers = self._get_headers(action_result, param.get("headers")) - - if phantom.is_fail(ret_val): - return ret_val - - ret_val, _ = self._make_http_call( - action_result, - endpoint=location, - method=method, - headers=headers, - verify=param.get("verify_certificate", False), - data=body, - ) - return ret_val - - def _handle_get_file(self, param, method): - action_result = ActionResult(dict(param)) - self.add_action_result(action_result) - - file_path = param[HTTP_JSON_FILE_PATH] - file_path = file_path.strip(" ") - file_path = file_path.rstrip("/") - hostname = param.get(HTTP_JSON_HOSTNAME) - if not hostname: - hostname = self._base_url - use_default_endpoint = True - else: - use_default_endpoint = False - hostname = hostname.strip(" ") - hostname = hostname.strip("/") - - if file_path == "": - return action_result.set_status(phantom.APP_ERROR, HTTP_INVALID_PATH_ERR) - - encoded_file_path = quote(file_path) - endpoint = f"{hostname}/{file_path}" - validate_endpoint = f"{hostname}/{encoded_file_path}" - - if not validators.url(validate_endpoint): - return action_result.set_status(phantom.APP_ERROR, HTTP_INVALID_URL_ERR) - file_name = file_path.split("/")[-1] - file_name = unquote_plus(file_name) - try: - ret_val, r = self._make_http_call( - action_result, - endpoint=endpoint, - method=method, - verify=param.get("verify_certificate", False), - use_default_endpoint=use_default_endpoint, - ) - except Exception as e: - err = self._get_error_message_from_exception(e) - return action_result.set_status(phantom.APP_ERROR, HTTP_SERVER_CONNECTION_ERR_MSG.format(error=err)) - - if phantom.is_fail(ret_val): - return action_result.get_status() - - if r.status_code == 200: - return self._save_file_to_vault(action_result, r, file_name) - else: - return action_result.set_status( - phantom.APP_ERROR, - HTTP_SERVER_CONNECTION_ERR_MSG.format(error=r.status_code), - ) - - def _handle_put_file(self, param, method): - action_result = ActionResult(dict(param)) - self.add_action_result(action_result) - - input_filename = param.get(HTTP_JSON_FILE_NAME, "") - - # fetching phantom vault details - try: - success, message, vault_meta_info = ph_rules.vault_info(vault_id=param[HTTP_JSON_VAULT_ID]) - if not success or not vault_meta_info: - error_msg = f" Error Details: {unquote_plus(message)}" if message else "" - return action_result.set_status( - phantom.APP_ERROR, - f"{HTTP_UNABLE_TO_RETRIEVE_VAULT_ITEM_ERR_MSG}.{error_msg}", - ) - vault_meta_info = list(vault_meta_info) - except Exception as e: - err = self._get_error_message_from_exception(e) - return action_result.set_status( - phantom.APP_ERROR, - f"{HTTP_UNABLE_TO_RETRIEVE_VAULT_ITEM_ERR_MSG}. {err}", - ) - - file_is_present = False - if input_filename: - input_filename = input_filename.strip() - for vault_data in vault_meta_info: - if vault_data.get("name") == input_filename: - file_is_present = True - break - if not file_is_present: - return action_result.set_status(phantom.APP_ERROR, HTTP_ERR_FILENAME_NOT_IN_VAULT) - else: - vault_meta_info[0]["name"] = input_filename - - # phantom vault file path - vault_path = vault_meta_info[0].get("path") - try: - f = open(vault_path, "rb") - files = {"file": f} - except Exception as e: - return action_result.set_status(phantom.APP_ERROR, self._get_error_message_from_exception(e)) - - # phantom vault file name - dest_file_name = vault_meta_info[0].get("name") - file_dest = param[HTTP_JSON_FILE_DEST] - endpoint = param.get(HTTP_JSON_HOST) - if not endpoint: - endpoint = self._base_url - use_default_endpoint = True - else: - use_default_endpoint = False - - file_dest = file_dest.strip("/") - endpoint = endpoint.rstrip("/") - - # encoding input file name - dest_file_name = dest_file_name.strip("/") - validate_dest_file_name = quote(dest_file_name) - - # Returning an error if the filename is included in the file_destination path - if dest_file_name in file_dest: - return action_result.set_status(phantom.APP_ERROR, HTTP_EXCLUDE_FILENAME_ERR_MSG) - - destination_path = f"{endpoint}/{file_dest}/{dest_file_name}" - validate_destination_path = f"{endpoint}/{file_dest}/{validate_dest_file_name}" - - if not validators.url(validate_destination_path): - return action_result.set_status(phantom.APP_ERROR, HTTP_INVALID_URL_ERR) - - params = {"file_path": file_dest} - - try: - ret_val, response = self._make_http_call( - action_result, - endpoint=destination_path, - method=method, - params=params, - verify=param.get("verify_certificate", False), - files=files, - use_default_endpoint=use_default_endpoint, - ) - except Exception as e: - err = self._get_error_message_from_exception(e) - return action_result.set_status(phantom.APP_ERROR, HTTP_SERVER_CONNECTION_ERR_MSG.format(error=err)) - finally: - f.close() - - if response.status_code == 200: - summary = {"file_sent": destination_path} - action_result.update_summary(summary) - return action_result.set_status(phantom.APP_SUCCESS) - else: - return action_result.set_status( - phantom.APP_ERROR, - HTTP_SERVER_CONNECTION_ERR_MSG.format(error=response.status_code), - ) - - def _save_file_to_vault(self, action_result, response, file_name): - # Create a tmp directory on the vault partition - - guid = uuid.uuid4() - if hasattr(Vault, "get_vault_tmp_dir"): - temp_dir = Vault.get_vault_tmp_dir() - else: - temp_dir = "/vault/tmp" - - local_dir = temp_dir + f"/{guid}" - self.save_progress(f"Using temp directory: {guid}") - try: - os.makedirs(local_dir) - except Exception as e: - return action_result.set_status( - phantom.APP_ERROR, - f"Unable to create temporary folder {temp_dir}.", - e, - ) - file_path = f"{local_dir}/{file_name}" - # open and download the file - with open(file_path, "wb") as f: - f.write(response.content) - contains = [] - file_ext = "" - magic_str = magic.from_file(file_path) - for regex, cur_contains, extension in self.MAGIC_FORMATS: - if regex.match(magic_str): - contains.extend(cur_contains) - if not file_ext: - file_ext = extension - file_name = f"{file_name}{file_ext}" - - # move the file to the vault - status, vault_ret_message, vault_id = ph_rules.vault_add( - file_location=file_path, - container=self.get_container_id(), - file_name=file_name, - metadata={"contains": contains}, - ) - curr_data = {} - - if status: - curr_data[phantom.APP_JSON_VAULT_ID] = vault_id - curr_data[phantom.APP_JSON_NAME] = file_name - if contains: - curr_data["file_type"] = ",".join(contains) - action_result.add_data(curr_data) - action_result.update_summary(curr_data) - action_result.set_status(phantom.APP_SUCCESS, "File successfully retrieved and added to vault") - else: - action_result.set_status(phantom.APP_ERROR, phantom.APP_ERR_FILE_ADD_TO_VAULT) - action_result.append_to_message(vault_ret_message) - - # remove the /tmp/<> temporary directory - shutil.rmtree(local_dir) - - return action_result.get_status() - - def _handle_http_get(self, param): - return self._verb(param, "get") - - def _handle_http_post(self, param): - return self._verb(param, "post") - - def _handle_http_patch(self, param): - return self._verb(param, "patch") - - def _handle_http_put(self, param): - return self._verb(param, "put") - - def _handle_http_delete(self, param): - return self._verb(param, "delete") - - def _handle_http_head(self, param): - return self._verb(param, "head") - - def _handle_http_options(self, param): - return self._verb(param, "options") - - def handle_action(self, param): - ret_val = phantom.APP_SUCCESS - - action_id = self.get_action_identifier() - - self.debug_print("action_id", self.get_action_identifier()) - - if action_id == "test_connectivity": - ret_val = self._handle_test_connectivity(param) - - elif action_id == "http_get": - ret_val = self._handle_http_get(param) - - elif action_id == "http_post": - ret_val = self._handle_http_post(param) - - elif action_id == "http_put": - ret_val = self._handle_http_put(param) - - elif action_id == "http_patch": - ret_val = self._handle_http_patch(param) - - elif action_id == "http_delete": - ret_val = self._handle_http_delete(param) - - elif action_id == "http_head": - ret_val = self._handle_http_head(param) - - elif action_id == "http_options": - ret_val = self._handle_http_options(param) - - elif action_id == "get_file": - ret_val = self._handle_get_file(param, "get") - - elif action_id == "put_file": - ret_val = self._handle_put_file(param, "post") - - return ret_val - - -if __name__ == "__main__": - import argparse - - import pudb - - pudb.set_trace() - - argparser = argparse.ArgumentParser() - - argparser.add_argument("input_test_json", help="Input Test JSON file") - argparser.add_argument("-u", "--username", help="username", required=False) - argparser.add_argument("-p", "--password", help="password", required=False) - argparser.add_argument( - "-v", - "--verify", - action="store_true", - help="verify", - required=False, - default=False, - ) - - args = argparser.parse_args() - verify = args.verify - session_id = None - verify = args.verify - - if args.username and args.password: - login_url = BaseConnector._get_phantom_base_url() + "login" - try: - print("Accessing the Login page") - r = requests.get(login_url, verify=verify, timeout=DEFAULT_REQUEST_TIMEOUT) - csrftoken = r.cookies["csrftoken"] - data = { - "username": args.username, - "password": args.password, - "csrfmiddlewaretoken": csrftoken, - } - headers = { - "Cookie": f"csrftoken={csrftoken}", - "Referer": login_url, - } - - print("Logging into Platform to get the session id") - r2 = requests.post( - login_url, - verify=verify, - data=data, - headers=headers, - timeout=DEFAULT_REQUEST_TIMEOUT, - ) - session_id = r2.cookies["sessionid"] - - except Exception as e: - print(f"Unable to get session id from the platform. Error: {e!s}") - sys.exit(1) - - if len(sys.argv) < 2: - print("No test json specified as input") - sys.exit(0) - - with open(sys.argv[1]) as f: - in_json = f.read() - in_json = json.loads(in_json) - print(json.dumps(in_json, indent=4)) - - connector = HttpConnector() - connector.print_progress_message = True - - if session_id is not None: - in_json["user_session_token"] = session_id - - ret_val = connector._handle_action(json.dumps(in_json), None) - print(json.dumps(json.loads(ret_val), indent=4)) - - sys.exit(0) diff --git a/http_consts.py b/http_consts.py deleted file mode 100644 index 9122885..0000000 --- a/http_consts.py +++ /dev/null @@ -1,46 +0,0 @@ -# File: http_consts.py -# -# Copyright (c) 2016-2025 Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed under -# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific language governing permissions -# and limitations under the License. - -HTTP_VALIDATE_INTEGER_MSG = "Please provide a valid integer value in the {key} parameter" -HTTP_ERR_CODE_MSG = "Error code unavailable" -HTTP_ERR_MSG = "Unknown error occurred. Please check the asset configuration and|or action parameters" -TYPE_ERR_MSG = "Error occurred while connecting to the HTTP server. Please check the asset configuration and|or the action parameters" -HTTP_SERVER_CONNECTION_ERR_MSG = "Error Connecting to file server. Error:{error}" -HTTP_ERR_FILE_ADD_TO_VAULT = "Error while adding the file to Vault" -HTTP_FILE_NOT_FOUND_ERR_MSG = "Please verify the file destination and make sure the filename is not included in it" -HTTP_UNABLE_TO_RETRIEVE_VAULT_ITEM_ERR_MSG = "Unable to retrieve vault item details" -HTTP_EXCLUDE_FILENAME_ERR_MSG = "Error: Do not include filename in the file destination" -HTTP_PUT_FILE_ERR_MSG = "Error putting file. {error}" -HTTP_JSON_FILE_PATH = "file_path" -HTTP_INVALID_PATH_ERR = "Invalid file path, please enter a valid file path" -HTTP_INVALID_URL_ERR = "Malformed URL, please enter hostname and filepath in proper format" - -HTTP_JSON_HOSTNAME = "hostname" -HTTP_JSON_ACCESS_TOKEN = "access_token" -HTTP_JSON_HOST = "host" -HTTP_JSON_VAULT_ID = "vault_id" -HTTP_JSON_FILE_DEST = "file_destination" -HTTP_JSON_FILE_NAME = "file_name" -UNKNOWN_ERR_MSG = "UNKNOWN ERR MSG" -UNKNOWN_ERR_CODE_MSG = "UNKNOWN ERR CODE MSG" -HTTP_ERR_FILENAME_NOT_IN_VAULT = "Could not find file with specified filename in vault, please provide a valid filename" -DEFAULT_REQUEST_TIMEOUT = 30 # in seconds -HTTP_STATE_IS_ENCRYPTED = "is_encrypted" - -# For encryption and decryption -HTTP_ENCRYPT_TOKEN = "Encrypting the {} token" -HTTP_DECRYPT_TOKEN = "Decrypting the {} token" -HTTP_ENCRYPTION_ERR = "Error occurred while encrypting the state file" -HTTP_DECRYPTION_ERR = "Error occurred while decrypting the state file" diff --git a/pyproject.toml b/pyproject.toml index a816e31..4c594fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,79 +1,8 @@ -# Ruff linting -[tool.ruff] +[tool.black] line-length = 145 -target-version = "py39" +target-version = ['py39'] +verbose = true -[tool.ruff.lint] -select = [ # Auto-fixable rules only - "I", # isort - "UP", # pyupgrade - "F401", # unused imports - "RUF" # ruff rules -] - -ignore = [ - "RUF012", # Not auto-fixable (remove eventually) - "RUF001" # Not auto-fixable (remove eventually) -] - -[tool.ruff.lint.per-file-ignores] -"__init__.py" = ["F401", "UP035"] # __init__.py file exceptions - -# Keep complexity below 28 -[tool.ruff.lint.mccabe] -max-complexity = 28 - -[tool.ruff.lint.isort] -combine-as-imports = true -lines-after-imports = 2 - -[tool.ruff.format] -quote-style = "double" -indent-style = "space" -skip-magic-trailing-comma = false -line-ending = "auto" - -# HTML linting -[tool.djlint] -profile = "django" -extension = "html" -indent = 2 - -# Auto-fixable rules only -include = "H008,H009,H010,H014,H024,H026,H033,T028,T034" - -# Ignore troublesome rules that aren't auto-fixable or causing issues -ignore = "D004,D018,H005,H006,H007,H011,H012,H013,H015,H016,H017,H019,H020,H021,H022,H023,H025,H029,H030,H031,H035,H036,H037,J004,J018,T001,T002,T003,T027,T032" - -# Markdown linting -[tool.mdformat] -wrap = true -number = true - -# Semgrep configuration -[tool.semgrep] -config = [ - "p/python", # Built-in Python rules - "semgrep", # Look for our other rules - "r/typescript.react.security.audit.react-dangerouslysetinnerhtml.react-dangerouslysetinnerhtml" # TypeScript React security rule -] -ignore-patterns = [ - "node_modules/", - "build/", - "dist/", - "vendor/", - "env/", - ".env/", - "venv/", - ".venv/", - ".tox/", - "*.min.js", - "test/", - "tests/", - "*_test.go", - ".semgrep", - "wheels/", - ".html", - "*.md", - "*.svg" -] +[tool.isort] +line_length = 145 +profile = "black" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 0c48bd6..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -beautifulsoup4==4.9.1 -validators==0.35.0 -xmltodict==0.12.0 diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..54b6cbf --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,3 @@ +from . import app + +__ALL__ = [app] diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..6ee1575 --- /dev/null +++ b/src/app.py @@ -0,0 +1,107 @@ +import requests +from soar_sdk.abstract import SOARClient + +# from soar_sdk.action_results import ActionOutput, OutputField +from soar_sdk.app import App +from soar_sdk.asset import AssetField, BaseAsset +from soar_sdk.exceptions import ActionFailure +from soar_sdk.logging import getLogger + +# from soar_sdk.params import Param, Params + +logger = getLogger() + + +class Asset(BaseAsset): + base_url: str = AssetField( + required=True, + description="Base URL for making queries. (e.g. https://myservice/)", + ) + test_path: str = AssetField( + required=False, + description="Endpoint for test connectivity. (e.g. /some/specific/endpoint , appended to Base URL)", + ) + auth_token_name: str = AssetField( + required=False, + description="Type of authentication token", + default="ph-auth-token", + ) + auth_token: str = AssetField(required=False, description="Value of authentication token") + username: str = AssetField(required=False, description="Username (for HTTP basic auth)") + password: str = AssetField(required=False, description="Password (for HTTP basic auth)") + oauth_token_url: str = AssetField(required=False, description="URL to fetch oauth token from") + client_id: str = AssetField(required=False, description="Client ID (for OAuth)") + client_secret: str = AssetField(required=False, description="Client Secret (for OAuth)") + timeout: float = AssetField(required=False, description="Timeout for HTTP calls") + test_http_method: str = AssetField( + required=False, + description="HTTP Method for Test Connectivity", + default="GET", + value_list=[ + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "OPTIONS", + "TRACE", + "PATCH", + ], + ) + + +app = App( + name="http", + app_type="information", + logo="logo_splunk.svg", + logo_dark="logo_splunk_dark.svg", + product_vendor="Generic", + product_name="HTTP", + publisher="Splunk", + appid="290b7499-0374-4930-9cdc-5e9b05d65827", + fips_compliant=True, + asset_cls=Asset, +) + + +@app.test_connectivity() +def test_connectivity(soar: SOARClient, asset: Asset) -> None: + # raise NotImplementedError() + + # zbudujmy pelen adres url + # nawet jesli nie ma test_patha to bedzie dzialac + full_url = asset.base_url.rstrip("/") + if asset.test_path: + full_url = full_url + "/" + asset.test_path.lstrip("/") + soar.save_progress(f"Wysylanie testowego zadania na adres: {full_url}") + + # źądanie + try: + response = requests.request( + method=asset.test_http_method, + url=full_url, + verify=False, + timeout=asset.timeout, + ) + + response.raise_for_status() + + soar.save_progress(f"Otrzymano pomyślną odpowiedź (Status: {response.status_code})") + except requests.exceptions.HTTPError as e: + # Błąd zwrócony przez serwer (np. 401, 403, 404, 500) + error_message = f"Serwer zwrócił błąd: {e.response.status_code} {e.response.reason}. " f"Treść odpowiedzi: {e.response.text}" + raise ActionFailure(error_message) + + except requests.exceptions.RequestException as e: + # Inne błędy połączenia (np. problem z DNS, odmowa połączenia, timeout) + error_message = f"Błąd połączenia z serwerem. Szczegóły: {e}" + raise ActionFailure(error_message) + + soar.save_progress("Test łączności zakończony pomyślnie.") + + +if __name__ == "__main__": + app.cli() + + +# dobrze otestuj przypadek gdzie test_path nie istnieje lub jest "/" diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..720a141 --- /dev/null +++ b/tox.ini @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 145 +max-complexity = 28 +extend-ignore = F403,E128,E126,E121,E127,E731,E201,E202,E203,E701,F405,E722,D,W503 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..3252754 --- /dev/null +++ b/uv.lock @@ -0,0 +1,746 @@ +version = 1 +revision = 1 +requires-python = "==3.9.*" +resolution-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'linux'", + "platform_machine == 'aarch64' and sys_platform == 'linux'", + "platform_machine == 'x86_64' and sys_platform == 'darwin'", + "platform_machine == 'arm64' and sys_platform == 'darwin'", +] +supported-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'linux'", + "platform_machine == 'aarch64' and sys_platform == 'linux'", + "platform_machine == 'x86_64' and sys_platform == 'darwin'", + "platform_machine == 'arm64' and sys_platform == 'darwin'", +] +required-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'linux'", +] + +[[package]] +name = "anyio" +version = "4.10.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "idna", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "sniffio", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "typing-extensions", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213 }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.10.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "soupsieve", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/69/daeee6d8f22c997e522cdbeb59641c4d31ab120aba0f2c799500f7456b7e/beautifulsoup4-4.10.0.tar.gz", hash = "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891", size = 399890 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/bf/f0f194d3379d3f3347478bd267f754fc68c11cbf2fe302a6ab69447b1417/beautifulsoup4-4.10.0-py3-none-any.whl", hash = "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf", size = 97398 }, +] + +[[package]] +name = "bleach" +version = "6.2.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "webencodings", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/9a/0e33f5054c54d349ea62c277191c020c2d6ef1d65ab2cb1993f91ec846d1/bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f", size = 203083 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406 }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216 }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.2" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/f8/dfb01ff6cc9af38552c69c9027501ff5a5117c4cc18dcd27cb5259fa1888/charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4", size = 201671 }, + { url = "https://files.pythonhosted.org/packages/32/fb/74e26ee556a9dbfe3bd264289b67be1e6d616329403036f6507bb9f3f29c/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7", size = 144744 }, + { url = "https://files.pythonhosted.org/packages/ad/06/8499ee5aa7addc6f6d72e068691826ff093329fe59891e83b092ae4c851c/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836", size = 154993 }, + { url = "https://files.pythonhosted.org/packages/f1/a2/5e4c187680728219254ef107a6949c60ee0e9a916a5dadb148c7ae82459c/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597", size = 147382 }, + { url = "https://files.pythonhosted.org/packages/4c/fe/56aca740dda674f0cc1ba1418c4d84534be51f639b5f98f538b332dc9a95/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7", size = 149536 }, + { url = "https://files.pythonhosted.org/packages/69/35/e52ab9a276186f729bce7a0638585d2982f50402046e4b0faa5d2c3ef2da/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba", size = 146365 }, + { url = "https://files.pythonhosted.org/packages/7a/3d/a5b2e48acef264d71e036ff30bcc49e51bde80219bb628ba3e00cf59baac/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518", size = 157735 }, + { url = "https://files.pythonhosted.org/packages/85/d8/23e2c112532a29f3eef374375a8684a4f3b8e784f62b01da931186f43494/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5", size = 154786 }, + { url = "https://files.pythonhosted.org/packages/c7/57/93e0169f08ecc20fe82d12254a200dfaceddc1c12a4077bf454ecc597e33/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3", size = 150203 }, + { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626 }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "coverage" +version = "7.10.2" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/76/17780846fc7aade1e66712e1e27dd28faa0a5d987a1f433610974959eaa8/coverage-7.10.2.tar.gz", hash = "sha256:5d6e6d84e6dd31a8ded64759626627247d676a23c1b892e1326f7c55c8d61055", size = 820754 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/c9/139fa9f64edfa5bae1492a4efecef7209f59ba5f9d862db594be7a85d7fb/coverage-7.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:765b13b164685a2f8b2abef867ad07aebedc0e090c757958a186f64e39d63dbd", size = 215003 }, + { url = "https://files.pythonhosted.org/packages/fd/9f/8682ccdd223c2ab34de6575ef3c78fae9bdaece1710b4d95bb9b0abd4d2f/coverage-7.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a219b70100500d0c7fd3ebb824a3302efb6b1a122baa9d4eb3f43df8f0b3d899", size = 215382 }, + { url = "https://files.pythonhosted.org/packages/dd/66/aaf159bfe94ee3996b8786034a8e713bc68cd650aa7c1a41b612846cdc41/coverage-7.10.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc3945b7bad33957a9eca16e9e5eae4b17cb03173ef594fdaad228f4fc7da53b", size = 243354 }, + { url = "https://files.pythonhosted.org/packages/21/31/8fd2f67d8580380e7b19b23838e308b6757197e94a1b3b87e0ad483f70c8/coverage-7.10.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bdff88e858ee608a924acfad32a180d2bf6e13e059d6a7174abbae075f30436", size = 244923 }, + { url = "https://files.pythonhosted.org/packages/55/90/67b129b08200e08962961f56604083923bc8484bc641c92ee6801c1ae822/coverage-7.10.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44329cbed24966c0b49acb386352c9722219af1f0c80db7f218af7793d251902", size = 242856 }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e8531ea19f047b8b1d1d1c85794e4b35ae762e570f072ca2afbce67be176/coverage-7.10.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c031da749a05f7a01447dd7f47beedb498edd293e31e1878c0d52db18787df0", size = 242044 }, + { url = "https://files.pythonhosted.org/packages/18/d8/9b768ac73a8ac2d10c080af23937212434a958c8d2a1c84e89b450237942/coverage-7.10.2-py3-none-any.whl", hash = "sha256:95db3750dd2e6e93d99fa2498f3a1580581e49c494bddccc6f85c5c21604921f", size = 206973 }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047 }, +] + +[[package]] +name = "distro" +version = "1.8.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/89/eaa3a3587ebf8bed93e45aa79be8c2af77d50790d15b53f6dfc85b57f398/distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8", size = 59428 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/2c/c90a3adaf0ddb70afe193f5ebfb539612af57cffe677c3126be533df3098/distro-1.8.0-py3-none-any.whl", hash = "sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff", size = 20315 }, +] + +[[package]] +name = "docopt" +version = "0.6.2" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901 } + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674 }, +] + +[[package]] +name = "filelock" +version = "3.18.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215 }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, +] + +[[package]] +name = "http" +version = "3.7.8" +source = { virtual = "." } +dependencies = [ + { name = "beautifulsoup4", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "splunk-soar-sdk", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "validators", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "xmltodict", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] + +[package.dev-dependencies] +dev = [ + { name = "coverage", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "mypy", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pre-commit", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pytest", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pytest-mock", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pytest-watch", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "ruff", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] + +[package.metadata] +requires-dist = [ + { name = "beautifulsoup4", specifier = "==4.10.0" }, + { name = "splunk-soar-sdk", specifier = ">=1.0.0b53" }, + { name = "validators", specifier = "==0.35.0" }, + { name = "xmltodict", specifier = "==0.12.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "coverage", specifier = ">=7.6.7,<8" }, + { name = "mypy", specifier = ">=1.2.0,<2" }, + { name = "pre-commit", specifier = ">=4.2.0,<5" }, + { name = "pytest", specifier = ">=7.4.2,<8" }, + { name = "pytest-mock", specifier = ">=3.14.0,<4" }, + { name = "pytest-watch", specifier = ">=4.2.0,<5" }, + { name = "ruff", specifier = ">=0.11.6,<1" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "certifi", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "h11", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "anyio", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "certifi", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "httpcore", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "idna", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, +] + +[[package]] +name = "humanize" +version = "4.12.3" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/d1/bbc4d251187a43f69844f7fd8941426549bbe4723e8ff0a7441796b0789f/humanize-4.12.3.tar.gz", hash = "sha256:8430be3a615106fdfceb0b2c1b41c4c98c6b0fc5cc59663a5539b111dd325fb0", size = 80514 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/1e/62a2ec3104394a2975a2629eec89276ede9dbe717092f6966fcf963e1bf0/humanize-4.12.3-py3-none-any.whl", hash = "sha256:2cbf6370af06568fa6d2da77c86edb7886f3160ecd19ee1ffef07979efc597f6", size = 128487 }, +] + +[[package]] +name = "identify" +version = "2.6.12" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "markupsafe", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "mdurl", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344 }, + { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389 }, + { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607 }, + { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728 }, + { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843 }, + { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946 }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +] + +[[package]] +name = "mypy" +version = "1.17.1" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "mypy-extensions", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pathspec", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "tomli", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "typing-extensions", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/22/ea637422dedf0bf36f3ef238eab4e455e2a0dcc3082b5cc067615347ab8e/mypy-1.17.1.tar.gz", hash = "sha256:25e01ec741ab5bb3eec8ba9cdb0f769230368a22c959c4937360efb89b7e9f01", size = 3352570 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/cb/673e3d34e5d8de60b3a61f44f80150a738bff568cd6b7efb55742a605e98/mypy-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d1092694f166a7e56c805caaf794e0585cabdbf1df36911c414e4e9abb62ae9", size = 10992466 }, + { url = "https://files.pythonhosted.org/packages/0c/d0/fe1895836eea3a33ab801561987a10569df92f2d3d4715abf2cfeaa29cb2/mypy-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79d44f9bfb004941ebb0abe8eff6504223a9c1ac51ef967d1263c6572bbebc99", size = 10117638 }, + { url = "https://files.pythonhosted.org/packages/97/f3/514aa5532303aafb95b9ca400a31054a2bd9489de166558c2baaeea9c522/mypy-1.17.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b01586eed696ec905e61bd2568f48740f7ac4a45b3a468e6423a03d3788a51a8", size = 11915673 }, + { url = "https://files.pythonhosted.org/packages/ab/c3/c0805f0edec96fe8e2c048b03769a6291523d509be8ee7f56ae922fa3882/mypy-1.17.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43808d9476c36b927fbcd0b0255ce75efe1b68a080154a38ae68a7e62de8f0f8", size = 12649022 }, + { url = "https://files.pythonhosted.org/packages/45/3e/d646b5a298ada21a8512fa7e5531f664535a495efa672601702398cea2b4/mypy-1.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:feb8cc32d319edd5859da2cc084493b3e2ce5e49a946377663cc90f6c15fb259", size = 12895536 }, + { url = "https://files.pythonhosted.org/packages/1d/f3/8fcd2af0f5b806f6cf463efaffd3c9548a28f84220493ecd38d127b6b66d/mypy-1.17.1-py3-none-any.whl", hash = "sha256:a9f52c0351c21fe24c21d8c0eb1f62967b262d6729393397b6f443c3b773c3b9", size = 2283411 }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963 }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, +] + +[[package]] +name = "platformdirs" +version = "4.3.8" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567 }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, +] + +[[package]] +name = "pre-commit" +version = "4.2.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "cfgv", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "identify", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "nodeenv", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pyyaml", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "virtualenv", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707 }, +] + +[[package]] +name = "pydantic" +version = "1.10.22" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9a/57/5996c63f0deec09e9e901a2b838247c97c6844999562eac4e435bcb83938/pydantic-1.10.22.tar.gz", hash = "sha256:ee1006cebd43a8e7158fb7190bb8f4e2da9649719bff65d0c287282ec38dec6d", size = 356771 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/6f/9658e94018bc7c4e71863fb0f1ea8d30f8b3439e17df7aa710b2bb72dbca/pydantic-1.10.22-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec54c89b2568b258bb30d7348ac4d82bec1b58b377fb56a00441e2ac66b24587", size = 2854460 }, + { url = "https://files.pythonhosted.org/packages/b8/b3/5184ec7d3423a37c193ffaeced03921f4c34d226f3c6852653784f37d38b/pydantic-1.10.22-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8f1d1a1532e4f3bcab4e34e8d2197a7def4b67072acd26cfa60e92d75803a48", size = 2587418 }, + { url = "https://files.pythonhosted.org/packages/90/25/27d769c5dc7491df5faebfc49a26f83ca2e070a9a788c67fde4c4e51d68b/pydantic-1.10.22-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ad83ca35508c27eae1005b6b61f369f78aae6d27ead2135ec156a2599910121", size = 3331289 }, + { url = "https://files.pythonhosted.org/packages/e9/87/eb3408e1c040a6d9f703e089d26a723d6c41f23a192e86bd7584d037d576/pydantic-1.10.22-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8aee040e25843f036192b1a1af62117504a209a043aa8db12e190bb86ad7e611", size = 3483434 }, + { url = "https://files.pythonhosted.org/packages/e9/e0/1ed151a56869be1588ad2d8cda9f8c1d95b16f74f09a7cea879ca9b63a8b/pydantic-1.10.22-py3-none-any.whl", hash = "sha256:343037d608bcbd34df937ac259708bfc83664dadf88afe8516c4f282d7d471a9", size = 166503 }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, +] + +[[package]] +name = "pytest" +version = "7.4.4" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "iniconfig", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "packaging", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pluggy", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "tomli", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/1f/9d8e98e4133ffb16c90f3b405c43e38d3abb715bb5d7a63a5a684f7e46a3/pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280", size = 1357116 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8", size = 325287 }, +] + +[[package]] +name = "pytest-mock" +version = "3.14.1" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "pytest", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/28/67172c96ba684058a4d24ffe144d64783d2a270d0af0d9e792737bddc75c/pytest_mock-3.14.1.tar.gz", hash = "sha256:159e9edac4c451ce77a5cdb9fc5d1100708d2dd4ba3c3df572f14097351af80e", size = 33241 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/05/77b60e520511c53d1c1ca75f1930c7dd8e971d0c4379b7f4b3f9644685ba/pytest_mock-3.14.1-py3-none-any.whl", hash = "sha256:178aefcd11307d874b4cd3100344e7e2d888d9791a6a1d9bfe90fbc1b74fd1d0", size = 9923 }, +] + +[[package]] +name = "pytest-watch" +version = "4.2.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "colorama", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "docopt", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pytest", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "watchdog", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/47/ab65fc1d682befc318c439940f81a0de1026048479f732e84fe714cd69c0/pytest-watch-4.2.0.tar.gz", hash = "sha256:06136f03d5b361718b8d0d234042f7b2f203910d8568f63df2f866b547b3d4b9", size = 16340 } + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777 }, + { url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318 }, + { url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891 }, + { url = "https://files.pythonhosted.org/packages/e9/6c/6e1b7f40181bc4805e2e07f4abc10a88ce4648e7e95ff1abe4ae4014a9b2/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", size = 722614 }, + { url = "https://files.pythonhosted.org/packages/3d/32/e7bd8535d22ea2874cef6a81021ba019474ace0d13a4819c2a4bce79bd6a/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", size = 737360 }, + { url = "https://files.pythonhosted.org/packages/d7/12/7322c1e30b9be969670b672573d45479edef72c9a0deac3bb2868f5d7469/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", size = 699006 }, + { url = "https://files.pythonhosted.org/packages/82/72/04fcad41ca56491995076630c3ec1e834be241664c0c09a64c9a2589b507/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", size = 723577 }, +] + +[[package]] +name = "requests" +version = "2.32.4" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "certifi", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "charset-normalizer", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "idna", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "urllib3", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847 }, +] + +[[package]] +name = "responses" +version = "0.22.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "requests", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "toml", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "types-toml", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "urllib3", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/cc/c15e28fdbc81909ac18a4c22bebe8517bbafef43947a072da6f042fbd4d5/responses-0.22.0.tar.gz", hash = "sha256:396acb2a13d25297789a5866b4881cf4e46ffd49cc26c43ab1117f40b973102e", size = 71785 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/d0/2b9030eedf7061ac60828fcd92a4b04dc9a7dd07f316300f2841c41421a0/responses-0.22.0-py3-none-any.whl", hash = "sha256:dcf294d204d14c436fddcc74caefdbc5764795a40ff4e6a7740ed8ddbf3294be", size = 51148 }, +] + +[[package]] +name = "rich" +version = "14.1.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "markdown-it-py", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pygments", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368 }, +] + +[[package]] +name = "ruff" +version = "0.12.7" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/81/0bd3594fa0f690466e41bd033bdcdf86cba8288345ac77ad4afbe5ec743a/ruff-0.12.7.tar.gz", hash = "sha256:1fc3193f238bc2d7968772c82831a4ff69252f673be371fb49663f0068b7ec71", size = 5197814 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/d2/6cb35e9c85e7a91e8d22ab32ae07ac39cc34a71f1009a6f9e4a2a019e602/ruff-0.12.7-py3-none-linux_armv6l.whl", hash = "sha256:76e4f31529899b8c434c3c1dede98c4483b89590e15fb49f2d46183801565303", size = 11852189 }, + { url = "https://files.pythonhosted.org/packages/63/5b/a4136b9921aa84638f1a6be7fb086f8cad0fde538ba76bda3682f2599a2f/ruff-0.12.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:789b7a03e72507c54fb3ba6209e4bb36517b90f1a3569ea17084e3fd295500fb", size = 12519389 }, + { url = "https://files.pythonhosted.org/packages/a8/c9/3e24a8472484269b6b1821794141f879c54645a111ded4b6f58f9ab0705f/ruff-0.12.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e1c2a3b8626339bb6369116e7030a4cf194ea48f49b64bb505732a7fce4f4e3", size = 11743384 }, + { url = "https://files.pythonhosted.org/packages/26/7c/458dd25deeb3452c43eaee853c0b17a1e84169f8021a26d500ead77964fd/ruff-0.12.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32dec41817623d388e645612ec70d5757a6d9c035f3744a52c7b195a57e03860", size = 11943759 }, + { url = "https://files.pythonhosted.org/packages/7f/8b/658798472ef260ca050e400ab96ef7e85c366c39cf3dfbef4d0a46a528b6/ruff-0.12.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47ef751f722053a5df5fa48d412dbb54d41ab9b17875c6840a58ec63ff0c247c", size = 11654028 }, + { url = "https://files.pythonhosted.org/packages/76/69/df73f65f53d6c463b19b6b312fd2391dc36425d926ec237a7ed028a90fc1/ruff-0.12.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5726f59b171111fa6a69d82aef48f00b56598b03a22f0f4170664ff4d8298efb", size = 14182353 }, + { url = "https://files.pythonhosted.org/packages/58/1e/de6cda406d99fea84b66811c189b5ea139814b98125b052424b55d28a41c/ruff-0.12.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74e6f5c04c4dd4aba223f4fe6e7104f79e0eebf7d307e4f9b18c18362124bccd", size = 13631555 }, + { url = "https://files.pythonhosted.org/packages/6f/ae/625d46d5164a6cc9261945a5e89df24457dc8262539ace3ac36c40f0b51e/ruff-0.12.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0bfe4e77fba61bf2ccadf8cf005d6133e3ce08793bbe870dd1c734f2699a3e", size = 12667556 }, + { url = "https://files.pythonhosted.org/packages/55/bf/9cb1ea5e3066779e42ade8d0cd3d3b0582a5720a814ae1586f85014656b6/ruff-0.12.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06bfb01e1623bf7f59ea749a841da56f8f653d641bfd046edee32ede7ff6c606", size = 12939784 }, + { url = "https://files.pythonhosted.org/packages/55/7f/7ead2663be5627c04be83754c4f3096603bf5e99ed856c7cd29618c691bd/ruff-0.12.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e41df94a957d50083fd09b916d6e89e497246698c3f3d5c681c8b3e7b9bb4ac8", size = 11771356 }, + { url = "https://files.pythonhosted.org/packages/17/40/a95352ea16edf78cd3a938085dccc55df692a4d8ba1b3af7accbe2c806b0/ruff-0.12.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4000623300563c709458d0ce170c3d0d788c23a058912f28bbadc6f905d67afa", size = 11612124 }, + { url = "https://files.pythonhosted.org/packages/be/34/c3ef2d7799c9778b835a76189c6f53c179d3bdebc8c65288c29032e03613/ruff-0.12.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a07a5c8ffa2611a52732bdc67bf88e243abd84fe2d7f6daef3826b59abbfeda4", size = 12998677 }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, +] + +[[package]] +name = "soupsieve" +version = "2.7" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/f4/4a80cd6ef364b2e8b65b15816a843c0980f7a5a2b4dc701fc574952aa19f/soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a", size = 103418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/9c/0e6afc12c269578be5c0c1c9f4b49a8d32770a080260c333ac04cc1c832d/soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", size = 36677 }, +] + +[[package]] +name = "splunk-soar-sdk" +version = "1.0.0b53" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "beautifulsoup4", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "bleach", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "click", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "distro", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "httpx", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "humanize", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "jinja2", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "packaging", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "pydantic", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "requests", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "responses", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "toml", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "tqdm", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "typer", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e3/17/739a355da45152ee7166d85042d4fd72ef2a8d0005d6d1cde7e695b872bf/splunk_soar_sdk-1.0.0b53.tar.gz", hash = "sha256:9febdd42e5d033769f16f61910f82ebc0f4ece258d82cdfabfd5a1d812687aad", size = 371276 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/b2/c4baa10d03554462616ec0eb02ec9231156acb19b287ecb8e80ae0208584/splunk_soar_sdk-1.0.0b53-py3-none-any.whl", hash = "sha256:3aa6096db9f57735ce5ca33c6f65bf13b610172244d26af8edbff2899662bad6", size = 146342 }, +] + +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, +] + +[[package]] +name = "typer" +version = "0.16.0" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "click", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "rich", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "shellingham", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "typing-extensions", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317 }, +] + +[[package]] +name = "types-toml" +version = "0.10.8.20240310" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/47/3e4c75042792bff8e90d7991aa5c51812cc668828cc6cce711e97f63a607/types-toml-0.10.8.20240310.tar.gz", hash = "sha256:3d41501302972436a6b8b239c850b26689657e25281b48ff0ec06345b8830331", size = 4392 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/a2/d32ab58c0b216912638b140ab2170ee4b8644067c293b170e19fba340ccc/types_toml-0.10.8.20240310-py3-none-any.whl", hash = "sha256:627b47775d25fa29977d9c70dc0cbab3f314f32c8d8d0c012f2ef5de7aaec05d", size = 4777 }, +] + +[[package]] +name = "typing-extensions" +version = "4.14.1" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906 }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795 }, +] + +[[package]] +name = "validators" +version = "0.35.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/66/a435d9ae49850b2f071f7ebd8119dd4e84872b01630d6736761e6e7fd847/validators-0.35.0.tar.gz", hash = "sha256:992d6c48a4e77c81f1b4daba10d16c3a9bb0dbb79b3a19ea847ff0928e70497a", size = 73399 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/6e/3e955517e22cbdd565f2f8b2e73d52528b14b8bcfdb04f62466b071de847/validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd", size = 44712 }, +] + +[[package]] +name = "virtualenv" +version = "20.33.1" +source = { registry = "https://pypi.python.org/simple" } +dependencies = [ + { name = "distlib", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "filelock", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "platformdirs", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/60/4f20960df6c7b363a18a55ab034c8f2bcd5d9770d1f94f9370ec104c1855/virtualenv-20.33.1.tar.gz", hash = "sha256:1b44478d9e261b3fb8baa5e74a0ca3bc0e05f21aa36167bf9cbf850e542765b8", size = 6082160 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/ff/ded57ac5ff40a09e6e198550bab075d780941e0b0f83cbeabd087c59383a/virtualenv-20.33.1-py3-none-any.whl", hash = "sha256:07c19bc66c11acab6a5958b815cbcee30891cd1c2ccf53785a28651a0d8d8a67", size = 6060362 }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390 }, + { url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386 }, + { url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017 }, + { url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903 }, + { url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381 }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, +] + +[[package]] +name = "xmltodict" +version = "0.12.0" +source = { registry = "https://pypi.python.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/40/0d783e14112e064127063fbf5d1fe1351723e5dfe9d6daad346a305f6c49/xmltodict-0.12.0.tar.gz", hash = "sha256:50d8c638ed7ecb88d90561beedbf720c9b4e851a9fa6c47ebd64e99d166d8a21", size = 18481 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/fd/30d5c1d3ac29ce229f6bdc40bbc20b28f716e8b363140c26eff19122d8a5/xmltodict-0.12.0-py2.py3-none-any.whl", hash = "sha256:8bbcb45cc982f48b2ca8fe7e7827c5d792f217ecf1792626f808bf41c3b86051", size = 9170 }, +]