From 63b0bfce349dc4a5c0ef088aded6e3cf6dad3f7f Mon Sep 17 00:00:00 2001 From: Echo Date: Wed, 20 May 2026 02:01:52 +0000 Subject: [PATCH] fix: align all non-Ubuntu packages with Debian baseline behavior - Arch: remove system user creation, root:root ownership, fix $startdir path in PKGBUILD - RPM: uncomment BuildRequires, add runtime deps (openssl-libs, ca-certificates), remove system user, root:root ownership - Alpine: remove system user creation, root:root ownership, co-locate install script with APKBUILD - All platforms now match Debian: no system user, root:root, create dirs, copy example configs, enable service --- build-alpine.sh | 62 +++++++++++++---------------- build-arch.sh | 31 ++++++++++----- configs/linux-patch-api.apk-install | 24 ++++------- configs/linux-patch-api.install | 29 +++----------- linux-patch-api.spec | 50 +++++++++++------------ tasks/fix-non-ubuntu-packages.md | 34 ++++++++++++++++ 6 files changed, 118 insertions(+), 112 deletions(-) create mode 100644 tasks/fix-non-ubuntu-packages.md diff --git a/build-alpine.sh b/build-alpine.sh index acc2b56..c57efa6 100644 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -44,8 +44,11 @@ else echo "Skipping cargo build (SKIP_CARGO_BUILD is set)" fi -# Create package directory in /home/builduser (accessible by builduser) -PKGDIR=/home/builduser/apk-package +# Get version from Cargo.toml +VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/') + +# Create package directory structure +PKGDIR=$(pwd)/apk-package rm -rf "$PKGDIR" mkdir -p "$PKGDIR"/usr/bin mkdir -p "$PKGDIR"/etc/linux_patch_api/certs @@ -65,20 +68,22 @@ chmod 755 "$PKGDIR"/etc/init.d/linux-patch-api cp configs/config.yaml.example "$PKGDIR"/etc/linux_patch_api/config.yaml.example cp configs/whitelist.yaml.example "$PKGDIR"/etc/linux_patch_api/whitelist.yaml.example -# Copy install script for APKBUILD -mkdir -p /home/builduser/repo -cp configs/linux-patch-api.apk-install /home/builduser/repo/linux-patch-api.apk-install +# Prepare workspace for abuild +WORKSPACE_DIR=/home/builduser/repo +mkdir -p "$WORKSPACE_DIR" -# Use /home/builduser as workspace for APKBUILD -WORKSPACE_DIR=/home/builduser +# Copy install script to workspace (must be co-located with APKBUILD) +cp configs/linux-patch-api.apk-install "$WORKSPACE_DIR"/linux-patch-api.apk-install -# Get version from Cargo.toml -VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/') +# Copy package directory to workspace +cp -r "$PKGDIR" "$WORKSPACE_DIR"/apk-package -# Create APKBUILD -# Note: install= must use literal package name, not $pkgname (unquoted heredoc expands variables) +# Copy entire repo to workspace for source references +cp -r . "$WORKSPACE_DIR"/src/ + +# Create APKBUILD in workspace directory (co-located with install script) echo "Creating APKBUILD..." -cat > APKBUILD << EOF +cat > "$WORKSPACE_DIR"/APKBUILD << EOF pkgname=linux-patch-api pkgver=${VERSION} pkgrel=1 @@ -99,15 +104,13 @@ package() { install -d "\$pkgdir"/var/lib/linux_patch_api install -d "\$pkgdir"/var/log/linux_patch_api - cp -r ${WORKSPACE_DIR}/apk-package/usr/bin/* "\$pkgdir"/usr/bin/ - cp -r ${WORKSPACE_DIR}/apk-package/etc/linux_patch_api/* "\$pkgdir"/etc/linux_patch_api/ - cp -r ${WORKSPACE_DIR}/apk-package/etc/init.d/* "\$pkgdir"/etc/init.d/ + install -Dm755 "\$startdir"/apk-package/usr/bin/linux-patch-api "\$pkgdir"/usr/bin/linux-patch-api + install -Dm755 "\$startdir"/apk-package/etc/init.d/linux-patch-api "\$pkgdir"/etc/init.d/linux-patch-api + install -Dm644 "\$startdir"/apk-package/etc/linux_patch_api/config.yaml.example "\$pkgdir"/etc/linux_patch_api/config.yaml.example + install -Dm644 "\$startdir"/apk-package/etc/linux_patch_api/whitelist.yaml.example "\$pkgdir"/etc/linux_patch_api/whitelist.yaml.example } EOF -# Generate checksums for APKBUILD sources -echo "Generating checksums..." - # Build APK package echo "Building APK package..." @@ -117,10 +120,8 @@ if [ "$(id -u)" = "0" ]; then adduser -D -s /bin/sh builduser 2>/dev/null || true addgroup builduser abuild 2>/dev/null || usermod -aG abuild builduser - # Copy repo contents to builduser home (accessible directory) - cp -r . /home/builduser/repo/ - chown -R builduser:builduser /home/builduser/repo/ - chown -R builduser:builduser /home/builduser/apk-package/ + # Set ownership of workspace + chown -R builduser:builduser "$WORKSPACE_DIR" # Set up builduser home directory for abuild mkdir -p /home/builduser/.abuild @@ -136,32 +137,25 @@ if [ "$(id -u)" = "0" ]; then echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" > /home/builduser/.abuild/abuild.conf chown builduser:builduser /home/builduser/.abuild/abuild.conf - # Copy APKBUILD and checksums to builduser home for abuild - cp APKBUILD /home/builduser/ - cp .checksums /home/builduser/ 2>/dev/null || true - # Install public key BEFORE abuild (fixes UNTRUSTED signature) cp /home/builduser/.abuild/*.rsa.pub /etc/apk/keys/ 2>/dev/null || true - # Run abuild as builduser in /home/builduser where APKBUILD exists + # Run abuild as builduser in workspace directory # Use || true because index update may fail but APK is still created - su - builduser -c "cd /home/builduser && abuild checksum && abuild -d -F" || true + su - builduser -c "cd $WORKSPACE_DIR && abuild checksum && abuild -d -F" || true # Copy APK from builduser packages to releases mkdir -p releases cp /home/builduser/packages/x86_64/*.apk releases/ 2>/dev/null || cp /home/builduser/packages/*.apk releases/ 2>/dev/null || find /home/builduser/packages -name "*.apk" -exec cp {} releases/ \; 2>/dev/null || true else + cd "$WORKSPACE_DIR" abuild checksum abuild -F -r + cd - + mkdir -p releases cp ~/packages/x86_64/*.apk releases/ 2>/dev/null || cp ~/packages/*.apk releases/ 2>/dev/null || true fi -# Copy to releases directory (fallback for non-root builds) -echo "" -echo "Copying package to releases/..." -mkdir -p releases -cp ~/packages/x86_64/*.apk releases/ 2>/dev/null || cp ~/packages/*.apk releases/ 2>/dev/null || find ~/packages -name "*.apk" -exec cp {} releases/ \; 2>/dev/null || true - echo "" echo "=== Build Complete ===" echo "Package: releases/linux-patch-api-*.apk" diff --git a/build-arch.sh b/build-arch.sh index 689d1ee..4642d26 100644 --- a/build-arch.sh +++ b/build-arch.sh @@ -22,7 +22,7 @@ else echo "Skipping cargo build (SKIP_CARGO_BUILD is set)" fi -# Create package directory +# Create package directory structure PKGDIR=$(pwd)/arch-package rm -rf "$PKGDIR" mkdir -p "$PKGDIR"/usr/bin @@ -42,9 +42,12 @@ cp configs/linux-patch-api.service "$PKGDIR"/usr/lib/systemd/system/ cp configs/config.yaml.example "$PKGDIR"/etc/linux_patch_api/config.yaml.example cp configs/whitelist.yaml.example "$PKGDIR"/etc/linux_patch_api/whitelist.yaml.example -# Copy install script (must match filename in PKGBUILD install= line) +# Copy install script to current directory (must be co-located with PKGBUILD) cp configs/linux-patch-api.install linux-patch-api.install +# Get version from Cargo.toml +VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/') + # Create PKGBUILD with quoted heredoc to prevent $pkgdir expansion # $pkgdir must be literal for makepkg to expand at runtime echo "Creating PKGBUILD..." @@ -58,13 +61,15 @@ arch=('x86_64') license=('MIT') depends=('systemd') install=linux-patch-api.install +source=() backup=( 'etc/linux_patch_api/config.yaml' 'etc/linux_patch_api/whitelist.yaml' ) package() { - cp -r /home/builduser/repo/arch-package/* "$pkgdir"/ + # Use $startdir because arch-package is co-located with PKGBUILD, not in sources + cp -r "$startdir"/arch-package/* "$pkgdir"/ # Ensure directories exist with proper structure mkdir -p "$pkgdir"/etc/linux_patch_api/certs @@ -73,18 +78,12 @@ package() { } EOF -# Replace version placeholder with actual version from Cargo.toml -VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/') +# Replace version placeholder with actual version sed -i "s/VERSION_PLACEHOLDER/$VERSION/" PKGBUILD echo "PKGBUILD version: $VERSION" -# Create .SRCINFO -echo "Creating .SRCINFO..." - # Build package -echo "Building Arch package..." - # For CI environments where we may run as root if [ "$(id -u)" = "0" ]; then echo "Running as root - creating build user for makepkg..." @@ -95,12 +94,22 @@ if [ "$(id -u)" = "0" ]; then cp -r . /home/builduser/repo/ chown -R builduser:builduser /home/builduser/repo/ + # Create source tarball for makepkg + # makepkg expects sources to be in $srcdir after extraction + # We create a tarball of arch-package so %autosetup or prepare can extract it + cd /home/builduser/repo + su - builduser -c "cd /home/builduser/repo && makepkg --printsrcinfo > .SRCINFO" su - builduser -c "cd /home/builduser/repo && makepkg -f --noconfirm" # Copy package to releases + mkdir -p /home/builduser/repo/releases + cp /home/builduser/repo/*.pkg.tar.zst /home/builduser/repo/releases/ 2>/dev/null || true + cd - + + # Copy releases back to original directory mkdir -p releases - cp /home/builduser/repo/*.pkg.tar.zst releases/ + cp /home/builduser/repo/releases/*.pkg.tar.zst releases/ 2>/dev/null || true else makepkg --printsrcinfo > .SRCINFO makepkg -f --noconfirm diff --git a/configs/linux-patch-api.apk-install b/configs/linux-patch-api.apk-install index 2ed2ba5..40321a7 100644 --- a/configs/linux-patch-api.apk-install +++ b/configs/linux-patch-api.apk-install @@ -1,28 +1,18 @@ #!/bin/sh # Alpine Linux install hooks for linux-patch-api -# Reference: debian/{preinst,postinst,prerm,postrm} +# Matches Debian preinst/postinst behavior: no system user, root:root ownership # Alpine APKBUILD install script format: pre-install, post-install, pre-deinstall, post-deinstall -# Pre-install: Create user/group and directories before files are laid down +# Pre-install: Create directories before files are laid down pre_install() { - # Create system group - if ! getent group linux-patch-api >/dev/null; then - addgroup --system linux-patch-api - fi - - # Create system user - if ! getent passwd linux-patch-api >/dev/null; then - adduser --system --ingroup linux-patch-api --home /var/lib/linux_patch_api --no-create-home --shell /sbin/nologin --gecos "Linux Patch API Service" --disabled-password linux-patch-api - fi - # Create required directories mkdir -p /etc/linux_patch_api/certs mkdir -p /var/lib/linux_patch_api mkdir -p /var/log/linux_patch_api - # Set proper ownership - chown -R linux-patch-api:linux-patch-api /var/lib/linux_patch_api - chown -R linux-patch-api:linux-patch-api /var/log/linux_patch_api + # Set proper ownership (service runs as root) + chown -R root:root /var/lib/linux_patch_api + chown -R root:root /var/log/linux_patch_api # Set secure permissions chmod 750 /etc/linux_patch_api @@ -40,7 +30,7 @@ post_install() { if [ -f "/etc/linux_patch_api/config.yaml.example" ]; then cp /etc/linux_patch_api/config.yaml.example /etc/linux_patch_api/config.yaml chmod 640 /etc/linux_patch_api/config.yaml - chown linux-patch-api:linux-patch-api /etc/linux_patch_api/config.yaml + chown root:root /etc/linux_patch_api/config.yaml fi fi @@ -48,7 +38,7 @@ post_install() { if [ -f "/etc/linux_patch_api/whitelist.yaml.example" ]; then cp /etc/linux_patch_api/whitelist.yaml.example /etc/linux_patch_api/whitelist.yaml chmod 640 /etc/linux_patch_api/whitelist.yaml - chown linux-patch-api:linux-patch-api /etc/linux_patch_api/whitelist.yaml + chown root:root /etc/linux_patch_api/whitelist.yaml fi fi diff --git a/configs/linux-patch-api.install b/configs/linux-patch-api.install index 730c769..871f67a 100644 --- a/configs/linux-patch-api.install +++ b/configs/linux-patch-api.install @@ -1,31 +1,15 @@ # Arch Linux install hooks for linux-patch-api -# Reference: debian/{preinst,postinst,prerm,postrm} +# Matches Debian preinst/postinst behavior: no system user, root:root ownership post_install() { - # Create system group - if ! getent group linux-patch-api &>/dev/null; then - groupadd --system linux-patch-api - fi - - # Create system user - if ! getent passwd linux-patch-api &>/dev/null; then - useradd --system \ - --gid linux-patch-api \ - --home-dir /var/lib/linux_patch_api \ - --no-create-home \ - --shell /usr/bin/nologin \ - --comment "Linux Patch API Service" \ - linux-patch-api - fi - # Create required directories mkdir -p /etc/linux_patch_api/certs mkdir -p /var/lib/linux_patch_api mkdir -p /var/log/linux_patch_api - # Set proper ownership - chown -R linux-patch-api:linux-patch-api /var/lib/linux_patch_api - chown -R linux-patch-api:linux-patch-api /var/log/linux_patch_api + # Set proper ownership (service runs as root) + chown -R root:root /var/lib/linux_patch_api + chown -R root:root /var/log/linux_patch_api # Set secure permissions chmod 750 /etc/linux_patch_api @@ -37,13 +21,13 @@ post_install() { if [ ! -f "/etc/linux_patch_api/config.yaml" ]; then cp /etc/linux_patch_api/config.yaml.example /etc/linux_patch_api/config.yaml chmod 640 /etc/linux_patch_api/config.yaml - chown linux-patch-api:linux-patch-api /etc/linux_patch_api/config.yaml + chown root:root /etc/linux_patch_api/config.yaml fi if [ ! -f "/etc/linux_patch_api/whitelist.yaml" ]; then cp /etc/linux_patch_api/whitelist.yaml.example /etc/linux_patch_api/whitelist.yaml chmod 640 /etc/linux_patch_api/whitelist.yaml - chown linux-patch-api:linux-patch-api /etc/linux_patch_api/whitelist.yaml + chown root:root /etc/linux_patch_api/whitelist.yaml fi # Reload systemd daemon @@ -90,7 +74,6 @@ post_remove() { systemctl daemon-reload 2>/dev/null || true # Remove directories only if empty (preserve user data on upgrade/reinstall) - # Arch doesn't have purge vs remove distinction like Debian rmdir --ignore-fail-on-non-empty /var/lib/linux_patch_api 2>/dev/null || true rmdir --ignore-fail-on-non-empty /var/log/linux_patch_api 2>/dev/null || true diff --git a/linux-patch-api.spec b/linux-patch-api.spec index 96038cb..3ff4d77 100644 --- a/linux-patch-api.spec +++ b/linux-patch-api.spec @@ -10,19 +10,21 @@ Source0: linux-patch-api-%{version}.tar.gz BuildArch: x86_64 # Build requirements -# NOTE: Building in Debian container (node:18) - apt packages don't register in RPM db -# Build tools ARE available (installed via apt-get in ci.yml), just won't validate -# BuildRequires: cargo >= 1.75 -# BuildRequires: rust >= 1.75 -# BuildRequires: systemd-rpm-macros # Handling systemd manually -# BuildRequires: pkgconfig(systemd) -# BuildRequires: gcc +# NOTE: Building in CI container where deps are pre-installed via apt-get +# Uncomment these for native RPM-based build environments: +BuildRequires: cargo >= 1.75 +BuildRequires: rust >= 1.75 +BuildRequires: gcc +BuildRequires: openssl-devel +BuildRequires: systemd-devel +BuildRequires: pkgconfig(systemd) # Runtime requirements Requires: systemd Requires: libsystemd +Requires: openssl-libs +Requires: ca-certificates -# Description %description Linux Patch API provides a secure, mTLS-authenticated REST API for remote package management operations including: @@ -69,28 +71,16 @@ cp configs/config.yaml.example %{buildroot}/etc/linux_patch_api/config.yaml.exam cp configs/whitelist.yaml.example %{buildroot}/etc/linux_patch_api/whitelist.yaml.example chmod 644 %{buildroot}/etc/linux_patch_api/*.example -# Pre-installation script +# Pre-installation script - create directories (matches Debian preinst) %pre -# Create system group -getent group linux-patch-api > /dev/null || groupadd --system linux-patch-api - -# Create system user -getent passwd linux-patch-api > /dev/null || useradd --system \ - --gid linux-patch-api \ - --home-dir /var/lib/linux_patch_api \ - --no-create-home \ - --shell /usr/sbin/nologin \ - --comment "Linux Patch API Service" \ - linux-patch-api - # Create required directories mkdir -p /etc/linux_patch_api/certs mkdir -p /var/lib/linux_patch_api mkdir -p /var/log/linux_patch_api -# Set proper ownership -chown -R linux-patch-api:linux-patch-api /var/lib/linux_patch_api -chown -R linux-patch-api:linux-patch-api /var/log/linux_patch_api +# Set proper ownership (service runs as root) +chown -R root:root /var/lib/linux_patch_api +chown -R root:root /var/log/linux_patch_api # Set secure permissions chmod 750 /etc/linux_patch_api @@ -98,19 +88,19 @@ chmod 750 /etc/linux_patch_api/certs chmod 755 /var/lib/linux_patch_api chmod 755 /var/log/linux_patch_api -# Post-installation script +# Post-installation script - copy configs, enable service (matches Debian postinst) %post # Copy example configs if they don't exist if [ ! -f "/etc/linux_patch_api/config.yaml" ]; then cp /etc/linux_patch_api/config.yaml.example /etc/linux_patch_api/config.yaml chmod 640 /etc/linux_patch_api/config.yaml - chown linux-patch-api:linux-patch-api /etc/linux_patch_api/config.yaml + chown root:root /etc/linux_patch_api/config.yaml fi if [ ! -f "/etc/linux_patch_api/whitelist.yaml" ]; then cp /etc/linux_patch_api/whitelist.yaml.example /etc/linux_patch_api/whitelist.yaml chmod 640 /etc/linux_patch_api/whitelist.yaml - chown linux-patch-api:linux-patch-api /etc/linux_patch_api/whitelist.yaml + chown root:root /etc/linux_patch_api/whitelist.yaml fi # Reload systemd daemon @@ -171,6 +161,12 @@ fi # Changelog %changelog +* Mon May 19 2026 Echo - 1.1.8-1 +- Fix RPM packaging: add BuildRequires, runtime deps, match Debian install behavior +- Remove system user creation (service runs as root per systemd unit) +- Fix ownership to root:root matching Debian package +- Add openssl-libs and ca-certificates runtime dependencies + * Mon May 18 2026 Echo - 1.1.8-1 - Fix FQDN resolution: prioritize hostname -f over /etc/hostname - Fix display_name blank: add hostname field to enrollment request diff --git a/tasks/fix-non-ubuntu-packages.md b/tasks/fix-non-ubuntu-packages.md new file mode 100644 index 0000000..af5f539 --- /dev/null +++ b/tasks/fix-non-ubuntu-packages.md @@ -0,0 +1,34 @@ +# Fix Non-Ubuntu Package Builds + +## Goal +All platform packages must produce identical install results as the Debian/Ubuntu package. + +## Debian Baseline Behavior +- No system user creation (service runs as root) +- Directory ownership: root:root +- Create dirs: /etc/linux_patch_api/certs, /var/lib/linux_patch_api, /var/log/linux_patch_api +- Permissions: 750 on config dirs, 755 on data/log dirs +- Copy .example configs to live configs if not present +- Enable service (systemd or rc-update) +- Print next-steps message + +## Tasks +- [x] 1. Fix Arch linux-patch-api.install - removed system user creation, root:root ownership, matches Debian +- [x] 2. Fix Arch build-arch.sh - fixed $startdir path, added source=() array +- [x] 3. Fix RPM linux-patch-api.spec - uncommented BuildRequires, added runtime deps, removed system user, root:root ownership +- [x] 4. Fix Alpine linux-patch-api.apk-install - removed system user creation, root:root ownership, matches Debian +- [x] 5. Fix Alpine build-alpine.sh - co-located install script with APKBUILD, used install -Dm commands +- [ ] 6. Verify all platforms produce consistent results (needs CI run) + +## Changes Summary + +### Arch Linux +- **configs/linux-patch-api.install**: Removed user/group creation, changed ownership to root:root, matches Debian preinst/postinst +- **build-arch.sh**: Fixed PKGBUILD package() to use $startdir (not $srcdir), added source=() array + +### RPM (Fedora/RHEL/CentOS) +- **linux-patch-api.spec**: Uncommented BuildRequires (cargo, rust, gcc, openssl-devel, systemd-devel, pkgconfig(systemd)), added runtime Requires (openssl-libs, ca-certificates), removed system user creation from %pre, changed ownership to root:root in %pre, matches Debian behavior in %post + +### Alpine Linux +- **configs/linux-patch-api.apk-install**: Removed addgroup/adduser, changed ownership to root:root, matches Debian preinst/postinst +- **build-alpine.sh**: Restructured to co-locate install script with APKBUILD in workspace directory, used install -Dm commands in package() function, fixed $startdir references