mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-24 12:07:58 +09:00
Hardening plan §6. Reduces the distro-specific if/else surface and handles
edge environments:
- Dependency manifest (scripts/deps/manifest.yaml): declarative per-family
package/python/node/docker/init spec. Consumed directly by the Phase 5
Python bootstrap; install.sh mirrors it inline (it can't parse YAML before
Python exists in the curl|bash path).
- New sourceable libs (built in parallel, each shellcheck-clean + unit-tested):
- scripts/lib/pkg.sh — pkg_detect/refresh/install/is_installed across
apt/dnf/yum/zypper/pacman/apk (PKG_MGR_OVERRIDE + PKG_DRY_RUN for tests).
- scripts/lib/init.sh — init_detect + start/stop/enable/disable/reload/
is_active across systemd/openrc/runit/sysvinit/none (INIT_OVERRIDE/DRY_RUN).
- scripts/lib/env.sh — is_container/is_wsl/has_systemd (override-friendly).
- ID_LIKE handling (G5/6.5): install.sh's os_family_from() (now a pure,
testable function reading ${SERVERKIT_OS_RELEASE}) maps unknown IDs via
ID_LIKE to debian/rhel/fedora/suse/arch/alpine — rhel before fedora so RHEL
clones pick the RHEL Docker repo.
- zypper + pacman + apk (G6/6.6): choose_pkg_manager/refresh_pkg_index/pkg_add,
provision_docker and provision_python gained suse/arch/alpine branches;
Docker enable/start is now init-aware (systemd OR OpenRC) so it no longer
aborts on Alpine.
- Templated systemd unit (6.7): serverkit-backend.service → templates/
serverkit-backend.service.in, rendered (render_service_unit) at install and
in refresh_config so a custom SERVERKIT_DIR/venv/log path is honored.
install_service warns-and-skips enable when has_systemd is false (G5).
- nginx TLS floor as a reversible conf.d snippet (6.8): install.sh + update.sh
prefer /etc/nginx/conf.d/serverkit-tls.conf when nginx.conf doesn't already
declare ssl_protocols (RHEL/Fedora/SUSE), falling back to the in-place edit
on Debian/Ubuntu to avoid a 'duplicate ssl_protocols' error. uninstall
removes only that snippet.
Tests: new scripts/test/test_lib.sh (13) + 4 new test_install.sh cases
(os_family_from, render_service_unit, harden_global_tls A/B). 13+15+10 pass;
shellcheck error+warning clean across all new/changed shell.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
98 lines
4.6 KiB
Bash
98 lines
4.6 KiB
Bash
# shellcheck shell=bash
|
|
#
|
|
# scripts/lib/env.sh — runtime-environment detection for install/update.
|
|
#
|
|
# The installer and updater behave differently depending on where they run:
|
|
# inside a Docker/podman/LXC container the host-level service plumbing
|
|
# (systemctl units, firewall rules, journald) is either absent or off-limits;
|
|
# under WSL there is usually no real init and /proc looks Linux-ish but a lot of
|
|
# systemd assumptions break; and on a plain bare-metal/VPS box systemd is the
|
|
# normal service manager. Rather than scatter ad-hoc `[ -f /.dockerenv ]` and
|
|
# `command -v systemctl` checks through the scripts, we centralise the three
|
|
# questions the rest of the tooling actually asks into named predicates so the
|
|
# intent is obvious at the call site (`if is_container; then ...`).
|
|
#
|
|
# Design rules:
|
|
# * Every check is SAFE on a non-Linux dev box (Windows/macOS): no file is
|
|
# read without a `[ -f ]`/`[ -d ]` guard first, and nothing here aborts the
|
|
# caller under `set -e`. Each predicate is a series of `if ... return 0; fi`
|
|
# checks ending in a single `return 1`, so a non-matching grep maps to
|
|
# "false" instead of leaking a failure exit status.
|
|
# * Each predicate honours a force-override env var (checked FIRST) so unit
|
|
# tests — and operators in weird environments — can pin the answer:
|
|
# SERVERKIT_IS_CONTAINER / SERVERKIT_IS_WSL / SERVERKIT_HAS_SYSTEMD
|
|
# each accept "1" (force true) or "0" (force false).
|
|
# * The marker/probe paths are likewise overridable so tests can point at
|
|
# fixtures instead of the real /proc and /run:
|
|
# SERVERKIT_DOCKERENV_FILE (default /.dockerenv)
|
|
# SERVERKIT_CONTAINERENV_FILE(default /run/.containerenv) [podman]
|
|
# SERVERKIT_CGROUP_FILE (default /proc/1/cgroup)
|
|
# SERVERKIT_OSRELEASE_FILE (default /proc/sys/kernel/osrelease)
|
|
#
|
|
# Contract (all three are predicates: return 0/true or 1/false, print nothing):
|
|
# is_container → running inside a container?
|
|
# is_wsl → running under Windows Subsystem for Linux?
|
|
# has_systemd → is systemd usable as the init/service manager?
|
|
|
|
# True if running inside a container (Docker, podman, LXC, systemd-nspawn, k8s).
|
|
# Several independent signals are checked because no single one is universal:
|
|
# Docker drops /.dockerenv, podman drops /run/.containerenv, nspawn/lxc export
|
|
# `container=...`, and as a last resort the init cgroup line names the runtime.
|
|
is_container() {
|
|
# Explicit force-override wins over any probing.
|
|
if [ "${SERVERKIT_IS_CONTAINER:-}" = "1" ]; then return 0; fi
|
|
if [ "${SERVERKIT_IS_CONTAINER:-}" = "0" ]; then return 1; fi
|
|
|
|
local dockerenv containerenv cgroup
|
|
dockerenv="${SERVERKIT_DOCKERENV_FILE:-/.dockerenv}"
|
|
containerenv="${SERVERKIT_CONTAINERENV_FILE:-/run/.containerenv}"
|
|
cgroup="${SERVERKIT_CGROUP_FILE:-/proc/1/cgroup}"
|
|
|
|
# Docker writes this marker into every container's root.
|
|
if [ -f "$dockerenv" ]; then return 0; fi
|
|
# podman's equivalent marker.
|
|
if [ -f "$containerenv" ]; then return 0; fi
|
|
# systemd-nspawn and many lxc setups export this into the environment.
|
|
if [ -n "${container:-}" ]; then return 0; fi
|
|
# Fall back to the PID-1 cgroup line, which names the runtime in most cases.
|
|
# `-a` treats the (possibly NUL-laden) /proc file as text so grep won't bail.
|
|
if [ -f "$cgroup" ] && grep -qaE 'docker|lxc|containerd|kubepods|podman' "$cgroup"; then
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# True under Windows Subsystem for Linux. The kernel release string is the
|
|
# reliable tell on both WSL1 and WSL2 ("...-microsoft-standard-WSL2"), so we
|
|
# match it case-insensitively rather than trusting any single distro quirk.
|
|
is_wsl() {
|
|
if [ "${SERVERKIT_IS_WSL:-}" = "1" ]; then return 0; fi
|
|
if [ "${SERVERKIT_IS_WSL:-}" = "0" ]; then return 1; fi
|
|
|
|
local osrelease
|
|
osrelease="${SERVERKIT_OSRELEASE_FILE:-/proc/sys/kernel/osrelease}"
|
|
|
|
if [ -f "$osrelease" ] && grep -qiE 'microsoft|WSL' "$osrelease"; then
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# True if systemd is usable as the init/service manager. Both conditions matter:
|
|
# `systemctl` must exist AND /run/systemd/system must be present — the latter is
|
|
# created by systemd itself when it is PID 1, so its existence implies systemd is
|
|
# actually running (not just installed). This keeps us from trying to drive
|
|
# systemctl inside a container whose init is something else.
|
|
has_systemd() {
|
|
if [ "${SERVERKIT_HAS_SYSTEMD:-}" = "1" ]; then return 0; fi
|
|
if [ "${SERVERKIT_HAS_SYSTEMD:-}" = "0" ]; then return 1; fi
|
|
|
|
if command -v systemctl >/dev/null 2>&1 && [ -d /run/systemd/system ]; then
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|