Blueforce-Linux/scripts/install/installer/modules/18-final-check.sh
emirhanmamak-blueforce e28783e563 feat(offline-repo): build the APT index so installs work without network
The package pool was committed but the installer still stopped at "no local
package repository": it requires the compiled bundle (Packages, Packages.gz,
packages.lock.tsv, SHA256SUMS), and building that had never run.

The bundle
- 1321 packages, 884 MiB, Ubuntu 26.04 amd64, built with apt-ftparchive on the
  fleet's own release so the closure matches the devices.
- built/pool/ is gitignored: those .deb files are already tracked once under
  provisioning/offline-repo/packages/, and the same ~890 MB does not need a
  second path. What the installer reads from the bundle is the index.
- The output directory is chmod 0755: mktemp -d created it 0700 and left it
  so, which made a valid bundle unreadable to the installer's probe.

dpkg-deb output was parsed wrong in four places
- `dpkg-deb -f <file> Package Version` prints "<Field>: <value>", and the
  callers kept the whole line, so the value carried its label. build-index.sh
  therefore accepted no package at all and reported an empty pool;
  add-packages.sh rejected every real .deb as an invalid name, missed version
  conflicts, and copied a duplicate; build-offline-repo.sh never matched a pin.
- The test suite could not see any of this: its dpkg-deb stub emitted bare
  values. The stub now prints the labels exactly as the real tool does, which
  is what surfaced the remaining three sites.

Tests
- The secret scan covers the files we author, not apt-ftparchive's index over
  third-party packages: polkit's own description reads "...asked for their
  password:", which is prose in the packages, not a leak. Any secret reaching a
  manifest, README or tool is still caught.
- The "test build must not touch the bundle" assertion now compares the
  directory before and after instead of demanding it be empty, so a
  maintainer's real build is not reported as test spill.
2026-09-16 21:42:27 +03:00

44 lines
2.6 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Final lifecycle gate: offline completes locally; READY requires enrolled remote proof.
set -euo pipefail
LOG_FILE="${LOG_FILE:-/var/log/blueforce-install.log}"; STATE_DIR="${STATE_DIR:-/var/lib/blueforce}"; CHECK_MODE=0
[[ "${1:-}" == --check ]] && CHECK_MODE=1
OFFLINE="${BF_OFFLINE:-0}"; SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
log() { echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) [18-final-check] $1" | tee -a "$LOG_FILE"; }
# Operator GUI runtime gate. The field application is the Python GUI (bfos), and
# tkinter is a separate package on Ubuntu: a minimal image has python3 but no
# window toolkit, so the operator would be left with no working entry point and
# no network to fix it. Checked here because every install path reaches this
# module, offline or not. When the GUI is unavailable the terminal console still
# works, so this reports the degradation instead of aborting the install.
if python3 -c 'import tkinter' >/dev/null 2>&1; then
log 'OK: operatör arayüzü (tkinter) hazır'
else
log 'WARN: tkinter yok; operatör arayüzü açılamaz. Terminal konsolu çalışır: sudo bf --tui'
log 'WARN: python3-tk paketi bu imajda eksik (offline depoda pinli: provisioning/offline-repo/manifests/base-packages.txt)'
fi
if [[ "$CHECK_MODE" == 1 ]]; then
command -v bf >/dev/null 2>&1 || log 'WARN(check): bf komutu PATH üzerinde yok; kurulum bf simgesini oluşturur'
fi
if [[ "$OFFLINE" == 1 ]]; then
# Only local gates are meaningful offline. No central peer, handshake, or READY claim.
for g in 01-precheck 02-system 03-user 04-hostname 05-network 06-wireguard 07-ssh 08-rdp 10-docker 11-meg 12-monitoring 13-firewall 14-update-policy 15-logrotate 16-gui 17-healthcheck; do
LOG_FILE=/dev/null BF_OFFLINE=1 bash "$SCRIPT_DIR/$g.sh" --check >/dev/null || { log "FAIL: offline local gate $g failed"; exit 1; }
done
[[ "$CHECK_MODE" == 1 ]] && { log 'OK(check): offline local gates pass'; exit 0; }
log 'OK: offline local gates pass; installer records PROVISIONED_OFFLINE'; exit 0
fi
[[ "$CHECK_MODE" == 1 ]] && exec /usr/local/bin/bf-check-ready
/usr/local/bin/bf-check-ready
python3 - "$STATE_DIR/state.json" <<'PY'
import json,os,sys,tempfile
p=sys.argv[1]; s=json.load(open(p));
if s.get('phase') not in ('ENROLLED','READY'): raise SystemExit('not enrolled')
s.update({'phase':'READY','fleet_status':'READY'})
fd,t=tempfile.mkstemp(prefix='state.json.',dir=os.path.dirname(p)); os.fchmod(fd,0o600)
with os.fdopen(fd,'w') as f: json.dump(s,f,sort_keys=True); f.write('\n')
os.replace(t,p)
PY
log 'OK: enrolled device has current handshake and remote checks; READY recorded'