Files
rust-package-builder/scripts/prepare-package.sh
T

273 lines
9.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
BUILDER_ROOT=${BUILDER_ROOT:-/opt/rust-package-builder}
source "$BUILDER_ROOT/scripts/lib.sh"
SRC=${1:?source path required}
PKG=${2:?package workspace required}
BINARY_PATH=${3:?binary path required}
rm -rf "$PKG"
mkdir -p "$PKG/payload" "$PKG/scripts"
install -D -m 0755 "$BINARY_PATH" "$PKG/payload/usr/bin/$BINARY_NAME"
SERVICE_SRC="$SRC/debian/${PACKAGE_NAME}.service"
ENV_SRC="$SRC/debian/${PACKAGE_NAME}.environment"
LOGROTATE_SRC="$BUILDER_ROOT/packaging/rustproxy.logrotate"
ACCESS_GUIDE_SRC="$BUILDER_ROOT/packaging/rustproxy-filesystem-access.md"
TMPFILES_SRC="$SRC/debian/${PACKAGE_NAME}.tmpfiles"
POSTINST_SRC="$SRC/debian/${PACKAGE_NAME}.postinst"
if [[ -r "$SERVICE_SRC" ]]; then
install -D -m 0644 "$SERVICE_SRC" "$PKG/payload/usr/lib/systemd/system/${PACKAGE_NAME}.service"
else
mkdir -p "$PKG/payload/usr/lib/systemd/system"
cat > "$PKG/payload/usr/lib/systemd/system/${PACKAGE_NAME}.service" <<UNIT
[Unit]
Description=$DESCRIPTION
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=rustproxy
Group=rustproxy
WorkingDirectory=/var/lib/rustproxy
UMask=0077
Environment=RUST_LOG=rust_proxy=info,warn
Environment=MALLOC_ARENA_MAX=2
Environment=PATH=/usr/local/bin:/usr/bin:/bin
EnvironmentFile=-/etc/rustproxy/environment
ExecStart=/usr/bin/$BINARY_NAME --data-dir /var/lib/rustproxy serve --admin-listen 0.0.0.0:9090 --proxy-listen 0.0.0.0:80 --tls-listen 0.0.0.0:443 --allow-remote-admin
Restart=on-failure
RestartSec=3
KillSignal=SIGINT
KillMode=control-group
TimeoutStopSec=120
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
LogsDirectory=rustproxy
LogsDirectoryMode=0700
ReadWritePaths=/var/lib/rustproxy /var/log/rustproxy
# Allow ACL/group-controlled read access to web roots and external certificates
# under /home; ProtectSystem=strict still makes all other paths read-only.
ProtectHome=read-only
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictSUIDSGID=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
SystemCallArchitectures=native
LockPersonality=true
[Install]
WantedBy=multi-user.target
UNIT
fi
# Match the 0.34.x CLI. Avoid changing upstream units that already provide
# their own ExecReload. Linux package revision forces rebuilding old binaries.
python3 "$BUILDER_ROOT/scripts/normalize-systemd-unit.py" \
"$PKG/payload/usr/lib/systemd/system/${PACKAGE_NAME}.service" "$BINARY_NAME"
if [[ -r "$ENV_SRC" ]]; then
install -D -m 0640 "$ENV_SRC" "$PKG/payload/etc/${PACKAGE_NAME}/environment"
fi
[[ -r "$LOGROTATE_SRC" ]] || fatal "missing bundled logrotate configuration: $LOGROTATE_SRC"
install -D -m 0644 "$LOGROTATE_SRC" "$PKG/payload/etc/logrotate.d/${PACKAGE_NAME}"
[[ -r "$ACCESS_GUIDE_SRC" ]] || fatal "missing Linux filesystem access guide: $ACCESS_GUIDE_SRC"
install -D -m 0644 "$ACCESS_GUIDE_SRC" "$PKG/payload/usr/share/doc/${PACKAGE_NAME}/FILESYSTEM_ACCESS.md"
if [[ -r "$TMPFILES_SRC" ]]; then
install -D -m 0644 "$TMPFILES_SRC" "$PKG/payload/usr/lib/tmpfiles.d/${PACKAGE_NAME}.conf"
fi
# Preserve optional project-owned monitoring assets used by RustProxy's existing Debian package.
if [[ -r "$SRC/grafana/rustproxy-overview.json" ]]; then
install -D -m 0644 "$SRC/grafana/rustproxy-overview.json" "$PKG/payload/usr/share/${PACKAGE_NAME}/grafana/rustproxy-overview.json"
fi
if [[ -r "$SRC/grafana/README.md" ]]; then
install -D -m 0644 "$SRC/grafana/README.md" "$PKG/payload/usr/share/doc/${PACKAGE_NAME}/grafana/README.md"
fi
cat > "$PKG/scripts/deb-postinstall.sh" <<'SCRIPT'
#!/bin/sh
set -e
SCRIPT
if [[ -r "$POSTINST_SRC" ]]; then
sed -e '/^#![[:space:]]*\/bin\/sh/d' \
-e '/^[[:space:]]*#DEBHELPER#[[:space:]]*$/d' \
-e '/^[[:space:]]*exit[[:space:]]\+0[[:space:]]*$/d' \
"$POSTINST_SRC" >> "$PKG/scripts/deb-postinstall.sh"
else
cat >> "$PKG/scripts/deb-postinstall.sh" <<SCRIPT
if ! getent group "$PACKAGE_NAME" >/dev/null 2>&1; then
addgroup --system "$PACKAGE_NAME" >/dev/null
fi
if ! getent passwd "$PACKAGE_NAME" >/dev/null 2>&1; then
adduser --system --ingroup "$PACKAGE_NAME" --home "/var/lib/$PACKAGE_NAME" --no-create-home \\
--disabled-password --shell /usr/sbin/nologin "$PACKAGE_NAME" >/dev/null
fi
install -d -o "$PACKAGE_NAME" -g "$PACKAGE_NAME" -m 0700 "/var/lib/$PACKAGE_NAME" "/var/log/$PACKAGE_NAME" "/etc/$PACKAGE_NAME"
SCRIPT
fi
cat >> "$PKG/scripts/deb-postinstall.sh" <<SCRIPT
systemctl daemon-reload >/dev/null 2>&1 || true
systemctl enable "${PACKAGE_NAME}.service" >/dev/null 2>&1 || true
systemctl restart "${PACKAGE_NAME}.service" >/dev/null 2>&1 || true
exit 0
SCRIPT
cat > "$PKG/scripts/deb-preremove.sh" <<SCRIPT
#!/bin/sh
set -e
case "\${1:-}" in
remove|deconfigure) systemctl stop "${PACKAGE_NAME}.service" >/dev/null 2>&1 || true ;;
esac
exit 0
SCRIPT
cat > "$PKG/scripts/deb-postremove.sh" <<SCRIPT
#!/bin/sh
set -e
systemctl daemon-reload >/dev/null 2>&1 || true
exit 0
SCRIPT
cat > "$PKG/scripts/rpm-postinstall.sh" <<SCRIPT
#!/bin/sh
set -e
if ! getent group "$PACKAGE_NAME" >/dev/null 2>&1; then
groupadd --system "$PACKAGE_NAME"
fi
if ! getent passwd "$PACKAGE_NAME" >/dev/null 2>&1; then
useradd --system --gid "$PACKAGE_NAME" --home-dir "/var/lib/$PACKAGE_NAME" --no-create-home --shell /sbin/nologin "$PACKAGE_NAME"
fi
install -d -o "$PACKAGE_NAME" -g "$PACKAGE_NAME" -m 0700 "/var/lib/$PACKAGE_NAME" "/var/log/$PACKAGE_NAME" "/etc/$PACKAGE_NAME"
systemd-tmpfiles --create "/usr/lib/tmpfiles.d/${PACKAGE_NAME}.conf" >/dev/null 2>&1 || true
systemctl daemon-reload >/dev/null 2>&1 || true
systemctl enable "${PACKAGE_NAME}.service" >/dev/null 2>&1 || true
systemctl restart "${PACKAGE_NAME}.service" >/dev/null 2>&1 || true
exit 0
SCRIPT
cat > "$PKG/scripts/rpm-preremove.sh" <<SCRIPT
#!/bin/sh
set -e
if [ "\${1:-1}" -eq 0 ]; then
systemctl stop "${PACKAGE_NAME}.service" >/dev/null 2>&1 || true
systemctl disable "${PACKAGE_NAME}.service" >/dev/null 2>&1 || true
fi
exit 0
SCRIPT
cat > "$PKG/scripts/rpm-postremove.sh" <<SCRIPT
#!/bin/sh
set -e
systemctl daemon-reload >/dev/null 2>&1 || true
exit 0
SCRIPT
chmod 0755 "$PKG/scripts"/*.sh
# Build nFPM contents dynamically from project-provided package assets.
CONTENTS_FILE="$PKG/contents.yaml"
: > "$CONTENTS_FILE"
add_content() {
local src=$1 dst=$2 mode=$3 type=${4:-}
{
printf ' - src: %s\n' "$(yaml_quote "$src")"
printf ' dst: %s\n' "$(yaml_quote "$dst")"
[[ -n "$type" ]] && printf ' type: %s\n' "$(yaml_quote "$type")"
printf ' file_info:\n mode: %s\n' "$mode"
} >> "$CONTENTS_FILE"
}
add_content "$PKG/payload/usr/bin/$BINARY_NAME" "/usr/bin/$BINARY_NAME" 0755
add_content "$PKG/payload/usr/lib/systemd/system/${PACKAGE_NAME}.service" "/usr/lib/systemd/system/${PACKAGE_NAME}.service" 0644
[[ -f "$PKG/payload/etc/${PACKAGE_NAME}/environment" ]] && add_content "$PKG/payload/etc/${PACKAGE_NAME}/environment" "/etc/${PACKAGE_NAME}/environment" 0640 'config|noreplace'
add_content "$PKG/payload/etc/logrotate.d/${PACKAGE_NAME}" "/etc/logrotate.d/${PACKAGE_NAME}" 0644 'config|noreplace'
add_content "$PKG/payload/usr/share/doc/${PACKAGE_NAME}/FILESYSTEM_ACCESS.md" "/usr/share/doc/${PACKAGE_NAME}/FILESYSTEM_ACCESS.md" 0644
[[ -f "$PKG/payload/usr/lib/tmpfiles.d/${PACKAGE_NAME}.conf" ]] && add_content "$PKG/payload/usr/lib/tmpfiles.d/${PACKAGE_NAME}.conf" "/usr/lib/tmpfiles.d/${PACKAGE_NAME}.conf" 0644
[[ -f "$PKG/payload/usr/share/${PACKAGE_NAME}/grafana/rustproxy-overview.json" ]] && add_content "$PKG/payload/usr/share/${PACKAGE_NAME}/grafana/rustproxy-overview.json" "/usr/share/${PACKAGE_NAME}/grafana/rustproxy-overview.json" 0644
[[ -f "$PKG/payload/usr/share/doc/${PACKAGE_NAME}/grafana/README.md" ]] && add_content "$PKG/payload/usr/share/doc/${PACKAGE_NAME}/grafana/README.md" "/usr/share/doc/${PACKAGE_NAME}/grafana/README.md" 0644
NAME_Q=$(yaml_quote "$PACKAGE_NAME")
VERSION_Q=$(yaml_quote "$VERSION")
MAINTAINER_Q=$(yaml_quote "$MAINTAINER")
DESC_Q=$(yaml_quote "$DESCRIPTION")
LICENSE_Q=$(yaml_quote "$LICENSE")
HOMEPAGE_Q=$(yaml_quote "$HOMEPAGE")
GPG_KEY_Q=$(yaml_quote "$GPG_PRIVATE_KEY_FILE")
cat > "$PKG/nfpm-deb.yaml" <<YAML
name: $NAME_Q
arch: amd64
platform: linux
version: $VERSION_Q
release: "$PACKAGE_RELEASE"
section: net
priority: optional
maintainer: $MAINTAINER_Q
description: $DESC_Q
license: $LICENSE_Q
homepage: $HOMEPAGE_Q
contents:
$(cat "$CONTENTS_FILE")
depends:
- adduser
- ca-certificates
- gzip
- logrotate
- python3
- python3-pip
- systemd
scripts:
postinstall: "$PKG/scripts/deb-postinstall.sh"
preremove: "$PKG/scripts/deb-preremove.sh"
postremove: "$PKG/scripts/deb-postremove.sh"
deb:
compression: xz
signature:
key_file: $GPG_KEY_Q
type: origin
YAML
cat > "$PKG/nfpm-rpm.yaml" <<YAML
name: $NAME_Q
arch: amd64
platform: linux
version: $VERSION_Q
release: "$PACKAGE_RELEASE"
section: net
priority: optional
maintainer: $MAINTAINER_Q
description: $DESC_Q
license: $LICENSE_Q
homepage: $HOMEPAGE_Q
vendor: $NAME_Q
contents:
$(cat "$CONTENTS_FILE")
depends:
- ca-certificates
- gzip
- logrotate
- shadow-utils
- '((python3 >= 3.10 and python3-pip) or (python3.12 and python3.12-pip) or (python3.11 and python3.11-pip))'
- systemd
scripts:
postinstall: "$PKG/scripts/rpm-postinstall.sh"
preremove: "$PKG/scripts/rpm-preremove.sh"
postremove: "$PKG/scripts/rpm-postremove.sh"
rpm:
compression: zstd
signature:
key_file: $GPG_KEY_Q
YAML