diff --git a/changelogs/fragments/10299-github_app_access_token-lookup.yml b/changelogs/fragments/10299-github_app_access_token-lookup.yml new file mode 100644 index 0000000000..16a1e31524 --- /dev/null +++ b/changelogs/fragments/10299-github_app_access_token-lookup.yml @@ -0,0 +1,4 @@ +bugfixes: + - github_app_access_token lookup plugin - avoid using jwt library requirement that conflicts with other modules requirements (https://github.com/ansible-collections/community.general/issues/10299) +breaking_changes: + - github_app_access_token lookup plugin - depends now on pyjwt rather than jwt (https://github.com/ansible-collections/community.general/issues/10299) diff --git a/plugins/lookup/github_app_access_token.py b/plugins/lookup/github_app_access_token.py index dbc8cde3b5..d2d7689ead 100644 --- a/plugins/lookup/github_app_access_token.py +++ b/plugins/lookup/github_app_access_token.py @@ -9,10 +9,12 @@ DOCUMENTATION = r""" name: github_app_access_token author: - Poh Wei Sheng (@weisheng-p) + - Bruno Lavoie (@blavoie) short_description: Obtain short-lived Github App Access tokens version_added: '8.2.0' requirements: - - jwt (https://github.com/GehirnInc/python-jwt) + - PyJWT (https://pypi.org/project/PyJWT/) + - cryptography (https://pypi.org/project/cryptography/) description: - This generates a Github access token that can be used with a C(git) command, if you use a Github App. options: @@ -66,9 +68,14 @@ _raw: elements: str """ +try: + from cryptography.hazmat.primitives import serialization + HAS_CRYPTOGRAPHY = True +except ImportError: + HAS_CRYPTOGRAPHY = False try: - from jwt import JWT, jwk_from_pem + import jwt # pyjwt HAS_JWT = True except ImportError: HAS_JWT = False @@ -81,26 +88,22 @@ from ansible.errors import AnsibleError, AnsibleOptionsError from ansible.plugins.lookup import LookupBase from ansible.utils.display import Display -if HAS_JWT: - jwt_instance = JWT() -else: - jwk_from_pem = None - jwt_instance = None - display = Display() def read_key(path, private_key=None): try: if private_key: - return jwk_from_pem(private_key.encode('utf-8')) - with open(path, 'rb') as pem_file: - return jwk_from_pem(pem_file.read()) + key_bytes = private_key.encode('utf-8') + else: + with open(path, 'rb') as pem_file: + key_bytes = pem_file.read() + return serialization.load_pem_private_key(key_bytes, password=None) except Exception as e: raise AnsibleError(f"Error while parsing key file: {e}") -def encode_jwt(app_id, jwk, exp=600): +def encode_jwt(app_id, private_key_obj, exp=600): now = int(time.time()) payload = { 'iat': now, @@ -108,7 +111,7 @@ def encode_jwt(app_id, jwk, exp=600): 'iss': app_id, } try: - return jwt_instance.encode(payload, jwk, alg='RS256') + return jwt.encode(payload, private_key_obj, algorithm='RS256') except Exception as e: raise AnsibleError(f"Error while encoding jwt: {e}") @@ -150,7 +153,11 @@ class LookupModule(LookupBase): def run(self, terms, variables=None, **kwargs): if not HAS_JWT: raise AnsibleError('Python jwt library is required. ' - 'Please install using "pip install jwt"') + 'Please install using "pip install pyjwt"') + + if not HAS_CRYPTOGRAPHY: + raise AnsibleError('Python cryptography library is required. ' + 'Please install using "pip install cryptography"') self.set_options(var_options=variables, direct=kwargs)