Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-castellan for
openSUSE:Factory checked in at 2026-03-15 14:32:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-castellan (Old)
and /work/SRC/openSUSE:Factory/.python-castellan.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-castellan"
Sun Mar 15 14:32:05 2026 rev:22 rq:1339016 version:5.6.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-castellan/python-castellan.changes
2026-01-22 15:19:40.475970111 +0100
+++
/work/SRC/openSUSE:Factory/.python-castellan.new.8177/python-castellan.changes
2026-03-15 14:32:47.604441395 +0100
@@ -1,0 +2,19 @@
+Mon Mar 9 21:51:39 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 5.6.0:
+ * barbican: Pass down domain/system scope
+ * Check context instance type directly
+ * barbican: Drop redundant full url composition
+ * Use more explicit import
+ * Bump vault used in tests
+ * Move vault functional tests to noble
+ * tox: Fix missing functional-vault-py310 env
+ * Fix wrong method name
+ * vault: Depreecate ineffective use\_ssl option
+ * Require valid url for vault\_url
+ * Drop redundant description about config sample
+ * vault: Restrict kv\_version
+ * Delay string interpolations at logging calls
+ * Remove reference to tag framework
+
+-------------------------------------------------------------------
Old:
----
castellan-5.5.0.tar.gz
New:
----
castellan-5.6.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-castellan.spec ++++++
--- /var/tmp/diff_new_pack.MzQXp9/_old 2026-03-15 14:32:48.096461648 +0100
+++ /var/tmp/diff_new_pack.MzQXp9/_new 2026-03-15 14:32:48.096461648 +0100
@@ -18,7 +18,7 @@
%global pythons %{primary_python}
Name: python-castellan
-Version: 5.5.0
+Version: 5.6.0
Release: 0
Summary: Generic Key Manager interface for OpenStack
License: Apache-2.0
++++++ castellan-5.5.0.tar.gz -> castellan-5.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/.zuul.yaml
new/castellan-5.6.0/.zuul.yaml
--- old/castellan-5.5.0/.zuul.yaml 2025-11-18 10:21:58.000000000 +0100
+++ new/castellan-5.6.0/.zuul.yaml 2026-02-24 11:37:13.000000000 +0100
@@ -1,12 +1,12 @@
- job:
name: castellan-functional-vault
- parent: openstack-tox-py310
+ parent: openstack-tox
description: |
Run tox functional-vault target
required-projects:
- name: openstack/castellan
vars:
- tox_envlist: functional-vault-py310
+ tox_envlist: functional-vault
- job:
name: castellan-functional-devstack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/AUTHORS new/castellan-5.6.0/AUTHORS
--- old/castellan-5.5.0/AUTHORS 2025-11-18 10:22:58.000000000 +0100
+++ new/castellan-5.6.0/AUTHORS 2026-02-24 11:38:00.000000000 +0100
@@ -76,6 +76,7 @@
Yandong Xuan <[email protected]>
Yushiro FURUKAWA <[email protected]>
Zhao Lei <[email protected]>
+abilash-p <[email protected]>
bhavani.cr <[email protected]>
dane-fichter <[email protected]>
gaofei <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/ChangeLog
new/castellan-5.6.0/ChangeLog
--- old/castellan-5.5.0/ChangeLog 2025-11-18 10:22:58.000000000 +0100
+++ new/castellan-5.6.0/ChangeLog 2026-02-24 11:38:00.000000000 +0100
@@ -1,16 +1,41 @@
CHANGES
=======
+5.6.0
+-----
+
+* barbican: Pass down domain/system scope
+* Check context instance type directly
+* barbican: Drop redundant full url composition
+* Use more explicit import
+* Bump vault used in tests
+* Move vault functional tests to noble
+* tox: Fix missing functional-vault-py310 env
+* Fix wrong method name
+* vault: Depreecate ineffective use\_ssl option
+* Require valid url for vault\_url
+* Drop redundant description about config sample
+* vault: Restrict kv\_version
+* Delay string interpolations at logging calls
+* Remove reference to tag framework
+
5.5.0
-----
* reno: Update master for unmaintained/2024.1
+* Fix hardcoded context string in \_config\_driver.py
+* Make sure [key\_manager] auth\_url is a valid URL
+* Validate [key\_manager] auth\_type at loading
+* barbican: Ensure valid URLs
* Migrate bandit options to pyproject.toml
+* Cleanup intermediate orders and containers
* pre-commit: Bump dependencies
* Migrate setup configuration to pyproject.toml
* Drop Python 3.9 support
* Fix missing session options in [barbican] section
* Update master for stable/2025.2
+* Fix missing argument
+* Drop redundant exception handling
5.4.1
-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/PKG-INFO new/castellan-5.6.0/PKG-INFO
--- old/castellan-5.5.0/PKG-INFO 2025-11-18 10:22:58.782896500 +0100
+++ new/castellan-5.6.0/PKG-INFO 2026-02-24 11:38:00.818245200 +0100
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
Name: castellan
-Version: 5.5.0
+Version: 5.6.0
Summary: Generic Key Manager interface for OpenStack
Author-email: OpenStack <[email protected]>
License: Apache-2.0
@@ -23,7 +23,7 @@
Requires-Dist: pbr>=2.0.0
Requires-Dist: cryptography>=2.7
Requires-Dist: python-barbicanclient>=5.5.0
-Requires-Dist: oslo.config>=6.4.0
+Requires-Dist: oslo.config>=9.3.0
Requires-Dist: oslo.context>=2.19.2
Requires-Dist: oslo.i18n>=3.15.3
Requires-Dist: oslo.log>=3.36.0
@@ -31,11 +31,17 @@
Requires-Dist: stevedore>=1.20.0
Requires-Dist: keystoneauth1>=3.4.0
Requires-Dist: requests>=2.18.0
+Dynamic: license-file
+Dynamic: requires-dist
=========
Castellan
=========
+.. image:: https://governance.openstack.org/tc/badges/castellan.svg
+
+.. Change things from this point on
+
Generic Key Manager interface for OpenStack.
* License: Apache License, Version 2.0
@@ -44,9 +50,3 @@
* Bugs: https://bugs.launchpad.net/castellan
* Release notes: https://docs.openstack.org/releasenotes/castellan
* Wiki: https://wiki.openstack.org/wiki/Castellan
-
-Team and repository tags
-========================
-
-.. image:: https://governance.openstack.org/tc/badges/castellan.svg
- :target: https://governance.openstack.org/tc/reference/tags/index.html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/README.rst
new/castellan-5.6.0/README.rst
--- old/castellan-5.5.0/README.rst 2025-11-18 10:21:58.000000000 +0100
+++ new/castellan-5.6.0/README.rst 2026-02-24 11:37:13.000000000 +0100
@@ -2,6 +2,10 @@
Castellan
=========
+.. image:: https://governance.openstack.org/tc/badges/castellan.svg
+
+.. Change things from this point on
+
Generic Key Manager interface for OpenStack.
* License: Apache License, Version 2.0
@@ -10,9 +14,3 @@
* Bugs: https://bugs.launchpad.net/castellan
* Release notes: https://docs.openstack.org/releasenotes/castellan
* Wiki: https://wiki.openstack.org/wiki/Castellan
-
-Team and repository tags
-========================
-
-.. image:: https://governance.openstack.org/tc/badges/castellan.svg
- :target: https://governance.openstack.org/tc/reference/tags/index.html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan/_config_driver.py
new/castellan-5.6.0/castellan/_config_driver.py
--- old/castellan-5.5.0/castellan/_config_driver.py 2025-11-18
10:21:58.000000000 +0100
+++ new/castellan-5.6.0/castellan/_config_driver.py 2026-02-24
11:37:13.000000000 +0100
@@ -42,8 +42,10 @@
.. autoclass:: CastellanConfigurationSource
"""
+from castellan.common.exception import AuthTypeInvalidError
from castellan.common.exception import KeyManagerError
from castellan.common.exception import ManagedObjectNotFoundError
+from castellan.common import utils
from castellan import key_manager
from oslo_config import cfg
@@ -110,6 +112,17 @@
self._mngr = key_manager.API(conf)
self._mapping = {}
+ try:
+ self._context = utils.credential_factory(conf)
+ except AuthTypeInvalidError:
+ self._context = None
+
+ LOG.warning("Invalid 'auth_type' in '%s', auth_type: %s. "
+ "Context set to 'None'. Supported 'auth_type' values: "
+ "'token', 'password', 'keystone_token', "
+ "'keystone_password'.",
+ config_file, conf.key_manager.auth_type)
+
cfg.ConfigParser(mapping_file, self._mapping).parse()
def get(self, group_name, option_name, opt):
@@ -118,7 +131,8 @@
castellan_id = self._mapping[group_name][option_name][0]
- return (self._mngr.get("ctx", castellan_id).get_encoded().decode(),
+ return (self._mngr.get(self._context, castellan_id)
+ .get_encoded().decode(),
cfg.LocationInfo(cfg.Locations.user, castellan_id))
except KeyError:
@@ -127,10 +141,10 @@
group_name, option_name, self._name)
except KeyManagerError:
- # bad mapping 'option =' without a castellan_id
- LOG.error("missing castellan_id for option '[%s] %s' in '[%s] "
- "mapping_file'",
- group_name, option_name, self._name)
+ # error retrieving the secret from the key manager
+ LOG.exception("Failed to retrieve secret for option '[%s] %s' in "
+ "'[%s] mapping_file'",
+ group_name, option_name, self._name)
except ManagedObjectNotFoundError:
# good mapping, but unknown castellan_id by secret manager
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan/common/exception.py
new/castellan-5.6.0/castellan/common/exception.py
--- old/castellan-5.5.0/castellan/common/exception.py 2025-11-18
10:21:58.000000000 +0100
+++ new/castellan-5.6.0/castellan/common/exception.py 2026-02-24
11:37:13.000000000 +0100
@@ -17,7 +17,7 @@
Castellan exception subclasses
"""
-import urllib
+import urllib.parse
from castellan.i18n import _
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan/common/utils.py
new/castellan-5.6.0/castellan/common/utils.py
--- old/castellan-5.5.0/castellan/common/utils.py 2025-11-18
10:21:58.000000000 +0100
+++ new/castellan-5.6.0/castellan/common/utils.py 2026-02-24
11:37:13.000000000 +0100
@@ -30,11 +30,13 @@
credential_opts = [
# auth_type opt
- cfg.StrOpt('auth_type',
- help="The type of authentication credential to create. "
- "Possible values are 'token', 'password', 'keystone_token', "
- "and 'keystone_password'. Required if no context is passed to "
- "the credential factory."),
+ cfg.StrOpt(
+ 'auth_type',
+ choices=(
+ 'token', 'password', 'keystone_token', 'keystone_password'
+ ),
+ help="The type of authentication credential to create. "
+ "Required if no context is passed to the credential factory."),
# token opt
cfg.StrOpt('token', secret=True,
@@ -51,7 +53,7 @@
"'keystone_password' auth_type."),
# keystone credential opts
- cfg.StrOpt('auth_url',
+ cfg.URIOpt('auth_url',
help="Use this endpoint to connect to Keystone."),
cfg.StrOpt('user_id',
help="User ID for authentication. Optional for "
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/castellan-5.5.0/castellan/key_manager/barbican_key_manager.py
new/castellan-5.6.0/castellan/key_manager/barbican_key_manager.py
--- old/castellan-5.5.0/castellan/key_manager/barbican_key_manager.py
2025-11-18 10:21:58.000000000 +0100
+++ new/castellan-5.6.0/castellan/key_manager/barbican_key_manager.py
2026-02-24 11:37:13.000000000 +0100
@@ -18,8 +18,9 @@
"""
import calendar
import time
-import urllib
+from barbicanclient import client as barbican_client_import
+from barbicanclient import exceptions as barbican_exceptions
from cryptography.hazmat import backends
from cryptography.hazmat.primitives import serialization
from cryptography import x509 as cryptography_x509
@@ -28,27 +29,27 @@
from keystoneauth1 import service_token
from keystoneauth1 import session
from oslo_config import cfg
+from oslo_context import context as oslo_context
from oslo_log import log as logging
from oslo_utils import excutils
+from oslo_utils import timeutils
+from castellan.common.credentials import keystone_password
+from castellan.common.credentials import keystone_token
from castellan.common import exception
from castellan.common.objects import key as key_base_class
from castellan.common.objects import opaque_data as op_data
from castellan.i18n import _
from castellan.key_manager import key_manager
-from barbicanclient import client as barbican_client_import
-from barbicanclient import exceptions as barbican_exceptions
-from oslo_utils import timeutils
-
_barbican_opts = [
- cfg.StrOpt('barbican_endpoint',
+ cfg.URIOpt('barbican_endpoint',
help='Use this endpoint to connect to Barbican, for example: '
'"http://localhost:9311/"'),
cfg.StrOpt('barbican_api_version',
help='Version of the Barbican API, for example: "v1"'),
- cfg.StrOpt('auth_endpoint',
+ cfg.URIOpt('auth_endpoint',
default='http://localhost/identity/v3',
deprecated_name='auth_url',
deprecated_group='key_manager',
@@ -122,7 +123,7 @@
"""Creates a client to connect to the Barbican service.
:param context: the user context for authentication
- :return: tuple of a Barbican Client object and its endpoint
+ :return: a Barbican Client object
:raises Forbidden: if the context is None
:raises KeyManagerError: if context is missing tenant or tenant is
None or error occurs while creating client
@@ -139,13 +140,10 @@
sess = session.Session(auth=auth, verify=self._verify)
endpoint = self._get_barbican_endpoint(auth, sess)
- return (
- barbican_client_import.Client(
- version=self.conf.barbican.barbican_api_version,
- session=sess,
- endpoint=endpoint),
- self._create_base_url(auth, sess, endpoint)
- )
+ return barbican_client_import.Client(
+ version=self.conf.barbican.barbican_api_version,
+ session=sess,
+ endpoint=endpoint)
# TODO(pbourke): more fine grained exception handling - we are eating
# tracebacks here
@@ -154,7 +152,7 @@
raise exception.KeyManagerError(reason=e)
def _get_keystone_auth(self, context):
- if context.__class__.__name__ == 'KeystonePassword':
+ if isinstance(context, keystone_password.KeystonePassword):
auth = identity.Password(
auth_url=context.auth_url,
username=context.username,
@@ -170,7 +168,7 @@
project_domain_id=context.project_domain_id,
project_domain_name=context.project_domain_name,
reauthenticate=context.reauthenticate)
- elif context.__class__.__name__ == 'KeystoneToken':
+ elif isinstance(context, keystone_token.KeystoneToken):
auth = identity.Token(
auth_url=context.auth_url,
token=context.token,
@@ -184,7 +182,7 @@
reauthenticate=context.reauthenticate)
# this will be kept for oslo.context compatibility until
# projects begin to use utils.credential_factory
- elif context.__class__.__name__ == 'RequestContext':
+ elif isinstance(context, oslo_context.RequestContext):
if getattr(context, 'get_auth_plugin', None):
auth = context.get_auth_plugin()
else:
@@ -194,7 +192,10 @@
project_id=context.project_id,
project_name=context.project_name,
project_domain_id=context.project_domain_id,
- project_domain_name=context.project_domain_name)
+ project_domain_name=context.project_domain_name,
+ domain_id=context.domain_id,
+ domain_name=context.domain_name,
+ system_scope=context.system_scope)
else:
msg = _("context must be of type KeystonePassword, "
"KeystoneToken, or RequestContext.")
@@ -227,33 +228,19 @@
interface=self.conf.barbican.barbican_endpoint_type,
region_name=self.conf.barbican.barbican_region_name)
- def _create_base_url(self, auth, sess, endpoint):
- api_version = None
- if self.conf.barbican.barbican_api_version:
- api_version = self.conf.barbican.barbican_api_version
- elif getattr(auth, 'service_catalog', None):
- endpoint_data = auth.service_catalog.endpoint_data_for(
- service_type='key-manager',
- interface=self.conf.barbican.barbican_endpoint_type,
- region_name=self.conf.barbican.barbican_region_name)
- api_version = endpoint_data.api_version
- elif getattr(auth, 'get_discovery', None):
- discovery = auth.get_discovery(sess, url=endpoint)
- raw_data = discovery.raw_version_data()
- if len(raw_data) == 0:
- msg = _(
- "Could not find discovery information for %s") % endpoint
- LOG.error(msg)
- raise exception.KeyManagerError(reason=msg)
- latest_version = raw_data[-1]
- api_version = latest_version.get('id')
-
- if endpoint[-1] != '/':
- endpoint += '/'
-
- base_url = urllib.parse.urljoin(endpoint, api_version)
+ def _delete_order(self, client, order_ref):
+ try:
+ client.orders.delete(order_ref)
+ except Exception as e:
+ LOG.warning("Failed to delete temporary order %s: %s",
+ order_ref, e)
- return base_url
+ def _delete_container(self, client, container_ref):
+ try:
+ client.containers.delete(container_ref)
+ except Exception as e:
+ LOG.warning("Failed to delete temporary container %s: %s",
+ container_ref, e)
def create_key(self, context, algorithm, length,
expiration=None, name=None):
@@ -268,7 +255,7 @@
:return: the UUID of the new key
:raises KeyManagerError: if key creation fails
"""
- barbican_client, _ = self._get_barbican_client(context)
+ barbican_client = self._get_barbican_client(context)
try:
key_order = barbican_client.orders.create_key(
@@ -278,7 +265,9 @@
expiration=expiration)
order_ref = key_order.submit()
order = self._get_active_order(barbican_client, order_ref)
- return self._retrieve_secret_uuid(order.secret_ref)
+ secret_ref = self._retrieve_secret_uuid(order.secret_ref)
+ self._delete_order(barbican_client, order_ref)
+ return secret_ref
except (barbican_exceptions.HTTPAuthError,
barbican_exceptions.HTTPClientError,
barbican_exceptions.HTTPServerError) as e:
@@ -299,7 +288,7 @@
:raises NotImplementedError: until implemented
:raises KeyManagerError: if key pair creation fails
"""
- barbican_client, _ = self._get_barbican_client(context)
+ barbican_client = self._get_barbican_client(context)
try:
key_pair_order = barbican_client.orders.create_asymmetric(
@@ -316,6 +305,8 @@
container.secret_refs['private_key'])
public_key_uuid = self._retrieve_secret_uuid(
container.secret_refs['public_key'])
+ self._delete_container(barbican_client, order.container_ref)
+ self._delete_order(barbican_client, order_ref)
return private_key_uuid, public_key_uuid
except (barbican_exceptions.HTTPAuthError,
barbican_exceptions.HTTPClientError,
@@ -388,7 +379,7 @@
:returns: the UUID of the stored object
:raises KeyManagerError: if object store fails
"""
- barbican_client, _ = self._get_barbican_client(context)
+ barbican_client = self._get_barbican_client(context)
try:
secret = self._get_barbican_object(barbican_client,
@@ -402,20 +393,6 @@
LOG.error("Error storing object: %s", e)
raise exception.KeyManagerError(reason=e)
- def _create_secret_ref(self, base_url, object_id):
- """Creates the URL required for accessing a secret.
-
- :param endpoint: Base endpoint URL
- :param object_id: the UUID of the key to copy
- :return: the URL of the requested secret
- """
- if not object_id:
- msg = _("Key ID is None")
- raise exception.KeyManagerError(reason=msg)
- if base_url[-1] != '/':
- base_url += '/'
- return urllib.parse.urljoin(base_url, "secrets/" + object_id)
-
def _get_active_order(self, barbican_client, order_ref):
"""Returns the order when it is active.
@@ -569,12 +546,13 @@
:raises HTTPClientError: if object retrieval fails with 4xx
:raises HTTPServerError: if object retrieval fails with 5xx
"""
+ if not object_id:
+ raise exception.KeyManagerError('key identifier not provided')
- barbican_client, base_url = self._get_barbican_client(context)
+ barbican_client = self._get_barbican_client(context)
try:
- secret_ref = self._create_secret_ref(base_url, object_id)
- return barbican_client.secrets.get(secret_ref)
+ return barbican_client.secrets.get(object_id)
except (barbican_exceptions.HTTPAuthError,
barbican_exceptions.HTTPClientError,
barbican_exceptions.HTTPServerError) as e:
@@ -625,10 +603,12 @@
:raises KeyManagerError: if object deletion fails
:raises ManagedObjectNotFoundError: if the object could not be found
"""
- barbican_client, base_url = self._get_barbican_client(context)
+ if not managed_object_id:
+ raise exception.KeyManagerError('key identifier not provided')
+
+ barbican_client = self._get_barbican_client(context)
try:
- secret_ref = self._create_secret_ref(base_url, managed_object_id)
- barbican_client.secrets.delete(secret_ref, force)
+ barbican_client.secrets.delete(managed_object_id, force)
except (barbican_exceptions.HTTPAuthError,
barbican_exceptions.HTTPClientError,
barbican_exceptions.HTTPServerError) as e:
@@ -650,11 +630,13 @@
:raises ManagedObjectNotFoundError: if the object could not be found
"""
- barbican_client, base_url = self._get_barbican_client(context)
+ if not managed_object_id:
+ raise exception.KeyManagerError('key identifier not provided')
+
+ barbican_client = self._get_barbican_client(context)
try:
- secret_ref = self._create_secret_ref(base_url, managed_object_id)
barbican_client.secrets.register_consumer(
- secret_ref, **consumer_data)
+ managed_object_id, **consumer_data)
except (barbican_exceptions.HTTPAuthError,
barbican_exceptions.HTTPClientError,
@@ -667,12 +649,13 @@
raise exception.KeyManagerError(reason=e)
def remove_consumer(self, context, managed_object_id, consumer_data):
+ if not managed_object_id:
+ raise exception.KeyManagerError('key identifier not provided')
- barbican_client, base_url = self._get_barbican_client(context)
+ barbican_client = self._get_barbican_client(context)
try:
- secret_ref = self._create_secret_ref(base_url, managed_object_id)
barbican_client.secrets.remove_consumer(
- secret_ref, **consumer_data)
+ managed_object_id, **consumer_data)
except (barbican_exceptions.HTTPAuthError,
barbican_exceptions.HTTPClientError,
barbican_exceptions.HTTPServerError) as e:
@@ -695,7 +678,7 @@
:raises KeyManagerError: if listing secrets fails
"""
objects = []
- barbican_client, _ = self._get_barbican_client(context)
+ barbican_client = self._get_barbican_client(context)
if object_type and object_type not in self._secret_type_dict:
msg = _("Invalid secret type: %s") % object_type
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/castellan-5.5.0/castellan/key_manager/vault_key_manager.py
new/castellan-5.6.0/castellan/key_manager/vault_key_manager.py
--- old/castellan-5.5.0/castellan/key_manager/vault_key_manager.py
2025-11-18 10:21:58.000000000 +0100
+++ new/castellan-5.6.0/castellan/key_manager/vault_key_manager.py
2026-02-24 11:37:13.000000000 +0100
@@ -54,23 +54,24 @@
help='AppRole secret_id for authentication with vault'),
cfg.StrOpt('kv_mountpoint',
default=_DEFAULT_MOUNTPOINT,
- help='Mountpoint of KV store in Vault to use, for example: '
- '{}'.format(_DEFAULT_MOUNTPOINT)),
+ help='Mountpoint of KV store in Vault to use'),
cfg.StrOpt('kv_path',
help='Path relative to root of KV store in Vault to use.'
),
cfg.IntOpt('kv_version',
default=_DEFAULT_VERSION,
- help='Version of KV store in Vault to use, for example: '
- '{}'.format(_DEFAULT_VERSION)),
- cfg.StrOpt('vault_url',
+ choices=(1, 2),
+ help='Version of KV store in Vault to use.'),
+ cfg.URIOpt('vault_url',
default=_DEFAULT_VAULT_URL,
- help='Use this endpoint to connect to Vault, for example: '
- '"%s"' % _DEFAULT_VAULT_URL),
+ schemes=('http', 'https'),
+ help='Use this endpoint to connect to Vault'),
cfg.StrOpt('ssl_ca_crt_file',
help='Absolute path to ca cert file'),
cfg.BoolOpt('use_ssl',
default=False,
+ deprecated_for_removal=True,
+ deprecated_reason='This option has no effect.',
help=_('SSL Enabled/Disabled')),
cfg.StrOpt("namespace",
help=_("Vault Namespace to use for all requests to Vault. "
@@ -173,10 +174,6 @@
headers=headers,
verify=self._verify_server,
timeout=self._timeout)
- except requests.exceptions.Timeout as ex:
- raise exception.KeyManagerError(str(ex))
- except requests.exceptions.ConnectionError as ex:
- raise exception.KeyManagerError(str(ex))
except Exception as ex:
raise exception.KeyManagerError(str(ex))
@@ -204,10 +201,6 @@
try:
resp = method(resource, headers=headers, json=json,
verify=self._verify_server, timeout=self._timeout)
- except requests.exceptions.Timeout as ex:
- raise exception.KeyManagerError(str(ex))
- except requests.exceptions.ConnectionError as ex:
- raise exception.KeyManagerError(str(ex))
except Exception as ex:
raise exception.KeyManagerError(str(ex))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan/options.py
new/castellan-5.6.0/castellan/options.py
--- old/castellan-5.5.0/castellan/options.py 2025-11-18 10:21:58.000000000
+0100
+++ new/castellan-5.6.0/castellan/options.py 2026-02-24 11:37:13.000000000
+0100
@@ -12,10 +12,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-from stevedore import ExtensionManager
+import warnings
from oslo_config import cfg
from oslo_log import log
+from stevedore import ExtensionManager
from castellan import key_manager
from castellan.key_manager import barbican_key_manager as bkm
@@ -126,8 +127,8 @@
conf.set_default('ssl_ca_crt_file', vault_ssl_ca_crt_file,
group=vkm._VAULT_OPT_GROUP)
if vault_use_ssl is not None:
- conf.set_default('use_ssl', vault_use_ssl,
- group=vkm._VAULT_OPT_GROUP)
+ warnings.warn('use_ssl option is deprecated',
+ category=DeprecationWarning)
if vault_namespace is not None:
conf.set_default('namespace', vault_namespace,
group=vkm._VAULT_OPT_GROUP)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/castellan-5.5.0/castellan/tests/unit/key_manager/mock_key_manager.py
new/castellan-5.6.0/castellan/tests/unit/key_manager/mock_key_manager.py
--- old/castellan-5.5.0/castellan/tests/unit/key_manager/mock_key_manager.py
2025-11-18 10:21:58.000000000 +0100
+++ new/castellan-5.6.0/castellan/tests/unit/key_manager/mock_key_manager.py
2026-02-24 11:37:13.000000000 +0100
@@ -181,7 +181,7 @@
try:
obj = copy.deepcopy(self.keys[managed_object_id])
except KeyError:
- raise exception.ManagedObjectNotFoundError()
+ raise exception.ManagedObjectNotFoundError(managed_object_id)
if metadata_only:
if hasattr(obj, "_key"):
@@ -204,20 +204,20 @@
try:
del self.keys[managed_object_id]
except KeyError:
- raise exception.ManagedObjectNotFoundError()
+ raise exception.ManagedObjectNotFoundError(managed_object_id)
def add_consumer(self, context, managed_object_id, consumer_data):
if context is None:
raise exception.Forbidden()
if managed_object_id not in self.keys:
- raise exception.ManagedObjectNotFoundError()
+ raise exception.ManagedObjectNotFoundError(managed_object_id)
self.keys[managed_object_id].consumers.append(consumer_data)
def remove_consumer(self, context, managed_object_id, consumer_data):
if context is None:
raise exception.Forbidden()
if managed_object_id not in self.keys:
- raise exception.ManagedObjectNotFoundError()
+ raise exception.ManagedObjectNotFoundError(managed_object_id)
self.keys[managed_object_id].consumers = [
c for c in self.keys[managed_object_id].consumers
if c != consumer_data]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/castellan-5.5.0/castellan/tests/unit/key_manager/test_barbican_key_manager.py
new/castellan-5.6.0/castellan/tests/unit/key_manager/test_barbican_key_manager.py
---
old/castellan-5.5.0/castellan/tests/unit/key_manager/test_barbican_key_manager.py
2025-11-18 10:21:58.000000000 +0100
+++
new/castellan-5.6.0/castellan/tests/unit/key_manager/test_barbican_key_manager.py
2026-02-24 11:37:13.000000000 +0100
@@ -48,10 +48,13 @@
self.ctxt.project_id = str(uuid.uuid4()).replace('-', '')
self.ctxt.project_domain_name = "foo"
self.ctxt.project_domain_id = str(uuid.uuid4()).replace('-', '')
+ self.ctxt.domain_id = None
+ self.ctxt.domain_name = None
+ self.ctxt.system_scope = None
# Create a key_id, secret_ref, pre_hex, and hex to use
self.key_id = "d152fa13-2b41-42ca-a934-6c21566c0f40"
- self.secret_ref = ("http://host:9311/v1/secrets/" + self.key_id)
+ self.secret_ref = self.key_id
self.pre_hex = "AIDxQp2++uAbKaTVDMXFYIu8PIugJGqkK0JLqkU0rhY="
self.hex = ("0080f1429dbefae01b29a4d50cc5c5608bbc3c8ba0246aa42b424baa4"
"534ae16")
@@ -156,115 +159,11 @@
auth = self.key_mgr._get_keystone_auth(self.ctxt)
self.assertIsInstance(auth, service_token.ServiceTokenAuthWrapper)
- def test_base_url_old_version(self):
- version = "v1"
- self.key_mgr.conf.barbican.barbican_api_version = version
- endpoint = "http://localhost:9311"
- base_url = self.key_mgr._create_base_url(mock.Mock(),
- mock.Mock(),
- endpoint)
- self.assertEqual(endpoint + "/" + version, base_url)
-
- def test_base_url_new_version(self):
- version = "v1"
- self.key_mgr.conf.barbican.barbican_api_version = version
- endpoint = "http://localhost/key_manager"
- base_url = self.key_mgr._create_base_url(mock.Mock(),
- mock.Mock(),
- endpoint)
- self.assertEqual(endpoint + "/" + version, base_url)
-
- def test_base_url_service_catalog(self):
- endpoint_data = mock.Mock()
- endpoint_data.api_version = 'v321'
-
- auth = mock.Mock(spec=['service_catalog'])
- auth.service_catalog.endpoint_data_for.return_value = endpoint_data
-
- endpoint = "http://localhost/key_manager"
-
- base_url = self.key_mgr._create_base_url(auth,
- mock.Mock(),
- endpoint)
- self.assertEqual(endpoint + "/" + endpoint_data.api_version, base_url)
- auth.service_catalog.endpoint_data_for.assert_called_once_with(
- service_type='key-manager', interface='public',
- region_name=None)
-
- def test_base_url_service_catalog_with_endpoint_type(self):
- self.key_mgr.conf.barbican.barbican_endpoint_type = 'internal'
-
- endpoint_data = mock.Mock()
- endpoint_data.api_version = 'v321'
-
- auth = mock.Mock(spec=['service_catalog'])
- auth.service_catalog.endpoint_data_for.return_value = endpoint_data
-
- endpoint = "http://localhost/key_manager"
-
- base_url = self.key_mgr._create_base_url(auth,
- mock.Mock(),
- endpoint)
- self.assertEqual(endpoint + "/" + endpoint_data.api_version, base_url)
- auth.service_catalog.endpoint_data_for.assert_called_once_with(
- service_type='key-manager', interface='internal',
- region_name=None)
-
- def test_base_url_service_catalog_with_region_name(self):
- self.key_mgr.conf.barbican.barbican_region_name = 'regionOne'
-
- endpoint_data = mock.Mock()
- endpoint_data.api_version = 'v321'
- auth = mock.Mock(spec=['service_catalog'])
- auth.service_catalog.endpoint_data_for.return_value = endpoint_data
-
- endpoint = "http://localhost/key_manager"
-
- base_url = self.key_mgr._create_base_url(auth,
- mock.Mock(),
- endpoint)
- self.assertEqual(endpoint + "/" + endpoint_data.api_version, base_url)
- auth.service_catalog.endpoint_data_for.assert_called_once_with(
- service_type='key-manager', interface='public',
- region_name='regionOne')
-
- def test_base_url_raise_exception(self):
- auth = mock.Mock(spec=['get_discovery'])
- sess = mock.Mock()
- discovery = mock.Mock()
- discovery.raw_version_data = mock.Mock(return_value=[])
- auth.get_discovery = mock.Mock(return_value=discovery)
-
- endpoint = "http://localhost/key_manager"
-
- self.assertRaises(exception.KeyManagerError,
- self.key_mgr._create_base_url,
- auth, sess, endpoint)
- auth.get_discovery.assert_called_once_with(sess, url=endpoint)
- self.assertEqual(1, discovery.raw_version_data.call_count)
-
- def test_base_url_get_discovery(self):
- version = 'v100500'
- auth = mock.Mock(spec=['get_discovery'])
- sess = mock.Mock()
- discovery = mock.Mock()
- auth.get_discovery = mock.Mock(return_value=discovery)
- discovery.raw_version_data = mock.Mock(return_value=[{'id': version}])
-
- endpoint = "http://localhost/key_manager"
-
- base_url = self.key_mgr._create_base_url(auth,
- sess,
- endpoint)
- self.assertEqual(endpoint + "/" + version, base_url)
- auth.get_discovery.assert_called_once_with(sess, url=endpoint)
- self.assertEqual(1, discovery.raw_version_data.call_count)
-
@mock.patch('castellan.key_manager.barbican_key_manager.'
'BarbicanKeyManager._get_barbican_client')
def test_create_key(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
# Create order_ref_url and assign return value
order_ref_url = ("http://localhost:9311/v1/orders/"
@@ -285,6 +184,7 @@
length=256)
mock_client.orders.get.assert_called_once_with(order_ref_url)
+ mock_client.orders.delete.assert_called_once_with(order_ref_url)
self.assertEqual(self.key_id, returned_uuid)
def test_create_key_null_context(self):
@@ -295,7 +195,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_create_key_with_error(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
key_order = mock.Mock()
mock_client.orders.create_key.return_value = key_order
@@ -306,9 +206,38 @@
@mock.patch('castellan.key_manager.barbican_key_manager.'
'BarbicanKeyManager._get_barbican_client')
+ def test_create_key_with_error_delete_order(self, mock_get_client):
+ mock_client = mock.Mock()
+ mock_get_client.return_value = mock_client
+
+ # Create order_ref_url and assign return value
+ order_ref_url = ("http://localhost:9311/v1/orders/"
+ "4fe939b7-72bc-49aa-bd1e-e979589858af")
+ key_order = mock.Mock()
+ mock_client.orders.create_key.return_value = key_order
+ mock_client.orders.delete.side_effect = Exception("SPAM!")
+ key_order.submit.return_value = order_ref_url
+
+ # Create order and assign return value
+ order = mock.Mock()
+ order.secret_ref = self.secret_ref
+ order.status = 'ACTIVE'
+ mock_client.orders.get.return_value = order
+
+ # Create the key, get the UUID
+ returned_uuid = self.key_mgr.create_key(self.ctxt,
+ algorithm='AES',
+ length=256)
+
+ mock_client.orders.get.assert_called_once_with(order_ref_url)
+ mock_client.orders.delete.assert_called_once_with(order_ref_url)
+ self.assertEqual(self.key_id, returned_uuid)
+
+ @mock.patch('castellan.key_manager.barbican_key_manager.'
+ 'BarbicanKeyManager._get_barbican_client')
def test_create_key_pair(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
# Create order_ref_url and assign return value
order_ref_url = ("http://localhost:9311/v1/orders/"
@@ -344,8 +273,8 @@
mock_client.orders.get.assert_called_once_with(order_ref_url)
mock_client.containers.get.assert_called_once_with(
container_ref)
-
- mock_client.orders.get.assert_called_once_with(order_ref_url)
+ mock_client.orders.delete.assert_called_once_with(order_ref_url)
+ mock_client.containers.delete.assert_called_once_with(container_ref)
self.assertEqual(private_key_id, returned_private_uuid)
self.assertEqual(public_key_id, returned_public_uuid)
@@ -357,7 +286,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_create_key_pair_with_error(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
asym_order = mock.Mock()
mock_client.orders.create_asymmetric.return_value = asym_order
@@ -366,6 +295,56 @@
self.assertRaises(exception.KeyManagerError,
self.key_mgr.create_key_pair, self.ctxt, 'RSA', 2048)
+ @mock.patch('castellan.key_manager.barbican_key_manager.'
+ 'BarbicanKeyManager._get_barbican_client')
+ def test_create_key_pair_error_in_delete_order_container(self,
+ mock_get_client):
+ mock_client = mock.Mock()
+ mock_get_client.return_value = mock_client
+
+ # Create order_ref_url and assign return value
+ order_ref_url = ("http://localhost:9311/v1/orders/"
+ "f45bf211-a917-4ead-9aec-1c91e52609df")
+ asym_order = mock.Mock()
+ mock_client.orders.create_asymmetric.return_value = asym_order
+ asym_order.submit.return_value = order_ref_url
+
+ # Create order and assign return value
+ order = mock.Mock()
+ container_id = "16caa8f4-dd34-4fb3-bf67-6c20533a30e4"
+ container_ref = ("http://localhost:9311/v1/containers/" + container_id)
+ order.container_ref = container_ref
+ order.status = 'ACTIVE'
+ mock_client.orders.get.return_value = order
+ mock_client.orders.delete.side_effect = Exception("SPAM!")
+
+ # Create container and assign return value
+ container = mock.Mock()
+ public_key_id = "43ed09c3-e551-4c24-b612-e619abe9b534"
+ pub_key_ref = ("http://localhost:9311/v1/secrets/" + public_key_id)
+ private_key_id = "32a0bc60-4e10-4269-9f17-f49767e99586"
+ priv_key_ref = ("http://localhost:9311/v1/secrets/" + private_key_id)
+ container.secret_refs = {'public_key': pub_key_ref,
+ 'private_key': priv_key_ref}
+ mock_client.containers.get.return_value = container
+ mock_client.containers.delete.side_effect = Exception("HAM!")
+
+ # Create the keys, get the UUIDs
+ returned_private_uuid, returned_public_uuid = (
+ self.key_mgr.create_key_pair(self.ctxt,
+ algorithm='RSA',
+ length=2048))
+
+ mock_client.orders.get.assert_called_once_with(order_ref_url)
+ mock_client.containers.get.assert_called_once_with(
+ container_ref)
+ mock_client.orders.delete.assert_called_once_with(order_ref_url)
+ mock_client.containers.delete.assert_called_once_with(
+ container_ref)
+
+ self.assertEqual(private_key_id, returned_private_uuid)
+ self.assertEqual(public_key_id, returned_public_uuid)
+
def test_delete_null_context(self):
self.assertRaises(exception.Forbidden,
self.key_mgr.delete, None, self.key_id)
@@ -374,7 +353,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_delete_key(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
self.key_mgr.delete(self.ctxt, self.key_id)
mock_client.secrets.delete.assert_called_once_with(
@@ -385,7 +364,7 @@
def test_delete_secret_with_consumers_no_force_parameter(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
mock_client.secrets.delete = mock.Mock(
side_effect=exception.KeyManagerError(
@@ -400,7 +379,7 @@
def test_delete_secret_with_consumers_force_parameter_false(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
mock_client.secrets.delete.side_effect = \
barbican_exceptions.HTTPClientError(
@@ -416,7 +395,7 @@
def test_delete_secret_with_consumers_force_parameter_true(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
self.key_mgr.delete(self.ctxt, self.key_id, force=True)
mock_client.secrets.delete.assert_called_once_with(
@@ -430,7 +409,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_delete_with_error(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
mock_client.secrets.delete = mock.Mock(
side_effect=barbican_exceptions.HTTPClientError('test error'))
self.assertRaises(exception.KeyManagerError,
@@ -440,7 +419,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_get_key(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
original_secret_metadata = mock.Mock()
original_secret_metadata.algorithm = mock.sentinel.alg
@@ -483,7 +462,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_get_with_error(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
mock_client.secrets.get.side_effect = \
barbican_exceptions.HTTPClientError('test error')
self.assertRaises(exception.KeyManagerError,
@@ -493,7 +472,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_store_key(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
# Create Key to store
secret_key = bytes(b'\x01\x02\xA0\xB3')
@@ -522,7 +501,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_store_key_with_name(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
# Create Key to store
secret_key = bytes(b'\x01\x02\xA0\xB3')
@@ -557,7 +536,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_store_with_error(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
mock_client.secrets.create.side_effect = \
barbican_exceptions.HTTPClientError('test error')
secret_key = bytes(b'\x01\x02\xA0\xB3')
@@ -572,7 +551,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_get_active_order(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
order_ref_url = ("http://localhost:9311/v1/orders/"
"4fe939b7-72bc-49aa-bd1e-e979589858af")
@@ -599,7 +578,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_get_active_order_timeout(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
order_ref_url = ("http://localhost:9311/v1/orders/"
"4fe939b7-72bc-49aa-bd1e-e979589858af")
@@ -624,7 +603,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_get_active_order_error(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
order_ref_url = ("http://localhost:9311/v1/orders/"
"4fe939b7-72bc-49aa-bd1e-e979589858af")
@@ -652,7 +631,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_list(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
original_secret_metadata = mock.Mock()
original_secret_metadata.algorithm = mock.sentinel.alg
@@ -704,7 +683,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_list_with_error(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
mock_client.secrets.list = mock.Mock(
side_effect=barbican_exceptions.HTTPClientError('test error'))
self.assertRaises(exception.KeyManagerError,
@@ -774,7 +753,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_add_consumer_with_different_project_fails(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Forbidden: SecretConsumer creation attempt not allowed - "
@@ -808,7 +787,7 @@
def test_add_consumer_with_invalid_managed_object_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = ValueError("Secret incorrectly specified.")
self._test_add_consumer_expects_error(
@@ -820,7 +799,7 @@
def test_add_consumer_with_inexistent_managed_object_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Not Found: Secret not found.", status_code=404)
@@ -833,7 +812,7 @@
def test_add_consumer_with_null_service_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -848,7 +827,7 @@
def test_add_consumer_with_empty_service_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -863,7 +842,7 @@
def test_add_consumer_with_null_resource_type_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -878,7 +857,7 @@
def test_add_consumer_with_empty_resource_type_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -893,7 +872,7 @@
def test_add_consumer_with_null_resource_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -908,7 +887,7 @@
def test_add_consumer_with_empty_resource_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -923,7 +902,7 @@
def test_add_consumer_with_valid_parameters_doesnt_fail(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
self.key_mgr.add_consumer(
self.ctxt, self.secret_ref, self._get_custom_consumer_data())
@@ -938,7 +917,7 @@
def test_remove_consumer_with_different_project_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Forbidden: SecretConsumer creation attempt not allowed - "
@@ -952,7 +931,7 @@
def test_remove_consumer_with_null_managed_object_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = ValueError("secret incorrectly specified.")
self._test_add_consumer_expects_error(
@@ -964,7 +943,7 @@
def test_remove_consumer_with_empty_managed_object_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = ValueError("secret incorrectly specified.")
self._test_add_consumer_expects_error(
@@ -976,7 +955,7 @@
def test_remove_consumer_with_invalid_managed_object_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = ValueError("Secret incorrectly specified.")
self._test_add_consumer_expects_error(
@@ -988,7 +967,7 @@
def test_remove_consumer_without_registered_managed_object_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Not Found: Secret not found.", status_code=404)
@@ -1000,7 +979,7 @@
'BarbicanKeyManager._get_barbican_client')
def test_remove_consumer_with_null_service_fails(self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -1015,7 +994,7 @@
def test_remove_consumer_with_empty_service_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -1030,7 +1009,7 @@
def test_remove_consumer_with_null_resource_type_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -1045,7 +1024,7 @@
def test_remove_consumer_with_empty_resource_type_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -1060,7 +1039,7 @@
def test_remove_consumer_with_null_resource_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -1075,7 +1054,7 @@
def test_remove_consumer_with_empty_resource_id_fails(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
side_effect = barbican_exceptions.HTTPClientError(
"Bad Request: Provided object does not match schema "
@@ -1090,6 +1069,6 @@
def test_remove_consumer_with_valid_parameters_doesnt_fail(
self, mock_get_client):
mock_client = mock.Mock()
- mock_get_client.return_value = (mock_client, self.base_url)
+ mock_get_client.return_value = mock_client
self.key_mgr.remove_consumer(
self.ctxt, self.secret_ref, self._get_custom_consumer_data())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/castellan-5.5.0/castellan/tests/unit/test_config_driver.py
new/castellan-5.6.0/castellan/tests/unit/test_config_driver.py
--- old/castellan-5.5.0/castellan/tests/unit/test_config_driver.py
2025-11-18 10:21:58.000000000 +0100
+++ new/castellan-5.6.0/castellan/tests/unit/test_config_driver.py
2026-02-24 11:37:13.000000000 +0100
@@ -73,7 +73,7 @@
opaque_data.OpaqueData(b"super_secret!"))
# driver config
- config = "[key_manager]\nbackend=vault"
+ config = "[key_manager]\nbackend=vault\nauth_type=keystone_password\n"
mapping = "[DEFAULT]\nmy_secret=" + secret_id
# creating temp files
@@ -106,3 +106,31 @@
source.get("DEFAULT",
"my_secret",
cfg.StrOpt(""))[0])
+
+ def test_missing_auth_type(self):
+ # driver config without auth_type
+ config = "[key_manager]\nbackend=vault\n"
+ mapping = "[DEFAULT]\nmy_secret=some_id"
+
+ # creating temp files
+ with tempfile.NamedTemporaryFile() as config_file:
+ config_file.write(config.encode("utf-8"))
+ config_file.flush()
+
+ with tempfile.NamedTemporaryFile() as mapping_file:
+ mapping_file.write(mapping.encode("utf-8"))
+ mapping_file.flush()
+
+ self.conf_fixture.load_raw_values(
+ group='castellan_source',
+ driver='castellan',
+ config_file=config_file.name,
+ mapping_file=mapping_file.name,
+ )
+
+ source = self.driver.open_source_from_opt_group(
+ self.conf,
+ 'castellan_source')
+
+ # testing that context is None
+ self.assertIsNone(source._context)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan/tests/unit/test_utils.py
new/castellan-5.6.0/castellan/tests/unit/test_utils.py
--- old/castellan-5.5.0/castellan/tests/unit/test_utils.py 2025-11-18
10:21:58.000000000 +0100
+++ new/castellan-5.6.0/castellan/tests/unit/test_utils.py 2026-02-24
11:37:13.000000000 +0100
@@ -195,12 +195,7 @@
self.assertEqual(auth_token_value, ks_token_context.token)
self.assertEqual(project_id_value, ks_token_context.project_id)
- def test_invalid_auth_type(self):
- self.config_fixture.config(
- auth_type='hotdog',
- group='key_manager'
- )
-
+ def test_no_auth_type(self):
self.assertRaises(exception.AuthTypeInvalidError,
utils.credential_factory,
conf=CONF)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan.egg-info/PKG-INFO
new/castellan-5.6.0/castellan.egg-info/PKG-INFO
--- old/castellan-5.5.0/castellan.egg-info/PKG-INFO 2025-11-18
10:22:58.000000000 +0100
+++ new/castellan-5.6.0/castellan.egg-info/PKG-INFO 2026-02-24
11:38:00.000000000 +0100
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
Name: castellan
-Version: 5.5.0
+Version: 5.6.0
Summary: Generic Key Manager interface for OpenStack
Author-email: OpenStack <[email protected]>
License: Apache-2.0
@@ -23,7 +23,7 @@
Requires-Dist: pbr>=2.0.0
Requires-Dist: cryptography>=2.7
Requires-Dist: python-barbicanclient>=5.5.0
-Requires-Dist: oslo.config>=6.4.0
+Requires-Dist: oslo.config>=9.3.0
Requires-Dist: oslo.context>=2.19.2
Requires-Dist: oslo.i18n>=3.15.3
Requires-Dist: oslo.log>=3.36.0
@@ -31,11 +31,17 @@
Requires-Dist: stevedore>=1.20.0
Requires-Dist: keystoneauth1>=3.4.0
Requires-Dist: requests>=2.18.0
+Dynamic: license-file
+Dynamic: requires-dist
=========
Castellan
=========
+.. image:: https://governance.openstack.org/tc/badges/castellan.svg
+
+.. Change things from this point on
+
Generic Key Manager interface for OpenStack.
* License: Apache License, Version 2.0
@@ -44,9 +50,3 @@
* Bugs: https://bugs.launchpad.net/castellan
* Release notes: https://docs.openstack.org/releasenotes/castellan
* Wiki: https://wiki.openstack.org/wiki/Castellan
-
-Team and repository tags
-========================
-
-.. image:: https://governance.openstack.org/tc/badges/castellan.svg
- :target: https://governance.openstack.org/tc/reference/tags/index.html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan.egg-info/SOURCES.txt
new/castellan-5.6.0/castellan.egg-info/SOURCES.txt
--- old/castellan-5.5.0/castellan.egg-info/SOURCES.txt 2025-11-18
10:22:58.000000000 +0100
+++ new/castellan-5.6.0/castellan.egg-info/SOURCES.txt 2026-02-24
11:38:00.000000000 +0100
@@ -104,8 +104,10 @@
releasenotes/notes/add-to-dict-and-from-dict-conversions-to-managed-objects-95a9f0fdbd371a87.yaml
releasenotes/notes/add-vault-provider-29a4c19fe67ab51f.yaml
releasenotes/notes/barbican-service-user-11ebbfcd33dace9d.yaml
+releasenotes/notes/bug-1638018-c23e87345e70f994.yaml
releasenotes/notes/bug-1876102-7c7288fb6e90b11d.yaml
releasenotes/notes/deprecate-auth-endpoint-b91a3e67b5c7263f.yaml
+releasenotes/notes/deprecate-vault-use_ssl-64a3b006bdcb1303.yaml
releasenotes/notes/drop-python-2-7-73d3113c69d724d6.yaml
releasenotes/notes/fix-vault-create-key-b4340a3067cbd93c.yaml
releasenotes/notes/fix-vault-flaky-kv-api-version-b0cd9d62a39d2907.yaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan.egg-info/pbr.json
new/castellan-5.6.0/castellan.egg-info/pbr.json
--- old/castellan-5.5.0/castellan.egg-info/pbr.json 2025-11-18
10:22:58.000000000 +0100
+++ new/castellan-5.6.0/castellan.egg-info/pbr.json 2026-02-24
11:38:00.000000000 +0100
@@ -1 +1 @@
-{"git_version": "77121e9", "is_release": true}
\ No newline at end of file
+{"git_version": "6966cd5", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/castellan.egg-info/requires.txt
new/castellan-5.6.0/castellan.egg-info/requires.txt
--- old/castellan-5.5.0/castellan.egg-info/requires.txt 2025-11-18
10:22:58.000000000 +0100
+++ new/castellan-5.6.0/castellan.egg-info/requires.txt 2026-02-24
11:38:00.000000000 +0100
@@ -1,7 +1,7 @@
pbr>=2.0.0
cryptography>=2.7
python-barbicanclient>=5.5.0
-oslo.config>=6.4.0
+oslo.config>=9.3.0
oslo.context>=2.19.2
oslo.i18n>=3.15.3
oslo.log>=3.36.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/castellan-5.5.0/releasenotes/notes/bug-1638018-c23e87345e70f994.yaml
new/castellan-5.6.0/releasenotes/notes/bug-1638018-c23e87345e70f994.yaml
--- old/castellan-5.5.0/releasenotes/notes/bug-1638018-c23e87345e70f994.yaml
1970-01-01 01:00:00.000000000 +0100
+++ new/castellan-5.6.0/releasenotes/notes/bug-1638018-c23e87345e70f994.yaml
2026-02-24 11:37:13.000000000 +0100
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ Barbican Key Manager in castellan will now attempt to delete intermediate
+ orders and containers created while creating keys or key pairs.
+ Failure to delete those intermediate entities will not fail the key or key
+ pair creation and will only be logged as warning.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/castellan-5.5.0/releasenotes/notes/deprecate-vault-use_ssl-64a3b006bdcb1303.yaml
new/castellan-5.6.0/releasenotes/notes/deprecate-vault-use_ssl-64a3b006bdcb1303.yaml
---
old/castellan-5.5.0/releasenotes/notes/deprecate-vault-use_ssl-64a3b006bdcb1303.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/castellan-5.6.0/releasenotes/notes/deprecate-vault-use_ssl-64a3b006bdcb1303.yaml
2026-02-24 11:37:13.000000000 +0100
@@ -0,0 +1,5 @@
+---
+deprecations:
+ - |
+ The ``[vault] use_ssl`` option has been deprecated. The option has had
+ no effect.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/requirements.txt
new/castellan-5.6.0/requirements.txt
--- old/castellan-5.5.0/requirements.txt 2025-11-18 10:21:58.000000000
+0100
+++ new/castellan-5.6.0/requirements.txt 2026-02-24 11:37:13.000000000
+0100
@@ -5,7 +5,7 @@
pbr>=2.0.0 # Apache-2.0
cryptography>=2.7 # BSD/Apache-2.0
python-barbicanclient>=5.5.0 # Apache-2.0
-oslo.config>=6.4.0 # Apache-2.0
+oslo.config>=9.3.0 # Apache-2.0
oslo.context>=2.19.2 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/tools/setup-vault-env.sh
new/castellan-5.6.0/tools/setup-vault-env.sh
--- old/castellan-5.5.0/tools/setup-vault-env.sh 2025-11-18
10:21:58.000000000 +0100
+++ new/castellan-5.6.0/tools/setup-vault-env.sh 2026-02-24
11:37:13.000000000 +0100
@@ -1,7 +1,7 @@
#!/bin/bash
set -eux
if [ -z "$(which vault)" ]; then
- VAULT_VERSION=1.4.2
+ VAULT_VERSION=1.21.2
SUFFIX=zip
case `uname -s` in
Darwin)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/castellan-5.5.0/tox.ini new/castellan-5.6.0/tox.ini
--- old/castellan-5.5.0/tox.ini 2025-11-18 10:21:58.000000000 +0100
+++ new/castellan-5.6.0/tox.ini 2026-02-24 11:37:13.000000000 +0100
@@ -84,11 +84,12 @@
oslo-config-generator
--config-file=etc/castellan/sample-config-generator.conf
[flake8]
-# [H106] Don't put vim configuration in source files.
-# [H203] Use assertIs(Not)None to check for None.
show-source = True
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
-enable-extensions = H106,H203
+# [H106] Don't put vim configuration in source files.
+# [H203] Use assertIs(Not)None to check for None.
+# H904: Delay string interpolations at logging calls
+enable-extensions = H106,H203,H904
[hacking]
import_exceptions = castellan.i18n