RedFlag/installer/linux/build-deb.sh
Fimeg 765ec4188f publish: carry the Windows product into the projection
The tree adds the installer, service and test paths admitted by this source commit. Nothing else changes about what may cross.

Source-Sha: 3e4a3aa4ce092e9e3f51bc78daf3ddc14d9638f8

Policy-Sha: 3e4a3aa4ce092e9e3f51bc78daf3ddc14d9638f8

Tree-Digest: 89d6fce3828a0e0de0c8eeb41ee6750f4462217e2a04b5190297134d7f4a50c3
2026-09-09 12:47:34 -04:00

150 lines
6.2 KiB
Shell

#!/bin/bash
# build-deb.sh — assemble the RedFlag Debian package from already-built Linux
# amd64 binaries. This script never compiles anything; it stages, sets modes,
# and calls dpkg-deb.
#
# Usage:
# installer/linux/build-deb.sh --version 0.3.0 \
# --agent dist/redflag-agent-linux-amd64 \
# --helper dist/redflag-helper-linux-amd64 \
# --desktop dist/redflag-desktop-linux-amd64 \
# [--outdir dist] [--maintainer "Name <mail>"]
#
# Binaries default to $BINDIR (--bindir, default ./dist) using the release
# artifact names above. Output: <outdir>/redflag_<version>_amd64.deb
# Validate the result with installer/linux/inspect-deb.sh.
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$HERE/../.." && pwd)"
VERSION=""
BINDIR="dist"
OUTDIR="dist"
MAINTAINER="RedFlag <redflag@localhost>"
AGENT_BIN=""; HELPER_BIN=""; DESKTOP_BIN=""
fail() { echo "[ERROR] [build-deb] $*" >&2; exit 1; }
log() { echo "[INFO] [build-deb] $*"; }
while [ $# -gt 0 ]; do
case "$1" in
--version) VERSION="$2"; shift 2 ;;
--bindir) BINDIR="$2"; shift 2 ;;
--outdir) OUTDIR="$2"; shift 2 ;;
--maintainer) MAINTAINER="$2"; shift 2 ;;
--agent) AGENT_BIN="$2"; shift 2 ;;
--helper) HELPER_BIN="$2"; shift 2 ;;
--desktop) DESKTOP_BIN="$2"; shift 2 ;;
-h|--help) sed -n '2,20p' "$0"; exit 0 ;;
*) fail "unknown option: $1" ;;
esac
done
[ -n "$VERSION" ] || fail "--version is required"
# Debian upstream versions must start with a digit and use a restricted alphabet.
[[ "$VERSION" =~ ^[0-9][A-Za-z0-9.+~-]*$ ]] || fail "invalid Debian version: $VERSION"
AGENT_BIN="${AGENT_BIN:-$BINDIR/redflag-agent-linux-amd64}"
HELPER_BIN="${HELPER_BIN:-$BINDIR/redflag-helper-linux-amd64}"
DESKTOP_BIN="${DESKTOP_BIN:-$BINDIR/redflag-desktop-linux-amd64}"
command -v dpkg-deb >/dev/null 2>&1 || fail "dpkg-deb not found (apt-get install dpkg-dev)"
# Refuse to package anything that is not a Linux amd64 ELF executable. A silently
# wrong-arch or truncated artifact would produce a .deb that installs and then
# fails at first start, which is worse than not building.
check_bin() {
local path="$1" name="$2"
[ -f "$path" ] || fail "$name binary missing: $path (build it first; this script does not compile)"
[ -s "$path" ] || fail "$name binary is empty: $path"
if command -v file >/dev/null 2>&1; then
local desc; desc="$(file -b "$path")"
case "$desc" in
*"ELF 64-bit"*x86-64*) ;;
*) fail "$name is not a Linux x86-64 ELF: $desc" ;;
esac
else
# No file(1): check the ELF magic and e_machine=EM_X86_64 (0x3e) directly.
local magic; magic="$(head -c 20 "$path" | od -An -tx1 | tr -d ' \n')"
[ "${magic:0:8}" = "7f454c46" ] || fail "$name is not an ELF binary: $path"
[ "${magic:36:4}" = "3e00" ] || fail "$name is not x86-64 (e_machine=${magic:36:4})"
fi
log "$name ok: $path ($(stat -c%s "$path") bytes)"
}
check_bin "$AGENT_BIN" agent
check_bin "$HELPER_BIN" helper
check_bin "$DESKTOP_BIN" desktop
PROVISION_SRC="$REPO_ROOT/scripts/provision-standalone-authority.sh"
[ -f "$PROVISION_SRC" ] || fail "provisioning script missing: $PROVISION_SRC"
STAGE="$(mktemp -d)"
trap 'rm -rf "$STAGE"' EXIT
# ---- payload ----------------------------------------------------------------
# Package files live in policy-correct locations; /usr/local/bin compatibility
# symlinks for the binaries' compiled-in paths are created by postinst, which is
# where policy allows /usr/local to be touched at all.
install -D -m 0755 "$AGENT_BIN" "$STAGE/usr/bin/redflag-agent"
install -D -m 0755 "$HELPER_BIN" "$STAGE/usr/bin/redflag-helper"
install -D -m 0755 "$DESKTOP_BIN" "$STAGE/usr/bin/redflag-desktop"
install -D -m 0644 "$HERE/systemd/redflag-agent.service" \
"$STAGE/lib/systemd/system/redflag-agent.service"
install -D -m 0644 "$HERE/desktop/redflag-desktop.desktop" \
"$STAGE/usr/share/applications/redflag-desktop.desktop"
install -D -m 0644 "$HERE/desktop/redflag-desktop.desktop" \
"$STAGE/etc/xdg/autostart/redflag-desktop.desktop"
install -D -m 0440 "$HERE/sudoers/redflag-agent" \
"$STAGE/etc/sudoers.d/redflag-agent"
install -D -m 0644 "$HERE/polkit/50-redflag-agent.rules" \
"$STAGE/etc/polkit-1/rules.d/50-redflag-agent.rules"
# The authority provisioning script ships verbatim — postinst calls it with path
# overrides rather than reimplementing any of its logic.
install -D -m 0755 "$PROVISION_SRC" \
"$STAGE/usr/lib/redflag/provision-standalone-authority.sh"
install -D -m 0644 "$REPO_ROOT/LICENSE" "$STAGE/usr/share/doc/redflag/copyright"
install -D -m 0644 "$REPO_ROOT/THIRD_PARTY_LICENSES.md" "$STAGE/usr/share/doc/redflag/THIRD_PARTY_LICENSES.md"
# ---- control ----------------------------------------------------------------
install -d -m 0755 "$STAGE/DEBIAN"
sed -e "s|@VERSION@|$VERSION|g" -e "s|@MAINTAINER@|$MAINTAINER|g" \
"$HERE/debian/control.in" > "$STAGE/DEBIAN/control"
for script in preinst postinst prerm postrm; do
sed -e "s|@VERSION@|$VERSION|g" "$HERE/debian/$script" > "$STAGE/DEBIAN/$script"
chmod 0755 "$STAGE/DEBIAN/$script"
done
# Static config files are conffiles so operator edits survive upgrades.
cat > "$STAGE/DEBIAN/conffiles" <<'EOF'
/etc/sudoers.d/redflag-agent
/etc/polkit-1/rules.d/50-redflag-agent.rules
/etc/xdg/autostart/redflag-desktop.desktop
EOF
# md5sums so `dpkg -V` / debsums can detect tampering with installed files.
( cd "$STAGE" && find . -type f ! -path './DEBIAN/*' -printf '%P\0' \
| xargs -0 md5sum > DEBIAN/md5sums )
# Syntax-check the maintainer scripts before shipping them. A broken postinst is
# discovered at install time on the operator's machine otherwise.
for script in preinst postinst prerm postrm; do
sh -n "$STAGE/DEBIAN/$script" || fail "$script failed shell syntax check"
done
if command -v visudo >/dev/null 2>&1; then
visudo -c -f "$STAGE/etc/sudoers.d/redflag-agent" >/dev/null \
|| fail "sudoers file failed validation"
log "sudoers validated"
fi
mkdir -p "$OUTDIR"
DEB="$OUTDIR/redflag_${VERSION}_amd64.deb"
# root:root ownership without needing root to build.
dpkg-deb --root-owner-group --build "$STAGE" "$DEB" >/dev/null
log "built: $DEB ($(stat -c%s "$DEB") bytes)"
echo "$DEB"