colibri/docs/ISO-SERVICE-LAYOUT.md
Sam & Hermes 3235f8c00e feat: ISO service hardening — rc.d + log rotation + layout docs
Hardens the FreeBSD service for production readiness:

- rc.d: post-start socket health check (waits up to 10s), post-stop
  socket cleanup, 'health' extra command that probes socket with
  a status command via nc.

- newsyslog: log rotation at 1MB, 7 compressed archives,
  colibri:colibri ownership.

- staging: copies newsyslog config into image root, updated
  staging report to list all installed files.

- docs/ISO-SERVICE-LAYOUT.md: filesystem layout, boot/shutdown
  behavior, startup validation commands, config knobs, secrets
  policy, log rotation details.

Shell syntax: sh -n clean on both scripts.
Workspace tests: all green.
2026-05-31 16:48:48 +02:00

3.5 KiB

Colibri ISO Service Layout

Service identity

Field Value
Service name colibri_daemon
Binary /usr/local/bin/colibri-daemon
User colibri (unprivileged, /usr/sbin/nologin)
Group colibri
Supervisor daemon(8) — restart on crash, privilege drop

Filesystem layout

/usr/local/bin/colibri-daemon        ← daemon binary (foreground, no self-daemonize)
/usr/local/bin/colibri                ← CLI client (status, create-task, etc.)
/usr/local/bin/colibri-smoke-agent    ← smoke test agent (fake Pi JSONL)
/usr/local/etc/rc.d/colibri_daemon    ← rc.d service script
/usr/local/etc/colibri/
  rc.conf.sample                      ← service config template
/usr/local/etc/newsyslog.conf.d/
  colibri.conf                        ← log rotation (1MB, 7 archives)

/var/db/colibri/                      ← persistent data (750 colibri:colibri)
  colibri.sqlite                      ← coordination store
  sessions/                           ← JSONL session files

/var/run/colibri/                     ← tmpfs (recreated each boot)
  colibri.sock                        ← Unix socket (750 colibri:colibri)
  colibri-daemon.pid                  ← daemon(8) supervisor pidfile

/var/log/colibri/                     ← persistent logs
  daemon.log                          ← stdout/stderr from colibri-daemon

Boot-time behavior

  1. rc.d starts colibri_daemon after LOGIN + cleanvar
  2. prestart: creates /var/run/colibri/, /var/db/colibri/, /var/log/colibri/
  3. daemon(8) forks colibri-daemon as user colibri, redirects logs
  4. poststart: waits up to 10s for /var/run/colibri/colibri.sock to appear
  5. Daemon binds socket, opens SQLite, starts scheduler loop
  6. CLI clients connect via colibri binary → Unix socket

Shutdown behavior

  1. rc.d sends SIGTERM to daemon(8)
  2. daemon(8) forwards to colibri-daemon child
  3. Colibri closes socket, flushes SQLite, stops scheduler
  4. poststop: removes stale socket from tmpfs

Startup validation

# Check service status
service colibri_daemon status

# Socket health (nc must be available)
service colibri_daemon health

# CLI smoke
colibri status
colibri create-task --title "iso-smoke"
colibri list-tasks --status queued

Config knobs (set in /etc/rc.conf or /etc/rc.conf.d/colibri_daemon)

Variable Default Purpose
colibri_daemon_enable NO Enable at boot (YES/NO)
colibri_daemon_user colibri Runtime user
colibri_daemon_group colibri Runtime group
colibri_cost_mode smart fast/smart/max
colibri_daemon_data_dir /var/db/colibri Persistent data
colibri_daemon_run_dir /var/run/colibri tmpfs runtime
colibri_daemon_socket $run_dir/colibri.sock Unix socket path
colibri_daemon_db_path $data_dir/colibri.sqlite SQLite path
colibri_daemon_logfile /var/log/colibri/daemon.log Log output

Log rotation

/usr/local/etc/newsyslog.conf.d/colibri.conf:

/var/log/colibri/daemon.log  colibri:colibri  640  7  1024  *  JC

Rotates at 1MB, keeps 7 compressed archives, bzip2 compression.

Secrets policy

  • No API keys in rc.conf or service environment files.
  • DEEPSEEK_API_KEY and other provider keys are set via a separate, mode-0600 env file sourced by the daemon (e.g. /usr/local/etc/colibri/provider.env).
  • The rc.d script does NOT read or expose secrets.
  • Logs go to /var/log/colibri/ which is mode 0750 colibri:colibri — only the colibri user and root can read them.