Bump version to 2.8.0-4
- Resolves: RHEL-117050 - Replication online reinitialization of a large database gets stalled. [rhel-9] - Resolves: RHEL-123279 - The new ipahealthcheck test ipahealthcheck.ds.backends.BackendsCheck raises CRITICAL issue [rhel-9] - Resolves: RHEL-140275 - ipa-healthcheck is complaining about missing or incorrectly configured system indexes. [rhel-9] - Resolves: RHEL-142980 - Scalability issue of replication online initialization with large database [rhel-9] - Resolves: RHEL-146899 - memory corruption in alias entry plugin [rhel-9] - Resolves: RHEL-147212 - Access logs are not getting deleted as configured. [rhel-9] - Resolves: RHEL-150907 - Remove memberof_del_dn_from_groups from MemberOf plugin [rhel-9]
This commit is contained in:
parent
d354d3760f
commit
1ef7deadc0
@ -1,31 +0,0 @@
|
||||
From 4eea3051931f552ee1df36e70c7278aaa36124a1 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Mon, 5 Jan 2026 14:38:38 +0100
|
||||
Subject: [PATCH] Issue 7166 - db_config_set asserts because of dynamic list
|
||||
(#7167)
|
||||
|
||||
Avoid assertion in db_config_set when args does not contains dynamic list attributes
|
||||
|
||||
Issue: #7166
|
||||
|
||||
Reviewed by: @tbordaz (Thanks!)
|
||||
---
|
||||
src/lib389/lib389/cli_conf/backend.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
|
||||
index dcf57d006..f8735e08e 100644
|
||||
--- a/src/lib389/lib389/cli_conf/backend.py
|
||||
+++ b/src/lib389/lib389/cli_conf/backend.py
|
||||
@@ -542,7 +542,7 @@ def db_config_set(inst, basedn, log, args):
|
||||
did_something = False
|
||||
replace_list = []
|
||||
|
||||
- if args.enable_dynamic_lists and args.disable_dynamic_lists:
|
||||
+ if getattr(args,'enable_dynamic_lists', None) and getattr(args, 'disable_dynamic_lists', None):
|
||||
raise ValueError("You can not enable and disable dynamic lists at the same time")
|
||||
|
||||
for attr, value in list(attrs.items()):
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From ed02c78055406b020089947459954142df3b1fea Mon Sep 17 00:00:00 2001
|
||||
From c5aab4f8ba822572daa9ef69a0109577bf2147e1 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Tue, 20 Jan 2026 09:52:47 +0100
|
||||
Subject: [PATCH] Issue 7189 - DSBLE0007 generates incorrect remediation
|
||||
@ -0,0 +1,48 @@
|
||||
From 327ebf93decaa19bd3919afaeba0dc122eef1990 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 12 Jan 2026 13:53:05 -0500
|
||||
Subject: [PATCH] Issue 7184 - argparse.HelpFormatter _format_actions_usage()
|
||||
is deprecated
|
||||
|
||||
Description:
|
||||
|
||||
_format_actions_usage() was removed in python 3.15. Instead we can use
|
||||
_get_actions_usage_parts() but it also behaves differently between
|
||||
python 3.14 and 3.15 so we need special handling.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7184
|
||||
|
||||
Reviewed by: spichugi(Thanks!)
|
||||
---
|
||||
src/lib389/lib389/cli_base/__init__.py | 15 ++++++++++++++-
|
||||
1 file changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/cli_base/__init__.py b/src/lib389/lib389/cli_base/__init__.py
|
||||
index 06b8f9964..f1055aadc 100644
|
||||
--- a/src/lib389/lib389/cli_base/__init__.py
|
||||
+++ b/src/lib389/lib389/cli_base/__init__.py
|
||||
@@ -413,7 +413,20 @@ class CustomHelpFormatter(argparse.HelpFormatter):
|
||||
|
||||
def _format_usage(self, usage, actions, groups, prefix):
|
||||
usage = super(CustomHelpFormatter, self)._format_usage(usage, actions, groups, prefix)
|
||||
- formatted_options = self._format_actions_usage(parent_arguments, [])
|
||||
+
|
||||
+ if sys.version_info < (3, 13):
|
||||
+ # Use _format_actions_usage() for Python 3.12 and earlier
|
||||
+ formatted_options = self._format_actions_usage(parent_arguments, [])
|
||||
+ else:
|
||||
+ # Use _get_actions_usage_parts() for Python 3.13 and later
|
||||
+ action_parts = self._get_actions_usage_parts(parent_arguments, [])
|
||||
+ if sys.version_info >= (3, 15):
|
||||
+ # Python 3.15 returns a tuple (list of actions, count of actions)
|
||||
+ formatted_options = ' '.join(action_parts[0])
|
||||
+ else:
|
||||
+ # Python 3.13 and 3.14 return a list of actions
|
||||
+ formatted_options = ' '.join(action_parts)
|
||||
+
|
||||
# If formatted_options already in usage - remove them
|
||||
if formatted_options in usage:
|
||||
usage = usage.replace(f' {formatted_options}', '')
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From 819a5898d1a4d913f786086f374693c306446abb Mon Sep 17 00:00:00 2001
|
||||
From dbabbe6a3c42b979d14960b355925c9748371cad Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Fri, 30 Jan 2026 12:00:13 +0100
|
||||
Subject: [PATCH] Issue 7027 - (2nd) 389-ds-base OpenScanHub Leaks Detected
|
||||
197
0009-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch
Normal file
197
0009-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch
Normal file
@ -0,0 +1,197 @@
|
||||
From 39d47ca91e866d30b35dca41d477ad4ee07f8a14 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Mon, 2 Feb 2026 15:39:18 +0100
|
||||
Subject: [PATCH] Issue 7213 - MDB_BAD_VALSIZE error while handling VLV (#7214)
|
||||
|
||||
* Issue 7213 - MDB_BAD_VALSIZE error while handling VLV
|
||||
Avoid failing lmdb operation when handling VLV index by truncating the key so that key+data is small enough.
|
||||
|
||||
Issue: #7213
|
||||
|
||||
Reviewed by: @mreynolds389 , @vashirov (Thanks!)
|
||||
|
||||
Assisted by: Claude A/I
|
||||
|
||||
(cherry picked from commit 5ebce22d4214bec5ed94ad84c4448164be99389a)
|
||||
---
|
||||
.../tests/suites/vlv/regression_test.py | 110 ++++++++++++++++++
|
||||
.../slapd/back-ldbm/db-mdb/mdb_layer.c | 5 +
|
||||
ldap/servers/slapd/back-ldbm/vlv.c | 7 +-
|
||||
3 files changed, 121 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/vlv/regression_test.py b/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
index c8db94b19..1cc03c303 100644
|
||||
--- a/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
@@ -1178,6 +1178,116 @@ def test_vlv_with_mr(vlv_setup_with_uid_mr):
|
||||
|
||||
|
||||
|
||||
+def test_vlv_long_attribute_value(topology_st, request):
|
||||
+ """
|
||||
+ Test VLV with an entry containing a very long attribute value (2K).
|
||||
+
|
||||
+ :id: 99126fa4-003e-11f1-b7d6-c85309d5c3e3
|
||||
+ :setup: Standalone instance.
|
||||
+ :steps:
|
||||
+ 1. Cleanup leftover from previous tests
|
||||
+ 2. Create VLV search and index on cn attribute
|
||||
+ 3. Reindex VLV
|
||||
+ 4. Add an entry with a cn attribute having 2K character value
|
||||
+ 5. Verify the entry was added successfully
|
||||
+ 6. Perform a VLV search to ensure it still works
|
||||
+ 7. Add another entry with a cn attribute having 2K character value
|
||||
+ 8. Verify the entry was added successfully
|
||||
+ 9. Perform a VLV search to ensure it still works
|
||||
+ :expectedresults:
|
||||
+ 1. Should Success.
|
||||
+ 2. Should Success.
|
||||
+ 3. Should Success.
|
||||
+ 4. Should Success.
|
||||
+ 5. Should Success.
|
||||
+ 6. Should Success.
|
||||
+ 7. Should Success.
|
||||
+ 8. Should Success.
|
||||
+ 9. Should Success.
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+ reindex_task = Tasks(inst)
|
||||
+
|
||||
+ users_to_delete = []
|
||||
+
|
||||
+ def fin():
|
||||
+ cleanup(inst)
|
||||
+ # Clean the added users
|
||||
+ for user in users_to_delete:
|
||||
+ user.delete()
|
||||
+
|
||||
+ if not DEBUGGING:
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ # Clean previous tests leftover
|
||||
+ fin()
|
||||
+
|
||||
+ # Create VLV search and index
|
||||
+ vlv_search, vlv_index = create_vlv_search_and_index(inst)
|
||||
+ assert reindex_task.reindex(
|
||||
+ suffix=DEFAULT_SUFFIX,
|
||||
+ attrname=vlv_index.rdn,
|
||||
+ args={TASK_WAIT: True},
|
||||
+ vlv=True
|
||||
+ ) == 0
|
||||
+
|
||||
+ # Add a few regular users first
|
||||
+ add_users(inst, 10)
|
||||
+
|
||||
+ # Create a very long cn value (2K characters)
|
||||
+ long_cn_value = 'a' * 2048 + '1'
|
||||
+
|
||||
+ # Add an entry with the long cn attribute
|
||||
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||||
+ user_properties = {
|
||||
+ 'uid': 'longcnuser1',
|
||||
+ 'cn': long_cn_value,
|
||||
+ 'sn': 'user1',
|
||||
+ 'uidNumber': '99999',
|
||||
+ 'gidNumber': '99999',
|
||||
+ 'homeDirectory': '/home/longcnuser1'
|
||||
+ }
|
||||
+ user = users.create(properties=user_properties)
|
||||
+ users_to_delete.append(user);
|
||||
+
|
||||
+ # Verify the entry was created and has the long cn value
|
||||
+ entry = user.get_attr_vals_utf8('cn')
|
||||
+ assert entry[0] == long_cn_value
|
||||
+ log.info(f'Successfully created user with cn length: {len(entry[0])}')
|
||||
+
|
||||
+ # Perform VLV search to ensure VLV still works with long attribute values
|
||||
+ conn = open_new_ldapi_conn(inst.serverid)
|
||||
+ count = len(conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(uid=*)"))
|
||||
+ assert count > 0
|
||||
+ log.info(f'VLV search successful with {count} entries including entry with 2K cn value')
|
||||
+
|
||||
+ # Add another entry with the long cn attribute
|
||||
+ long_cn_value = 'a' * 2048 + '2'
|
||||
+
|
||||
+ user_properties = {
|
||||
+ 'uid': 'longcnuser2',
|
||||
+ 'cn': long_cn_value,
|
||||
+ 'sn': 'user2',
|
||||
+ 'uidNumber': '99998',
|
||||
+ 'gidNumber': '99998',
|
||||
+ 'homeDirectory': '/home/longcnuser2'
|
||||
+ }
|
||||
+ user = users.create(properties=user_properties)
|
||||
+ users_to_delete.append(user);
|
||||
+
|
||||
+ # Verify the entry was created and has the long cn value
|
||||
+ entry = user.get_attr_vals_utf8('cn')
|
||||
+ assert entry[0] == long_cn_value
|
||||
+ log.info(f'Successfully created user with cn length: {len(entry[0])}')
|
||||
+
|
||||
+ # Perform VLV search to ensure VLV still works with long attribute values
|
||||
+ conn = open_new_ldapi_conn(inst.serverid)
|
||||
+ count = len(conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(uid=*)"))
|
||||
+ assert count > 1
|
||||
+ log.info(f'VLV search successful with {count} entries including entry with 2K cn value')
|
||||
+
|
||||
+
|
||||
+
|
||||
if __name__ == "__main__":
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c
|
||||
index c6e9f8b01..ffbd6609f 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c
|
||||
@@ -2138,10 +2138,15 @@ void *dbmdb_recno_cache_build(void *arg)
|
||||
recno = 1;
|
||||
}
|
||||
while (rc == 0) {
|
||||
+ struct ldbminfo *li = (struct ldbminfo *)rcctx->cursor->be->be_database->plg_private;
|
||||
slapi_log_err(SLAPI_LOG_DEBUG, "dbmdb_recno_cache_build", "recno=%d\n", recno);
|
||||
if (recno % RECNO_CACHE_INTERVAL == 1) {
|
||||
/* Prepare the cache data */
|
||||
len = sizeof(*rce) + data.mv_size + key.mv_size;
|
||||
+ if (len > li->li_max_key_len) {
|
||||
+ key.mv_size = li->li_max_key_len - data.mv_size - sizeof(*rce);
|
||||
+ len = li->li_max_key_len;
|
||||
+ }
|
||||
rce = (dbmdb_recno_cache_elmt_t*)slapi_ch_malloc(len);
|
||||
rce->len = len;
|
||||
rce->recno = recno;
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c
|
||||
index 18431799c..a1cd226f4 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/vlv.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/vlv.c
|
||||
@@ -866,6 +866,7 @@ do_vlv_update_index(back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct
|
||||
struct vlv_key *key = NULL;
|
||||
dbi_val_t data = {0};
|
||||
dblayer_private *priv = NULL;
|
||||
+ size_t key_size_limit = li->li_max_key_len - sizeof(entry->ep_id);
|
||||
|
||||
slapi_pblock_get(pb, SLAPI_BACKEND, &be);
|
||||
priv = (dblayer_private *)li->li_dblayer_private;
|
||||
@@ -886,6 +887,10 @@ do_vlv_update_index(back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct
|
||||
return rc;
|
||||
}
|
||||
|
||||
+ /* Truncate the key if it is too long */
|
||||
+ if (key->key.size > key_size_limit) {
|
||||
+ key->key.size = key_size_limit;
|
||||
+ }
|
||||
if (NULL != txn) {
|
||||
db_txn = txn->back_txn_txn;
|
||||
} else {
|
||||
@@ -930,7 +935,7 @@ do_vlv_update_index(back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct
|
||||
if (txn && txn->back_special_handling_fn) {
|
||||
rc = txn->back_special_handling_fn(be, BTXNACT_VLV_DEL, db, &key->key, &data, txn);
|
||||
} else {
|
||||
- rc = dblayer_db_op(be, db, db_txn, DBI_OP_DEL, &key->key, NULL);
|
||||
+ rc = dblayer_db_op(be, db, db_txn, DBI_OP_DEL, &key->key, &data);
|
||||
}
|
||||
if (rc == 0) {
|
||||
if (txn && txn->back_special_handling_fn) {
|
||||
--
|
||||
2.52.0
|
||||
|
||||
43
0010-Issue-6542-RPM-build-errors-on-Fedora-42.patch
Normal file
43
0010-Issue-6542-RPM-build-errors-on-Fedora-42.patch
Normal file
@ -0,0 +1,43 @@
|
||||
From 70d323d4d9ca4d1d682ab4a273178946922c6929 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Fri, 24 Jan 2025 11:10:45 +0100
|
||||
Subject: [PATCH] Issue 6542 - RPM build errors on Fedora 42
|
||||
|
||||
Bug Description:
|
||||
Fedora 42 has unified `/bin` and `/sbin`: https://fedoraproject.org/wiki/Changes/Unify_bin_and_sbin
|
||||
https://docs.fedoraproject.org/en-US/packaging-guidelines/#_merged_file_system_layout
|
||||
|
||||
This change causes RPM build to fail with:
|
||||
```
|
||||
RPM build errors:
|
||||
File not found: /builddir/build/BUILD/389-ds-base-3.1.2-build/BUILDROOT/usr/bin/openldap_to_ds
|
||||
```
|
||||
|
||||
Fix Description:
|
||||
Patch `setup.py.in` based on Fedora or RHEL version that support unified
|
||||
`/bin` and `/sbin`.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/6542
|
||||
|
||||
Reviewed by: @mreynolds389, @droideck (Thanks!)
|
||||
---
|
||||
rpm/389-ds-base.spec.in | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
|
||||
index 258d94698..44a158ce5 100644
|
||||
--- a/rpm/389-ds-base.spec.in
|
||||
+++ b/rpm/389-ds-base.spec.in
|
||||
@@ -522,6 +522,9 @@ autoreconf -fiv
|
||||
|
||||
%if 0%{?rhel} > 7 || 0%{?fedora}
|
||||
# lib389
|
||||
+%if 0%{?fedora} >= 42 || 0%{?rhel} >= 11
|
||||
+ sed -i "/prefix/s@sbin@bin@g" src/lib389/setup.py.in
|
||||
+%endif
|
||||
make src/lib389/setup.py
|
||||
pushd ./src/lib389
|
||||
%py3_build
|
||||
--
|
||||
2.52.0
|
||||
|
||||
3318
0011-Issue-6476-Fix-build-failure-with-GCC-15.patch
Normal file
3318
0011-Issue-6476-Fix-build-failure-with-GCC-15.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
From 41c72bf9900a7e28e0f589384f6e0ce292607e9d Mon Sep 17 00:00:00 2001
|
||||
From 7a45b50bf3d9cfc8f7e805379fcb39d5669d6c8b Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Revert index scan limits for system indexes
|
||||
@ -729,7 +729,7 @@ index d3c9ccf35..1d9be4683 100644
|
||||
'nsslapd-import-cachesize',
|
||||
'nsslapd-idl-switch',
|
||||
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
|
||||
index f8735e08e..ec9b5debe 100644
|
||||
index dcf57d006..80008d22d 100644
|
||||
--- a/src/lib389/lib389/cli_conf/backend.py
|
||||
+++ b/src/lib389/lib389/cli_conf/backend.py
|
||||
@@ -39,7 +39,6 @@ arg_to_attr = {
|
||||
@ -1,4 +1,4 @@
|
||||
From 450015057d84bb032996e0bd76941b1ab6e1c08c Mon Sep 17 00:00:00 2001
|
||||
From a58212943da2604091e7d5a20829ab54970d41c9 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Add upgrade function to remove
|
||||
313
0014-Issue-7223-Add-upgrade-function-to-remove-ancestorid.patch
Normal file
313
0014-Issue-7223-Add-upgrade-function-to-remove-ancestorid.patch
Normal file
@ -0,0 +1,313 @@
|
||||
From 9a9446b9bafe25eacf97039e66d6ef19d366315c Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Add upgrade function to remove ancestorid index
|
||||
config entry
|
||||
|
||||
Description:
|
||||
Add `upgrade_remove_ancestorid_index_config()` function that removes:
|
||||
* ancestorid from `cn=default indexes`
|
||||
* ancestorid index config entries from each backend's `cn=index`
|
||||
|
||||
Also remove ancestorid index configuration from template-dse.ldif.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7223
|
||||
|
||||
Reviewed by: @progier389, @tbordaz, @droideck (Thanks!)
|
||||
---
|
||||
.../healthcheck/health_system_indexes_test.py | 85 +++++++++++
|
||||
ldap/ldif/template-dse.ldif.in | 8 --
|
||||
ldap/servers/slapd/upgrade.c | 133 +++++++++++++++++-
|
||||
3 files changed, 214 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
index b0d7a99ec..4b0c58835 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -501,6 +501,91 @@ def test_upgrade_removes_parentid_scanlimit(topology_st):
|
||||
|
||||
log.info("Upgrade successfully removed nsIndexIDListScanLimit from parentid index")
|
||||
|
||||
+ # Verify idempotency - restart again and ensure no errors
|
||||
+ log.info("Restart server again to verify idempotency (no errors on second run)")
|
||||
+ standalone.restart()
|
||||
+ # Verify the attribute is still absent
|
||||
+ scanlimit_after_second = parentid_index.get_attr_vals_utf8("nsIndexIDListScanLimit")
|
||||
+ assert not scanlimit_after_second, \
|
||||
+ f"nsIndexIDListScanLimit should still be absent after second restart but found: {scanlimit_after_second}"
|
||||
+ log.info("Idempotency verified - no issues on second restart")
|
||||
+
|
||||
+
|
||||
+def test_upgrade_removes_ancestorid_index_config(topology_st):
|
||||
+ """Check if upgrade function removes ancestorid index config entry
|
||||
+
|
||||
+ :id: 3f3d6e9b-75ac-4f0d-b2ce-7204e6eacd0a
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Create DS instance
|
||||
+ 2. Stop the server
|
||||
+ 3. Use DSEldif to add an ancestorid index config entry
|
||||
+ 4. Start the server (triggers upgrade)
|
||||
+ 5. Verify ancestorid index config entry is removed
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ 4. Success
|
||||
+ 5. ancestorid index config entry is no longer present
|
||||
+ """
|
||||
+ from lib389.dseldif import DSEldif
|
||||
+
|
||||
+ standalone = topology_st.standalone
|
||||
+ ANCESTORID_DN = "cn=ancestorid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config"
|
||||
+
|
||||
+ log.info("Stop the server")
|
||||
+ standalone.stop()
|
||||
+
|
||||
+ log.info("Add ancestorid index config entry using DSEldif")
|
||||
+ dse_ldif = DSEldif(standalone)
|
||||
+
|
||||
+ # Create a fake ancestorid index entry
|
||||
+ ancestorid_entry = [
|
||||
+ "dn: {}\n".format(ANCESTORID_DN),
|
||||
+ "objectClass: top\n",
|
||||
+ "objectClass: nsIndex\n",
|
||||
+ "cn: ancestorid\n",
|
||||
+ "nsSystemIndex: true\n",
|
||||
+ "nsIndexType: eq\n",
|
||||
+ "nsMatchingRule: integerOrderingMatch\n",
|
||||
+ "\n"
|
||||
+ ]
|
||||
+ dse_ldif.add_entry(ancestorid_entry)
|
||||
+
|
||||
+ # Verify it was added by re-reading dse.ldif
|
||||
+ dse_ldif2 = DSEldif(standalone)
|
||||
+ cn_value = dse_ldif2.get(ANCESTORID_DN, "cn")
|
||||
+ assert cn_value is not None, "Failed to add ancestorid index config entry"
|
||||
+ log.info(f"Added ancestorid index entry with cn: {cn_value}")
|
||||
+
|
||||
+ log.info("Start the server (triggers upgrade)")
|
||||
+ standalone.start()
|
||||
+
|
||||
+ log.info("Verify ancestorid index config entry was removed by upgrade")
|
||||
+ # Check via LDAP - the upgrade should have removed the entry
|
||||
+ try:
|
||||
+ ancestorid_index = Index(standalone, ANCESTORID_DN)
|
||||
+ # If we can get the entry, it wasn't removed - this is a failure
|
||||
+ cn_after = ancestorid_index.get_attr_vals_utf8("cn")
|
||||
+ assert False, f"ancestorid index config entry should have been removed but still exists: {cn_after}"
|
||||
+ except Exception as e:
|
||||
+ # Entry should not exist - this is expected
|
||||
+ log.info(f"ancestorid index config entry correctly removed (got exception: {e})")
|
||||
+
|
||||
+ log.info("Upgrade successfully removed ancestorid index config entry")
|
||||
+
|
||||
+ # Verify idempotency - restart again and ensure no errors
|
||||
+ log.info("Restart server again to verify idempotency (no errors on second run)")
|
||||
+ standalone.restart()
|
||||
+ # Verify the entry is still absent
|
||||
+ try:
|
||||
+ ancestorid_index = Index(standalone, ANCESTORID_DN)
|
||||
+ cn_after_second = ancestorid_index.get_attr_vals_utf8("cn")
|
||||
+ assert False, f"ancestorid index config entry should still be absent after second restart but found: {cn_after_second}"
|
||||
+ except Exception as e:
|
||||
+ log.info(f"Idempotency verified - ancestorid still absent after second restart (got exception: {e})")
|
||||
+
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run isolated
|
||||
diff --git a/ldap/ldif/template-dse.ldif.in b/ldap/ldif/template-dse.ldif.in
|
||||
index 6f97d492b..70e7a85ac 100644
|
||||
--- a/ldap/ldif/template-dse.ldif.in
|
||||
+++ b/ldap/ldif/template-dse.ldif.in
|
||||
@@ -990,14 +990,6 @@ cn: aci
|
||||
nssystemindex: true
|
||||
nsindextype: pres
|
||||
|
||||
-dn: cn=ancestorid,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config
|
||||
-objectclass: top
|
||||
-objectclass: nsIndex
|
||||
-cn: ancestorid
|
||||
-nssystemindex: true
|
||||
-nsindextype: eq
|
||||
-nsmatchingrule: integerOrderingMatch
|
||||
-
|
||||
dn: cn=cn,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config
|
||||
objectclass: top
|
||||
objectclass: nsIndex
|
||||
diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c
|
||||
index adfec63de..d9156cae9 100644
|
||||
--- a/ldap/servers/slapd/upgrade.c
|
||||
+++ b/ldap/servers/slapd/upgrade.c
|
||||
@@ -380,6 +380,126 @@ upgrade_remove_index_scanlimit(void)
|
||||
return uresult;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Remove ancestorid index configuration entry if present.
|
||||
+ *
|
||||
+ * The ancestorid index is special - it has no corresponding attribute type
|
||||
+ * and should not have a DSE config entry. If an entry exists, remove it.
|
||||
+ *
|
||||
+ * This function removes:
|
||||
+ * 1. The ancestorid entry from cn=default indexes (to prevent re-creation on startup)
|
||||
+ * 2. The ancestorid entry from each backend's cn=index (if it exists)
|
||||
+ */
|
||||
+static upgrade_status
|
||||
+upgrade_remove_ancestorid_index_config(void)
|
||||
+{
|
||||
+ struct slapi_pblock *pb = slapi_pblock_new();
|
||||
+ Slapi_Entry **backends = NULL;
|
||||
+ const char *be_base_dn = "cn=ldbm database,cn=plugins,cn=config";
|
||||
+ const char *be_filter = "(objectclass=nsBackendInstance)";
|
||||
+ upgrade_status uresult = UPGRADE_SUCCESS;
|
||||
+ int rc;
|
||||
+
|
||||
+ /*
|
||||
+ * First, remove ancestorid from cn=default indexes to prevent
|
||||
+ * ldbm_instance_create_default_user_indexes() from re-creating it.
|
||||
+ */
|
||||
+ {
|
||||
+ Slapi_PBlock *def_pb = slapi_pblock_new();
|
||||
+ char *def_idx_dn = slapi_create_dn_string(
|
||||
+ "cn=ancestorid,cn=default indexes,cn=config,%s", be_base_dn);
|
||||
+
|
||||
+ if (def_idx_dn) {
|
||||
+ slapi_delete_internal_set_pb(
|
||||
+ def_pb, def_idx_dn, NULL, NULL,
|
||||
+ plugin_get_default_component_id(), 0);
|
||||
+ slapi_delete_internal_pb(def_pb);
|
||||
+ slapi_pblock_get(def_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
|
||||
+
|
||||
+ if (rc == LDAP_SUCCESS) {
|
||||
+ slapi_log_err(SLAPI_LOG_NOTICE, "upgrade_remove_ancestorid_index_config",
|
||||
+ "Removed 'ancestorid' from default indexes.\n");
|
||||
+ } else if (rc != LDAP_NO_SUCH_OBJECT) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "upgrade_remove_ancestorid_index_config",
|
||||
+ "Failed to remove 'ancestorid' from default indexes: error %d\n", rc);
|
||||
+ }
|
||||
+
|
||||
+ slapi_ch_free_string(&def_idx_dn);
|
||||
+ }
|
||||
+ slapi_pblock_destroy(def_pb);
|
||||
+ }
|
||||
+
|
||||
+ /* Search for all backend instances */
|
||||
+ slapi_search_internal_set_pb(
|
||||
+ pb, be_base_dn,
|
||||
+ LDAP_SCOPE_ONELEVEL,
|
||||
+ be_filter, NULL, 0, NULL, NULL,
|
||||
+ plugin_get_default_component_id(), 0);
|
||||
+ slapi_search_internal_pb(pb);
|
||||
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &backends);
|
||||
+
|
||||
+ if (backends) {
|
||||
+ for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) {
|
||||
+ const char *be_dn = slapi_entry_get_dn_const(backends[be_idx]);
|
||||
+ const char *be_name = slapi_entry_attr_get_ref(backends[be_idx], "cn");
|
||||
+ if (!be_dn || !be_name) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ struct slapi_pblock *idx_pb = slapi_pblock_new();
|
||||
+ Slapi_Entry **idx_entries = NULL;
|
||||
+ char *idx_dn = slapi_create_dn_string("cn=ancestorid,cn=index,%s",
|
||||
+ be_dn);
|
||||
+ char *idx_filter = "(objectclass=nsIndex)";
|
||||
+
|
||||
+ if (!idx_dn) {
|
||||
+ slapi_pblock_destroy(idx_pb);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ slapi_search_internal_set_pb(
|
||||
+ idx_pb, idx_dn,
|
||||
+ LDAP_SCOPE_BASE,
|
||||
+ idx_filter, NULL, 0, NULL, NULL,
|
||||
+ plugin_get_default_component_id(), 0);
|
||||
+ slapi_search_internal_pb(idx_pb);
|
||||
+ slapi_pblock_get(idx_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &idx_entries);
|
||||
+
|
||||
+ if (idx_entries && idx_entries[0]) {
|
||||
+ /* ancestorid index entry exists - delete it */
|
||||
+ Slapi_PBlock *del_pb = slapi_pblock_new();
|
||||
+
|
||||
+ slapi_delete_internal_set_pb(
|
||||
+ del_pb, idx_dn, NULL, NULL,
|
||||
+ plugin_get_default_component_id(), 0);
|
||||
+ slapi_delete_internal_pb(del_pb);
|
||||
+ slapi_pblock_get(del_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
|
||||
+
|
||||
+ if (rc == LDAP_SUCCESS) {
|
||||
+ slapi_log_err(SLAPI_LOG_NOTICE, "upgrade_remove_ancestorid_index_config",
|
||||
+ "Removed 'ancestorid' index config entry in backend '%s'.\n",
|
||||
+ be_name);
|
||||
+ } else if (rc != LDAP_NO_SUCH_OBJECT) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "upgrade_remove_ancestorid_index_config",
|
||||
+ "Failed to remove 'ancestorid' index config entry in backend '%s': error %d\n",
|
||||
+ be_name, rc);
|
||||
+ }
|
||||
+
|
||||
+ slapi_pblock_destroy(del_pb);
|
||||
+ }
|
||||
+
|
||||
+ slapi_ch_free_string(&idx_dn);
|
||||
+ slapi_free_search_results_internal(idx_pb);
|
||||
+ slapi_pblock_destroy(idx_pb);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ slapi_free_search_results_internal(pb);
|
||||
+ slapi_pblock_destroy(pb);
|
||||
+
|
||||
+ return uresult;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Check if parentid/ancestorid indexes are missing the integerOrderingMatch
|
||||
* matching rule.
|
||||
@@ -394,7 +514,7 @@ upgrade_check_id_index_matching_rule(void)
|
||||
Slapi_Entry **backends = NULL;
|
||||
const char *be_base_dn = "cn=ldbm database,cn=plugins,cn=config";
|
||||
const char *be_filter = "(objectclass=nsBackendInstance)";
|
||||
- const char *attrs_to_check[] = {"parentid", "ancestorid", NULL};
|
||||
+ const char *attrs_to_check[] = {"parentid", NULL};
|
||||
upgrade_status uresult = UPGRADE_SUCCESS;
|
||||
|
||||
/* Search for all backend instances */
|
||||
@@ -408,8 +528,9 @@ upgrade_check_id_index_matching_rule(void)
|
||||
|
||||
if (backends) {
|
||||
for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) {
|
||||
+ const char *be_dn = slapi_entry_get_dn_const(backends[be_idx]);
|
||||
const char *be_name = slapi_entry_attr_get_ref(backends[be_idx], "cn");
|
||||
- if (!be_name) {
|
||||
+ if (!be_dn || !be_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -418,8 +539,8 @@ upgrade_check_id_index_matching_rule(void)
|
||||
const char *attr_name = attrs_to_check[attr_idx];
|
||||
struct slapi_pblock *idx_pb = slapi_pblock_new();
|
||||
Slapi_Entry **idx_entries = NULL;
|
||||
- char *idx_dn = slapi_create_dn_string("cn=%s,cn=index,cn=%s,%s",
|
||||
- attr_name, be_name, be_base_dn);
|
||||
+ char *idx_dn = slapi_create_dn_string("cn=%s,cn=index,%s",
|
||||
+ attr_name, be_dn);
|
||||
char *idx_filter = "(objectclass=nsIndex)";
|
||||
PRBool has_matching_rule = PR_FALSE;
|
||||
|
||||
@@ -512,6 +633,10 @@ upgrade_server(void)
|
||||
return UPGRADE_FAILURE;
|
||||
}
|
||||
|
||||
+ if (upgrade_remove_ancestorid_index_config() != UPGRADE_SUCCESS) {
|
||||
+ return UPGRADE_FAILURE;
|
||||
+ }
|
||||
+
|
||||
if (upgrade_check_id_index_matching_rule() != UPGRADE_SUCCESS) {
|
||||
return UPGRADE_FAILURE;
|
||||
}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From 46154ef03c7543a452b17540460dc808805bd4b7 Mon Sep 17 00:00:00 2001
|
||||
From b5bee921b7f4cfbf7a2edbe55d4291f487f4a140 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Detect and log index ordering mismatch during
|
||||
@ -1,4 +1,4 @@
|
||||
From c741eceaf0ba751d95153f032826c20249838de5 Mon Sep 17 00:00:00 2001
|
||||
From 04eca1fe36480561bc2f59440d971e000133d213 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Add dsctl index-check command for offline index
|
||||
@ -24,11 +24,11 @@ Reviewed by: @progier389, @tbordaz, @droideck (Thanks!)
|
||||
4 files changed, 1068 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
index b0d7a99ec..55b9d2f6d 100644
|
||||
index 4b0c58835..571465562 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -502,6 +502,599 @@ def test_upgrade_removes_parentid_scanlimit(topology_st):
|
||||
log.info("Upgrade successfully removed nsIndexIDListScanLimit from parentid index")
|
||||
@@ -587,6 +587,599 @@ def test_upgrade_removes_ancestorid_index_config(topology_st):
|
||||
log.info(f"Idempotency verified - ancestorid still absent after second restart (got exception: {e})")
|
||||
|
||||
|
||||
+def test_index_check_basic(topology_st):
|
||||
@ -628,10 +628,10 @@ index b0d7a99ec..55b9d2f6d 100644
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
|
||||
index 258d94698..94d8c04c9 100644
|
||||
index 44a158ce5..0175dfa7c 100644
|
||||
--- a/rpm/389-ds-base.spec.in
|
||||
+++ b/rpm/389-ds-base.spec.in
|
||||
@@ -642,42 +642,45 @@ if ! getent passwd $USERNAME >/dev/null ; then
|
||||
@@ -645,42 +645,45 @@ if ! getent passwd $USERNAME >/dev/null ; then
|
||||
fi
|
||||
|
||||
# Reload our sysctl before we restart (if we can)
|
||||
@ -1,4 +1,4 @@
|
||||
From d1886fbc7d97e49ac0b8bc5bd6ae7e3263bb0cfb Mon Sep 17 00:00:00 2001
|
||||
From c1f0756b453b7ea219add236f60a72b3fc660af0 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Tue, 27 Jan 2026 14:26:29 +0100
|
||||
Subject: [PATCH] Issue 7096 - (2nd) During replication online total init the
|
||||
@ -1,4 +1,4 @@
|
||||
From 42c38a7a95e898a6185ac7c71ad89119ef406509 Mon Sep 17 00:00:00 2001
|
||||
From 35237d57daf6fdf20a42c3cef27130ba70f0cdc2 Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
Date: Tue, 18 Nov 2025 21:57:10 +0530
|
||||
Subject: [PATCH] Issue 7076, 6992, 6784, 6214 - Fix CI test failures (#7077)
|
||||
@ -53,7 +53,7 @@ index be825efe9..e9b611439 100644
|
||||
log.info(f'Backup directory is {backup_dir}')
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
index 55b9d2f6d..da7673283 100644
|
||||
index 571465562..4cd4d0c70 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -172,6 +172,7 @@ def test_missing_parentid(topology_st, log_buffering_enabled):
|
||||
@ -1,4 +1,4 @@
|
||||
From b5a8ab96ec5c2a0cc0d478c5a906f3d2bfb4f6c5 Mon Sep 17 00:00:00 2001
|
||||
From 04a0f5560ea741972b9c264af23b377893ab7133 Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 15:41:09 +0530
|
||||
Subject: [PATCH] Issue 7076 - Fix revert_cache() never called in modrdn
|
||||
@ -1,4 +1,4 @@
|
||||
From cd530816544b9a583adc517db2ff34cdfa84fc43 Mon Sep 17 00:00:00 2001
|
||||
From fb8acf6141b069e250be3821c1e70ee7ed448720 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Wed, 11 Feb 2026 19:53:44 +0100
|
||||
Subject: [PATCH] Issue 6947 - Fix health_system_indexes_test.py
|
||||
@ -8,7 +8,7 @@ Subject: [PATCH] Issue 6947 - Fix health_system_indexes_test.py
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
index da7673283..932857dd6 100644
|
||||
index 4cd4d0c70..3b3651b38 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -99,6 +99,7 @@ def run_healthcheck_and_flush_log(topology, instance, searched_code, json, searc
|
||||
@ -1,4 +1,4 @@
|
||||
From 64dcdbcbba3e8e2239a2e099787c40713c8a0a7e Mon Sep 17 00:00:00 2001
|
||||
From 8761b28fd2f2cf3d2e2119bdf1b348bc7d2d1834 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Mon, 9 Feb 2026 13:18:09 +0100
|
||||
Subject: [PATCH] Issue 7121 - (2nd) LeakSanitizer: various leaks during
|
||||
@ -1,4 +1,4 @@
|
||||
From eaa2077433bc3a38dee60ae5255f067aa3113691 Mon Sep 17 00:00:00 2001
|
||||
From 86b15d688949197a9efe3d5fc7a7eadcdd46e115 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Tue, 16 Dec 2025 15:48:35 -0800
|
||||
Subject: [PATCH] Issue 7150 - Compressed access log rotations skipped,
|
||||
@ -1,4 +1,4 @@
|
||||
From 8c7de629b83fe12a36cabe89e2b19124dcd6c937 Mon Sep 17 00:00:00 2001
|
||||
From 524cae18721234e1bc8d958c89684008d62e6b30 Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 15:33:08 +0000
|
||||
Subject: [PATCH] Issue 7224 - CI Test - Simplify
|
||||
@ -0,0 +1,92 @@
|
||||
From 91e03f431d8ee0b1d316ebd7add232bf49360db2 Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Thu, 12 Feb 2026 10:42:09 +0000
|
||||
Subject: [PATCH] Issue 7231 - Sync repl tests fail in FIPS mode due to non
|
||||
FIPS compliant crypto (#7232)
|
||||
|
||||
Description:
|
||||
Several sync_repl tests fail when running on a FIPS enabled system. The failures
|
||||
are caused by the sync repl client (Sync_persist), using TLS options and ciphers
|
||||
that are not FIPS compatible.
|
||||
|
||||
Fix:
|
||||
Update the sync repl client to use FIPS approved TLS version.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7231
|
||||
|
||||
Reviewed by: @progier389, @droideck (Thank you)
|
||||
---
|
||||
.../tests/suites/syncrepl_plugin/basic_test.py | 15 +++++++++++++--
|
||||
1 file changed, 13 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
index c22331eb5..1e9a530bb 100644
|
||||
--- a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
+++ b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
@@ -20,7 +20,7 @@ from lib389.idm.group import Groups
|
||||
from lib389.topologies import topology_st as topology
|
||||
from lib389.topologies import topology_m2 as topo_m2
|
||||
from lib389.paths import Paths
|
||||
-from lib389.utils import ds_is_older
|
||||
+from lib389.utils import ds_is_older, is_fips
|
||||
from lib389.plugins import RetroChangelogPlugin, ContentSyncPlugin, AutoMembershipPlugin, MemberOfPlugin, MemberOfSharedConfig, AutoMembershipDefinitions, MEPTemplates, MEPConfigs, ManagedEntriesPlugin, MEPTemplate
|
||||
from lib389._constants import *
|
||||
|
||||
@@ -214,6 +214,12 @@ class Sync_persist(threading.Thread, ReconnectLDAPObject, SyncreplConsumer):
|
||||
def run(self):
|
||||
"""Start a sync repl client"""
|
||||
ldap_connection = TestSyncer(self.inst.toLDAPURL())
|
||||
+ ldap_connection.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND)
|
||||
+ ldap_connection.set_option(ldap.OPT_X_TLS_CACERTFILE, os.path.join(self.inst.get_config_dir(), "ca.crt"))
|
||||
+ if is_fips():
|
||||
+ ldap_connection.set_option(ldap.OPT_X_TLS_PROTOCOL_MIN, ldap.OPT_X_TLS_PROTOCOL_TLS1_2)
|
||||
+ ldap_connection.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
|
||||
+
|
||||
ldap_connection.simple_bind_s('cn=directory manager', 'password')
|
||||
ldap_search = ldap_connection.syncrepl_search(
|
||||
"dc=example,dc=com",
|
||||
@@ -253,6 +259,7 @@ def test_sync_repl_mep(topology, request):
|
||||
5. Success
|
||||
"""
|
||||
inst = topology[0]
|
||||
+ inst.enable_tls()
|
||||
|
||||
# Enable/configure retroCL
|
||||
plugin = RetroChangelogPlugin(inst)
|
||||
@@ -338,6 +345,7 @@ def test_sync_repl_cookie(topology, init_sync_repl_plugins, request):
|
||||
5.: succeeds
|
||||
"""
|
||||
inst = topology[0]
|
||||
+ inst.enable_tls()
|
||||
|
||||
# create a sync repl client and wait 5 seconds to be sure it is running
|
||||
sync_repl = Sync_persist(inst)
|
||||
@@ -404,6 +412,8 @@ def test_sync_repl_cookie_add_del(topology, init_sync_repl_plugins, request):
|
||||
6.: succeeds
|
||||
"""
|
||||
inst = topology[0]
|
||||
+ inst.enable_tls()
|
||||
+
|
||||
# create a sync repl client and wait 5 seconds to be sure it is running
|
||||
sync_repl = Sync_persist(inst)
|
||||
sync_repl.start()
|
||||
@@ -547,6 +557,7 @@ def test_sync_repl_cenotaph(topo_m2, request):
|
||||
5. Should succeeds
|
||||
"""
|
||||
m1 = topo_m2.ms["supplier1"]
|
||||
+ m1.enable_tls()
|
||||
# Enable/configure retroCL
|
||||
plugin = RetroChangelogPlugin(m1)
|
||||
plugin.disable()
|
||||
@@ -605,7 +616,7 @@ def test_sync_repl_dynamic_plugin(topology, request):
|
||||
3. Should succeeds
|
||||
4. Should succeeds
|
||||
"""
|
||||
-
|
||||
+ topology.standalone.enable_tls()
|
||||
# Reset the instance in a default config
|
||||
# Disable content sync plugin
|
||||
topology.standalone.plugins.disable(name=PLUGIN_REPL_SYNC)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
From bd57467f6efd8e398eb2e608331711bdd571d3ac Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Thu, 12 Feb 2026 09:58:54 -0500
|
||||
Subject: [PATCH] Issue 7248 - CLI - attribute uniqueness - fix usage for
|
||||
exclude subtree option
|
||||
|
||||
Description:
|
||||
|
||||
Fix typo in usage message for the exclude subtree option
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/7248
|
||||
|
||||
Reviewed by: progier (Thanks!)
|
||||
---
|
||||
src/lib389/lib389/cli_conf/plugins/attruniq.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/cli_conf/plugins/attruniq.py b/src/lib389/lib389/cli_conf/plugins/attruniq.py
|
||||
index bc925eb1c..26ca5d819 100644
|
||||
--- a/src/lib389/lib389/cli_conf/plugins/attruniq.py
|
||||
+++ b/src/lib389/lib389/cli_conf/plugins/attruniq.py
|
||||
@@ -127,7 +127,7 @@ def _add_parser_args(parser):
|
||||
help='Sets the DN under which the plug-in checks for uniqueness of '
|
||||
'the attributes value. This attribute is multi-valued (uniqueness-subtrees)')
|
||||
parser.add_argument('--exclude-subtree', nargs='+',
|
||||
- help='Sets subtrees that should not excludedfrom attribute uniqueness. '
|
||||
+ help='Sets subtrees that should be excluded from attribute uniqueness checks. '
|
||||
'This attribute is multi-valued (uniqueness-exclude-subtrees)')
|
||||
parser.add_argument('--across-all-subtrees', choices=['on', 'off'], type=str.lower,
|
||||
help='If enabled (on), the plug-in checks that the attribute is unique across all subtrees '
|
||||
--
|
||||
2.52.0
|
||||
|
||||
201
0026-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch
Normal file
201
0026-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch
Normal file
@ -0,0 +1,201 @@
|
||||
From 180329d9ca672306f8e90d599890be3a6a8aa95c Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Thu, 12 Feb 2026 11:13:45 -0500
|
||||
Subject: [PATCH] Issue - CLI - dsctl db2index needs some hardening with MBD
|
||||
|
||||
Description:
|
||||
|
||||
The usage for dsctl db2index was confusing. The way the attr options and
|
||||
backend name were displayed it looks like the backend name could come after
|
||||
the attributes, but instead the backend name was treated as an attribute.
|
||||
|
||||
Instead make the backend name required, and change the attribute naming to
|
||||
require individual options instead of a list of values.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7250
|
||||
|
||||
Reviewed by: progier(Thanks!)
|
||||
---
|
||||
.../tests/suites/import/import_test.py | 2 +-
|
||||
src/lib389/lib389/__init__.py | 40 ++++++-------------
|
||||
src/lib389/lib389/cli_ctl/dbtasks.py | 37 +++++++----------
|
||||
3 files changed, 27 insertions(+), 52 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/import/import_test.py b/dirsrvtests/tests/suites/import/import_test.py
|
||||
index 18caec633..058a4b3c7 100644
|
||||
--- a/dirsrvtests/tests/suites/import/import_test.py
|
||||
+++ b/dirsrvtests/tests/suites/import/import_test.py
|
||||
@@ -512,7 +512,7 @@ def test_entry_with_escaped_characters_fails_to_import_and_index(topo, _import_c
|
||||
count += 1
|
||||
# Now re-index the database
|
||||
topo.standalone.stop()
|
||||
- topo.standalone.db2index()
|
||||
+ topo.standalone.db2index(bename="userroot")
|
||||
topo.standalone.start()
|
||||
# Should not return error.
|
||||
assert not topo.standalone.searchErrorsLog('error')
|
||||
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
|
||||
index 39a2852e5..ec47987be 100644
|
||||
--- a/src/lib389/lib389/__init__.py
|
||||
+++ b/src/lib389/lib389/__init__.py
|
||||
@@ -2985,7 +2985,7 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
|
||||
return True
|
||||
|
||||
- def db2index(self, bename=None, suffixes=None, attrs=None, vlvTag=None):
|
||||
+ def db2index(self, bename, suffixes=None, attrs=None, vlvTag=None):
|
||||
"""
|
||||
@param bename - The backend name to reindex
|
||||
@param suffixes - List/tuple of suffixes to reindex, currently unused
|
||||
@@ -2998,34 +2998,18 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
if self.status():
|
||||
self.log.error("db2index: Can not operate while directory server is running")
|
||||
return False
|
||||
- cmd = [prog, ]
|
||||
- # No backend specified, do an upgrade on all backends
|
||||
- # Backend and no attrs specified, reindex with all backend indexes
|
||||
- # Backend and attr/s specified, reindex backend with attr/s
|
||||
- if bename:
|
||||
- cmd.append('db2index')
|
||||
- cmd.append('-n')
|
||||
- cmd.append(bename)
|
||||
- if attrs:
|
||||
- for attr in attrs:
|
||||
- cmd.append('-t')
|
||||
- cmd.append(attr)
|
||||
- else:
|
||||
- dse_ldif = DSEldif(self)
|
||||
- indexes = dse_ldif.get_indexes(bename)
|
||||
- if indexes:
|
||||
- for idx in indexes:
|
||||
- cmd.append('-t')
|
||||
- cmd.append(idx)
|
||||
+ cmd = [prog, 'db2index', '-n', bename, '-D', self.get_config_dir()]
|
||||
+ if attrs:
|
||||
+ for attr in attrs:
|
||||
+ cmd.append('-t')
|
||||
+ cmd.append(attr)
|
||||
else:
|
||||
- cmd.append('upgradedb')
|
||||
- cmd.append('-a')
|
||||
- now = datetime.now().isoformat()
|
||||
- cmd.append(os.path.join(self.get_bak_dir(), 'reindex_%s' % now))
|
||||
- cmd.append('-f')
|
||||
-
|
||||
- cmd.append('-D')
|
||||
- cmd.append(self.get_config_dir())
|
||||
+ dse_ldif = DSEldif(self)
|
||||
+ indexes = dse_ldif.get_indexes(bename)
|
||||
+ if indexes:
|
||||
+ for idx in indexes:
|
||||
+ cmd.append('-t')
|
||||
+ cmd.append(idx)
|
||||
|
||||
try:
|
||||
result = subprocess.check_output(cmd, encoding='utf-8')
|
||||
diff --git a/src/lib389/lib389/cli_ctl/dbtasks.py b/src/lib389/lib389/cli_ctl/dbtasks.py
|
||||
index 16da966d1..cd96cdaf7 100644
|
||||
--- a/src/lib389/lib389/cli_ctl/dbtasks.py
|
||||
+++ b/src/lib389/lib389/cli_ctl/dbtasks.py
|
||||
@@ -26,32 +26,18 @@ class IndexOrdering(Enum):
|
||||
|
||||
|
||||
def dbtasks_db2index(inst, log, args):
|
||||
- rtn = False
|
||||
- if not args.backend:
|
||||
- if not inst.db2index():
|
||||
- rtn = False
|
||||
- else:
|
||||
- rtn = True
|
||||
- elif args.backend and not args.attr:
|
||||
- if not inst.db2index(bename=args.backend):
|
||||
- rtn = False
|
||||
- else:
|
||||
- rtn = True
|
||||
+ inst.log = log
|
||||
+ if not inst.db2index(bename=args.backend, attrs=args.attr):
|
||||
+ log.fatal("db2index failed")
|
||||
+ return False
|
||||
else:
|
||||
- if not inst.db2index(bename=args.backend, attrs=args.attr):
|
||||
- rtn = False
|
||||
- else:
|
||||
- rtn = True
|
||||
- if rtn:
|
||||
log.info("db2index successful")
|
||||
- return rtn
|
||||
- else:
|
||||
- log.fatal("db2index failed")
|
||||
- return rtn
|
||||
+ return True
|
||||
|
||||
|
||||
def dbtasks_db2bak(inst, log, args):
|
||||
# Needs an output name?
|
||||
+ inst.log = log
|
||||
if not inst.db2bak(args.archive):
|
||||
log.fatal("db2bak failed")
|
||||
return False
|
||||
@@ -61,6 +47,7 @@ def dbtasks_db2bak(inst, log, args):
|
||||
|
||||
def dbtasks_bak2db(inst, log, args):
|
||||
# Needs the archive to restore.
|
||||
+ inst.log = log
|
||||
if not inst.bak2db(args.archive):
|
||||
log.fatal("bak2db failed")
|
||||
return False
|
||||
@@ -70,6 +57,7 @@ def dbtasks_bak2db(inst, log, args):
|
||||
|
||||
def dbtasks_db2ldif(inst, log, args):
|
||||
# If export filename is provided, check if file path exists
|
||||
+ inst.log = log
|
||||
if args.ldif:
|
||||
path = Path(args.ldif)
|
||||
parent = path.parent.absolute()
|
||||
@@ -88,6 +76,7 @@ def dbtasks_db2ldif(inst, log, args):
|
||||
|
||||
def dbtasks_ldif2db(inst, log, args):
|
||||
# Check if ldif file exists
|
||||
+ inst.log = log
|
||||
if not os.path.exists(args.ldif):
|
||||
raise ValueError("The LDIF file does not exist: " + args.ldif)
|
||||
|
||||
@@ -103,6 +92,7 @@ def dbtasks_ldif2db(inst, log, args):
|
||||
|
||||
|
||||
def dbtasks_backups(inst, log, args):
|
||||
+ inst.log = log
|
||||
if args.delete:
|
||||
# Delete backup
|
||||
inst.del_backup(args.delete[0])
|
||||
@@ -117,6 +107,7 @@ def dbtasks_backups(inst, log, args):
|
||||
|
||||
|
||||
def dbtasks_ldifs(inst, log, args):
|
||||
+ inst.log = log
|
||||
if args.delete:
|
||||
# Delete LDIF file
|
||||
inst.del_ldif(args.delete[0])
|
||||
@@ -131,6 +122,7 @@ def dbtasks_ldifs(inst, log, args):
|
||||
|
||||
|
||||
def dbtasks_verify(inst, log, args):
|
||||
+ inst.log = log
|
||||
if not inst.dbverify(bename=args.backend):
|
||||
log.fatal("dbverify failed")
|
||||
return False
|
||||
@@ -521,9 +513,8 @@ def dbtasks_index_check(inst, log, args):
|
||||
|
||||
def create_parser(subcommands):
|
||||
db2index_parser = subcommands.add_parser('db2index', help="Initialise a reindex of the server database. The server must be stopped for this to proceed.", formatter_class=CustomHelpFormatter)
|
||||
- # db2index_parser.add_argument('suffix', help="The suffix to reindex. IE dc=example,dc=com.")
|
||||
- db2index_parser.add_argument('backend', nargs="?", help="The backend to reindex. IE userRoot", default=False)
|
||||
- db2index_parser.add_argument('--attr', nargs="*", help="The attribute's to reindex. IE --attr aci cn givenname", default=False)
|
||||
+ db2index_parser.add_argument('backend', help="The backend to reindex. IE userRoot")
|
||||
+ db2index_parser.add_argument('--attr', action='append', help="An attribute to reindex. IE: --attr member --attr cn ...")
|
||||
db2index_parser.set_defaults(func=dbtasks_db2index)
|
||||
|
||||
db2bak_parser = subcommands.add_parser('db2bak', help="Initialise a BDB backup of the database. The server must be stopped for this to proceed.", formatter_class=CustomHelpFormatter)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
From c831a7af2afb7cfd2eb958476a7a8d421ac5d339 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Fri, 13 Feb 2026 15:38:52 +0100
|
||||
Subject: [PATCH] Issue 7184 - (2nd) argparse.HelpFormatter
|
||||
_format_actions_usage() is deprecated (#7257)
|
||||
|
||||
Description:
|
||||
`_format_actions_usage()` was also removed in Python 3.14.3.
|
||||
Replace version check with `isinstance()` to handle the return type of
|
||||
`_get_actions_usage_parts()` more robustly across Python versions.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7184
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7253
|
||||
|
||||
Reviewed by: @progier389 (Thanks!)
|
||||
---
|
||||
src/lib389/lib389/cli_base/__init__.py | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/cli_base/__init__.py b/src/lib389/lib389/cli_base/__init__.py
|
||||
index f1055aadc..3af8a46e6 100644
|
||||
--- a/src/lib389/lib389/cli_base/__init__.py
|
||||
+++ b/src/lib389/lib389/cli_base/__init__.py
|
||||
@@ -420,11 +420,11 @@ class CustomHelpFormatter(argparse.HelpFormatter):
|
||||
else:
|
||||
# Use _get_actions_usage_parts() for Python 3.13 and later
|
||||
action_parts = self._get_actions_usage_parts(parent_arguments, [])
|
||||
- if sys.version_info >= (3, 15):
|
||||
- # Python 3.15 returns a tuple (list of actions, count of actions)
|
||||
+ if isinstance(action_parts, tuple):
|
||||
+ # Python 3.14.3+ and 3.15+ return a tuple (list of actions, count of actions)
|
||||
formatted_options = ' '.join(action_parts[0])
|
||||
else:
|
||||
- # Python 3.13 and 3.14 return a list of actions
|
||||
+ # Earlier versions return a list of actions
|
||||
formatted_options = ' '.join(action_parts)
|
||||
|
||||
# If formatted_options already in usage - remove them
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From a7f8eb79dde03ac771de2335a2acb4aed48483a2 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Fri, 13 Feb 2026 16:27:25 +0100
|
||||
Subject: [PATCH] Issue 7213 - (2nd) MDB_BAD_VALSIZE error while handling VLV
|
||||
(#7258)
|
||||
|
||||
Decription:
|
||||
Disable test_vlv_long_attribute_value on BDB as it hangs sometimes in
|
||||
CI, blocking other pipelines.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7213
|
||||
|
||||
Reviewed by: @progier389 (Thanks!)
|
||||
---
|
||||
dirsrvtests/tests/suites/vlv/regression_test.py | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/vlv/regression_test.py b/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
index 1cc03c303..94001af62 100644
|
||||
--- a/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
@@ -1178,6 +1178,7 @@ def test_vlv_with_mr(vlv_setup_with_uid_mr):
|
||||
|
||||
|
||||
|
||||
+@pytest.mark.skipif(get_default_db_lib() == "bdb", reason="Hangs on BDB")
|
||||
def test_vlv_long_attribute_value(topology_st, request):
|
||||
"""
|
||||
Test VLV with an entry containing a very long attribute value (2K).
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
From 75b1213dfb94495160a735c2688cee03d6be5a9a Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Fri, 13 Feb 2026 16:58:24 +0100
|
||||
Subject: [PATCH] Issue 7223 - Use lexicographical order for ancestorid (#7256)
|
||||
|
||||
Description:
|
||||
`ldbm_instance_create_default_indexes()` configured ancestorid with
|
||||
integerOrderingMatch in the in-memory attrinfo, but ancestorid on disk
|
||||
might be using lexicographic ordering (data before the upgrade or after
|
||||
ldif2db import).
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7223
|
||||
|
||||
Reviewed by: @tbordaz (Thanks!)
|
||||
---
|
||||
ldap/servers/slapd/back-ldbm/instance.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c
|
||||
index 3fcdb5554..563cf96db 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/instance.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/instance.c
|
||||
@@ -239,7 +239,7 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
* ancestorid is special, there is actually no such attr type
|
||||
* but we still want to use the attr index file APIs.
|
||||
*/
|
||||
- e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, "integerOrderingMatch");
|
||||
+ e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, 0);
|
||||
attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL);
|
||||
slapi_entry_free(e);
|
||||
}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
From 7809104b9edb2d05ceee7ca819152f365cc1beb0 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Wed, 11 Feb 2026 15:51:47 -0500
|
||||
Subject: [PATCH] Issue 7066/7052 - allow password history to be set to zero
|
||||
and remove history
|
||||
|
||||
Description:
|
||||
|
||||
For local password policies the server was incorrectly rejecting updates that
|
||||
set the value to zero. When password history is set to zero the old passwords
|
||||
in the entry history are not cleaned as expected.
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/7052
|
||||
relates: https://github.com/389ds/389-ds-base/issues/7066
|
||||
|
||||
Reviewed by: progier(Thanks!)
|
||||
---
|
||||
.../tests/suites/password/pwp_history_test.py | 9 ++++++---
|
||||
ldap/servers/slapd/modify.c | 2 +-
|
||||
ldap/servers/slapd/pw.c | 13 ++++++++++++-
|
||||
3 files changed, 19 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/pwp_history_test.py b/dirsrvtests/tests/suites/password/pwp_history_test.py
|
||||
index 8a15a1986..387824bc5 100644
|
||||
--- a/dirsrvtests/tests/suites/password/pwp_history_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/pwp_history_test.py
|
||||
@@ -108,8 +108,12 @@ def test_history_is_not_overwritten(topology_st, user):
|
||||
user.set('userpassword', USER_PWD)
|
||||
|
||||
|
||||
-def test_basic(topology_st, user):
|
||||
- """Test basic password policy history feature functionality
|
||||
+@pytest.mark.parametrize('policy',
|
||||
+ [(pytest.param('global')),
|
||||
+ (pytest.param('subtree')),
|
||||
+ (pytest.param('user'))])
|
||||
+def test_basic(topology_st, user, policy):
|
||||
+ """Test basic password policy history feature functionality with dynamic count reduction
|
||||
|
||||
:id: 83d74f7d-3036-4944-8839-1b40bbf265ff
|
||||
:setup: Standalone instance, a test user
|
||||
@@ -238,7 +242,6 @@ def test_basic(topology_st, user):
|
||||
|
||||
#
|
||||
# Reset password by Directory Manager(admin reset)
|
||||
- #
|
||||
dm = DirectoryManager(topology_st.standalone)
|
||||
dm.rebind()
|
||||
time.sleep(.5)
|
||||
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
|
||||
index b0066faf8..d76427886 100644
|
||||
--- a/ldap/servers/slapd/modify.c
|
||||
+++ b/ldap/servers/slapd/modify.c
|
||||
@@ -87,7 +87,7 @@ static struct attr_value_check
|
||||
{CONFIG_PW_WARNING_ATTRIBUTE, check_pw_duration_value, 0, -1},
|
||||
{CONFIG_PW_MINLENGTH_ATTRIBUTE, attr_check_minmax, 2, 512},
|
||||
{CONFIG_PW_MAXFAILURE_ATTRIBUTE, attr_check_minmax, 1, 32767},
|
||||
- {CONFIG_PW_INHISTORY_ATTRIBUTE, attr_check_minmax, 1, 24},
|
||||
+ {CONFIG_PW_INHISTORY_ATTRIBUTE, attr_check_minmax, 0, 24},
|
||||
{CONFIG_PW_LOCKDURATION_ATTRIBUTE, check_pw_duration_value, -1, -1},
|
||||
{CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE, check_pw_resetfailurecount_value, -1, -1},
|
||||
{CONFIG_PW_GRACELIMIT_ATTRIBUTE, attr_check_minmax, 0, -1},
|
||||
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
|
||||
index cda1c404f..12cf759ce 100644
|
||||
--- a/ldap/servers/slapd/pw.c
|
||||
+++ b/ldap/servers/slapd/pw.c
|
||||
@@ -1532,7 +1532,18 @@ update_pw_history(Slapi_PBlock *pb, const Slapi_DN *sdn, char *old_pw)
|
||||
pwpolicy = new_passwdPolicy(pb, dn);
|
||||
|
||||
if (pwpolicy->pw_inhistory == 0){
|
||||
- /* We are only enforcing the current password, just return */
|
||||
+ /* We are only enforcing the current password, just return but first
|
||||
+ * cleanup any old passwords in the history */
|
||||
+ attribute.mod_type = "passwordHistory";
|
||||
+ attribute.mod_op = LDAP_MOD_REPLACE;
|
||||
+ attribute.mod_values = NULL;
|
||||
+ list_of_mods[0] = &attribute;
|
||||
+ list_of_mods[1] = NULL;
|
||||
+ mod_pb = slapi_pblock_new();
|
||||
+ slapi_modify_internal_set_pb_ext(mod_pb, sdn, list_of_mods, NULL, NULL, pw_get_componentID(), 0);
|
||||
+ slapi_modify_internal_pb(mod_pb);
|
||||
+ slapi_pblock_destroy(mod_pb);
|
||||
+
|
||||
return res;
|
||||
}
|
||||
|
||||
--
|
||||
2.52.0
|
||||
|
||||
260
0031-Issue-7243-UI-fix-certificate-table-and-modal.patch
Normal file
260
0031-Issue-7243-UI-fix-certificate-table-and-modal.patch
Normal file
@ -0,0 +1,260 @@
|
||||
From 4209ff65310c54b6ab55594984201b1214fb75b2 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 16 Feb 2026 16:52:52 -0500
|
||||
Subject: [PATCH] Issue 7243 - UI - fix certificate table and modal
|
||||
|
||||
Description:
|
||||
|
||||
The certificate table was not handling sorting and pagination correctly, and
|
||||
the add cert modal was not correctly selecting certs on disk
|
||||
|
||||
This was fixed upstream for the hot cetificate features, but only backporting
|
||||
the table/modal changes to older branches
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/7243
|
||||
|
||||
Reviewed by: spichugi(Thanks!)
|
||||
---
|
||||
.../src/lib/security/securityModals.jsx | 4 +-
|
||||
.../src/lib/security/securityTables.jsx | 85 ++++++-------------
|
||||
2 files changed, 29 insertions(+), 60 deletions(-)
|
||||
|
||||
diff --git a/src/cockpit/389-console/src/lib/security/securityModals.jsx b/src/cockpit/389-console/src/lib/security/securityModals.jsx
|
||||
index a42aa50d6..c4af753c0 100644
|
||||
--- a/src/cockpit/389-console/src/lib/security/securityModals.jsx
|
||||
+++ b/src/cockpit/389-console/src/lib/security/securityModals.jsx
|
||||
@@ -298,7 +298,9 @@ export class SecurityAddCertModal extends React.Component {
|
||||
<FormSelect
|
||||
value={selectCertName}
|
||||
id="selectCertName"
|
||||
- onChange={handleCertSelect}
|
||||
+ onChange={(e, str) => {
|
||||
+ handleCertSelect(str);
|
||||
+ }}
|
||||
aria-label="FormSelect Input"
|
||||
className="ds-cert-select"
|
||||
validated={selectValidated}
|
||||
diff --git a/src/cockpit/389-console/src/lib/security/securityTables.jsx b/src/cockpit/389-console/src/lib/security/securityTables.jsx
|
||||
index fce4cb04e..a6c64e6c1 100644
|
||||
--- a/src/cockpit/389-console/src/lib/security/securityTables.jsx
|
||||
+++ b/src/cockpit/389-console/src/lib/security/securityTables.jsx
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
Grid,
|
||||
GridItem,
|
||||
Pagination,
|
||||
- PaginationVariant,
|
||||
SearchInput,
|
||||
Tooltip,
|
||||
} from '@patternfly/react-core';
|
||||
@@ -94,10 +93,10 @@ class KeyTable extends React.Component {
|
||||
];
|
||||
|
||||
handleSort(_event, index, direction) {
|
||||
- const sortedRows = [...this.state.rows].sort((a, b) =>
|
||||
+ const sortedRows = [...this.state.rows].sort((a, b) =>
|
||||
(a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)
|
||||
);
|
||||
-
|
||||
+
|
||||
this.setState({
|
||||
sortBy: {
|
||||
index,
|
||||
@@ -127,7 +126,7 @@ class KeyTable extends React.Component {
|
||||
>
|
||||
<a className="ds-font-size-sm">{_("What is an orphan key?")}</a>
|
||||
</Tooltip>
|
||||
- <Table
|
||||
+ <Table
|
||||
className="ds-margin-top"
|
||||
aria-label="orph key table"
|
||||
variant="compact"
|
||||
@@ -135,7 +134,7 @@ class KeyTable extends React.Component {
|
||||
<Thead>
|
||||
<Tr>
|
||||
{columns.map((column, idx) => (
|
||||
- <Th
|
||||
+ <Th
|
||||
key={idx}
|
||||
sort={column.sortable ? {
|
||||
sortBy,
|
||||
@@ -163,7 +162,7 @@ class KeyTable extends React.Component {
|
||||
)}
|
||||
{hasRows && (
|
||||
<Td isActionCell>
|
||||
- <ActionsColumn
|
||||
+ <ActionsColumn
|
||||
items={this.getActionsForRow(row)}
|
||||
/>
|
||||
</Td>
|
||||
@@ -224,7 +223,7 @@ class CSRTable extends React.Component {
|
||||
}
|
||||
|
||||
handleSort(_event, index, direction) {
|
||||
- const sortedRows = [...this.state.rows].sort((a, b) =>
|
||||
+ const sortedRows = [...this.state.rows].sort((a, b) =>
|
||||
(a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)
|
||||
);
|
||||
this.setState({
|
||||
@@ -316,7 +315,7 @@ class CSRTable extends React.Component {
|
||||
onClear={(evt) => this.handleSearchChange(evt, '')}
|
||||
/>
|
||||
}
|
||||
- <Table
|
||||
+ <Table
|
||||
className="ds-margin-top"
|
||||
aria-label="csr table"
|
||||
variant="compact"
|
||||
@@ -324,7 +323,7 @@ class CSRTable extends React.Component {
|
||||
<Thead>
|
||||
<Tr>
|
||||
{columns.map((column, idx) => (
|
||||
- <Th
|
||||
+ <Th
|
||||
key={idx}
|
||||
sort={column.sortable ? {
|
||||
sortBy,
|
||||
@@ -352,7 +351,7 @@ class CSRTable extends React.Component {
|
||||
)}
|
||||
{hasRows && (
|
||||
<Td isActionCell>
|
||||
- <ActionsColumn
|
||||
+ <ActionsColumn
|
||||
items={this.getActionsForRow(row)}
|
||||
/>
|
||||
</Td>
|
||||
@@ -418,41 +417,11 @@ class CertTable extends React.Component {
|
||||
}
|
||||
|
||||
handleSort(_event, columnIndex, direction) {
|
||||
- const sorted_rows = [];
|
||||
- const rows = [];
|
||||
- let count = 0;
|
||||
-
|
||||
- // Convert the rows pairings into a sortable array
|
||||
- for (let idx = 0; idx < this.state.rows.length; idx += 2) {
|
||||
- sorted_rows.push({
|
||||
- expandedRow: this.state.rows[idx + 1],
|
||||
- 1: this.state.rows[idx].cells[0].content,
|
||||
- 2: this.state.rows[idx].cells[1].content,
|
||||
- 3: this.state.rows[idx].cells[2].content,
|
||||
- issuer: this.state.rows[idx].issuer,
|
||||
- flags: this.state.rows[idx].flags
|
||||
- });
|
||||
- }
|
||||
+ const rows = [...this.state.rows];
|
||||
|
||||
- sorted_rows.sort((a, b) => (a[columnIndex + 1] > b[columnIndex + 1]) ? 1 : -1);
|
||||
+ rows.sort((a, b) => (a.cells[columnIndex].content > b.cells[columnIndex].content) ? 1 : -1);
|
||||
if (direction !== SortByDirection.asc) {
|
||||
- sorted_rows.reverse();
|
||||
- }
|
||||
-
|
||||
- for (const srow of sorted_rows) {
|
||||
- rows.push({
|
||||
- isOpen: false,
|
||||
- cells: [
|
||||
- { content: srow[1] },
|
||||
- { content: srow[2] },
|
||||
- { content: srow[3] }
|
||||
- ],
|
||||
- issuer: srow.issuer,
|
||||
- flags: srow.flags,
|
||||
- });
|
||||
- srow.expandedRow.parent = count;
|
||||
- rows.push(srow.expandedRow);
|
||||
- count += 2;
|
||||
+ rows.reverse();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
@@ -534,18 +503,16 @@ class CertTable extends React.Component {
|
||||
rows.push(
|
||||
{
|
||||
isOpen: false,
|
||||
- cells: [cert.attrs.nickname, cert.attrs.subject, cert.attrs.expires],
|
||||
+ cells: [
|
||||
+ { content: cert.attrs.nickname },
|
||||
+ { content: cert.attrs.subject },
|
||||
+ { content: cert.attrs.expires }
|
||||
+ ],
|
||||
issuer: cert.attrs.issuer,
|
||||
flags: cert.attrs.flags,
|
||||
-
|
||||
- },
|
||||
- {
|
||||
- parent: count,
|
||||
- fullWidth: true,
|
||||
- cells: [{ title: this.getExpandedRow(cert.attrs.issuer, cert.attrs.flags) }]
|
||||
- },
|
||||
+ }
|
||||
);
|
||||
- count += 2;
|
||||
+ count += 1;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
@@ -587,7 +554,7 @@ class CertTable extends React.Component {
|
||||
onChange={this.handleSearchChange}
|
||||
onClear={(evt) => this.handleSearchChange(evt, '')}
|
||||
/>}
|
||||
- <Table
|
||||
+ <Table
|
||||
aria-label="cert table"
|
||||
variant='compact'
|
||||
>
|
||||
@@ -626,7 +593,7 @@ class CertTable extends React.Component {
|
||||
</Td>
|
||||
))}
|
||||
<Td isActionCell>
|
||||
- <ActionsColumn
|
||||
+ <ActionsColumn
|
||||
items={this.getActionsForRow(row)}
|
||||
/>
|
||||
</Td>
|
||||
@@ -646,7 +613,7 @@ class CertTable extends React.Component {
|
||||
</Table>
|
||||
{hasRows &&
|
||||
<Pagination
|
||||
- itemCount={this.state.rows.length / 2}
|
||||
+ itemCount={this.state.rows.length}
|
||||
widgetId="pagination-options-menu-bottom"
|
||||
perPage={perPage}
|
||||
page={page}
|
||||
@@ -728,7 +695,7 @@ class CRLTable extends React.Component {
|
||||
if (direction !== SortByDirection.asc) {
|
||||
sorted_rows.reverse();
|
||||
}
|
||||
-
|
||||
+
|
||||
for (const srow of sorted_rows) {
|
||||
rows.push({
|
||||
isOpen: false,
|
||||
@@ -806,14 +773,14 @@ class CRLTable extends React.Component {
|
||||
onChange={this.handleSearchChange}
|
||||
onClear={(evt) => this.handleSearchChange(evt, '')}
|
||||
/>
|
||||
- <Table
|
||||
+ <Table
|
||||
aria-label="CRL Table"
|
||||
variant="compact"
|
||||
>
|
||||
<Thead>
|
||||
<Tr>
|
||||
{this.state.columns.map((column, idx) => (
|
||||
- <Th
|
||||
+ <Th
|
||||
key={idx}
|
||||
sort={column.sortable ? {
|
||||
sortBy: this.state.sortBy,
|
||||
@@ -836,7 +803,7 @@ class CRLTable extends React.Component {
|
||||
))}
|
||||
{this.state.hasRows && (
|
||||
<Td isActionCell>
|
||||
- <ActionsColumn
|
||||
+ <ActionsColumn
|
||||
items={this.getActionsForRow(row)}
|
||||
/>
|
||||
</Td>
|
||||
--
|
||||
2.52.0
|
||||
|
||||
538
0032-Issue-7223-Remove-integerOrderingMatch-requirement-f.patch
Normal file
538
0032-Issue-7223-Remove-integerOrderingMatch-requirement-f.patch
Normal file
@ -0,0 +1,538 @@
|
||||
From 09b6f770f15ee8d333377b7902e18b78f4f7008c Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Wed, 18 Feb 2026 09:26:57 +0100
|
||||
Subject: [PATCH] Issue 7223 - Remove integerOrderingMatch requirement for
|
||||
parentid (#7264)
|
||||
|
||||
Description:
|
||||
integerOrderingMatch was introduced as a requirement for parentid and
|
||||
ancestorid indexes for performance reasons. But after #7096 the order
|
||||
for parentid doesn't make a lot of difference.
|
||||
|
||||
Fix Description:
|
||||
* Remove integerOrderingMatch requirement for parentid.
|
||||
* Read only first 100 keys from dbscan in index ordering check
|
||||
* Do not run dsctl index-check during RPM upgrade
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/pull/7223
|
||||
|
||||
Reviewed by: @progier389, @tbordaz (Thanks!)
|
||||
---
|
||||
.../healthcheck/health_system_indexes_test.py | 83 ++++----------
|
||||
ldap/servers/slapd/upgrade.c | 105 ------------------
|
||||
rpm/389-ds-base.spec.in | 3 -
|
||||
src/lib389/lib389/backend.py | 5 +-
|
||||
src/lib389/lib389/cli_ctl/dbtasks.py | 99 ++++++++---------
|
||||
5 files changed, 73 insertions(+), 222 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
index 3b3651b38..71a9f590a 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -180,7 +180,8 @@ def test_missing_parentid(topology_st, log_buffering_enabled):
|
||||
|
||||
|
||||
def test_missing_matching_rule(topology_st, log_buffering_enabled):
|
||||
- """Check if healthcheck returns DSBLE0007 code when parentId index is missing integerOrderingMatch
|
||||
+ """Check that healthcheck does NOT report DSBLE0007 when parentId index is missing integerOrderingMatch.
|
||||
+ Both lexicographic and integer orderings are valid for parentid.
|
||||
|
||||
:id: 7ffa71db-8995-430a-bed8-59bce944221c
|
||||
:setup: Standalone instance
|
||||
@@ -190,19 +191,14 @@ def test_missing_matching_rule(topology_st, log_buffering_enabled):
|
||||
3. Use healthcheck without --json option
|
||||
4. Use healthcheck with --json option
|
||||
5. Re-add the matching rule
|
||||
- 6. Use healthcheck without --json option
|
||||
- 7. Use healthcheck with --json option
|
||||
:expectedresults:
|
||||
1. Success
|
||||
2. Success
|
||||
- 3. healthcheck reports DSBLE0007 code and related details
|
||||
- 4. healthcheck reports DSBLE0007 code and related details
|
||||
+ 3. healthcheck reports no issues found
|
||||
+ 4. healthcheck reports no issues found
|
||||
5. Success
|
||||
- 6. healthcheck reports no issues found
|
||||
- 7. healthcheck reports no issues found
|
||||
"""
|
||||
|
||||
- RET_CODE = "DSBLE0007"
|
||||
PARENTID_DN = "cn=parentid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config"
|
||||
|
||||
standalone = topology_st.standalone
|
||||
@@ -211,17 +207,14 @@ def test_missing_matching_rule(topology_st, log_buffering_enabled):
|
||||
parentid_index = Index(standalone, PARENTID_DN)
|
||||
parentid_index.remove("nsMatchingRule", "integerOrderingMatch")
|
||||
|
||||
- run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=RET_CODE)
|
||||
- run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=RET_CODE)
|
||||
+ run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT)
|
||||
+ run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT)
|
||||
|
||||
log.info("Re-add the integerOrderingMatch matching rule")
|
||||
parentid_index = Index(standalone, PARENTID_DN)
|
||||
parentid_index.add("nsMatchingRule", "integerOrderingMatch")
|
||||
standalone.restart()
|
||||
|
||||
- run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT)
|
||||
- run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT)
|
||||
-
|
||||
|
||||
def test_usn_plugin_missing_entryusn(topology_st, usn_plugin_enabled, log_buffering_enabled):
|
||||
"""Check if healthcheck returns DSBLE0007 code when USN plugin is enabled but entryusn index is missing
|
||||
@@ -911,7 +904,9 @@ def test_index_check_fixes_ancestorid_config(topology_st):
|
||||
|
||||
|
||||
def test_index_check_fixes_missing_matching_rule(topology_st):
|
||||
- """Check if dsctl index-check --fix adds missing integerOrderingMatch
|
||||
+ """Check that removing integerOrderingMatch from parentid config is not
|
||||
+ flagged as an issue when disk ordering cannot be determined.
|
||||
+ Both lexicographic and integer orderings are valid for parentid.
|
||||
|
||||
:id: 6c1d4e9f-0a3b-4d5c-1e7f-8a9b0c2d3e4f
|
||||
:setup: Standalone instance
|
||||
@@ -919,18 +914,14 @@ def test_index_check_fixes_missing_matching_rule(topology_st):
|
||||
1. Create DS instance
|
||||
2. Stop the server
|
||||
3. Remove integerOrderingMatch from parentid index using DSEldif
|
||||
- 4. Run dsctl index-check (should detect issue)
|
||||
- 5. Run dsctl index-check --fix
|
||||
- 6. Verify integerOrderingMatch was added back
|
||||
- 7. Start the server
|
||||
+ 4. Run dsctl index-check (should NOT detect issue since disk ordering is unknown)
|
||||
+ 5. Start the server
|
||||
:expectedresults:
|
||||
1. Success
|
||||
2. Success
|
||||
3. Success
|
||||
- 4. index-check returns False and detects missing matching rule
|
||||
- 5. index-check returns True after fix
|
||||
- 6. integerOrderingMatch is present
|
||||
- 7. Success
|
||||
+ 4. index-check returns True (no issues, disk ordering unknown)
|
||||
+ 5. Success
|
||||
"""
|
||||
from lib389.cli_ctl.dbtasks import dbtasks_index_check
|
||||
from lib389.dseldif import DSEldif
|
||||
@@ -964,34 +955,20 @@ def test_index_check_fixes_missing_matching_rule(topology_st):
|
||||
f"integerOrderingMatch should be removed, but found: {mr}"
|
||||
log.info("integerOrderingMatch removed from parentid index")
|
||||
|
||||
- log.info("Run index-check without --fix (should detect issue)")
|
||||
+ log.info("Run index-check (should NOT detect issue - disk ordering unknown)")
|
||||
args = FakeArgs()
|
||||
args.backend = "userRoot"
|
||||
args.fix = False
|
||||
|
||||
result = dbtasks_index_check(standalone, topology_st.logcap.log, args)
|
||||
- assert result is False, "index-check should detect missing matching rule"
|
||||
- assert topology_st.logcap.contains("missing integerOrderingMatch")
|
||||
+ assert result is True, \
|
||||
+ "index-check should not flag missing integerOrderingMatch when disk ordering is unknown"
|
||||
+ assert topology_st.logcap.contains("could not determine disk ordering")
|
||||
topology_st.logcap.flush()
|
||||
|
||||
- log.info("Run index-check with --fix")
|
||||
- args.fix = True
|
||||
- result = dbtasks_index_check(standalone, topology_st.logcap.log, args)
|
||||
- assert result is True, "index-check --fix should succeed"
|
||||
- assert topology_st.logcap.contains("integerOrderingMatch")
|
||||
- topology_st.logcap.flush()
|
||||
-
|
||||
- log.info("Verify integerOrderingMatch was added back")
|
||||
- dse_ldif = DSEldif(standalone) # Reload to get fresh data
|
||||
- matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule")
|
||||
- assert matching_rules is not None, "nsMatchingRule should be present"
|
||||
- found_int_order = False
|
||||
- for mr in matching_rules:
|
||||
- if "integerorderingmatch" in mr.lower():
|
||||
- found_int_order = True
|
||||
- break
|
||||
- assert found_int_order, f"integerOrderingMatch should be present, got: {matching_rules}"
|
||||
- log.info("integerOrderingMatch successfully added back")
|
||||
+ log.info("Restore integerOrderingMatch and start the server")
|
||||
+ dse_ldif = DSEldif(standalone)
|
||||
+ dse_ldif.add(parentid_dn, "nsMatchingRule", "integerOrderingMatch")
|
||||
|
||||
log.info("Start the server")
|
||||
standalone.start()
|
||||
@@ -1081,7 +1058,7 @@ def test_index_check_fixes_multiple_issues(topology_st):
|
||||
:steps:
|
||||
1. Create DS instance
|
||||
2. Stop the server
|
||||
- 3. Add multiple issues: scanlimit, ancestorid config, missing matching rule
|
||||
+ 3. Add multiple issues: scanlimit and ancestorid config
|
||||
4. Run dsctl index-check (should detect all issues)
|
||||
5. Run dsctl index-check --fix
|
||||
6. Verify all issues were fixed
|
||||
@@ -1123,14 +1100,6 @@ def test_index_check_fixes_multiple_issues(topology_st):
|
||||
]
|
||||
dse_ldif.add_entry(ancestorid_entry)
|
||||
|
||||
- log.info("Add issue 3: Remove integerOrderingMatch from parentid")
|
||||
- dse_ldif = DSEldif(standalone) # Reload
|
||||
- matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule")
|
||||
- if matching_rules:
|
||||
- for mr in matching_rules:
|
||||
- if "integerorderingmatch" in mr.lower():
|
||||
- dse_ldif.delete(parentid_dn, "nsMatchingRule", mr)
|
||||
-
|
||||
log.info("Run index-check without --fix (should detect all issues)")
|
||||
args = FakeArgs()
|
||||
args.backend = "userRoot"
|
||||
@@ -1161,16 +1130,6 @@ def test_index_check_fixes_multiple_issues(topology_st):
|
||||
cn_value = dse_ldif.get(ancestorid_dn, "cn", single=True)
|
||||
assert cn_value is None, f"ancestorid config should be removed, got: {cn_value}"
|
||||
|
||||
- # Check matching rule added back
|
||||
- matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule")
|
||||
- found_int_order = False
|
||||
- if matching_rules:
|
||||
- for mr in matching_rules:
|
||||
- if "integerorderingmatch" in mr.lower():
|
||||
- found_int_order = True
|
||||
- break
|
||||
- assert found_int_order, f"integerOrderingMatch should be present, got: {matching_rules}"
|
||||
-
|
||||
log.info("All issues verified as fixed")
|
||||
|
||||
log.info("Run index-check again to confirm all clear")
|
||||
diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c
|
||||
index d9156cae9..537c38feb 100644
|
||||
--- a/ldap/servers/slapd/upgrade.c
|
||||
+++ b/ldap/servers/slapd/upgrade.c
|
||||
@@ -500,107 +500,6 @@ upgrade_remove_ancestorid_index_config(void)
|
||||
return uresult;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Check if parentid/ancestorid indexes are missing the integerOrderingMatch
|
||||
- * matching rule.
|
||||
- *
|
||||
- * This function logs a warning if we detect this condition, advising
|
||||
- * the administrator to reindex the affected attributes.
|
||||
- */
|
||||
-static upgrade_status
|
||||
-upgrade_check_id_index_matching_rule(void)
|
||||
-{
|
||||
- struct slapi_pblock *pb = slapi_pblock_new();
|
||||
- Slapi_Entry **backends = NULL;
|
||||
- const char *be_base_dn = "cn=ldbm database,cn=plugins,cn=config";
|
||||
- const char *be_filter = "(objectclass=nsBackendInstance)";
|
||||
- const char *attrs_to_check[] = {"parentid", NULL};
|
||||
- upgrade_status uresult = UPGRADE_SUCCESS;
|
||||
-
|
||||
- /* Search for all backend instances */
|
||||
- slapi_search_internal_set_pb(
|
||||
- pb, be_base_dn,
|
||||
- LDAP_SCOPE_ONELEVEL,
|
||||
- be_filter, NULL, 0, NULL, NULL,
|
||||
- plugin_get_default_component_id(), 0);
|
||||
- slapi_search_internal_pb(pb);
|
||||
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &backends);
|
||||
-
|
||||
- if (backends) {
|
||||
- for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) {
|
||||
- const char *be_dn = slapi_entry_get_dn_const(backends[be_idx]);
|
||||
- const char *be_name = slapi_entry_attr_get_ref(backends[be_idx], "cn");
|
||||
- if (!be_dn || !be_name) {
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- /* Check each attribute that should have integerOrderingMatch */
|
||||
- for (size_t attr_idx = 0; attrs_to_check[attr_idx] != NULL; attr_idx++) {
|
||||
- const char *attr_name = attrs_to_check[attr_idx];
|
||||
- struct slapi_pblock *idx_pb = slapi_pblock_new();
|
||||
- Slapi_Entry **idx_entries = NULL;
|
||||
- char *idx_dn = slapi_create_dn_string("cn=%s,cn=index,%s",
|
||||
- attr_name, be_dn);
|
||||
- char *idx_filter = "(objectclass=nsIndex)";
|
||||
- PRBool has_matching_rule = PR_FALSE;
|
||||
-
|
||||
- if (!idx_dn) {
|
||||
- slapi_pblock_destroy(idx_pb);
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- slapi_search_internal_set_pb(
|
||||
- idx_pb, idx_dn,
|
||||
- LDAP_SCOPE_BASE,
|
||||
- idx_filter, NULL, 0, NULL, NULL,
|
||||
- plugin_get_default_component_id(), 0);
|
||||
- slapi_search_internal_pb(idx_pb);
|
||||
- slapi_pblock_get(idx_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &idx_entries);
|
||||
-
|
||||
- if (idx_entries && idx_entries[0]) {
|
||||
- /* Index exists, check if it has integerOrderingMatch */
|
||||
- Slapi_Attr *mr_attr = NULL;
|
||||
- if (slapi_entry_attr_find(idx_entries[0], "nsMatchingRule", &mr_attr) == 0) {
|
||||
- Slapi_Value *sval = NULL;
|
||||
- int idx;
|
||||
- for (idx = slapi_attr_first_value(mr_attr, &sval);
|
||||
- idx != -1;
|
||||
- idx = slapi_attr_next_value(mr_attr, idx, &sval)) {
|
||||
- const struct berval *bval = slapi_value_get_berval(sval);
|
||||
- if (bval && bval->bv_val &&
|
||||
- strcasecmp(bval->bv_val, "integerOrderingMatch") == 0) {
|
||||
- has_matching_rule = PR_TRUE;
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (!has_matching_rule) {
|
||||
- /* Index exists but doesn't have integerOrderingMatch, log a warning */
|
||||
- slapi_log_err(SLAPI_LOG_ERR, "upgrade_check_id_index_matching_rule",
|
||||
- "Index '%s' in backend '%s' is missing 'nsMatchingRule: integerOrderingMatch'. "
|
||||
- "Incorrectly configured system indexes can lead to poor search performance, replication issues, and other operational problems. "
|
||||
- "To fix this, add the matching rule and reindex: "
|
||||
- "dsconf <instance> backend index set --add-mr integerOrderingMatch --attr %s %s && "
|
||||
- "dsconf <instance> backend index reindex --attr %s %s. "
|
||||
- "WARNING: Reindexing can be resource-intensive and may impact server performance on a live system. "
|
||||
- "Consider scheduling reindexing during maintenance windows or periods of low activity.\n",
|
||||
- attr_name, be_name, attr_name, be_name, attr_name, be_name);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- slapi_ch_free_string(&idx_dn);
|
||||
- slapi_free_search_results_internal(idx_pb);
|
||||
- slapi_pblock_destroy(idx_pb);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- slapi_free_search_results_internal(pb);
|
||||
- slapi_pblock_destroy(pb);
|
||||
-
|
||||
- return uresult;
|
||||
-}
|
||||
|
||||
upgrade_status
|
||||
upgrade_server(void)
|
||||
@@ -637,10 +536,6 @@ upgrade_server(void)
|
||||
return UPGRADE_FAILURE;
|
||||
}
|
||||
|
||||
- if (upgrade_check_id_index_matching_rule() != UPGRADE_SUCCESS) {
|
||||
- return UPGRADE_FAILURE;
|
||||
- }
|
||||
-
|
||||
return UPGRADE_SUCCESS;
|
||||
}
|
||||
|
||||
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
|
||||
index 0175dfa7c..f78258f6a 100644
|
||||
--- a/rpm/389-ds-base.spec.in
|
||||
+++ b/rpm/389-ds-base.spec.in
|
||||
@@ -667,9 +667,6 @@ for dir in "$instbase"/slapd-* ; do
|
||||
else
|
||||
echo "instance $inst is not running" >> "$output" 2>&1 || :
|
||||
fi
|
||||
- # Run index-check on all instances (running or not)
|
||||
- # This fixes index ordering mismatches from older versions
|
||||
- dsctl "$inst_name" index-check --fix >> "$output2" 2>&1 || :
|
||||
ninst=$((ninst + 1))
|
||||
done
|
||||
|
||||
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
|
||||
index 1d9be4683..29a1796ac 100644
|
||||
--- a/src/lib389/lib389/backend.py
|
||||
+++ b/src/lib389/lib389/backend.py
|
||||
@@ -617,9 +617,10 @@ class Backend(DSLdapObject):
|
||||
# Default system indexes taken from ldap/servers/slapd/back-ldbm/instance.c
|
||||
# Note: entryrdn and ancestorid are internal system indexes that are not
|
||||
# exposed in cn=config - they are managed internally by the server.
|
||||
- # Only parentid has a DSE config entry (for the integerOrderingMatch rule).
|
||||
+ # parentid works correctly with both lexicographic and integer ordering,
|
||||
+ # so integerOrderingMatch is not required.
|
||||
expected_system_indexes = {
|
||||
- 'parentid': {'types': ['eq'], 'matching_rule': 'integerOrderingMatch'},
|
||||
+ 'parentid': {'types': ['eq'], 'matching_rule': None},
|
||||
'objectClass': {'types': ['eq'], 'matching_rule': None},
|
||||
'aci': {'types': ['pres'], 'matching_rule': None},
|
||||
'nscpEntryDN': {'types': ['eq'], 'matching_rule': None},
|
||||
diff --git a/src/lib389/lib389/cli_ctl/dbtasks.py b/src/lib389/lib389/cli_ctl/dbtasks.py
|
||||
index cd96cdaf7..b02de203f 100644
|
||||
--- a/src/lib389/lib389/cli_ctl/dbtasks.py
|
||||
+++ b/src/lib389/lib389/cli_ctl/dbtasks.py
|
||||
@@ -10,6 +10,7 @@
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
+import signal
|
||||
import subprocess
|
||||
from enum import Enum
|
||||
from lib389._constants import TaskWarning
|
||||
@@ -263,45 +264,53 @@ def _check_disk_ordering(db_dir, backend, index_name, dbscan_path, is_mdb, log):
|
||||
if not index_file:
|
||||
return IndexOrdering.UNKNOWN
|
||||
|
||||
+ # Only read the first 100 lines from dbscan to avoid scanning the
|
||||
+ # entire index (which can take hours on large databases).
|
||||
try:
|
||||
- result = subprocess.run(
|
||||
+ proc = subprocess.Popen(
|
||||
[dbscan_path, "-f", index_file],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
- timeout=60,
|
||||
)
|
||||
|
||||
- if result.returncode != 0:
|
||||
- log.warning(" dbscan returned non-zero exit code for %s", index_file)
|
||||
- return IndexOrdering.UNKNOWN
|
||||
-
|
||||
- # Parse keys from dbscan output
|
||||
keys = []
|
||||
- for line in result.stdout.split("\n"):
|
||||
+ line_count = 0
|
||||
+ assert proc.stdout is not None
|
||||
+ for line in proc.stdout:
|
||||
+ line_count += 1
|
||||
+ if line_count > 100:
|
||||
+ break
|
||||
line = line.strip()
|
||||
if line.startswith("="):
|
||||
match = re.match(r"^=(\d+)", line)
|
||||
if match:
|
||||
keys.append(int(match.group(1)))
|
||||
|
||||
+ proc.terminate()
|
||||
+ try:
|
||||
+ proc.wait(timeout=5)
|
||||
+ except subprocess.TimeoutExpired:
|
||||
+ proc.kill()
|
||||
+ proc.wait()
|
||||
+
|
||||
+ if proc.returncode not in (0, -signal.SIGTERM):
|
||||
+ log.warning(" dbscan returned non-zero exit code for %s", index_file)
|
||||
+ return IndexOrdering.UNKNOWN
|
||||
+
|
||||
if len(keys) < 2:
|
||||
return IndexOrdering.UNKNOWN
|
||||
|
||||
# Check if keys are in integer order by looking for decreasing numeric values
|
||||
# (which would indicate lexicographic ordering, e.g., "3" < "30" < "4")
|
||||
prev_id = keys[0]
|
||||
- for i in range(1, min(len(keys), 100)):
|
||||
- current_id = keys[i]
|
||||
+ for current_id in keys[1:]:
|
||||
if prev_id > current_id:
|
||||
return IndexOrdering.LEXICOGRAPHIC
|
||||
prev_id = current_id
|
||||
|
||||
return IndexOrdering.INTEGER
|
||||
|
||||
- except subprocess.TimeoutExpired:
|
||||
- log.warning(" dbscan timed out for %s", index_file)
|
||||
- return IndexOrdering.UNKNOWN
|
||||
except OSError as e:
|
||||
log.warning(" Error running dbscan: %s", e)
|
||||
return IndexOrdering.UNKNOWN
|
||||
@@ -375,8 +384,7 @@ def dbtasks_index_check(inst, log, args):
|
||||
|
||||
# Track all issues found
|
||||
all_ok = True
|
||||
- mismatches = [] # (backend, index_name) tuples needing reindex
|
||||
- missing_matching_rules = [] # (backend, index_name) tuples missing integerOrderingMatch
|
||||
+ config_fixes = [] # (backend, index_name, action) tuples: action is "add_mr" or "remove_mr"
|
||||
scan_limits_to_remove = [] # (backend, index_name) tuples with nsIndexIDListScanLimit
|
||||
ancestorid_configs_to_remove = [] # backend names with ancestorid config entries
|
||||
remove_ancestorid_from_defaults = False # Flag to remove from cn=default indexes
|
||||
@@ -409,13 +417,6 @@ def dbtasks_index_check(inst, log, args):
|
||||
|
||||
if disk_ordering == IndexOrdering.UNKNOWN:
|
||||
log.info(" %s - could not determine disk ordering, skipping", index_name)
|
||||
- # For parentid, still check if matching rule is missing
|
||||
- if index_name == "parentid":
|
||||
- config_has_int_order = _has_integer_ordering_match(dse_ldif, backend, index_name)
|
||||
- if not config_has_int_order:
|
||||
- log.warning(" %s - missing integerOrderingMatch in config", index_name)
|
||||
- missing_matching_rules.append((backend, index_name))
|
||||
- all_ok = False
|
||||
continue
|
||||
|
||||
config_has_int_order = _has_integer_ordering_match(dse_ldif, backend, index_name)
|
||||
@@ -423,18 +424,15 @@ def dbtasks_index_check(inst, log, args):
|
||||
log.info(" %s - config: %s, disk: %s",
|
||||
index_name, config_desc, disk_ordering.value)
|
||||
|
||||
- # For parentid, the desired state is always integer ordering
|
||||
+ # Both orderings are valid for parentid, but config must match disk.
|
||||
if index_name == "parentid":
|
||||
- if not config_has_int_order:
|
||||
- log.warning(" %s - missing integerOrderingMatch in config", index_name)
|
||||
- if (backend, index_name) not in missing_matching_rules:
|
||||
- missing_matching_rules.append((backend, index_name))
|
||||
+ if config_has_int_order and disk_ordering == IndexOrdering.LEXICOGRAPHIC:
|
||||
+ log.warning(" %s - MISMATCH: config has integerOrderingMatch but disk is lexicographic", index_name)
|
||||
+ config_fixes.append((backend, index_name, "remove_mr"))
|
||||
all_ok = False
|
||||
-
|
||||
- if disk_ordering == IndexOrdering.LEXICOGRAPHIC:
|
||||
- log.warning(" %s - disk ordering is lexicographic, needs reindex", index_name)
|
||||
- if (backend, index_name) not in mismatches:
|
||||
- mismatches.append((backend, index_name))
|
||||
+ elif not config_has_int_order and disk_ordering == IndexOrdering.INTEGER:
|
||||
+ log.warning(" %s - MISMATCH: config is lexicographic but disk has integer ordering", index_name)
|
||||
+ config_fixes.append((backend, index_name, "add_mr"))
|
||||
all_ok = False
|
||||
|
||||
# Handle issues
|
||||
@@ -480,26 +478,27 @@ def dbtasks_index_check(inst, log, args):
|
||||
log.error(" Failed to remove ancestorid config from backend %s: %s", backend, e)
|
||||
return False
|
||||
|
||||
- # Add missing matching rules to dse.ldif
|
||||
- for backend, index_name in missing_matching_rules:
|
||||
+ # Fix config-vs-disk ordering mismatches by adjusting config to match disk
|
||||
+ for backend, index_name, action in config_fixes:
|
||||
index_dn = "cn={},cn=index,cn={},cn=ldbm database,cn=plugins,cn=config".format(
|
||||
index_name, backend
|
||||
)
|
||||
- log.info(" Adding integerOrderingMatch to %s in backend %s...", index_name, backend)
|
||||
- try:
|
||||
- dse_ldif.add(index_dn, "nsMatchingRule", "integerOrderingMatch")
|
||||
- log.info(" Updated dse.ldif with integerOrderingMatch for %s", index_name)
|
||||
- except Exception as e:
|
||||
- log.error(" Failed to update dse.ldif for %s: %s", index_name, e)
|
||||
- return False
|
||||
-
|
||||
- # Reindex indexes with disk ordering issues
|
||||
- for backend, index_name in mismatches:
|
||||
- log.info(" Reindexing %s in backend %s...", index_name, backend)
|
||||
- if not inst.db2index(bename=backend, attrs=[index_name]):
|
||||
- log.error(" Failed to reindex %s", index_name)
|
||||
- return False
|
||||
- log.info(" Reindex of %s completed successfully", index_name)
|
||||
+ if action == "add_mr":
|
||||
+ log.info(" Adding integerOrderingMatch to %s in backend %s...", index_name, backend)
|
||||
+ try:
|
||||
+ dse_ldif.add(index_dn, "nsMatchingRule", "integerOrderingMatch")
|
||||
+ log.info(" Updated dse.ldif with integerOrderingMatch for %s", index_name)
|
||||
+ except Exception as e:
|
||||
+ log.error(" Failed to update dse.ldif for %s: %s", index_name, e)
|
||||
+ return False
|
||||
+ elif action == "remove_mr":
|
||||
+ log.info(" Removing integerOrderingMatch from %s in backend %s...", index_name, backend)
|
||||
+ try:
|
||||
+ dse_ldif.delete(index_dn, "nsMatchingRule", "integerOrderingMatch")
|
||||
+ log.info(" Removed integerOrderingMatch from %s", index_name)
|
||||
+ except Exception as e:
|
||||
+ log.error(" Failed to remove integerOrderingMatch from %s: %s", index_name, e)
|
||||
+ return False
|
||||
|
||||
log.info("All issues fixed")
|
||||
return True
|
||||
@@ -563,5 +562,5 @@ def create_parser(subcommands):
|
||||
index_check_parser.add_argument('backend', nargs='?', default=None,
|
||||
help="Backend to check. If not specified, all backends are checked.")
|
||||
index_check_parser.add_argument('--fix', action='store_true', default=False,
|
||||
- help="Fix mismatches by reindexing affected indexes")
|
||||
+ help="Fix mismatches by adjusting config to match on-disk data")
|
||||
index_check_parser.set_defaults(func=dbtasks_index_check)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
202
0033-Issue-7053-Remove-memberof_del_dn_from_groups-from-M.patch
Normal file
202
0033-Issue-7053-Remove-memberof_del_dn_from_groups-from-M.patch
Normal file
@ -0,0 +1,202 @@
|
||||
From 31bef3852f7064c73f66974d7c41262d2a724eab Mon Sep 17 00:00:00 2001
|
||||
From: Alex Kulberg <vectinx@yandex.ru>
|
||||
Date: Tue, 9 Dec 2025 17:11:56 +0300
|
||||
Subject: [PATCH] Issue 7053 - Remove memberof_del_dn_from_groups from MemberOf
|
||||
plugin (#7064)
|
||||
|
||||
Bug Description:
|
||||
|
||||
The member plugin creates redundant changes to the member attribute
|
||||
in groups when deleting a user, although the referential integrity
|
||||
of the member attribute should be controlled by the Referential Integrity plugin.
|
||||
Furthermore, memberof doesn't take replication of operations into account
|
||||
and performs the change on every server instance in the topology.
|
||||
|
||||
Fix Description:
|
||||
|
||||
Remove the `memberof_del_dn_from_groups` function from the MemberOf plugin,
|
||||
completely transferring responsibility for deleting users from groups
|
||||
to the Referential Integrity plugin.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7053
|
||||
|
||||
Reviewed by: @tbordaz
|
||||
---
|
||||
.../memberof_include_scopes_test.py | 13 ++-
|
||||
ldap/servers/plugins/memberof/memberof.c | 79 -------------------
|
||||
2 files changed, 9 insertions(+), 83 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py b/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py
|
||||
index e1d3b0a96..347eb880f 100644
|
||||
--- a/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py
|
||||
@@ -13,7 +13,7 @@ import time
|
||||
from lib389.utils import ensure_str
|
||||
from lib389.topologies import topology_st as topo
|
||||
from lib389._constants import *
|
||||
-from lib389.plugins import MemberOfPlugin
|
||||
+from lib389.plugins import MemberOfPlugin, ReferentialIntegrityPlugin
|
||||
from lib389.idm.user import UserAccount, UserAccounts
|
||||
from lib389.idm.group import Group, Groups
|
||||
from lib389.idm.nscontainer import nsContainers
|
||||
@@ -77,6 +77,13 @@ def test_multiple_scopes(topo):
|
||||
|
||||
inst = topo.standalone
|
||||
|
||||
+ EXCLUDED_SUBTREE = 'cn=exclude,%s' % SUFFIX
|
||||
+ # enable Referential Integrity plugin
|
||||
+ # to correctly process the 'member' attribute
|
||||
+ refint = ReferentialIntegrityPlugin(inst)
|
||||
+ refint.add_excludescope(EXCLUDED_SUBTREE)
|
||||
+ refint.enable()
|
||||
+
|
||||
# configure plugin
|
||||
memberof = MemberOfPlugin(inst)
|
||||
memberof.enable()
|
||||
@@ -106,7 +113,6 @@ def test_multiple_scopes(topo):
|
||||
check_membership(inst, f'uid=test_m3,{SUBTREE_3}', f'cn=g3,{SUBTREE_3}', False)
|
||||
|
||||
# Set exclude scope
|
||||
- EXCLUDED_SUBTREE = 'cn=exclude,%s' % SUFFIX
|
||||
EXCLUDED_USER = f"uid=test_m1,{EXCLUDED_SUBTREE}"
|
||||
INCLUDED_USER = f"uid=test_m1,{SUBTREE_1}"
|
||||
GROUP_DN = f'cn=g1,{SUBTREE_1}'
|
||||
@@ -122,9 +128,8 @@ def test_multiple_scopes(topo):
|
||||
# Check memberOf and group are cleaned up
|
||||
check_membership(inst, EXCLUDED_USER, GROUP_DN, False)
|
||||
group = Group(topo.standalone, dn=GROUP_DN)
|
||||
- assert not group.present("member", EXCLUDED_USER)
|
||||
assert not group.present("member", INCLUDED_USER)
|
||||
-
|
||||
+ assert not group.present("member", EXCLUDED_USER)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
|
||||
index c4b5afee7..5de2e9e72 100644
|
||||
--- a/ldap/servers/plugins/memberof/memberof.c
|
||||
+++ b/ldap/servers/plugins/memberof/memberof.c
|
||||
@@ -151,7 +151,6 @@ static void memberof_set_plugin_id(void *plugin_id);
|
||||
static int memberof_compare(MemberOfConfig *config, const void *a, const void *b);
|
||||
static int memberof_qsort_compare(const void *a, const void *b);
|
||||
static void memberof_load_array(Slapi_Value **array, Slapi_Attr *attr);
|
||||
-static int memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_Entry *e, Slapi_DN *sdn);
|
||||
static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_DN *sdn, MemberOfConfig *config, char **types, plugin_search_entry_callback callback, void *callback_data, int *cached, PRBool use_grp_cache);
|
||||
static int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn, Slapi_Value *memberdn);
|
||||
static int memberof_is_grouping_attr(char *type, MemberOfConfig *config);
|
||||
@@ -540,21 +539,6 @@ deferred_modrdn_func(MemberofDeferredModrdnTask *task)
|
||||
* attributes to refer to the new name. */
|
||||
if (ret == LDAP_SUCCESS && pre_sdn && post_sdn) {
|
||||
if (!memberof_entry_in_scope(&configCopy, &post_entry_info)) {
|
||||
- /*
|
||||
- * After modrdn the group contains both the pre and post DN's as
|
||||
- * members, so we need to cleanup both in this case.
|
||||
- */
|
||||
- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, pre_e, pre_sdn))) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
|
||||
- "deferred_modrdn_func - Delete dn failed for preop entry(%s), error (%d)\n",
|
||||
- slapi_sdn_get_dn(pre_sdn), ret);
|
||||
- }
|
||||
- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, post_e, post_sdn))) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
|
||||
- "deferred_modrdn_func - Delete dn failed for postop entry(%s), error (%d)\n",
|
||||
- slapi_sdn_get_dn(post_sdn), ret);
|
||||
- }
|
||||
-
|
||||
if (ret == LDAP_SUCCESS && pre_e && configCopy.group_filter &&
|
||||
0 == slapi_filter_test_simple(pre_e, configCopy.group_filter))
|
||||
{
|
||||
@@ -638,16 +622,6 @@ deferred_del_func(MemberofDeferredDelTask *task)
|
||||
free_configCopy = PR_TRUE;
|
||||
memberof_unlock_config();
|
||||
|
||||
- /* remove this DN from the
|
||||
- * membership lists of groups
|
||||
- */
|
||||
- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, e, sdn))) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
|
||||
- "deferred_del_func - Error deleting dn (%s) from group. Error (%d)\n",
|
||||
- slapi_sdn_get_dn(sdn), ret);
|
||||
- goto bail;
|
||||
- }
|
||||
-
|
||||
/* is the entry of interest as a group? */
|
||||
if (e && configCopy.group_filter && 0 == slapi_filter_test_simple(e, configCopy.group_filter)) {
|
||||
Slapi_Attr *attr = 0;
|
||||
@@ -1456,16 +1430,6 @@ memberof_postop_del(Slapi_PBlock *pb)
|
||||
memberof_copy_config(&configCopy, memberof_get_config());
|
||||
memberof_unlock_config();
|
||||
|
||||
- /* remove this DN from the
|
||||
- * membership lists of groups
|
||||
- */
|
||||
- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, e, sdn))) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
|
||||
- "memberof_postop_del - Error deleting dn (%s) from group. Error (%d)\n",
|
||||
- slapi_sdn_get_dn(sdn), ret);
|
||||
- goto bail;
|
||||
- }
|
||||
-
|
||||
/* is the entry of interest as a group? */
|
||||
if (e && configCopy.group_filter && 0 == slapi_filter_test_simple(e, configCopy.group_filter)) {
|
||||
Slapi_Attr *attr = 0;
|
||||
@@ -1496,34 +1460,6 @@ done:
|
||||
}
|
||||
|
||||
|
||||
-/* Deletes a member dn from all groups that refer to it. */
|
||||
-static int
|
||||
-memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_Entry *e, Slapi_DN *sdn)
|
||||
-{
|
||||
- char *groupattrs[2] = {0, 0};
|
||||
- int rc = LDAP_SUCCESS;
|
||||
- int cached = 0;
|
||||
-
|
||||
- /* Loop through each grouping attribute to find groups that have
|
||||
- * dn as a member. For any matches, delete the dn value from the
|
||||
- * same grouping attribute. */
|
||||
- for (size_t i = 0; config->groupattrs && config->groupattrs[i] && rc == LDAP_SUCCESS; i++) {
|
||||
- memberof_del_dn_data data = {(char *)slapi_sdn_get_dn(sdn),
|
||||
- config->groupattrs[i], config};
|
||||
-
|
||||
- groupattrs[0] = config->groupattrs[i];
|
||||
-
|
||||
- slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM,
|
||||
- "memberof_del_dn_from_groups: Ancestors of %s attr: %s\n",
|
||||
- slapi_sdn_get_dn(sdn),
|
||||
- groupattrs[0]);
|
||||
- rc = memberof_call_foreach_dn(pb, e, sdn, config, groupattrs,
|
||||
- memberof_del_dn_type_callback, &data, &cached, PR_FALSE);
|
||||
- }
|
||||
-
|
||||
- return rc;
|
||||
-}
|
||||
-
|
||||
int
|
||||
memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data)
|
||||
{
|
||||
@@ -1904,21 +1840,6 @@ memberof_postop_modrdn(Slapi_PBlock *pb)
|
||||
* attributes to refer to the new name. */
|
||||
if (ret == LDAP_SUCCESS && pre_sdn && post_sdn) {
|
||||
if (!memberof_entry_in_scope(&configCopy, &post_entry_info)) {
|
||||
- /*
|
||||
- * After modrdn the group contains both the pre and post DN's as
|
||||
- * members, so we need to cleanup both in this case.
|
||||
- */
|
||||
- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, pre_e, pre_sdn))) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
|
||||
- "memberof_postop_modrdn - Delete dn failed for preop entry(%s), error (%d)\n",
|
||||
- slapi_sdn_get_dn(pre_sdn), ret);
|
||||
- }
|
||||
- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, post_e, post_sdn))) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
|
||||
- "memberof_postop_modrdn - Delete dn failed for postop entry(%s), error (%d)\n",
|
||||
- slapi_sdn_get_dn(post_sdn), ret);
|
||||
- }
|
||||
-
|
||||
if (ret == LDAP_SUCCESS && pre_e && configCopy.group_filter &&
|
||||
0 == slapi_filter_test_simple(pre_e, configCopy.group_filter)) {
|
||||
/* is the entry of interest as a group? */
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -47,7 +47,7 @@ ExcludeArch: i686
|
||||
Summary: 389 Directory Server (base)
|
||||
Name: 389-ds-base
|
||||
Version: 2.8.0
|
||||
Release: 3%{?dist}
|
||||
Release: 4%{?dist}
|
||||
License: GPL-3.0-or-later WITH GPL-3.0-389-ds-base-exception AND (Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT) AND (Apache-2.0 OR LGPL-2.1-or-later OR MIT) AND (Apache-2.0 OR MIT) AND (CC-BY-4.0 AND MIT) AND (MIT OR Apache-2.0) AND Unicode-3.0 AND (MIT OR CC0-1.0) AND (MIT OR Unlicense) AND 0BSD AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND ISC AND MIT AND MIT AND ISC AND MPL-2.0 AND PSF-2.0 AND Zlib
|
||||
URL: https://www.port389.org
|
||||
Conflicts: selinux-policy-base < 3.9.8
|
||||
@ -471,20 +471,34 @@ Patch: 0002-Issue-7096-During-replication-online-total-init-the-.patc
|
||||
Patch: 0003-Issue-Revise-paged-result-search-locking.patch
|
||||
Patch: 0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch
|
||||
Patch: 0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch
|
||||
Patch: 0006-Issue-7166-db_config_set-asserts-because-of-dynamic-.patch
|
||||
Patch: 0007-Issue-7224-CI-Test-Simplify-test_reserve_descriptor_.patch
|
||||
Patch: 0008-Issue-7189-DSBLE0007-generates-incorrect-remediation.patch
|
||||
Patch: 0009-Issue-7027-2nd-389-ds-base-OpenScanHub-Leaks-Detecte.patch
|
||||
Patch: 0010-Issue-7223-Revert-index-scan-limits-for-system-index.patch
|
||||
Patch: 0011-Issue-7223-Add-upgrade-function-to-remove-nsIndexIDL.patch
|
||||
Patch: 0012-Issue-7223-Detect-and-log-index-ordering-mismatch-du.patch
|
||||
Patch: 0013-Issue-7223-Add-dsctl-index-check-command-for-offline.patch
|
||||
Patch: 0014-Issue-7096-2nd-During-replication-online-total-init-.patch
|
||||
Patch: 0015-Issue-7076-6992-6784-6214-Fix-CI-test-failures-7077.patch
|
||||
Patch: 0016-Issue-7076-Fix-revert_cache-never-called-in-modrdn-7.patch
|
||||
Patch: 0017-Issue-6947-Fix-health_system_indexes_test.py.patch
|
||||
Patch: 0018-Issue-7121-2nd-LeakSanitizer-various-leaks-during-re.patch
|
||||
Patch: 0019-Issue-7150-Compressed-access-log-rotations-skipped-a.patch
|
||||
Patch: 0006-Issue-7189-DSBLE0007-generates-incorrect-remediation.patch
|
||||
Patch: 0007-Issue-7184-argparse.HelpFormatter-_format_actions_us.patch
|
||||
Patch: 0008-Issue-7027-2nd-389-ds-base-OpenScanHub-Leaks-Detecte.patch
|
||||
Patch: 0009-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch
|
||||
Patch: 0010-Issue-6542-RPM-build-errors-on-Fedora-42.patch
|
||||
Patch: 0011-Issue-6476-Fix-build-failure-with-GCC-15.patch
|
||||
Patch: 0012-Issue-7223-Revert-index-scan-limits-for-system-index.patch
|
||||
Patch: 0013-Issue-7223-Add-upgrade-function-to-remove-nsIndexIDL.patch
|
||||
Patch: 0014-Issue-7223-Add-upgrade-function-to-remove-ancestorid.patch
|
||||
Patch: 0015-Issue-7223-Detect-and-log-index-ordering-mismatch-du.patch
|
||||
Patch: 0016-Issue-7223-Add-dsctl-index-check-command-for-offline.patch
|
||||
Patch: 0017-Issue-7096-2nd-During-replication-online-total-init-.patch
|
||||
Patch: 0018-Issue-7076-6992-6784-6214-Fix-CI-test-failures-7077.patch
|
||||
Patch: 0019-Issue-7076-Fix-revert_cache-never-called-in-modrdn-7.patch
|
||||
Patch: 0020-Issue-6947-Fix-health_system_indexes_test.py.patch
|
||||
Patch: 0021-Issue-7121-2nd-LeakSanitizer-various-leaks-during-re.patch
|
||||
Patch: 0022-Issue-7150-Compressed-access-log-rotations-skipped-a.patch
|
||||
Patch: 0023-Issue-7224-CI-Test-Simplify-test_reserve_descriptor_.patch
|
||||
Patch: 0024-Issue-7231-Sync-repl-tests-fail-in-FIPS-mode-due-to-.patch
|
||||
Patch: 0025-Issue-7248-CLI-attribute-uniqueness-fix-usage-for-ex.patch
|
||||
Patch: 0026-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch
|
||||
Patch: 0027-Issue-7184-2nd-argparse.HelpFormatter-_format_action.patch
|
||||
Patch: 0028-Issue-7213-2nd-MDB_BAD_VALSIZE-error-while-handling-.patch
|
||||
Patch: 0029-Issue-7223-Use-lexicographical-order-for-ancestorid-.patch
|
||||
Patch: 0030-Issue-7066-7052-allow-password-history-to-be-set-to-.patch
|
||||
Patch: 0031-Issue-7243-UI-fix-certificate-table-and-modal.patch
|
||||
Patch: 0032-Issue-7223-Remove-integerOrderingMatch-requirement-f.patch
|
||||
Patch: 0033-Issue-7053-Remove-memberof_del_dn_from_groups-from-M.patch
|
||||
|
||||
%description
|
||||
389 Directory Server is an LDAPv3 compliant server. The base package includes
|
||||
@ -782,9 +796,6 @@ for dir in "$instbase"/slapd-* ; do
|
||||
else
|
||||
echo "instance $inst is not running" >> "$output" 2>&1 || :
|
||||
fi
|
||||
# Run index-check on all instances (running or not)
|
||||
# This fixes index ordering mismatches from older versions
|
||||
dsctl "$inst_name" index-check --fix >> "$output2" 2>&1 || :
|
||||
ninst=$((ninst + 1))
|
||||
done
|
||||
|
||||
@ -937,6 +948,15 @@ exit 0
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Fri Feb 20 2026 Viktor Ashirov <vashirov@redhat.com> - 2.8.0-4
|
||||
- Resolves: RHEL-117050 - Replication online reinitialization of a large database gets stalled. [rhel-9]
|
||||
- Resolves: RHEL-123279 - The new ipahealthcheck test ipahealthcheck.ds.backends.BackendsCheck raises CRITICAL issue [rhel-9]
|
||||
- Resolves: RHEL-140275 - ipa-healthcheck is complaining about missing or incorrectly configured system indexes. [rhel-9]
|
||||
- Resolves: RHEL-142980 - Scalability issue of replication online initialization with large database [rhel-9]
|
||||
- Resolves: RHEL-146899 - memory corruption in alias entry plugin [rhel-9]
|
||||
- Resolves: RHEL-147212 - Access logs are not getting deleted as configured. [rhel-9]
|
||||
- Resolves: RHEL-150907 - Remove memberof_del_dn_from_groups from MemberOf plugin [rhel-9]
|
||||
|
||||
* Thu Feb 12 2026 Viktor Ashirov <vashirov@redhat.com> - 2.8.0-3
|
||||
- Resolves: RHEL-117050 - Replication online reinitialization of a large database gets stalled. [rhel-9]
|
||||
- Resolves: RHEL-123244 - Attribute uniqueness is not enforced upon modrdn operation [rhel-9]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user