You are not logged in.
Hello,
I have created packages for my personal use for maybe two years now but never submitted them to the AUR. Now I would like to submit two of them (not yet submitted). I've got permission from the developer of Psono to add his software to the AUR under the condition that it needs to include a disclaimer that the package is not officially supported and the developer is not responsible for any issues with it. I've read the Arch Linux package guidelines cover to cover and also made both packages REUSE compliant. Both PKGBUILD files are almost identical (apart from the software edition) so i will show only one here. The PKGBUILD downloads a docker image from docker hub and extracts the needed files from it for use. The docker fetch function was downloaded from GitHub. This is mentioned and linked in a commented out line in the PKGBUILD. I do have a few questions regarding the Python environment it uses at the bottom of the post.
Contents of PKGBUILD:
# Maintainer: 7thCore <redacted-for-now>
# Disclaimer: This AUR package is maintained by the community and is not
# officially supported by the software developers or the package maintainer.
# Use this package at your own risk. The developers of the original software
# and the package maintainer are not responsible for any issues, bugs, or
# damages resulting from its use. For installation or usage questions, please
# do not contact the original developers. Instead, seek assistance from the
# package maintainer, the Arch Linux community or relevant forums.
pkgname=psono-ee-combo
pkgver=1.0
pkgrel=1
pkgdesc='Enterprise Edition of the open source and self hosted password manager. Includes the server, file server, web client and web admin portal.'
arch=('x86_64' 'aarch64')
url='https://psono.com'
license=('Apache-2.0')
depends=('bash'
'coreutils'
'gcc'
'git'
'glibc'
'haveged'
'libb2'
'libffi'
'libldap'
'libpqxx'
'libsasl'
'libyaml'
'nginx'
'openssl'
'postgresql'
'python>=3.14'
'python<3.15'
'util-linux')
optdepends=('logrotate: rotates system logs automatically'
'fail2ban: bans IPs after too many failed authentication attempts')
makedepends=('curl'
'gzip'
'jq'
'patchelf'
'sed'
'tar')
provides=('psono-server'
'psono-fileserver'
'psono-web-client'
'psono-admin-client')
conflicts=('psono-server'
'psono-fileserver'
'psono-web-client'
'psono-admin-client')
backup=('etc/fail2ban/filter.d/psono-ee.conf'
'etc/fail2ban/jail.d/psono-ee.local'
'etc/logrotate.d/psono'
'etc/nginx/sites-available/psono-ee-combo.conf'
'usr/share/webapps/psono-webclient/config.json'
'usr/share/webapps/psono-webclient/portal/config.json'
'var/lib/psono/.psono_fileserver/settings.yaml'
'var/lib/psono/.psono_server/settings.yaml')
options=('!strip' '!debug')
install='psono-script.install'
source=('conf_psono.logrotate'
'conf_psono-fail2ban-filter.conf'
'conf_psono-fail2ban-jail.local'
'conf_psono-fileserver-settings.yaml'
'conf_psono-nginx.conf'
'conf_psono-server-settings.yaml'
'pacman_05-psono-ee-pre.hook'
'pacman_99-psono-ee-post.hook'
'psono-ee-server-requirements.patch'
'psono-script.install'
'psono-ee-combo.sysusers'
'script_psono-ee-pacman-hooks.sh'
'systemd_psono-fileserver-cleanup.service'
'systemd_psono-fileserver-cleanup.timer'
'systemd_psono-fileserver-ping.service'
'systemd_psono-fileserver-ping.timer'
'systemd_psono-fileserver.service'
'systemd_psono-server-ee-cleartoken.service'
'systemd_psono-server-ee-cleartoken.timer'
'systemd_psono-server-ee.service')
sha256sums=('bd391b1824d182c3d5813ca71535d5e47c2404883f1bc58f76b677fde3d6e70f'
'66ac600efad0aa1af7ddfeca5452f369ac3fe8f0e8c9ad90ae1bf73be18460bc'
'5d422995f77d17c65d7827e0af27afb0ba6500e91e17f66fcb758aa322d8108c'
'7d658724229b49a4e69e45e0a57b536a42ec02ad1c3343539b21f8fa505c1002'
'2f815769b7dd5c672b491138e59e1709ea30676d66c7562ad54c7c2ce14dc55c'
'6316939b8c5a36b1b3c379a50d5a86a2d4c153a4e38ec7b2b2e18da7ad7db34d'
'b3cdc9d315b628f0970459a4af08bbe4b5c08e1b8a0dff8da7f5a0c6875c76f9'
'd9f9810503879afd9774e399d1efe6d1f3dfe3aaa017f0ce16010ff8549a858d'
'4a171e8c0ee529bad90ad37e6633f8dc7cfe40e02fb4cf24f6e95f8084b4584a'
'f11ad9dd5312625014e321e33af697523d9af1a9c2d0a9ed1584ea24e80ec69b'
'd09f410988034a25b9607316f4f5d6f69b27dbe4d70e7c74ae7cabd43f276f8f'
'42bc0970dc2b9918191893d08b32cb94d643e5bbb6c791f4a0d0ad7d70c8a153'
'af7985b5a1ebf8664888959f8dd9f4d24ada00702548e4e07253eacddacc8403'
'ac7d656c02632ca81fb3683a65764b076e25a5ae39bdd2a4ef9d5827b984e1fe'
'4009d186b42e1c79bebf340899a649a15f2019945dca1d81bcd8ec9455852e97'
'e013719b0a8fd62e4c1d0fc3e83fc1903fc7189205bb58899b7e5fd4a7ae6b26'
'36f51e9ae755436353caebf80bda3293122729a26a3cc75ff6b652a2460c9977'
'108d1cf9373cc5ebb98373b3469a64a24e6fd4bfc973e0056d2101b6c77de442'
'ebc9d9ad66ff7cfdbf4698b2ce24392b1a52ff6a0294f72288e14be1ede6219b'
'7f8252a5fc9967e5f373688039fa2136ab914ed94d2e8d514eadc817a5b708ff')
pkgver() {
# The version number is combined by the developer on docker. First numbers are the server version,
# second are the client portal version and third are the admin portal version. To keep up with this
# version form, add the file server version to the version number.
PSONO_EE_COMBO_VERSION=$(curl -s "https://hub.docker.com/v2/repositories/psono/psono-combo-enterprise/tags?page_size=1" | jq -r '.results[0].name' | sed 's/-/_/g')
PSONO_FILESERVER_VERSION=$(curl -s "https://hub.docker.com/v2/repositories/psono/psono-fileserver/tags?page_size=1" | jq -r '.results[0].name')
printf "$PSONO_EE_COMBO_VERSION"_"$PSONO_FILESERVER_VERSION"
}
prepare() {
# Docker fetch function modified from https://github.com/jjlin/docker-image-extract
docker_fetch() {
PLATFORM="$2"
OUT_DIR="${srcdir}/psono-src-docker"
image_spec="$1"
image="${image_spec%%:*}"
if [ "${image#*/}" = "${image}" ]; then
image="library/${image}"
fi
ref="${image_spec#*:}"
# Split platform (OS/arch/variant) into separate variables.
IFS=/ read -r OS ARCH VARIANT <<< "${PLATFORM}"
fetch() {
if [ $# -eq 2 ]; then
set -- -H "$2" "$1"
elif [ $# -eq 3 ]; then
set -- -H "$2" -H "$3" "$1"
fi
curl -sSL "$@"
}
manifest_list_url="https://hub.docker.com/v2/repositories/${image}/tags/${ref}"
if [ -z "${ref##sha256:*}" ]; then
digest="${ref}"
else
echo "Getting multi-arch manifest list..."
digest=$(fetch "${manifest_list_url}" | jq -r '.images[] | select(.architecture == "'"${ARCH}"'" and .os == "'"${OS}"'" and (.variant == "'"${VARIANT}"'" or (.variant | not))) | .digest' | head -n 1)
if [ -n "${digest}" ]; then
echo "Platform ${PLATFORM} resolved to '${digest}'..."
else
echo "No image digest found. Verify that the image, ref, and platform are valid."
exit 1
fi
fi
api_token_url="https://auth.docker.io/token?service=registry.docker.io&scope=repository:$image:pull"
manifest_url="https://registry-1.docker.io/v2/${image}/manifests/${digest}"
blobs_base_url="https://registry-1.docker.io/v2/${image}/blobs"
echo "Getting API token..."
token=$(fetch "${api_token_url}" | jq -r '.token')
auth_header="Authorization: Bearer $token"
docker_manifest_v2="application/vnd.docker.distribution.manifest.v2+json"
oci_manifest_v1="application/vnd.oci.image.manifest.v1+json"
accept_header="Accept: ${docker_manifest_v2},${oci_manifest_v1}"
echo "Getting image manifest for $image:$ref..."
layers=$(fetch "${manifest_url}" "${auth_header}" "${accept_header}" | jq -r '.layers[].digest')
if [ -z "${layers}" ]; then
echo "No layers returned. Verify that the image and ref are valid."
exit 1
fi
for layer in $layers; do
hash="${layer#sha256:}"
echo "Fetching and extracting layer ${hash}..."
fetch "${blobs_base_url}/${layer}" "${auth_header}" | gzip -d | tar -C "${OUT_DIR}" -xf -
OLD_IFS="${IFS}"
find "${OUT_DIR}" -name '.wh.*' | while IFS= read -r f; do
dir="${f%/*}"
wh_file="${f##*/}"
file="${wh_file#.wh.}"
rm -rf "${dir}/${wh_file}" "${dir}/${file}"
done
IFS="${OLD_IFS}"
done
echo "Image contents extracted into ${OUT_DIR}."
}
printf "\e[1;31mDisclaimer: This AUR package is maintained by the community and is not\e[0m\n"
printf "\e[1;31mofficially supported by the software developers or the package maintainer.\e[0m\n"
printf "\e[1;31mUse this package at your own risk. The developers of the original software\e[0m\n"
printf "\e[1;31mand the package maintainer are not responsible for any issues, bugs, or\e[0m\n"
printf "\e[1;31mdamages resulting from its use. For installation or usage questions, please\e[0m\n"
printf "\e[1;31mdo not contact the original developers. Instead, seek assistance from the\e[0m\n"
printf "\e[1;31mpackage maintainer, the Arch Linux community or relevant forums.\e[0m\n"
if [ "$(uname -m)" = "x86_64" ]; then
PLATFORM_DEFAULT="linux/amd64"
elif [ "$(uname -m)" = "aarch64" ]; then
PLATFORM_DEFAULT="linux/arm64"
fi
[ -d "${srcdir}/psono-ee-src" ] && rm -rf "${srcdir}/psono-ee-src"
[ -d "${srcdir}/psono-fs-src" ] && rm -rf "${srcdir}/psono-fs-src"
[ -d "${srcdir}/psono-web" ] && rm -rf "${srcdir}/psono-web"
[ -d "${srcdir}/psono-web-admin" ] && rm -rf "${srcdir}/psono-web-admin"
[ -d "${srcdir}/psono-src-docker" ] && rm -rf "${srcdir}/psono-src-docker"
[ -d "${srcdir}/python_env" ] && rm -rf "${srcdir}/python_env"
mkdir -p "${srcdir}/psono-ee-src"
mkdir -p "${srcdir}/psono-fs-src"
mkdir -p "${srcdir}/psono-web"
mkdir -p "${srcdir}/psono-web-admin"
mkdir -p "${srcdir}/psono-src-docker"
mkdir -p "${srcdir}/python_env"
printf "\e[32mFetching Psono Server Enterprise Edition Docker image\e[0m\n"
docker_fetch psono/psono-combo-enterprise:latest "$PLATFORM_DEFAULT"
printf "\e[32mExtracting Psono Server Enterprise Edition from Docker image\e[0m\n"
cp -rf ${srcdir}/psono-src-docker ${srcdir}/test-srv
mv ${srcdir}/psono-src-docker/root/psono/* ${srcdir}/psono-ee-src/
mv ${srcdir}/psono-src-docker/root/requirements.txt ${srcdir}/psono-ee-src/
mv ${srcdir}/psono-src-docker/root/requirements-amd64.txt ${srcdir}/psono-ee-src/
mv ${srcdir}/psono-src-docker/root/.pip/pip.conf ${srcdir}/conf_psono-python-pip.conf
printf "\e[32mExtracting Psono Admin Portal from Docker image\e[0m\n"
mv ${srcdir}/psono-src-docker/usr/share/nginx/html/portal/* "${srcdir}/psono-web-admin/"
printf "\e[32mExtracting Psono Web Portal from Docker image\e[0m\n"
mv ${srcdir}/psono-src-docker/usr/share/nginx/html/* "${srcdir}/psono-web/"
printf "\e[32mRemoving unused files of Psono Server Enterprise Edition Docker image\e[0m\n"
rm -rf ${srcdir}/psono-src-docker/*
printf "\e[32mFetching Psono File Server Docker image\e[0m\n"
docker_fetch psono/psono-fileserver:latest "$PLATFORM_DEFAULT"
printf "\e[32mExtracting Psono File Server from Docker image\e[0m\n"
cp -rf ${srcdir}/psono-src-docker ${srcdir}/test-fsrv
mv ${srcdir}/psono-src-docker/root/psono/* ${srcdir}/psono-fs-src/
mv ${srcdir}/psono-src-docker/root/requirements.txt ${srcdir}/psono-fs-src/
printf "\e[32mRemoving unused files of Psono File Server Docker image\e[0m\n"
rm -rf ${srcdir}/psono-src-docker/*
printf "\e[32mPatching Psono Server Enterprise Edition requirements.txt\e[0m\n"
cd "${srcdir}/psono-ee-src" || exit 1
patch -Np1 -i "${srcdir}/psono-ee-server-requirements.patch"
# Find the latest pyarmor_runtime.so folder, cd to it and patch pyarmor_runtime.so
printf "\e[32mPatching pyarmor_runtime.so ELF by replacing libc.so with libc.so.6 to avoid 'invalid ELF header' errors\e[0m\n"
cd "${srcdir}/psono-ee-src" || exit 1
PYARMOR_RUNTIME_DIR=$(ls -d pyarmor_runtime_* | sort -V | tail -n 1)
if [[ -d "$PYARMOR_RUNTIME_DIR" ]]; then
cd "$PYARMOR_RUNTIME_DIR" || exit 1
patchelf --replace-needed libc.so libc.so.6 pyarmor_runtime.so
fi
}
build() {
printf "\e[32mPreparing Psono Server Enterprise Edition python virtual environment\e[0m\n"
/usr/bin/python3.14 -m venv ${srcdir}/python_env/psono-server-ee-3.14
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-server-ee-3.14/bin/python3.14 -m pip install --upgrade pip
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-server-ee-3.14/bin/pip3.14 install -r ${srcdir}/psono-ee-src/requirements.txt
if [ "$(uname -m)" = "x86_64" ]; then
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-server-ee-3.14/bin/pip3.14 install -r ${srcdir}/psono-ee-src/requirements-amd64.txt
fi
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-server-ee-3.14/bin/pip3.14 install gunicorn
printf "\e[32mChanging paths of python virtual environment files\e[0m\n"
find ${srcdir}/python_env/psono-server-ee-3.14 -type f ! -type l -exec sed -i "s|${srcdir}/python_env/psono-server-ee-3.14|/var/lib/psono/.python_env/psono-server-ee-3.14|g" {} +
printf "\e[32mDeleting python virtual environment cache files\e[0m\n"
find ${srcdir}/python_env/psono-server-ee-3.14/lib/python3.14/site-packages -type f -name "*.pyc" -delete -o -type d -name "__pycache__" -exec rm -rf {} +
printf "\e[32mPreparing Psono File Server python virtual environment\e[0m\n"
/usr/bin/python3.14 -m venv ${srcdir}/python_env/psono-fileserver-3.14
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-fileserver-3.14/bin/python3.14 -m pip install --upgrade pip
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-fileserver-3.14/bin/pip3.14 install -r ${srcdir}/psono-fs-src/requirements.txt
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-fileserver-3.14/bin/pip3.14 install gunicorn
printf "\e[32mChanging paths of python virtual environment files\e[0m\n"
find ${srcdir}/python_env/psono-fileserver-3.14 -type f ! -type l -exec sed -i "s|${srcdir}/python_env/psono-fileserver-3.14|/var/lib/psono/.python_env/psono-fileserver-3.14|g" {} +
printf "\e[32mDeleting python virtual environment cache files\e[0m\n"
find ${srcdir}/python_env/psono-fileserver-3.14/lib/python3.14/site-packages -type f -name "*.pyc" -delete -o -type d -name "__pycache__" -exec rm -rf {} +
}
package() {
# Fail2ban
install -dm755 "${pkgdir}/etc/fail2ban/jail.d"
install -dm755 "${pkgdir}/etc/fail2ban/filter.d"
install -Dm644 "${srcdir}/conf_psono-fail2ban-filter.conf" "${pkgdir}/etc/fail2ban/filter.d/psono-ee.conf"
install -Dm644 "${srcdir}/conf_psono-fail2ban-jail.local" "${pkgdir}/etc/fail2ban/jail.d/psono-ee.local"
# Logrotate
install -dm755 "${pkgdir}/etc/logrotate.d"
install -Dm644 "${srcdir}/conf_psono.logrotate" "${pkgdir}/etc/logrotate.d/psono"
# Nginx
install -dm755 "${pkgdir}/etc/nginx/sites-available"
install -dm755 "${pkgdir}/etc/nginx/sites-enabled"
install -Dm644 "${srcdir}/conf_psono-nginx.conf" "${pkgdir}/etc/nginx/sites-available/psono-ee-combo.conf"
# Pacman
install -Dm644 "${srcdir}/pacman_05-psono-ee-pre.hook" "${pkgdir}/usr/share/libalpm/hooks/05-psono-ee-pre.hook"
install -Dm644 "${srcdir}/pacman_99-psono-ee-post.hook" "${pkgdir}/usr/share/libalpm/hooks/99-psono-ee-post.hook"
install -Dm755 "${srcdir}/script_psono-ee-pacman-hooks.sh" "${pkgdir}/usr/share/libalpm/scripts/psono-ee-pacman-hooks.sh"
# Psono
install -dm755 "${pkgdir}/var/lib/psono/psono-fileserver"
install -dm755 "${pkgdir}/var/lib/psono/psono-server-ee"
install -dm755 "${pkgdir}/var/lib/psono/psono-shard"
install -dm755 "${pkgdir}/var/lib/psono/.pip"
install -dm755 "${pkgdir}/var/lib/psono/.psono_fileserver"
install -dm755 "${pkgdir}/var/lib/psono/.psono_server"
install -dm755 "${pkgdir}/var/log/psono"
install -dm755 "${pkgdir}/usr/share/webapps/psono-webclient/portal"
install -Dm644 "${srcdir}/conf_psono-fileserver-settings.yaml" "${pkgdir}/var/lib/psono/.psono_fileserver/settings.yaml"
install -Dm644 "${srcdir}/conf_psono-python-pip.conf" "${pkgdir}/var/lib/psono/.pip/pip.conf"
install -Dm644 "${srcdir}/conf_psono-server-settings.yaml" "${pkgdir}/var/lib/psono/.psono_server/settings.yaml"
install -Dm644 "${srcdir}/psono-ee-combo.sysusers" "${pkgdir}/usr/lib/sysusers.d/psono.conf"
install -Dm644 "${srcdir}/systemd_psono-fileserver-cleanup.service" "${pkgdir}/usr/lib/systemd/system/psono-fileserver-cleanup.service"
install -Dm644 "${srcdir}/systemd_psono-fileserver-cleanup.timer" "${pkgdir}/usr/lib/systemd/system/psono-fileserver-cleanup.timer"
install -Dm644 "${srcdir}/systemd_psono-fileserver-ping.service" "${pkgdir}/usr/lib/systemd/system/psono-fileserver-ping.service"
install -Dm644 "${srcdir}/systemd_psono-fileserver-ping.timer" "${pkgdir}/usr/lib/systemd/system/psono-fileserver-ping.timer"
install -Dm644 "${srcdir}/systemd_psono-fileserver.service" "${pkgdir}/usr/lib/systemd/system/psono-fileserver.service"
install -Dm644 "${srcdir}/systemd_psono-server-ee-cleartoken.service" "${pkgdir}/usr/lib/systemd/system/psono-server-ee-cleartoken.service"
install -Dm644 "${srcdir}/systemd_psono-server-ee-cleartoken.timer" "${pkgdir}/usr/lib/systemd/system/psono-server-ee-cleartoken.timer"
install -Dm644 "${srcdir}/systemd_psono-server-ee.service" "${pkgdir}/usr/lib/systemd/system/psono-server-ee.service"
cp -dr --no-preserve=ownership "${srcdir}/psono-ee-src"/* "${pkgdir}/var/lib/psono/psono-server-ee/"
cp -dr --no-preserve=ownership "${srcdir}/psono-fs-src"/* "${pkgdir}/var/lib/psono/psono-fileserver/"
cp -dr --no-preserve=ownership "${srcdir}/psono-web"/* "${pkgdir}/usr/share/webapps/psono-webclient/"
cp -dr --no-preserve=ownership "${srcdir}/psono-web-admin"/* "${pkgdir}/usr/share/webapps/psono-webclient/portal/"
cp -dr --no-preserve=ownership "${srcdir}/python_env" "${pkgdir}/var/lib/psono/.python_env"
}Source files (I added prefixes for easy managment):
LICENSES
LICENSE
PKGBUILD
README.md
REUSE.toml
conf_psono-fail2ban-filter.conf
conf_psono-fail2ban-jail.local
conf_psono-fileserver-settings.yaml
conf_psono-nginx.conf
conf_psono-server-settings.yaml
conf_psono.logrotate
pacman_05-psono-ee-pre.hook
pacman_99-psono-ee-post.hook
psono-ee-server-requirements.patch
psono-script.install
script_psono-ee-pacman-hooks.sh
systemd_psono-fileserver-cleanup.service
systemd_psono-fileserver-cleanup.timer
systemd_psono-fileserver-ping.service
systemd_psono-fileserver-ping.timer
systemd_psono-fileserver.service
systemd_psono-server-ee-cleartoken.service
systemd_psono-server-ee-cleartoken.timer
systemd_psono-server-ee.serviceREUSE.toml:
version = 1
[[annotations]]
path = [
"PKGBUILD",
"README.md",
"keys/**",
".SRCINFO",
".gitignore",
".nvchecker.toml",
"*.install",
"*.sysusers",
"*sysusers.conf",
"*.tmpfiles",
"*tmpfiles.conf",
"*.logrotate",
"*.pam",
"*.service",
"*.socket",
"*.timer",
"*.desktop",
"*.hook",
"conf_psono-fail2ban-filter.conf",
"conf_psono-fail2ban-jail.local",
"conf_psono-nginx.conf",
"psono-ee-server-requirements.patch",
"script_psono-ee-pacman-hooks.sh",
]
SPDX-FileCopyrightText = "Arch Linux contributors"
SPDX-License-Identifier = "0BSD"
[[annotations]]
path = [
"conf_psono-fileserver-settings.yaml",
"conf_psono-server-settings.yaml",
]
SPDX-FileCopyrightText = "psono-ee-combo contributors"
SPDX-License-Identifier = "Apache-2.0"psono-script.install
pre_install() {
echo "-----------------------------------------------------------------------------"
echo " Psono Enterprise Edition: DISCLAIMER"
echo "-----------------------------------------------------------------------------'"
echo " This AUR package is maintained by the community and is not"
echo " officially supported by the software developers or the package maintainer."
echo " Use this package at your own risk. The developers of the original software"
echo " and the package maintainer are not responsible for any issues, bugs, or"
echo " damages resulting from its use. For installation or usage questions, please"
echo " do not contact the original developers. Instead, seek assistance from the"
echo " package maintainer, the Arch Linux community or relevant forums."
echo "-----------------------------------------------------------------------------"
}
post_install() {
echo "Psono Enterprise Edition: CAUTION"
echo "Don't forget to setup your Psono configuration and execute the following command to complete the Psono installation before starting the services:"
echo "'runuser -l psono -s /bin/bash -c \"/var/lib/psono/.python_env/psono-server-ee-3.14/bin/python3.14 /var/lib/psono/psono-server-ee/psono/manage.py migrate\"'"
}
pre_upgrade() {
echo "-----------------------------------------------------------------------------"
echo " Psono Enterprise Edition: DISCLAIMER"
echo "-----------------------------------------------------------------------------'"
echo " This AUR package is maintained by the community and is not"
echo " officially supported by the software developers or the package maintainer."
echo " Use this package at your own risk. The developers of the original software"
echo " and the package maintainer are not responsible for any issues, bugs, or"
echo " damages resulting from its use. For installation or usage questions, please"
echo " do not contact the original developers. Instead, seek assistance from the"
echo " package maintainer, the Arch Linux community or relevant forums."
echo "-----------------------------------------------------------------------------"
}
post_upgrade() {
echo "Psono Enterprise Edition: CAUTION"
echo "A pacman hook should migrate the new update but if for whatever reason it failed, use this command to migrate it manually before starting the services:"
echo "'runuser -l psono -s /bin/bash -c \"/var/lib/psono/.python_env/psono-server-ee-3.14/bin/python3.14 /var/lib/psono/psono-server-ee/psono/manage.py migrate\"'"
}
pre_remove() {
echo "Psono Enterprise Edition: CAUTION"
echo "Some files may be left over from the installation at /var/lib/psono such as configuration files, fileserver shards and the psono user account."
echo "Remember to backup these files before deleting the user account and it's contents at /var/lib/psono if you intend to use this configuration"
echo "with your database again. Configuration files have secrets designated to access the database and encrypted shard files. Without those secrets"
echo "you will not be able to access the databse and the encrypted files again. YOU HAVE BEEN WARNED."
}
post_remove() {
rm -rf /usr/share/webapps/psono-webclient
}script_psono-ee-pacman-hooks.sh
#!/bin/sh
#Stop all psono services
psono_stop() {
/usr/bin/systemctl stop psono-server-ee.service psono-server-ee-cleartoken.timer psono-fileserver.service psono-fileserver-cleanup.timer psono-fileserver-ping.timer
}
#Execute migration and start psono services
psono_migrate_start() {
cd "/var/lib/psono/psono-server-ee" || exit
sudo -u psono /var/lib/psono/.python_env/psono-server-ee-3.14/bin/python3.14 /var/lib/psono/psono-server-ee/manage.py migrate
# The hook runs after 30-systemd-daemon-reload.hook so another systemctl daemon-reload is not necessary.
/usr/bin/systemctl start psono-server-ee.service psono-server-ee-cleartoken.timer psono-fileserver.service psono-fileserver-cleanup.timer psono-fileserver-ping.timer
}
case "$1" in
stop)
psono_stop
;;
migrate)
psono_migrate_start
;;
*)
exit 1
;;
esacQuestions:
- the original software requires a python environment, currently it's being installed by the package install script. The install script however uses sudo and I'm not sure what are the guidelines regarding it so if someone could explain, I'd apprechiate it See Edit 2 below
- are there any other ways python environments are installed with packages? See Edit 6 below
- problem with the libc.so library, apparently it contains "links" to libc.so.6 and is causing problems with python, resulting in "Invalid ELF header" errors. This has been the case for about a year and a half now. Creating a backup of libc.so and symlinking libc.so.6 to libc.so fixes the issue and I created a pacman hook for this process. However from my common sense perspective this is a big no no because libc.so is not part of my package and I shouldn't manipulate it. Am i wrong? Any recommendations? See Edit 4 below
- any other issues i am missing regarding my source files?
Feedback apprechiated.
Regards,
7thCore
Edit: Added url to PKGBUILD and renamed some config files.
Edit 2: Removed sudo as dependancy and replaced sudo with runuser.
Edit 3: Changed the pre_remove() backup location to /opt/backups/psono-backup
Edit 4: Removed pacman libc.so patching and added patchelf to build process to replace libc.so with libc.so.6 in pyarmor_runtime.so ELF in the Psono software to solve the glibc package tampering. Tested in live environment and confirmed working.
Edit 5: Removed checks for curl and wget from docker_fetch(), recoded docker_fetch() to only use curl and jq, removed wget as make dependancy
Edit 6: Added build() function to handle python venv building and packaging with the package, added sysusers file and removed user creation from the install file, removed printf ascii escape codes for color
Edit 7: Removed user removal from the install script because the user might still own some files after removal. Removed psono backup from the install script because modified files don't get deleted by pacman
Edit 8: Removed docker_fetch() from PKGBUILD, added docker dlagent, renamed user psono to psono-server to avoid user clashing between psono packages, changed app installation dir to /var/lib/psono-server/ to avoid /var/lib/psono/psono/psono repetition
Last edited by 7thCore (2026-03-19 14:31:41)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
- the original software requires a python environment, currently it's being installed by the package install script. The install script however uses sudo and I'm not sure what are the guidelines regarding it so if someone could explain, I'd apprechiate it
- are there any other ways python environments are installed with packages?
- problem with the libc.so library, apparently it contains "links" to libc.so.6 and is causing problems with python, resulting in "Invalid ELF header" errors. This has been the case for about a year and a half now. Creating a backup of libc.so and symlinking libc.so.6 to libc.so fixes the issue and I created a pacman hook for this process. However from my common sense perspective this is a big no no because libc.so is not part of my package and I shouldn't manipulate it. Am i wrong? Any recommendations?
That suggests the sw needs a specific python setup and relies on libraries provided by them instead of system libraries .I guess this is proprietary software ?
the url= link indicates it's open source.
psono-script.install looks like it's intended to be run as user with elevated rights for certain parts .
Such scripts are not suitable for packages and are only useful to see what things need to be done.
pip is only useful for user environments and is blocked from systemwide stuff, updating systemwide packages is the job of pacman.
To package this software for archlinux you'd probably have to disable the auto-update feature and create packages for psono-server-ee and psono-fileserver .
The pre_remove() function makes changes to /root/ user settings and archlinux packages are forbidden to touch user stuff .
The services and timer files should not be included in the packages, but put somewhere in a vcs (git) repository so they can be maintained and updated when needed.
It might be possible to use a custom DL-agent for the docker part.
I didn't investigate in-depth, but sofar I haven't seen anything that blocks creating archlinux packages for this.
NOTE: it won't be easy, a lot of work and may need changes by upstream.
Disliking systemd intensely, but not satisfied with alternatives so focusing on taming systemd.
clean chroot building not flexible enough ?
Try clean chroot manager by graysky
Offline
That suggests the sw needs a specific python setup and relies on libraries provided by them instead of system libraries .
I guess this is proprietary software ?
the url= link indicates it's open source.
Yes, it uses a python virtual environment that's being installed by the psono-script.install script used by pacman when installing or upgrading the package.
Edit: removed pacman libc.so patching and added patchelf to build process to replace libc.so with libc.so.6 in pyarmor_runtime.so ELF in the Psono software to solve the glibc package tampering. Tested in live environment and confirmed working.
psono-script.install looks like it's intended to be run as user with elevated rights for certain parts .
Such scripts are not suitable for packages and are only useful to see what things need to be done.
pip is only useful for user environments and is blocked from systemwide stuff, updating systemwide packages is the job of pacman.
Some of it yes:
- pre_install() create a new system user and system group called psono with it's home folder located at /var/lib/psono where the python application and the virtual environments for it are stored. This user has it's login disabled
- post_install() uses sudo (I think I'll switch this to the runuser command and get rid of the sudo dependancy) to execute commands as the psono user, the commands create a python virtual environment, upgrades pip in that python virtual environment (not the system package) and installs packages designated in psono's requirements.txt file. It does not install, update, modify system packages in any way, shape or form. The python virtual environment is in the psono user's home folder.
To package this software for archlinux you'd probably have to disable the auto-update feature and create packages for psono-server-ee and psono-fileserver .
Split them up you mean? That can be done with ease. I'll have to remove the userdel from pre_remove() then. If both packages are installed they'll both use the same user and a manual cleanup may be required. I could also have a package each for the web client and the web admin created. Also what auto update feature? The migrate command you mean?
The pre_remove() function makes changes to /root/ user settings and archlinux packages are forbidden to touch user stuff .
Understood, I'll pick a more appropriate location for a configuration backup and a backup of the encrypted files from the fileserver. The configuration files have secrets for the database so I believe it's appropriate to create a backup of them just in case. Without those same secrets the postgresql database and the encrypted files are useless and can't be reused if that is the intention.
Edit: moved the location to /opt/backups/psono-backup
The services and timer files should not be included in the packages, but put somewhere in a vcs (git) repository so they can be maintained and updated when needed.
Can be done no problem. I just used this on my personal GitLab server so I could update my personal repository with it. I can upload it to GitHub and link it here if you wish to take a look at it.
It might be possible to use a custom DL-agent for the docker part.
It's already part of the PKGBUILD file. You might have missed it. Search for the docker_fetch() function. Every time the package is built a command in prepare() calls the docker_fetch() function and grabs the latest release of the server and fileserver from docker's hub.
The reason I'm creating a new user is so the systemd services run the software with the psono user's user permision. No elevated access, so it can only run what it needs to. I'm basically doing what for example postgresql does when it creates the postgres user and runs the service as that user. Here is the Psono server service file for example:
# /usr/lib/systemd/system/psono-server-ee.service
[Unit]
Description=Psono Password Manager - Enterprise Edition Service
After=network.target network-online.target
Wants=network-online.target
[Service]
Type=notify
TimeoutSec=120
# Psono user specific settings
User=psono
Group=psono
LogsDirectory=psono
StateDirectory=psono
SyslogIdentifier=psono
WorkingDirectory=/var/lib/psono/psono-server-ee/psono
Environment=HOME=/var/lib/psono
# Executable settings
ExecStart=/var/lib/psono/.python_env/psono-server-ee-3.14/bin/gunicorn --bind 0.0.0.0:10100 wsgi
KillMode=mixed
KillSignal=SIGINT
RestartForceExitStatus=100
TimeoutSec=15min
# Additional security-related features
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
NoNewPrivileges=true
ProtectControlGroups=true
ProtectKernelModules=true
ProtectKernelTunables=true
PrivateDevices=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=true
RestrictRealtime=true
SystemCallArchitectures=native
[Install]
WantedBy=multi-user.targetLet me know what you think.
Last edited by 7thCore (2026-03-17 10:38:05)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
things have improved.
prepare() - docker fetch
makepkg has a special feature DLAGENTS .
Using this you would add the docker image in source= array and use a custom DLAGENT to download the image.
No idea if that's possible for docker_fetch, but it's worth it to look into.
Note that you should choose which tools are needed to build (and add them to makedeps unless they're a member of base-devel) .
Don't check for curl/wget , choose one and use that.
makedepends are only needed during build and can/should be removed after.
# Given a JSON input on stdin, extract the string value associated with the
# specified key. This avoids an extra dependency on a tool like `jq`.
extract() {
local key="$1"
# Extract "<key>":"<val>" (assumes key/val won't contain double quotes).
# The colon may have whitespace on either side.
grep -o "\"${key}\"[[:space:]]*:[[:space:]]*\"[^\"]\+\"" |
# Extract just <val> by deleting the last '"', and then greedily deleting
# everything up to '"'.
sed -e 's/"$//' -e 's/.*"//'
}jq is already a makedepend, why not use it ?
from install script
printf "\e[32mUpdating Python packages from requirements.txt for Psono Fileserver\e[0m\n"
runuser -l psono -s /bin/bash -c "/usr/bin/python3.14 -m venv /var/lib/psono/.python_env/psono-fileserver-3.14"
runuser -l psono -s /bin/bash -c "/var/lib/psono/.python_env/psono-fileserver-3.14/bin/python3.14 -m pip install --upgrade pip"
runuser -l psono -s /bin/bash -c "/var/lib/psono/.python_env/psono-fileserver-3.14/bin/pip3.14 install -r /var/lib/psono/psono-fileserver/requirements.txt"
runuser -l psono -s /bin/bash -c "/var/lib/psono/.python_env/psono-fileserver-3.14/bin/pip3.14 install gunicorn"commands like those are ok for a user virtual python environment but I've never seen them used for a systemwide python app install .
It's questionable if AUR moderators will accept this approach, but it will definitely block adoption of this package into official repos .
Package those applications following https://wiki.archlinux.org/title/Python … guidelines is much better (though likely harder)
Disliking systemd intensely, but not satisfied with alternatives so focusing on taming systemd.
clean chroot building not flexible enough ?
Try clean chroot manager by graysky
Offline
I think a much better approach would be to move the most egregious steps, especially the 'pip' installs inside the venv, from the install script to a build() function in the PKGBUILD. Since it's running in a venv, they can (should) be performed by an unprivileged user at build time. And then use the install() function to move the resultant files into /var/lib/psono, owed by the 'psono' user.
However, if this package already uses both venv and docker images, it does raise the question: why isn't this running entirely in a container? Or vice-versa: entirely without needing the Docker overhead and networking/file management pains?
Offline
So you're suggesting I do something like this in PKGBUILD?
build() {
printf "\e[32mPreparing Psono Server Enterprise Edition python virtual environment\e[0m\n"
/usr/bin/python3.14 -m venv ${srcdir}/python_env/psono-server-ee-3.14
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-server-ee-3.14/bin/python3.14 -m pip install --upgrade pip
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-server-ee-3.14/bin/pip3.14 install -r ${srcdir}/psono-ee-src/requirements.txt
if [ "$(uname -m)" = "x86_64" ]; then
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-server-ee-3.14/bin/pip3.14 install -r ${srcdir}/psono-ee-src/requirements-amd64.txt
fi
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-server-ee-3.14/bin/pip3.14 install gunicorn
printf "\e[32mChanging paths of python virtual environment files\e[0m\n"
find ${srcdir}/python_env/psono-server-ee-3.14 -type f ! -type l -exec sed -i "s|${srcdir}/python_env/psono-server-ee-3.14|/var/lib/psono/.python_env/psono-server-ee-3.14|g" {} +
printf "\e[32mDeleting python virtual environment cache files\e[0m\n"
find ${srcdir}/python_env/psono-server-ee-3.14/lib/python3.14/site-packages -type f -name "*.pyc" -delete -o -type d -name "__pycache__" -exec rm -rf {} +
printf "\e[32mPreparing Psono File Server python virtual environment\e[0m\n"
/usr/bin/python3.14 -m venv ${srcdir}/python_env/psono-fileserver-3.14
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-fileserver-3.14/bin/python3.14 -m pip install --upgrade pip
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-fileserver-3.14/bin/pip3.14 install -r ${srcdir}/psono-fs-src/requirements.txt
PIP_CONFIG_FILE="${srcdir}/conf_psono-python-pip.conf" ${srcdir}/python_env/psono-fileserver-3.14/bin/pip3.14 install gunicorn
printf "\e[32mChanging paths of python virtual environment files\e[0m\n"
find ${srcdir}/python_env/psono-fileserver-3.14 -type f ! -type l -exec sed -i "s|${srcdir}/python_env/psono-fileserver-3.14|/var/lib/psono/.python_env/psono-fileserver-3.14|g" {} +
printf "\e[32mDeleting python virtual environment cache files\e[0m\n"
find ${srcdir}/python_env/psono-fileserver-3.14/lib/python3.14/site-packages -type f -name "*.pyc" -delete -o -type d -name "__pycache__" -exec rm -rf {} +
}And remove it from the psono-ee.install like so:
pre_install() {
getent group psono >/dev/null || groupadd --system psono
getent passwd psono >/dev/null || useradd --system -g psono -d /var/lib/psono -s /usr/bin/nologin psono
}
post_install() {
printf "\e[1;31mDisclaimer: This AUR package is maintained by the community and is not\e[0m\n"
printf "\e[1;31mofficially supported by the software developers or the package maintainer.\e[0m\n"
printf "\e[1;31mUse this package at your own risk. The developers of the original software\e[0m\n"
printf "\e[1;31mand the package maintainer are not responsible for any issues, bugs, or\e[0m\n"
printf "\e[1;31mdamages resulting from its use. For installation or usage questions, please\e[0m\n"
printf "\e[1;31mdo not contact the original developers. Instead, seek assistance from the\e[0m\n"
printf "\e[1;31mpackage maintainer, the Arch Linux community or relevant forums.\e[0m\n"
printf "\e[32mDon't forget to setup your Psono configuration and execute the following command to complete the Psono installation before starting the services:\e[0m\n"
printf "\e[32m'runuser -l psono -s /bin/bash -c \"/var/lib/psono/.python_env/psono-server-ee-3.14/bin/python3.14 /var/lib/psono/psono-server-ee/psono/manage.py migrate\"'\e[0m\n"
chown -R psono:psono /var/lib/psono
chown -R psono:psono /var/log/psono
}
post_upgrade() {
printf "\e[1;31mDisclaimer: This AUR package is maintained by the community and is not\e[0m\n"
printf "\e[1;31mofficially supported by the software developers or the package maintainer.\e[0m\n"
printf "\e[1;31mUse this package at your own risk. The developers of the original software\e[0m\n"
printf "\e[1;31mand the package maintainer are not responsible for any issues, bugs, or\e[0m\n"
printf "\e[1;31mdamages resulting from its use. For installation or usage questions, please\e[0m\n"
printf "\e[1;31mdo not contact the original developers. Instead, seek assistance from the\e[0m\n"
printf "\e[1;31mpackage maintainer, the Arch Linux community or relevant forums.\e[0m\n"
chown -R psono:psono /var/lib/psono
chown -R psono:psono /var/log/psono
}
pre_remove() {
printf "\e[32mBacking up Psono configuration and shards to /opt/backups/psono-backup\e[0m\n"
mkdir -p /opt/backups/psono-backup
cp /etc/nginx/sites-available/psono-ee-combo.conf /opt/backups/psono-backup/psono-ee-combo-nginx.conf
cp /var/lib/psono/.psono_server/settings.yaml /opt/backups/psono-backup/server_settings.yaml
cp /var/lib/psono/.psono_fileserver/settings.yaml /opt/backups/psono-backup/fileserver_settings.yaml
cp -rf /var/lib/psono/psono-shard /opt/backups/psono-backup/
}
post_remove() {
userdel --remove psono
rm /etc/nginx/sites-available/psono-ee-combo.conf
rm /etc/nginx/sites-enabled/psono-ee-combo.conf
rm -rf /usr/share/webapps/psono-webclient
}Well I tried it in a live environment and it works. The package is however 130MB in size tho,but it works.
The reason the Psono developers are using both docker and venv is, I belive, because they can control the environment easily and administrators can update the software via docker. Creates less problems. Psono has quite an extensive list of requirements to function, some are even not available in the Arch Linux repository.
Edit: the find commands had to be added so the python cache is regenerated on first execution on a machine that the package was installed to and the other find command changes paths, otherwise it will still have the ${srcdir} paths and the venv won't function at all.
Edit 2: Let me know if this solution is acceptable and if so, I'll edit the original post to include it.
Edit 3: Removed checks for curl and wget from docker_fetch(), recoded docker_fetch() to only use curl and jq, removed wget as make dependancy
Last edited by 7thCore (2026-03-17 22:39:10)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
I'd say it's MUCH better now that you "build" the package in the build() function and not have any binaries created/installed during the install function. As for the 130MB in size: if that is true representation of the size that gets installed, then that's actually another big benefit: pacman will now accurately check available disk space before installing.
As a sanity check: compare the full size of the files installed with the "old" method of doing the full build during the install() to what pacman believes the install requires for the 130MB package. If those are roughly the same, then that's great. If there's a big difference, perhaps you can strip out some files.
find ${srcdir}/python_env/psono-fileserver-3.14/lib/python3.14/site-packages -type f -name "*.pyc" -delete -o -type d -name "__pycache__" -exec rm -rf {} +
I am not an expert in packaging Python packages, so I could be wrong here, but I don't think you want to remove the optimized bytecode files. I know this will inflate the package size even more, but that way pacman keeps track of them. See Python package guidelines. Ctrl-f for "pyc".
Edit: forgot to add this: to create the "psono" user/group, I believe you should be using the systemd.sysusers functionality. This is how the postgresql package creates its 'postgres' user:
=== PKGBUILD:
package() {
...
install -Dm644 postgresql.sysusers "${pkgdir}/usr/lib/sysusers.d/postgresql.conf"
}
=== postgresql.sysusers:
u postgres - "PostgreSQL user" /var/lib/postgres /usr/bin/bashLastly, this might be too subjective, but I personally think you shouldn't pretty-print your "printf's" and just keep it straight plain-text. It will get saved in pacman.log and it makes it harder to automate and search.
Last edited by twelveeighty (2026-03-18 00:45:58)
Offline
With building the python environments the installation size gets reduced by 640M because there is no pip cache present in the psono user's .cache directory. The complete file size of extracted files is 450M.
The python_venv directory with the bytecode files is 1.2G and without it's 380M.
I am not an expert in packaging Python packages, so I could be wrong here, but I don't think you want to remove the optimized bytecode files. I know this will inflate the package size even more, but that way pacman keeps track of them. See Python package guidelines. Ctrl-f for "pyc".
From my testing, not cleaning up the bytecode files results in bytecode errors and 100% guaranteed crashing executing any command from both virtual environments on the new installation. I tested with and without the cleanup by building the package and installing it on the same machine. It's most likely a path issue because the python venv gets generated for example in /home/users/psono-ee-combo/src/python_venv/psono-server-ee-3.14 and that path gets passed to the venv and it's bytecode files. Cleaning them up is a necessity to prevent errors from showing up on fresh installations.
forgot to add this: to create the "psono" user/group, I believe you should be using the systemd.sysusers functionality. This is how the postgresql package creates its 'postgres' user:
Added. What about the postgresql.tmpfiles file? It creates the /var/lib postgres/data folder, but that's for an empty folder and postgresql doesn't ship anything in those folders.
Edit: Problem, the install script can't chown the user directory because the user is created after the package installation.
Edit 2: Never mind, forgot that I set LogsDirectory, StateDirectory and SyslogIdentifier in the systemd services. Those change the ownership to psono as soon as they're activated.
Lastly, this might be too subjective, but I personally think you shouldn't pretty-print your "printf's" and just keep it straight plain-text. It will get saved in pacman.log and it makes it harder to automate and search.
Done. First post updated.
Edit: I'll research Lone_Wolf's suggested approach too. I don't quite understand it just yet but I'll see what comes of it.
Edit 2: Removed user removal from the install script because the user might still own some files after removal. Removed psono backup from the install script because modified files don't get deleted by pacman. Using sysusers to create psono user. Updated first post.
Edit 3: Todo: split server and fileserver to their own packages, 'python -m build --wheel' might not be viable here, there are no build files or folders for the python application unless I create them in the prepare() function somehow. Still researching.
Anything else? Also should I create new PKGBUILD reviews for the seperate packages or just update the first post?
Last edited by 7thCore (2026-03-18 12:51:53)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
I think it's worth exploring and fixing the venv / pyc issues, it'll make the package much cleaner if all system files are tracked by pacman. It seems you are correctly creating the venv underneath the $srcdir. Can you post the full error/exception trace from the new installation?
Probably keep updating your first first with the latest PKGBUILD is easier for us, btw.
Before you submit to the AUR, I think there are a couple of required "housekeeping" things needed - see AUR guidelines. For instance: all packages in the AUR assume that base-devel from [core] is installed, so you should clean up the depends arrays. For example, gcc is part pf base-devel, so it shouldn't be in "depends". Same goes for gzip and sed in makedepends. I didn't go through all of them.
As for your package name, since you are copying binary code from a Docker image, I think this package should have the -bin suffix, since it's precompiled binaries that are being installed. The Documentation on this mentions "non-free" binary applications, but I think it still applies.
Is it your intent to always pull the "latest" Docker image when installing? That's certainly a packaging choice you are making. You could also "pin" the version to a specific one and thoroughly test it. You can also submit two packages to AUR: one for a specific tested version and another that just points to the latest Docker image (like you have now). That's obviously more work, I'll leave it up to you to decide.
As Lone_Wolf already pointed out, "blindly" copying the Docker image is probably what most Arch users would be concerned about, since it's not captured by the usual "source" array and matched to the "sha256sums". So the installer is basically copying a binary image locally that is not checked against a known checksum upfront. It's similar to a "git" package, but in those cases it's pulling source code, not binary code. If you can get a DLAGENT to work so that it's hash is verified with one that's in the sha256sums array, that would be better.
Offline
I'd prefer if you didn't change the content of the first post (except adding edit y notes) and put new PKGBUILD/.install etc only in new posts.
Reason: editing the first post makes it near impossible to see what changes have been made and very hard to follow the thread.
As for .pyc files in packages : I'm 99% sure those are created by makepkg for use with system python.
Since you're using a venv, they are unlikely to match and deleting them makes sense.
Disliking systemd intensely, but not satisfied with alternatives so focusing on taming systemd.
clean chroot building not flexible enough ?
Try clean chroot manager by graysky
Offline
@Lone_Wolf Understood. I can restore the first post if you wish. All of it is on my personal gitlab.
Also do you approve of the python venv packaging? Or should I try to do it another way?
@twelveeighty I'll get you that error in a few hours.
Edit: Does the custom dlagent come with the package source?
Edit 2: regarding the custom dlagent, I've been experimenting and it's gonna be hard to implement a sha check because there's no archive available. It just downloads the folder structure with the files. Regarding having always the latest docker image downloaded, that can be separated in two packages also, one for example psono-server-ee-latest and one psono-server-ee-stable, the stable being locked to a specific version. The docker_fetch() function I provided can download tag/version specific images.
Edit 3: I have a dlagent working for docker downloading and with hash. I'll post in an hour or so.
Last edited by 7thCore (2026-03-19 06:14:39)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
I believe this is warranted for a double post.
Alright, let me give you the rundown of what I did. First thing's first, I split the packages. Packages that are going to use the custom docker dlagent are now going to be psono-server-ee, psono-server-ce, psono-fileserver with ee and ce being mutually exclusive. Currently I'm focusing getting psono-server-ee up to code and running and I can implement the same processes to the other packages with ease. From this point forward I'll be posting only about the psono-server-ee package and it's corresponding files.
Now let's get to it. The PKGBUILD had the docker_fetch() function removed and the custom DLAGENT was added as dlagent-docker-fetch.sh for downloading docker images. This can work with any docker image, appart from the few lines of code at the bottom of the dlagent script that are specific for this image/package. When all is set up, the files get archived in a tarball and that tarball's hash is taken for the sha256sums array. The tar command uses a specific mtime flag so the hash isn't affected by metadata. This makes sure that hashes are consistent for the exact same files in the tarball. This was tested multiple times on multiple machines and it works without issue.
Version specific packaging, the pkgver() function was removed and the pkgver variable was added where needed to download the specific version of the docker image, in this case version 7.1.0 and will always download version 7.1.0 as long as it's available on docker hub. This makes the option of having a stable long term package but can be updated by just changing the pkgver variable. The custom dlagent will accept a version number, 'latest' or whatever the tag on docker hub is.
Regarding licenses and REUSE missing in files, I want to get the packaging process working first before I mess with that again.
Minor things done:
- python venv moved from /var/lib/psono-server/.python_env/psono-server-ee-3.14 to /var/lib/psono-server/.psono-server-venv-3.14
- removed base-devel packages from makedepends
- the psono user was renamed to psono-server (the psono-fileserver will have it's own user, these applications can work on their own on separate machines)
- the application is now directly in the psono-server user's home folder to avoid /var/lib/psono-server/psono-server-ee repetition
- added bin suffix to package name
PKGBUILD
# Maintainer: 7thCore <redacted-for-now>
# Disclaimer: This AUR package is maintained by the community and is not
# officially supported by the software developers or the package maintainer.
# Use this package at your own risk. The developers of the original software
# and the package maintainer are not responsible for any issues, bugs, or
# damages resulting from its use. For installation or usage questions, please
# do not contact the original developers. Instead, seek assistance from the
# package maintainer, the Arch Linux community or relevant forums.
pkgname=psono-server-ee-bin
pkgver=7.1.0
pkgrel=1
pkgdesc='Enterprise Edition of the open source and self hosted password manager. Server application.'
arch=('x86_64' 'aarch64')
url='https://psono.com'
license=('Apache-2.0')
depends=('bash'
'coreutils'
'gcc'
'git'
'glibc'
'haveged'
'libb2'
'libffi'
'libldap'
'libpqxx'
'libsasl'
'libyaml'
'nginx'
'openssl'
'postgresql'
'python>=3.14'
'python<3.15'
'util-linux')
optdepends=('logrotate: rotates system logs automatically'
'fail2ban: bans IPs after too many failed authentication attempts')
makedepends=('curl'
'jq'
'patchelf'
'tar')
provides=('psono-server')
conflicts=('psono-server')
backup=('etc/fail2ban/filter.d/psono-ee.conf'
'etc/fail2ban/jail.d/psono-ee.local'
'etc/logrotate.d/psono-server-ee'
'etc/nginx/sites-available/psono.conf'
'var/lib/psono-server/.psono_server/settings.yaml')
options=('!strip' '!debug')
install='psono-server-ee.install'
source=('dlagent-docker-fetch.sh'
'psono-server-ee-cleartoken.service'
'psono-server-ee-cleartoken.timer'
'psono-server-ee-fail2ban-filter.conf'
'psono-server-ee-fail2ban-jail.local'
'psono-server-ee-nginx.conf'
'psono-server-ee-requirements.patch'
'psono-server-ee-settings.yaml'
'psono-server-ee.install'
'psono-server-ee.logrotate'
'psono-server-ee.service'
'psono-server-ee.sysusers'
"docker://psono/psono-server-enterprise_${pkgver}.tar.gz")
noextract=("psono-server-enterprise_${pkgver}.tar.gz")
sha256sums=('7d010c586f8701a674614a8b60da8fd6ef4027c771944754b0f9ec74106b05b0'
'1ec9dac8494c2ff985cd670bff21cdbec8965ea331f9b390fb042aac81f90b45'
'ebc9d9ad66ff7cfdbf4698b2ce24392b1a52ff6a0294f72288e14be1ede6219b'
'66ac600efad0aa1af7ddfeca5452f369ac3fe8f0e8c9ad90ae1bf73be18460bc'
'5d422995f77d17c65d7827e0af27afb0ba6500e91e17f66fcb758aa322d8108c'
'2f815769b7dd5c672b491138e59e1709ea30676d66c7562ad54c7c2ce14dc55c'
'4a171e8c0ee529bad90ad37e6633f8dc7cfe40e02fb4cf24f6e95f8084b4584a'
'442a92d0960b6a9ff72d3ef9459cf4ed32a2e03ddce782b1b66a0fe270eec56e'
'aa319ef6fb166cfebdaa0d1593dc1629bf4290227e28fd23dec2118745c7939d'
'bd391b1824d182c3d5813ca71535d5e47c2404883f1bc58f76b677fde3d6e70f'
'41a4a39279c62760fdf4a82a185c444e19010301513b3e9e7a7a20580ef6f035'
'ebcd077d359894605e8e082bce9fc9ce1307b1932310dc79bd5402224eb32ff0'
'7d03b5c8031b89fbd8aad16776add5e00cd3e5783162f8148d86a0f5323ee7b8')
DLAGENTS=('docker::./dlagent-docker-fetch.sh %u')
prepare() {
printf "\e[1;31mDisclaimer: This AUR package is maintained by the community and is not\e[0m\n"
printf "\e[1;31mofficially supported by the software developers or the package maintainer.\e[0m\n"
printf "\e[1;31mUse this package at your own risk. The developers of the original software\e[0m\n"
printf "\e[1;31mand the package maintainer are not responsible for any issues, bugs, or\e[0m\n"
printf "\e[1;31mdamages resulting from its use. For installation or usage questions, please\e[0m\n"
printf "\e[1;31mdo not contact the original developers. Instead, seek assistance from the\e[0m\n"
printf "\e[1;31mpackage maintainer, the Arch Linux community or relevant forums.\e[0m\n"
[ -d "${srcdir}/psono-server-ee-src" ] && rm -rf "${srcdir}/psono-server-ee-src"
mkdir -p "${srcdir}/psono-server-ee-src"
[ -d "${srcdir}/psono-server-venv-3.14" ] && rm -rf "${srcdir}/psono-server-venv-3.14"
mkdir -p "${srcdir}/psono-server-venv-3.14"
printf "\e[32mExtracting Psono Server Enterprise Edition\e[0m\n"
tar -xvf "psono-server-enterprise_${pkgver}.tar.gz" -C "${srcdir}/psono-server-ee-src"
printf "\e[32mPatching Psono Server Enterprise Edition requirements.txt\e[0m\n"
cd "${srcdir}/psono-server-ee-src" || exit 1
patch -Np1 -i "${srcdir}/psono-server-ee-requirements.patch"
# Find the latest pyarmor_runtime.so folder, cd to it and patch pyarmor_runtime.so
printf "\e[32mPatching pyarmor_runtime.so ELF by replacing libc.so with libc.so.6 to avoid 'invalid ELF header' errors\e[0m\n"
cd "${srcdir}/psono-server-ee-src" || exit 1
PYARMOR_RUNTIME_DIR=$(ls -d pyarmor_runtime_* | sort -V | tail -n 1)
if [[ -d "$PYARMOR_RUNTIME_DIR" ]]; then
cd "$PYARMOR_RUNTIME_DIR" || exit 1
patchelf --replace-needed libc.so libc.so.6 pyarmor_runtime.so
fi
}
build() {
printf "\e[32mPreparing Psono Server Enterprise Edition python virtual environment\e[0m\n"
/usr/bin/python3.14 -m venv ${srcdir}/psono-server-venv-3.14
PIP_CONFIG_FILE="${srcdir}/psono-server-ee-src/psono-pip.conf" ${srcdir}/psono-server-venv-3.14/bin/python3.14 -m pip install --upgrade pip
PIP_CONFIG_FILE="${srcdir}/psono-server-ee-src/psono-pip.conf" ${srcdir}/psono-server-venv-3.14/bin/pip3.14 install -r ${srcdir}/psono-server-ee-src/requirements.txt
if [ "$(uname -m)" = "x86_64" ]; then
PIP_CONFIG_FILE="${srcdir}/psono-server-ee-src/psono-pip.conf" ${srcdir}/psono-server-venv-3.14/bin/pip3.14 install -r ${srcdir}/psono-server-ee-src/requirements-amd64.txt
fi
PIP_CONFIG_FILE="${srcdir}/psono-server-ee-src/psono-pip.conf" ${srcdir}/psono-server-venv-3.14/bin/pip3.14 install gunicorn
printf "\e[32mChanging paths of python virtual environment files\e[0m\n"
find ${srcdir}/psono-server-venv-3.14 -type f ! -type l -exec sed -i "s|${srcdir}/psono-server-venv-3.14|/var/lib/psono-server/.psono-server-venv-3.14|g" {} +
printf "\e[32mDeleting python virtual environment cache files\e[0m\n"
find ${srcdir}/psono-server-venv-3.14/lib/python3.14/site-packages -type f -name "*.pyc" -delete -o -type d -name "__pycache__" -exec rm -rf {} +
}
package() {
# Fail2ban
install -dm755 "${pkgdir}/etc/fail2ban/jail.d"
install -dm755 "${pkgdir}/etc/fail2ban/filter.d"
install -Dm644 "${srcdir}/psono-server-ee-fail2ban-filter.conf" "${pkgdir}/etc/fail2ban/filter.d/psono-ee.conf"
install -Dm644 "${srcdir}/psono-server-ee-fail2ban-jail.local" "${pkgdir}/etc/fail2ban/jail.d/psono-ee.local"
# Logrotate
install -dm755 "${pkgdir}/etc/logrotate.d"
install -Dm644 "${srcdir}/psono-server-ee.logrotate" "${pkgdir}/etc/logrotate.d/psono-server-ee"
# Nginx
install -dm755 "${pkgdir}/etc/nginx/sites-available"
install -dm755 "${pkgdir}/etc/nginx/sites-enabled"
install -Dm644 "${srcdir}/psono-server-ee-nginx.conf" "${pkgdir}/etc/nginx/sites-available/psono.conf"
# Psono
install -dm755 "${pkgdir}/var/lib/psono-server/"
install -Dm644 "${srcdir}/psono-server-ee-settings.yaml" "${pkgdir}/var/lib/psono-server/.psono_server/settings.yaml"
install -Dm644 "${srcdir}/psono-server-ee.sysusers" "${pkgdir}/usr/lib/sysusers.d/psono.conf"
install -Dm644 "${srcdir}/psono-server-ee.service" "${pkgdir}/usr/lib/systemd/system/psono-server-ee.service"
install -Dm644 "${srcdir}/psono-server-ee-cleartoken.service" "${pkgdir}/usr/lib/systemd/system/psono-server-ee-cleartoken.service"
install -Dm644 "${srcdir}/psono-server-ee-cleartoken.timer" "${pkgdir}/usr/lib/systemd/system/psono-server-ee-cleartoken.timer"
#Psono software and python virtual environment
cp -dr --no-preserve=ownership "${srcdir}/psono-server-ee-src"/* "${pkgdir}/var/lib/psono-server/"
cp -dr --no-preserve=ownership "${srcdir}/psono-server-venv-3.14" "${pkgdir}/var/lib/psono-server/.psono-server-venv-3.14"
}dlagent-docker-fetch.sh
#!/bin/bash
# Docker fetch function modified from https://github.com/jjlin/docker-image-extract
docker_fetch() {
image_spec="$1"
output_dir="$2"
[ -d "$output_dir" ] && rm -rf "$output_dir"
mkdir -p "$output_dir"
if [ "$(uname -m)" = "x86_64" ]; then
PLATFORM="linux/amd64"
elif [ "$(uname -m)" = "aarch64" ]; then
PLATFORM="linux/arm64"
fi
image="${image_spec%%:*}"
if [ "${image#*/}" = "${image}" ]; then
image="library/${image}"
fi
ref="${image_spec#*:}"
# Split platform (OS/arch/variant) into separate variables.
IFS=/ read -r OS ARCH VARIANT <<< "${PLATFORM}"
fetch() {
if [ $# -eq 2 ]; then
set -- -H "$2" "$1"
elif [ $# -eq 3 ]; then
set -- -H "$2" -H "$3" "$1"
fi
curl -sSL "$@"
}
manifest_list_url="https://hub.docker.com/v2/repositories/${image}/tags/${ref}"
if [ -z "${ref##sha256:*}" ]; then
digest="${ref}"
else
echo "Getting multi-arch manifest list..."
digest=$(fetch "${manifest_list_url}" | jq -r '.images[] | select(.architecture == "'"${ARCH}"'" and .os == "'"${OS}"'" and (.variant == "'"${VARIANT}"'" or (.variant | not))) | .digest' | head -n 1)
if [ -n "${digest}" ]; then
echo "Platform ${PLATFORM} resolved to '${digest}'..."
else
echo "No image digest found. Verify that the image, ref, and platform are valid."
exit 1
fi
fi
api_token_url="https://auth.docker.io/token?service=registry.docker.io&scope=repository:$image:pull"
manifest_url="https://registry-1.docker.io/v2/${image}/manifests/${digest}"
blobs_base_url="https://registry-1.docker.io/v2/${image}/blobs"
echo "Getting API token..."
token=$(fetch "${api_token_url}" | jq -r '.token')
auth_header="Authorization: Bearer $token"
docker_manifest_v2="application/vnd.docker.distribution.manifest.v2+json"
oci_manifest_v1="application/vnd.oci.image.manifest.v1+json"
accept_header="Accept: ${docker_manifest_v2},${oci_manifest_v1}"
echo "Getting image manifest for $image:$ref..."
layers=$(fetch "${manifest_url}" "${auth_header}" "${accept_header}" | jq -r '.layers[].digest')
if [ -z "${layers}" ]; then
echo "No layers returned. Verify that the image and ref are valid."
exit 1
fi
for layer in $layers; do
hash="${layer#sha256:}"
echo "Fetching and extracting layer ${hash}..."
fetch "${blobs_base_url}/${layer}" "${auth_header}" | gzip -d | tar -C "${output_dir}" -xf -
OLD_IFS="${IFS}"
find "${output_dir}" -name '.wh.*' | while IFS= read -r f; do
dir="${f%/*}"
wh_file="${f##*/}"
file="${wh_file#.wh.}"
rm -rf "${dir}/${wh_file}" "${dir}/${file}"
done
IFS="${OLD_IFS}"
done
echo "Image contents extracted into ${output_dir}."
}
# Get the input variable, remove 'docker://', remove the '.tar.gz' extension, replace underscores with colons
input_docker_link="$1"
docker_link="${input_docker_link#docker://}"
docker_link="$(echo "$docker_link" | sed -E 's/\.tar\.gz$//')"
output_docker="${docker_link#*/}"
docker_link="$(echo "$docker_link" | sed -E 's/_/:/g')"
# Use docker_fetch to get the image
docker_fetch "${docker_link}" ./"${output_docker}"
# Package specific operations
mv "${output_docker}"/root/requirements.txt "${output_docker}"/root/psono/requirements.txt
mv "${output_docker}"/root/requirements-amd64.txt "${output_docker}"/root/psono/requirements-amd64.txt
mv "${output_docker}"/root/.pip/pip.conf "${output_docker}"/root/psono/psono-pip.conf
# The archive has to be created with a fixed mtime flag for every operation to ensure the hash is consistent for the same files
tar --mtime='2002-03-11' -cf ./"${output_docker}".tar.gz -C "${output_docker}"/root/psono .
rm -rf "${output_docker}"File list:
PKGBUILD
dlagent-docker-fetch.sh
psono-server-ee-cleartoken.service
psono-server-ee-cleartoken.timer
psono-server-ee-fail2ban-filter.conf
psono-server-ee-fail2ban-jail.local
psono-server-ee-nginx.conf
psono-server-ee-requirements.patch
psono-server-ee-settings.yaml
psono-server-ee.install
psono-server-ee.logrotate
psono-server-ee.service
psono-server-ee.sysusersLast edited by 7thCore (2026-03-19 13:56:39)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
To me, that looks pretty good. I'd say submit it to the AUR, don't forget to create a .SRCINFO first, before commiting.
Edit: forgot to mention that I learned from this that Docker images can be unpacked and installed "locally" as if they were mere zip files, something I didn't know even after working with containers/kubernetes for years.
Last edited by twelveeighty (2026-03-19 14:50:20)
Offline
Will do. I just have to set up all the other packages. I'm also thinking of writing some documentation for it. Sort of guide or maybe an Arch Wiki page if i'll be allowed to. Not sure how it works for AUR packages.
Edit: forgot to mention that I learned from this that Docker images can be unpacked and installed "locally" as if they were mere zip files, something I didn't know even after working with containers/kubernetes for years.
Yeah there's always something new to learn. I wonder if people will take the dlagent I slapped together, use it or improve it. I sure hope so.
Also here's the error code if the python cache isn't deleted when building the package. You mentioned a day ago you wanted to see it:
Error processing line 1 of /var/lib/psono-server/.psono-server-venv-3.14/lib/python3.14/site-packages/distutils-precedence.pth:
Traceback (most recent call last):
File "<frozen site>", line 213, in addpackage
File "<string>", line 1, in <module>
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 755, in exec_module
File "<frozen importlib._bootstrap_external>", line 888, in get_code
File "<frozen importlib._bootstrap_external>", line 511, in _compile_bytecode
ValueError: bad marshal data (unknown type code)
Remainder of file ignored
Error processing line 1 of /var/lib/psono-server/.psono-server-venv-3.14/lib/python3.14/site-packages/distutils-precedence.pth:
Traceback (most recent call last):
File "<frozen site>", line 213, in addpackage
File "<string>", line 1, in <module>
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 755, in exec_module
File "<frozen importlib._bootstrap_external>", line 888, in get_code
File "<frozen importlib._bootstrap_external>", line 511, in _compile_bytecode
ValueError: bad marshal data (unknown type code)
Remainder of file ignored
Traceback (most recent call last):
File "/var/lib/psono-server/.psono-server-venv-3.14/bin/gunicorn", line 3, in <module>
from gunicorn.app.wsgiapp import run
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 755, in exec_module
File "<frozen importlib._bootstrap_external>", line 888, in get_code
File "<frozen importlib._bootstrap_external>", line 511, in _compile_bytecode
ValueError: bad marshal data (unknown type code)Last edited by 7thCore (2026-03-19 18:57:31)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
Will do. I just have to set up all the other packages. I'm also thinking of writing some documentation for it. Sort of guide or maybe an Arch Wiki page if i'll be allowed to. Not sure how it works for AUR packages.
Start it as a user page on the archwiki. Once it's fleshed out you can ask wiki admins whether they're ok with adding it as an 'official' page.
https://wiki.archlinux.org/title/Help:Editing and https://wiki.archlinux.org/title/ArchWiki:Contributing should help to get started.
ADDED
To me, that looks pretty good. I'd say submit it to the AUR, don't forget to create a .SRCINFO first, before commiting.
Please don't submit it yet.
I haven't seen any PKGBUILDs that use a python venv. The method you're using for it now is a lot better then in your opening post but only aur moderators can determine if that's acceptable .
I suggest you post on the aur general ML and ask for the opinion of the aur moderators.
Note that others may also respond, but only aur moderators / archlinux package maintainers can decide on something like this.
Last edited by Lone_Wolf (2026-03-20 11:51:37)
Disliking systemd intensely, but not satisfied with alternatives so focusing on taming systemd.
clean chroot building not flexible enough ?
Try clean chroot manager by graysky
Offline
Please don't submit it yet.
I haven't seen any PKGBUILDs that use a python venv. The method you're using for it now is a lot better then in your opening post but only aur moderators can determine if that's acceptable .I suggest you post on the aur general ML and ask for the opinion of the aur moderators.
Note that others may also respond, but only aur moderators / archlinux package maintainers can decide on something like this.
Done. I also included the package source files for them to test. Thank you for the advice.
I also redid the PKGBUILD a bit, added some quotes because srcdir and pkgdir had issues if spaces were involved. I also moved the settings.yaml files for the server and fileserver to /etc/psono-server and /etc/psono-fileserver and symlinked the folders.
# Maintainer: 7thCore <redacted-for-now>
# Disclaimer: This AUR package is maintained by the community and is not
# officially supported by the software developers or the package maintainer.
# Use this package at your own risk. The developers of the original software
# and the package maintainer are not responsible for any issues, bugs, or
# damages resulting from its use. For installation or usage questions, please
# do not contact the original developers. Instead, seek assistance from the
# package maintainer, the Arch Linux community or relevant forums.
pkgname=psono-server-ee-bin
pkgver=7.1.0
pkgrel=1
pkgdesc='Enterprise Edition of the open source and self hosted password manager. Server application.'
arch=('x86_64' 'aarch64')
url='https://psono.com'
license=('Apache-2.0')
depends=('bash'
'coreutils'
'gcc'
'git'
'glibc'
'haveged'
'libb2'
'libffi'
'libldap'
'libpqxx'
'libsasl'
'libyaml'
'nginx'
'openssl'
'postgresql'
'python>=3.14'
'python<3.15'
'util-linux')
optdepends=('logrotate: rotates system logs automatically'
'fail2ban: bans IPs after too many failed authentication attempts')
makedepends=('curl'
'jq'
'patchelf'
'tar')
provides=('psono-server')
conflicts=('psono-server')
backup=('etc/fail2ban/filter.d/psono-ee.conf'
'etc/fail2ban/jail.d/psono-ee.local'
'etc/logrotate.d/psono-server-ee'
'etc/nginx/sites-available/psono-server.conf'
'etc/psono-server/settings.yaml')
options=('!strip' '!debug')
install='psono-server-ee.install'
source=('dlagent-docker-fetch.sh'
'psono-server-ee-cleartoken.service'
'psono-server-ee-cleartoken.timer'
'psono-server-ee-fail2ban-filter.conf'
'psono-server-ee-fail2ban-jail.local'
'psono-server-ee-nginx.conf'
'psono-server-ee-requirements.patch'
'psono-server-ee-settings.yaml'
'psono-server-ee.install'
'psono-server-ee.logrotate'
'psono-server-ee.service'
'psono-server-ee.sysusers'
"docker://psono/psono-server-enterprise_${pkgver}.tar.gz")
noextract=("psono-server-enterprise_${pkgver}.tar.gz")
sha256sums=('e9f6f4f08232c9b2eb9db0778c01f12d3ac8efb3a3c239f8c993abc8508aa4ff'
'83cd8165c7696d7a026f3deb85fccc19613f804c12e0a03bde40e2dd6aab9052'
'ebc9d9ad66ff7cfdbf4698b2ce24392b1a52ff6a0294f72288e14be1ede6219b'
'66ac600efad0aa1af7ddfeca5452f369ac3fe8f0e8c9ad90ae1bf73be18460bc'
'5d422995f77d17c65d7827e0af27afb0ba6500e91e17f66fcb758aa322d8108c'
'2f815769b7dd5c672b491138e59e1709ea30676d66c7562ad54c7c2ce14dc55c'
'4a171e8c0ee529bad90ad37e6633f8dc7cfe40e02fb4cf24f6e95f8084b4584a'
'cde81070860ce7517d12c62aaebd6e0d70e469997fdc33334e69d6d6f4486208'
'299834859853461fbbd567605e33dd8a64896c7d4fa24353320e313de02c8e59'
'bd391b1824d182c3d5813ca71535d5e47c2404883f1bc58f76b677fde3d6e70f'
'547dd095dc43bcd72275f6660d684ecd98d3458d9154dc0caeb2bc49e8082a8d'
'ebcd077d359894605e8e082bce9fc9ce1307b1932310dc79bd5402224eb32ff0'
'64be27ee7ae22043c546350f7c56f1d26af1a1ead8429feda311f2fdadd73da2')
DLAGENTS=('docker::./dlagent-docker-fetch.sh %u')
prepare() {
printf "\e[1;31mDisclaimer: This AUR package is maintained by the community and is not\e[0m\n"
printf "\e[1;31mofficially supported by the software developers or the package maintainer.\e[0m\n"
printf "\e[1;31mUse this package at your own risk. The developers of the original software\e[0m\n"
printf "\e[1;31mand the package maintainer are not responsible for any issues, bugs, or\e[0m\n"
printf "\e[1;31mdamages resulting from its use. For installation or usage questions, please\e[0m\n"
printf "\e[1;31mdo not contact the original developers. Instead, seek assistance from the\e[0m\n"
printf "\e[1;31mpackage maintainer, the Arch Linux community or relevant forums.\e[0m\n"
[ -d "${srcdir}/psono-server-ee-src" ] && rm -rf "${srcdir}/psono-server-ee-src"
mkdir -p "${srcdir}/psono-server-ee-src"
[ -d "${srcdir}/psono_venv3.14" ] && rm -rf "${srcdir}/psono_venv3.14"
mkdir -p "${srcdir}/psono_venv3.14"
printf "\e[32mExtracting Psono Server Enterprise Edition\e[0m\n"
tar -xvf "psono-server-enterprise_${pkgver}.tar.gz" -C "${srcdir}/psono-server-ee-src"
mv "${srcdir}/psono-server-ee-src/pip.conf" "${srcdir}/psono-server-ee-pip.conf"
printf "\e[32mPatching Psono Server Enterprise Edition requirements.txt\e[0m\n"
cd "${srcdir}/psono-server-ee-src" || exit 1
patch -Np1 -i "${srcdir}/psono-server-ee-requirements.patch"
# Find the latest pyarmor_runtime.so folder, cd to it and patch pyarmor_runtime.so
printf "\e[32mPatching pyarmor_runtime.so ELF by replacing libc.so with libc.so.6 to avoid 'invalid ELF header' errors\e[0m\n"
cd "${srcdir}/psono-server-ee-src" || exit 1
PYARMOR_RUNTIME_DIR=$(ls -d pyarmor_runtime_* | sort -V | tail -n 1)
if [[ -d "$PYARMOR_RUNTIME_DIR" ]]; then
cd "$PYARMOR_RUNTIME_DIR" || exit 1
patchelf --replace-needed libc.so libc.so.6 pyarmor_runtime.so
fi
}
build() {
printf "\e[32mPreparing Psono Server Enterprise Edition python virtual environment\e[0m\n"
/usr/bin/python3.14 -m venv "${srcdir}/psono_venv3.14"
PIP_CONFIG_FILE="${srcdir}/psono-server-ee-pip.conf" "${srcdir}/psono_venv3.14/bin/python3.14" -m pip install --upgrade pip
PIP_CONFIG_FILE="${srcdir}/psono-server-ee-pip.conf" "${srcdir}/psono_venv3.14/bin/pip3.14" install -r "${srcdir}/psono-server-ee-src/requirements.txt"
if [ "$(uname -m)" = "x86_64" ]; then
PIP_CONFIG_FILE="${srcdir}/psono-server-ee-pip.conf" "${srcdir}/psono_venv3.14/bin/pip3.14" install -r "${srcdir}/psono-server-ee-src/requirements-amd64.txt"
fi
PIP_CONFIG_FILE="${srcdir}/psono-server-ee-pip.conf" "${srcdir}/psono_venv3.14/bin/pip3.14" install gunicorn
printf "\e[32mChanging paths of python virtual environment files\e[0m\n"
find "${srcdir}/psono_venv3.14" -type f ! -type l -exec sed -i "s|${srcdir}/psono_venv3.14|/var/lib/psono-server/.psono_venv3.14|g" {} +
printf "\e[32mDeleting python virtual environment cache files\e[0m\n"
find "${srcdir}/psono_venv3.14/lib/python3.14/site-packages" -type f -name "*.pyc" -delete -o -type d -name "__pycache__" -exec rm -rf {} +
}
package() {
# Fail2ban
install -dm755 "${pkgdir}/etc/fail2ban/jail.d"
install -dm755 "${pkgdir}/etc/fail2ban/filter.d"
install -Dm644 "${srcdir}/psono-server-ee-fail2ban-filter.conf" "${pkgdir}/etc/fail2ban/filter.d/psono-ee.conf"
install -Dm644 "${srcdir}/psono-server-ee-fail2ban-jail.local" "${pkgdir}/etc/fail2ban/jail.d/psono-ee.local"
# Logrotate
install -dm755 "${pkgdir}/etc/logrotate.d"
install -Dm644 "${srcdir}/psono-server-ee.logrotate" "${pkgdir}/etc/logrotate.d/psono-server-ee"
# Nginx
install -dm755 "${pkgdir}/etc/nginx/sites-available"
install -dm755 "${pkgdir}/etc/nginx/sites-enabled"
install -Dm644 "${srcdir}/psono-server-ee-nginx.conf" "${pkgdir}/etc/nginx/sites-available/psono-server.conf"
# Psono
install -dm755 "${pkgdir}/etc/psono-server"
install -dm755 "${pkgdir}/var/lib/psono-server/.pip"
install -Dm644 "${srcdir}/psono-server-ee-settings.yaml" "${pkgdir}/etc/psono-server/settings.yaml"
install -Dm644 "${srcdir}/psono-server-ee-pip.conf" "${pkgdir}/var/lib/psono-server/.pip/pip.conf"
install -Dm644 "${srcdir}/psono-server-ee-settings.yaml" "${pkgdir}/etc/psono-server/settings.yaml"
install -Dm644 "${srcdir}/psono-server-ee.sysusers" "${pkgdir}/usr/lib/sysusers.d/psono-server.conf"
install -Dm644 "${srcdir}/psono-server-ee.service" "${pkgdir}/usr/lib/systemd/system/psono-server-ee.service"
install -Dm644 "${srcdir}/psono-server-ee-cleartoken.service" "${pkgdir}/usr/lib/systemd/system/psono-server-ee-cleartoken.service"
install -Dm644 "${srcdir}/psono-server-ee-cleartoken.timer" "${pkgdir}/usr/lib/systemd/system/psono-server-ee-cleartoken.timer"
# Psono software and python virtual environment
cp -dr --no-preserve=ownership "${srcdir}/psono-server-ee-src"/* "${pkgdir}/var/lib/psono-server/"
cp -dr --no-preserve=ownership "${srcdir}/psono_venv3.14" "${pkgdir}/var/lib/psono-server/.psono_venv3.14"
# Symlink the psono-server configuration directory
ln -s "/etc/psono-server" "${pkgdir}/var/lib/psono-server/.psono_server"
}Last edited by 7thCore (2026-03-20 18:54:08)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
Well it did not go well. The main problems were downloading from docker and the python virtual environment.
Downloading from docker can be mitigated by downloading sources for psono-server-ce, psono-fileserver, psono-client and psono-admin-client from psono's gitlab. However psono-server-ee is docker only and not available on gitlab, probably because it has a lot more features and is free only up to 10 user, after that is pay per user.
The venv discussion, I was told that if I want to post these on the AUR, I also need to add the needed dependencies and I should update psono with my patches to make sure the latest python packages can run with it, then submit it upstream. I get the process and somewhat agree with it but I do not have a lot of time usually and I am not a professional coder. And the amount of dependencies psono uses is not small at all.
This is the requirements.txt file for psono-server comunity edition version 7.1.2:
#
# This file is autogenerated by pip-compile with Python 3.14
# by the following command:
#
# pip-compile --output-file=requirements.txt requirements.in
#
apache-libcloud==3.8.0
# via
# -r requirements.in
# django-storages
asgiref==3.11.0
# via
# daphne
# django
# django-countries
asn1crypto==1.5.1
# via webauthn
attrs==25.4.0
# via
# jsonschema
# referencing
# service-identity
# twisted
autobahn==25.12.2
# via daphne
automat==25.4.16
# via twisted
azure-core==1.38.0
# via
# azure-storage-blob
# django-storages
azure-storage-blob==12.28.0
# via django-storages
bcrypt==4.3.0
# via
# -r requirements.in
# paramiko
boto3==1.34.39
# via
# -r requirements.in
# django-storages
botocore==1.34.162
# via
# boto3
# s3transfer
cbor2==5.9.0
# via
# autobahn
# webauthn
certifi==2026.1.4
# via
# requests
# sentry-sdk
cffi==2.0.0
# via
# autobahn
# cryptography
# pynacl
charset-normalizer==3.4.4
# via requests
constantly==23.10.4
# via twisted
cryptography==46.0.5
# via
# autobahn
# azure-storage-blob
# google-auth
# paramiko
# pyopenssl
# service-identity
# webauthn
daphne==4.1.2
# via -r requirements.in
dj-database-url==2.1.0
# via -r requirements.in
django==5.2.12
# via
# -r requirements.in
# dj-database-url
# django-anymail
# django-cors-headers
# django-filter
# django-redis
# django-storages
# django-timezone-field
# djangorestframework
# drf-spectacular
# sentry-sdk
django-anymail==12.0
# via -r requirements.in
django-cors-headers==3.10.1
# via -r requirements.in
django-countries==8.2.0
# via -r requirements.in
django-filter==2.4.0
# via -r requirements.in
django-redis==5.4.0
# via -r requirements.in
django-storages[azure,boto3,google,libcloud,sftp]==1.14.2
# via -r requirements.in
django-timezone-field==7.1
# via -r requirements.in
djangorestframework==3.16.1
# via
# -r requirements.in
# drf-spectacular
drf-spectacular==0.28.0
# via -r requirements.in
duo-client==5.5.0
# via -r requirements.in
google-api-core==2.29.0
# via
# google-cloud-core
# google-cloud-storage
google-auth==2.48.0rc0
# via
# google-api-core
# google-cloud-core
# google-cloud-storage
google-cloud-core==2.5.0
# via google-cloud-storage
google-cloud-storage==2.14.0
# via
# -r requirements.in
# django-storages
google-crc32c==1.8.0
# via
# google-cloud-storage
# google-resumable-media
google-resumable-media==2.8.0
# via google-cloud-storage
googleapis-common-protos==1.72.0
# via google-api-core
hyperlink==21.0.0
# via
# autobahn
# twisted
idna==3.11
# via
# hyperlink
# requests
# twisted
incremental==24.11.0
# via twisted
inflection==0.5.1
# via drf-spectacular
isodate==0.7.2
# via azure-storage-blob
jmespath==1.1.0
# via
# boto3
# botocore
jsonschema==4.26.0
# via drf-spectacular
jsonschema-specifications==2025.9.1
# via jsonschema
more-itertools==8.2.0
# via -r requirements.in
msgpack==1.1.2
# via autobahn
ntplib==0.3.4
# via -r requirements.in
packaging==26.0
# via incremental
paramiko==3.4.0
# via
# -r requirements.in
# django-storages
pillow==12.1.1
# via -r requirements.in
proto-plus==1.27.0
# via google-api-core
protobuf==6.33.5
# via
# google-api-core
# googleapis-common-protos
# proto-plus
psycopg[binary]==3.3.2
# via -r requirements.in
psycopg-binary==3.3.2
# via psycopg
py-ubjson==0.16.1
# via autobahn
pyasn1==0.6.3
# via
# pyasn1-modules
# rsa
# service-identity
pyasn1-modules==0.4.2
# via
# google-auth
# service-identity
pycparser==3.0
# via cffi
pycryptodomex==3.19.1
# via -r requirements.in
pynacl==1.6.2
# via
# -r requirements.in
# paramiko
pyopenssl==26.0.0
# via
# twisted
# webauthn
pyotp==2.3.0
# via -r requirements.in
python-dateutil==2.8.0
# via
# -r requirements.in
# botocore
pyyaml==6.0.1
# via
# -r requirements.in
# drf-spectacular
redis==7.1.0
# via django-redis
referencing==0.37.0
# via
# jsonschema
# jsonschema-specifications
requests==2.33.0
# via
# -r requirements.in
# apache-libcloud
# azure-core
# django-anymail
# google-api-core
# google-cloud-storage
# yubico-client
rpds-py==0.30.0
# via
# jsonschema
# referencing
rsa==4.9.1
# via google-auth
s3transfer==0.10.4
# via boto3
scrypt==0.8.27
# via -r requirements.in
sentry-sdk[django]==2.48.0
# via -r requirements.in
service-identity==24.2.0
# via twisted
six==1.17.0
# via python-dateutil
sqlparse==0.5.5
# via django
toml==0.10.2
# via -r requirements.in
twisted[tls]==25.5.0
# via daphne
txaio==25.12.2
# via autobahn
typing-extensions==4.15.0
# via
# azure-core
# azure-storage-blob
# dj-database-url
# django-countries
# twisted
tzdata==2025.3
# via -r requirements.in
ujson==5.12.0
# via autobahn
uritemplate==4.2.0
# via drf-spectacular
urllib3==2.6.3
# via
# botocore
# django-anymail
# requests
# sentry-sdk
webauthn==2.7.0
# via -r requirements.in
yubico-client==1.12.0
# via -r requirements.in
zope-interface==8.2
# via twisted
# The following packages are considered to be unsafe in a requirements file:
# setuptoolsAs you can see it's quite extensive and a lot of these Arch doesn't have. I thereby shelved this project but am still confused on why it's not ok and another package on the AUR installs a venv via a ExecStartPre entry in a systemd service and after installing it, starts the software using the venv to do it.
Edit: thank you both Lone_Wolf and twelveeighty, you helped me a lot and I have learned much from this, the dlagent, packaging python virtual environments, sysusers files, down the line I even hardened the systemd service files. I appreciate all your help. Thanks again ![]()
Last edited by 7thCore (2026-03-27 16:45:33)
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline
I did not see the thread on the AUR ML, so if this was discussed at length, let me know and I'll venture into the archives to look myself.
Re: downloading from Docker - was it made clear that you verify the binary download against the hash that's in the PKGBUILD? Or, if the actual source (Docker) was the issue, then you *could* take the approach of documenting how the user extracts those image layers manually before running makepkg, similar to how binary files are handled for products that require a (paid) license. There's ample instances of that in the AUR today.
Offline
It was a somewhat short discussion. The title is: AUR package with python venv
The docker part was explained in the first mail sent to the mailing list, that it downloads, compresses it in a tarball with the same mtime and checks the hash againts the one available in the PKGBUILD.
I also provided a tarball with the source for them to test building.
The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.
Offline