From d37540ec5a8286ca2176647b89e1ba58bf428a11 Mon Sep 17 00:00:00 2001 From: Boris Lechner <148430302+Boris-INSA@users.noreply.github.com> Date: Mon, 17 Jun 2024 15:57:27 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Added=20a=20facultative=20configura?= =?UTF-8?q?tion=20file=20for=20CLI=20tools=20to=20allow=20certain=20users?= =?UTF-8?q?=20to=20use=20the=20CLI=20without=20granting=20them=20read=20ac?= =?UTF-8?q?cess=20to=20the=20configuration=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 1 + hermes.py | 2 +- lib/config/__init__.py | 29 ++++++++++++++++++------- lib/config/config-schema-cli.yml | 36 ++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 lib/config/config-schema-cli.yml diff --git a/ChangeLog.md b/ChangeLog.md index 2d82fbe..1097df4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added the ability to fetch dictionnaries values for attributes : the dictionnaries can contain any supported value type : int, float, str, datetime, list, dict. No filtering of dict values is made : None, empty sub-dict, or empty list are left as provided. - Added a new setting `hermes.cli_socket.dont_manage_sockfile` that allow to delegate the CLI server sockfile creation to SystemD. +- Added a facultative configuration file named ***APPNAME*-cli-config.yml** for CLI tools to allow certain users to use the CLI without granting them read access to the configuration file. ### Fixed diff --git a/hermes.py b/hermes.py index d5e5013..336d478 100755 --- a/hermes.py +++ b/hermes.py @@ -71,7 +71,7 @@ len("hermes-") : -len("-cli") ] # Hack to force app context config = HermesConfig(autoload=False, allowMultipleInstances=True) - config.load(loadplugins=False, dontManageCacheDir=True) + config.load(loadplugins=False, isCLI=True) if config["hermes"]["cli_socket"]["path"] is None: print( diff --git a/lib/config/__init__.py b/lib/config/__init__.py index a351262..6b0cf20 100644 --- a/lib/config/__init__.py +++ b/lib/config/__init__.py @@ -143,34 +143,44 @@ def savecachefile(self, cacheFilename: str | None = None): """Override method only to disable backup files in cache""" return super().savecachefile(cacheFilename, dontKeepBackup=True) - def load(self, loadplugins: bool = True, dontManageCacheDir: bool = False): + def load(self, loadplugins: bool = True, isCLI: bool = False): """Load and validate config of current appname, and fill config dictionary. Setup logging, and signals handlers. Load plugins, and validate their config. """ self._config = {} self._setAppname() - schemas = self._getRequiredSchemas() + schemas = self._getRequiredSchemas(isCLI=isCLI) schema = self._mergeSchemas(schemas) - with open(f"""{self._config["appname"]}-config.yml""") as f: - config = yaml.load(f, Loader=YAMLUniqueKeyCSafeLoader) + config = None + if isCLI: + try: + with open(f"""{self._config["appname"]}-cli-config.yml""") as f: + config = yaml.load(f, Loader=YAMLUniqueKeyCSafeLoader) + except Exception: + pass - validator = Validator(schema) + if config is None: + # Not CLI or cli-config not found + with open(f"""{self._config["appname"]}-config.yml""") as f: + config = yaml.load(f, Loader=YAMLUniqueKeyCSafeLoader) + + validator = Validator(schema, purge_unknown=isCLI) if not validator.validate(config): raise HermesConfigError(validator.errors) self._config |= validator.normalized(config) self._rawconfig = deepcopy(self._config) - if not dontManageCacheDir: + if not isCLI: lib.utils.logging.setup_logger(self) # Setup logging LocalCache.setup(self) # Update cache files settings super().__init__( jsondataattr="_rawconfig", cachefilename="_hermesconfig", - dontManageCacheDir=dontManageCacheDir, + dontManageCacheDir=isCLI, ) if not self._allowMultipleInstances: @@ -262,7 +272,7 @@ def _validateAppname(self, name: str): f"The specified name '{name}' doesn't respect app naming scheme. Please refer to the documentation" ) - def _getRequiredSchemas(self) -> dict[str, str]: + def _getRequiredSchemas(self, isCLI: bool = False) -> dict[str, str]: """Fill a dict containing main config key and absolute path of config schemas required by current appname. Those values will be used to build Cerberus validation schema in order to validate config file. """ @@ -271,6 +281,9 @@ def _getRequiredSchemas(self) -> dict[str, str]: # Retrieve absolute path of hermes source directory appdir = os.path.realpath(os.path.dirname(__file__) + "/../../") + if isCLI: + return {"hermes": f"{appdir}/lib/config/config-schema-cli.yml"} + schemas = { # Global config "hermes": f"{appdir}/lib/config/config-schema.yml", diff --git a/lib/config/config-schema-cli.yml b/lib/config/config-schema-cli.yml new file mode 100644 index 0000000..a43d6c1 --- /dev/null +++ b/lib/config/config-schema-cli.yml @@ -0,0 +1,36 @@ +# Hermes : Change Data Capture (CDC) tool from any source(s) to any target +# Copyright (C) 2024 INSA Strasbourg +# +# This file is part of Hermes. +# +# Hermes is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Hermes is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Hermes. If not, see . + +# https://docs.python-cerberus.org/validation-rules.html + +hermes: + type: dict + required: true + empty: false + schema: + cli_socket: + type: dict + required: true + empty: false + nullable: false + schema: + path: + type: string + required: true + empty: false + nullable: false