From 0adeecf8ec83e4e1555b9d96e7fb3a9c0aa8419a Mon Sep 17 00:00:00 2001 From: glimps-cbi Date: Fri, 15 Nov 2024 14:47:22 +0100 Subject: [PATCH] feat(glimps): add view token to analysis result --- Glimps/CHANGELOG.md | 9 +- Glimps/action_analyse_a_file.json | 16 +- ...on_analyse_a_file_and_wait_for_result.json | 326 ++++++++++-------- Glimps/action_export_analysis_result.json | 6 +- Glimps/action_get_profile_status.json | 8 +- Glimps/action_retrieve_analysis.json | 310 +++++++++-------- Glimps/action_search_analysis.json | 310 +++++++++-------- Glimps/glimps/base.py | 20 +- Glimps/glimps/errors.py | 12 - Glimps/glimps/export_action.py | 4 +- Glimps/glimps/get_status_action.py | 4 +- Glimps/glimps/models.py | 112 +++--- Glimps/glimps/retrieve_analysis_action.py | 14 +- .../search_analysis_by_sha256_action.py | 18 +- .../submit_file_to_be_analysed_action.py | 15 +- Glimps/main.py | 20 +- Glimps/manifest.json | 2 +- Glimps/poetry.lock | 262 +++++--------- Glimps/pyproject.toml | 4 +- Glimps/tests/conftest.py | 14 +- Glimps/tests/test_export.py | 70 ++-- Glimps/tests/test_get_status.py | 12 +- Glimps/tests/test_retrieve_analysis.py | 37 +- .../tests/test_search_analysis_by_sha256.py | 38 +- .../tests/test_submit_file_to_be_analysed.py | 78 +++-- 25 files changed, 888 insertions(+), 833 deletions(-) delete mode 100644 Glimps/glimps/errors.py diff --git a/Glimps/CHANGELOG.md b/Glimps/CHANGELOG.md index 4740e3e7c..fa124e04c 100644 --- a/Glimps/CHANGELOG.md +++ b/Glimps/CHANGELOG.md @@ -11,13 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Waitfor action : submit a file to Glimps detect and wit for analysis to finish -- Get status action : get Glimps detect profile status -- export submission : export analysis result in a given format and layout +- Waitfor action: submit a file to GLIMPS detect and wait for analysis to finish +- Get status action: get GLIMPS detect profile status +- Export submission: export analysis result in a given format and layout ### Changed -- use Glimps py-gdetect client to perform actions +- Upgrade sekoia-automation-sdk +- Use GLIMPS py-gdetect client to perform actions ## 2024-05-28 - 1.13.0 diff --git a/Glimps/action_analyse_a_file.json b/Glimps/action_analyse_a_file.json index 4a1555580..ea3b93878 100644 --- a/Glimps/action_analyse_a_file.json +++ b/Glimps/action_analyse_a_file.json @@ -2,42 +2,42 @@ "name": "Analyse a file", "description": "Submit file to Glimps Detect to be analysed", "uuid": "14c3192f-532c-506d-ae0d-452b64d8718d", - "docker_parameters": "SubmitFileToBeAnalysed", + "docker_parameters": "SubmitFile", "arguments": { "title": "SubmitArgument", "type": "object", "properties": { "file_name": { "title": "File Name", - "description": "name of submitted file", + "description": "Name of submitted file", "type": "string" }, "bypass_cache": { "title": "Bypass Cache", - "description": "If True, the file is analyzed, even if a result already exists", + "description": "If true, file is analyzed, even if a result already exists", "default": false, "type": "boolean" }, "user_tags": { "title": "User Tags", - "description": "If filled, the file will be tagged with those tags", + "description": "Analysis will be tagged with those tags", "default": [], "type": "array", "items": {} }, "description": { "title": "Description", - "description": " If filled, a description will be added to the analysis", + "description": "Description added to the analysis", "type": "string" }, "archive_pwd": { "title": "Archive Pwd", - "description": "If filled, the password used to extract archive", + "description": "Password used to extract archive", "type": "string" }, "push_timeout": { "title": "Push Timeout", - "description": "The maximum time (in seconds) to wait for a response when submitting file", + "description": "Maximum time (in seconds) to wait for a response when submitting file", "default": 30, "type": "number" } @@ -58,7 +58,7 @@ }, "uuid": { "title": "Uuid", - "description": "uuid of the submitted analysis", + "description": "UUID of the submitted analysis", "type": "string" } } diff --git a/Glimps/action_analyse_a_file_and_wait_for_result.json b/Glimps/action_analyse_a_file_and_wait_for_result.json index 576a9d9f2..9c9faae10 100644 --- a/Glimps/action_analyse_a_file_and_wait_for_result.json +++ b/Glimps/action_analyse_a_file_and_wait_for_result.json @@ -2,54 +2,54 @@ "name": "Analyse a file and wait for result", "description": "Submit file to Glimps Detect to be analysed and wait for its results", "uuid": "7836a5fb-5ded-55ee-aca1-c6a3d080c49b", - "docker_parameters": "SubmitFileWaitForResult", + "docker_parameters": "WaitForFile", "arguments": { "title": "WaitForResultArgument", "type": "object", "properties": { "file_name": { "title": "File Name", - "description": "name of submitted file", + "description": "Name of submitted file", "type": "string" }, "bypass_cache": { "title": "Bypass Cache", - "description": "If True, the file is analyzed, even if a result already exists", + "description": "If true, file is analyzed, even if a result already exists", "default": false, "type": "boolean" }, "user_tags": { "title": "User Tags", - "description": "If filled, the file will be tagged with those tags", + "description": "Analysis will be tagged with those tags", "default": [], "type": "array", "items": {} }, "description": { "title": "Description", - "description": " If filled, a description will be added to the analysis", + "description": "Description added to the analysis", "type": "string" }, "archive_pwd": { "title": "Archive Pwd", - "description": "If filled, the password used to extract archive", + "description": "Password used to extract archive", "type": "string" }, "push_timeout": { "title": "Push Timeout", - "description": "The maximum time (in seconds) to wait for a response when submitting file", + "description": "Maximum time (in seconds) to wait for a response when submitting file", "default": 30, "type": "number" }, "pull_time": { "title": "Pull Time", - "description": "The time to wait (in seconds) between each requests to get a result", + "description": "Time to wait (in seconds) between each requests to get a result", "default": 1.0, "type": "number" }, "timeout": { "title": "Timeout", - "description": "The maximum time execution of this method in seconds", + "description": "Maximum time (in seconds) to wait for the analysis to end", "default": 180, "type": "number" } @@ -62,153 +62,24 @@ "title": "AnalysisResponse", "type": "object", "properties": { - "status": { - "title": "Status", - "description": "false means an error occured", - "type": "boolean" - }, - "special_status_code": { - "title": "Special Status Code", - "description": "special error code, 0 means no special case", - "type": "integer" - }, - "uuid": { - "title": "Uuid", - "description": "Unique analysis identifier", - "type": "string" - }, - "sha256": { - "title": "Sha256", - "description": "string hex encoded input file SHA256", - "type": "string" - }, - "sha1": { - "title": "Sha1", - "description": "string hex encoded input file SHA1", - "type": "string" - }, - "md5": { - "title": "Md5", - "description": "string hex encoded input file MD5", - "type": "string" - }, - "ssdeep": { - "title": "Ssdeep", - "description": "string input file SSDeep", - "type": "string" - }, - "is_malware": { - "title": "Is Malware", - "description": "analysis result, is a malware or not", - "type": "boolean" - }, - "score": { - "title": "Score", - "description": "highest score given by probes", - "type": "integer" - }, - "done": { - "title": "Done", - "description": "is analysis finished", - "type": "boolean" - }, - "timestamp": { - "title": "Timestamp", - "description": "timestamp of the start of analysis in milliseconds", - "type": "integer" - }, - "file_count": { - "title": "File Count", - "description": "amount of file in the submission (input + extracted)", - "type": "integer" - }, - "duration": { - "title": "Duration", - "description": "duration of the analysis in milliseconds", - "type": "integer" - }, - "filetype": { - "title": "Filetype", - "description": "type of the file", - "type": "string" - }, - "size": { - "title": "Size", - "description": "input file size (in bytes)", - "type": "integer" - }, - "sid": { - "title": "Sid", - "description": "analysis UUID handled by GLIMPS malware finder - expert\ncould be used to construct expert link like:\nhttps://gmalware.useddomain.glimps.re/expert/en/analysis/results/advanced/${SID}", - "type": "string" - }, - "token": { - "title": "Token", - "description": "token that can be used to view analysis result in expert view", - "type": "string" + "analysis": { + "title": "Analysis", + "description": "Analysis response details", + "allOf": [ + { + "$ref": "#/definitions/AnalysisDetails" + } + ] }, - "error": { - "title": "Error", - "description": "error message if Status is false", + "view_url": { + "title": "View Url", + "description": "Analysis URL", + "default": "", "type": "string" - }, - "errors": { - "title": "Errors", - "description": "error message by services", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "filenames": { - "title": "Filenames", - "description": "list of analysed filename", - "type": "array", - "items": { - "type": "string" - } - }, - "malwares": { - "title": "Malwares", - "description": "list of malware names found in analysis", - "type": "array", - "items": { - "type": "string" - } - }, - "files": { - "title": "Files", - "description": "array of submission files (input file and extracted sub-files)", - "type": "array", - "items": { - "$ref": "#/definitions/FileResult" - } - }, - "threats": { - "title": "Threats", - "description": "Summary of threats found in submission. Each submission file reaching threshold score will add an entry. Entry keys are the SHA256 of files", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Threat" - } } }, "required": [ - "status", - "special_status_code", - "uuid", - "sha256", - "sha1", - "md5", - "ssdeep", - "is_malware", - "score", - "done", - "timestamp", - "file_count", - "duration", - "filetype", - "size" + "analysis" ], "definitions": { "AvResult": { @@ -360,6 +231,159 @@ "file_size", "mime" ] + }, + "AnalysisDetails": { + "title": "AnalysisDetails", + "type": "object", + "properties": { + "status": { + "title": "Status", + "description": "False means an error occured", + "type": "boolean" + }, + "special_status_code": { + "title": "Special Status Code", + "description": "Special error code, 0 means no special case", + "type": "integer" + }, + "uuid": { + "title": "Uuid", + "description": "Unique analysis identifier", + "type": "string" + }, + "sha256": { + "title": "Sha256", + "description": "String hex encoded input file SHA256", + "type": "string" + }, + "sha1": { + "title": "Sha1", + "description": "String hex encoded input file SHA1", + "type": "string" + }, + "md5": { + "title": "Md5", + "description": "String hex encoded input file MD5", + "type": "string" + }, + "ssdeep": { + "title": "Ssdeep", + "description": "File's SSDeep", + "type": "string" + }, + "is_malware": { + "title": "Is Malware", + "description": "Analysis verdict, malware or not", + "type": "boolean" + }, + "score": { + "title": "Score", + "description": "Highest score given by the services, of all the files in the submission", + "type": "integer" + }, + "done": { + "title": "Done", + "description": "Analysis status, true if analysis is done", + "type": "boolean" + }, + "timestamp": { + "title": "Timestamp", + "description": "Timestamp of the start of analysis in milliseconds", + "type": "integer" + }, + "file_count": { + "title": "File Count", + "description": "Amount of file in the submission (input + extracted)", + "type": "integer" + }, + "duration": { + "title": "Duration", + "description": "Duration of the analysis in milliseconds", + "type": "integer" + }, + "filetype": { + "title": "Filetype", + "description": "Type of the file", + "type": "string" + }, + "size": { + "title": "Size", + "description": "Input file size (in bytes)", + "type": "integer" + }, + "sid": { + "title": "Sid", + "description": "Analysis ID on GLIMPS Malware Expert\ncould be used to construct expert link like:\nhttps://gmalware.useddomain.glimps.re/expert/en/analysis/results/advanced/${SID}", + "type": "string" + }, + "token": { + "title": "Token", + "description": "Token that can be used to view analysis result in expert view", + "type": "string" + }, + "error": { + "title": "Error", + "description": "Error message if Status is false", + "type": "string" + }, + "errors": { + "title": "Errors", + "description": "Error message by services", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "filenames": { + "title": "Filenames", + "description": "List of analysed filename", + "type": "array", + "items": { + "type": "string" + } + }, + "malwares": { + "title": "Malwares", + "description": "List of malware names found in analysis", + "type": "array", + "items": { + "type": "string" + } + }, + "files": { + "title": "Files", + "description": "Array of submission files (input file and extracted sub-files)", + "type": "array", + "items": { + "$ref": "#/definitions/FileResult" + } + }, + "threats": { + "title": "Threats", + "description": "Summary of threats found in submission. Each submission file reaching threshold score will add an entry. Entry keys are files' SHA256", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Threat" + } + } + }, + "required": [ + "status", + "special_status_code", + "uuid", + "sha256", + "sha1", + "md5", + "ssdeep", + "is_malware", + "score", + "done", + "timestamp", + "file_count", + "duration", + "filetype", + "size" + ] } } } diff --git a/Glimps/action_export_analysis_result.json b/Glimps/action_export_analysis_result.json index 4a9af6894..9d1deb555 100644 --- a/Glimps/action_export_analysis_result.json +++ b/Glimps/action_export_analysis_result.json @@ -14,17 +14,17 @@ }, "format": { "title": "Format", - "description": "export format", + "description": "Export format", "type": "string" }, "layout": { "title": "Layout", - "description": "export layout", + "description": "Export layout", "type": "string" }, "is_full": { "title": "Is Full", - "description": "should export full analysis or summarized", + "description": "Export full analysis or summarized", "default": false, "type": "string" } diff --git a/Glimps/action_get_profile_status.json b/Glimps/action_get_profile_status.json index 04166962c..ad664dc8d 100644 --- a/Glimps/action_get_profile_status.json +++ b/Glimps/action_get_profile_status.json @@ -10,22 +10,22 @@ "properties": { "daily_quota": { "title": "Daily Quota", - "description": "Number of submissions authorized for the profile within 24h.", + "description": "Number of submissions authorized for the profile within 24h", "type": "integer" }, "available_daily_quota": { "title": "Available Daily Quota", - "description": "Number of submissions still available within 24h. It's a sliding window, so a new slot will be released 24h after each submission.", + "description": "Number of submissions still available within 24h. It's a sliding window, so a new slot will be released 24h after each submission", "type": "integer" }, "cache": { "title": "Cache", - "description": "If True, the profile is configured to use cached result by default.", + "description": "If True, the profile is configured to use cached result by default", "type": "boolean" }, "estimated_analysis_duration": { "title": "Estimated Analysis Duration", - "description": "t's an estimation of the duration for the next submissions in milliseconds. It's based on the average time of submissions and the submission queue state. The real duration could differ from the estimation.", + "description": "Estimation of the duration for the next submissions in milliseconds. It's based on the average time of submissions and the submission queue state. The real duration could differ from the estimation", "type": "integer" } }, diff --git a/Glimps/action_retrieve_analysis.json b/Glimps/action_retrieve_analysis.json index fb04c7d2c..4704d6b55 100644 --- a/Glimps/action_retrieve_analysis.json +++ b/Glimps/action_retrieve_analysis.json @@ -9,7 +9,7 @@ "properties": { "uuid": { "title": "Uuid", - "description": "uuid of analysis", + "description": "UUID of the analysis", "type": "string" } }, @@ -21,153 +21,24 @@ "title": "AnalysisResponse", "type": "object", "properties": { - "status": { - "title": "Status", - "description": "false means an error occured", - "type": "boolean" - }, - "special_status_code": { - "title": "Special Status Code", - "description": "special error code, 0 means no special case", - "type": "integer" - }, - "uuid": { - "title": "Uuid", - "description": "Unique analysis identifier", - "type": "string" - }, - "sha256": { - "title": "Sha256", - "description": "string hex encoded input file SHA256", - "type": "string" - }, - "sha1": { - "title": "Sha1", - "description": "string hex encoded input file SHA1", - "type": "string" - }, - "md5": { - "title": "Md5", - "description": "string hex encoded input file MD5", - "type": "string" - }, - "ssdeep": { - "title": "Ssdeep", - "description": "string input file SSDeep", - "type": "string" - }, - "is_malware": { - "title": "Is Malware", - "description": "analysis result, is a malware or not", - "type": "boolean" - }, - "score": { - "title": "Score", - "description": "highest score given by probes", - "type": "integer" - }, - "done": { - "title": "Done", - "description": "is analysis finished", - "type": "boolean" - }, - "timestamp": { - "title": "Timestamp", - "description": "timestamp of the start of analysis in milliseconds", - "type": "integer" - }, - "file_count": { - "title": "File Count", - "description": "amount of file in the submission (input + extracted)", - "type": "integer" - }, - "duration": { - "title": "Duration", - "description": "duration of the analysis in milliseconds", - "type": "integer" - }, - "filetype": { - "title": "Filetype", - "description": "type of the file", - "type": "string" - }, - "size": { - "title": "Size", - "description": "input file size (in bytes)", - "type": "integer" - }, - "sid": { - "title": "Sid", - "description": "analysis UUID handled by GLIMPS malware finder - expert\ncould be used to construct expert link like:\nhttps://gmalware.useddomain.glimps.re/expert/en/analysis/results/advanced/${SID}", - "type": "string" - }, - "token": { - "title": "Token", - "description": "token that can be used to view analysis result in expert view", - "type": "string" + "analysis": { + "title": "Analysis", + "description": "Analysis response details", + "allOf": [ + { + "$ref": "#/definitions/AnalysisDetails" + } + ] }, - "error": { - "title": "Error", - "description": "error message if Status is false", + "view_url": { + "title": "View Url", + "description": "Analysis URL", + "default": "", "type": "string" - }, - "errors": { - "title": "Errors", - "description": "error message by services", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "filenames": { - "title": "Filenames", - "description": "list of analysed filename", - "type": "array", - "items": { - "type": "string" - } - }, - "malwares": { - "title": "Malwares", - "description": "list of malware names found in analysis", - "type": "array", - "items": { - "type": "string" - } - }, - "files": { - "title": "Files", - "description": "array of submission files (input file and extracted sub-files)", - "type": "array", - "items": { - "$ref": "#/definitions/FileResult" - } - }, - "threats": { - "title": "Threats", - "description": "Summary of threats found in submission. Each submission file reaching threshold score will add an entry. Entry keys are the SHA256 of files", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Threat" - } } }, "required": [ - "status", - "special_status_code", - "uuid", - "sha256", - "sha1", - "md5", - "ssdeep", - "is_malware", - "score", - "done", - "timestamp", - "file_count", - "duration", - "filetype", - "size" + "analysis" ], "definitions": { "AvResult": { @@ -319,6 +190,159 @@ "file_size", "mime" ] + }, + "AnalysisDetails": { + "title": "AnalysisDetails", + "type": "object", + "properties": { + "status": { + "title": "Status", + "description": "False means an error occured", + "type": "boolean" + }, + "special_status_code": { + "title": "Special Status Code", + "description": "Special error code, 0 means no special case", + "type": "integer" + }, + "uuid": { + "title": "Uuid", + "description": "Unique analysis identifier", + "type": "string" + }, + "sha256": { + "title": "Sha256", + "description": "String hex encoded input file SHA256", + "type": "string" + }, + "sha1": { + "title": "Sha1", + "description": "String hex encoded input file SHA1", + "type": "string" + }, + "md5": { + "title": "Md5", + "description": "String hex encoded input file MD5", + "type": "string" + }, + "ssdeep": { + "title": "Ssdeep", + "description": "File's SSDeep", + "type": "string" + }, + "is_malware": { + "title": "Is Malware", + "description": "Analysis verdict, malware or not", + "type": "boolean" + }, + "score": { + "title": "Score", + "description": "Highest score given by the services, of all the files in the submission", + "type": "integer" + }, + "done": { + "title": "Done", + "description": "Analysis status, true if analysis is done", + "type": "boolean" + }, + "timestamp": { + "title": "Timestamp", + "description": "Timestamp of the start of analysis in milliseconds", + "type": "integer" + }, + "file_count": { + "title": "File Count", + "description": "Amount of file in the submission (input + extracted)", + "type": "integer" + }, + "duration": { + "title": "Duration", + "description": "Duration of the analysis in milliseconds", + "type": "integer" + }, + "filetype": { + "title": "Filetype", + "description": "Type of the file", + "type": "string" + }, + "size": { + "title": "Size", + "description": "Input file size (in bytes)", + "type": "integer" + }, + "sid": { + "title": "Sid", + "description": "Analysis ID on GLIMPS Malware Expert\ncould be used to construct expert link like:\nhttps://gmalware.useddomain.glimps.re/expert/en/analysis/results/advanced/${SID}", + "type": "string" + }, + "token": { + "title": "Token", + "description": "Token that can be used to view analysis result in expert view", + "type": "string" + }, + "error": { + "title": "Error", + "description": "Error message if Status is false", + "type": "string" + }, + "errors": { + "title": "Errors", + "description": "Error message by services", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "filenames": { + "title": "Filenames", + "description": "List of analysed filename", + "type": "array", + "items": { + "type": "string" + } + }, + "malwares": { + "title": "Malwares", + "description": "List of malware names found in analysis", + "type": "array", + "items": { + "type": "string" + } + }, + "files": { + "title": "Files", + "description": "Array of submission files (input file and extracted sub-files)", + "type": "array", + "items": { + "$ref": "#/definitions/FileResult" + } + }, + "threats": { + "title": "Threats", + "description": "Summary of threats found in submission. Each submission file reaching threshold score will add an entry. Entry keys are files' SHA256", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Threat" + } + } + }, + "required": [ + "status", + "special_status_code", + "uuid", + "sha256", + "sha1", + "md5", + "ssdeep", + "is_malware", + "score", + "done", + "timestamp", + "file_count", + "duration", + "filetype", + "size" + ] } } } diff --git a/Glimps/action_search_analysis.json b/Glimps/action_search_analysis.json index 360e361b0..5c4b2e777 100644 --- a/Glimps/action_search_analysis.json +++ b/Glimps/action_search_analysis.json @@ -9,7 +9,7 @@ "properties": { "sha256": { "title": "Sha256", - "description": "sha256 of file to search", + "description": "SHA256 of file to search", "type": "string" } }, @@ -21,153 +21,24 @@ "title": "AnalysisResponse", "type": "object", "properties": { - "status": { - "title": "Status", - "description": "false means an error occured", - "type": "boolean" - }, - "special_status_code": { - "title": "Special Status Code", - "description": "special error code, 0 means no special case", - "type": "integer" - }, - "uuid": { - "title": "Uuid", - "description": "Unique analysis identifier", - "type": "string" - }, - "sha256": { - "title": "Sha256", - "description": "string hex encoded input file SHA256", - "type": "string" - }, - "sha1": { - "title": "Sha1", - "description": "string hex encoded input file SHA1", - "type": "string" - }, - "md5": { - "title": "Md5", - "description": "string hex encoded input file MD5", - "type": "string" - }, - "ssdeep": { - "title": "Ssdeep", - "description": "string input file SSDeep", - "type": "string" - }, - "is_malware": { - "title": "Is Malware", - "description": "analysis result, is a malware or not", - "type": "boolean" - }, - "score": { - "title": "Score", - "description": "highest score given by probes", - "type": "integer" - }, - "done": { - "title": "Done", - "description": "is analysis finished", - "type": "boolean" - }, - "timestamp": { - "title": "Timestamp", - "description": "timestamp of the start of analysis in milliseconds", - "type": "integer" - }, - "file_count": { - "title": "File Count", - "description": "amount of file in the submission (input + extracted)", - "type": "integer" - }, - "duration": { - "title": "Duration", - "description": "duration of the analysis in milliseconds", - "type": "integer" - }, - "filetype": { - "title": "Filetype", - "description": "type of the file", - "type": "string" - }, - "size": { - "title": "Size", - "description": "input file size (in bytes)", - "type": "integer" - }, - "sid": { - "title": "Sid", - "description": "analysis UUID handled by GLIMPS malware finder - expert\ncould be used to construct expert link like:\nhttps://gmalware.useddomain.glimps.re/expert/en/analysis/results/advanced/${SID}", - "type": "string" - }, - "token": { - "title": "Token", - "description": "token that can be used to view analysis result in expert view", - "type": "string" + "analysis": { + "title": "Analysis", + "description": "Analysis response details", + "allOf": [ + { + "$ref": "#/definitions/AnalysisDetails" + } + ] }, - "error": { - "title": "Error", - "description": "error message if Status is false", + "view_url": { + "title": "View Url", + "description": "Analysis URL", + "default": "", "type": "string" - }, - "errors": { - "title": "Errors", - "description": "error message by services", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "filenames": { - "title": "Filenames", - "description": "list of analysed filename", - "type": "array", - "items": { - "type": "string" - } - }, - "malwares": { - "title": "Malwares", - "description": "list of malware names found in analysis", - "type": "array", - "items": { - "type": "string" - } - }, - "files": { - "title": "Files", - "description": "array of submission files (input file and extracted sub-files)", - "type": "array", - "items": { - "$ref": "#/definitions/FileResult" - } - }, - "threats": { - "title": "Threats", - "description": "Summary of threats found in submission. Each submission file reaching threshold score will add an entry. Entry keys are the SHA256 of files", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Threat" - } } }, "required": [ - "status", - "special_status_code", - "uuid", - "sha256", - "sha1", - "md5", - "ssdeep", - "is_malware", - "score", - "done", - "timestamp", - "file_count", - "duration", - "filetype", - "size" + "analysis" ], "definitions": { "AvResult": { @@ -319,6 +190,159 @@ "file_size", "mime" ] + }, + "AnalysisDetails": { + "title": "AnalysisDetails", + "type": "object", + "properties": { + "status": { + "title": "Status", + "description": "False means an error occured", + "type": "boolean" + }, + "special_status_code": { + "title": "Special Status Code", + "description": "Special error code, 0 means no special case", + "type": "integer" + }, + "uuid": { + "title": "Uuid", + "description": "Unique analysis identifier", + "type": "string" + }, + "sha256": { + "title": "Sha256", + "description": "String hex encoded input file SHA256", + "type": "string" + }, + "sha1": { + "title": "Sha1", + "description": "String hex encoded input file SHA1", + "type": "string" + }, + "md5": { + "title": "Md5", + "description": "String hex encoded input file MD5", + "type": "string" + }, + "ssdeep": { + "title": "Ssdeep", + "description": "File's SSDeep", + "type": "string" + }, + "is_malware": { + "title": "Is Malware", + "description": "Analysis verdict, malware or not", + "type": "boolean" + }, + "score": { + "title": "Score", + "description": "Highest score given by the services, of all the files in the submission", + "type": "integer" + }, + "done": { + "title": "Done", + "description": "Analysis status, true if analysis is done", + "type": "boolean" + }, + "timestamp": { + "title": "Timestamp", + "description": "Timestamp of the start of analysis in milliseconds", + "type": "integer" + }, + "file_count": { + "title": "File Count", + "description": "Amount of file in the submission (input + extracted)", + "type": "integer" + }, + "duration": { + "title": "Duration", + "description": "Duration of the analysis in milliseconds", + "type": "integer" + }, + "filetype": { + "title": "Filetype", + "description": "Type of the file", + "type": "string" + }, + "size": { + "title": "Size", + "description": "Input file size (in bytes)", + "type": "integer" + }, + "sid": { + "title": "Sid", + "description": "Analysis ID on GLIMPS Malware Expert\ncould be used to construct expert link like:\nhttps://gmalware.useddomain.glimps.re/expert/en/analysis/results/advanced/${SID}", + "type": "string" + }, + "token": { + "title": "Token", + "description": "Token that can be used to view analysis result in expert view", + "type": "string" + }, + "error": { + "title": "Error", + "description": "Error message if Status is false", + "type": "string" + }, + "errors": { + "title": "Errors", + "description": "Error message by services", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "filenames": { + "title": "Filenames", + "description": "List of analysed filename", + "type": "array", + "items": { + "type": "string" + } + }, + "malwares": { + "title": "Malwares", + "description": "List of malware names found in analysis", + "type": "array", + "items": { + "type": "string" + } + }, + "files": { + "title": "Files", + "description": "Array of submission files (input file and extracted sub-files)", + "type": "array", + "items": { + "$ref": "#/definitions/FileResult" + } + }, + "threats": { + "title": "Threats", + "description": "Summary of threats found in submission. Each submission file reaching threshold score will add an entry. Entry keys are files' SHA256", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Threat" + } + } + }, + "required": [ + "status", + "special_status_code", + "uuid", + "sha256", + "sha1", + "md5", + "ssdeep", + "is_malware", + "score", + "done", + "timestamp", + "file_count", + "duration", + "filetype", + "size" + ] } } } diff --git a/Glimps/glimps/base.py b/Glimps/glimps/base.py index 7a6bd9926..d892d9ba2 100644 --- a/Glimps/glimps/base.py +++ b/Glimps/glimps/base.py @@ -1,14 +1,26 @@ from sekoia_automation.action import Action -from gdetect import Client +from gdetect import Client, GDetectError from functools import cached_property -from glimps.models import GlimpsModule +from glimps.models import GLIMPSModule -class GlimpsAction(Action): - module: GlimpsModule +class GLIMPSAction(Action): + module: GLIMPSModule @cached_property def gdetect_client(self): return Client( self.module.configuration.base_url, self.module.configuration.api_key ) + + def _get_token_view_url(self, analysis: dict) -> str: + """Extract url token view from analysis response, if possible""" + response = "" + try: + response = self.gdetect_client.extract_url_token_view(analysis) + except GDetectError: + try: + response = self.gdetect_client.extract_expert_url(analysis) + except GDetectError: + pass + return response diff --git a/Glimps/glimps/errors.py b/Glimps/glimps/errors.py deleted file mode 100644 index 58640d885..000000000 --- a/Glimps/glimps/errors.py +++ /dev/null @@ -1,12 +0,0 @@ -class Error(Exception): - """Base class for exceptions in this module.""" - - pass - - -class MaxFileSizeExceedError(Error): - def __init__(self, msg=None): - self.message = msg if msg else "The file exceeds the maximum size of 40MB" - - def __str__(self): - return f"{self.__class__.__name__} {self.message}" diff --git a/Glimps/glimps/export_action.py b/Glimps/glimps/export_action.py index e6b9dfd09..6e68731c4 100644 --- a/Glimps/glimps/export_action.py +++ b/Glimps/glimps/export_action.py @@ -1,8 +1,8 @@ -from glimps.base import GlimpsAction +from glimps.base import GLIMPSAction from glimps.models import ExportSubmissionArguments -class ExportSubmission(GlimpsAction): +class ExportSubmission(GLIMPSAction): """Action to export analysis result with the requested layout and format""" name = "Export analysis result" diff --git a/Glimps/glimps/get_status_action.py b/Glimps/glimps/get_status_action.py index 8387d3337..a05257ebc 100644 --- a/Glimps/glimps/get_status_action.py +++ b/Glimps/glimps/get_status_action.py @@ -1,8 +1,8 @@ -from glimps.base import GlimpsAction +from glimps.base import GLIMPSAction from glimps.models import ProfileStatus -class GetStatus(GlimpsAction): +class GetStatus(GLIMPSAction): """Action to retrieve profile status""" name = "Get profile status" diff --git a/Glimps/glimps/models.py b/Glimps/glimps/models.py index 98f78245b..aade120fc 100644 --- a/Glimps/glimps/models.py +++ b/Glimps/glimps/models.py @@ -5,59 +5,62 @@ from pydantic import BaseModel, Field, validator from sekoia_automation.module import Module from typing_extensions import TypedDict, NotRequired +from gdetect.consts import EXPORT_FORMATS, EXPORT_LAYOUTS -class GlimpsConfiguration(BaseModel): +class GLIMPSConfiguration(BaseModel): api_key: str = Field(..., secret=True, description="Glimps detect token") base_url: str = Field(..., description="Glimps detect url") -class GlimpsModule(Module): - configuration: GlimpsConfiguration +class GLIMPSModule(Module): + configuration: GLIMPSConfiguration class SubmitArgument(BaseModel): - file_name: str = Field(..., description="name of submitted file") + file_name: str = Field(..., description="Name of submitted file") bypass_cache: bool = Field( default=False, - description="If True, the file is analyzed, even if a result already exists", + description="If true, file is analyzed, even if a result already exists", ) user_tags: tuple = Field( - default=(), description="If filled, the file will be tagged with those tags" + default=(), description="Analysis will be tagged with those tags" ) - description: str | None = Field( - description=" If filled, a description will be added to the analysis" + description: str = Field( + default=None, + description="Description added to the analysis", ) - archive_pwd: str | None = Field( - description="If filled, the password used to extract archive" + archive_pwd: str = Field( + default=None, description="Password used to extract archive" ) push_timeout: float = Field( default=30, - description="The maximum time (in seconds) to wait for a response when submitting file", + description="Maximum time (in seconds) to wait for a response when submitting file", ) class WaitForResultArgument(SubmitArgument): pull_time: float = Field( default=1.0, - description="The time to wait (in seconds) between each requests to get a result", + description="Time to wait (in seconds) between each requests to get a result", ) timeout: float = Field( - default=180, description="The maximum time execution of this method in seconds" + default=180, + description="Maximum time (in seconds) to wait for the analysis to end", ) class SearchAnalysisBySha256Argument(BaseModel): - sha256: str = Field(..., description="sha256 of file to search") + sha256: str = Field(..., description="SHA256 of file to search") class GetAnalysisByUUIDArgument(BaseModel): - uuid: str = Field(..., description="uuid of analysis") + uuid: str = Field(..., description="UUID of the analysis") class SubmitResponse(BaseModel): status: bool = Field(default=False, description="False means that an error occured") - uuid: str = Field(default=None, description="uuid of the submitted analysis") + uuid: str = Field(default=None, description="UUID of the submitted analysis") class Tag(TypedDict): @@ -94,89 +97,94 @@ class FileResult(TypedDict): av_result: NotRequired[list[AvResult]] -class AnalysisResponse(BaseModel): - status: bool = Field(description="false means an error occured") +class AnalysisDetails(BaseModel): + status: bool = Field(description="False means an error occured") special_status_code: int = Field( - description="special error code, 0 means no special case" + description="Special error code, 0 means no special case" ) uuid: str = Field(description="Unique analysis identifier") - sha256: str = Field(description="string hex encoded input file SHA256") - sha1: str = Field(description="string hex encoded input file SHA1") - md5: str = Field(description="string hex encoded input file MD5") - ssdeep: str = Field(description="string input file SSDeep") - is_malware: bool = Field(description="analysis result, is a malware or not") - score: int = Field(description="highest score given by probes") - done: bool = Field(description="is analysis finished") + sha256: str = Field(description="String hex encoded input file SHA256") + sha1: str = Field(description="String hex encoded input file SHA1") + md5: str = Field(description="String hex encoded input file MD5") + ssdeep: str = Field(description="File's SSDeep") + is_malware: bool = Field(description="Analysis verdict, malware or not") + score: int = Field( + description="Highest score given by the services, of all the files in the submission" + ) + done: bool = Field(description="Analysis status, true if analysis is done") timestamp: int = Field( - description="timestamp of the start of analysis in milliseconds" + description="Timestamp of the start of analysis in milliseconds" ) file_count: int = Field( - description="amount of file in the submission (input + extracted)" + description="Amount of file in the submission (input + extracted)" ) - duration: int = Field(description="duration of the analysis in milliseconds") - filetype: str = Field(description="type of the file") - size: int = Field(description="input file size (in bytes)") + duration: int = Field(description="Duration of the analysis in milliseconds") + filetype: str = Field(description="Type of the file") + size: int = Field(description="Input file size (in bytes)") # non required fields below sid: str = Field( default=None, - description="analysis UUID handled by GLIMPS malware finder - expert\ncould be used to construct expert link like:\nhttps://gmalware.useddomain.glimps.re/expert/en/analysis/results/advanced/${SID}", + description="Analysis ID on GLIMPS Malware Expert\ncould be used to construct expert link like:\nhttps://gmalware.useddomain.glimps.re/expert/en/analysis/results/advanced/${SID}", ) token: str = Field( default=None, - description="token that can be used to view analysis result in expert view", + description="Token that can be used to view analysis result in expert view", ) - error: str = Field(default=None, description="error message if Status is false") + error: str = Field(default=None, description="Error message if Status is false") errors: dict[str, str] = Field( - default=None, description="error message by services" + default=None, description="Error message by services" ) - filenames: list[str] = Field(default=None, description="list of analysed filename") + filenames: list[str] = Field(default=None, description="List of analysed filename") malwares: list[str] = Field( - default=None, description="list of malware names found in analysis" + default=None, description="List of malware names found in analysis" ) files: list[FileResult] = Field( default=None, - description="array of submission files (input file and extracted sub-files)", + description="Array of submission files (input file and extracted sub-files)", ) threats: dict[str, Threat] = Field( default=None, - description="Summary of threats found in submission. Each submission file reaching threshold score will add an entry. Entry keys are the SHA256 of files", + description="Summary of threats found in submission. Each submission file reaching threshold score will add an entry. Entry keys are files' SHA256", ) +class AnalysisResponse(BaseModel): + analysis: AnalysisDetails = Field(..., description="Analysis response details") + view_url: str = Field(default="", description="Analysis URL") + + class ProfileStatus(BaseModel): daily_quota: int = Field( - description="Number of submissions authorized for the profile within 24h." + description="Number of submissions authorized for the profile within 24h" ) available_daily_quota: int = Field( - description="Number of submissions still available within 24h. It's a sliding window, so a new slot will be released 24h after each submission." + description="Number of submissions still available within 24h. It's a sliding window, so a new slot will be released 24h after each submission" ) cache: bool = Field( - description="If True, the profile is configured to use cached result by default." + description="If True, the profile is configured to use cached result by default" ) estimated_analysis_duration: int = Field( - description="t's an estimation of the duration for the next submissions in milliseconds. It's based on the average time of submissions and the submission queue state. The real duration could differ from the estimation." + description="Estimation of the duration for the next submissions in milliseconds. It's based on the average time of submissions and the submission queue state. The real duration could differ from the estimation" ) class ExportSubmissionArguments(BaseModel): uuid: str = Field(description="Unique analysis identifier") - format: str = Field(description="export format") - layout: str = Field(description="export layout") + format: str = Field(description="Export format") + layout: str = Field(description="Export layout") is_full: str = Field( - default=False, description="should export full analysis or summarized" + default=False, description="Export full analysis or summarized" ) @validator("format") def check_format(cls, v: str): - allowed_format = ["misp", "stix", "json", "pdf", "markdown", "csv"] - if v not in allowed_format: - raise ValueError(f"format must be on of {allowed_format}") + if v not in EXPORT_FORMATS: + raise ValueError(f"format must be one of {EXPORT_FORMATS}") return v @validator("layout") def check_layout(cls, v: str): - allowed_layout = ["fr", "en"] - if v not in allowed_layout: - raise ValueError(f"format must be on of {allowed_layout}") + if v not in EXPORT_LAYOUTS: + raise ValueError(f"layout must be one of {EXPORT_LAYOUTS}") return v diff --git a/Glimps/glimps/retrieve_analysis_action.py b/Glimps/glimps/retrieve_analysis_action.py index 29db48380..fea3e6e6e 100644 --- a/Glimps/glimps/retrieve_analysis_action.py +++ b/Glimps/glimps/retrieve_analysis_action.py @@ -1,8 +1,8 @@ -from glimps.base import GlimpsAction -from glimps.models import AnalysisResponse, GetAnalysisByUUIDArgument +from glimps.base import GLIMPSAction +from glimps.models import AnalysisDetails, GetAnalysisByUUIDArgument, AnalysisResponse -class RetrieveAnalysis(GlimpsAction): +class RetrieveAnalysis(GLIMPSAction): """Action to get a result by uuid""" name = "Retrieve analysis" @@ -10,6 +10,8 @@ class RetrieveAnalysis(GlimpsAction): results_model = AnalysisResponse def run(self, arguments: GetAnalysisByUUIDArgument) -> AnalysisResponse: - analysis = self.gdetect_client.get_by_uuid(arguments.uuid) - response = AnalysisResponse.parse_obj(analysis) - return response + raw_analysis = self.gdetect_client.get_by_uuid(arguments.uuid) + details = AnalysisDetails.parse_obj(raw_analysis) + view_token: str = self._get_token_view_url(raw_analysis) + + return AnalysisResponse(analysis=details, view_url=view_token) diff --git a/Glimps/glimps/search_analysis_by_sha256_action.py b/Glimps/glimps/search_analysis_by_sha256_action.py index 2fc369a09..54bb49c71 100644 --- a/Glimps/glimps/search_analysis_by_sha256_action.py +++ b/Glimps/glimps/search_analysis_by_sha256_action.py @@ -1,8 +1,12 @@ -from glimps.base import GlimpsAction -from glimps.models import AnalysisResponse, SearchAnalysisBySha256Argument +from glimps.base import GLIMPSAction +from glimps.models import ( + AnalysisDetails, + SearchAnalysisBySha256Argument, + AnalysisResponse, +) -class SearchPreviousAnalysis(GlimpsAction): +class SearchPreviousAnalysis(GLIMPSAction): """Action to search an analysis result using the file sha256""" name = "Search analysis" @@ -10,6 +14,8 @@ class SearchPreviousAnalysis(GlimpsAction): results_model = AnalysisResponse def run(self, arguments: SearchAnalysisBySha256Argument) -> AnalysisResponse: - analysis = self.gdetect_client.get_by_sha256(arguments.sha256) - response: AnalysisResponse = AnalysisResponse.parse_obj(analysis) - return response + raw_analysis = self.gdetect_client.get_by_sha256(arguments.sha256) + details: AnalysisDetails = AnalysisDetails.parse_obj(raw_analysis) + view_token: str = self._get_token_view_url(raw_analysis) + + return AnalysisResponse(analysis=details, view_url=view_token) diff --git a/Glimps/glimps/submit_file_to_be_analysed_action.py b/Glimps/glimps/submit_file_to_be_analysed_action.py index 3f08d488c..9f4f083a8 100644 --- a/Glimps/glimps/submit_file_to_be_analysed_action.py +++ b/Glimps/glimps/submit_file_to_be_analysed_action.py @@ -1,9 +1,9 @@ -from glimps.base import GlimpsAction +from glimps.base import GLIMPSAction from glimps.models import SubmitArgument, SubmitResponse -from glimps.models import WaitForResultArgument, AnalysisResponse +from glimps.models import WaitForResultArgument, AnalysisDetails, AnalysisResponse -class SubmitFileToBeAnalysed(GlimpsAction): +class SubmitFile(GLIMPSAction): """Action to submit a file for glimps malware analysis""" name = "Analyse a file" @@ -24,7 +24,7 @@ def run(self, arguments: SubmitArgument) -> SubmitResponse: return response -class SubmitFileWaitForResult(GlimpsAction): +class WaitForFile(GLIMPSAction): """Action to submit a file to GLIMPS Detect and wait for a result""" name = "Analyse a file and wait for result" @@ -32,7 +32,7 @@ class SubmitFileWaitForResult(GlimpsAction): results_model = AnalysisResponse def run(self, arguments: WaitForResultArgument) -> AnalysisResponse: - analysis = self.gdetect_client.waitfor( + raw_analysis = self.gdetect_client.waitfor( self._data_path.joinpath(arguments.file_name), bypass_cache=arguments.bypass_cache, pull_time=arguments.pull_time, @@ -42,6 +42,7 @@ def run(self, arguments: WaitForResultArgument) -> AnalysisResponse: description=arguments.description, archive_password=arguments.archive_pwd, ) - response: AnalysisResponse = AnalysisResponse.parse_obj(analysis) + details = AnalysisDetails.parse_obj(raw_analysis) + view_token: str = self._get_token_view_url(raw_analysis) - return response + return AnalysisResponse(analysis=details, view_url=view_token) diff --git a/Glimps/main.py b/Glimps/main.py index 75dff566e..6ed6e64af 100644 --- a/Glimps/main.py +++ b/Glimps/main.py @@ -1,19 +1,19 @@ -from glimps.models import GlimpsModule +from glimps.models import GLIMPSModule -from glimps.submit_file_to_be_analysed_action import SubmitFileToBeAnalysed -from glimps.get_status_action import GetStatus -from glimps.retrieve_analysis_action import RetrieveAnalysis from glimps.export_action import ExportSubmission from glimps.search_analysis_by_sha256_action import SearchPreviousAnalysis -from glimps.submit_file_to_be_analysed_action import SubmitFileWaitForResult +from glimps.submit_file_to_be_analysed_action import WaitForFile +from glimps.submit_file_to_be_analysed_action import SubmitFile +from glimps.get_status_action import GetStatus +from glimps.retrieve_analysis_action import RetrieveAnalysis if __name__ == "__main__": - module = GlimpsModule() - module.register(SubmitFileToBeAnalysed, "SubmitFileToBeAnalysed") - module.register(GetStatus, "GetStatus") - module.register(RetrieveAnalysis, "RetrieveAnalysis") + module = GLIMPSModule() module.register(ExportSubmission, "ExportSubmission") module.register(SearchPreviousAnalysis, "SearchPreviousAnalysis") - module.register(SubmitFileWaitForResult, "SubmitFileWaitForResult") + module.register(WaitForFile, "WaitForFile") + module.register(SubmitFile, "SubmitFile") + module.register(GetStatus, "GetStatus") + module.register(RetrieveAnalysis, "RetrieveAnalysis") module.run() diff --git a/Glimps/manifest.json b/Glimps/manifest.json index aa4b3a982..cb48ca76e 100644 --- a/Glimps/manifest.json +++ b/Glimps/manifest.json @@ -5,7 +5,7 @@ "description": "[Glimps](https://www.glimps.fr/) offers a DeepLearning solution to detect, analyze and classify malwares. It enables faster responses during incidents with a detailed understanding of the threat", "version": "1.14.0", "configuration": { - "title": "GlimpsConfiguration", + "title": "GLIMPSConfiguration", "type": "object", "properties": { "api_key": { diff --git a/Glimps/poetry.lock b/Glimps/poetry.lock index 63413dee1..4f12034b3 100644 --- a/Glimps/poetry.lock +++ b/Glimps/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "arrow" @@ -100,17 +100,17 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.35.59" +version = "1.35.63" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.35.59-py3-none-any.whl", hash = "sha256:8f8ff97cb9cb2e1ec7374209d0c09c1926b75604d6464c34bafaffd6d6cf0529"}, - {file = "boto3-1.35.59.tar.gz", hash = "sha256:81f4d8d6eff3e26b82cabd42eda816cfac9482821fdef353f18d2ba2f6e75f2d"}, + {file = "boto3-1.35.63-py3-none-any.whl", hash = "sha256:d0f938d4f6f392b6ffc5e75fff14a42e5bbb5228675a0367c8af55398abadbec"}, + {file = "boto3-1.35.63.tar.gz", hash = "sha256:deb593d9a0fb240deb4c43e4da8e6626d7c36be7b2fd2fe28f49d44d395b7de0"}, ] [package.dependencies] -botocore = ">=1.35.59,<1.36.0" +botocore = ">=1.35.63,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -119,13 +119,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.35.59" +version = "1.35.63" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.35.59-py3-none-any.whl", hash = "sha256:bcd66d7f55c8d1b6020eb86f2d87893fe591fb4be6a7d2a689c18be586452334"}, - {file = "botocore-1.35.59.tar.gz", hash = "sha256:de0ce655fedfc02c87869dfaa3b622488a17ff37da316ef8106cbe1573b83c98"}, + {file = "botocore-1.35.63-py3-none-any.whl", hash = "sha256:0ca1200694a4c0a3fa846795d8e8a08404c214e21195eb9e010c4b8a4ca78a4a"}, + {file = "botocore-1.35.63.tar.gz", hash = "sha256:2b8196bab0a997d206c3d490b52e779ef47dffb68c57c685443f77293aca1589"}, ] [package.dependencies] @@ -399,19 +399,15 @@ files = [ [[package]] name = "cleo" -version = "2.1.0" +version = "2.2.1" description = "Cleo allows you to create beautiful and testable command-line interfaces." optional = false -python-versions = ">=3.7,<4.0" +python-versions = "<4.0,>=3.7" files = [ - {file = "cleo-2.1.0-py3-none-any.whl", hash = "sha256:4a31bd4dd45695a64ee3c4758f583f134267c2bc518d8ae9a29cf237d009b07e"}, - {file = "cleo-2.1.0.tar.gz", hash = "sha256:0b2c880b5d13660a7ea651001fb4acb527696c01f15c9ee650f377aa543fd523"}, + {file = "cleo-2.2.1-py3-none-any.whl", hash = "sha256:cede63e60a30db8fe9f98ad6a40276c5d1761ba32b68fc8f1846c49d49dbb967"}, + {file = "cleo-2.2.1.tar.gz", hash = "sha256:d9db0fa3a194efb9caadfe1e718bf48cc48f08b7b1ee8381526ecc67c58856c4"}, ] -[package.dependencies] -crashtest = ">=0.4.1,<0.5.0" -rapidfuzz = ">=3.0.0,<4.0.0" - [[package]] name = "click" version = "8.1.7" @@ -491,73 +487,73 @@ rich = "*" [[package]] name = "coverage" -version = "7.6.4" +version = "7.6.7" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, - {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, - {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, - {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, - {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, - {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, - {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, - {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, - {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, - {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, - {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, - {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, - {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, - {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, - {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, - {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, - {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, - {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, - {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, - {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, - {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, - {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, - {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, - {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, - {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, - {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, + {file = "coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e"}, + {file = "coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314"}, + {file = "coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a"}, + {file = "coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163"}, + {file = "coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469"}, + {file = "coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4"}, + {file = "coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2"}, + {file = "coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f"}, + {file = "coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9"}, + {file = "coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb"}, + {file = "coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76"}, + {file = "coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c"}, + {file = "coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3"}, + {file = "coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384"}, + {file = "coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30"}, + {file = "coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42"}, + {file = "coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413"}, + {file = "coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3"}, + {file = "coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8"}, + {file = "coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56"}, + {file = "coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874"}, + {file = "coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289"}, + {file = "coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c"}, + {file = "coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13"}, + {file = "coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671"}, + {file = "coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24"}, ] [package.dependencies] @@ -770,13 +766,13 @@ typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "gdetect" -version = "0.7.0" +version = "0.8.0" description = "Library and CLI for GLIMPS Detect API" optional = false python-versions = ">=3.8" files = [ - {file = "gdetect-0.7.0-py3-none-any.whl", hash = "sha256:b1b197deae246bcdb7c964b2a3c324a9455da44299384113a8ccd3194cf6c709"}, - {file = "gdetect-0.7.0.tar.gz", hash = "sha256:7092fa43c06024d58ae94098bd8efa77579f6480479eefd40131e1cc4fa6ce33"}, + {file = "gdetect-0.8.0-py3-none-any.whl", hash = "sha256:dd7c60901b11bf594b4073071fa099f53382625949d399d138609fab339ce97b"}, + {file = "gdetect-0.8.0.tar.gz", hash = "sha256:0de2497b4b3d494caa030dc81a28010211f430bd1604494a0972cbb52013f931"}, ] [package.dependencies] @@ -1617,106 +1613,6 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] -[[package]] -name = "rapidfuzz" -version = "3.10.1" -description = "rapid fuzzy string matching" -optional = false -python-versions = ">=3.9" -files = [ - {file = "rapidfuzz-3.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f17d9f21bf2f2f785d74f7b0d407805468b4c173fa3e52c86ec94436b338e74a"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b31f358a70efc143909fb3d75ac6cd3c139cd41339aa8f2a3a0ead8315731f2b"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f4f43f2204b56a61448ec2dd061e26fd344c404da99fb19f3458200c5874ba2"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d81bf186a453a2757472133b24915768abc7c3964194406ed93e170e16c21cb"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3611c8f45379a12063d70075c75134f2a8bd2e4e9b8a7995112ddae95ca1c982"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c3b537b97ac30da4b73930fa8a4fe2f79c6d1c10ad535c5c09726612cd6bed9"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231ef1ec9cf7b59809ce3301006500b9d564ddb324635f4ea8f16b3e2a1780da"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed4f3adc1294834955b7e74edd3c6bd1aad5831c007f2d91ea839e76461a5879"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7b6015da2e707bf632a71772a2dbf0703cff6525732c005ad24987fe86e8ec32"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1b35a118d61d6f008e8e3fb3a77674d10806a8972c7b8be433d6598df4d60b01"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bc308d79a7e877226f36bdf4e149e3ed398d8277c140be5c1fd892ec41739e6d"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f017dbfecc172e2d0c37cf9e3d519179d71a7f16094b57430dffc496a098aa17"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-win32.whl", hash = "sha256:36c0e1483e21f918d0f2f26799fe5ac91c7b0c34220b73007301c4f831a9c4c7"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:10746c1d4c8cd8881c28a87fd7ba0c9c102346dfe7ff1b0d021cdf093e9adbff"}, - {file = "rapidfuzz-3.10.1-cp310-cp310-win_arm64.whl", hash = "sha256:dfa64b89dcb906835e275187569e51aa9d546a444489e97aaf2cc84011565fbe"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:92958ae075c87fef393f835ed02d4fe8d5ee2059a0934c6c447ea3417dfbf0e8"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba7521e072c53e33c384e78615d0718e645cab3c366ecd3cc8cb732befd94967"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d02cbd75d283c287471b5b3738b3e05c9096150f93f2d2dfa10b3d700f2db9"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:efa1582a397da038e2f2576c9cd49b842f56fde37d84a6b0200ffebc08d82350"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f12912acee1f506f974f58de9fdc2e62eea5667377a7e9156de53241c05fdba8"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666d5d8b17becc3f53447bcb2b6b33ce6c2df78792495d1fa82b2924cd48701a"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26f71582c0d62445067ee338ddad99b655a8f4e4ed517a90dcbfbb7d19310474"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8a2ef08b27167bcff230ffbfeedd4c4fa6353563d6aaa015d725dd3632fc3de7"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:365e4fc1a2b95082c890f5e98489b894e6bf8c338c6ac89bb6523c2ca6e9f086"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1996feb7a61609fa842e6b5e0c549983222ffdedaf29644cc67e479902846dfe"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:cf654702f144beaa093103841a2ea6910d617d0bb3fccb1d1fd63c54dde2cd49"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec108bf25de674781d0a9a935030ba090c78d49def3d60f8724f3fc1e8e75024"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-win32.whl", hash = "sha256:031f8b367e5d92f7a1e27f7322012f3c321c3110137b43cc3bf678505583ef48"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:f98f36c6a1bb9a6c8bbec99ad87c8c0e364f34761739b5ea9adf7b48129ae8cf"}, - {file = "rapidfuzz-3.10.1-cp311-cp311-win_arm64.whl", hash = "sha256:f1da2028cb4e41be55ee797a82d6c1cf589442504244249dfeb32efc608edee7"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1340b56340896bede246f612b6ecf685f661a56aabef3d2512481bfe23ac5835"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2316515169b7b5a453f0ce3adbc46c42aa332cae9f2edb668e24d1fc92b2f2bb"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e06fe6a12241ec1b72c0566c6b28cda714d61965d86569595ad24793d1ab259"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d99c1cd9443b19164ec185a7d752f4b4db19c066c136f028991a480720472e23"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1d9aa156ed52d3446388ba4c2f335e312191d1ca9d1f5762ee983cf23e4ecf6"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:54bcf4efaaee8e015822be0c2c28214815f4f6b4f70d8362cfecbd58a71188ac"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0c955e32afdbfdf6e9ee663d24afb25210152d98c26d22d399712d29a9b976b"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:191633722203f5b7717efcb73a14f76f3b124877d0608c070b827c5226d0b972"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:195baad28057ec9609e40385991004e470af9ef87401e24ebe72c064431524ab"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0fff4a6b87c07366662b62ae994ffbeadc472e72f725923f94b72a3db49f4671"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4ffed25f9fdc0b287f30a98467493d1e1ce5b583f6317f70ec0263b3c97dbba6"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d02cf8e5af89a9ac8f53c438ddff6d773f62c25c6619b29db96f4aae248177c0"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-win32.whl", hash = "sha256:f3bb81d4fe6a5d20650f8c0afcc8f6e1941f6fecdb434f11b874c42467baded0"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:aaf83e9170cb1338922ae42d320699dccbbdca8ffed07faeb0b9257822c26e24"}, - {file = "rapidfuzz-3.10.1-cp312-cp312-win_arm64.whl", hash = "sha256:c5da802a0d085ad81b0f62828fb55557996c497b2d0b551bbdfeafd6d447892f"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fc22d69a1c9cccd560a5c434c0371b2df0f47c309c635a01a913e03bbf183710"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38b0dac2c8e057562b8f0d8ae5b663d2d6a28c5ab624de5b73cef9abb6129a24"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fde3bbb14e92ce8fcb5c2edfff72e474d0080cadda1c97785bf4822f037a309"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9141fb0592e55f98fe9ac0f3ce883199b9c13e262e0bf40c5b18cdf926109d16"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:237bec5dd1bfc9b40bbd786cd27949ef0c0eb5fab5eb491904c6b5df59d39d3c"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18123168cba156ab5794ea6de66db50f21bb3c66ae748d03316e71b27d907b95"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b75fe506c8e02769cc47f5ab21ce3e09b6211d3edaa8f8f27331cb6988779be"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da82aa4b46973aaf9e03bb4c3d6977004648c8638febfc0f9d237e865761270"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c34c022d5ad564f1a5a57a4a89793bd70d7bad428150fb8ff2760b223407cdcf"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e96c84d6c2a0ca94e15acb5399118fff669f4306beb98a6d8ec6f5dccab4412"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e8e154b84a311263e1aca86818c962e1fa9eefdd643d1d5d197fcd2738f88cb9"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:335fee93188f8cd585552bb8057228ce0111bd227fa81bfd40b7df6b75def8ab"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-win32.whl", hash = "sha256:6729b856166a9e95c278410f73683957ea6100c8a9d0a8dbe434c49663689255"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:0e06d99ad1ad97cb2ef7f51ec6b1fedd74a3a700e4949353871cf331d07b382a"}, - {file = "rapidfuzz-3.10.1-cp313-cp313-win_arm64.whl", hash = "sha256:8d1b7082104d596a3eb012e0549b2634ed15015b569f48879701e9d8db959dbb"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:779027d3307e1a2b1dc0c03c34df87a470a368a1a0840a9d2908baf2d4067956"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:440b5608ab12650d0390128d6858bc839ae77ffe5edf0b33a1551f2fa9860651"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cac41a411e07a6f3dc80dfbd33f6be70ea0abd72e99c59310819d09f07d945"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:958473c9f0bca250590200fd520b75be0dbdbc4a7327dc87a55b6d7dc8d68552"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ef60dfa73749ef91cb6073be1a3e135f4846ec809cc115f3cbfc6fe283a5584"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7fbac18f2c19fc983838a60611e67e3262e36859994c26f2ee85bb268de2355"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a0d519ff39db887cd73f4e297922786d548f5c05d6b51f4e6754f452a7f4296"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bebb7bc6aeb91cc57e4881b222484c26759ca865794187217c9dcea6c33adae6"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe07f8b9c3bb5c5ad1d2c66884253e03800f4189a60eb6acd6119ebaf3eb9894"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bfa48a4a2d45a41457f0840c48e579db157a927f4e97acf6e20df8fc521c79de"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2cf44d01bfe8ee605b7eaeecbc2b9ca64fc55765f17b304b40ed8995f69d7716"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e6bbca9246d9eedaa1c84e04a7f555493ba324d52ae4d9f3d9ddd1b740dcd87"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-win32.whl", hash = "sha256:567f88180f2c1423b4fe3f3ad6e6310fc97b85bdba574801548597287fc07028"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6b2cd7c29d6ecdf0b780deb587198f13213ac01c430ada6913452fd0c40190fc"}, - {file = "rapidfuzz-3.10.1-cp39-cp39-win_arm64.whl", hash = "sha256:9f912d459e46607ce276128f52bea21ebc3e9a5ccf4cccfef30dd5bddcf47be8"}, - {file = "rapidfuzz-3.10.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ac4452f182243cfab30ba4668ef2de101effaedc30f9faabb06a095a8c90fd16"}, - {file = "rapidfuzz-3.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:565c2bd4f7d23c32834652b27b51dd711814ab614b4e12add8476be4e20d1cf5"}, - {file = "rapidfuzz-3.10.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:187d9747149321607be4ccd6f9f366730078bed806178ec3eeb31d05545e9e8f"}, - {file = "rapidfuzz-3.10.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:616290fb9a8fa87e48cb0326d26f98d4e29f17c3b762c2d586f2b35c1fd2034b"}, - {file = "rapidfuzz-3.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:073a5b107e17ebd264198b78614c0206fa438cce749692af5bc5f8f484883f50"}, - {file = "rapidfuzz-3.10.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39c4983e2e2ccb9732f3ac7d81617088822f4a12291d416b09b8a1eadebb3e29"}, - {file = "rapidfuzz-3.10.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ac7adee6bcf0c6fee495d877edad1540a7e0f5fc208da03ccb64734b43522d7a"}, - {file = "rapidfuzz-3.10.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:425f4ac80b22153d391ee3f94bc854668a0c6c129f05cf2eaf5ee74474ddb69e"}, - {file = "rapidfuzz-3.10.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65a2fa13e8a219f9b5dcb9e74abe3ced5838a7327e629f426d333dfc8c5a6e66"}, - {file = "rapidfuzz-3.10.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75561f3df9a906aaa23787e9992b228b1ab69007932dc42070f747103e177ba8"}, - {file = "rapidfuzz-3.10.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:edd062490537e97ca125bc6c7f2b7331c2b73d21dc304615afe61ad1691e15d5"}, - {file = "rapidfuzz-3.10.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfcc8feccf63245a22dfdd16e222f1a39771a44b870beb748117a0e09cbb4a62"}, - {file = "rapidfuzz-3.10.1.tar.gz", hash = "sha256:5a15546d847a915b3f42dc79ef9b0c78b998b4e2c53b252e7166284066585979"}, -] - -[package.extras] -all = ["numpy"] - [[package]] name = "referencing" version = "0.35.1" @@ -2414,4 +2310,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "52709212b8f4850ae54ce801292d05b5e6750dfd109f69b30c55b4b917ab4bb3" +content-hash = "3aa36f11a7abd7bc966d64ceee9c192dccb4c033b83509a7bcbadb0427c3c041" diff --git a/Glimps/pyproject.toml b/Glimps/pyproject.toml index 70a908dba..1e1a783c1 100644 --- a/Glimps/pyproject.toml +++ b/Glimps/pyproject.toml @@ -6,9 +6,9 @@ authors = [] [tool.poetry.dependencies] python = ">=3.10,<3.12" -sekoia-automation-sdk = "^1.13.0" +sekoia-automation-sdk = "^1.17.0" tenacity = "*" -gdetect = "^0.7.0" +gdetect = "^0.8.0" [tool.poetry.dev-dependencies] pytest = "*" diff --git a/Glimps/tests/conftest.py b/Glimps/tests/conftest.py index eeb765d2e..558ed56d1 100644 --- a/Glimps/tests/conftest.py +++ b/Glimps/tests/conftest.py @@ -7,8 +7,8 @@ from sekoia_automation import constants from glimps.retrieve_analysis_action import RetrieveAnalysis from glimps.search_analysis_by_sha256_action import SearchPreviousAnalysis -from glimps.submit_file_to_be_analysed_action import SubmitFileWaitForResult -from glimps.models import GlimpsConfiguration +from glimps.submit_file_to_be_analysed_action import WaitForFile +from glimps.models import GLIMPSConfiguration @pytest.fixture(scope="session") @@ -30,7 +30,7 @@ def symphony_storage(): @pytest.fixture(scope="session") def set_up_retrieve_analysis_action(token): action = RetrieveAnalysis() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url="https://gmalware.ggp.glimps.re" ) return action @@ -39,7 +39,7 @@ def set_up_retrieve_analysis_action(token): @pytest.fixture(scope="session") def set_up_search_analysis_action(token): action = SearchPreviousAnalysis() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url="https://gmalware.ggp.glimps.re" ) return action @@ -47,14 +47,14 @@ def set_up_search_analysis_action(token): @pytest.fixture(scope="session") def set_up_wait_for_action(token, symphony_storage): - action = SubmitFileWaitForResult(data_path=symphony_storage) - action.module.configuration = GlimpsConfiguration( + action = WaitForFile(data_path=symphony_storage) + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url="https://gmalware.ggp.glimps.re" ) return action -@pytest.fixture(scope="session") +@pytest.fixture def analysis_result(): uuid = "1da0cb84-c5cc-4832-8882-4a7e9df11ed2" mock_analysis_result = { diff --git a/Glimps/tests/test_export.py b/Glimps/tests/test_export.py index b55681f7a..38e5efb09 100644 --- a/Glimps/tests/test_export.py +++ b/Glimps/tests/test_export.py @@ -1,48 +1,56 @@ import pytest from glimps.models import ( - GlimpsConfiguration, + GLIMPSConfiguration, ExportSubmissionArguments, ) from glimps.export_action import ExportSubmission from unittest.mock import patch from gdetect import GDetectError from pydantic.error_wrappers import ValidationError +import os +from glimps.submit_file_to_be_analysed_action import ( + WaitForFile, + WaitForResultArgument, + AnalysisResponse, +) test_base_url = "https://gmalware.ggp.glimps.re" # NB: GGP lite version doesn't yet allow to export result analysis -# @pytest.mark.skipif("'GLIMPS_API_KEY' not in os.environ.keys()") -# def test_integration_get_status(add_file_to_storage): -# symphony_storage, file, _sha256 = add_file_to_storage -# module_configuration = GlimpsConfiguration( -# api_key=os.environ["GLIMPS_API_KEY"], -# base_url=test_base_url, -# ) - -# prepare = SubmitFileToBeAnalysed(data_path=symphony_storage) -# prepare.module.configuration = module_configuration - -# arguments = SubmitArgument(file_name=file) -# response: SubmitResponse = prepare.run(arguments) -# assert response is not None -# assert response.get("status") is True -# assert response.get("uuid") != "" - -# action = ExportSubmission() -# action.module.configuration = module_configuration -# args = ExportSubmissionArguments( -# uuid=response.get("uuid"), format="csv", layout="en" -# ) - -# response: bytes = action.run(args) -# assert response is not None -# assert response.decode("utf-8") != "" +@pytest.mark.skipif( + "{'GLIMPS_API_KEY', 'GLIMPS_API_URL'}.issubset(os.environ.keys()) == False" +) +def test_integration_get_export(add_file_to_storage): + symphony_storage, file, _ = add_file_to_storage + module_configuration = GLIMPSConfiguration( + api_key=os.environ["GLIMPS_API_KEY"], + base_url=os.environ["GLIMPS_API_URL"], + ) + + prepare = WaitForFile(data_path=symphony_storage) + prepare.module.configuration = module_configuration + + arguments = WaitForResultArgument(file_name=file) + response: AnalysisResponse = prepare.run(arguments) + assert response is not None + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("uuid") != "" + + action = ExportSubmission() + action.module.configuration = module_configuration + args = ExportSubmissionArguments( + uuid=response.get("analysis").get("uuid"), format="csv", layout="en" + ) + + response: bytes = action.run(args) + assert response is not None + assert response.decode("utf-8") != "" def test_export_succeed(token): action = ExportSubmission() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url=test_base_url ) uuid = "1da0cb84-c5cc-4832-8882-4a7e9df11ed2" @@ -58,7 +66,7 @@ def test_export_succeed(token): def test_export_error(token): action = ExportSubmission() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url=test_base_url ) uuid = "1da0cb84-c5cc-4832-8882-4a7e9df11ed2" @@ -72,7 +80,7 @@ def test_export_error(token): def test_export_bad_format(token): action = ExportSubmission() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url=test_base_url ) uuid = "1da0cb84-c5cc-4832-8882-4a7e9df11ed2" @@ -82,7 +90,7 @@ def test_export_bad_format(token): def test_export_bad_layout(token): action = ExportSubmission() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url=test_base_url ) uuid = "1da0cb84-c5cc-4832-8882-4a7e9df11ed2" diff --git a/Glimps/tests/test_get_status.py b/Glimps/tests/test_get_status.py index 342ed2d2a..e37c29056 100644 --- a/Glimps/tests/test_get_status.py +++ b/Glimps/tests/test_get_status.py @@ -1,16 +1,18 @@ import pytest import os import json -from glimps.models import GlimpsConfiguration, ProfileStatus +from glimps.models import GLIMPSConfiguration, ProfileStatus from glimps.get_status_action import GetStatus from unittest.mock import patch import requests -@pytest.mark.skipif("'GLIMPS_API_KEY' not in os.environ.keys()") +@pytest.mark.skipif( + "{'GLIMPS_API_KEY', 'GLIMPS_API_URL'}.issubset(os.environ.keys()) == False" +) def test_integration_get_status(): action = GetStatus() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=os.environ["GLIMPS_API_KEY"], base_url="https://gmalware.ggp.glimps.re" ) @@ -21,7 +23,7 @@ def test_integration_get_status(): def test_get_status_error(token): action = GetStatus() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url="https://gmalware.ggp.glimps.re" ) @@ -40,7 +42,7 @@ def test_get_status_error(token): def test_get_status_ok(token): action = GetStatus() - action.module.configuration = GlimpsConfiguration( + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url="https://gmalware.ggp.glimps.re" ) diff --git a/Glimps/tests/test_retrieve_analysis.py b/Glimps/tests/test_retrieve_analysis.py index 436f7863e..611631fdf 100644 --- a/Glimps/tests/test_retrieve_analysis.py +++ b/Glimps/tests/test_retrieve_analysis.py @@ -3,25 +3,27 @@ from unittest.mock import patch from glimps.retrieve_analysis_action import RetrieveAnalysis -from glimps.submit_file_to_be_analysed_action import SubmitFileToBeAnalysed +from glimps.submit_file_to_be_analysed_action import SubmitFile from glimps.models import ( SubmitArgument, SubmitResponse, AnalysisResponse, - GlimpsConfiguration, + GLIMPSConfiguration, GetAnalysisByUUIDArgument, ) from gdetect import BadUUIDError -@pytest.mark.skipif("'GLIMPS_API_KEY' not in os.environ.keys()") +@pytest.mark.skipif( + "{'GLIMPS_API_KEY', 'GLIMPS_API_URL'}.issubset(os.environ.keys()) == False" +) def test_integration_retrieve_analysis(add_file_to_storage): symphony_storage, file, _ = add_file_to_storage - module_configuration = GlimpsConfiguration( + module_configuration = GLIMPSConfiguration( api_key=os.environ["GLIMPS_API_KEY"], - base_url="https://gmalware.ggp.glimps.re", + base_url=os.environ["GLIMPS_API_URL"], ) - prepare = SubmitFileToBeAnalysed(data_path=symphony_storage) + prepare = SubmitFile(data_path=symphony_storage) prepare.module.configuration = module_configuration arguments = SubmitArgument(file_name=file) @@ -37,7 +39,7 @@ def test_integration_retrieve_analysis(add_file_to_storage): response = action.run(arguments) assert response is not None - assert response.get("status") is True + assert response.get("analysis").get("status") is True def test_retrieve_analysis(set_up_retrieve_analysis_action, analysis_result): @@ -48,9 +50,24 @@ def test_retrieve_analysis(set_up_retrieve_analysis_action, analysis_result): mock.return_value = mock_analysis_result response: AnalysisResponse = action.run(arguments) - assert response.get("status") is True - assert response.get("uuid") == uuid - assert response.get("error") is None + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("uuid") == uuid + assert response.get("analysis").get("error") is None + + +def test_retrieve_analysis_view_token(set_up_retrieve_analysis_action, analysis_result): + action: RetrieveAnalysis = set_up_retrieve_analysis_action + uuid, mock_analysis_result = analysis_result + mock_analysis_result.update({"token": "sometoken"}) + arguments = GetAnalysisByUUIDArgument(uuid=uuid) + with patch("gdetect.api.Client.get_by_uuid") as mock: + mock.return_value = mock_analysis_result + response: AnalysisResponse = action.run(arguments) + + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("uuid") == uuid + assert response.get("analysis").get("error") is None + assert response.get("view_url") is not None and response.get("view_url") != "" def test_retrieve_analysis_error(set_up_retrieve_analysis_action): diff --git a/Glimps/tests/test_search_analysis_by_sha256.py b/Glimps/tests/test_search_analysis_by_sha256.py index 87206bfe0..24011ce32 100644 --- a/Glimps/tests/test_search_analysis_by_sha256.py +++ b/Glimps/tests/test_search_analysis_by_sha256.py @@ -3,24 +3,26 @@ from unittest.mock import patch from glimps.search_analysis_by_sha256_action import SearchPreviousAnalysis -from glimps.submit_file_to_be_analysed_action import SubmitFileToBeAnalysed +from glimps.submit_file_to_be_analysed_action import SubmitFile from glimps.models import ( SubmitArgument, SubmitResponse, AnalysisResponse, - GlimpsConfiguration, + GLIMPSConfiguration, SearchAnalysisBySha256Argument, ) from gdetect import BadSHA256Error -@pytest.mark.skipif("'GLIMPS_API_KEY' not in os.environ.keys()") +@pytest.mark.skipif( + "{'GLIMPS_API_KEY', 'GLIMPS_API_URL'}.issubset(os.environ.keys()) == False" +) def test_integration_search_analysis(add_file_to_storage): symphony_storage, file, sha256 = add_file_to_storage - module_configuration = GlimpsConfiguration( - api_key=os.environ["GLIMPS_API_KEY"], base_url="https://gmalware.ggp.glimps.re" + module_configuration = GLIMPSConfiguration( + api_key=os.environ["GLIMPS_API_KEY"], base_url=os.environ["GLIMPS_API_URL"] ) - prepare = SubmitFileToBeAnalysed(data_path=symphony_storage) + prepare = SubmitFile(data_path=symphony_storage) prepare.module.configuration = module_configuration arguments = SubmitArgument(file_name=file) @@ -37,8 +39,8 @@ def test_integration_search_analysis(add_file_to_storage): response: AnalysisResponse = action.run(arguments) assert response is not None - assert response.get("status") is True - assert response.get("uuid") == submit_response.get("uuid") + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("uuid") == submit_response.get("uuid") def test_search_analysis(set_up_search_analysis_action, analysis_result): @@ -52,8 +54,24 @@ def test_search_analysis(set_up_search_analysis_action, analysis_result): response: AnalysisResponse = action.run(arguments) assert response is not None - assert response.get("status") is True - assert response.get("uuid") == uuid + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("uuid") == uuid + + +def test_search_analysis_view_token(set_up_search_analysis_action, analysis_result): + action: SearchPreviousAnalysis = set_up_search_analysis_action + arguments = SearchAnalysisBySha256Argument( + sha256="131f95c51cc819465fa1797f6ccacf9d494aaaff46fa3eac73ae63ffbdfd8267" + ) + uuid, mock_analysis_result = analysis_result + mock_analysis_result.update({"token": "sometoken"}) + with patch("gdetect.api.Client.get_by_sha256") as mock: + mock.return_value = mock_analysis_result + response: AnalysisResponse = action.run(arguments) + + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("uuid") == uuid + assert response.get("view_url") is not None and response.get("view_url") != "" def test_search_analysis_error(set_up_search_analysis_action): diff --git a/Glimps/tests/test_submit_file_to_be_analysed.py b/Glimps/tests/test_submit_file_to_be_analysed.py index a6152368d..813878e1b 100644 --- a/Glimps/tests/test_submit_file_to_be_analysed.py +++ b/Glimps/tests/test_submit_file_to_be_analysed.py @@ -1,14 +1,14 @@ import os import pytest from glimps.submit_file_to_be_analysed_action import ( - SubmitFileToBeAnalysed, - SubmitFileWaitForResult, + SubmitFile, + WaitForFile, ) from glimps.models import ( SubmitArgument, SubmitResponse, - AnalysisResponse, - GlimpsConfiguration, + AnalysisDetails, + GLIMPSConfiguration, WaitForResultArgument, ) from gdetect import GDetectError @@ -17,12 +17,14 @@ test_base_url = "https://gmalware.ggp.glimps.re" -@pytest.mark.skipif("'GLIMPS_API_KEY' not in os.environ.keys()") -def test_submit_file_to_be_analysed(add_file_to_storage): +@pytest.mark.skipif( + "{'GLIMPS_API_KEY', 'GLIMPS_API_URL'}.issubset(os.environ.keys()) == False" +) +def test_integration_submit_file_to_be_analysed(add_file_to_storage): symphony_storage, file, _ = add_file_to_storage - action = SubmitFileToBeAnalysed(data_path=symphony_storage) - action.module.configuration = GlimpsConfiguration( - api_key=os.environ["GLIMPS_API_KEY"], base_url="https://gmalware.ggp.glimps.re" + action = SubmitFile(data_path=symphony_storage) + action.module.configuration = GLIMPSConfiguration( + api_key=os.environ["GLIMPS_API_KEY"], base_url=os.environ["GLIMPS_API_URL"] ) arguments = SubmitArgument(file_name=file) @@ -36,8 +38,8 @@ def test_submit_file_to_be_analysed(add_file_to_storage): def test_submit_file_to_be_analysed_succeed(add_file_to_storage, token): symphony_storage, file, _ = add_file_to_storage - action = SubmitFileToBeAnalysed(data_path=symphony_storage) - action.module.configuration = GlimpsConfiguration( + action = SubmitFile(data_path=symphony_storage) + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url=test_base_url ) @@ -54,8 +56,8 @@ def test_submit_file_to_be_analysed_succeed(add_file_to_storage, token): def test_submit_file_gdetect_error(add_file_to_storage, token): symphony_storage, file, _ = add_file_to_storage - action = SubmitFileToBeAnalysed(data_path=symphony_storage) - action.module.configuration = GlimpsConfiguration( + action = SubmitFile(data_path=symphony_storage) + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url=test_base_url ) @@ -69,8 +71,8 @@ def test_submit_file_gdetect_error(add_file_to_storage, token): def test_submit_file_error(add_file_to_storage, token): symphony_storage, file, _ = add_file_to_storage - action = SubmitFileToBeAnalysed(data_path=symphony_storage) - action.module.configuration = GlimpsConfiguration( + action = SubmitFile(data_path=symphony_storage) + action.module.configuration = GLIMPSConfiguration( api_key=token, base_url=test_base_url ) @@ -83,24 +85,24 @@ def test_submit_file_error(add_file_to_storage, token): @pytest.mark.skipif("'GLIMPS_API_KEY' not in os.environ.keys()") -def test_wait_for_analysis(add_file_to_storage): +def test_integration_wait_for_analysis(add_file_to_storage): symphony_storage, file, sha256 = add_file_to_storage - action = SubmitFileWaitForResult(data_path=symphony_storage) - action.module.configuration = GlimpsConfiguration( + action = WaitForFile(data_path=symphony_storage) + action.module.configuration = GLIMPSConfiguration( api_key=os.environ["GLIMPS_API_KEY"], base_url=test_base_url ) arguments = WaitForResultArgument(file_name=file) - response: AnalysisResponse = action.run(arguments) + response: AnalysisDetails = action.run(arguments) assert response is not None - assert response.get("status") is True - assert response.get("sha256") == sha256 + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("sha256") == sha256 def test_wait_for_succeed(add_file_to_storage, set_up_wait_for_action, analysis_result): _, file, _ = add_file_to_storage - action: SubmitFileWaitForResult = set_up_wait_for_action + action: WaitForFile = set_up_wait_for_action uuid, mock_analysis_result = analysis_result arguments = WaitForResultArgument(file_name=file) @@ -108,16 +110,38 @@ def test_wait_for_succeed(add_file_to_storage, set_up_wait_for_action, analysis_ mock_push.return_value = {"status": True, "uuid": uuid} with patch("gdetect.api.Client.get_by_uuid") as mock_pull: mock_pull.return_value = mock_analysis_result - response: AnalysisResponse = action.run(arguments) + response: AnalysisDetails = action.run(arguments) assert response is not None - assert response.get("status") is True - assert response.get("uuid") == uuid + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("uuid") == uuid + assert response.get("view_url") == "" + + +def test_wait_for_view_token( + add_file_to_storage, set_up_wait_for_action, analysis_result +): + _, file, _ = add_file_to_storage + action: WaitForFile = set_up_wait_for_action + + uuid, mock_analysis_result = analysis_result + mock_analysis_result.update({"token": "sometoken"}) + arguments = WaitForResultArgument(file_name=file) + with patch("gdetect.api.Client.push_reader") as mock_push: + mock_push.return_value = {"status": True, "uuid": uuid} + with patch("gdetect.api.Client.get_by_uuid") as mock_pull: + mock_pull.return_value = mock_analysis_result + response: AnalysisDetails = action.run(arguments) + + assert response.get("analysis").get("status") is True + assert response.get("analysis").get("uuid") == uuid + assert response.get("analysis").get("error") is None + assert response.get("view_url") is not None and response.get("view_url") != "" def test_wait_for_timeout(add_file_to_storage, set_up_wait_for_action, analysis_result): _, file, _ = add_file_to_storage - action: SubmitFileWaitForResult = set_up_wait_for_action + action: WaitForFile = set_up_wait_for_action uuid, mock_analysis_result = analysis_result # set very small timeout to trigger timeout exception arguments = WaitForResultArgument(file_name=file, timeout=0.1, pull_time=0.1) @@ -131,7 +155,7 @@ def test_wait_for_timeout(add_file_to_storage, set_up_wait_for_action, analysis_ def test_wait_for_exception(add_file_to_storage, set_up_wait_for_action): _, file, _ = add_file_to_storage - action: SubmitFileWaitForResult = set_up_wait_for_action + action: WaitForFile = set_up_wait_for_action # set very small timeout to trigger timeout exception arguments = WaitForResultArgument(file_name=file, timeout=1, pull_time=1)