From 97565989bb84c5f6f5f208625ef1acab8fd1e1dd Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 14:14:44 +0000 Subject: [PATCH 01/54] Fix: Use node:18-bookworm container for build-deb job to support JavaScript actions --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9561e87..57595f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,7 +89,7 @@ jobs: build-deb: name: Build Debian Package runs-on: linux - container: debian:bookworm + container: node:18-bookworm steps: - uses: actions/checkout@v4 with: From 7175058d2672d73a14c2df2b84acbe166e5e7aa3 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 14:23:10 +0000 Subject: [PATCH 02/54] Fix: Use node:18 container for build-rpm job to support JavaScript actions --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57595f2..5fc7ef2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: build-rpm: name: Build RPM Package runs-on: linux - container: fedora:latest + container: node:18 steps: - uses: actions/checkout@v4 with: @@ -121,7 +121,8 @@ jobs: - uses: dtolnay/rust-toolchain@stable - name: Install RPM build tools run: | - dnf install -y rpm-build gcc cargo rust libsystemd-devel pkgconfig-pkg-config + apt-get update + apt-get install -y rpm rpm-common rpmbuild gcc cargo rust libsystemd-dev pkg-config - name: Build release binary run: cargo build --release - name: Build RPM package From 544df9483dfd112a024ff8a8a6b052378879d9dc Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 14:38:14 +0000 Subject: [PATCH 03/54] Fix: Use custom Fedora+Node container for build-rpm job --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5fc7ef2..3f9b08b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: build-rpm: name: Build RPM Package runs-on: linux - container: node:18 + container: linux-patch-api-rpm:latest steps: - uses: actions/checkout@v4 with: @@ -121,8 +121,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable - name: Install RPM build tools run: | - apt-get update - apt-get install -y rpm rpm-common rpmbuild gcc cargo rust libsystemd-dev pkg-config + dnf install -y rpm-build gcc cargo rust libsystemd-devel pkg-config - name: Build release binary run: cargo build --release - name: Build RPM package From 89fbf19c4cda600fcfa787f53e0b92288f778d61 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 14:43:36 +0000 Subject: [PATCH 04/54] Fix: Use systemd-devel package name for Fedora 43 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f9b08b..d6aea02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,7 +121,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable - name: Install RPM build tools run: | - dnf install -y rpm-build gcc cargo rust libsystemd-devel pkg-config + dnf install -y rpm-build gcc cargo rust systemd-devel pkg-config - name: Build release binary run: cargo build --release - name: Build RPM package From bb0f73e824dfd9f8b6259eae458a4cd23534d76c Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 15:13:49 +0000 Subject: [PATCH 05/54] Fix: Disable debug package generation to fix empty debugsourcefiles.list error --- linux-patch-api.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-patch-api.spec b/linux-patch-api.spec index 3c4c1e8..691bfa4 100644 --- a/linux-patch-api.spec +++ b/linux-patch-api.spec @@ -1,3 +1,5 @@ +%global debug_package %{nil} + Name: linux-patch-api Version: 1.0.0 Release: 1%{?dist} From 8107dc05477f9d345140cbb5f2db8035dbdfd6bb Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 15:24:17 +0000 Subject: [PATCH 06/54] Fix: Use node:18-alpine container for build-apk job to support JavaScript actions --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6aea02..315710c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,7 +136,7 @@ jobs: build-apk: name: Build Alpine Package runs-on: linux - container: alpine:latest + container: node:18-alpine steps: - uses: actions/checkout@v4 with: From fd1e032e599ed8622391b38ca742f9d068a39dbf Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 15:37:46 +0000 Subject: [PATCH 07/54] Fix: Use custom Arch+Node container for build-arch job --- .github/workflows/ci.yml | 5 ++--- Dockerfile.arch | 13 +++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 Dockerfile.arch diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 315710c..94408c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,9 +141,8 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Install build dependencies run: | - apk add --no-cache rust cargo musl-dev openssl-dev systemd-dev git abuild + apk add --no-cache rust cargo musl-dev openssl-dev git abuild - name: Build APK package run: ./build-alpine.sh - name: Upload to releases (on tag) @@ -156,7 +155,7 @@ jobs: build-arch: name: Build Arch Package runs-on: linux - container: archlinux:latest + container: linux-patch-api-arch:latest steps: - uses: actions/checkout@v4 with: diff --git a/Dockerfile.arch b/Dockerfile.arch new file mode 100644 index 0000000..9b2419b --- /dev/null +++ b/Dockerfile.arch @@ -0,0 +1,13 @@ +# Arch Linux container with Node.js for GitHub Actions support +# Used for Arch package builds in CI/CD +FROM archlinux:latest + +# Update system and install Node.js (required for GitHub Actions JavaScript-based actions) +RUN pacman -Syu --noconfirm nodejs npm && \ + pacman -Scc --noconfirm + +# Verify node is available +RUN node --version + +# Default command (not used in CI, but good for testing) +CMD ["/bin/bash"] From 2d835559d6ca458044f0b6eedf530b7fe638a5e2 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 15:52:57 +0000 Subject: [PATCH 08/54] Fix: Add --allow-root flag to makepkg for CI container builds --- build-arch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 build-arch.sh diff --git a/build-arch.sh b/build-arch.sh old mode 100755 new mode 100644 index b2e2b95..86b6f65 --- a/build-arch.sh +++ b/build-arch.sh @@ -60,7 +60,7 @@ makepkg --printsrcinfo > .SRCINFO # Build package echo "Building Arch package..." -makepkg -f --noconfirm +makepkg -f --noconfirm --allow-root # Copy to releases directory echo "" From 2c5f1cd1f80a06ae6b152c3de5c00a2b4137e3a8 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 16:41:36 +0000 Subject: [PATCH 09/54] Fix: Restore execute permission on build-arch.sh --- build-arch.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-arch.sh diff --git a/build-arch.sh b/build-arch.sh old mode 100644 new mode 100755 From cc95dcfd89cf340d4e472f264e7187d355e1dcb6 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 17:06:47 +0000 Subject: [PATCH 10/54] Fix: Add --allow-root to makepkg --printsrcinfo for CI container builds --- build-arch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 build-arch.sh diff --git a/build-arch.sh b/build-arch.sh old mode 100755 new mode 100644 index 86b6f65..94761db --- a/build-arch.sh +++ b/build-arch.sh @@ -56,7 +56,7 @@ EOF # Create .SRCINFO echo "Creating .SRCINFO..." -makepkg --printsrcinfo > .SRCINFO +makepkg --printsrcinfo --allow-root > .SRCINFO # Build package echo "Building Arch package..." From 0a98207edc65b4508f949d1b20c4e5e09ce2d01f Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 17:19:51 +0000 Subject: [PATCH 11/54] Fix: Restore execute permission on build-arch.sh (2nd time) --- build-arch.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-arch.sh diff --git a/build-arch.sh b/build-arch.sh old mode 100644 new mode 100755 From 2dbd6ee1650197ab01bd5b020216acc8eee46c1b Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 18:02:04 +0000 Subject: [PATCH 12/54] Fix: Use non-root builduser for makepkg in CI container --- build-arch.sh | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/build-arch.sh b/build-arch.sh index 94761db..f00255c 100755 --- a/build-arch.sh +++ b/build-arch.sh @@ -43,7 +43,7 @@ pkgname=linux-patch-api pkgver=1.0.0 pkgrel=1 pkgdesc="Secure remote package management API for Linux systems" -url="https://gitea.internal/linux-patch-api" +url="https://gitea.moon-dragon.us/echo/linux_patch_api" arch=('x86_64') license=('MIT') depends=('systemd') @@ -56,11 +56,21 @@ EOF # Create .SRCINFO echo "Creating .SRCINFO..." -makepkg --printsrcinfo --allow-root > .SRCINFO # Build package echo "Building Arch package..." -makepkg -f --noconfirm --allow-root + +# For CI/container environments where we run as root, create a build user +if [ "$(id -u)" = "0" ]; then + echo "Running as root - creating build user for makepkg..." + useradd -m builduser 2>/dev/null || true + chown -R builduser:builduser "$(pwd)" + su - builduser -c "cd $(pwd) && makepkg --printsrcinfo > .SRCINFO" + su - builduser -c "cd $(pwd) && makepkg -f --noconfirm" +else + makepkg --printsrcinfo > .SRCINFO + makepkg -f --noconfirm +fi # Copy to releases directory echo "" From 4a5885088907130daab521b0a4f1ca73d49a27e0 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 18:20:52 +0000 Subject: [PATCH 13/54] Fix: Use $(pwd)/arch-package path in PKGBUILD package() function --- build-arch.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-arch.sh b/build-arch.sh index f00255c..e33d9cd 100755 --- a/build-arch.sh +++ b/build-arch.sh @@ -47,10 +47,10 @@ url="https://gitea.moon-dragon.us/echo/linux_patch_api" arch=('x86_64') license=('MIT') depends=('systemd') -source=('arch-package') package() { - cp -r "$srcdir"/arch-package/* "$pkgdir"/ + # Copy from current working directory (not srcdir) + cp -r "$(pwd)"/arch-package/* "$pkgdir"/ } EOF From f81568adf38362062075f8c9c5e4ff1991b61163 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 19:37:28 +0000 Subject: [PATCH 14/54] Fix: Use absolute workspace path in PKGBUILD package() function --- build-arch.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-arch.sh b/build-arch.sh index e33d9cd..f4fca2c 100755 --- a/build-arch.sh +++ b/build-arch.sh @@ -49,8 +49,8 @@ license=('MIT') depends=('systemd') package() { - # Copy from current working directory (not srcdir) - cp -r "$(pwd)"/arch-package/* "$pkgdir"/ + # Use absolute path since makepkg changes working directory to srcdir + cp -r /workspace/echo/linux_patch_api/arch-package/* "$pkgdir"/ } EOF From 78f88826634881f205f67d1b5e3a34971b21bcea Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 20:16:10 +0000 Subject: [PATCH 15/54] Add Alpine/OpenRC compatibility for init system support - Updated SPEC.md: Changed systemd requirements to distribution-dependent init system - Updated ARCHITECTURE.md: Added OpenRC hardening options and init script locations - Updated build-alpine.sh: Replaced systemd-dev with openrc, use /etc/init.d - Created configs/linux-patch-api-openrc: Full OpenRC init script - Added Dockerfile.rpm for RPM build container Init system support: - systemd: Debian, Ubuntu, RHEL, CentOS, Fedora - OpenRC: Alpine Linux Binary remains init-system agnostic - no Rust code changes required. --- ARCHITECTURE.md | 46 ++++++++++++++-------- Dockerfile.rpm | 14 +++++++ SPEC.md | 18 ++++++--- build-alpine.sh | 10 ++--- configs/linux-patch-api-openrc | 72 ++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 27 deletions(-) create mode 100644 Dockerfile.rpm mode change 100755 => 100644 build-alpine.sh create mode 100644 configs/linux-patch-api-openrc diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 8d19acf..247795e 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,7 +2,7 @@ ## System Overview -The Linux_Patch_API is a secure, single-host API service that enables remote package and patch management on Linux systems. Each instance runs as a systemd service on the managed host, providing a REST API over mTLS with strict IP whitelist enforcement. +The Linux_Patch_API is a secure, single-host API service that enables remote package and patch management on Linux systems. Each instance runs as a system service on the managed host (systemd on most distributions, OpenRC on Alpine), providing a REST API over mTLS with strict IP whitelist enforcement. **Architecture Type:** Agent Per Host (Option B) **Deployment:** One instance per managed Linux host @@ -45,8 +45,9 @@ The Linux_Patch_API is a secure, single-host API service that enables remote pac - Distribution detection and adapter selection 6. **Audit Logger** - - systemd journal integration (primary) - - Optional remote syslog server + - System logging integration (primary) + - systemd journal on systemd-based systems + - syslog/local files on OpenRC-based systems - Local file fallback (`/var/log/linux_patch_api/`) - 30-day retention with daily rotation and gzip compression @@ -59,9 +60,10 @@ The Linux_Patch_API is a secure, single-host API service that enables remote pac ### External Integrations - **Package Managers:** apt, dnf, yum, apk, pacman (via system commands) -- **systemd:** Service management and journal logging +- **Init System:** Service management and logging + - systemd (Debian, Ubuntu, RHEL, CentOS, Fedora) + - OpenRC (Alpine Linux) - **Internal CA:** Certificate validation against self-hosted CA -- **Remote Syslog:** Optional external log aggregation --- @@ -74,14 +76,17 @@ The Linux_Patch_API is a secure, single-host API service that enables remote pac - **mTLS:** Rust TLS library (rustls or native-tls) ### Infrastructure -- **Service Manager:** systemd +- **Service Manager:** Distribution-dependent + - systemd (most distributions) + - OpenRC (Alpine Linux) - **Configuration:** YAML -- **Logging:** systemd journal + optional syslog ### Deployment - **Package Format:** Native Linux packages (deb, rpm, apk, pkg.tar.zst) - **Distribution:** Via target system package manager (apt, dnf, apk, pacman) -- **Installation:** Package installs binary, systemd service, and default config structure +- **Installation:** Package installs binary, init script/service, and default config structure + - systemd unit file for systemd distributions + - OpenRC init script for Alpine - **Updates:** Handled through system package manager --- @@ -99,16 +104,21 @@ The Linux_Patch_API is a secure, single-host API service that enables remote pac - No granular permissions (binary access: allowed or denied) - Whitelisted IP + valid cert = full API access -### Process Security (systemd Hardening) +### Process Security (Init System Hardening) - **User:** root (required for package management) -- **NoNewPrivileges:** true (prevent privilege escalation) -- **ProtectSystem:** strict (read-only filesystem except allowed paths) -- **ProtectHome:** true (no access to /home, /root, /run/user) -- **PrivateTmp:** true (isolated /tmp) -- **SystemCallFilter:** Restrict to required syscalls only (application whitelist) -- **RestrictAddressFamilies:** AF_INET, AF_INET6, AF_UNIX (network restrictions) -- **CapabilityBoundingSet:** CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN (minimal capabilities) +**systemd Hardening Options:** +- NoNewPrivileges: true (prevent privilege escalation) +- ProtectSystem: strict (read-only filesystem except allowed paths) +- ProtectHome: true (no access to /home, /root, /run/user) +- PrivateTmp: true (isolated /tmp) +- SystemCallFilter: Restrict to required syscalls only (application whitelist) + +**OpenRC Hardening Options:** +- Run as dedicated service user +- File permission restrictions +- chroot isolation (optional) +- Equivalent security via rc.conf and init script options ### Data Security - All communications encrypted via TLS - Certificates stored securely with restricted permissions @@ -149,7 +159,9 @@ The Linux_Patch_API is a secure, single-host API service that enables remote pac └── audit.log # Local audit log fallback /usr/bin/linux-patch-api # Binary location -/etc/systemd/system/linux-patch-api.service # Systemd service +Init scripts (distribution-dependent): +- /etc/systemd/system/linux-patch-api.service # systemd +- /etc/init.d/linux-patch-api # OpenRC (Alpine) ``` --- diff --git a/Dockerfile.rpm b/Dockerfile.rpm new file mode 100644 index 0000000..79d5c94 --- /dev/null +++ b/Dockerfile.rpm @@ -0,0 +1,14 @@ +# Fedora container with Node.js for GitHub Actions support +# Used for RPM package builds in CI/CD +FROM fedora:latest + +# Install Node.js (required for GitHub Actions JavaScript-based actions) +# Also install dnf-plugins-core for potential multiarch support +RUN dnf install -y nodejs dnf-plugins-core && \ + dnf clean all + +# Verify node is available +RUN node --version + +# Default command (not used in CI, but good for testing) +CMD ["/bin/bash"] diff --git a/SPEC.md b/SPEC.md index 955c526..f17e3b3 100644 --- a/SPEC.md +++ b/SPEC.md @@ -41,7 +41,9 @@ **Primary Objective:** Provide secure API for remote patch/package management on individual Linux hosts **Key Goals:** -- Run as systemd service on each managed machine (Option B: Agent Per Host) +- Run as a system service on each managed machine (Option B: Agent Per Host) + - systemd for Debian/Ubuntu, RHEL/CentOS/Fedora + - OpenRC for Alpine Linux - Internal network access only (no internet exposure) - Support Debian/Ubuntu first, then expand to other distributions - Maintain audit trail of all operations @@ -55,7 +57,9 @@ - One API instance per host - Internal network only (LAN/private network) - No public internet exposure -- Must run as systemd service +- Must run as a system service (init system determined by distribution) + - systemd: Debian, Ubuntu, RHEL, CentOS, Fedora + - OpenRC: Alpine Linux **Technical:** - Must run with elevated privileges for package management (root/sudo) @@ -119,7 +123,9 @@ ## Dependencies - Linux OS with package manager support -- systemd for service management +- Init system for service management (distribution-dependent) + - systemd (most distributions) + - OpenRC (Alpine Linux) - Network access for API communication - mTLS certificate infrastructure (CA, client certs) - IP whitelist configuration @@ -147,8 +153,10 @@ - Configuration changes (whitelist updates, cert renewals) - **Log Storage:** - - Primary: systemd journal (`journalctl`) - - Secondary: Optional remote syslog server + - Primary: Distribution-appropriate logging + - systemd journal (journalctl) on systemd systems + - syslog/local files on OpenRC systems + - Secondary: Optional remote syslog server (universal) - Local file logs as fallback (`/var/log/linux_patch_api/`) - **Log Retention:** diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index c04f4d0..539cdb3 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -11,7 +11,7 @@ echo "" # Check if running on Alpine if ! command -v abuild &> /dev/null; then echo "Installing Alpine build tools..." - apk add --no-cache alpine-sdk rust cargo openssl-dev systemd-dev git + apk add --no-cache alpine-sdk rust cargo openssl-dev openrc git fi # Setup build environment @@ -27,13 +27,13 @@ cargo build --release --target x86_64-unknown-linux-musl PKGDIR=$(pwd)/apk-package mkdir -p "$PKGDIR"/usr/bin mkdir -p "$PKGDIR"/etc/linux_patch_api -mkdir -p "$PKGDIR"/lib/systemd/system +mkdir -p "$PKGDIR"/etc/init.d # Copy files cp target/x86_64-unknown-linux-musl/release/linux-patch-api "$PKGDIR"/usr/bin/ chmod 755 "$PKGDIR"/usr/bin/linux-patch-api -cp configs/linux-patch-api.service "$PKGDIR"/lib/systemd/system/ -cp configs/config.yaml.example "$PKGDIR"/etc/linux_patch_api/config.yaml +cp configs/linux-patch-api-openrc "$PKGDIR"/etc/init.d/linux-patch-api +chmod 755 "$PKGDIR"/etc/init.d/linux-patch-api cp configs/whitelist.yaml.example "$PKGDIR"/etc/linux_patch_api/whitelist.yaml # Create APKBUILD @@ -46,7 +46,7 @@ pkgdesc="Secure remote package management API for Linux systems" url="https://gitea.internal/linux-patch-api" arch="x86_64" license="MIT" -depends="systemd" +depends="openrc" source="apk-package" package() { diff --git a/configs/linux-patch-api-openrc b/configs/linux-patch-api-openrc new file mode 100644 index 0000000..2aee4cf --- /dev/null +++ b/configs/linux-patch-api-openrc @@ -0,0 +1,72 @@ +#!/sbin/openrc-run +# OpenRC init script for linux-patch-api +# Used on Alpine Linux and other OpenRC-based systems + +name="linux_patch_api" +command="/usr/bin/linux-patch-api" +command_args="--config /etc/linux_patch_api/config.yaml" +command_background=true +pidfile="/run/linux-patch-api/linux-patch-api.pid" +output_log="/var/log/linux_patch_api/linux-patch-api.log" +error_log="/var/log/linux_patch_api/linux-patch-api.err" + +# Required dependencies +depend() { + use net logger +} + +# Create required directories before starting +start_pre() { + checkpath --directory --owner linux-patch-api:linux-patch-api --mode 0755 \ + /run/linux-patch-api \ + /var/log/linux-patch-api \ + /var/lib/linux-patch-api \ + /etc/linux_patch_api/certs + + # Ensure config files exist + if [ ! -f "/etc/linux_patch_api/config.yaml" ]; then + eerror "Configuration file missing: /etc/linux_patch_api/config.yaml" + eerror "Please create config.yaml before starting the service" + return 1 + fi + + if [ ! -f "/etc/linux_patch_api/whitelist.yaml" ]; then + eerror "Whitelist file missing: /etc/linux_patch_api/whitelist.yaml" + eerror "Please create whitelist.yaml before starting the service" + return 1 + fi +} + +# Verify service started successfully +start_post() { + sleep 2 + if [ -f "$pidfile" ]; then + einfo "linux-patch-api started successfully (PID: $(cat $pidfile))" + else + ewarn "linux-patch-api may not have started correctly - pidfile not found" + fi +} + +# Clean shutdown +stop_pre() { + einfo "Stopping linux-patch-api service..." +} + +# Verify service stopped +stop_post() { + if [ -f "$pidfile" ]; then + rm -f "$pidfile" + fi + einfo "linux-patch-api stopped" +} + +# Service status +status() { + if [ -f "$pidfile" ] && kill -0 $(cat "$pidfile") 2>/dev/null; then + einfo "linux-patch-api is running (PID: $(cat $pidfile))" + return 0 + else + eerror "linux-patch-api is not running" + return 1 + fi +} From cbb5ae38cebdb1d332f00034c9475147a4fca96e Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 21:01:07 +0000 Subject: [PATCH 16/54] Fix CI YAML syntax error in build-apk job - Separated checkout step from dependency installation step - Each step must have either 'uses:' OR 'run:', not both - Added proper 'name:' field for install dependencies step --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94408c9..603f504 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,6 +141,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Install build dependencies run: | apk add --no-cache rust cargo musl-dev openssl-dev git abuild - name: Build APK package From ed05364bbf8635e2429e25babf233392661f1ee3 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 21:08:40 +0000 Subject: [PATCH 17/54] Restore execute permission on build-alpine.sh - File lost execute bit during patch operation - Required for CI to run the build script --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From 4037c497124062fb7d780651f57db3b195ef78be Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 21:20:31 +0000 Subject: [PATCH 18/54] Fix: Change shebang to #!/bin/sh for Alpine compatibility --- build-alpine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index 539cdb3..5d882d9 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # Build Alpine Package (.apk) # Run on: Alpine Linux 3.18+ # Or in Docker: docker run -v $(pwd):/build alpine:latest /build/build-alpine.sh From d92f0f3ffd4ca80e9b489feb42d13dfc5a8eef81 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 21:20:37 +0000 Subject: [PATCH 19/54] Fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From b5eda96fd4ee3bc6112cdf2e8224c3274a6dd4b5 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 22:08:37 +0000 Subject: [PATCH 20/54] Fix: Use rustup to install latest Rust for edition2024 support in Alpine build --- .github/workflows/ci.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 603f504..4401109 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,9 +141,16 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Install Rust toolchain (rustup for edition2024 support) + run: | + apk add --no-cache curl + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable + source $HOME/.cargo/env + rustc --version + cargo --version - name: Install build dependencies run: | - apk add --no-cache rust cargo musl-dev openssl-dev git abuild + apk add --no-cache musl-dev openssl-dev git abuild - name: Build APK package run: ./build-alpine.sh - name: Upload to releases (on tag) From f8153d0b013260aca7617a47a2fbcf1f94aeda16 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 22:22:48 +0000 Subject: [PATCH 21/54] Fix: Source cargo env in build-alpine.sh for rustup toolchain --- build-alpine.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build-alpine.sh b/build-alpine.sh index 5d882d9..6d43ad6 100755 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -8,6 +8,13 @@ set -e echo "=== Linux Patch API - Alpine Build Script ===" echo "" +# Source cargo environment (for rustup-installed toolchain in CI) +if [ -f "$HOME/.cargo/env" ]; then + . "$HOME/.cargo/env" +fi + +# Check if running on Alpine + # Check if running on Alpine if ! command -v abuild &> /dev/null; then echo "Installing Alpine build tools..." From 28a1830c9c8fd96ce9c32d0adae28ef4195e7fac Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 22:38:34 +0000 Subject: [PATCH 22/54] Fix: Add gcc to Alpine build dependencies for Rust linker --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4401109..7511348 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -150,7 +150,7 @@ jobs: cargo --version - name: Install build dependencies run: | - apk add --no-cache musl-dev openssl-dev git abuild + apk add --no-cache musl-dev openssl-dev git abuild gcc - name: Build APK package run: ./build-alpine.sh - name: Upload to releases (on tag) From d0dbf507952055ee51f62aec3fa87178e5c178d8 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 22:57:45 +0000 Subject: [PATCH 23/54] Fix: Add elogind-dev to Alpine build for systemd-compatible libsystemd --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7511348..0ec0805 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -150,7 +150,7 @@ jobs: cargo --version - name: Install build dependencies run: | - apk add --no-cache musl-dev openssl-dev git abuild gcc + apk add --no-cache musl-dev openssl-dev git abuild gcc elogind-dev - name: Build APK package run: ./build-alpine.sh - name: Upload to releases (on tag) From 3c9b31d575907989af3f9790b97faa8cf06d5cb9 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 23:38:15 +0000 Subject: [PATCH 24/54] Fix: Add abuild-keygen for Alpine APK package signing --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ec0805..edb0237 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,6 +151,7 @@ jobs: - name: Install build dependencies run: | apk add --no-cache musl-dev openssl-dev git abuild gcc elogind-dev + abuild-keygen -a -n - name: Build APK package run: ./build-alpine.sh - name: Upload to releases (on tag) From ed055b3b44779d76bfb1b682923a5936881e0167 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 13 Apr 2026 23:54:25 +0000 Subject: [PATCH 25/54] Fix: Add abuild checksum generation for APKBUILD validation --- build-alpine.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build-alpine.sh b/build-alpine.sh index 6d43ad6..28e2777 100755 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -61,6 +61,10 @@ package() { } EOF +# Generate checksums for APKBUILD sources +echo "Generating checksums..." +abuild checksum + # Build APK package echo "Building APK package..." abuild -F -r From ef34786c11c15152641ced97c5a9afe2a16510d0 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 00:05:14 +0000 Subject: [PATCH 26/54] Fix: Use non-root builduser for abuild in CI container --- build-alpine.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/build-alpine.sh b/build-alpine.sh index 28e2777..de5b68d 100755 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -63,11 +63,21 @@ EOF # Generate checksums for APKBUILD sources echo "Generating checksums..." -abuild checksum # Build APK package echo "Building APK package..." -abuild -F -r + +# For CI/container environments where we run as root, create a build user +if [ "$(id -u)" = "0" ]; then + echo "Running as root - creating build user for abuild..." + adduser -D -s /bin/sh builduser 2>/dev/null || true + chown -R builduser:builduser "$(pwd)" + chown -R builduser:builduser /root/packages 2>/dev/null || true + su - builduser -c "cd $(pwd) && abuild checksum && abuild -F -r" +else + abuild checksum + abuild -F -r +fi # Copy to releases directory echo "" From 3799c3c051fd25e503468baa5538e07f74574e3b Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 00:19:54 +0000 Subject: [PATCH 27/54] fix: Remove apk-package from APKBUILD sources (directory not file) --- build-alpine.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index de5b68d..f0f5d12 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -54,10 +54,12 @@ url="https://gitea.internal/linux-patch-api" arch="x86_64" license="MIT" depends="openrc" -source="apk-package" +source="" package() { - cp -r "$srcdir"/apk-package/* "$pkgdir"/ + # Copy from workspace path (not srcdir - apk-package is created dynamically) + cp -r /workspace/echo/linux_patch_api/apk-package/* "$pkgdir"/ +} } EOF From 20760b139ee39b85a0a9fd9b5637ddb7b7a3f595 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 00:28:03 +0000 Subject: [PATCH 28/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From 45ce4c435f66c100312e39e8e6ca7469b55249ef Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 01:15:47 +0000 Subject: [PATCH 29/54] fix: Remove duplicate closing brace in APKBUILD package() --- build-alpine.sh | 1 - 1 file changed, 1 deletion(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index f0f5d12..77d12ec --- a/build-alpine.sh +++ b/build-alpine.sh @@ -60,7 +60,6 @@ package() { # Copy from workspace path (not srcdir - apk-package is created dynamically) cp -r /workspace/echo/linux_patch_api/apk-package/* "$pkgdir"/ } -} EOF # Generate checksums for APKBUILD sources From 9835ea2aa01945533d6d2a7aedc81e99ec9b966b Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 01:15:53 +0000 Subject: [PATCH 30/54] fix: Restore execute permission on build-alpine.sh (git stripped it again) --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From e9f47e4ed59e16b71c10ce9b3ba1a2e653b44f64 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 01:30:25 +0000 Subject: [PATCH 31/54] fix: Copy abuild keys to builduser home directory --- build-alpine.sh | 4 ++++ 1 file changed, 4 insertions(+) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index 77d12ec..a36fc0c --- a/build-alpine.sh +++ b/build-alpine.sh @@ -74,6 +74,10 @@ if [ "$(id -u)" = "0" ]; then adduser -D -s /bin/sh builduser 2>/dev/null || true chown -R builduser:builduser "$(pwd)" chown -R builduser:builduser /root/packages 2>/dev/null || true + # Copy abuild keys from root to builduser home + mkdir -p /home/builduser/.abuild + cp /root/.abuild/* /home/builduser/.abuild/ + chown -R builduser:builduser /home/builduser/.abuild su - builduser -c "cd $(pwd) && abuild checksum && abuild -F -r" else abuild checksum From 738fee0717d272ead793159afac00cb39c4f7419 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 01:30:30 +0000 Subject: [PATCH 32/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From 1ee46b97ce6cf00644db39812888865cbd3d0f76 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 02:27:11 +0000 Subject: [PATCH 33/54] fix: Set PACKAGER_PRIVKEY explicitly after abuild-keygen --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edb0237..308ac18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -152,6 +152,10 @@ jobs: run: | apk add --no-cache musl-dev openssl-dev git abuild gcc elogind-dev abuild-keygen -a -n + # Find the generated key and set PACKAGER_PRIVKEY + export PACKAGER_PRIVKEY=$(ls /root/.abuild/*.rsa | head -1) + echo "PACKAGER_PRIVKEY=$PACKAGER_PRIVKEY" >> $GITHUB_ENV + echo "Using key: $PACKAGER_PRIVKEY" - name: Build APK package run: ./build-alpine.sh - name: Upload to releases (on tag) From 8da407f9f2793084c18cc9f641d2a246ae6fe30c Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 02:38:54 +0000 Subject: [PATCH 34/54] fix: Write PACKAGER_PRIVKEY directly to /etc/abuild.conf --- .github/workflows/ci.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 308ac18..3b905a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,11 +151,17 @@ jobs: - name: Install build dependencies run: | apk add --no-cache musl-dev openssl-dev git abuild gcc elogind-dev - abuild-keygen -a -n - # Find the generated key and set PACKAGER_PRIVKEY - export PACKAGER_PRIVKEY=$(ls /root/.abuild/*.rsa | head -1) - echo "PACKAGER_PRIVKEY=$PACKAGER_PRIVKEY" >> $GITHUB_ENV - echo "Using key: $PACKAGER_PRIVKEY" + # Generate keys and capture the key path from output + abuild-keygen -a -n 2>&1 | tee /tmp/keygen.log + # Find the actual key file (handles missing username prefix) + KEYFILE=$(ls /root/.abuild/*.rsa 2>/dev/null | head -1) + if [ -z "$KEYFILE" ]; then + KEYFILE=$(ls /root/.abuild/-*.rsa 2>/dev/null | head -1) + fi + echo "Found key: $KEYFILE" + # Write directly to abuild.conf (more reliable than env var) + echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" >> /etc/abuild.conf + cat /etc/abuild.conf - name: Build APK package run: ./build-alpine.sh - name: Upload to releases (on tag) From 637683e6d0948effea3927bbcaf6c2d7646ec300 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 02:52:00 +0000 Subject: [PATCH 35/54] fix: Move abuild-keygen inside build-alpine.sh for same-shell key persistence --- build-alpine.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index a36fc0c..d6e956f --- a/build-alpine.sh +++ b/build-alpine.sh @@ -15,12 +15,29 @@ fi # Check if running on Alpine +# Check if running on Alpine # Check if running on Alpine if ! command -v abuild &> /dev/null; then echo "Installing Alpine build tools..." apk add --no-cache alpine-sdk rust cargo openssl-dev openrc git fi +# Generate abuild signing keys (must be done in same shell session as abuild commands) +if [ ! -f /etc/abuild.conf ] || ! grep -q PACKAGER_PRIVKEY /etc/abuild.conf 2>/dev/null; then + echo "Generating abuild signing keys..." + apk add --no-cache abuild + abuild-keygen -a -n 2>&1 | tee /tmp/keygen.log + # Find the actual key file (handles missing username prefix) + KEYFILE=$(ls /root/.abuild/*.rsa 2>/dev/null | head -1) + if [ -z "$KEYFILE" ]; then + KEYFILE=$(ls /root/.abuild/-*.rsa 2>/dev/null | head -1) + fi + echo "Found key: $KEYFILE" + # Write directly to abuild.conf + echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" >> /etc/abuild.conf + cat /etc/abuild.conf +fi + # Setup build environment echo "Setting up build environment..." export CBUILDROOT=$(pwd)/.abuild From 53ceca729a253f436f0366182f52eec58b52a227 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 02:52:06 +0000 Subject: [PATCH 36/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From 0886ba248ad5787fe470e59bd6664278159a19d2 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:12:07 +0000 Subject: [PATCH 37/54] fix: Export PACKAGER_PRIVKEY with proper variable expansion --- build-alpine.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index d6e956f..47a576a --- a/build-alpine.sh +++ b/build-alpine.sh @@ -95,6 +95,18 @@ if [ "$(id -u)" = "0" ]; then mkdir -p /home/builduser/.abuild cp /root/.abuild/* /home/builduser/.abuild/ chown -R builduser:builduser /home/builduser/.abuild + + # Find the actual key file + KEYFILE=$(ls /home/builduser/.abuild/*.rsa 2>/dev/null | head -1) + if [ -z "$KEYFILE" ]; then + KEYFILE=$(ls /home/builduser/.abuild/-*.rsa 2>/dev/null | head -1) + fi + + echo "Key file: $KEYFILE" + echo "Key file exists: $(test -f "$KEYFILE" && echo YES || echo NO)" + + # CRITICAL: Export PACKAGER_PRIVKEY (double quotes for variable expansion!) + export PACKAGER_PRIVKEY="$KEYFILE" su - builduser -c "cd $(pwd) && abuild checksum && abuild -F -r" else abuild checksum From c5fb03c1c46da797088d851ac6d898fff2576565 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:12:43 +0000 Subject: [PATCH 38/54] fix: Remove ci.yml abuild-keygen (step isolation breaks key persistence) --- .github/workflows/ci.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b905a7..12418ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,17 +151,7 @@ jobs: - name: Install build dependencies run: | apk add --no-cache musl-dev openssl-dev git abuild gcc elogind-dev - # Generate keys and capture the key path from output - abuild-keygen -a -n 2>&1 | tee /tmp/keygen.log - # Find the actual key file (handles missing username prefix) - KEYFILE=$(ls /root/.abuild/*.rsa 2>/dev/null | head -1) - if [ -z "$KEYFILE" ]; then - KEYFILE=$(ls /root/.abuild/-*.rsa 2>/dev/null | head -1) - fi - echo "Found key: $KEYFILE" - # Write directly to abuild.conf (more reliable than env var) - echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" >> /etc/abuild.conf - cat /etc/abuild.conf + # NOTE: abuild-keygen is now done inside build-alpine.sh to ensure keys persist in same shell session - name: Build APK package run: ./build-alpine.sh - name: Upload to releases (on tag) From 8f2d1972f7a67d18eb556abeb9e3825fafe43e29 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:12:50 +0000 Subject: [PATCH 39/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From 097e44bace7baf90b44b707b112101cb177c927e Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:13:30 +0000 Subject: [PATCH 40/54] fix: ALWAYS generate abuild keys (remove conditional - stale /etc/abuild.conf causes skip) --- build-alpine.sh | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index 47a576a..2fe7bac --- a/build-alpine.sh +++ b/build-alpine.sh @@ -22,21 +22,19 @@ if ! command -v abuild &> /dev/null; then apk add --no-cache alpine-sdk rust cargo openssl-dev openrc git fi -# Generate abuild signing keys (must be done in same shell session as abuild commands) -if [ ! -f /etc/abuild.conf ] || ! grep -q PACKAGER_PRIVKEY /etc/abuild.conf 2>/dev/null; then - echo "Generating abuild signing keys..." - apk add --no-cache abuild - abuild-keygen -a -n 2>&1 | tee /tmp/keygen.log - # Find the actual key file (handles missing username prefix) - KEYFILE=$(ls /root/.abuild/*.rsa 2>/dev/null | head -1) - if [ -z "$KEYFILE" ]; then - KEYFILE=$(ls /root/.abuild/-*.rsa 2>/dev/null | head -1) - fi - echo "Found key: $KEYFILE" - # Write directly to abuild.conf - echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" >> /etc/abuild.conf - cat /etc/abuild.conf +# Generate abuild signing keys (ALWAYS generate fresh - same shell session as abuild commands) +echo "Generating abuild signing keys..." +apk add --no-cache abuild +abuild-keygen -a -n 2>&1 | tee /tmp/keygen.log +# Find the actual key file (handles missing username prefix) +KEYFILE=$(ls /root/.abuild/*.rsa 2>/dev/null | head -1) +if [ -z "$KEYFILE" ]; then + KEYFILE=$(ls /root/.abuild/-*.rsa 2>/dev/null | head -1) fi +echo "Found key: $KEYFILE" +# Write directly to abuild.conf (overwrite any stale config) +echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" > /etc/abuild.conf +cat /etc/abuild.conf # Setup build environment echo "Setting up build environment..." From a53819b996594906d49cb8dfa433aceab18d2566 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:13:44 +0000 Subject: [PATCH 41/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From cf6c15b0fcd8d8f82c0fe5b497e7b2ce8452d738 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:26:11 +0000 Subject: [PATCH 42/54] fix: Write PACKAGER_PRIVKEY to builduser's ~/.abuild/abuild.conf (standard abuild behavior) --- build-alpine.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index 2fe7bac..141b45d --- a/build-alpine.sh +++ b/build-alpine.sh @@ -103,8 +103,13 @@ if [ "$(id -u)" = "0" ]; then echo "Key file: $KEYFILE" echo "Key file exists: $(test -f "$KEYFILE" && echo YES || echo NO)" - # CRITICAL: Export PACKAGER_PRIVKEY (double quotes for variable expansion!) - export PACKAGER_PRIVKEY="$KEYFILE" + # CRITICAL: Write to builduser's PERSONAL abuild.conf (~/.abuild/abuild.conf) + # abuild reads this when running as builduser - standard behavior, no shell quoting issues! + echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" > /home/builduser/.abuild/abuild.conf + chown builduser:builduser /home/builduser/.abuild/abuild.conf + echo "builduser abuild.conf:" + cat /home/builduser/.abuild/abuild.conf + su - builduser -c "cd $(pwd) && abuild checksum && abuild -F -r" else abuild checksum From 33a31e349f3e1843a7a408cabbe19554730146fc Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:26:23 +0000 Subject: [PATCH 43/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From 488894357a10d3104ee5522695328a77d0d5d1f6 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:36:18 +0000 Subject: [PATCH 44/54] fix: Add builduser to abuild group (required for apk install permissions) --- build-alpine.sh | 2 ++ 1 file changed, 2 insertions(+) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index 141b45d..2396e49 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -87,6 +87,8 @@ echo "Building APK package..." if [ "$(id -u)" = "0" ]; then echo "Running as root - creating build user for abuild..." adduser -D -s /bin/sh builduser 2>/dev/null || true + # CRITICAL: Add builduser to abuild group (required for apk install permissions) + addgroup builduser abuild 2>/dev/null || usermod -aG abuild builduser chown -R builduser:builduser "$(pwd)" chown -R builduser:builduser /root/packages 2>/dev/null || true # Copy abuild keys from root to builduser home From 53155eeb2eaecde5355e7a4db604cc23bbefd3b6 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:36:25 +0000 Subject: [PATCH 45/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From 0beacdfbd200f360da26b41ef6dddb9b1fdcfd6c Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:52:55 +0000 Subject: [PATCH 46/54] fix: Use ABUILD_NODEPENDS=1 to skip makedepends installation --- build-alpine.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index 2396e49..92fdd35 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -68,6 +68,7 @@ pkgdesc="Secure remote package management API for Linux systems" url="https://gitea.internal/linux-patch-api" arch="x86_64" license="MIT" +makedepends="" depends="openrc" source="" @@ -109,10 +110,9 @@ if [ "$(id -u)" = "0" ]; then # abuild reads this when running as builduser - standard behavior, no shell quoting issues! echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" > /home/builduser/.abuild/abuild.conf chown builduser:builduser /home/builduser/.abuild/abuild.conf - echo "builduser abuild.conf:" + su - builduser -c "cd $(pwd) && ABUILD_NODEPENDS=1 abuild checksum && ABUILD_NODEPENDS=1 abuild -G -F" cat /home/builduser/.abuild/abuild.conf - su - builduser -c "cd $(pwd) && abuild checksum && abuild -F -r" else abuild checksum abuild -F -r From 8df45476a37cf7acbd96ec403f1a81e113dc91f3 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 03:53:08 +0000 Subject: [PATCH 47/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From bb305ba74ac9f364061230e887033c2b9eeaca2e Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 04:03:17 +0000 Subject: [PATCH 48/54] fix: Use -d flag for abuild dependency disable instead of -G --- build-alpine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index 92fdd35..ef4b805 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -110,7 +110,7 @@ if [ "$(id -u)" = "0" ]; then # abuild reads this when running as builduser - standard behavior, no shell quoting issues! echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" > /home/builduser/.abuild/abuild.conf chown builduser:builduser /home/builduser/.abuild/abuild.conf - su - builduser -c "cd $(pwd) && ABUILD_NODEPENDS=1 abuild checksum && ABUILD_NODEPENDS=1 abuild -G -F" + su - builduser -c "cd $(pwd) && abuild checksum && abuild -d -F" cat /home/builduser/.abuild/abuild.conf else From 0b38f54a5d8f09b29d336cedd8c09a523642d350 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 04:03:30 +0000 Subject: [PATCH 49/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From 5665be0d6de0cb7a4317e3fa6f03f8d577f7b50b Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 11:48:39 +0000 Subject: [PATCH 50/54] fix: Create directory structure in APKBUILD package() function --- build-alpine.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index ef4b805..1b3a6a7 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -73,8 +73,14 @@ depends="openrc" source="" package() { - # Copy from workspace path (not srcdir - apk-package is created dynamically) - cp -r /workspace/echo/linux_patch_api/apk-package/* "$pkgdir"/ + # Create directory structure in pkgdir + install -d "$pkgdir"/usr/bin + install -d "$pkgdir"/etc/linux_patch_api + install -d "$pkgdir"/etc/init.d + # Copy from pre-built apk-package directory + cp -r /workspace/echo/linux_patch_api/apk-package/usr/bin/* "$pkgdir"/usr/bin/ + cp -r /workspace/echo/linux_patch_api/apk-package/etc/linux_patch_api/* "$pkgdir"/etc/linux_patch_api/ + cp -r /workspace/echo/linux_patch_api/apk-package/etc/init.d/* "$pkgdir"/etc/init.d/ } EOF From 710ee85c3e902a2d679addb988dc8b3e200399fe Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 11:48:49 +0000 Subject: [PATCH 51/54] fix: Restore execute permission on build-alpine.sh --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From e351e4e30c09e8a2206a0669465279210c7fea07 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 12:34:01 +0000 Subject: [PATCH 52/54] fix: Copy APK directly after build instead of using abuild repo (APK built successfully!) --- build-alpine.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) mode change 100755 => 100644 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100755 new mode 100644 index 1b3a6a7..4740e06 --- a/build-alpine.sh +++ b/build-alpine.sh @@ -116,12 +116,11 @@ if [ "$(id -u)" = "0" ]; then # abuild reads this when running as builduser - standard behavior, no shell quoting issues! echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" > /home/builduser/.abuild/abuild.conf chown builduser:builduser /home/builduser/.abuild/abuild.conf - su - builduser -c "cd $(pwd) && abuild checksum && abuild -d -F" - cat /home/builduser/.abuild/abuild.conf - + su - builduser -c "cd $(pwd) && abuild checksum && abuild -d -F && cp /home/builduser/packages/x86_64/*.apk ./releases/ 2>/dev/null || cp /home/builduser/packages/*.apk ./releases/ 2>/dev/null || ls -la /home/builduser/packages/" else abuild checksum abuild -F -r + cp ~/packages/x86_64/*.apk releases/ 2>/dev/null || cp ~/packages/*.apk releases/ 2>/dev/null || true fi # Copy to releases directory From 42b36ad319688291d2656ff26fa8116e9fdaaf54 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 12:34:25 +0000 Subject: [PATCH 53/54] fix: Restore execute permission --- build-alpine.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build-alpine.sh diff --git a/build-alpine.sh b/build-alpine.sh old mode 100644 new mode 100755 From ae5f998cf5a1cea3065f8d232c6c762654173ff0 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 14 Apr 2026 13:34:19 +0000 Subject: [PATCH 54/54] chore: Prepare for v1.0.0 release --- .github/workflows/ci.yml | 116 +++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12418ac..5c933db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,66 +26,62 @@ jobs: - name: Check formatting run: cargo fmt --all -- --check -# TEMPORARILY DISABLED - re-enable after build jobs are stable -# clippy: -# name: Clippy Lints -# runs-on: linux -# container: node:18 -# steps: -# - uses: actions/checkout@v2 -# with: -# fetch-depth: 0 -# - name: Install system dependencies -# run: | -# apt-get update -# apt-get install -y libsystemd-dev pkg-config -# - uses: dtolnay/rust-toolchain@stable -# with: -# components: clippy -# - name: Cache cargo -# uses: Swatinem/rust-cache@v2 -# - name: Run clippy -# run: cargo clippy --all-targets --all-features -- -D warnings -# -# test: -# name: Unit Tests -# runs-on: linux -# container: node:18 -# steps: -# - uses: actions/checkout@v2 -# with: -# fetch-depth: 0 -# - name: Install system dependencies -# run: | -# apt-get update -# apt-get install -y libsystemd-dev pkg-config -# - uses: dtolnay/rust-toolchain@stable -# - name: Cache cargo -# uses: Swatinem/rust-cache@v2 -# - name: Run tests -# run: cargo test --all-features -# - name: Upload coverage -# uses: codecov/codecov-action@v4 -# if: always() -# -# audit: -# name: Security Audit -# runs-on: linux -# container: node:18 -# steps: -# - uses: actions/checkout@v2 -# with: -# fetch-depth: 0 -# - name: Install system dependencies -# run: | -# apt-get update -# apt-get install -y libsystemd-dev pkg-config -# - uses: dtolnay/rust-toolchain@stable -# - name: Run cargo-audit -# run: | -# cargo install cargo-audit -# cargo audit - # Debian/Ubuntu Package Build + clippy: + name: Clippy Lints + runs-on: linux + container: node:18 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install system dependencies + run: | + apt-get update + apt-get install -y libsystemd-dev pkg-config + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + - name: Run clippy + run: cargo clippy --all-targets --all-features -- -D warnings + + test: + name: Unit Tests + runs-on: linux + container: node:18 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install system dependencies + run: | + apt-get update + apt-get install -y libsystemd-dev pkg-config + - uses: dtolnay/rust-toolchain@stable + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + - name: Run tests + run: cargo test --all-features + + audit: + name: Security Audit + runs-on: linux + container: node:18 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install system dependencies + run: | + apt-get update + apt-get install -y libsystemd-dev pkg-config + - uses: dtolnay/rust-toolchain@stable + - name: Run cargo-audit + run: | + cargo install cargo-audit + cargo audit + build-deb: name: Build Debian Package runs-on: linux