Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Jun 2026 20:28:36 +0000
From:      Jochen Neumeister <joneum@FreeBSD.org>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-main@FreeBSD.org
Subject:   git: d10cb9f3925e - main - net/py-lib389: Add new port
Message-ID:  <6a42d574.308d5.71e52160@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by joneum:

URL: https://cgit.FreeBSD.org/ports/commit/?id=d10cb9f3925e39cf9da8e59975fac96e1edc66c0

commit d10cb9f3925e39cf9da8e59975fac96e1edc66c0
Author:     Jochen Neumeister <joneum@FreeBSD.org>
AuthorDate: 2026-06-29 20:25:46 +0000
Commit:     Jochen Neumeister <joneum@FreeBSD.org>
CommitDate: 2026-06-29 20:27:24 +0000

    net/py-lib389: Add new port
    
    lib389 provides the Python library and command-line administration
    tools for 389 Directory Server.
    
    It includes tools for creating and managing Directory Server
    instances, configuring servers, and managing directory entries.
    
    This port is required for the development of net/freeipa-server.
    
    WWW: https://www.port389.org/
    
    Sponsored by:   Netzkommune GmbH
---
 net/Makefile                                       |   1 +
 net/py-lib389/Makefile                             |  49 ++++
 net/py-lib389/distinfo                             |   3 +
 net/py-lib389/files/patch-lib389_____init____.py   |  17 ++
 .../files/patch-lib389_instance_remove.py          |  19 ++
 net/py-lib389/files/patch-lib389_instance_setup.py |  16 ++
 net/py-lib389/files/patch-lib389_nss__ssl.py       | 273 +++++++++++++++++++++
 net/py-lib389/files/patch-pyproject.toml           |  18 ++
 net/py-lib389/pkg-descr                            |   3 +
 net/py-lib389/pkg-message                          |  26 ++
 10 files changed, 425 insertions(+)

diff --git a/net/Makefile b/net/Makefile
index 372552f8f5ee..991e3659aa6e 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -1095,6 +1095,7 @@
     SUBDIR += py-ldap3
     SUBDIR += py-ldapdomaindump
     SUBDIR += py-ldappool
+    SUBDIR += py-lib389
     SUBDIR += py-libcloud
     SUBDIR += py-libdnet
     SUBDIR += py-magic-wormhole
diff --git a/net/py-lib389/Makefile b/net/py-lib389/Makefile
new file mode 100644
index 000000000000..bbd0cc090984
--- /dev/null
+++ b/net/py-lib389/Makefile
@@ -0,0 +1,49 @@
+PORTNAME=	lib389
+DISTVERSION=	3.2.1
+CATEGORIES=	net python
+MASTER_SITES=	https://github.com/389ds/389-ds-base/releases/download/389-ds-base-${DISTVERSION}/
+PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
+DISTNAME=	389-ds-base-${DISTVERSION}
+
+MAINTAINER=	joneum@FreeBSD.org
+COMMENT=	Python library and administration tools for 389 Directory Server
+WWW=		https://www.port389.org/
+
+LICENSE=	GPLv3+
+LICENSE_FILE=	${WRKSRC}/LICENSE
+
+BUILD_DEPENDS=	${PYTHON_PKGNAMEPREFIX}argcomplete>=0:devel/py-argcomplete@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}argparse-manpage>=0:devel/py-argparse-manpage@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}cryptography>=0:security/py-cryptography@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}distro>=0:sysutils/py-distro@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}psutil>=0:sysutils/py-psutil@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}pyasn1>=0:devel/py-pyasn1@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}pyasn1-modules>=0:devel/py-pyasn1-modules@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}python-ldap>=0:net/py-python-ldap@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}wheel>=0:devel/py-wheel@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}setuptools>=0:devel/py-setuptools@${PY_FLAVOR}
+
+RUN_DEPENDS=	389-ds-base>=${DISTVERSION}:net/389-ds-base \
+		${PYTHON_PKGNAMEPREFIX}argcomplete>=0:devel/py-argcomplete@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}cryptography>=0:security/py-cryptography@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}distro>=0:sysutils/py-distro@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}psutil>=0:sysutils/py-psutil@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}pyasn1>=0:devel/py-pyasn1@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}pyasn1-modules>=0:devel/py-pyasn1-modules@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}python-ldap>=0:net/py-python-ldap@${PY_FLAVOR}
+
+USES=		python:3.12+ shebangfix tar:bzip2
+USE_PYTHON=	autoplist concurrent pep517
+
+SHEBANG_FILES=	cli/dsconf \
+		cli/dscontainer \
+		cli/dscreate \
+		cli/dsctl \
+		cli/dsidm \
+		cli/openldap_to_ds
+
+WRKSRC_SUBDIR=	src/lib389
+
+NO_ARCH=	yes
+
+.include <bsd.port.mk>
diff --git a/net/py-lib389/distinfo b/net/py-lib389/distinfo
new file mode 100644
index 000000000000..b8bec5a2634e
--- /dev/null
+++ b/net/py-lib389/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1782503513
+SHA256 (389-ds-base-3.2.1.tar.bz2) = a5b7b533484f16d5271c97b7dbde485b22fa63d2bfb4434ce9b6720849e67559
+SIZE (389-ds-base-3.2.1.tar.bz2) = 23711885
diff --git a/net/py-lib389/files/patch-lib389_____init____.py b/net/py-lib389/files/patch-lib389_____init____.py
new file mode 100644
index 000000000000..5412b1b5490d
--- /dev/null
+++ b/net/py-lib389/files/patch-lib389_____init____.py
@@ -0,0 +1,17 @@
+--- lib389/__init__.py.orig	2026-06-29 17:03:20 UTC
++++ lib389/__init__.py
+@@ -1158,6 +1158,14 @@ class DirSrv(SimpleLDAPObject, object):
+                 raise e from None
+         else:
+             self.log.debug("systemd status -> False")
++
++            # Runtime directories may be removed during a system reboot.
++            config_stat = os.stat(self.ds_paths.config_dir)
++            for path in (self.ds_paths.run_dir, self.ds_paths.lock_dir):
++                os.makedirs(path, mode=0o770, exist_ok=True)
++                os.chmod(path, 0o770)
++                os.chown(path, config_stat.st_uid, config_stat.st_gid)
++
+             # Start the process.
+             # Wait for it to terminate
+             # This means the server is probably ready to go ....
diff --git a/net/py-lib389/files/patch-lib389_instance_remove.py b/net/py-lib389/files/patch-lib389_instance_remove.py
new file mode 100644
index 000000000000..5f73eddec86a
--- /dev/null
+++ b/net/py-lib389/files/patch-lib389_instance_remove.py
@@ -0,0 +1,19 @@
+--- lib389/instance/remove.py.orig	2026-06-29 17:03:20 UTC
++++ lib389/instance/remove.py
+@@ -96,12 +96,12 @@ def remove_ds_instance(dirsrv, force=False):
+         _log.debug("Removing %s" % remove_paths[path_k])
+         shutil.rmtree(remove_paths[path_k], ignore_errors=True)
+ 
+-    # Remove parent (/var/lib/dirsrv/slapd-INST)
+-    shutil.rmtree(remove_paths['db_dir'].replace('db', ''), ignore_errors=True)
++    # Remove the parent instance data directory.
++    shutil.rmtree(os.path.dirname(remove_paths['db_dir']), ignore_errors=True)
+ 
+-    # Remove /run/slapd-isntance
++    # Remove the configured LDAPI socket.
+     try:
+-        os.remove(f'/run/slapd-{dirsrv.serverid}.socket')
++        os.remove(dirsrv.ds_paths.ldapi)
+     except OSError as e:
+         _log.debug("Failed to remove socket file: " + str(e))
+ 
diff --git a/net/py-lib389/files/patch-lib389_instance_setup.py b/net/py-lib389/files/patch-lib389_instance_setup.py
new file mode 100644
index 000000000000..9b7516a33ca0
--- /dev/null
+++ b/net/py-lib389/files/patch-lib389_instance_setup.py
@@ -0,0 +1,16 @@
+--- lib389/instance/setup.py.orig	2026-06-29 17:03:20 UTC
++++ lib389/instance/setup.py
+@@ -826,10 +826,10 @@ class SetupDs(object):
+         # which subsequently breaks containers starting as instance.start then believes
+         # it COULD check the ds status. The times we need to check for systemd are mainly
+         # in other environments that use systemd natively in their containers.
+-        container_result = 1
+-        if not self.containerised:
++        container_result = None
++        if not self.containerised and shutil.which("systemd-detect-virt"):
+             container_result = subprocess.run(["systemd-detect-virt", "-c"], stdout=subprocess.PIPE)
+-        if self.containerised or container_result.returncode == 0:
++        if self.containerised or (container_result is not None and container_result.returncode == 0):
+             # In a container, set the db_home_dir to the db path
+             self.log.debug("Container detected setting db home directory to db directory.")
+             slapd['db_home_dir'] = slapd['db_dir']
diff --git a/net/py-lib389/files/patch-lib389_nss__ssl.py b/net/py-lib389/files/patch-lib389_nss__ssl.py
new file mode 100644
index 000000000000..372fa702b51b
--- /dev/null
+++ b/net/py-lib389/files/patch-lib389_nss__ssl.py
@@ -0,0 +1,273 @@
+--- lib389/nss_ssl.py.orig	2026-06-29 18:47:35 UTC
++++ lib389/nss_ssl.py
+@@ -198,7 +198,7 @@ only.
+ 
+         # Init the db.
+         # 48886; This needs to be sql format ...
+-        cmd = ['/usr/bin/certutil', '-N', '-d', self._certdb, '-f', '%s/%s' % (self._certdb, PWD_TXT),  '-@', '%s/%s' % (self._certdb, PWD_TXT)]
++        cmd = ['certutil', '-N', '-d', self._certdb, '-f', '%s/%s' % (self._certdb, PWD_TXT),  '-@', '%s/%s' % (self._certdb, PWD_TXT)]
+         self._generate_noise('%s/noise.txt' % self._certdb)
+         self.log.debug("nss cmd: %s", format_cmd_list(cmd))
+         try:
+@@ -255,15 +255,15 @@ only.
+             return True
+ 
+         try:
+-            openssl_version = check_output(['/usr/bin/openssl', 'version']).decode('utf-8').strip()
++            openssl_version = check_output(['openssl', 'version']).decode('utf-8').strip()
+         except subprocess.CalledProcessError as e:
+             raise ValueError(e.output.decode('utf-8').rstrip())
+         rehash_available = DSVersion(openssl_version.split(' ')[1]) >= DSVersion('1.1.0')
+ 
+         if rehash_available:
+-            cmd = ['/usr/bin/openssl', 'rehash', certdir]
++            cmd = ['openssl', 'rehash', certdir]
+         else:
+-            cmd = ['/usr/bin/c_rehash', certdir]
++            cmd = ['c_rehash', certdir]
+         self.log.debug("nss cmd: %s", format_cmd_list(cmd))
+         try:
+             res = run(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+@@ -285,7 +285,7 @@ only.
+         self._generate_noise('%s/noise.txt' % self._certdb)
+         # Now run the command. Can we do this with NSS native?
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-S',
+             '-n',
+             CA_NAME,
+@@ -315,7 +315,7 @@ only.
+         # Now extract the CAcert to a well know place.
+         # This allows us to point the cacert dir here and it "just works"
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-L',
+             '-n',
+             CA_NAME,
+@@ -339,7 +339,7 @@ only.
+         """
+ 
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-L',
+             '-n',
+             CA_NAME,
+@@ -371,7 +371,7 @@ only.
+ 
+         # Generate a CSR for a new CA cert
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-R',
+             '-s',
+             ISSUER,
+@@ -396,7 +396,7 @@ only.
+ 
+         # Sign the CSR with our old CA
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-C',
+             '-d',
+             self._certdb,
+@@ -423,7 +423,7 @@ only.
+ 
+         # Import the new CA to our DB instead of the old CA
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-A',
+             '-n', CA_NAME,
+             '-t', "CT,,",
+@@ -442,7 +442,7 @@ only.
+ 
+     def _rsa_cert_list(self):
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-L',
+             '-d',
+             self._certdb,
+@@ -475,7 +475,7 @@ only.
+ 
+     def _openssl_get_csr_subject(self, csr_dir, csr_name):
+         cmd = [
+-            '/usr/bin/openssl',
++            'openssl',
+             'req',
+             '-subject',
+             '-noout',
+@@ -498,7 +498,7 @@ only.
+ 
+     def _openssl_get_csr_sub_alt_names(self, csr_dir, csr_name):
+         cmd = [
+-            '/usr/bin/openssl',
++            'openssl',
+             'req',
+             '-noout',
+             '-text',
+@@ -529,7 +529,7 @@ only.
+         if name and csr_dir:
+             if os.path.exists(csr_dir + "/" + name + ".csr"):
+                 cmd = [
+-                    "/usr/bin/sed",
++                    "sed",
+                     "-n",
+                     '/BEGIN NEW/,/END NEW/p',
+                     csr_dir + "/" + name + ".csr"
+@@ -547,7 +547,7 @@ only.
+         csr_dir = self.dirsrv.get_cert_dir()
+         # Search for .csr file extensions in instance config dir
+         cmd = [
+-            '/usr/bin/find',
++            'find',
+             csr_dir,
+             '-type',
+             'f',
+@@ -571,7 +571,7 @@ only.
+             csr = []
+             # Get last modified time stamp
+             cmd = [
+-                '/usr/bin/date',
++                'date',
+                 '-r',
+                 '%s/%s'% (csr_dir, csr_file),
+                 '+%Y-%m-%d %H:%M:%S',
+@@ -596,7 +596,7 @@ only.
+     def _rsa_cert_key_exists(self, cert_tuple):
+         name = cert_tuple[0]
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-K',
+             '-d',
+             self._certdb,
+@@ -688,7 +688,7 @@ only.
+         # Create noise.
+         self._generate_noise('%s/noise.txt' % self._certdb)
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-S',
+             '-n',
+             name,
+@@ -741,7 +741,7 @@ only.
+         self._generate_noise('%s/noise.txt' % self._certdb)
+ 
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-R',
+             # We want a dual purposes client and server cert
+             '--keyUsage',
+@@ -781,7 +781,7 @@ only.
+         ca_path = '%s/ca.crt' % self._certdb
+ 
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-C',
+             '-d',
+             self._certdb,
+@@ -819,7 +819,7 @@ only.
+             shutil.copyfile(ca, '%s/ca.crt' % self._certdb)
+             self.openssl_rehash(self._certdb)
+             cmd = [
+-                '/usr/bin/certutil',
++                'certutil',
+                 '-A',
+                 '-n', CA_NAME,
+                 '-t', "CT,,",
+@@ -840,7 +840,7 @@ only.
+                 raise ValueError("The certificate file ({}) does not exist".format(crt))
+             self._assert_not_chain(crt)
+             cmd = [
+-                '/usr/bin/certutil',
++                'certutil',
+                 '-A',
+                 '-n', name,
+                 '-t', ",,",
+@@ -856,7 +856,7 @@ only.
+             except subprocess.CalledProcessError as e:
+                 raise ValueError(e.output.decode('utf-8').rstrip())
+             cmd = [
+-                '/usr/bin/certutil',
++                'certutil',
+                 '-V',
+                 '-d', self._certdb,
+                 '-n', name,
+@@ -881,7 +881,7 @@ only.
+         # Wait a second to avoid an NSS bug with serial ids based on time.
+         time.sleep(1)
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-S',
+             '-n',
+             '%s%s' % (USER_PREFIX, name),
+@@ -992,7 +992,7 @@ only.
+     def list_keys(self, orphan=None):
+         key_list = []
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-K',
+             '-d',
+             self._certdb,
+@@ -1019,7 +1019,7 @@ only.
+ 
+     def del_key(self, keyid):
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-F',
+             '-d',
+             self._certdb,
+@@ -1040,7 +1040,7 @@ only.
+         """Delete this certificate
+         """
+         cmd = [
+-                '/usr/bin/certutil',
++                'certutil',
+                 '-D',
+                 '-d', self._certdb,
+                 '-n', nickname,
+@@ -1072,7 +1072,7 @@ only.
+ 
+         # Modify certificate flags
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-M',
+             '-d', self._certdb,
+             '-n', nickname,
+@@ -1088,7 +1088,7 @@ only.
+ 
+     def display_cert_details(self, nickname):
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-d', self._certdb,
+             '-n', nickname,
+             '-L',
+@@ -1274,7 +1274,7 @@ only.
+         trust_flags = "CT,," if ca else ",,"
+ 
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-A',
+             '-d', self._certdb,
+             '-n', nickname,
+@@ -1511,7 +1511,7 @@ only.
+         :raise ValueError: error
+         """
+         cmd = [
+-            '/usr/bin/certutil',
++            'certutil',
+             '-L',
+             '-d', self._certdb,
+             '-n', nickname,
diff --git a/net/py-lib389/files/patch-pyproject.toml b/net/py-lib389/files/patch-pyproject.toml
new file mode 100644
index 000000000000..dd9d9915828f
--- /dev/null
+++ b/net/py-lib389/files/patch-pyproject.toml
@@ -0,0 +1,18 @@
+--- pyproject.toml.orig	2026-06-29 14:08:52 UTC
++++ pyproject.toml
+@@ -58,7 +58,6 @@ build_py       = "build_hooks.build_py"
+ 
+ [tool.setuptools.cmdclass]
+ build_py       = "build_hooks.build_py"
+-install        = "build_hooks.install"
+ build_manpages = "build_hooks.build_manpages"
+ 
+ [tool.build_manpages]
+@@ -89,6 +88,7 @@ include = ["lib389", "lib389.*"]
+ 
+ [tool.setuptools.packages.find]
+ include = ["lib389", "lib389.*"]
++exclude = ["lib389.tests", "lib389.tests.*"]
+ 
+ [dependency-groups]
+ test = ["pytest"]
diff --git a/net/py-lib389/pkg-descr b/net/py-lib389/pkg-descr
new file mode 100644
index 000000000000..cde021b1d915
--- /dev/null
+++ b/net/py-lib389/pkg-descr
@@ -0,0 +1,3 @@
+lib389 is the Python administration library for 389 Directory Server. It
+provides APIs and command-line tools for creating, configuring, managing,
+and inspecting directory server instances.
diff --git a/net/py-lib389/pkg-message b/net/py-lib389/pkg-message
new file mode 100644
index 000000000000..ababe76c5d27
--- /dev/null
+++ b/net/py-lib389/pkg-message
@@ -0,0 +1,26 @@
+[
+{ type: install
+  message: <<EOM
+The lib389 command-line tools can be used to create and manage
+389 Directory Server instances.
+
+Create an instance interactively:
+
+  dscreate interactive
+
+Create an instance from an INF file:
+
+  dscreate from-file /path/to/instance.inf
+
+Manage an existing instance:
+
+  dsctl <instance> status
+  dsctl <instance> start
+  dsctl <instance> stop
+  dsctl <instance> remove --do-it
+
+Use dsconf to manage the server configuration and dsidm to manage
+directory entries.
+EOM
+}
+]


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a42d574.308d5.71e52160>