From 789c8095362f817d6a07dfdccf0057035dbb677c Mon Sep 17 00:00:00 2001 From: Javier Asensio Date: Wed, 5 Apr 2023 12:14:17 +0100 Subject: [PATCH 1/2] Improve credentials parsing errors Now will get the following errors as a TentaclioFileError: 1. Not found: the file is not in the fs 2. Missing `secrets:` element 3. Yaml can't be parsed: File name and error description/line included. No context is shown in the logs as we would be logging passwords ``` [...] creds = _load_creds_from_yaml(yaml_reader) File "/home/javi/src/tentaclio/src/tentaclio/credentials/reader.py", line 66, in _load_creds_from_yaml raise TentaclioFileError(_process_mark_error(error)) tentaclio.credentials.reader.TentaclioFileError: Your tentaclio secrets file is malformed: File: /home/javi/src/tentaclio/kk.yml expected alphabetic or numeric character, but found ' ' in "", line 1, column 2 while scanning an alias in "", line 1, column 1 ``` --- src/tentaclio/credentials/__init__.py | 1 + src/tentaclio/credentials/reader.py | 43 ++++++++++++++++++++++++--- tests/unit/credentials/test_reader.py | 6 ++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/tentaclio/credentials/__init__.py b/src/tentaclio/credentials/__init__.py index a1634c46..3d2bbb81 100644 --- a/src/tentaclio/credentials/__init__.py +++ b/src/tentaclio/credentials/__init__.py @@ -1,3 +1,4 @@ """Credential management module.""" from .api import * # noqa from .injection import * # noqa +from .reader import TentaclioFileError # noqa diff --git a/src/tentaclio/credentials/reader.py b/src/tentaclio/credentials/reader.py index a591b2b8..e68763da 100644 --- a/src/tentaclio/credentials/reader.py +++ b/src/tentaclio/credentials/reader.py @@ -15,6 +15,25 @@ TENTACLIO_SECRETS_FILE = "TENTACLIO__SECRETS_FILE" +class TentaclioFileError(Exception): + TENTACLIO_FILE = os.getenv(TENTACLIO_SECRETS_FILE, "") + ERROR_TEMPLATE = """ +######################################### + +Your tentaclio secrets file is malformed: + +File: {tentaclio_file} + +{message} + +Check https://github.com/octoenergy/tentaclio#credentials-file for more info about this file +""" + + def __init__(self, message: str): + message = self.ERROR_TEMPLATE.format(message=message, tentaclio_file=self.TENTACLIO_FILE) + super().__init__(message) + + def add_credentials_from_env_file( injector: injection.CredentialsInjector, ) -> injection.CredentialsInjector: @@ -29,10 +48,27 @@ def add_credentials_from_env_file( return injector +def _process_mark_error(error: yaml.MarkedYAMLError) -> str: + error_str = "" + if error.problem_mark is not None: + error_str += str(error.problem) + "\n" + error_str += str(error.problem_mark) + "\n" + if error.context_mark is not None: + error_str += str(error.context) + "\n" + error_str += str(error.context_mark) + "\n" + return error_str + + def _load_creds_from_yaml(yaml_reader: protocols.Reader) -> dict: - loaded_data = yaml.safe_load(io.StringIO(yaml_reader.read())) + try: + loaded_data = yaml.safe_load(io.StringIO(yaml_reader.read())) + except yaml.MarkedYAMLError as error: + raise TentaclioFileError(_process_mark_error(error)) + if SECRETS not in loaded_data: - raise KeyError(f"no secrets in yaml data. Make sure the file has a '{SECRETS}' element") + raise TentaclioFileError( + "No secrets in yaml data. Make sure the file has a `secrets:` element" + ) return loaded_data[SECRETS] @@ -43,8 +79,7 @@ def _load_from_file( with open(path, "r") as f: return add_credentials_from_reader(injector, f) except IOError as e: - logger.error("Error while loading secrets file {path}") - raise e + raise TentaclioFileError("File not found") from e def add_credentials_from_reader( diff --git a/tests/unit/credentials/test_reader.py b/tests/unit/credentials/test_reader.py index 962e349a..6256f127 100644 --- a/tests/unit/credentials/test_reader.py +++ b/tests/unit/credentials/test_reader.py @@ -3,7 +3,7 @@ import pytest from tentaclio import urls -from tentaclio.credentials import injection, reader +from tentaclio.credentials import TentaclioFileError, injection, reader @pytest.fixture @@ -32,13 +32,13 @@ def creds_yaml_bad_url(): def test_bad_yaml(): - with pytest.raises(Exception): + with pytest.raises(TentaclioFileError): data = io.StringIO("sadfsaf") reader.add_credentials_from_reader(injection.CredentialsInjector(), data) def test_no_credentials_in_file(no_creds_yaml): - with pytest.raises(KeyError): + with pytest.raises(TentaclioFileError): data = io.StringIO(no_creds_yaml) reader.add_credentials_from_reader(injection.CredentialsInjector(), data) From ab1cecfab023eea8d2669292359b822a37d3ce5e Mon Sep 17 00:00:00 2001 From: Javier Asensio Date: Wed, 5 Apr 2023 12:37:48 +0100 Subject: [PATCH 2/2] Prepare release 1.1.0 --- CHANGELOG.txt | 4 ++++ setup.py | 2 +- src/tentaclio/credentials/reader.py | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e05a5471..0f3d3e1a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.0] - 2023-04-05 +### Changed + - Credential files error reporting to help users identify the credentials issues + ## [1.0.9] - 2023-01-25 ### Added - Add `tentaclio.streams.api.make_empty_safe` to modify the standard behavoir of creating diff --git a/setup.py b/setup.py index 3708a129..77e6cfb7 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools.command.install import install -VERSION = "1.0.9" +VERSION = "1.1.0" REPO_ROOT = pathlib.Path(__file__).parent diff --git a/src/tentaclio/credentials/reader.py b/src/tentaclio/credentials/reader.py index e68763da..b297e7b0 100644 --- a/src/tentaclio/credentials/reader.py +++ b/src/tentaclio/credentials/reader.py @@ -16,6 +16,8 @@ class TentaclioFileError(Exception): + """Tentaclio secrets file errors.""" + TENTACLIO_FILE = os.getenv(TENTACLIO_SECRETS_FILE, "") ERROR_TEMPLATE = """ ######################################### @@ -30,6 +32,7 @@ class TentaclioFileError(Exception): """ def __init__(self, message: str): + """Intialise a new TentaclioFileError.""" message = self.ERROR_TEMPLATE.format(message=message, tentaclio_file=self.TENTACLIO_FILE) super().__init__(message)