colibri: gate autospawn on /var/db/colibri/.secured (honor colibri_daemon_require_secured) #183

Closed
opened 2026-06-25 06:17:28 +02:00 by clawdie · 0 comments
Owner

colibri: honor colibri_daemon_require_secured — gate autospawn on .secured

The clawdie-iso first-boot password gate (clawdie-iso PR #139) writes /var/db/colibri/.secured when the operator sets the root+operator passwords, and the operator image sets colibri_daemon_require_secured="YES" in rc.conf. This is the daemon-side consumer that makes "the agent will not start/register until secured" actually true.

Part A — required interlock (packaging/freebsd/colibri_daemon.in)

  1. Add a default near the others (so deployed hosts default OFF):
    : ${colibri_daemon_require_secured:="NO"}
    
  2. In colibri_daemon_prestart(), after the . provider.env source block (lines ~99-103, which sets COLIBRI_AUTOSPAWN=YES) so this override wins:
    # Operator-image safety gate: don't autospawn an agent until the first-boot
    # password gate has run (clawdie-firstboot-rootpw writes ${data_dir}/.secured).
    if checkyesno colibri_daemon_require_secured && \
       [ ! -e "${colibri_daemon_data_dir}/.secured" ]; then
        warn "colibri: node unsecured (no root password yet) — agent autospawn disabled"
        export COLIBRI_AUTOSPAWN=NO
    fi
    

Why this shape:

  • Opt-in knob → the shared FreeBSD port (packaging/freebsd/port/.../colibri_daemon.in) on deployed hosts never sets it, so they're unaffected (default NO). An unconditional check would disable autospawn on every deployed host forever — that's the bug this avoids.
  • Placement after . provider.env → overrides the COLIBRI_AUTOSPAWN=YES from provider.env. export in prestart propagates to the daemon child (same mechanism as the existing COLIBRI_DAEMON_DATA_DIR exports). Daemon honors it via env_truthy("COLIBRI_AUTOSPAWN") (crates/colibri-daemon/src/socket.rs:415).
  • No reboot in the normal flow: the gate is BEFORE: LOGIN, the daemon is REQUIRE: LOGIN, rc is synchronous — so on the boot where the operator sets the password, .secured already exists when this prestart runs → autospawn proceeds the same boot. Reboot only matters if the password is set outside the gate.
  • Gate autospawn, not daemon start: the daemon stays up so status/glasspane/TUI work; no agent ⇒ no node_register ⇒ mother never hears from an unsecured node.

Without this, a skipped node shows a running daemon with no agent and no explanation ("broken or just unsecured?").

  • Add secured: bool to the daemon status response (true iff ${data_dir}/.secured exists).
  • TUI/glasspane: when false, show [UNSECURED — set root password to activate agent] instead of a blank pane.
  • colibri status: print Node: UNSECURED (set root password to activate agent) when false.

Explicitly NOT doing (Option 3 / auto-wake poll)

Dropped. rc ordering already avoids the reboot it was meant to solve; not worth the scheduler poll + respawn-guard + mid-session marker race.

Test

A small shell test for the prestart logic, mirroring clawdie-iso/tests/firstboot-rootpw-test.sh: require_secured=YES + marker absent → AUTOSPAWN=NO; marker present → unchanged; require_secured=NO → unchanged.

Coupling

Ships with clawdie-iso #139 in the same 0.12 image. #139 already sets the knob and its skip message promises this behavior — Part A makes the promise true. Boot-test on osa together.

## colibri: honor `colibri_daemon_require_secured` — gate autospawn on `.secured` The clawdie-iso first-boot password gate ([clawdie-iso PR #139](https://code.smilepowered.org/clawdie/clawdie-iso/pulls/139)) writes `/var/db/colibri/.secured` when the operator sets the root+operator passwords, and the **operator image** sets `colibri_daemon_require_secured="YES"` in rc.conf. This is the daemon-side consumer that makes "the agent will not start/register until secured" actually true. ### Part A — required interlock (`packaging/freebsd/colibri_daemon.in`) 1. Add a default near the others (so **deployed hosts default OFF**): ```sh : ${colibri_daemon_require_secured:="NO"} ``` 2. In `colibri_daemon_prestart()`, **after** the `. provider.env` source block (lines ~99-103, which sets `COLIBRI_AUTOSPAWN=YES`) so this override wins: ```sh # Operator-image safety gate: don't autospawn an agent until the first-boot # password gate has run (clawdie-firstboot-rootpw writes ${data_dir}/.secured). if checkyesno colibri_daemon_require_secured && \ [ ! -e "${colibri_daemon_data_dir}/.secured" ]; then warn "colibri: node unsecured (no root password yet) — agent autospawn disabled" export COLIBRI_AUTOSPAWN=NO fi ``` Why this shape: - **Opt-in knob** → the shared FreeBSD port (`packaging/freebsd/port/.../colibri_daemon.in`) on **deployed hosts** never sets it, so they're unaffected (default NO). An unconditional check would disable autospawn on every deployed host forever — that's the bug this avoids. - **Placement after `. provider.env`** → overrides the `COLIBRI_AUTOSPAWN=YES` from provider.env. `export` in prestart propagates to the daemon child (same mechanism as the existing `COLIBRI_DAEMON_DATA_DIR` exports). Daemon honors it via `env_truthy("COLIBRI_AUTOSPAWN")` (`crates/colibri-daemon/src/socket.rs:415`). - **No reboot in the normal flow**: the gate is `BEFORE: LOGIN`, the daemon is `REQUIRE: LOGIN`, rc is synchronous — so on the boot where the operator sets the password, `.secured` already exists when this prestart runs → autospawn proceeds the same boot. Reboot only matters if the password is set outside the gate. - Gate *autospawn*, not daemon *start*: the daemon stays up so status/glasspane/TUI work; no agent ⇒ no `node_register` ⇒ mother never hears from an unsecured node. ### Part B — recommended UX: visible unsecured state Without this, a skipped node shows a running daemon with no agent and no explanation ("broken or just unsecured?"). - Add `secured: bool` to the daemon status response (true iff `${data_dir}/.secured` exists). - TUI/glasspane: when false, show `[UNSECURED — set root password to activate agent]` instead of a blank pane. - `colibri status`: print `Node: UNSECURED (set root password to activate agent)` when false. ### Explicitly NOT doing (Option 3 / auto-wake poll) Dropped. rc ordering already avoids the reboot it was meant to solve; not worth the scheduler poll + respawn-guard + mid-session marker race. ### Test A small shell test for the prestart logic, mirroring `clawdie-iso/tests/firstboot-rootpw-test.sh`: `require_secured=YES` + marker absent → `AUTOSPAWN=NO`; marker present → unchanged; `require_secured=NO` → unchanged. ### Coupling Ships with clawdie-iso #139 in the same 0.12 image. #139 already sets the knob and its skip message promises this behavior — Part A makes the promise true. Boot-test on osa together.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: clawdie/colibri#183
No description provided.