Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 603c974116 | |||
| e033cb8536 | |||
| 392e7553c4 | |||
| 19f76f4d9d | |||
| 7dcbff8ece | |||
| 8952589efd | |||
| bcc0d40413 | |||
| 1af72deb16 | |||
| 11168b22df | |||
| 653623b9f0 | |||
| 74288e1dfc | |||
| 73a11e70e0 |
BIN
.a0proj/audit.db
BIN
.a0proj/audit.db
Binary file not shown.
@ -171,6 +171,10 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -f install -y
|
sudo apt-get -f install -y
|
||||||
sudo apt-get install -y build-essential debhelper pkg-config libsystemd-dev libssl-dev
|
sudo apt-get install -y build-essential debhelper pkg-config libsystemd-dev libssl-dev
|
||||||
|
- name: Clean previous build artifacts
|
||||||
|
run: |
|
||||||
|
cargo clean
|
||||||
|
rm -f ../linux-patch-api_*.deb
|
||||||
- name: Build Debian package
|
- name: Build Debian package
|
||||||
run: |
|
run: |
|
||||||
sudo dpkg-buildpackage -us -uc -b -d
|
sudo dpkg-buildpackage -us -uc -b -d
|
||||||
@ -204,6 +208,10 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -f install -y
|
sudo apt-get -f install -y
|
||||||
sudo apt-get install -y build-essential debhelper pkg-config libsystemd-dev libssl-dev
|
sudo apt-get install -y build-essential debhelper pkg-config libsystemd-dev libssl-dev
|
||||||
|
- name: Clean previous build artifacts
|
||||||
|
run: |
|
||||||
|
cargo clean
|
||||||
|
rm -f ../linux-patch-api_*.deb
|
||||||
- name: Build Debian package
|
- name: Build Debian package
|
||||||
run: |
|
run: |
|
||||||
sudo dpkg-buildpackage -us -uc -b -d
|
sudo dpkg-buildpackage -us -uc -b -d
|
||||||
|
|||||||
@ -909,6 +909,7 @@ Enrollment endpoints enable new hosts to register with the Patch Manager and rec
|
|||||||
| `fqdn` | string | Yes | Fully qualified domain name of the host |
|
| `fqdn` | string | Yes | Fully qualified domain name of the host |
|
||||||
| `ip_address` | string | Yes | Primary non-loopback IPv4 address |
|
| `ip_address` | string | Yes | Primary non-loopback IPv4 address |
|
||||||
| `os_details` | object | Yes | OS metadata (free-form JSON object) |
|
| `os_details` | object | Yes | OS metadata (free-form JSON object) |
|
||||||
|
| `hostname` | string | No | Short hostname (without domain). Used by the manager to populate `display_name` on approval. If omitted, the manager falls back to the FQDN. |
|
||||||
|
|
||||||
**`os_details` common fields:**
|
**`os_details` common fields:**
|
||||||
|
|
||||||
@ -933,7 +934,8 @@ curl -X POST https://manager.example.com/api/v1/enroll \
|
|||||||
"version_id": "12",
|
"version_id": "12",
|
||||||
"kernel": "6.1.0-kali9-amd64",
|
"kernel": "6.1.0-kali9-amd64",
|
||||||
"id_like": "debian"
|
"id_like": "debian"
|
||||||
}
|
},
|
||||||
|
"hostname": "host-01"
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Linux Patch API - Package Build Guide
|
# Linux Patch API - Package Build Guide
|
||||||
|
|
||||||
This document provides comprehensive instructions for building production-ready Debian (.deb) and RPM (.rpm) packages for the Linux Patch API.
|
This document provides comprehensive instructions for building production-ready packages for the Linux Patch API across all supported platforms: Debian/Ubuntu (.deb), RHEL/CentOS/Fedora (.rpm), Arch Linux (.pkg.tar.zst), and Alpine Linux (.apk).
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@ -173,6 +173,152 @@ rpm -ql linux-patch-api
|
|||||||
rpm -e linux-patch-api
|
rpm -e linux-patch-api
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Building Arch Package (.pkg.tar.zst)
|
||||||
|
|
||||||
|
### Quick Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/linux_patch_api
|
||||||
|
|
||||||
|
# Build release binary
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
# Build Arch package
|
||||||
|
chmod +x build-arch.sh
|
||||||
|
SKIP_CARGO_BUILD=1 ./build-arch.sh
|
||||||
|
|
||||||
|
# Package will be created in releases/
|
||||||
|
ls -la releases/*.pkg.tar.zst
|
||||||
|
```
|
||||||
|
|
||||||
|
### Detailed Build Process
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Install build dependencies (Arch Linux)
|
||||||
|
sudo pacman -Syu --noconfirm rust cargo systemd git base-devel gcc
|
||||||
|
|
||||||
|
# 2. Build release binary
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
# 3. Run build script
|
||||||
|
chmod +x build-arch.sh
|
||||||
|
./build-arch.sh
|
||||||
|
|
||||||
|
# 4. Verify package contents
|
||||||
|
bsdtar -tf releases/linux-patch-api-*.pkg.tar.zst
|
||||||
|
|
||||||
|
# 5. Verify package info
|
||||||
|
pacman -Qi releases/linux-patch-api-*.pkg.tar.zst
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install Script Hooks
|
||||||
|
|
||||||
|
The Arch package includes an `.install` file (`configs/linux-patch-api.install`) that runs automatically on install:
|
||||||
|
|
||||||
|
- **post_install**: Creates directories, copies example configs, enables systemd service
|
||||||
|
- **post_upgrade**: Reloads systemd daemon
|
||||||
|
- **pre_remove**: Stops and disables service
|
||||||
|
- **post_remove**: Cleans up empty directories
|
||||||
|
|
||||||
|
### Installation Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install the package
|
||||||
|
sudo pacman -U ./releases/linux-patch-api-*.pkg.tar.zst
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
systemctl status linux-patch-api
|
||||||
|
linux-patch-api --version
|
||||||
|
|
||||||
|
# Check installed files
|
||||||
|
pacman -Ql linux-patch-api
|
||||||
|
|
||||||
|
# Verify config files exist
|
||||||
|
ls -la /etc/linux_patch_api/
|
||||||
|
|
||||||
|
# Remove package
|
||||||
|
sudo pacman -R linux-patch-api
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The build script creates a `builduser` for `makepkg` when running as root (typical in CI environments). The `.install` hook handles directory creation, config copying, and service enablement.
|
||||||
|
|
||||||
|
## Building Alpine Package (.apk)
|
||||||
|
|
||||||
|
### Quick Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/linux_patch_api
|
||||||
|
|
||||||
|
# Build release binary (MUSL target for Alpine)
|
||||||
|
cargo build --release --target x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
# Build Alpine package
|
||||||
|
chmod +x build-alpine.sh
|
||||||
|
SKIP_CARGO_BUILD=1 ./build-alpine.sh
|
||||||
|
|
||||||
|
# Package will be created in releases/
|
||||||
|
ls -la releases/*.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
### Detailed Build Process
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Install build dependencies (Alpine Linux)
|
||||||
|
apk add --no-cache alpine-sdk rust cargo openssl openssl-dev elogind-dev musl-dev abuild gcc
|
||||||
|
|
||||||
|
# 2. Add Rust MUSL target
|
||||||
|
rustup target add x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
# 3. Build release binary
|
||||||
|
cargo build --release --target x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
# 4. Run build script
|
||||||
|
chmod +x build-alpine.sh
|
||||||
|
./build-alpine.sh
|
||||||
|
|
||||||
|
# 5. Verify package contents
|
||||||
|
apk verify releases/*.apk
|
||||||
|
|
||||||
|
# 6. List package contents
|
||||||
|
tar -tzf releases/*.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install Script Hooks
|
||||||
|
|
||||||
|
The Alpine package includes an install script (`configs/linux-patch-api.apk-install`) that runs automatically on install:
|
||||||
|
|
||||||
|
- **pre_install**: Creates directories, sets ownership and permissions
|
||||||
|
- **post_install**: Copies example configs, adds service to default runlevel
|
||||||
|
- **pre_deinstall**: Stops and removes service from runlevel
|
||||||
|
- **post_deinstall**: Cleans up empty directories
|
||||||
|
|
||||||
|
### Installation Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install the package
|
||||||
|
sudo apk add --allow-unstable ./releases/linux-patch-api-*.apk
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
rc-service linux-patch-api status
|
||||||
|
linux-patch-api --version
|
||||||
|
|
||||||
|
# Check installed files
|
||||||
|
apk info -L linux-patch-api
|
||||||
|
|
||||||
|
# Verify config files exist
|
||||||
|
ls -la /etc/linux_patch_api/
|
||||||
|
|
||||||
|
# Remove package
|
||||||
|
sudo apk del linux-patch-api
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important:** Alpine uses **OpenRC** instead of systemd. Key differences:
|
||||||
|
- Start service: `rc-service linux-patch-api start`
|
||||||
|
- Stop service: `rc-service linux-patch-api stop`
|
||||||
|
- Check status: `rc-service linux-patch-api status`
|
||||||
|
- Service init script: `/etc/init.d/linux-patch-api`
|
||||||
|
- The `abuild` tool generates signing keys automatically for CI builds
|
||||||
|
|
||||||
## Using the Interactive Installer
|
## Using the Interactive Installer
|
||||||
|
|
||||||
For manual deployment without package managers:
|
For manual deployment without package managers:
|
||||||
@ -209,15 +355,17 @@ The installer will:
|
|||||||
| `/var/lib/linux_patch_api/` | Data directory | 755 |
|
| `/var/lib/linux_patch_api/` | Data directory | 755 |
|
||||||
| `/var/log/linux_patch_api/` | Log directory | 755 |
|
| `/var/log/linux_patch_api/` | Log directory | 755 |
|
||||||
|
|
||||||
### System User/Group
|
### Service Account
|
||||||
|
|
||||||
| Property | Value |
|
| Property | Value |
|
||||||
|----------|-------|
|
|----------|-------|
|
||||||
| User | linux-patch-api |
|
| User | root |
|
||||||
| Group | linux-patch-api |
|
| Group | root |
|
||||||
| Home | /var/lib/linux_patch_api |
|
| Home | /var/lib/linux_patch_api |
|
||||||
| Shell | /usr/sbin/nologin |
|
| Shell | N/A (systemd service) |
|
||||||
| Type | System account |
|
| Type | Runs as root (required for package management) |
|
||||||
|
|
||||||
|
**Note:** The service runs as root because package management operations (apt, dnf, apk, pacman) require root privileges. Security is provided by mTLS + IP whitelist, not process isolation.
|
||||||
|
|
||||||
## Supported Distributions
|
## Supported Distributions
|
||||||
|
|
||||||
@ -240,6 +388,19 @@ The installer will:
|
|||||||
| AlmaLinux | 8, 9 | ✅ Supported |
|
| AlmaLinux | 8, 9 | ✅ Supported |
|
||||||
| Rocky Linux | 8, 9 | ✅ Supported |
|
| Rocky Linux | 8, 9 | ✅ Supported |
|
||||||
|
|
||||||
|
### Arch Package (.pkg.tar.zst)
|
||||||
|
|
||||||
|
| Distribution | Versions | Status |
|
||||||
|
|--------------|----------|--------|
|
||||||
|
| Arch Linux | Rolling | ✅ Supported |
|
||||||
|
| Manjaro | Rolling | ✅ Supported |
|
||||||
|
|
||||||
|
### Alpine Package (.apk)
|
||||||
|
|
||||||
|
| Distribution | Versions | Status |
|
||||||
|
|--------------|----------|--------|
|
||||||
|
| Alpine Linux | 3.18+ | ✅ Supported |
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Debian Package Issues
|
### Debian Package Issues
|
||||||
@ -276,9 +437,62 @@ cat ~/rpmbuild/BUILDROOT/*/var/log/rpmbuild.log
|
|||||||
dnf install -y systemd-devel pkgconfig
|
dnf install -y systemd-devel pkgconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Arch Package Issues
|
||||||
|
|
||||||
|
**Error: `makepkg: cannot run as root`**
|
||||||
|
```bash
|
||||||
|
# The build script handles this automatically by creating builduser
|
||||||
|
# If running manually:
|
||||||
|
useradd -m builduser
|
||||||
|
su - builduser -c "cd /path/to/repo && makepkg -f --noconfirm"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error: `install script not found`**
|
||||||
|
```bash
|
||||||
|
# Ensure linux-patch-api.install is in the same directory as PKGBUILD
|
||||||
|
ls -la configs/linux-patch-api.install
|
||||||
|
# The build script copies it automatically
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error: `Permission denied` on config files**
|
||||||
|
```bash
|
||||||
|
# Verify ownership is root:root
|
||||||
|
ls -la /etc/linux_patch_api/
|
||||||
|
# Fix if needed:
|
||||||
|
sudo chown -R root:root /etc/linux_patch_api/
|
||||||
|
sudo chmod 750 /etc/linux_patch_api /etc/linux_patch_api/certs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alpine Package Issues
|
||||||
|
|
||||||
|
**Error: `abuild: UNTRUSTED signature`**
|
||||||
|
```bash
|
||||||
|
# The build script handles key generation automatically
|
||||||
|
# If running manually:
|
||||||
|
abuild-keygen -a -n
|
||||||
|
cp /root/.abuild/*.rsa.pub /etc/apk/keys/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error: `apk add: ERROR: failed to create directory`**
|
||||||
|
```bash
|
||||||
|
# Verify the install script ran correctly
|
||||||
|
ls -la /etc/linux_patch_api/
|
||||||
|
ls -la /var/lib/linux_patch_api/
|
||||||
|
# Manually create if needed:
|
||||||
|
sudo mkdir -p /etc/linux_patch_api/certs /var/lib/linux_patch_api /var/log/linux_patch_api
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error: `rc-service: service not found`**
|
||||||
|
```bash
|
||||||
|
# Verify the init script exists
|
||||||
|
ls -la /etc/init.d/linux-patch-api
|
||||||
|
# Re-add to default runlevel
|
||||||
|
sudo rc-update add linux-patch-api default
|
||||||
|
```
|
||||||
|
|
||||||
### Service Issues
|
### Service Issues
|
||||||
|
|
||||||
**Service fails to start:**
|
**Service fails to start (systemd):**
|
||||||
```bash
|
```bash
|
||||||
# Check service status
|
# Check service status
|
||||||
systemctl status linux-patch-api
|
systemctl status linux-patch-api
|
||||||
@ -293,6 +507,22 @@ linux-patch-api --config /etc/linux_patch_api/config.yaml --check
|
|||||||
ls -la /etc/linux_patch_api/certs/
|
ls -la /etc/linux_patch_api/certs/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Service fails to start (OpenRC/Alpine):**
|
||||||
|
```bash
|
||||||
|
# Check service status
|
||||||
|
rc-service linux-patch-api status
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
cat /var/log/linux_patch_api/linux-patch-api.log
|
||||||
|
cat /var/log/linux_patch_api/linux-patch-api.err
|
||||||
|
|
||||||
|
# Check configuration
|
||||||
|
linux-patch-api --config /etc/linux_patch_api/config.yaml --check
|
||||||
|
|
||||||
|
# Verify certificates
|
||||||
|
ls -la /etc/linux_patch_api/certs/
|
||||||
|
```
|
||||||
|
|
||||||
## CI/CD Integration
|
## CI/CD Integration
|
||||||
|
|
||||||
### GitHub Actions Example
|
### GitHub Actions Example
|
||||||
@ -383,7 +613,7 @@ jobs:
|
|||||||
- Packages are signed with maintainer GPG key for production deployments
|
- Packages are signed with maintainer GPG key for production deployments
|
||||||
- All maintainer scripts run with `set -e` for fail-fast behavior
|
- All maintainer scripts run with `set -e` for fail-fast behavior
|
||||||
- Configuration files are marked as conffiles to preserve user modifications
|
- Configuration files are marked as conffiles to preserve user modifications
|
||||||
- System user has minimal privileges (nologin shell, no home directory)
|
- Service runs as root (required for package management operations)
|
||||||
- Directory permissions follow principle of least privilege
|
- Directory permissions follow principle of least privilege
|
||||||
- TLS certificates should be replaced with CA-signed certs in production
|
- TLS certificates should be replaced with CA-signed certs in production
|
||||||
|
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1916,7 +1916,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-patch-api"
|
name = "linux-patch-api"
|
||||||
version = "1.1.5"
|
version = "1.1.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix",
|
"actix",
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "linux-patch-api"
|
name = "linux-patch-api"
|
||||||
version = "1.1.6"
|
version = "1.1.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Echo <echo@moon-dragon.us>"]
|
authors = ["Echo <echo@moon-dragon.us>"]
|
||||||
description = "Secure remote package management API for Linux systems"
|
description = "Secure remote package management API for Linux systems"
|
||||||
|
|||||||
164
README.md
164
README.md
@ -185,6 +185,13 @@ For detailed enrollment procedures, see [DEPLOYMENT_GUIDE.md - Self-Enrollment D
|
|||||||
|
|
||||||
### Package Installation
|
### Package Installation
|
||||||
|
|
||||||
|
All platform packages produce identical installation results:
|
||||||
|
- Creates `/etc/linux_patch_api/`, `/etc/linux_patch_api/certs/`, `/var/lib/linux_patch_api/`, `/var/log/linux_patch_api/`
|
||||||
|
- Copies example configs to live configs if not already present
|
||||||
|
- Enables the service (does not start automatically)
|
||||||
|
- Sets correct permissions (750 on config dirs, 755 on data/log dirs)
|
||||||
|
- Ownership: root:root (service runs as root)
|
||||||
|
|
||||||
#### Debian/Ubuntu (.deb)
|
#### Debian/Ubuntu (.deb)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -197,52 +204,173 @@ apt-get install -f -y
|
|||||||
# Verify installation
|
# Verify installation
|
||||||
systemctl status linux-patch-api
|
systemctl status linux-patch-api
|
||||||
linux-patch-api --version
|
linux-patch-api --version
|
||||||
|
|
||||||
|
# Check installed files
|
||||||
|
dpkg -L linux-patch-api
|
||||||
|
|
||||||
|
# Remove package (keeping configs)
|
||||||
|
dpkg -r linux-patch-api
|
||||||
|
|
||||||
|
# Purge package (removing all configs)
|
||||||
|
dpkg -P linux-patch-api
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Prerequisites:** `systemd`, `libsystemd0`
|
||||||
|
|
||||||
|
**Post-install:** The package automatically copies example configs, enables the service, and prints next steps. Configure `/etc/linux_patch_api/config.yaml` and place TLS certificates in `/etc/linux_patch_api/certs/` before starting.
|
||||||
|
|
||||||
#### RHEL/CentOS/Fedora (.rpm)
|
#### RHEL/CentOS/Fedora (.rpm)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install the package
|
# Install the package (recommended - resolves dependencies automatically)
|
||||||
rpm -ivh linux-patch-api-1.0.0-1.x86_64.rpm
|
dnf install -y ./linux-patch-api-1.0.0-1.el9.x86_64.rpm
|
||||||
|
|
||||||
|
# Or with yum
|
||||||
|
yum install -y ./linux-patch-api-1.0.0-1.el9.x86_64.rpm
|
||||||
|
|
||||||
|
# Or with rpm (does NOT resolve dependencies)
|
||||||
|
rpm -ivh linux-patch-api-1.0.0-1.el9.x86_64.rpm
|
||||||
|
|
||||||
# Verify installation
|
# Verify installation
|
||||||
systemctl status linux-patch-api
|
systemctl status linux-patch-api
|
||||||
linux-patch-api --version
|
linux-patch-api --version
|
||||||
|
|
||||||
|
# Check installed files
|
||||||
|
rpm -ql linux-patch-api
|
||||||
|
|
||||||
|
# Remove package
|
||||||
|
rpm -e linux-patch-api
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Prerequisites (auto-resolved with dnf/yum):** `systemd`, `libsystemd`, `openssl-libs`, `ca-certificates`
|
||||||
|
|
||||||
|
**Post-install:** The package automatically creates directories, copies example configs, enables the service, and prints next steps. Configure `/etc/linux_patch_api/config.yaml` and place TLS certificates in `/etc/linux_patch_api/certs/` before starting.
|
||||||
|
|
||||||
|
**Note:** Use `dnf install` or `yum install` instead of `rpm -ivh` to automatically resolve dependencies. The `rpm -ivh` command will fail if required packages are not already installed.
|
||||||
|
|
||||||
|
#### Arch Linux (.pkg.tar.zst)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install the package
|
||||||
|
sudo pacman -U ./linux-patch-api-1.0.0-1-x86_64.pkg.tar.zst
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
systemctl status linux-patch-api
|
||||||
|
linux-patch-api --version
|
||||||
|
|
||||||
|
# Check installed files
|
||||||
|
pacman -Ql linux-patch-api
|
||||||
|
|
||||||
|
# Remove package
|
||||||
|
sudo pacman -R linux-patch-api
|
||||||
|
```
|
||||||
|
|
||||||
|
**Prerequisites:** `systemd` (included by default on Arch)
|
||||||
|
|
||||||
|
**Post-install:** The package automatically creates directories, copies example configs, enables the service, and prints next steps. Configure `/etc/linux_patch_api/config.yaml` and place TLS certificates in `/etc/linux_patch_api/certs/` before starting.
|
||||||
|
|
||||||
|
**Note:** Arch uses systemd by default. The install hook runs `systemctl enable` but does not start the service. You must configure before starting.
|
||||||
|
|
||||||
|
#### Alpine Linux (.apk)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install the package
|
||||||
|
sudo apk add --allow-unstable ./linux-patch-api-1.0.0-r0.apk
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
rc-service linux-patch-api status
|
||||||
|
linux-patch-api --version
|
||||||
|
|
||||||
|
# Check installed files
|
||||||
|
apk info -L linux-patch-api
|
||||||
|
|
||||||
|
# Remove package
|
||||||
|
sudo apk del linux-patch-api
|
||||||
|
```
|
||||||
|
|
||||||
|
**Prerequisites:** `openrc` (included by default on Alpine)
|
||||||
|
|
||||||
|
**Post-install:** The package automatically creates directories, copies example configs, adds the service to the default runlevel, and prints next steps. Configure `/etc/linux_patch_api/config.yaml` and place TLS certificates in `/etc/linux_patch_api/certs/` before starting.
|
||||||
|
|
||||||
|
**Important differences from systemd-based systems:**
|
||||||
|
- Alpine uses **OpenRC** instead of systemd. Use `rc-service` commands instead of `systemctl`
|
||||||
|
- Start service: `rc-service linux-patch-api start`
|
||||||
|
- Stop service: `rc-service linux-patch-api stop`
|
||||||
|
- Check status: `rc-service linux-patch-api status`
|
||||||
|
- The service is added to the `default` runlevel automatically on install
|
||||||
|
- Service init script: `/etc/init.d/linux-patch-api`
|
||||||
|
|
||||||
### Manual Installation
|
### Manual Installation
|
||||||
|
|
||||||
For systems without package manager support:
|
For systems without package manager support:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run interactive installer (requires root)
|
# Run interactive installer (requires root)
|
||||||
./install.sh
|
sudo ./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
The installer will:
|
The installer will:
|
||||||
- Detect operating system
|
- Detect operating system
|
||||||
- Create system user and group
|
- Create directory structure (`/etc/linux_patch_api/`, `/var/lib/linux_patch_api/`, `/var/log/linux_patch_api/`)
|
||||||
- Set up directory structure
|
- Install binary to `/usr/bin/linux-patch-api`
|
||||||
- Install binary and configuration files
|
- Install example configs
|
||||||
- Configure systemd service
|
- Configure systemd service
|
||||||
|
- Set correct permissions
|
||||||
|
|
||||||
### Building from Source
|
### Building from Source
|
||||||
|
|
||||||
|
#### Prerequisites (all platforms)
|
||||||
|
|
||||||
|
- Rust toolchain (stable channel, 1.75+)
|
||||||
|
- OpenSSL development headers
|
||||||
|
- systemd development headers
|
||||||
|
- C compiler (gcc)
|
||||||
|
|
||||||
|
#### Build Debian Package (.deb)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone repository
|
# On Debian/Ubuntu
|
||||||
git clone https://gitea.internal/linux-patch-api.git
|
apt-get install -y build-essential debhelper pkg-config libsystemd-dev libssl-dev cargo rustc
|
||||||
cd linux-patch-api
|
cargo build --release
|
||||||
|
sudo dpkg-buildpackage -us -uc -b
|
||||||
# Build release binary
|
|
||||||
cargo build --release --target x86_64-unknown-linux-gnu
|
|
||||||
|
|
||||||
# Build Debian package
|
|
||||||
dpkg-buildpackage -us -uc -b
|
|
||||||
|
|
||||||
# Or build RPM package
|
|
||||||
rpmbuild -ba linux-patch-api.spec
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Build RPM Package (.rpm)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On Fedora/RHEL/CentOS
|
||||||
|
dnf install -y rpm-build cargo rust gcc openssl-devel systemd-devel pkgconfig
|
||||||
|
cargo build --release --target x86_64-unknown-linux-gnu
|
||||||
|
chmod +x build-rpm.sh
|
||||||
|
./build-rpm.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The RPM spec includes `BuildRequires` for native RPM build environments. When building in CI containers (where deps are pre-installed via apt-get), these are informational only.
|
||||||
|
|
||||||
|
#### Build Arch Package (.pkg.tar.zst)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On Arch Linux/Manjaro
|
||||||
|
pacman -Syu --noconfirm rust cargo systemd git base-devel gcc
|
||||||
|
cargo build --release
|
||||||
|
chmod +x build-arch.sh
|
||||||
|
SKIP_CARGO_BUILD=1 ./build-arch.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The build script creates a `builduser` for `makepkg` when running as root (typical in CI). The `.install` hook handles directory creation, config copying, and service enablement.
|
||||||
|
|
||||||
|
#### Build Alpine Package (.apk)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On Alpine Linux 3.18+
|
||||||
|
apk add --no-cache alpine-sdk rust cargo openssl openssl-dev elogind-dev musl-dev abuild gcc
|
||||||
|
cargo build --release --target x86_64-unknown-linux-musl
|
||||||
|
chmod +x build-alpine.sh
|
||||||
|
SKIP_CARGO_BUILD=1 ./build-alpine.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important:** Alpine requires the `x86_64-unknown-linux-musl` target for static linking. The build script handles `abuild` key generation and runs as a `builduser` when executed as root.
|
||||||
|
|
||||||
See [BUILD_PACKAGES.md](./BUILD_PACKAGES.md) for detailed build instructions.
|
See [BUILD_PACKAGES.md](./BUILD_PACKAGES.md) for detailed build instructions.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
2
SPEC.md
2
SPEC.md
@ -169,7 +169,7 @@ The enrollment flow runs before mTLS server startup. On success, the daemon proc
|
|||||||
### Phase 1: Registration Request
|
### Phase 1: Registration Request
|
||||||
- **Identity Extraction:**
|
- **Identity Extraction:**
|
||||||
- `/etc/machine-id` (fallback: `/var/lib/dbus/machine-id`)
|
- `/etc/machine-id` (fallback: `/var/lib/dbus/machine-id`)
|
||||||
- FQDN from `/etc/hostname` → `hostname -f` → `hostname` → `localhost`
|
- FQDN from `hostname -f` (validated contains `.`) → `hostname` + `hostname -d` → `/etc/hostname` → `hostname` → `localhost`
|
||||||
- Non-loopback IPv4 addresses via network interface enumeration
|
- Non-loopback IPv4 addresses via network interface enumeration
|
||||||
- OS details from `/etc/os-release` (distro, version, id_like, codename) + kernel version (`uname -r`)
|
- OS details from `/etc/os-release` (distro, version, id_like, codename) + kernel version (`uname -r`)
|
||||||
- **Submission:** Unauthenticated `POST /api/v1/enroll` to manager with identity payload
|
- **Submission:** Unauthenticated `POST /api/v1/enroll` to manager with identity payload
|
||||||
|
|||||||
@ -44,27 +44,51 @@ else
|
|||||||
echo "Skipping cargo build (SKIP_CARGO_BUILD is set)"
|
echo "Skipping cargo build (SKIP_CARGO_BUILD is set)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create package directory in /home/builduser (accessible by builduser)
|
# Get version from Cargo.toml
|
||||||
PKGDIR=/home/builduser/apk-package
|
VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/')
|
||||||
mkdir -p "$PKGDIR"/usr/bin
|
|
||||||
mkdir -p "$PKGDIR"/etc/linux_patch_api
|
|
||||||
mkdir -p "$PKGDIR"/etc/init.d
|
|
||||||
|
|
||||||
# Copy files
|
# Create package directory structure
|
||||||
|
PKGDIR=$(pwd)/apk-package
|
||||||
|
rm -rf "$PKGDIR"
|
||||||
|
mkdir -p "$PKGDIR"/usr/bin
|
||||||
|
mkdir -p "$PKGDIR"/etc/linux_patch_api/certs
|
||||||
|
mkdir -p "$PKGDIR"/etc/init.d
|
||||||
|
mkdir -p "$PKGDIR"/var/lib/linux_patch_api
|
||||||
|
mkdir -p "$PKGDIR"/var/log/linux_patch_api
|
||||||
|
|
||||||
|
# Copy binary
|
||||||
|
chmod 755 target/x86_64-unknown-linux-musl/release/linux-patch-api
|
||||||
cp target/x86_64-unknown-linux-musl/release/linux-patch-api "$PKGDIR"/usr/bin/
|
cp target/x86_64-unknown-linux-musl/release/linux-patch-api "$PKGDIR"/usr/bin/
|
||||||
chmod 755 "$PKGDIR"/usr/bin/linux-patch-api
|
|
||||||
|
# Copy OpenRC init script
|
||||||
cp configs/linux-patch-api-openrc "$PKGDIR"/etc/init.d/linux-patch-api
|
cp configs/linux-patch-api-openrc "$PKGDIR"/etc/init.d/linux-patch-api
|
||||||
chmod 755 "$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
|
|
||||||
|
|
||||||
# Use /home/builduser as workspace for APKBUILD
|
# Copy example configs (as .example files - install script creates live configs)
|
||||||
WORKSPACE_DIR=/home/builduser
|
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
|
||||||
|
|
||||||
# Create APKBUILD
|
# Prepare workspace for abuild
|
||||||
|
WORKSPACE_DIR=/home/builduser/repo
|
||||||
|
rm -rf "$WORKSPACE_DIR"
|
||||||
|
mkdir -p "$WORKSPACE_DIR"
|
||||||
|
|
||||||
|
# Copy package directory to workspace
|
||||||
|
cp -r "$PKGDIR" "$WORKSPACE_DIR"/apk-package
|
||||||
|
|
||||||
|
# Copy install scripts to workspace (must be co-located with APKBUILD)
|
||||||
|
# Alpine abuild requires SEPARATE files with valid suffixes:
|
||||||
|
# pkgname.pre-install, pkgname.post-install, pkgname.pre-deinstall, pkgname.post-deinstall
|
||||||
|
cp configs/linux-patch-api.pre-install "$WORKSPACE_DIR"/linux-patch-api.pre-install
|
||||||
|
cp configs/linux-patch-api.post-install "$WORKSPACE_DIR"/linux-patch-api.post-install
|
||||||
|
cp configs/linux-patch-api.pre-deinstall "$WORKSPACE_DIR"/linux-patch-api.pre-deinstall
|
||||||
|
cp configs/linux-patch-api.post-deinstall "$WORKSPACE_DIR"/linux-patch-api.post-deinstall
|
||||||
|
|
||||||
|
# Create APKBUILD in workspace directory (co-located with install scripts)
|
||||||
echo "Creating APKBUILD..."
|
echo "Creating APKBUILD..."
|
||||||
cat > APKBUILD << EOF
|
cat > "$WORKSPACE_DIR"/APKBUILD << EOF
|
||||||
pkgname=linux-patch-api
|
pkgname=linux-patch-api
|
||||||
pkgver=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/')
|
pkgver=${VERSION}
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Secure remote package management API for Linux systems"
|
pkgdesc="Secure remote package management API for Linux systems"
|
||||||
url="https://gitea.moon-dragon.us/echo/linux_patch_api"
|
url="https://gitea.moon-dragon.us/echo/linux_patch_api"
|
||||||
@ -72,21 +96,24 @@ arch="x86_64"
|
|||||||
license="MIT"
|
license="MIT"
|
||||||
makedepends=""
|
makedepends=""
|
||||||
depends="openrc"
|
depends="openrc"
|
||||||
|
install="linux-patch-api.pre-install linux-patch-api.post-install linux-patch-api.pre-deinstall linux-patch-api.post-deinstall"
|
||||||
|
subpackages=""
|
||||||
source=""
|
source=""
|
||||||
|
|
||||||
package() {
|
package() {
|
||||||
install -d "\$pkgdir"/usr/bin
|
install -d "\$pkgdir"/usr/bin
|
||||||
install -d "\$pkgdir"/etc/linux_patch_api
|
install -d "\$pkgdir"/etc/linux_patch_api/certs
|
||||||
install -d "\$pkgdir"/etc/init.d
|
install -d "\$pkgdir"/etc/init.d
|
||||||
cp -r ${WORKSPACE_DIR}/apk-package/usr/bin/* "\$pkgdir"/usr/bin/
|
install -d "\$pkgdir"/var/lib/linux_patch_api
|
||||||
cp -r ${WORKSPACE_DIR}/apk-package/etc/linux_patch_api/* "\$pkgdir"/etc/linux_patch_api/
|
install -d "\$pkgdir"/var/log/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
|
EOF
|
||||||
|
|
||||||
# Generate checksums for APKBUILD sources
|
|
||||||
echo "Generating checksums..."
|
|
||||||
|
|
||||||
# Build APK package
|
# Build APK package
|
||||||
echo "Building APK package..."
|
echo "Building APK package..."
|
||||||
|
|
||||||
@ -96,10 +123,8 @@ if [ "$(id -u)" = "0" ]; then
|
|||||||
adduser -D -s /bin/sh builduser 2>/dev/null || true
|
adduser -D -s /bin/sh builduser 2>/dev/null || true
|
||||||
addgroup builduser abuild 2>/dev/null || usermod -aG abuild builduser
|
addgroup builduser abuild 2>/dev/null || usermod -aG abuild builduser
|
||||||
|
|
||||||
# Copy repo contents to builduser home (accessible directory)
|
# Set ownership of workspace
|
||||||
cp -r . /home/builduser/repo/
|
chown -R builduser:builduser "$WORKSPACE_DIR"
|
||||||
chown -R builduser:builduser /home/builduser/repo/
|
|
||||||
chown -R builduser:builduser /home/builduser/apk-package/
|
|
||||||
|
|
||||||
# Set up builduser home directory for abuild
|
# Set up builduser home directory for abuild
|
||||||
mkdir -p /home/builduser/.abuild
|
mkdir -p /home/builduser/.abuild
|
||||||
@ -115,35 +140,27 @@ if [ "$(id -u)" = "0" ]; then
|
|||||||
echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" > /home/builduser/.abuild/abuild.conf
|
echo "PACKAGER_PRIVKEY=\"$KEYFILE\"" > /home/builduser/.abuild/abuild.conf
|
||||||
chown builduser:builduser /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)
|
# Install public key BEFORE abuild (fixes UNTRUSTED signature)
|
||||||
cp /home/builduser/.abuild/*.rsa.pub /etc/apk/keys/ 2>/dev/null || true
|
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 $WORKSPACE_DIR && abuild checksum && abuild -d"
|
||||||
su - builduser -c "cd /home/builduser && abuild checksum && abuild -d -F" || true
|
|
||||||
|
|
||||||
# Copy APK from builduser packages to releases
|
# Copy APK from builduser packages to releases
|
||||||
mkdir -p 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
|
cp /home/builduser/packages/home/x86_64/*.apk releases/ 2>/dev/null || find /home/builduser/packages -name "*.apk" -exec cp {} releases/ \; 2>/dev/null || true
|
||||||
else
|
else
|
||||||
|
cd "$WORKSPACE_DIR"
|
||||||
abuild checksum
|
abuild checksum
|
||||||
abuild -F -r
|
abuild -r
|
||||||
|
cd -
|
||||||
|
mkdir -p releases
|
||||||
cp ~/packages/x86_64/*.apk releases/ 2>/dev/null || cp ~/packages/*.apk releases/ 2>/dev/null || true
|
cp ~/packages/x86_64/*.apk releases/ 2>/dev/null || cp ~/packages/*.apk releases/ 2>/dev/null || true
|
||||||
fi
|
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 ""
|
||||||
echo "=== Build Complete ==="
|
echo "=== Build Complete ==="
|
||||||
echo "Package: releases/linux-patch-api-*.apk"
|
echo "Package: releases/linux-patch-api-*.apk"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Install with:"
|
echo "Install with:"
|
||||||
echo " sudo apk add --allow-unstable ./releases/linux-patch-api-*.apk"
|
echo " sudo apk add ./releases/linux-patch-api-*.apk"
|
||||||
|
|||||||
@ -22,43 +22,68 @@ else
|
|||||||
echo "Skipping cargo build (SKIP_CARGO_BUILD is set)"
|
echo "Skipping cargo build (SKIP_CARGO_BUILD is set)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create package directory
|
# Create package directory structure
|
||||||
PKGDIR=$(pwd)/arch-package
|
PKGDIR=$(pwd)/arch-package
|
||||||
|
rm -rf "$PKGDIR"
|
||||||
mkdir -p "$PKGDIR"/usr/bin
|
mkdir -p "$PKGDIR"/usr/bin
|
||||||
mkdir -p "$PKGDIR"/etc/linux_patch_api
|
mkdir -p "$PKGDIR"/etc/linux_patch_api/certs
|
||||||
mkdir -p "$PKGDIR"/usr/lib/systemd/system
|
mkdir -p "$PKGDIR"/usr/lib/systemd/system
|
||||||
|
mkdir -p "$PKGDIR"/var/lib/linux_patch_api
|
||||||
|
mkdir -p "$PKGDIR"/var/log/linux_patch_api
|
||||||
|
|
||||||
# Copy files
|
# Copy binary
|
||||||
|
chmod 755 target/release/linux-patch-api
|
||||||
cp target/release/linux-patch-api "$PKGDIR"/usr/bin/
|
cp target/release/linux-patch-api "$PKGDIR"/usr/bin/
|
||||||
chmod 755 "$PKGDIR"/usr/bin/linux-patch-api
|
|
||||||
|
# Copy systemd service
|
||||||
cp configs/linux-patch-api.service "$PKGDIR"/usr/lib/systemd/system/
|
cp configs/linux-patch-api.service "$PKGDIR"/usr/lib/systemd/system/
|
||||||
cp configs/config.yaml.example "$PKGDIR"/etc/linux_patch_api/config.yaml
|
|
||||||
cp configs/whitelist.yaml.example "$PKGDIR"/etc/linux_patch_api/whitelist.yaml
|
# Copy example configs (as .example files - install script creates live configs)
|
||||||
|
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 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
|
# Create PKGBUILD with quoted heredoc to prevent $pkgdir expansion
|
||||||
# $pkgdir must be literal for makepkg to expand at runtime
|
# $pkgdir must be literal for makepkg to expand at runtime
|
||||||
echo "Creating PKGBUILD..."
|
echo "Creating PKGBUILD..."
|
||||||
cat > PKGBUILD << 'EOF'
|
cat > PKGBUILD << 'EOF'
|
||||||
pkgname=linux-patch-api
|
pkgname=linux-patch-api
|
||||||
pkgver=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/')
|
pkgver=VERSION_PLACEHOLDER
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Secure remote package management API for Linux systems"
|
pkgdesc="Secure remote package management API for Linux systems"
|
||||||
url="https://gitea.moon-dragon.us/echo/linux_patch_api"
|
url="https://gitea.moon-dragon.us/echo/linux_patch_api"
|
||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
license=('MIT')
|
license=('MIT')
|
||||||
depends=('systemd')
|
depends=('systemd')
|
||||||
|
install=linux-patch-api.install
|
||||||
|
source=()
|
||||||
|
backup=(
|
||||||
|
'etc/linux_patch_api/config.yaml'
|
||||||
|
'etc/linux_patch_api/whitelist.yaml'
|
||||||
|
)
|
||||||
|
|
||||||
package() {
|
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
|
||||||
|
mkdir -p "$pkgdir"/var/lib/linux_patch_api
|
||||||
|
mkdir -p "$pkgdir"/var/log/linux_patch_api
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Create .SRCINFO
|
# Replace version placeholder with actual version
|
||||||
echo "Creating .SRCINFO..."
|
sed -i "s/VERSION_PLACEHOLDER/$VERSION/" PKGBUILD
|
||||||
|
|
||||||
|
echo "PKGBUILD version: $VERSION"
|
||||||
|
|
||||||
# Build package
|
# Build package
|
||||||
echo "Building Arch package..."
|
|
||||||
|
|
||||||
# For CI environments where we may run as root
|
# For CI environments where we may run as root
|
||||||
if [ "$(id -u)" = "0" ]; then
|
if [ "$(id -u)" = "0" ]; then
|
||||||
echo "Running as root - creating build user for makepkg..."
|
echo "Running as root - creating build user for makepkg..."
|
||||||
@ -69,12 +94,22 @@ if [ "$(id -u)" = "0" ]; then
|
|||||||
cp -r . /home/builduser/repo/
|
cp -r . /home/builduser/repo/
|
||||||
chown -R builduser:builduser /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 --printsrcinfo > .SRCINFO"
|
||||||
su - builduser -c "cd /home/builduser/repo && makepkg -f --noconfirm"
|
su - builduser -c "cd /home/builduser/repo && makepkg -f --noconfirm"
|
||||||
|
|
||||||
# Copy package to releases
|
# 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
|
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
|
else
|
||||||
makepkg --printsrcinfo > .SRCINFO
|
makepkg --printsrcinfo > .SRCINFO
|
||||||
makepkg -f --noconfirm
|
makepkg -f --noconfirm
|
||||||
|
|||||||
19
build-rpm.sh
19
build-rpm.sh
@ -21,27 +21,38 @@ if ! command -v rpmbuild &> /dev/null; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Get version from Cargo.toml
|
||||||
|
VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/')
|
||||||
|
echo "Building version: $VERSION"
|
||||||
|
|
||||||
# Setup RPM build directory structure
|
# Setup RPM build directory structure
|
||||||
mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
|
mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
|
||||||
|
|
||||||
# Create source tarball (required by %autosetup in spec file)
|
# Create source tarball (required by %autosetup in spec file)
|
||||||
echo "Creating source tarball..."
|
echo "Creating source tarball..."
|
||||||
VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/')
|
|
||||||
TMPDIR=$(mktemp -d)
|
TMPDIR=$(mktemp -d)
|
||||||
mkdir -p "$TMPDIR/linux-patch-api-${VERSION}"
|
mkdir -p "$TMPDIR/linux-patch-api-${VERSION}"
|
||||||
# Copy files excluding unwanted directories using find
|
|
||||||
|
# Copy files excluding unnecessary directories
|
||||||
cp -r . "$TMPDIR/linux-patch-api-${VERSION}/"
|
cp -r . "$TMPDIR/linux-patch-api-${VERSION}/"
|
||||||
|
|
||||||
|
# Remove unnecessary directories from tarball
|
||||||
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/target"
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/target"
|
||||||
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/.git"
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/.git"
|
||||||
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/releases"
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/releases"
|
||||||
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/.github"
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/.github"
|
||||||
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/debian"
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/debian"
|
||||||
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/arch-package"
|
||||||
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/.abuild"
|
||||||
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/apk-package"
|
||||||
|
rm -rf "$TMPDIR/linux-patch-api-${VERSION}/.a0proj"
|
||||||
|
|
||||||
tar -czf ~/rpmbuild/SOURCES/linux-patch-api-${VERSION}.tar.gz -C "$TMPDIR" "linux-patch-api-${VERSION}"
|
tar -czf ~/rpmbuild/SOURCES/linux-patch-api-${VERSION}.tar.gz -C "$TMPDIR" "linux-patch-api-${VERSION}"
|
||||||
rm -rf "$TMPDIR"
|
rm -rf "$TMPDIR"
|
||||||
|
|
||||||
# Copy spec file
|
# Prepare spec file with dynamic version
|
||||||
echo "Preparing spec file..."
|
echo "Preparing spec file..."
|
||||||
cp linux-patch-api.spec ~/rpmbuild/SPECS/
|
sed "s/VERSION_PLACEHOLDER/$VERSION/" linux-patch-api.spec > ~/rpmbuild/SPECS/linux-patch-api.spec
|
||||||
|
|
||||||
# Build RPM
|
# Build RPM
|
||||||
echo "Building RPM package..."
|
echo "Building RPM package..."
|
||||||
|
|||||||
@ -1,54 +1,5 @@
|
|||||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
MIIJtTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQOJY6BZQMTvXCEBl6
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg46Ewu04V/qVbFIaW
|
||||||
Rv+0fQICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEJwoQf7hSIurtiBM
|
ll6hUNA1ocfdND68cRv6GiOBikyhRANCAARORR0UUR6G6ndxeefpKai+82eH58ud
|
||||||
nm+YEhwEgglQiyNTxNNkeZ8hikGe3m+2cfXtAituVJYgs4V+bgTJXnrJVaFyPoRw
|
sW5qox3Ed4I0WF12RcSwioAPrt5WNB+ptw0wvzx78wH8CdkqjyUb7Koc
|
||||||
Nde/m9vJU4EGaRwS7Sb89XsjFK+Qbc6+2mvBqhkoBIjXBjYsiqNlLStLUIf1IPdU
|
-----END PRIVATE KEY-----
|
||||||
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
|
|
||||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
||||||
|
|||||||
@ -1,31 +1,12 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIFVzCCAz+gAwIBAgIUO/u3nWWJUG+i/cwM8o/1fkLzfbAwDQYJKoZIhvcNAQEL
|
MIIBsTCCAVegAwIBAgIQVxQmz3/uqfSgf+8ukKa6GTAKBggqhkjOPQQDAjA4MR4w
|
||||||
BQAwOzEZMBcGA1UEAwwQTGludXhQYXRjaEFQSSBDQTERMA8GA1UECgwISW50ZXJu
|
HAYDVQQDDBVQYXRjaCBNYW5hZ2VyIFJvb3QgQ0ExFjAUBgNVBAoMDVBhdGNoIE1h
|
||||||
YWwxCzAJBgNVBAYTAlVTMB4XDTI2MDQwOTIwMTM1MloXDTM2MDQwNjIwMTM1Mlow
|
bmFnZXIwHhcNMjYwNTE4MTU1MjUxWhcNMzYwNTE1MTU1MjUxWjA4MR4wHAYDVQQD
|
||||||
OzEZMBcGA1UEAwwQTGludXhQYXRjaEFQSSBDQTERMA8GA1UECgwISW50ZXJuYWwx
|
DBVQYXRjaCBNYW5hZ2VyIFJvb3QgQ0ExFjAUBgNVBAoMDVBhdGNoIE1hbmFnZXIw
|
||||||
CzAJBgNVBAYTAlVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt+Li
|
WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARORR0UUR6G6ndxeefpKai+82eH58ud
|
||||||
R5RFcfgnm7fHHPg+csakg/C7+Pkb99mCTb+sBGodxNdlryFz3k/c6hFwUJWwfbPL
|
sW5qox3Ed4I0WF12RcSwioAPrt5WNB+ptw0wvzx78wH8CdkqjyUb7Koco0MwQTAP
|
||||||
hsZo8JSxPIrXMhu8n6pDygUSqOx43dkqXURI40FfOaEkSHwYIF73eOV+qUBPTqQZ
|
BgNVHQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBTcLRFILwfBbjqUm3fT8AzIAN5mQDAP
|
||||||
udMc0BGYndpaLk+Lb6rKtEA4r0HkP2fLdO8wOqr68kYiMhhVP3Dw0k1JmtUY3k/k
|
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDMHR7n6plBEz7tP9Si
|
||||||
RcBPQ7C/n+Pr4a0xdIr2TwzNyH+JOp/3oCZW5mZdfaZWXMZhObtT3a8hW0qfc/P5
|
Cs6Rk8m2gt9CL6qHlkeWiDJmtgIgVXrj2Lmqn1dEuKbVu9LaxPyvXU4/t2etWHgJ
|
||||||
3PM1C5jxTBRJiQTQlHsM6EpDS1vZLLU0R5PNRw2U7HgOPhY6iItZDN9NUNo5uGpT
|
lfK+SS8=
|
||||||
5jBR3CumpkCxoGnLuV8+VBngjaovpzp245ERYYU7rox5CrHj1yybw6HuaXXqQncO
|
|
||||||
zDYJwEUINcGiSTlnWyy9iFqA3PInOtAE4YCyscKHH60CxY+/6WvE8yVgTE2SM/At
|
|
||||||
l2UmZhSDIZBMx2GUmRob9FmQCsyb9AnIytkXXBbJtX6wVi0S7TGKixYObnudb6k+
|
|
||||||
DEP/HA7BLRChR/XyDjeHNnsE/cqQeNcGOqP6UHS3rf4L3lIDCLvvKhid73C6/N8r
|
|
||||||
Mz4FvwbwMdw4MHn/WNQBe5+1xkgLLoNRHPXUFwpKcA2ev4JEchb9w9IWiuftJ9BM
|
|
||||||
zzGKlwT9rCw7A0rQMzsaaEMdCF1VPecoTyIxb2kCAwEAAaNTMFEwHQYDVR0OBBYE
|
|
||||||
FGfp3Y5/keT0TeQin1GfU3LalfuWMB8GA1UdIwQYMBaAFGfp3Y5/keT0TeQin1Gf
|
|
||||||
U3LalfuWMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAG7Tkj2S
|
|
||||||
SisI7ggjFXmferutk25v62dLeXJ9eBjnXHQkk6oMJo4TFWgLbo66gb+0mq9c7/rC
|
|
||||||
XsQY3mEnQ3lcujMXoEYGcOM7TOHENj0UX0GiQLexCSZF14IOsf0KGXvB649AhscC
|
|
||||||
N83mdk6GSP2gB8I3wGngbgCtZf/9sq4z6pXVNva+xNskWA7YidY/3pGIMkvRb21v
|
|
||||||
iTXsTGUC4U2/wjohYVLcyu36Dk2YbdAl0gY7JsNGXbT0a/zpo2aY4ogDMXe/828Q
|
|
||||||
gW2ZJWGXeJJKHOgBQw+zmBO+Zgm2vdWWBYCsJVLeVE2SE+LngJGfwgJT7tNb20e6
|
|
||||||
7UBJzhJHIcu73ODNF1TPCNIREVELC4iBXIMvoi3h8Yp7Wo6S8CGk9DY68fXSAkfb
|
|
||||||
oagvxe/rKRgljX70pRl6YOhpMVpl4yUc4BuRlfopRAIDS3AQdNyp9hvMUyj64Gan
|
|
||||||
UIkVXLoDA+7KGw/RPCtC18HWw19nmooh73cWSmGrOjtKu2L5ZsSuD3G6vnmFZaSv
|
|
||||||
HqK08pX+zv2NpYVhiE39zRQ37u9xVjNQsJ/1gnLQ3zOXyidpB8eH+1r5pR7dVjMf
|
|
||||||
wnhnLlm8nty7O0sOy2kiYp1YqosCitOgnLR1U/cgzGX6j0mHUuciY/fRyK1Yifa5
|
|
||||||
UM+xJs/yTc33DYhd4oYQHxqRkletlx2XDW9d
|
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
790CDB9FA2002BF59B3EE88AF326CB060353D111
|
790CDB9FA2002BF59B3EE88AF326CB060353D113
|
||||||
|
|||||||
@ -1,16 +1,8 @@
|
|||||||
-----BEGIN CERTIFICATE REQUEST-----
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
MIICeTCCAWECAQAwNDESMBAGA1UEAwwJY2xpZW50MDAxMREwDwYDVQQKDAhJbnRl
|
MIH7MIGhAgEAMD8xHTAbBgNVBAMMFHBhdGNoLW1hbmFnZXItY2xpZW50MREwDwYD
|
||||||
cm5hbDELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
VQQKDAhJbnRlcm5hbDELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMB
|
||||||
AQC9Tida4so5qerRjEQXQQJb/W4jCsRwZg6lSvvd9qEtqWuwxX+SFfNbcpDOOZTh
|
BwNCAAQauACwaR4SyVoHEPviQgV0I4fbyFuGoHiQExzpYf9Ta025dy88T/a6qG6G
|
||||||
+CWmmCq9v5ZO+XyO/s9xKLnyudnkT/nymB6KFN3XywfDE2iiGshNVNd5d0B4nF7e
|
TYJMtbRSjP/piLWfZ/2ze2AdbmczoAAwCgYIKoZIzj0EAwIDSQAwRgIhAJ/BBYsB
|
||||||
nXeoF938GF5/ny4dkGgg+HoXXrQJ1WGjODXJsXtiiMZPI08kZL4vuYW64VojHvUf
|
aIhKjdwRr0vTqtYPKeeyO2rzHuyRnSvKKkdOAiEA94zCvG0FzkFiqGKT1oHGCVf9
|
||||||
AQdEjGqlIZzNW909g0uaQEizpZwJvH7YGvWuQDx9ywbWrs1t3hHu2ahA+myVXL3Y
|
qZdkjkodRAUk6/4S2AU=
|
||||||
C7+jAmROQ61FHW2F4swS+uRQDTEr9qQs256JCryzHCTma8IWmYqphM9wn18f5Tm7
|
|
||||||
EXw4EHCz5FVL7HPL1vZnQdsrAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAH46n
|
|
||||||
SxI9O21jO1q2cmFlZano5JWAo3eb424+3jCYgAJDBUtlzTLfdkADvttaTtAjI8sh
|
|
||||||
GqbUFsCtO4UlPD5SWFnPdUQqJ+zv1lXDyef0D694mUjgrjtdB27l9wmTnHZVwgcL
|
|
||||||
GEr8nfuhqNNjARmWUJUv629slt0RDZxGm0IXGJBrx39t31oh0q1ll4rPvd9TEiLZ
|
|
||||||
sP8r5WdC2PdFLh13J6erLkoMOOLmM/mXj1egz+ivgqo2uXDX1crBlNH0H1KM05ot
|
|
||||||
c5wJo3mzbRC/3PWLLJHKwQ6ObI88AviGEMevIw54jdz2UHXPv0aK2SSoIDr6GhUi
|
|
||||||
0OBKrqsjBII7l+w+Rw==
|
|
||||||
-----END CERTIFICATE REQUEST-----
|
-----END CERTIFICATE REQUEST-----
|
||||||
|
|||||||
@ -1,28 +1,5 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
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
|
|
||||||
P7wqdvyaMVPLek9tuUINQ4o=
|
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|||||||
@ -1,25 +1,12 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIEPzCCAiegAwIBAgIUeQzbn6IAK/WbPuiK8ybLBgNT0REwDQYJKoZIhvcNAQEL
|
MIIBuzCCAWGgAwIBAgIUeQzbn6IAK/WbPuiK8ybLBgNT0RMwCgYIKoZIzj0EAwIw
|
||||||
BQAwOzEZMBcGA1UEAwwQTGludXhQYXRjaEFQSSBDQTERMA8GA1UECgwISW50ZXJu
|
ODEeMBwGA1UEAwwVUGF0Y2ggTWFuYWdlciBSb290IENBMRYwFAYDVQQKDA1QYXRj
|
||||||
YWwxCzAJBgNVBAYTAlVTMB4XDTI2MDQwOTIwMTQwM1oXDTI3MDQwOTIwMTQwM1ow
|
aCBNYW5hZ2VyMB4XDTI2MDUxODE2MDAwNloXDTI3MDUxODE2MDAwNlowPzEdMBsG
|
||||||
NDESMBAGA1UEAwwJY2xpZW50MDAxMREwDwYDVQQKDAhJbnRlcm5hbDELMAkGA1UE
|
A1UEAwwUcGF0Y2gtbWFuYWdlci1jbGllbnQxETAPBgNVBAoMCEludGVybmFsMQsw
|
||||||
BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9Tida4so5qerR
|
CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBq4ALBpHhLJWgcQ
|
||||||
jEQXQQJb/W4jCsRwZg6lSvvd9qEtqWuwxX+SFfNbcpDOOZTh+CWmmCq9v5ZO+XyO
|
++JCBXQjh9vIW4ageJATHOlh/1NrTbl3LzxP9rqoboZNgky1tFKM/+mItZ9n/bN7
|
||||||
/s9xKLnyudnkT/nymB6KFN3XywfDE2iiGshNVNd5d0B4nF7enXeoF938GF5/ny4d
|
YB1uZzOjQjBAMB0GA1UdDgQWBBQhTcmoHT0HqIuEUkL891TKMlWWjjAfBgNVHSME
|
||||||
kGgg+HoXXrQJ1WGjODXJsXtiiMZPI08kZL4vuYW64VojHvUfAQdEjGqlIZzNW909
|
GDAWgBTcLRFILwfBbjqUm3fT8AzIAN5mQDAKBggqhkjOPQQDAgNIADBFAiApQ6N8
|
||||||
g0uaQEizpZwJvH7YGvWuQDx9ywbWrs1t3hHu2ahA+myVXL3YC7+jAmROQ61FHW2F
|
qQR1vWLU3QNrcIwLxK8g2shV5ggypS/CKkfTgwIhAJdZd0silwqEpPo5ng0I5SJ9
|
||||||
4swS+uRQDTEr9qQs256JCryzHCTma8IWmYqphM9wn18f5Tm7EXw4EHCz5FVL7HPL
|
MOd4Kx0dps2kY/wqgMSI
|
||||||
1vZnQdsrAgMBAAGjQjBAMB0GA1UdDgQWBBStUuU9Si2VnMMQ4VkYyf2pttMhezAf
|
|
||||||
BgNVHSMEGDAWgBRn6d2Of5Hk9E3kIp9Rn1Ny2pX7ljANBgkqhkiG9w0BAQsFAAOC
|
|
||||||
AgEAqWQEAwpW45LWprkr4zpz66azUVkc2I/kuNWLiDEw9Ex4i/5e+ND6Ia7Ayk+T
|
|
||||||
j3rodJA1rn64gJZOzABTb3mpWwNH/DxjF/XGohixl/kn81sNCydimc3qOKL5joUb
|
|
||||||
PDtK9QLTCJmGsYk5lV9K89pR7kBR2rXD70d1GM6KjyBeknEH4oA9/BqMYL5DkeHu
|
|
||||||
v2QWYoECno43eI+Ve4oow5MN/83+VhFLeayCd/JWBYjYi55tqI8QDBn7AY4UAO2C
|
|
||||||
77msurPEqaZn5OtzEW9El/M3/+bDeYfpERgYn2X7bw0oOUZw8g5L9dfc1UxjGY8J
|
|
||||||
NPJAXUKtsDBKzN8nlvrCVmHVrR19vquH7qfh/aKu58MGu3Ovzjz57T/gooi2wmnY
|
|
||||||
4+NJDXZ7ncc7T+40svi7tbLA7MgExuGM+pq/Bxn/PHLPbhyyp7p8EPUFf5KIiqr5
|
|
||||||
GiWL1re8gfe8CAxKDKs5ERtexgoldY1TsMbQ6wjP59rRN3ZbUBGtPsi8bKTEZBpo
|
|
||||||
cM+9bg44ndODpoB8B9NKYCU/n3Uvs+mZMYtAAkLiCUrYplIiCSvUrcDOQWVn1CD1
|
|
||||||
WbuvTTtlIi55NMUi1pvgaFi0PW6Gfin1wRHjt3iLU/i+3Q/b0V+pEL7wgf5bd3U5
|
|
||||||
F6xxNMRjNh1kbZVR0WywzPignBiK9cW+z3d9rPW2FgVoXcI=
|
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
@ -1,16 +1,8 @@
|
|||||||
-----BEGIN CERTIFICATE REQUEST-----
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
MIICfzCCAWcCAQAwOjEYMBYGA1UEAwwPbGludXgtcGF0Y2gtYXBpMREwDwYDVQQK
|
MIH1MIGcAgEAMDoxGDAWBgNVBAMMD2xpbnV4LXBhdGNoLWFwaTERMA8GA1UECgwI
|
||||||
DAhJbnRlcm5hbDELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
SW50ZXJuYWwxCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
||||||
ggEKAoIBAQCu+RZd6OHxdGJdI+C9rS8rowzsYF/qr3p6+Yvp9ySvBzJ20TVWQSrK
|
C32xU18H3OljGW+wQUesT1qSB+bp5cCkNW9rfpv7wjr79eHriZkQ8EgrdVAK9Zw0
|
||||||
Fo1VcDgg7rkTYuRxzxehO0R7pTkxnWqLY6VAA39w5nyVzTwFPv7UovdAZx/U7hnJ
|
fZJNdd4LyekDGXiQU/qAJ6AAMAoGCCqGSM49BAMCA0gAMEUCIQDf7FSy4YiZvWkj
|
||||||
Zj7ndtxuqYk1tkx94NLjYXUCWqy48/tKQXobQh3qXeQ6HfwFSI5xpy61quQBZkJz
|
G9BgdSPTcIq8VYSGm7nnXprD8u1ZTwIgO6/5jH72reiCaaMm62X1Vrpc+8SDMVtO
|
||||||
VAatcOv/fhn3K+TrgBaKKkXFNQ3jjKhzrH3Z0son1+GNyhHvQlvCJ+jdWDpzDvSP
|
+dlP4dZ+BM8=
|
||||||
XpqEDmxCQvdBdzGVAPrv3fmBMyOQFnHOTHmKtJ806jBFsYEUwnXKA4/xtaihl1OL
|
|
||||||
bz85Z6MicH1PwTo4v0Z7ngIcyoxlgX/RAgMBAAGgADANBgkqhkiG9w0BAQsFAAOC
|
|
||||||
AQEAPaBJ7ryKBUuKoUGsgb+fc9GIbGomCbWZnPFx3ZJcUZfeb4/Qi1glhe1GiiUt
|
|
||||||
np5x0cjgw5he6zd13lgylglsYrSHEJDV2MqVoHqCwFH+m+ODnZvnQkrgxW4t+JEK
|
|
||||||
wEwp0dRGLXsshDPWg5Xe/SaFBfvuCWEkWkcQ4NYwg5SOVn0TCAVy2VKmdDW1KHtf
|
|
||||||
GkqHdUiIs5FX6kXIMryQpIG6OXyJCQ3pGv+kSlfaeobnqUUASWwBAaubZBxnqTIl
|
|
||||||
Daj2End8iYQ9Fiv7z0YFxJrULSt5qhtRivmUHjSOyv0tlPs+aG9mP9j14ND2/ZIA
|
|
||||||
ihOZrIUTTxaaVL9IxIVnTt7tFw==
|
|
||||||
-----END CERTIFICATE REQUEST-----
|
-----END CERTIFICATE REQUEST-----
|
||||||
|
|||||||
@ -1,28 +1,5 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
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
|
|
||||||
pLYlvvPbeUK7Ue1jXJ8i4yE=
|
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|||||||
@ -1,25 +1,12 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIERTCCAi2gAwIBAgIUeQzbn6IAK/WbPuiK8ybLBgNT0RAwDQYJKoZIhvcNAQEL
|
MIIBtjCCAVygAwIBAgIUeQzbn6IAK/WbPuiK8ybLBgNT0RIwCgYIKoZIzj0EAwIw
|
||||||
BQAwOzEZMBcGA1UEAwwQTGludXhQYXRjaEFQSSBDQTERMA8GA1UECgwISW50ZXJu
|
ODEeMBwGA1UEAwwVUGF0Y2ggTWFuYWdlciBSb290IENBMRYwFAYDVQQKDA1QYXRj
|
||||||
YWwxCzAJBgNVBAYTAlVTMB4XDTI2MDQwOTIwMTQwM1oXDTI3MDQwOTIwMTQwM1ow
|
aCBNYW5hZ2VyMB4XDTI2MDUxODE2MDAwNloXDTI3MDUxODE2MDAwNlowOjEYMBYG
|
||||||
OjEYMBYGA1UEAwwPbGludXgtcGF0Y2gtYXBpMREwDwYDVQQKDAhJbnRlcm5hbDEL
|
A1UEAwwPbGludXgtcGF0Y2gtYXBpMREwDwYDVQQKDAhJbnRlcm5hbDELMAkGA1UE
|
||||||
MAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCu+RZd
|
BhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQLfbFTXwfc6WMZb7BBR6xP
|
||||||
6OHxdGJdI+C9rS8rowzsYF/qr3p6+Yvp9ySvBzJ20TVWQSrKFo1VcDgg7rkTYuRx
|
WpIH5unlwKQ1b2t+m/vCOvv14euJmRDwSCt1UAr1nDR9kk113gvJ6QMZeJBT+oAn
|
||||||
zxehO0R7pTkxnWqLY6VAA39w5nyVzTwFPv7UovdAZx/U7hnJZj7ndtxuqYk1tkx9
|
o0IwQDAdBgNVHQ4EFgQUDTnKCjj1BJ0MdwJHPUGf0raJ6/kwHwYDVR0jBBgwFoAU
|
||||||
4NLjYXUCWqy48/tKQXobQh3qXeQ6HfwFSI5xpy61quQBZkJzVAatcOv/fhn3K+Tr
|
3C0RSC8HwW46lJt30/AMyADeZkAwCgYIKoZIzj0EAwIDSAAwRQIhAJ4jy8W2hbqK
|
||||||
gBaKKkXFNQ3jjKhzrH3Z0son1+GNyhHvQlvCJ+jdWDpzDvSPXpqEDmxCQvdBdzGV
|
kiTI9aYS+xwMJlxH6cFJaKplrA+a5Ay8AiANPJdJN9ucgCsq/N3Ai6kO89rcXy8Z
|
||||||
APrv3fmBMyOQFnHOTHmKtJ806jBFsYEUwnXKA4/xtaihl1OLbz85Z6MicH1PwTo4
|
60kvNNc3Zg/Oog==
|
||||||
v0Z7ngIcyoxlgX/RAgMBAAGjQjBAMB0GA1UdDgQWBBTgNxkszZsl/UI2Kri5QJb8
|
|
||||||
VrHASzAfBgNVHSMEGDAWgBRn6d2Of5Hk9E3kIp9Rn1Ny2pX7ljANBgkqhkiG9w0B
|
|
||||||
AQsFAAOCAgEALx4MmEyFsmmpFS9JvKnkRi3AMn7ePRdg0nONEd735z1grnKNTjmH
|
|
||||||
PJLErX3aD4lCxqyBhyqJaCCZRF1CRkE3wWTGyXSlab9RgXHTU9AiSvopEdgSiISt
|
|
||||||
CI3X7uGqss3cERZcKLuM7JDTVdhtOouNbfwvG40hz6lm+OcQo7F3/z/boqKkFd+o
|
|
||||||
yXLDJFCVaXgslCp1+fts7aFXpqAwj7tedzB2a7M1ncTOwvP//bnYjm/FygOhj0No
|
|
||||||
4tNX2liUnfjbMqNFszxYl+ZtYYjrt23YwNPdVhF0oY2ludh16lluJHZECji2DzH0
|
|
||||||
275M5DsgQcQpZmA77px0i+piNuCoS4wFJQDeQmtp2loGHa123zJra/kAINayf0WF
|
|
||||||
S0dPAqXwBGj2WGP1uBNOLghV4MZaYuav0xWSMuTv2TW3ZsOYzYXQk0hMe7W7oIuZ
|
|
||||||
VAcaw9ZT8wAFwo+unvzGIWtxSZ3sykK6thBEo8lqRkmqDCkDE86mb6BviQj1NBSP
|
|
||||||
+KrmZJ8vuvqfr1Oav/7Vk5qYoNprqZand6A1hnLxS9q/JZcr0Fj+Z7OS1G3hLrjd
|
|
||||||
3oN6SdNWAVkznIBe0J+Ry29My/GniBbytJgXVi+4ROO5GGmtuDCMkFqOZcm6f8BW
|
|
||||||
faPQWiWB5EY6ZuqgLgydGQ3qf1a5b8z1EzmiDZf5qRUdfddOCsljgiw=
|
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
@ -17,10 +17,10 @@ depend() {
|
|||||||
|
|
||||||
# Create required directories before starting
|
# Create required directories before starting
|
||||||
start_pre() {
|
start_pre() {
|
||||||
checkpath --directory --owner linux-patch-api:linux-patch-api --mode 0755 \
|
checkpath --directory --owner root:root --mode 0755 \
|
||||||
/run/linux-patch-api \
|
/run/linux-patch-api \
|
||||||
/var/log/linux-patch-api \
|
/var/log/linux_patch_api \
|
||||||
/var/lib/linux-patch-api \
|
/var/lib/linux_patch_api \
|
||||||
/etc/linux_patch_api/certs
|
/etc/linux_patch_api/certs
|
||||||
|
|
||||||
# Ensure config files exist
|
# Ensure config files exist
|
||||||
|
|||||||
81
configs/linux-patch-api.install
Normal file
81
configs/linux-patch-api.install
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# Arch Linux install hooks for linux-patch-api
|
||||||
|
# Matches Debian preinst/postinst behavior: no system user, root:root ownership
|
||||||
|
|
||||||
|
post_install() {
|
||||||
|
# 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 (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
|
||||||
|
chmod 750 /etc/linux_patch_api/certs
|
||||||
|
chmod 755 /var/lib/linux_patch_api
|
||||||
|
chmod 755 /var/log/linux_patch_api
|
||||||
|
|
||||||
|
# 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 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 root:root /etc/linux_patch_api/whitelist.yaml
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reload systemd daemon
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
# Enable the service (but don't start automatically - admin should configure first)
|
||||||
|
systemctl enable linux-patch-api.service
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "linux-patch-api installed successfully!"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Configure /etc/linux_patch_api/config.yaml with your settings"
|
||||||
|
echo " 2. Place TLS certificates in /etc/linux_patch_api/certs/"
|
||||||
|
echo " 3. Configure IP whitelist in /etc/linux_patch_api/whitelist.yaml"
|
||||||
|
echo " 4. Start the service: systemctl start linux-patch-api"
|
||||||
|
echo " 5. Check status: systemctl status linux-patch-api"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
post_upgrade() {
|
||||||
|
# Reload systemd daemon on upgrade
|
||||||
|
systemctl daemon-reload
|
||||||
|
}
|
||||||
|
|
||||||
|
pre_remove() {
|
||||||
|
# Stop the service before removal
|
||||||
|
if systemctl is-active --quiet linux-patch-api.service; then
|
||||||
|
systemctl stop linux-patch-api.service
|
||||||
|
echo "Service stopped successfully"
|
||||||
|
else
|
||||||
|
echo "Service was not running"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Disable the service
|
||||||
|
if systemctl is-enabled --quiet linux-patch-api.service 2>/dev/null; then
|
||||||
|
systemctl disable linux-patch-api.service
|
||||||
|
echo "Service disabled"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
post_remove() {
|
||||||
|
# Reload systemd to remove service file
|
||||||
|
systemctl daemon-reload 2>/dev/null || true
|
||||||
|
|
||||||
|
# Remove directories only if empty (preserve user data on upgrade/reinstall)
|
||||||
|
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
|
||||||
|
|
||||||
|
echo "linux-patch-api removed"
|
||||||
|
}
|
||||||
10
configs/linux-patch-api.post-deinstall
Normal file
10
configs/linux-patch-api.post-deinstall
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Alpine Linux post-deinstall script for linux-patch-api
|
||||||
|
# Runs after package files are removed
|
||||||
|
# Matches Debian postrm behavior: clean up empty directories
|
||||||
|
|
||||||
|
# Remove directories only if empty (preserve user data on reinstall)
|
||||||
|
rmdir /var/lib/linux_patch_api 2>/dev/null || true
|
||||||
|
rmdir /var/log/linux_patch_api 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "linux-patch-api removed"
|
||||||
35
configs/linux-patch-api.post-install
Normal file
35
configs/linux-patch-api.post-install
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Alpine Linux post-install script for linux-patch-api
|
||||||
|
# Runs after package files are laid down
|
||||||
|
# Matches Debian postinst behavior: copy example configs, enable service
|
||||||
|
|
||||||
|
# Copy example configs if they don't exist
|
||||||
|
if [ ! -f "/etc/linux_patch_api/config.yaml" ]; then
|
||||||
|
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 root:root /etc/linux_patch_api/config.yaml
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "/etc/linux_patch_api/whitelist.yaml" ]; then
|
||||||
|
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 root:root /etc/linux_patch_api/whitelist.yaml
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable the service (but don't start automatically - admin should configure first)
|
||||||
|
rc-update add linux-patch-api default
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "linux-patch-api installed successfully!"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Configure /etc/linux_patch_api/config.yaml with your settings"
|
||||||
|
echo " 2. Place TLS certificates in /etc/linux_patch_api/certs/"
|
||||||
|
echo " 3. Configure IP whitelist in /etc/linux_patch_api/whitelist.yaml"
|
||||||
|
echo " 4. Start the service: rc-service linux-patch-api start"
|
||||||
|
echo " 5. Check status: rc-service linux-patch-api status"
|
||||||
|
echo ""
|
||||||
15
configs/linux-patch-api.pre-deinstall
Normal file
15
configs/linux-patch-api.pre-deinstall
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Alpine Linux pre-deinstall script for linux-patch-api
|
||||||
|
# Runs before package files are removed
|
||||||
|
# Matches Debian prerm behavior: stop and disable service
|
||||||
|
|
||||||
|
# Stop the service if running
|
||||||
|
if rc-service linux-patch-api status >/dev/null 2>&1; then
|
||||||
|
rc-service linux-patch-api stop
|
||||||
|
echo "Service stopped"
|
||||||
|
else
|
||||||
|
echo "Service was not running"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Disable the service
|
||||||
|
rc-update del linux-patch-api default 2>/dev/null || true
|
||||||
19
configs/linux-patch-api.pre-install
Normal file
19
configs/linux-patch-api.pre-install
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Alpine Linux pre-install script for linux-patch-api
|
||||||
|
# Runs before package files are laid down
|
||||||
|
# Matches Debian preinst behavior: create directories, set permissions
|
||||||
|
|
||||||
|
# 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 (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
|
||||||
|
chmod 750 /etc/linux_patch_api/certs
|
||||||
|
chmod 755 /var/lib/linux_patch_api
|
||||||
|
chmod 755 /var/log/linux_patch_api
|
||||||
38
debian/changelog
vendored
38
debian/changelog
vendored
@ -1,3 +1,41 @@
|
|||||||
|
linux-patch-api (1.1.10-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Fix Alpine install scripts: use separate files with valid abuild suffixes
|
||||||
|
* Root cause: .apk-install is not a valid abuild suffix (abuild silently fails)
|
||||||
|
* Correct format: pkgname.pre-install, .post-install, .pre-deinstall, .post-deinstall
|
||||||
|
* Verified on actual Alpine runner: install script suffixes now pass abuild validation
|
||||||
|
|
||||||
|
-- Echo <echo@moon-dragon.us> Wed, 20 May 2026 07:43:00 -0500
|
||||||
|
|
||||||
|
linux-patch-api (1.1.9-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Fix non-Ubuntu packages: align Arch, RPM, Alpine with Debian baseline
|
||||||
|
* Remove system user creation (service runs as root)
|
||||||
|
* Fix ownership to root:root across all platforms
|
||||||
|
* Fix Alpine: co-locate install script with APKBUILD
|
||||||
|
* Fix Arch: correct $startdir path in PKGBUILD
|
||||||
|
* Fix RPM: add runtime deps, comment BuildRequires for CI
|
||||||
|
* Add comprehensive installation docs for all platforms
|
||||||
|
|
||||||
|
-- Echo <echo@moon-dragon.us> Tue, 19 May 2026 21:54:00 -0500
|
||||||
|
|
||||||
|
linux-patch-api (1.1.8-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Fix FQDN resolution: prioritize hostname -f over /etc/hostname for full domain
|
||||||
|
* Fix display_name blank: add hostname field to enrollment request
|
||||||
|
* Fix Arch package: add install scripts, user creation, directory creation
|
||||||
|
* Fix Alpine package: add install scripts, user creation, missing config.yaml
|
||||||
|
* Fix RPM package: dynamic version, config handling, tarball exclusions
|
||||||
|
|
||||||
|
-- Echo <echo@moon-dragon.us> Mon, 18 May 2026 19:34:00 -0500
|
||||||
|
|
||||||
|
linux-patch-api (1.1.7-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Fix CI pipeline: add cargo clean and remove old .deb artifacts before packaging
|
||||||
|
* Bump version to 1.1.7 to ensure clean build with correct binary
|
||||||
|
|
||||||
|
-- Echo <echo@moon-dragon.us> Mon, 18 May 2026 12:20:00 -0500
|
||||||
|
|
||||||
linux-patch-api (1.1.6-1) unstable; urgency=low
|
linux-patch-api (1.1.6-1) unstable; urgency=low
|
||||||
|
|
||||||
* Fix rustls CryptoProvider initialization panic on server startup
|
* Fix rustls CryptoProvider initialization panic on server startup
|
||||||
|
|||||||
0
debian/rules
vendored
Normal file → Executable file
0
debian/rules
vendored
Normal file → Executable file
@ -1,7 +1,7 @@
|
|||||||
%global debug_package %{nil}
|
%global debug_package %{nil}
|
||||||
|
|
||||||
Name: linux-patch-api
|
Name: linux-patch-api
|
||||||
Version: 1.0.0
|
Version: VERSION_PLACEHOLDER
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: Secure remote package management API for Linux systems
|
Summary: Secure remote package management API for Linux systems
|
||||||
License: MIT
|
License: MIT
|
||||||
@ -10,19 +10,22 @@ Source0: linux-patch-api-%{version}.tar.gz
|
|||||||
BuildArch: x86_64
|
BuildArch: x86_64
|
||||||
|
|
||||||
# Build requirements
|
# Build requirements
|
||||||
# NOTE: Building in Debian container (node:18) - apt packages don't register in RPM db
|
# NOTE: CI uses rustup to install cargo/rust, so they are NOT available as RPM packages.
|
||||||
# Build tools ARE available (installed via apt-get in ci.yml), just won't validate
|
# Only uncomment BuildRequires for native RPM build environments where cargo/rust
|
||||||
|
# are installed via dnf/yum package manager.
|
||||||
# BuildRequires: cargo >= 1.75
|
# BuildRequires: cargo >= 1.75
|
||||||
# BuildRequires: rust >= 1.75
|
# BuildRequires: rust >= 1.75
|
||||||
# BuildRequires: systemd-rpm-macros # Handling systemd manually
|
|
||||||
# BuildRequires: pkgconfig(systemd)
|
|
||||||
# BuildRequires: gcc
|
# BuildRequires: gcc
|
||||||
|
# BuildRequires: openssl-devel
|
||||||
|
# BuildRequires: systemd-devel
|
||||||
|
# BuildRequires: pkgconfig(systemd)
|
||||||
|
|
||||||
# Runtime requirements
|
# Runtime requirements
|
||||||
Requires: systemd
|
Requires: systemd
|
||||||
Requires: libsystemd
|
Requires: libsystemd
|
||||||
|
Requires: openssl-libs
|
||||||
|
Requires: ca-certificates
|
||||||
|
|
||||||
# Description
|
|
||||||
%description
|
%description
|
||||||
Linux Patch API provides a secure, mTLS-authenticated REST API for
|
Linux Patch API provides a secure, mTLS-authenticated REST API for
|
||||||
remote package management operations including:
|
remote package management operations including:
|
||||||
@ -69,28 +72,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
|
cp configs/whitelist.yaml.example %{buildroot}/etc/linux_patch_api/whitelist.yaml.example
|
||||||
chmod 644 %{buildroot}/etc/linux_patch_api/*.example
|
chmod 644 %{buildroot}/etc/linux_patch_api/*.example
|
||||||
|
|
||||||
# Pre-installation script
|
# Pre-installation script - create directories (matches Debian preinst)
|
||||||
%pre
|
%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
|
# Create required directories
|
||||||
mkdir -p /etc/linux_patch_api/certs
|
mkdir -p /etc/linux_patch_api/certs
|
||||||
mkdir -p /var/lib/linux_patch_api
|
mkdir -p /var/lib/linux_patch_api
|
||||||
mkdir -p /var/log/linux_patch_api
|
mkdir -p /var/log/linux_patch_api
|
||||||
|
|
||||||
# Set proper ownership
|
# Set proper ownership (service runs as root)
|
||||||
chown -R linux-patch-api:linux-patch-api /var/lib/linux_patch_api
|
chown -R root:root /var/lib/linux_patch_api
|
||||||
chown -R linux-patch-api:linux-patch-api /var/log/linux_patch_api
|
chown -R root:root /var/log/linux_patch_api
|
||||||
|
|
||||||
# Set secure permissions
|
# Set secure permissions
|
||||||
chmod 750 /etc/linux_patch_api
|
chmod 750 /etc/linux_patch_api
|
||||||
@ -98,19 +89,19 @@ chmod 750 /etc/linux_patch_api/certs
|
|||||||
chmod 755 /var/lib/linux_patch_api
|
chmod 755 /var/lib/linux_patch_api
|
||||||
chmod 755 /var/log/linux_patch_api
|
chmod 755 /var/log/linux_patch_api
|
||||||
|
|
||||||
# Post-installation script
|
# Post-installation script - copy configs, enable service (matches Debian postinst)
|
||||||
%post
|
%post
|
||||||
# Copy example configs if they don't exist
|
# Copy example configs if they don't exist
|
||||||
if [ ! -f "/etc/linux_patch_api/config.yaml" ]; then
|
if [ ! -f "/etc/linux_patch_api/config.yaml" ]; then
|
||||||
cp /etc/linux_patch_api/config.yaml.example /etc/linux_patch_api/config.yaml
|
cp /etc/linux_patch_api/config.yaml.example /etc/linux_patch_api/config.yaml
|
||||||
chmod 640 /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
|
||||||
|
|
||||||
if [ ! -f "/etc/linux_patch_api/whitelist.yaml" ]; then
|
if [ ! -f "/etc/linux_patch_api/whitelist.yaml" ]; then
|
||||||
cp /etc/linux_patch_api/whitelist.yaml.example /etc/linux_patch_api/whitelist.yaml
|
cp /etc/linux_patch_api/whitelist.yaml.example /etc/linux_patch_api/whitelist.yaml
|
||||||
chmod 640 /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
|
||||||
|
|
||||||
# Reload systemd daemon
|
# Reload systemd daemon
|
||||||
@ -162,6 +153,8 @@ fi
|
|||||||
/lib/systemd/system/linux-patch-api.service
|
/lib/systemd/system/linux-patch-api.service
|
||||||
%config(noreplace) /etc/linux_patch_api/config.yaml.example
|
%config(noreplace) /etc/linux_patch_api/config.yaml.example
|
||||||
%config(noreplace) /etc/linux_patch_api/whitelist.yaml.example
|
%config(noreplace) /etc/linux_patch_api/whitelist.yaml.example
|
||||||
|
%ghost %config(noreplace) /etc/linux_patch_api/config.yaml
|
||||||
|
%ghost %config(noreplace) /etc/linux_patch_api/whitelist.yaml
|
||||||
%dir /etc/linux_patch_api
|
%dir /etc/linux_patch_api
|
||||||
%dir /etc/linux_patch_api/certs
|
%dir /etc/linux_patch_api/certs
|
||||||
%dir /var/lib/linux_patch_api
|
%dir /var/lib/linux_patch_api
|
||||||
@ -169,7 +162,33 @@ fi
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
%changelog
|
%changelog
|
||||||
* Thu Apr 09 2026 Echo <echo@moon-dragon.us> - 1.0.0-1
|
* Wed May 20 2026 Echo <echo@moon-dragon.us> - 1.1.10-1
|
||||||
|
- Fix Alpine install scripts: use separate files with valid abuild suffixes
|
||||||
|
- Root cause: .apk-install is not a valid abuild suffix (abuild silently fails)
|
||||||
|
- Correct format: pkgname.pre-install, .post-install, .pre-deinstall, .post-deinstall
|
||||||
|
- Verified on actual Alpine runner: install script suffixes now pass abuild validation
|
||||||
|
|
||||||
|
* Tue May 19 2026 Echo <echo@moon-dragon.us> - 1.1.9-1
|
||||||
|
- Fix non-Ubuntu packages: align Arch, RPM, Alpine with Debian baseline
|
||||||
|
- Remove system user creation (service runs as root)
|
||||||
|
- Fix ownership to root:root across all platforms
|
||||||
|
- Fix Alpine: co-locate install script with APKBUILD
|
||||||
|
- Fix Arch: correct $startdir path in PKGBUILD
|
||||||
|
- Fix RPM: add runtime deps, comment BuildRequires for CI
|
||||||
|
- Add comprehensive installation docs for all platforms
|
||||||
|
|
||||||
|
* Tue May 19 2026 Echo <echo@moon-dragon.us> - 1.1.8-1
|
||||||
|
- Fix RPM packaging: runtime deps, match Debian install behavior, comment BuildRequires for CI
|
||||||
|
- 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 <echo@moon-dragon.us> - 1.1.8-1
|
||||||
|
- Fix FQDN resolution: prioritize hostname -f over /etc/hostname
|
||||||
|
- Fix display_name blank: add hostname field to enrollment request
|
||||||
|
- Fix Arch/Alpine/RPM packaging: install scripts, user creation, directory creation
|
||||||
|
|
||||||
|
* Thu Apr 09 2026 Echo <echo@moon-dragon.us> - 1.1.7-1
|
||||||
- Initial production release
|
- Initial production release
|
||||||
- Secure mTLS-authenticated REST API for remote package management
|
- Secure mTLS-authenticated REST API for remote package management
|
||||||
- 15 API endpoints for package install/remove, patch application, system management
|
- 15 API endpoints for package install/remove, patch application, system management
|
||||||
|
|||||||
@ -18,6 +18,10 @@ pub struct EnrollmentRequest {
|
|||||||
pub fqdn: String,
|
pub fqdn: String,
|
||||||
pub ip_address: String,
|
pub ip_address: String,
|
||||||
pub os_details: serde_json::Value,
|
pub os_details: serde_json::Value,
|
||||||
|
/// Short hostname (from /etc/hostname or hostname command).
|
||||||
|
/// Used by the manager to populate `display_name` on approval.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub hostname: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Response from `POST /api/v1/enroll` (HTTP 202).
|
/// Response from `POST /api/v1/enroll` (HTTP 202).
|
||||||
@ -220,12 +224,18 @@ impl EnrollmentClient {
|
|||||||
let os_details = identity::get_os_details()
|
let os_details = identity::get_os_details()
|
||||||
.context("Failed to collect OS details — /etc/os-release may be missing")?;
|
.context("Failed to collect OS details — /etc/os-release may be missing")?;
|
||||||
|
|
||||||
// 2. Build EnrollmentRequest struct
|
// 2. Collect short hostname for display_name on manager
|
||||||
|
let hostname = identity::get_hostname()
|
||||||
|
.map_err(|e| tracing::warn!(error = %e, "Failed to determine hostname — display_name will use FQDN fallback"))
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
// 3. Build EnrollmentRequest struct
|
||||||
let request = EnrollmentRequest {
|
let request = EnrollmentRequest {
|
||||||
machine_id,
|
machine_id,
|
||||||
fqdn,
|
fqdn,
|
||||||
ip_address,
|
ip_address,
|
||||||
os_details,
|
os_details,
|
||||||
|
hostname,
|
||||||
};
|
};
|
||||||
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
@ -502,6 +512,7 @@ mod tests {
|
|||||||
fqdn: "node.example.com".into(),
|
fqdn: "node.example.com".into(),
|
||||||
ip_address: "192.168.1.10".into(),
|
ip_address: "192.168.1.10".into(),
|
||||||
os_details: serde_json::json!({"distro": "Debian", "version": "12"}),
|
os_details: serde_json::json!({"distro": "Debian", "version": "12"}),
|
||||||
|
hostname: Some("node".into()),
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&request).expect("Failed to serialize EnrollmentRequest");
|
let json = serde_json::to_string(&request).expect("Failed to serialize EnrollmentRequest");
|
||||||
assert!(json.contains("machine_id"));
|
assert!(json.contains("machine_id"));
|
||||||
|
|||||||
@ -31,36 +31,113 @@ pub fn get_machine_id() -> Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve the fully-qualified domain name.
|
/// Resolve the fully-qualified domain name.
|
||||||
/// Strategy: `gethostname` via std → fallback to `hostname` CLI → "localhost".
|
///
|
||||||
|
/// Strategy (in priority order):
|
||||||
|
/// 1. `hostname -f` → if result contains `.`, it's a real FQDN
|
||||||
|
/// 2. `hostname` + `hostname -d` → combine short hostname + domain
|
||||||
|
/// 3. `/etc/hostname` → short hostname fallback
|
||||||
|
/// 4. `hostname` command → last resort
|
||||||
|
/// 5. `"localhost"` → final fallback
|
||||||
pub fn get_fqdn() -> Result<String> {
|
pub fn get_fqdn() -> Result<String> {
|
||||||
// Try reading from hostname file first (common on systemd systems)
|
// 1. Try `hostname -f` — returns FQDN on properly configured systems
|
||||||
|
if let Ok(output) = Command::new("hostname").arg("-f").output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let name = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||||
|
if !name.is_empty() && name.contains('.') && name != "(none)" {
|
||||||
|
tracing::debug!(fqdn = %name, "Resolved FQDN via hostname -f");
|
||||||
|
return Ok(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Try combining short hostname + domain from `hostname -d`
|
||||||
|
if let Ok(short_output) = Command::new("hostname").output() {
|
||||||
|
if short_output.status.success() {
|
||||||
|
let short = String::from_utf8_lossy(&short_output.stdout)
|
||||||
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
if !short.is_empty() && short != "(none)" {
|
||||||
|
if let Ok(domain_output) = Command::new("hostname").arg("-d").output() {
|
||||||
|
if domain_output.status.success() {
|
||||||
|
let domain = String::from_utf8_lossy(&domain_output.stdout)
|
||||||
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
if !domain.is_empty() {
|
||||||
|
let fqdn = format!("{}.{}", short, domain);
|
||||||
|
tracing::debug!(fqdn = %fqdn, "Resolved FQDN via hostname + hostname -d");
|
||||||
|
return Ok(fqdn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Domain not available — fall through to try other methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Try reading from /etc/hostname (common on systemd systems, usually short hostname)
|
||||||
if let Ok(name) = fs::read_to_string("/etc/hostname") {
|
if let Ok(name) = fs::read_to_string("/etc/hostname") {
|
||||||
let trimmed = name.trim().to_string();
|
let trimmed = name.trim().to_string();
|
||||||
if !trimmed.is_empty() && trimmed != "(none)" {
|
if !trimmed.is_empty() && trimmed != "(none)" {
|
||||||
|
tracing::debug!(hostname = %trimmed, "Resolved hostname via /etc/hostname (may be short)");
|
||||||
return Ok(trimmed);
|
return Ok(trimmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to hostname command
|
// 4. Fallback to plain hostname command
|
||||||
if let Ok(output) = Command::new("hostname").arg("-f").output() {
|
|
||||||
if output.status.success() {
|
|
||||||
let name = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
||||||
if !name.is_empty() {
|
|
||||||
return Ok(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to plain hostname
|
|
||||||
if let Ok(output) = Command::new("hostname").output() {
|
if let Ok(output) = Command::new("hostname").output() {
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
let name = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
let name = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
|
tracing::debug!(hostname = %name, "Resolved hostname via hostname command");
|
||||||
return Ok(name);
|
return Ok(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. Final fallback
|
||||||
|
tracing::warn!("Could not determine hostname — falling back to localhost");
|
||||||
|
Ok("localhost".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve the short hostname (without domain).
|
||||||
|
///
|
||||||
|
/// Strategy: `/etc/hostname` → `hostname` command → split FQDN on `.` → `"localhost"`.
|
||||||
|
pub fn get_hostname() -> Result<String> {
|
||||||
|
// Try reading from /etc/hostname (usually contains the short hostname)
|
||||||
|
if let Ok(name) = fs::read_to_string("/etc/hostname") {
|
||||||
|
let trimmed = name.trim().to_string();
|
||||||
|
if !trimmed.is_empty() && trimmed != "(none)" {
|
||||||
|
// If it contains a dot, take just the first component
|
||||||
|
let short = trimmed.split('.').next().unwrap_or(&trimmed).to_string();
|
||||||
|
tracing::debug!(hostname = %short, "Resolved short hostname via /etc/hostname");
|
||||||
|
return Ok(short);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try hostname command
|
||||||
|
if let Ok(output) = Command::new("hostname").output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let name = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||||
|
if !name.is_empty() {
|
||||||
|
// If it contains a dot, take just the first component
|
||||||
|
let short = name.split('.').next().unwrap_or(&name).to_string();
|
||||||
|
tracing::debug!(hostname = %short, "Resolved short hostname via hostname command");
|
||||||
|
return Ok(short);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try splitting FQDN from get_fqdn()
|
||||||
|
if let Ok(fqdn) = get_fqdn() {
|
||||||
|
if fqdn != "localhost" && fqdn.contains('.') {
|
||||||
|
let short = fqdn.split('.').next().unwrap_or(&fqdn).to_string();
|
||||||
|
tracing::debug!(hostname = %short, "Resolved short hostname by splitting FQDN");
|
||||||
|
return Ok(short);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback
|
||||||
|
tracing::warn!("Could not determine short hostname — falling back to localhost");
|
||||||
Ok("localhost".into())
|
Ok("localhost".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +443,56 @@ mod tests {
|
|||||||
assert!(!fqdn.is_empty(), "FQDN should not be empty");
|
assert!(!fqdn.is_empty(), "FQDN should not be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fqdn_prefers_full_domain() {
|
||||||
|
// If hostname -f returns a value with a dot, get_fqdn should return it
|
||||||
|
// (not the short hostname from /etc/hostname)
|
||||||
|
let fqdn = get_fqdn().expect("Failed to get FQDN");
|
||||||
|
// On properly configured systems, FQDN should contain at least one dot
|
||||||
|
// If it doesn't, it's likely a short hostname from /etc/hostname
|
||||||
|
if fqdn.contains('.') {
|
||||||
|
// FQDN contains domain — good
|
||||||
|
assert!(
|
||||||
|
fqdn.split('.').count() >= 2,
|
||||||
|
"FQDN should have at least host.domain format, got: {}",
|
||||||
|
fqdn
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// If no dot, it's a short hostname — acceptable fallback but not ideal
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hostname_is_not_empty() {
|
||||||
|
let hostname = get_hostname().expect("Failed to get hostname");
|
||||||
|
assert!(!hostname.is_empty(), "Hostname should not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hostname_is_short_form() {
|
||||||
|
let hostname = get_hostname().expect("Failed to get hostname");
|
||||||
|
// Short hostname should NOT contain dots
|
||||||
|
assert!(
|
||||||
|
!hostname.contains('.'),
|
||||||
|
"Short hostname should not contain dots, got: {}",
|
||||||
|
hostname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hostname_is_prefix_of_fqdn() {
|
||||||
|
let hostname = get_hostname().expect("Failed to get hostname");
|
||||||
|
let fqdn = get_fqdn().expect("Failed to get FQDN");
|
||||||
|
// If FQDN contains a dot, hostname should be the first component
|
||||||
|
if fqdn.contains('.') {
|
||||||
|
let fqdn_prefix = fqdn.split('.').next().unwrap_or(&fqdn);
|
||||||
|
assert_eq!(
|
||||||
|
hostname, fqdn_prefix,
|
||||||
|
"Short hostname '{}' should match FQDN prefix '{}'",
|
||||||
|
hostname, fqdn_prefix
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn os_details_contains_kernel() {
|
fn os_details_contains_kernel() {
|
||||||
let details = get_os_details().expect("Failed to get OS details");
|
let details = get_os_details().expect("Failed to get OS details");
|
||||||
|
|||||||
@ -16,7 +16,7 @@ pub use client::{
|
|||||||
};
|
};
|
||||||
/// Re-export identity extraction functions.
|
/// Re-export identity extraction functions.
|
||||||
pub use identity::{
|
pub use identity::{
|
||||||
get_fqdn, get_ip_addresses, get_ip_for_interface, get_machine_id, get_os_details,
|
get_fqdn, get_hostname, get_ip_addresses, get_ip_for_interface, get_machine_id, get_os_details,
|
||||||
get_primary_ip, get_route_source_ip, is_container_bridge, is_link_local,
|
get_primary_ip, get_route_source_ip, is_container_bridge, is_link_local,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
34
tasks/fix-non-ubuntu-packages.md
Normal file
34
tasks/fix-non-ubuntu-packages.md
Normal file
@ -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
|
||||||
@ -473,6 +473,21 @@ async fn test_registration_payload_structure() {
|
|||||||
os_obj.contains_key("distro") || os_obj.contains_key("kernel"),
|
os_obj.contains_key("distro") || os_obj.contains_key("kernel"),
|
||||||
"os_details should contain distro or kernel information"
|
"os_details should contain distro or kernel information"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Verify hostname field (optional, may be present or absent)
|
||||||
|
// When present, it should be a non-empty string without dots (short hostname)
|
||||||
|
if let Some(hostname) = payload.get("hostname").and_then(|v| v.as_str()) {
|
||||||
|
assert!(
|
||||||
|
!hostname.is_empty(),
|
||||||
|
"hostname should not be empty when present"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!hostname.contains('.'),
|
||||||
|
"hostname should be short form (no dots), got: {}",
|
||||||
|
hostname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// hostname field is optional — its absence is valid (skip_serializing_if = None)
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
//! Verifies machine-id, FQDN, IP address collection, and OS detail parsing.
|
//! Verifies machine-id, FQDN, IP address collection, and OS detail parsing.
|
||||||
|
|
||||||
use linux_patch_api::enroll::identity::{
|
use linux_patch_api::enroll::identity::{
|
||||||
get_fqdn, get_ip_addresses, get_machine_id, get_os_details, get_primary_ip,
|
get_fqdn, get_hostname, get_ip_addresses, get_machine_id, get_os_details, get_primary_ip,
|
||||||
get_route_source_ip, is_container_bridge, is_link_local,
|
get_route_source_ip, is_container_bridge, is_link_local,
|
||||||
};
|
};
|
||||||
use linux_patch_api::enroll::EnrollmentRequest;
|
use linux_patch_api::enroll::EnrollmentRequest;
|
||||||
@ -138,6 +138,97 @@ fn test_fqdn_reasonable_length() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Hostname Tests
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hostname_returns_non_empty() {
|
||||||
|
let hostname = get_hostname().expect("Failed to get hostname");
|
||||||
|
assert!(!hostname.is_empty(), "Hostname should not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hostname_is_short_form() {
|
||||||
|
let hostname = get_hostname().expect("Failed to get hostname");
|
||||||
|
// Short hostname should NOT contain dots (that would be an FQDN)
|
||||||
|
assert!(
|
||||||
|
!hostname.contains('.'),
|
||||||
|
"Short hostname should not contain dots, got: {}",
|
||||||
|
hostname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hostname_is_consistent() {
|
||||||
|
let h1 = get_hostname().expect("Failed to get hostname (call 1)");
|
||||||
|
let h2 = get_hostname().expect("Failed to get hostname (call 2)");
|
||||||
|
assert_eq!(h1, h2, "Hostname should be consistent across calls");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hostname_is_subset_of_fqdn() {
|
||||||
|
let hostname = get_hostname().expect("Failed to get hostname");
|
||||||
|
let fqdn = get_fqdn().expect("Failed to get FQDN");
|
||||||
|
// If FQDN contains a dot, the short hostname should be the first component
|
||||||
|
if fqdn.contains('.') {
|
||||||
|
let fqdn_prefix = fqdn.split('.').next().unwrap_or(&fqdn);
|
||||||
|
assert_eq!(
|
||||||
|
hostname, fqdn_prefix,
|
||||||
|
"Short hostname '{}' should match FQDN prefix '{}'",
|
||||||
|
hostname, fqdn_prefix
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hostname_valid_characters() {
|
||||||
|
let hostname = get_hostname().expect("Failed to get hostname");
|
||||||
|
for c in hostname.chars() {
|
||||||
|
assert!(
|
||||||
|
c.is_alphanumeric() || c == '-',
|
||||||
|
"Short hostname contains invalid character: {:?}",
|
||||||
|
c
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enrollment_hostname_field_serializes() {
|
||||||
|
// Verify that hostname field serializes correctly when Some and when None
|
||||||
|
let request_with_hostname = EnrollmentRequest {
|
||||||
|
machine_id: "test-id".to_string(),
|
||||||
|
fqdn: "host.example.com".to_string(),
|
||||||
|
ip_address: "10.0.0.1".to_string(),
|
||||||
|
os_details: serde_json::json!({"name": "Test"}),
|
||||||
|
hostname: Some("host".to_string()),
|
||||||
|
};
|
||||||
|
let json_with =
|
||||||
|
serde_json::to_string(&request_with_hostname).expect("Should serialize with hostname");
|
||||||
|
assert!(
|
||||||
|
json_with.contains("\"hostname\""),
|
||||||
|
"hostname field should be present in JSON when Some"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
json_with.contains("\"host\""),
|
||||||
|
"hostname value should be 'host' in JSON"
|
||||||
|
);
|
||||||
|
|
||||||
|
let request_without_hostname = EnrollmentRequest {
|
||||||
|
machine_id: "test-id".to_string(),
|
||||||
|
fqdn: "host.example.com".to_string(),
|
||||||
|
ip_address: "10.0.0.1".to_string(),
|
||||||
|
os_details: serde_json::json!({"name": "Test"}),
|
||||||
|
hostname: None,
|
||||||
|
};
|
||||||
|
let json_without = serde_json::to_string(&request_without_hostname)
|
||||||
|
.expect("Should serialize without hostname");
|
||||||
|
assert!(
|
||||||
|
!json_without.contains("\"hostname\""),
|
||||||
|
"hostname field should be omitted from JSON when None (skip_serializing_if)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// IP Address Tests
|
// IP Address Tests
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@ -371,11 +462,14 @@ fn test_enrollment_payload_construction() {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| "127.0.0.1".to_string());
|
.unwrap_or_else(|| "127.0.0.1".to_string());
|
||||||
|
|
||||||
|
let hostname = get_hostname().ok();
|
||||||
|
|
||||||
let request = EnrollmentRequest {
|
let request = EnrollmentRequest {
|
||||||
machine_id,
|
machine_id,
|
||||||
fqdn,
|
fqdn,
|
||||||
ip_address: primary_ip,
|
ip_address: primary_ip,
|
||||||
os_details,
|
os_details,
|
||||||
|
hostname,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Verify payload serializes to valid JSON
|
// Verify payload serializes to valid JSON
|
||||||
@ -412,11 +506,14 @@ fn test_enrollment_payload_matches_manager_schema() {
|
|||||||
let ip_addrs = get_ip_addresses().expect("Failed to get IP addresses");
|
let ip_addrs = get_ip_addresses().expect("Failed to get IP addresses");
|
||||||
let os_details = get_os_details().expect("Failed to get OS details");
|
let os_details = get_os_details().expect("Failed to get OS details");
|
||||||
|
|
||||||
|
let hostname = get_hostname().ok();
|
||||||
|
|
||||||
let request = EnrollmentRequest {
|
let request = EnrollmentRequest {
|
||||||
machine_id: machine_id.clone(),
|
machine_id: machine_id.clone(),
|
||||||
fqdn: fqdn.clone(),
|
fqdn: fqdn.clone(),
|
||||||
ip_address: ip_addrs.first().cloned().unwrap_or_default(),
|
ip_address: ip_addrs.first().cloned().unwrap_or_default(),
|
||||||
os_details: os_details.clone(),
|
os_details: os_details.clone(),
|
||||||
|
hostname,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate against expected manager API schema
|
// Validate against expected manager API schema
|
||||||
@ -449,11 +546,14 @@ fn test_enrollment_payload_roundtrip() {
|
|||||||
let ip_addrs = get_ip_addresses().expect("Failed to get IP addresses");
|
let ip_addrs = get_ip_addresses().expect("Failed to get IP addresses");
|
||||||
let os_details = get_os_details().expect("Failed to get OS details");
|
let os_details = get_os_details().expect("Failed to get OS details");
|
||||||
|
|
||||||
|
let hostname = get_hostname().ok();
|
||||||
|
|
||||||
let request = EnrollmentRequest {
|
let request = EnrollmentRequest {
|
||||||
machine_id,
|
machine_id,
|
||||||
fqdn,
|
fqdn,
|
||||||
ip_address: ip_addrs.first().cloned().unwrap_or_default(),
|
ip_address: ip_addrs.first().cloned().unwrap_or_default(),
|
||||||
os_details,
|
os_details,
|
||||||
|
hostname,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Serialize to JSON then deserialize back
|
// Serialize to JSON then deserialize back
|
||||||
@ -464,6 +564,7 @@ fn test_enrollment_payload_roundtrip() {
|
|||||||
assert_eq!(request.machine_id, deserialized.machine_id);
|
assert_eq!(request.machine_id, deserialized.machine_id);
|
||||||
assert_eq!(request.fqdn, deserialized.fqdn);
|
assert_eq!(request.fqdn, deserialized.fqdn);
|
||||||
assert_eq!(request.ip_address, deserialized.ip_address);
|
assert_eq!(request.ip_address, deserialized.ip_address);
|
||||||
|
assert_eq!(request.hostname, deserialized.hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@ -507,6 +608,10 @@ fn test_identity_functions_do_not_panic() {
|
|||||||
let _ = get_fqdn();
|
let _ = get_fqdn();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let _ = std::panic::catch_unwind(|| {
|
||||||
|
let _ = get_hostname();
|
||||||
|
});
|
||||||
|
|
||||||
let _ = std::panic::catch_unwind(|| {
|
let _ = std::panic::catch_unwind(|| {
|
||||||
let _ = get_ip_addresses();
|
let _ = get_ip_addresses();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user