From 52682cda5c1250b87491bce37b1291373dd54145 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Fri, 22 Nov 2024 17:23:59 +0100 Subject: [PATCH 01/15] feat: setup base configuration format --- .../presentation_submission/format_config.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 pyeudiw/openid4vp/presentation_submission/format_config.yml diff --git a/pyeudiw/openid4vp/presentation_submission/format_config.yml b/pyeudiw/openid4vp/presentation_submission/format_config.yml new file mode 100644 index 00000000..de4b2cf2 --- /dev/null +++ b/pyeudiw/openid4vp/presentation_submission/format_config.yml @@ -0,0 +1,13 @@ +formats: + - name: "vc+sd-jwt" + module: "pyeudiw.openid4vp.presentation_submission" + class: "VcSdJwt" + - name: "ldp_vp" + module: "pyeudiw.openid4vp.presentation_submission" + class: "LdpVp" + - name: "jwt_vp_json" + module: "pyeudiw.openid4vp.presentation_submission" + class: "JwtVpJson" + - name: "ac_vp" + module: "pyeudiw.openid4vp.presentation_submission" + class: "AcVp" From df312138a628a19d9506e95359255f0583b0a1d0 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Fri, 22 Nov 2024 17:24:28 +0100 Subject: [PATCH 02/15] feat: setup draft base class --- .../presentation_submission/__init__.py | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 pyeudiw/openid4vp/presentation_submission/__init__.py diff --git a/pyeudiw/openid4vp/presentation_submission/__init__.py b/pyeudiw/openid4vp/presentation_submission/__init__.py new file mode 100644 index 00000000..e5d3f7e7 --- /dev/null +++ b/pyeudiw/openid4vp/presentation_submission/__init__.py @@ -0,0 +1,87 @@ +import os +import yaml +import importlib +from typing import Dict, Any +import logging + +logger = logging.getLogger(__name__) + +class PresentationSubmission: + def __init__(self, submission: Dict[str, Any]): + """ + Initialize the PresentationSubmission handler with the submission data. + + Args: + submission (Dict[str, Any]): The presentation submission data. + + Raises: + KeyError: If the 'format' key is missing in the submission. + ValueError: If the format is not supported or not defined in the configuration. + ImportError: If the module or class cannot be loaded. + """ + self.config = self._load_config() + self.submission = submission + self.handlers = self._initialize_handlers() + + def _load_config(self) -> Dict[str, Any]: + """ + Load the configuration from format_config.yml located in the same directory. + + Returns: + Dict[str, Any]: The configuration dictionary. + + Raises: + FileNotFoundError: If the configuration file is not found. + """ + config_path = os.path.join(os.path.dirname(__file__), "format_config.yml") + if not os.path.exists(config_path): + raise FileNotFoundError(f"Configuration file not found: {config_path}") + + with open(config_path, "r") as config_file: + return yaml.safe_load(config_file) + + def _initialize_handlers(self) -> Dict[int, object]: + """ + Initialize handlers for each item in the 'descriptor_map' of the submission. + + Returns: + Dict[int, object]: A dictionary mapping indices to handler instances. + + Raises: + KeyError: If the 'format' key is missing in any descriptor. + ValueError: If a format is not supported or not defined in the configuration. + ImportError: If a module or class cannot be loaded. + """ + handlers = {} + + try: + descriptor_map = self.submission.get("descriptor_map", []) + except KeyError: + raise KeyError("The 'descriptor_map' key is missing in the submission.") + + for index, descriptor in enumerate(descriptor_map): + format_name = descriptor.get("format") + if not format_name: + raise KeyError(f"The 'format' key is missing in descriptor at index {index}.") + + # Search for the format in the configuration + format_conf = next((fmt for fmt in self.config.get("formats", []) if fmt["name"] == format_name), None) + if not format_conf: + raise ValueError(f"Format '{format_name}' is not supported or not defined in the configuration.") + + module_name = format_conf["module"] + class_name = format_conf["class"] + + try: + # Dynamically load the module and class + module = importlib.import_module(module_name) + cls = getattr(module, class_name) + handlers[index] = cls() # Instantiate the class + except ModuleNotFoundError: + logger.warning(f"Module '{module_name}' not found for format '{format_name}'. Skipping index {index}.") + except AttributeError: + logger.warning(f"Class '{class_name}' not found in module '{module_name}' for format '{format_name}'. Skipping index {index}.") + except Exception as e: + logger.warning(f"Error loading format '{format_name}' for index {index}: {e}") + + return handlers From 1eb207b8ca31148e4730f3e3a8b249161a82f2c3 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Fri, 22 Nov 2024 17:24:45 +0100 Subject: [PATCH 03/15] feat: tests added --- .../openid4vp/presentation_submission.py | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 pyeudiw/tests/openid4vp/presentation_submission.py diff --git a/pyeudiw/tests/openid4vp/presentation_submission.py b/pyeudiw/tests/openid4vp/presentation_submission.py new file mode 100644 index 00000000..f08244f1 --- /dev/null +++ b/pyeudiw/tests/openid4vp/presentation_submission.py @@ -0,0 +1,77 @@ +import pytest +from unittest.mock import patch, MagicMock +from pyeudiw.openid4vp.presentation_submission import PresentationSubmission + + +# Mock data for testing +mock_format_config = { + "formats": [ + {"name": "ldp_vp", "module": "mock.module", "class": "MockLdpVpHandler"}, + {"name": "jwt_vp_json", "module": "mock.module", "class": "MockJwtVpJsonHandler"} + ] +} + +valid_submission = { + "descriptor_map": [ + {"format": "ldp_vp", "id": "descriptor_1", "path": "$"}, + {"format": "jwt_vp_json", "id": "descriptor_2", "path": "$"} + ] +} + +def test_presentation_submission_initialization(): + """ + Test that the PresentationSubmission class initializes correctly, + loads handlers for all valid formats, and handles missing configurations. + """ + # Mock handler classes + mock_ldp_vp_handler = MagicMock(name="MockLdpVpHandler") + mock_jwt_vp_json_handler = MagicMock(name="MockJwtVpJsonHandler") + + # Mock import_module to return a fake module with our mock classes + mock_module = MagicMock() + setattr(mock_module, "MockLdpVpHandler", mock_ldp_vp_handler) + setattr(mock_module, "MockJwtVpJsonHandler", mock_jwt_vp_json_handler) + + with patch("pyeudiw.openid4vp.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config), \ + patch("importlib.import_module", return_value=mock_module): + + # Initialize the class + ps = PresentationSubmission(valid_submission) + + # Assert that handlers were created for all formats in descriptor_map + assert len(ps.handlers) == len(valid_submission["descriptor_map"]), "Not all handlers were created." + + # Check that the handlers are instances of the mocked classes + assert ps.handlers[0] is mock_ldp_vp_handler(), "Handler for 'ldp_vp' format is incorrect." + assert ps.handlers[1] is mock_jwt_vp_json_handler(), "Handler for 'jwt_vp_json' format is incorrect." + +def test_presentation_submission_invalid_format(): + """ + Test that the PresentationSubmission class handles unsupported formats gracefully. + """ + invalid_submission = { + "descriptor_map": [ + {"format": "unsupported_format", "id": "descriptor_3", "path": "$"} + ] + } + + with patch("pyeudiw.openid4vp.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + # Expect a ValueError for unsupported format + with pytest.raises(ValueError, match="Format 'unsupported_format' is not supported or not defined in the configuration."): + PresentationSubmission(invalid_submission) + +def test_presentation_submission_missing_format_key(): + """ + Test that the PresentationSubmission class raises KeyError + when the 'format' key is missing in a descriptor. + """ + missing_format_submission = { + "descriptor_map": [ + {"id": "descriptor_4", "path": "$"} + ] + } + + with patch("pyeudiw.openid4vp.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + # Expect a KeyError for missing 'format' + with pytest.raises(KeyError, match="The 'format' key is missing in descriptor at index 0."): + PresentationSubmission(missing_format_submission) From 35d23c8b11d06d4c9b8797bbac7efcb5779378c2 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter <114922565+LadyCodesItBetter@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:06:18 +0100 Subject: [PATCH 04/15] Update pyeudiw/openid4vp/presentation_submission/format_config.yml Co-authored-by: Giuseppe De Marco --- pyeudiw/openid4vp/presentation_submission/format_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyeudiw/openid4vp/presentation_submission/format_config.yml b/pyeudiw/openid4vp/presentation_submission/format_config.yml index de4b2cf2..0091f2ee 100644 --- a/pyeudiw/openid4vp/presentation_submission/format_config.yml +++ b/pyeudiw/openid4vp/presentation_submission/format_config.yml @@ -1,5 +1,5 @@ formats: - - name: "vc+sd-jwt" + - name: "dc+sd-jwt" module: "pyeudiw.openid4vp.presentation_submission" class: "VcSdJwt" - name: "ldp_vp" From 68a81d568f42012644d84910be1ff7e503ff9f34 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Mon, 25 Nov 2024 11:10:03 +0100 Subject: [PATCH 05/15] fix: out of init file --- .../presentation_submission/__init__.py | 87 ------------------- .../presentation_submission.py | 87 +++++++++++++++++++ .../openid4vp/presentation_submission.py | 10 ++- 3 files changed, 93 insertions(+), 91 deletions(-) create mode 100644 pyeudiw/openid4vp/presentation_submission/presentation_submission.py diff --git a/pyeudiw/openid4vp/presentation_submission/__init__.py b/pyeudiw/openid4vp/presentation_submission/__init__.py index e5d3f7e7..e69de29b 100644 --- a/pyeudiw/openid4vp/presentation_submission/__init__.py +++ b/pyeudiw/openid4vp/presentation_submission/__init__.py @@ -1,87 +0,0 @@ -import os -import yaml -import importlib -from typing import Dict, Any -import logging - -logger = logging.getLogger(__name__) - -class PresentationSubmission: - def __init__(self, submission: Dict[str, Any]): - """ - Initialize the PresentationSubmission handler with the submission data. - - Args: - submission (Dict[str, Any]): The presentation submission data. - - Raises: - KeyError: If the 'format' key is missing in the submission. - ValueError: If the format is not supported or not defined in the configuration. - ImportError: If the module or class cannot be loaded. - """ - self.config = self._load_config() - self.submission = submission - self.handlers = self._initialize_handlers() - - def _load_config(self) -> Dict[str, Any]: - """ - Load the configuration from format_config.yml located in the same directory. - - Returns: - Dict[str, Any]: The configuration dictionary. - - Raises: - FileNotFoundError: If the configuration file is not found. - """ - config_path = os.path.join(os.path.dirname(__file__), "format_config.yml") - if not os.path.exists(config_path): - raise FileNotFoundError(f"Configuration file not found: {config_path}") - - with open(config_path, "r") as config_file: - return yaml.safe_load(config_file) - - def _initialize_handlers(self) -> Dict[int, object]: - """ - Initialize handlers for each item in the 'descriptor_map' of the submission. - - Returns: - Dict[int, object]: A dictionary mapping indices to handler instances. - - Raises: - KeyError: If the 'format' key is missing in any descriptor. - ValueError: If a format is not supported or not defined in the configuration. - ImportError: If a module or class cannot be loaded. - """ - handlers = {} - - try: - descriptor_map = self.submission.get("descriptor_map", []) - except KeyError: - raise KeyError("The 'descriptor_map' key is missing in the submission.") - - for index, descriptor in enumerate(descriptor_map): - format_name = descriptor.get("format") - if not format_name: - raise KeyError(f"The 'format' key is missing in descriptor at index {index}.") - - # Search for the format in the configuration - format_conf = next((fmt for fmt in self.config.get("formats", []) if fmt["name"] == format_name), None) - if not format_conf: - raise ValueError(f"Format '{format_name}' is not supported or not defined in the configuration.") - - module_name = format_conf["module"] - class_name = format_conf["class"] - - try: - # Dynamically load the module and class - module = importlib.import_module(module_name) - cls = getattr(module, class_name) - handlers[index] = cls() # Instantiate the class - except ModuleNotFoundError: - logger.warning(f"Module '{module_name}' not found for format '{format_name}'. Skipping index {index}.") - except AttributeError: - logger.warning(f"Class '{class_name}' not found in module '{module_name}' for format '{format_name}'. Skipping index {index}.") - except Exception as e: - logger.warning(f"Error loading format '{format_name}' for index {index}: {e}") - - return handlers diff --git a/pyeudiw/openid4vp/presentation_submission/presentation_submission.py b/pyeudiw/openid4vp/presentation_submission/presentation_submission.py new file mode 100644 index 00000000..e5d3f7e7 --- /dev/null +++ b/pyeudiw/openid4vp/presentation_submission/presentation_submission.py @@ -0,0 +1,87 @@ +import os +import yaml +import importlib +from typing import Dict, Any +import logging + +logger = logging.getLogger(__name__) + +class PresentationSubmission: + def __init__(self, submission: Dict[str, Any]): + """ + Initialize the PresentationSubmission handler with the submission data. + + Args: + submission (Dict[str, Any]): The presentation submission data. + + Raises: + KeyError: If the 'format' key is missing in the submission. + ValueError: If the format is not supported or not defined in the configuration. + ImportError: If the module or class cannot be loaded. + """ + self.config = self._load_config() + self.submission = submission + self.handlers = self._initialize_handlers() + + def _load_config(self) -> Dict[str, Any]: + """ + Load the configuration from format_config.yml located in the same directory. + + Returns: + Dict[str, Any]: The configuration dictionary. + + Raises: + FileNotFoundError: If the configuration file is not found. + """ + config_path = os.path.join(os.path.dirname(__file__), "format_config.yml") + if not os.path.exists(config_path): + raise FileNotFoundError(f"Configuration file not found: {config_path}") + + with open(config_path, "r") as config_file: + return yaml.safe_load(config_file) + + def _initialize_handlers(self) -> Dict[int, object]: + """ + Initialize handlers for each item in the 'descriptor_map' of the submission. + + Returns: + Dict[int, object]: A dictionary mapping indices to handler instances. + + Raises: + KeyError: If the 'format' key is missing in any descriptor. + ValueError: If a format is not supported or not defined in the configuration. + ImportError: If a module or class cannot be loaded. + """ + handlers = {} + + try: + descriptor_map = self.submission.get("descriptor_map", []) + except KeyError: + raise KeyError("The 'descriptor_map' key is missing in the submission.") + + for index, descriptor in enumerate(descriptor_map): + format_name = descriptor.get("format") + if not format_name: + raise KeyError(f"The 'format' key is missing in descriptor at index {index}.") + + # Search for the format in the configuration + format_conf = next((fmt for fmt in self.config.get("formats", []) if fmt["name"] == format_name), None) + if not format_conf: + raise ValueError(f"Format '{format_name}' is not supported or not defined in the configuration.") + + module_name = format_conf["module"] + class_name = format_conf["class"] + + try: + # Dynamically load the module and class + module = importlib.import_module(module_name) + cls = getattr(module, class_name) + handlers[index] = cls() # Instantiate the class + except ModuleNotFoundError: + logger.warning(f"Module '{module_name}' not found for format '{format_name}'. Skipping index {index}.") + except AttributeError: + logger.warning(f"Class '{class_name}' not found in module '{module_name}' for format '{format_name}'. Skipping index {index}.") + except Exception as e: + logger.warning(f"Error loading format '{format_name}' for index {index}: {e}") + + return handlers diff --git a/pyeudiw/tests/openid4vp/presentation_submission.py b/pyeudiw/tests/openid4vp/presentation_submission.py index f08244f1..1ac8aad0 100644 --- a/pyeudiw/tests/openid4vp/presentation_submission.py +++ b/pyeudiw/tests/openid4vp/presentation_submission.py @@ -1,6 +1,8 @@ import pytest from unittest.mock import patch, MagicMock -from pyeudiw.openid4vp.presentation_submission import PresentationSubmission + +from pyeudiw.openid4vp.presentation_submission.presentation_submission import PresentationSubmission + # Mock data for testing @@ -32,7 +34,7 @@ def test_presentation_submission_initialization(): setattr(mock_module, "MockLdpVpHandler", mock_ldp_vp_handler) setattr(mock_module, "MockJwtVpJsonHandler", mock_jwt_vp_json_handler) - with patch("pyeudiw.openid4vp.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config), \ + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config), \ patch("importlib.import_module", return_value=mock_module): # Initialize the class @@ -55,7 +57,7 @@ def test_presentation_submission_invalid_format(): ] } - with patch("pyeudiw.openid4vp.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): # Expect a ValueError for unsupported format with pytest.raises(ValueError, match="Format 'unsupported_format' is not supported or not defined in the configuration."): PresentationSubmission(invalid_submission) @@ -71,7 +73,7 @@ def test_presentation_submission_missing_format_key(): ] } - with patch("pyeudiw.openid4vp.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): # Expect a KeyError for missing 'format' with pytest.raises(KeyError, match="The 'format' key is missing in descriptor at index 0."): PresentationSubmission(missing_format_submission) From 6ae5b6ce618eb70f1ceacd14edb9eb741757de6a Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Tue, 26 Nov 2024 11:55:29 +0100 Subject: [PATCH 06/15] feat: add pydantic schema for presentation submission --- .../openid4vp/presentation_submission/schemas.py | 13 +++++++++++++ pyeudiw/openid4vp/schemas/response.py | 14 +------------- 2 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 pyeudiw/openid4vp/presentation_submission/schemas.py diff --git a/pyeudiw/openid4vp/presentation_submission/schemas.py b/pyeudiw/openid4vp/presentation_submission/schemas.py new file mode 100644 index 00000000..f1b9d671 --- /dev/null +++ b/pyeudiw/openid4vp/presentation_submission/schemas.py @@ -0,0 +1,13 @@ +from pydantic import BaseModel + + +class DescriptorSchema(BaseModel): + id: str + path: str + format: str + + +class PresentationSubmissionSchema(BaseModel): + definition_id: str + id: str + descriptor_map: list[DescriptorSchema] \ No newline at end of file diff --git a/pyeudiw/openid4vp/schemas/response.py b/pyeudiw/openid4vp/schemas/response.py index 5124b2d9..d7f6d986 100644 --- a/pyeudiw/openid4vp/schemas/response.py +++ b/pyeudiw/openid4vp/schemas/response.py @@ -3,19 +3,7 @@ from pydantic import BaseModel, field_validator from pyeudiw.jwt.utils import is_jwt_format - - -class DescriptorSchema(BaseModel): - id: str - path: str - format: str - - -class PresentationSubmissionSchema(BaseModel): - definition_id: str - id: str - descriptor_map: list[DescriptorSchema] - +from pyeudiw.openid4vp.presentation_submission.schemas import PresentationSubmissionSchema class ResponseSchema(BaseModel): state: Optional[str] From 6b4a1f971f3e2a37e78cc1cbb545785259aca0c1 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Tue, 26 Nov 2024 12:35:03 +0100 Subject: [PATCH 07/15] feat: add validation function and enforce byte size and numeric limit for descriptor_map --- .../{format_config.yml => config.yml} | 2 + .../presentation_submission.py | 42 +++++++++- .../presentation_submission/schemas.py | 18 ++++- .../openid4vp/presentation_submission.py | 76 ++++++++++++++----- 4 files changed, 113 insertions(+), 25 deletions(-) rename pyeudiw/openid4vp/presentation_submission/{format_config.yml => config.yml} (91%) diff --git a/pyeudiw/openid4vp/presentation_submission/format_config.yml b/pyeudiw/openid4vp/presentation_submission/config.yml similarity index 91% rename from pyeudiw/openid4vp/presentation_submission/format_config.yml rename to pyeudiw/openid4vp/presentation_submission/config.yml index 0091f2ee..47065dd9 100644 --- a/pyeudiw/openid4vp/presentation_submission/format_config.yml +++ b/pyeudiw/openid4vp/presentation_submission/config.yml @@ -11,3 +11,5 @@ formats: - name: "ac_vp" module: "pyeudiw.openid4vp.presentation_submission" class: "AcVp" + +MAX_SUBMISSION_SIZE: 10 * 1024 * 1024 diff --git a/pyeudiw/openid4vp/presentation_submission/presentation_submission.py b/pyeudiw/openid4vp/presentation_submission/presentation_submission.py index e5d3f7e7..9943561a 100644 --- a/pyeudiw/openid4vp/presentation_submission/presentation_submission.py +++ b/pyeudiw/openid4vp/presentation_submission/presentation_submission.py @@ -1,9 +1,12 @@ import os +from pydantic import ValidationError import yaml import importlib from typing import Dict, Any import logging +from pyeudiw.openid4vp.presentation_submission.schemas import PresentationSubmissionSchema + logger = logging.getLogger(__name__) class PresentationSubmission: @@ -18,9 +21,10 @@ def __init__(self, submission: Dict[str, Any]): KeyError: If the 'format' key is missing in the submission. ValueError: If the format is not supported or not defined in the configuration. ImportError: If the module or class cannot be loaded. + ValidationError: If the submission data is invalid or exceeds size limits. """ self.config = self._load_config() - self.submission = submission + self.submission = self._validate_submission(submission) self.handlers = self._initialize_handlers() def _load_config(self) -> Dict[str, Any]: @@ -33,13 +37,43 @@ def _load_config(self) -> Dict[str, Any]: Raises: FileNotFoundError: If the configuration file is not found. """ - config_path = os.path.join(os.path.dirname(__file__), "format_config.yml") + config_path = os.path.join(os.path.dirname(__file__), "config.yml") if not os.path.exists(config_path): raise FileNotFoundError(f"Configuration file not found: {config_path}") with open(config_path, "r") as config_file: return yaml.safe_load(config_file) + + def _validate_submission(self, submission: Dict[str, Any]) -> PresentationSubmissionSchema: + """ + Validate the submission data using Pydantic and check its total size. + + Args: + submission (Dict[str, Any]): The presentation submission data. + Returns: + PresentationSubmissionSchema: Validated submission schema. + + Raises: + ValidationError: If the submission data is invalid or exceeds size limits. + """ + max_size = self.config.get("MAX_SUBMISSION_SIZE", 10 * 1024 * 1024) + + # Check submission size + submission_size = len(str(submission).encode("utf-8")) + if submission_size > max_size: + logger.warning( + f"Rejected submission: size {submission_size} bytes exceeds limit {max_size} bytes." + ) + raise ValueError( + f"Submission size exceeds maximum allowed limit of {max_size} bytes." + ) + + try: + return PresentationSubmissionSchema(**submission) + except ValidationError as e: + logger.error(f"Submission validation failed: {e}") + raise def _initialize_handlers(self) -> Dict[int, object]: """ Initialize handlers for each item in the 'descriptor_map' of the submission. @@ -55,12 +89,12 @@ def _initialize_handlers(self) -> Dict[int, object]: handlers = {} try: - descriptor_map = self.submission.get("descriptor_map", []) + descriptor_map = self.submission.descriptor_map except KeyError: raise KeyError("The 'descriptor_map' key is missing in the submission.") for index, descriptor in enumerate(descriptor_map): - format_name = descriptor.get("format") + format_name = descriptor.format if not format_name: raise KeyError(f"The 'format' key is missing in descriptor at index {index}.") diff --git a/pyeudiw/openid4vp/presentation_submission/schemas.py b/pyeudiw/openid4vp/presentation_submission/schemas.py index f1b9d671..4c6bbb4b 100644 --- a/pyeudiw/openid4vp/presentation_submission/schemas.py +++ b/pyeudiw/openid4vp/presentation_submission/schemas.py @@ -1,13 +1,23 @@ -from pydantic import BaseModel +from typing import Any, Dict, List +from pydantic import BaseModel, field_validator class DescriptorSchema(BaseModel): id: str - path: str format: str + path: str + path_nested: Dict[str, Any] = None class PresentationSubmissionSchema(BaseModel): - definition_id: str id: str - descriptor_map: list[DescriptorSchema] \ No newline at end of file + definition_id: str + descriptor_map: List[DescriptorSchema] + + @field_validator("descriptor_map") + @classmethod + def check_descriptor_map_size(cls, value): + max_descriptors = 100 # TODO: Define a reasonable limit + if len(value) > max_descriptors: + raise ValueError(f"descriptor_map exceeds maximum allowed size of {max_descriptors} items.") + return value \ No newline at end of file diff --git a/pyeudiw/tests/openid4vp/presentation_submission.py b/pyeudiw/tests/openid4vp/presentation_submission.py index 1ac8aad0..3549e753 100644 --- a/pyeudiw/tests/openid4vp/presentation_submission.py +++ b/pyeudiw/tests/openid4vp/presentation_submission.py @@ -1,29 +1,38 @@ import pytest from unittest.mock import patch, MagicMock - +from pydantic import ValidationError from pyeudiw.openid4vp.presentation_submission.presentation_submission import PresentationSubmission - # Mock data for testing mock_format_config = { "formats": [ {"name": "ldp_vp", "module": "mock.module", "class": "MockLdpVpHandler"}, {"name": "jwt_vp_json", "module": "mock.module", "class": "MockJwtVpJsonHandler"} - ] + ], + "MAX_SUBMISSION_SIZE": 10 * 1024 # 10 KB } valid_submission = { + "id": "submission_id", + "definition_id": "definition_id", "descriptor_map": [ - {"format": "ldp_vp", "id": "descriptor_1", "path": "$"}, - {"format": "jwt_vp_json", "id": "descriptor_2", "path": "$"} + {"id": "descriptor_1", "format": "ldp_vp", "path": "$"}, + {"id": "descriptor_2", "format": "jwt_vp_json", "path": "$"} ] } -def test_presentation_submission_initialization(): +large_submission = { + "id": "submission_id_large", + "definition_id": "definition_id_large", + "descriptor_map": [{"id": f"descriptor_{i}", "format": "ldp_vp", "path": "$"} for i in range(101)] # Exceeds limit +} + + +def test_presentation_submission_initialization_with_schema_validation(): """ - Test that the PresentationSubmission class initializes correctly, - loads handlers for all valid formats, and handles missing configurations. + Test that the PresentationSubmission class initializes correctly + and validates against the Pydantic schema. """ # Mock handler classes mock_ldp_vp_handler = MagicMock(name="MockLdpVpHandler") @@ -47,33 +56,66 @@ def test_presentation_submission_initialization(): assert ps.handlers[0] is mock_ldp_vp_handler(), "Handler for 'ldp_vp' format is incorrect." assert ps.handlers[1] is mock_jwt_vp_json_handler(), "Handler for 'jwt_vp_json' format is incorrect." + +def test_presentation_submission_large_submission_with_schema(): + """ + Test that the PresentationSubmission class raises a ValidationError + when the submission exceeds the descriptor_map size limit. + """ + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + # Expect a ValidationError for exceeding descriptor_map size limit + with pytest.raises(ValidationError, match="descriptor_map exceeds maximum allowed size of 100 items"): + PresentationSubmission(large_submission) + + +def test_presentation_submission_missing_descriptor_key(): + """ + Test that the PresentationSubmission class raises a ValidationError + when required keys are missing in the descriptor_map. + """ + invalid_submission = { + "id": "invalid_submission_id", + "definition_id": "invalid_definition_id", + "descriptor_map": [ + {"format": "ldp_vp"} + ] + } + + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + + with pytest.raises(ValidationError, match=r"Field required"): + PresentationSubmission(invalid_submission) + def test_presentation_submission_invalid_format(): """ - Test that the PresentationSubmission class handles unsupported formats gracefully. + Test that the PresentationSubmission class raises a ValueError + when an unsupported format is encountered. """ invalid_submission = { + "id": "invalid_submission_id", + "definition_id": "invalid_definition_id", "descriptor_map": [ - {"format": "unsupported_format", "id": "descriptor_3", "path": "$"} + {"format": "unsupported_format", "id": "descriptor_1", "path": "$"} ] } with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): - # Expect a ValueError for unsupported format with pytest.raises(ValueError, match="Format 'unsupported_format' is not supported or not defined in the configuration."): PresentationSubmission(invalid_submission) def test_presentation_submission_missing_format_key(): """ - Test that the PresentationSubmission class raises KeyError + Test that the PresentationSubmission class raises a KeyError when the 'format' key is missing in a descriptor. """ - missing_format_submission = { + missing_format_key_submission = { + "id": "missing_format_submission_id", + "definition_id": "missing_format_definition_id", "descriptor_map": [ - {"id": "descriptor_4", "path": "$"} + {"id": "descriptor_1", "path": "$"} # Missing 'format' key ] } with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): - # Expect a KeyError for missing 'format' - with pytest.raises(KeyError, match="The 'format' key is missing in descriptor at index 0."): - PresentationSubmission(missing_format_submission) + with pytest.raises(ValidationError, match=r"descriptor_map\.0\.format\s+Field required"): + PresentationSubmission(missing_format_key_submission) From 72fe6946a072813824135f638943d7347d29864f Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter <114922565+LadyCodesItBetter@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:36:31 +0100 Subject: [PATCH 08/15] Update pyeudiw/openid4vp/presentation_submission/config.yml --- pyeudiw/openid4vp/presentation_submission/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyeudiw/openid4vp/presentation_submission/config.yml b/pyeudiw/openid4vp/presentation_submission/config.yml index 47065dd9..04286a43 100644 --- a/pyeudiw/openid4vp/presentation_submission/config.yml +++ b/pyeudiw/openid4vp/presentation_submission/config.yml @@ -12,4 +12,4 @@ formats: module: "pyeudiw.openid4vp.presentation_submission" class: "AcVp" -MAX_SUBMISSION_SIZE: 10 * 1024 * 1024 +MAX_SUBMISSION_SIZE: 4096 * 100 From 6c6a456d2178edac513c57a006d5f7e3a5ae0228 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter <114922565+LadyCodesItBetter@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:37:57 +0100 Subject: [PATCH 09/15] Update pyeudiw/openid4vp/presentation_submission/config.yml --- pyeudiw/openid4vp/presentation_submission/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyeudiw/openid4vp/presentation_submission/config.yml b/pyeudiw/openid4vp/presentation_submission/config.yml index 04286a43..8495cc79 100644 --- a/pyeudiw/openid4vp/presentation_submission/config.yml +++ b/pyeudiw/openid4vp/presentation_submission/config.yml @@ -12,4 +12,4 @@ formats: module: "pyeudiw.openid4vp.presentation_submission" class: "AcVp" -MAX_SUBMISSION_SIZE: 4096 * 100 +MAX_SUBMISSION_SIZE: 4096 From 345006e038f4ef7b4d3b516f37daf9453cad6210 Mon Sep 17 00:00:00 2001 From: Giuseppe De Marco Date: Tue, 26 Nov 2024 14:39:32 +0100 Subject: [PATCH 10/15] Apply suggestions from code review --- .../openid4vp/presentation_submission/presentation_submission.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyeudiw/openid4vp/presentation_submission/presentation_submission.py b/pyeudiw/openid4vp/presentation_submission/presentation_submission.py index 9943561a..95830393 100644 --- a/pyeudiw/openid4vp/presentation_submission/presentation_submission.py +++ b/pyeudiw/openid4vp/presentation_submission/presentation_submission.py @@ -74,6 +74,7 @@ def _validate_submission(self, submission: Dict[str, Any]) -> PresentationSubmis except ValidationError as e: logger.error(f"Submission validation failed: {e}") raise + def _initialize_handlers(self) -> Dict[int, object]: """ Initialize handlers for each item in the 'descriptor_map' of the submission. From 110e6aeabf1c72ea29fe59e48af48db12bc0dfdc Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Thu, 23 Jan 2025 12:18:33 +0100 Subject: [PATCH 11/15] fix: deprecated import type and rename file for test tool recognizing --- .../openid4vp/presentation_submission.py | 121 ------------------ 1 file changed, 121 deletions(-) delete mode 100644 pyeudiw/tests/openid4vp/presentation_submission.py diff --git a/pyeudiw/tests/openid4vp/presentation_submission.py b/pyeudiw/tests/openid4vp/presentation_submission.py deleted file mode 100644 index 3549e753..00000000 --- a/pyeudiw/tests/openid4vp/presentation_submission.py +++ /dev/null @@ -1,121 +0,0 @@ -import pytest -from unittest.mock import patch, MagicMock -from pydantic import ValidationError -from pyeudiw.openid4vp.presentation_submission.presentation_submission import PresentationSubmission - - -# Mock data for testing -mock_format_config = { - "formats": [ - {"name": "ldp_vp", "module": "mock.module", "class": "MockLdpVpHandler"}, - {"name": "jwt_vp_json", "module": "mock.module", "class": "MockJwtVpJsonHandler"} - ], - "MAX_SUBMISSION_SIZE": 10 * 1024 # 10 KB -} - -valid_submission = { - "id": "submission_id", - "definition_id": "definition_id", - "descriptor_map": [ - {"id": "descriptor_1", "format": "ldp_vp", "path": "$"}, - {"id": "descriptor_2", "format": "jwt_vp_json", "path": "$"} - ] -} - -large_submission = { - "id": "submission_id_large", - "definition_id": "definition_id_large", - "descriptor_map": [{"id": f"descriptor_{i}", "format": "ldp_vp", "path": "$"} for i in range(101)] # Exceeds limit -} - - -def test_presentation_submission_initialization_with_schema_validation(): - """ - Test that the PresentationSubmission class initializes correctly - and validates against the Pydantic schema. - """ - # Mock handler classes - mock_ldp_vp_handler = MagicMock(name="MockLdpVpHandler") - mock_jwt_vp_json_handler = MagicMock(name="MockJwtVpJsonHandler") - - # Mock import_module to return a fake module with our mock classes - mock_module = MagicMock() - setattr(mock_module, "MockLdpVpHandler", mock_ldp_vp_handler) - setattr(mock_module, "MockJwtVpJsonHandler", mock_jwt_vp_json_handler) - - with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config), \ - patch("importlib.import_module", return_value=mock_module): - - # Initialize the class - ps = PresentationSubmission(valid_submission) - - # Assert that handlers were created for all formats in descriptor_map - assert len(ps.handlers) == len(valid_submission["descriptor_map"]), "Not all handlers were created." - - # Check that the handlers are instances of the mocked classes - assert ps.handlers[0] is mock_ldp_vp_handler(), "Handler for 'ldp_vp' format is incorrect." - assert ps.handlers[1] is mock_jwt_vp_json_handler(), "Handler for 'jwt_vp_json' format is incorrect." - - -def test_presentation_submission_large_submission_with_schema(): - """ - Test that the PresentationSubmission class raises a ValidationError - when the submission exceeds the descriptor_map size limit. - """ - with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): - # Expect a ValidationError for exceeding descriptor_map size limit - with pytest.raises(ValidationError, match="descriptor_map exceeds maximum allowed size of 100 items"): - PresentationSubmission(large_submission) - - -def test_presentation_submission_missing_descriptor_key(): - """ - Test that the PresentationSubmission class raises a ValidationError - when required keys are missing in the descriptor_map. - """ - invalid_submission = { - "id": "invalid_submission_id", - "definition_id": "invalid_definition_id", - "descriptor_map": [ - {"format": "ldp_vp"} - ] - } - - with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): - - with pytest.raises(ValidationError, match=r"Field required"): - PresentationSubmission(invalid_submission) - -def test_presentation_submission_invalid_format(): - """ - Test that the PresentationSubmission class raises a ValueError - when an unsupported format is encountered. - """ - invalid_submission = { - "id": "invalid_submission_id", - "definition_id": "invalid_definition_id", - "descriptor_map": [ - {"format": "unsupported_format", "id": "descriptor_1", "path": "$"} - ] - } - - with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): - with pytest.raises(ValueError, match="Format 'unsupported_format' is not supported or not defined in the configuration."): - PresentationSubmission(invalid_submission) - -def test_presentation_submission_missing_format_key(): - """ - Test that the PresentationSubmission class raises a KeyError - when the 'format' key is missing in a descriptor. - """ - missing_format_key_submission = { - "id": "missing_format_submission_id", - "definition_id": "missing_format_definition_id", - "descriptor_map": [ - {"id": "descriptor_1", "path": "$"} # Missing 'format' key - ] - } - - with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): - with pytest.raises(ValidationError, match=r"descriptor_map\.0\.format\s+Field required"): - PresentationSubmission(missing_format_key_submission) From ef7d34cae8485ba210caace3b769cce47e2c8eb8 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Thu, 23 Jan 2025 12:20:01 +0100 Subject: [PATCH 12/15] fix: deprecated import type and rename file for test tool recognizing --- .vscode/settings.json | 19 +++ .../presentation_submission.py | 18 +-- .../presentation_submission/schemas.py | 6 +- .../openid4vp/test_presentation_submission.py | 121 ++++++++++++++++++ 4 files changed, 152 insertions(+), 12 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 pyeudiw/tests/openid4vp/test_presentation_submission.py diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..cb2e43fd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "[python]": { + "editor.defaultFormatter": "ms-python.python" + }, + "python.formatting.provider": "none", + "yaml.customTags": [ + "!sd scalar", + "!sd mapping", + "!sd sequence" + ], + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, + "terminal.integrated.fontSize": 12, + "window.zoomLevel":0, + "editor.fontSize": 14 +} \ No newline at end of file diff --git a/pyeudiw/openid4vp/presentation_submission/presentation_submission.py b/pyeudiw/openid4vp/presentation_submission/presentation_submission.py index 95830393..6a054ff6 100644 --- a/pyeudiw/openid4vp/presentation_submission/presentation_submission.py +++ b/pyeudiw/openid4vp/presentation_submission/presentation_submission.py @@ -2,7 +2,7 @@ from pydantic import ValidationError import yaml import importlib -from typing import Dict, Any +from typing import Any import logging from pyeudiw.openid4vp.presentation_submission.schemas import PresentationSubmissionSchema @@ -10,12 +10,12 @@ logger = logging.getLogger(__name__) class PresentationSubmission: - def __init__(self, submission: Dict[str, Any]): + def __init__(self, submission: dict[str, Any]): """ Initialize the PresentationSubmission handler with the submission data. Args: - submission (Dict[str, Any]): The presentation submission data. + submission (dict[str, Any]): The presentation submission data. Raises: KeyError: If the 'format' key is missing in the submission. @@ -27,12 +27,12 @@ def __init__(self, submission: Dict[str, Any]): self.submission = self._validate_submission(submission) self.handlers = self._initialize_handlers() - def _load_config(self) -> Dict[str, Any]: + def _load_config(self) -> dict[str, Any]: """ Load the configuration from format_config.yml located in the same directory. Returns: - Dict[str, Any]: The configuration dictionary. + dict[str, Any]: The configuration dictionary. Raises: FileNotFoundError: If the configuration file is not found. @@ -44,12 +44,12 @@ def _load_config(self) -> Dict[str, Any]: with open(config_path, "r") as config_file: return yaml.safe_load(config_file) - def _validate_submission(self, submission: Dict[str, Any]) -> PresentationSubmissionSchema: + def _validate_submission(self, submission: dict[str, Any]) -> PresentationSubmissionSchema: """ Validate the submission data using Pydantic and check its total size. Args: - submission (Dict[str, Any]): The presentation submission data. + submission (dict[str, Any]): The presentation submission data. Returns: PresentationSubmissionSchema: Validated submission schema. @@ -75,12 +75,12 @@ def _validate_submission(self, submission: Dict[str, Any]) -> PresentationSubmis logger.error(f"Submission validation failed: {e}") raise - def _initialize_handlers(self) -> Dict[int, object]: + def _initialize_handlers(self) -> dict[int, object]: """ Initialize handlers for each item in the 'descriptor_map' of the submission. Returns: - Dict[int, object]: A dictionary mapping indices to handler instances. + dict[int, object]: A dictionary mapping indices to handler instances. Raises: KeyError: If the 'format' key is missing in any descriptor. diff --git a/pyeudiw/openid4vp/presentation_submission/schemas.py b/pyeudiw/openid4vp/presentation_submission/schemas.py index 4c6bbb4b..41565d52 100644 --- a/pyeudiw/openid4vp/presentation_submission/schemas.py +++ b/pyeudiw/openid4vp/presentation_submission/schemas.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List +from typing import Any from pydantic import BaseModel, field_validator @@ -6,13 +6,13 @@ class DescriptorSchema(BaseModel): id: str format: str path: str - path_nested: Dict[str, Any] = None + path_nested: dict[str, Any] = None class PresentationSubmissionSchema(BaseModel): id: str definition_id: str - descriptor_map: List[DescriptorSchema] + descriptor_map: list[DescriptorSchema] @field_validator("descriptor_map") @classmethod diff --git a/pyeudiw/tests/openid4vp/test_presentation_submission.py b/pyeudiw/tests/openid4vp/test_presentation_submission.py new file mode 100644 index 00000000..c820a052 --- /dev/null +++ b/pyeudiw/tests/openid4vp/test_presentation_submission.py @@ -0,0 +1,121 @@ +from unittest.mock import patch, MagicMock +from pydantic import ValidationError +from pytest import raises +from pyeudiw.openid4vp.presentation_submission.presentation_submission import PresentationSubmission + + +# Mock data for testing +mock_format_config = { + "formats": [ + {"name": "ldp_vp", "module": "mock.module", "class": "MockLdpVpHandler"}, + {"name": "jwt_vp_json", "module": "mock.module", "class": "MockJwtVpJsonHandler"} + ], + "MAX_SUBMISSION_SIZE": 10 * 1024 # 10 KB +} + +valid_submission = { + "id": "submission_id", + "definition_id": "definition_id", + "descriptor_map": [ + {"id": "descriptor_1", "format": "ldp_vp", "path": "$"}, + {"id": "descriptor_2", "format": "jwt_vp_json", "path": "$"} + ] +} + +large_submission = { + "id": "submission_id_large", + "definition_id": "definition_id_large", + "descriptor_map": [{"id": f"descriptor_{i}", "format": "ldp_vp", "path": "$"} for i in range(101)] # Exceeds limit +} + + +def test_presentation_submission_initialization_with_schema_validation(): + """ + Test that the PresentationSubmission class initializes correctly + and validates against the Pydantic schema. + """ + # Mock handler classes + mock_ldp_vp_handler = MagicMock(name="MockLdpVpHandler") + mock_jwt_vp_json_handler = MagicMock(name="MockJwtVpJsonHandler") + + # Mock import_module to return a fake module with our mock classes + mock_module = MagicMock() + setattr(mock_module, "MockLdpVpHandler", mock_ldp_vp_handler) + setattr(mock_module, "MockJwtVpJsonHandler", mock_jwt_vp_json_handler) + + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config), \ + patch("importlib.import_module", return_value=mock_module): + + # Initialize the class + ps = PresentationSubmission(valid_submission) + + # Assert that handlers were created for all formats in descriptor_map + assert len(ps.handlers) == len(valid_submission["descriptor_map"]), "Not all handlers were created." + + # Check that the handlers are instances of the mocked classes + assert ps.handlers[0] is mock_ldp_vp_handler(), "Handler for 'ldp_vp' format is incorrect." + assert ps.handlers[1] is mock_jwt_vp_json_handler(), "Handler for 'jwt_vp_json' format is incorrect." + + +def test_presentation_submission_large_submission_with_schema(): + """ + Test that the PresentationSubmission class raises a ValidationError + when the submission exceeds the descriptor_map size limit. + """ + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + # Expect a ValidationError for exceeding descriptor_map size limit + with raises(ValidationError, match="descriptor_map exceeds maximum allowed size of 100 items"): + PresentationSubmission(large_submission) + + +def test_presentation_submission_missing_descriptor_key(): + """ + Test that the PresentationSubmission class raises a ValidationError + when required keys are missing in the descriptor_map. + """ + invalid_submission = { + "id": "invalid_submission_id", + "definition_id": "invalid_definition_id", + "descriptor_map": [ + {"format": "ldp_vp"} + ] + } + + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + + with raises(ValidationError, match=r"Field required"): + PresentationSubmission(invalid_submission) + +def test_presentation_submission_invalid_format(): + """ + Test that the PresentationSubmission class raises a ValueError + when an unsupported format is encountered. + """ + invalid_submission = { + "id": "invalid_submission_id", + "definition_id": "invalid_definition_id", + "descriptor_map": [ + {"format": "unsupported_format", "id": "descriptor_1", "path": "$"} + ] + } + + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + with raises(ValueError, match="Format 'unsupported_format' is not supported or not defined in the configuration."): + PresentationSubmission(invalid_submission) + +def test_presentation_submission_missing_format_key(): + """ + Test that the PresentationSubmission class raises a KeyError + when the 'format' key is missing in a descriptor. + """ + missing_format_key_submission = { + "id": "missing_format_submission_id", + "definition_id": "missing_format_definition_id", + "descriptor_map": [ + {"id": "descriptor_1", "path": "$"} # Missing 'format' key + ] + } + + with patch("pyeudiw.openid4vp.presentation_submission.presentation_submission.PresentationSubmission._load_config", return_value=mock_format_config): + with raises(ValidationError, match=r"descriptor_map\.0\.format\s+Field required"): + PresentationSubmission(missing_format_key_submission) From 9a9e6a673ccfda3b60c1fa318199dcc264d4a1a0 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Thu, 23 Jan 2025 15:29:50 +0100 Subject: [PATCH 13/15] fix:broken indentation --- .github/workflows/python-app.yml | 138 +++++++++++++++---------------- 1 file changed, 67 insertions(+), 71 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index a522fdb5..b561d8f9 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -5,12 +5,11 @@ name: pyeudiw on: push: - branches: [ "*" ] + branches: ["*"] pull_request: - branches: [ "*" ] + branches: ["*"] jobs: - pre_job: runs-on: ubuntu-latest outputs: @@ -19,11 +18,10 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v3.4.0 with: - skip_after_successful_duplicate: 'true' - same_content_newer: 'true' + skip_after_successful_duplicate: "true" + same_content_newer: "true" main_job: - needs: pre_job if: needs.pre_job.outputs.should_skip != 'true' @@ -33,72 +31,70 @@ jobs: fail-fast: false matrix: python-version: - - '3.10' - - '3.11' - - '3.12' + - "3.10" + - "3.11" + - "3.12" steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install system package - run: | - sudo apt update - sudo apt install python3-dev python3-pip - - name: Install MongoDB - run: | - sudo apt-get install -y gnupg wget - sudo wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add - - sudo echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.4 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list - sudo apt-get update - sudo apt-get install -y mongodb-org - - name: Start MongoDB - run: sudo systemctl start mongod - - name: Install dependencies - run: | - python -m pip install --upgrade pip - if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - if [ -f requirements-customizations.txt ]; then pip install -r requirements-customizations.txt; fi - python -m pip install -U setuptools - python -m pip install -e . - python -m pip install "Pillow>=10.0.0,<10.1" "device_detector>=5.0,<6" "satosa>=8.4,<8.6" "jinja2>=3.0,<4" "pymongo>=4.4.1,<4.5" aiohttp - python -m pip install git+https://github.com/openwallet-foundation-labs/sd-jwt-python.git - python -m pip install git+https://github.com/peppelinux/pyMDOC-CBOR.git + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install system package + run: | + sudo apt update + sudo apt install python3-dev python3-pip + - name: Install MongoDB + run: | + sudo apt-get install -y gnupg curl + sudo curl -fsSL https://pgp.mongodb.com/server-7.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor + sudo echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list + sudo apt-get update + sudo apt-get install -y mongodb-org + - name: Start MongoDB + run: sudo systemctl start mongod + - name: Install dependencies + run: | + python -m pip install --upgrade pip + if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + if [ -f requirements-customizations.txt ]; then pip install -r requirements-customizations.txt; fi + python -m pip install -U setuptools + python -m pip install -e . + python -m pip install "Pillow>=10.0.0,<10.1" "device_detector>=5.0,<6" "satosa>=8.4,<8.6" "jinja2>=3.0,<4" "pymongo>=4.4.1,<4.5" aiohttp + python -m pip install git+https://github.com/peppelinux/pyMDOC-CBOR.git + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 pyeudiw --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 pyeudiw --count --exit-zero --statistics --max-line-length 160 + - name: Tests + run: | + # pytest --cov=pyeudiw --cov-fail-under=90 pyeudiw + pytest --cov=pyeudiw pyeudiw + coverage report -m --skip-covered + - name: Bandit Security Scan + run: | + bandit -r -x pyeudiw/tests* pyeudiw/* + - name: Lint with html linter + run: | + echo -e '\nHTML:' + readarray -d '' array < <(find $SRC example -name "*.html" -print0) + echo "Running linter on (${#array[@]}): " + printf '\t- %s\n' "${array[@]}" + echo "Linter output:" - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 pyeudiw --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 pyeudiw --count --exit-zero --statistics --max-line-length 160 - - name: Tests - run: | - # pytest --cov=pyeudiw --cov-fail-under=90 pyeudiw - pytest --cov=pyeudiw pyeudiw - coverage report -m --skip-covered - - name: Bandit Security Scan - run: | - bandit -r -x pyeudiw/tests* pyeudiw/* - - name: Lint with html linter - run: | - echo -e '\nHTML:' - readarray -d '' array < <(find $SRC example -name "*.html" -print0) - echo "Running linter on (${#array[@]}): " - printf '\t- %s\n' "${array[@]}" - echo "Linter output:" + for file in "${array[@]}" + do + echo -e "\n$file:" + html_lint.py "$file" | awk -v path="file://$PWD/$file:" '$0=path$0' | sed -e 's/: /:\n\t/'; + done - for file in "${array[@]}" - do - echo -e "\n$file:" - html_lint.py "$file" | awk -v path="file://$PWD/$file:" '$0=path$0' | sed -e 's/: /:\n\t/'; - done - - # block if the html linter fails - #for file in "${array[@]}" - #do - #errors=$(html_lint.py "$file" | grep -c 'Error') - #if [ "$errors" -gt 0 ]; then exit 1; fi; - #done + # block if the html linter fails + #for file in "${array[@]}" + #do + #errors=$(html_lint.py "$file" | grep -c 'Error') + #if [ "$errors" -gt 0 ]; then exit 1; fi; + #done From 682ce614ade99e0329884ffdd0141f7b671a7af5 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter <114922565+LadyCodesItBetter@users.noreply.github.com> Date: Thu, 23 Jan 2025 15:34:18 +0100 Subject: [PATCH 14/15] Update python-app.yml From 43016c3e643b6b7bb66d575d89c9255c953ac510 Mon Sep 17 00:00:00 2001 From: LadyCodesItBetter Date: Thu, 23 Jan 2025 15:40:52 +0100 Subject: [PATCH 15/15] fix:broken indentation --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index b561d8f9..76283d4b 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -97,4 +97,4 @@ jobs: #do #errors=$(html_lint.py "$file" | grep -c 'Error') #if [ "$errors" -gt 0 ]; then exit 1; fi; - #done + #done \ No newline at end of file