Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add ConfigurationStep for JWTSecrets #53

Merged
merged 4 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ python:
extra_requirements:
- notifications
- docs
- setup-configuration

1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Features
:caption: Contents:

quickstart
setup_config
ref/index


Expand Down
37 changes: 37 additions & 0 deletions docs/setup_config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Setup configuration
===================

Loading JWTSecrets from a YAML file
***************************************************

This library provides a ``ConfigurationStep``
(from the library ``django-setup-configuration``, see the
`documentation <https://github.com/maykinmedia/django-setup-configuration>`_
for more information on how to run ``setup_configuration``)
to configure the client credentials.

To add this step to your configuration steps, add ``django_setup_configuration`` to ``INSTALLED_APPS`` and add the following setting:

.. code:: python

SETUP_CONFIGURATION_STEPS = [
...
"vng_api_common.contrib.setup_configuration.steps.JWTSecretsConfigurationStep"
...
]

The YAML file that is passed to ``setup_configuration`` must set the
``vng_api_common_credentials_config_enable`` flag to ``true`` to enable the step. Any number of ``identifier`` and
``secret`` pairs can be defined under ``vng_api_common_credentials.items``

Example file:

.. code:: yaml

vng_api_common_credentials_config_enable: True
vng_api_common_credentials:
items:
- identifier: user-id
secret: super-secret
- identifier: user-id2
secret: super-secret2
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ tests =
zgw-consumers-oas
testutils =
zgw-consumers-oas
setup-configuration =
django-setup-configuration>=0.4.0
pep8 = flake8
coverage = pytest-cov
docs =
Expand Down
1 change: 1 addition & 0 deletions testapp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"simple_certmanager",
"zgw_consumers",
"notifications_api_common",
"django_setup_configuration",
"vng_api_common",
"vng_api_common.authorizations",
"vng_api_common.notifications",
Expand Down
7 changes: 7 additions & 0 deletions tests/files/setup_config_jwtsecrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
vng_api_common_credentials_config_enable: True
vng_api_common_credentials:
items:
- identifier: user-id
secret: super-secret
- identifier: user-id2
secret: super-secret2
62 changes: 62 additions & 0 deletions tests/test_configuration_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import pytest
from django_setup_configuration.test_utils import execute_single_step

from vng_api_common.contrib.setup_configuration.steps import JWTSecretsConfigurationStep
from vng_api_common.models import JWTSecret

CONFIG_FILE_PATH = "tests/files/setup_config_jwtsecrets.yaml"


@pytest.mark.django_db
def test_execute_configuration_step_success():
execute_single_step(JWTSecretsConfigurationStep, yaml_source=CONFIG_FILE_PATH)

assert JWTSecret.objects.count() == 2

credential1, credential2 = JWTSecret.objects.all()

assert credential1.identifier == "user-id"
assert credential1.secret == "super-secret"

assert credential2.identifier == "user-id2"
assert credential2.secret == "super-secret2"


@pytest.mark.django_db
def test_execute_configuration_step_update_existing():
JWTSecret.objects.create(identifier="user-id", secret="old")
JWTSecret.objects.create(identifier="user-id2", secret="old2")

execute_single_step(JWTSecretsConfigurationStep, yaml_source=CONFIG_FILE_PATH)

assert JWTSecret.objects.count() == 2

credential1, credential2 = JWTSecret.objects.all()

assert credential1.identifier == "user-id"
assert credential1.secret == "super-secret"

assert credential2.identifier == "user-id2"
assert credential2.secret == "super-secret2"


@pytest.mark.django_db
def test_execute_configuration_step_idempotent():
def make_assertions():
assert JWTSecret.objects.count() == 2

credential1, credential2 = JWTSecret.objects.all()

assert credential1.identifier == "user-id"
assert credential1.secret == "super-secret"

assert credential2.identifier == "user-id2"
assert credential2.secret == "super-secret2"

execute_single_step(JWTSecretsConfigurationStep, yaml_source=CONFIG_FILE_PATH)

make_assertions()

execute_single_step(JWTSecretsConfigurationStep, yaml_source=CONFIG_FILE_PATH)

make_assertions()
2 changes: 2 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ DJANGO =
extras =
tests
coverage
setup-configuration
deps =
django42: Django~=4.2.0
setenv =
Expand Down Expand Up @@ -52,6 +53,7 @@ extras =
notifications
tests
docs
setup-configuration
commands=
pytest check_sphinx.py -v \
--tb=auto \
Expand Down
Empty file.
Empty file.
18 changes: 18 additions & 0 deletions vng_api_common/contrib/setup_configuration/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django_setup_configuration.models import ConfigurationModel
from pydantic import Field

from vng_api_common.models import JWTSecret


class SingleJWTSecretConfigurationModel(ConfigurationModel):
class Meta:
django_model_refs = {
JWTSecret: [
"identifier",
"secret",
]
}


class JWTSecretsConfigurationModel(ConfigurationModel):
items: list[SingleJWTSecretConfigurationModel] = Field(default_factory=list)
23 changes: 23 additions & 0 deletions vng_api_common/contrib/setup_configuration/steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django_setup_configuration.configuration import BaseConfigurationStep

from vng_api_common.models import JWTSecret

from .models import JWTSecretsConfigurationModel


class JWTSecretsConfigurationStep(BaseConfigurationStep[JWTSecretsConfigurationModel]):
"""
Configure credentials for Applications that need access
"""

verbose_name = "Configuration to create credentials"
config_model = JWTSecretsConfigurationModel
namespace = "vng_api_common_credentials"
enable_setting = "vng_api_common_credentials_config_enable"

def execute(self, model: JWTSecretsConfigurationModel):
for config in model.items:
JWTSecret.objects.update_or_create(
identifier=config.identifier,
defaults={"secret": config.secret},
)
Loading