diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index da10b3d..fb52b42 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -8,7 +8,33 @@ on: branches: ["*"] jobs: + skip-check: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.check.outputs.should_skip }} + steps: + - uses: actions/github-script@v7 + id: check + with: + script: | + const branch = process.env.BRANCH || ''; + const { data: { workflow_runs } } = await github.rest.actions.listWorkflowRunsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + status: 'in_progress', + }); + const otherRunning = workflow_runs.filter( + r => r.id != context.runId && + r.name === context.workflow && + (!branch || r.head_branch === branch) + ); + core.setOutput('should_skip', otherRunning.length > 0 ? 'true' : 'false'); + env: + BRANCH: ${{ github.head_ref || github.ref_name }} + lint: + needs: skip-check + if: needs.skip-check.outputs.should_skip != 'true' name: flake8 runs-on: ubuntu-latest steps: @@ -29,6 +55,8 @@ jobs: flake8 pymdoccbor isort: + needs: skip-check + if: needs.skip-check.outputs.should_skip != 'true' name: isort runs-on: ubuntu-latest steps: @@ -48,6 +76,8 @@ jobs: isort pymdoccbor --check-only --diff bandit: + needs: skip-check + if: needs.skip-check.outputs.should_skip != 'true' name: Bandit security scan runs-on: ubuntu-latest steps: @@ -67,6 +97,8 @@ jobs: bandit -r -x pymdoccbor/tests pymdoccbor -f txt radon: + needs: skip-check + if: needs.skip-check.outputs.should_skip != 'true' name: Radon complexity runs-on: ubuntu-latest steps: diff --git a/.github/workflows/dependency-security.yml b/.github/workflows/dependency-security.yml index bf29427..54c29af 100644 --- a/.github/workflows/dependency-security.yml +++ b/.github/workflows/dependency-security.yml @@ -8,7 +8,33 @@ on: branches: ["*"] jobs: + skip-check: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.check.outputs.should_skip }} + steps: + - uses: actions/github-script@v7 + id: check + with: + script: | + const branch = process.env.BRANCH || ''; + const { data: { workflow_runs } } = await github.rest.actions.listWorkflowRunsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + status: 'in_progress', + }); + const otherRunning = workflow_runs.filter( + r => r.id != context.runId && + r.name === context.workflow && + (!branch || r.head_branch === branch) + ); + core.setOutput('should_skip', otherRunning.length > 0 ? 'true' : 'false'); + env: + BRANCH: ${{ github.head_ref || github.ref_name }} + pip-audit: + needs: skip-check + if: needs.skip-check.outputs.should_skip != 'true' name: pip-audit runs-on: ubuntu-latest steps: @@ -23,8 +49,8 @@ jobs: python -m venv env source env/bin/activate pip install --upgrade pip pip-audit - pip install "cbor2>=5.4.0" "cbor-diag>=1.1.0" "pycose>=1.0.1" pip install -r requirements-dev.txt + pip install -e . # Exit 1 on any vulnerability (fail CI). --skip-editable whitelists pymdoccbor (local package, not on PyPI). # Ignore only unfixable: ecdsa CVE-2024-23342 (no upstream fix; see docs/SECURITY-DEPENDENCIES.md). diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 5746da5..987188a 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -10,8 +10,33 @@ on: branches: [ "*" ] jobs: - build: + skip-check: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.check.outputs.should_skip }} + steps: + - uses: actions/github-script@v7 + id: check + with: + script: | + const branch = process.env.BRANCH || ''; + const { data: { workflow_runs } } = await github.rest.actions.listWorkflowRunsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + status: 'in_progress', + }); + const otherRunning = workflow_runs.filter( + r => r.id != context.runId && + r.name === context.workflow && + (!branch || r.head_branch === branch) + ); + core.setOutput('should_skip', otherRunning.length > 0 ? 'true' : 'false'); + env: + BRANCH: ${{ github.head_ref || github.ref_name }} + build: + needs: skip-check + if: needs.skip-check.outputs.should_skip != 'true' runs-on: ubuntu-22.04 strategy: @@ -21,6 +46,8 @@ jobs: - '3.10' - "3.11" - "3.12" + - "3.13" + - "3.14" steps: - uses: actions/checkout@v4 diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..42b31ba --- /dev/null +++ b/NOTICE @@ -0,0 +1,11 @@ +IdentityPython pyMDOC-CBOR +https://github.com/IdentityPython/pyMDOC-CBOR + +This project aligns with the EU Digital Identity Wallet reference implementation: +https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR + +Modifications in that repository are Copyright (c) European Commission +and licensed under the Apache License, Version 2.0. + +This project is licensed under the Apache License, Version 2.0. +See the LICENSE file for details. diff --git a/README.md b/README.md index bb586ce..771fec7 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,10 @@ Other examples at [cbor official documentation](https://github.com/agronholm/cbo - [Python Certvalidator](https://github.com/wbond/certvalidator/blob/master/docs/usage.md) +## EUDI Wallet reference implementation + +This project aligns with the [EU Digital Identity Wallet pyMDOC-CBOR](https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR) reference implementation. That repository may contain additional modifications for EUDI Wallet PID and mDL use cases (European Commission) since the EU Digital Identity Wallet pyMDOC-CBOR is a fork of this project. + ## Authors and contributors - Giuseppe De Marco diff --git a/pymdoccbor/__init__.py b/pymdoccbor/__init__.py index 6849410..c68196d 100644 --- a/pymdoccbor/__init__.py +++ b/pymdoccbor/__init__.py @@ -1 +1 @@ -__version__ = "1.1.0" +__version__ = "1.2.0" diff --git a/pymdoccbor/exceptions.py b/pymdoccbor/exceptions.py index 51a38d2..115683b 100644 --- a/pymdoccbor/exceptions.py +++ b/pymdoccbor/exceptions.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR class InvalidMdoc(Exception): """ """ diff --git a/pymdoccbor/mdoc/exceptions.py b/pymdoccbor/mdoc/exceptions.py index d3a1ff4..79ef31c 100644 --- a/pymdoccbor/mdoc/exceptions.py +++ b/pymdoccbor/mdoc/exceptions.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR class MissingPrivateKey(Exception): pass diff --git a/pymdoccbor/mdoc/issuer.py b/pymdoccbor/mdoc/issuer.py index ef7f3d3..807ef6b 100644 --- a/pymdoccbor/mdoc/issuer.py +++ b/pymdoccbor/mdoc/issuer.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR import base64 import binascii import logging diff --git a/pymdoccbor/mdoc/issuersigned.py b/pymdoccbor/mdoc/issuersigned.py index 4b55875..7b840be 100644 --- a/pymdoccbor/mdoc/issuersigned.py +++ b/pymdoccbor/mdoc/issuersigned.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR from typing import Union import cbor2 diff --git a/pymdoccbor/mdoc/verifier.py b/pymdoccbor/mdoc/verifier.py index 993aacd..bba6ed8 100644 --- a/pymdoccbor/mdoc/verifier.py +++ b/pymdoccbor/mdoc/verifier.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR import binascii import logging from typing import List diff --git a/pymdoccbor/mso/issuer.py b/pymdoccbor/mso/issuer.py index 06d3118..ae6fb8a 100644 --- a/pymdoccbor/mso/issuer.py +++ b/pymdoccbor/mso/issuer.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR import datetime import hashlib import logging diff --git a/pymdoccbor/mso/verifier.py b/pymdoccbor/mso/verifier.py index 8fb4f7c..c63ad12 100644 --- a/pymdoccbor/mso/verifier.py +++ b/pymdoccbor/mso/verifier.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR import hashlib import logging from datetime import datetime, timezone @@ -39,15 +40,21 @@ def __init__(self, data: Union[cbor2.CBORTag, bytes, list]) -> None: self._data = data - # not used if isinstance(self._data, bytes): self.object: Sign1Message = bytes2CoseSign1( cbor2.dumps(cbor2.CBORTag(18, value=self._data))) elif isinstance(self._data, list): self.object: Sign1Message = cborlist2CoseSign1(self._data) + elif isinstance(self._data, cbor2.CBORTag) and self._data.tag == 18: + # COSE_Sign1 is CBOR tag 18; value can be list (decoded) or bytes + val = self._data.value + if isinstance(val, list): + self.object = cborlist2CoseSign1(val) + else: + self.object = bytes2CoseSign1(cbor2.dumps(self._data)) else: raise UnsupportedMsoDataFormat( - f"MsoParser only supports raw bytes and list, a {type(data)} was provided" + f"MsoParser only supports raw bytes, list, or CBORTag(18); got {type(data)}" ) self.object.key = None diff --git a/pymdoccbor/tests/test_07_mso_verifier.py b/pymdoccbor/tests/test_07_mso_verifier.py index 6be01f2..1479747 100644 --- a/pymdoccbor/tests/test_07_mso_verifier.py +++ b/pymdoccbor/tests/test_07_mso_verifier.py @@ -27,7 +27,7 @@ def test_mso_verifier_fail(): try: MsoVerifier(None) except Exception as e: - assert str(e) == "MsoParser only supports raw bytes and list, a was provided" + assert "raw bytes" in str(e) and "NoneType" in str(e) def test_mso_verifier_creation(): diff --git a/pymdoccbor/tools.py b/pymdoccbor/tools.py index 3d4416e..96fadca 100644 --- a/pymdoccbor/tools.py +++ b/pymdoccbor/tools.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR import json import random diff --git a/pymdoccbor/x509.py b/pymdoccbor/x509.py index e911df1..525053b 100644 --- a/pymdoccbor/x509.py +++ b/pymdoccbor/x509.py @@ -1,3 +1,4 @@ +# Aligns with https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR from typing import Any, Union from cryptography import x509 diff --git a/setup.py b/setup.py index 295ec91..56f299b 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,11 @@ def readme(): "Programming Language :: Python :: 3.12", "Topic :: Software Development :: Libraries :: Python Modules", ], - url="https://github.com/IdentityPython/pyMDL-MDOC", + url="https://github.com/IdentityPython/pyMDOC-CBOR", + project_urls={ + "EUDI Wallet reference": "https://github.com/eu-digital-identity-wallet/pyMDOC-CBOR", + "Source": "https://github.com/IdentityPython/pyMDOC-CBOR", + }, author="Giuseppe De Marco", author_email="demarcog83@gmail.com", license="License :: OSI Approved :: Apache Software License",