Skip to content

Commit

Permalink
✨ Added a facultative configuration file for CLI tools to allow certa…
Browse files Browse the repository at this point in the history
…in users to use the CLI without granting them read access to the configuration file
  • Loading branch information
Boris-INSA committed Jun 17, 2024
1 parent f75a30c commit d37540e
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 9 deletions.
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion hermes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
29 changes: 21 additions & 8 deletions lib/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
"""
Expand All @@ -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",
Expand Down
36 changes: 36 additions & 0 deletions lib/config/config-schema-cli.yml
Original file line number Diff line number Diff line change
@@ -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://www.gnu.org/licenses/>.

# 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

0 comments on commit d37540e

Please sign in to comment.