diff --git a/CHANGELOG.md b/CHANGELOG.md index b071d63a6..0743e065a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,19 @@ Changelog This is the changelog for Puppetboard. +5.0.0 +----- + +* Stop setting `SECRET_KEY` value to a random string by default. This has caused issues in deployments with more than one app replica or when the app was restarted. Please set this to your own long, random string, **the same for each application replica**. Implements [#721](https://github.com/voxpupuli/puppetboard/issues/721). +* Drop support for Python 3.7 (end-of-life in June 2023). PR [#899](https://github.com/voxpupuli/puppetboard/pull/899) +* Fix broken links in Classes view. PR [#868](https://github.com/voxpupuli/puppetboard/pull/868), fixes [#816](https://github.com/voxpupuli/puppetboard/issues/816). +* Fix if fact is `None` (default for full node view). PR [#908](https://github.com/voxpupuli/puppetboard/pull/908), fixes [#907](https://github.com/voxpupuli/puppetboard/issues/907). +* Dependencies update. + +Thanks to the following contributors of this release: +* [Louis Charreau](https://github.com/lcharreau) +* [Yehuda Katz](https://github.com/yakatz) + 4.3.0 ----- diff --git a/README.md b/README.md index 04a6fa8c2..4dbb721c5 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,9 @@ to explicitly specify the protocol to be used setting the `PUPPETDB_PROTO` varia Other settings that might be interesting, in no particular order: +- `SECRET_KEY`: set this to a long string, **the same for each application replica** and keep it secret. Refer to + [Flask documentation](https://flask.palletsprojects.com/en/2.1.x/quickstart/#sessions), section + "How to generate good secret keys" for more info. - `FAVORITE_ENVS`: an ordered list of Puppet environment names that will be shown immediately after "All Environments" and before other environments (which are sorted by name) in the dropdown for choosing the environment shown in the top-right of the UI. Environments listed here that do not really exist in your deployment are silently ignored. @@ -175,8 +178,6 @@ Other settings that might be interesting, in no particular order: Defaults to `friendly`. - `CODE_PREFIX_TO_REMOVE`: what code path that should be shortened in "Friendly errors" to "…" for readability. A regexp. Defaults to `/etc/puppetlabs/code/environments(/.*?/modules)?`. -- `SECRET_KEY`: Refer to [Flask documentation](https://flask.palletsprojects.com/en/2.0.x/quickstart/#sessions), - section "How to generate good secret keys" for more info. Defaults to a random 64-char string generated by `secrets.token_hex(32)`, prepended with a `default-` string. **Warning** Leaving SECRET_KEY set to a default value WILL cause issues when the app is restarted or has more than 1 replica (f.e. uWSGI workers, k8s replicas etc.) and some features (in particular: queries) are used. Please set SECRET_KEY to your own value, the same for all app replicas. This will be REQUIRED starting with Puppetboard 5.x which will NOT contain the default value anymore. Please see [#721](https://github.com/voxpupuli/puppetboard/issues/721) for more info. - `PUPPETDB_TIMEOUT`: Defaults to 20 seconds, but you might need to increase this value. It depends on how big the results are when querying PuppetDB. This behaviour will change in a future release when pagination will be introduced. - `UNRESPONSIVE_HOURS`: The amount of hours since the last check-in after which a node is considered unresponsive. diff --git a/puppetboard/app.py b/puppetboard/app.py index 627d1521d..ca0759d7a 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -45,7 +45,7 @@ running_as = os.path.basename(sys.argv[0]) if not is_a_test(): check_db_version(puppetdb) -check_secret_key(app.config.get('SECRET_KEY')) + check_secret_key(app.config.get('SECRET_KEY')) logging.basicConfig(level=app.config['LOGLEVEL'].upper()) log = logging.getLogger(__name__) diff --git a/puppetboard/core.py b/puppetboard/core.py index 4d43b7d0f..43ef71a30 100644 --- a/puppetboard/core.py +++ b/puppetboard/core.py @@ -1,8 +1,8 @@ import logging import re import socket +from importlib.metadata import version -import pkg_resources from flask import Flask from flask_caching import Cache from flask_apscheduler import APScheduler @@ -70,7 +70,7 @@ def get_puppetdb(): timeout=app.config['PUPPETDB_TIMEOUT'], protocol=app.config['PUPPETDB_PROTO'], ) - requests_version = pkg_resources.get_distribution("requests").version + requests_version = version("requests") user_agent_header = { "user-agent": f"puppetboard/{own_version} (r/{requests_version})", } diff --git a/puppetboard/default_settings.py b/puppetboard/default_settings.py index ff970459e..39b290def 100644 --- a/puppetboard/default_settings.py +++ b/puppetboard/default_settings.py @@ -8,7 +8,8 @@ PUPPETDB_CERT = None PUPPETDB_TIMEOUT = 20 DEFAULT_ENVIRONMENT = 'production' -SECRET_KEY = f"default-{secrets.token_hex(32)}" +# this empty string has to be changed, we validate it with check_secret_key() +SECRET_KEY = '' # nosec UNRESPONSIVE_HOURS = 2 ENABLE_QUERY = True # Uncomment to restrict the enabled PuppetDB endpoints in the query page. @@ -78,7 +79,7 @@ ('noop', 'Noop'), ] # Type of caching object to use when `SCHEDULER_ENABLED` is set to `True`. -# If more than one worker, use a shared backend (e.g. `MemcachedCache`) +# If more than one worker, use a shared backend (e.g. `MemcachedCache`) # to allow the sharing of the cache between the processes. CACHE_TYPE = 'SimpleCache' # Cache litefime in second diff --git a/puppetboard/docker_settings.py b/puppetboard/docker_settings.py index ebf65e5cc..ba53563cb 100644 --- a/puppetboard/docker_settings.py +++ b/puppetboard/docker_settings.py @@ -60,7 +60,8 @@ def coerce_bool(v, default): PUPPETDB_PROTO = os.getenv('PUPPETDB_PROTO', None) PUPPETDB_TIMEOUT = int(os.getenv('PUPPETDB_TIMEOUT', '20')) DEFAULT_ENVIRONMENT = os.getenv('DEFAULT_ENVIRONMENT', 'production') -SECRET_KEY = os.getenv('SECRET_KEY', f"default-{secrets.token_hex(32)}") +# this empty string has to be changed, we validate it with check_secret_key() +SECRET_KEY = os.getenv('SECRET_KEY', '') # nosec UNRESPONSIVE_HOURS = int(os.getenv('UNRESPONSIVE_HOURS', '2')) ENABLE_QUERY = coerce_bool(os.getenv('ENABLE_QUERY'), True) # Uncomment to restrict the enabled PuppetDB endpoints in the query page. @@ -177,7 +178,7 @@ def coerce_bool(v, default): CLASS_EVENTS_STATUS_COLUMNS = [(CLASS_EVENTS_STATUS_COLUMNS_STR[i].strip(), CLASS_EVENTS_STATUS_COLUMNS_STR[i + 1].strip()) for i in range(0, len(CLASS_EVENTS_STATUS_COLUMNS_STR), 2)] -# Enabled a scheduler instance to trigger jobs in background. +# Enabled a scheduler instance to trigger jobs in background. SCHEDULER_ENABLED = coerce_bool(os.getenv('SCHEDULER_ENABLED'), False) # Tuples are hard to express as an environment variable, so here diff --git a/puppetboard/utils.py b/puppetboard/utils.py index 36c656598..7e3bff1d0 100644 --- a/puppetboard/utils.py +++ b/puppetboard/utils.py @@ -49,25 +49,11 @@ def check_db_version(puppetdb): def check_secret_key(secret_key_value): - """ - Check if the secret key value is set to a default value, that will stop - being accepted in v5.x of the app. - """ - - if type(secret_key_value) is str and secret_key_value.startswith("default-"): - log.warning( - "Leaving SECRET_KEY set to a default value WILL cause issues" - " when the app is restarted or has more than 1 replica" - " (f.e. uWSGI workers, k8s replicas etc.) and some features" - " (in particular: queries) are used.\n" - "Please set SECRET_KEY to your own value, the same for all app" - " replicas.\n" - "This will be REQUIRED starting with Puppetboard 5.x which" - " will NOT contain the default value anymore.\n" - "Please see" - " https://github.com/voxpupuli/puppetboard/issues/721" - " for more info." - ) + if not secret_key_value: + log.critical('Please set SECRET_KEY to a long, random string,' + ' **the same for each application replica**,' + ' and do not share it.') + sys.exit(1) def parse_python(value: str): diff --git a/puppetboard/version.py b/puppetboard/version.py index fe99f7990..68ce45b7f 100644 --- a/puppetboard/version.py +++ b/puppetboard/version.py @@ -2,4 +2,4 @@ # Puppetboard version module # -__version__ = '4.3.0' +__version__ = '5.0.0' diff --git a/test/test_form.py b/test/test_form.py index fbc28c10e..a0a440197 100644 --- a/test/test_form.py +++ b/test/test_form.py @@ -1,9 +1,13 @@ -from puppetboard import app, forms +from puppetboard import forms +from puppetboard.core import get_app + +app = get_app() +app.config['SECRET_KEY'] = 'the random string' def test_form_valid(capsys): for form in [forms.QueryForm]: - with app.app.test_request_context(): + with app.test_request_context(): qf = form() out, err = capsys.readouterr() assert qf is not None