feat: apply runs an overlay's state hooks (0041 step 7, #62) #63

Merged
marcos-mendez merged 3 commits from feat/overlay-state-hooks into main 2026-10-01 18:05:12 -03:00
marcos-mendez commented 2026-10-01 16:12:43 -03:00 (Migrated from github.com)

Item 1 of #62, needed by step 7 of handbook decision 0041 (Keel Web): keel converged only units, so turning coraza on in the spec wrote Monit's waf-blocks check and loaded nothing.

apply --system now runs an overlay's state hooks with enabled or disabled:

  • /usr/lib/keel/overlays/<name>/state, which the overlay's package ships (keel-overlay-coraza has it since common#21);
  • then every executable in /usr/lib/keel/overlays/<name>/state.d/, in name order, plain names only as run-parts has it. keel-web uses anubis/state.d/ to route its default site through Anubis while the overlay is enabled.

They run after the overlay's units come up and before they go down. A hook cannot be asked for its state, so keel records it in /var/lib/keel/overlays/<name> once every hook passed and runs them again only when the spec differs from the record (a second apply changes nothing; a new machine runs each hook once). A failed hook fails the step and records nothing. Nothing runs under --root. keel 0.15.0.

Items 2 to 4 of #62 stay open (diff and inspect for a unitless overlay, the Anubis key's file, Monit's re-encoding).

Test plan

  • tests/test_system_overlay_hooks.py (16 tests, written first): order around the units, the record, --root, state.d ordering and filtering; keel/system/hooks.py 100 percent, full suite at 99 percent
  • on the Keel Web image of step 7 (Keel-Linux/keel-web#1): simple to cloud simple and back through the spec; Coraza's hook and keel-web's ran once each way, records written, a second apply changed nothing, Monit gained and lost waf-blocks and anubis

After review (a510b9f)

  • hooks.state: {path, timeout} in the overlay manifest, validated (rule 12's checks; timeout 1 to 600 s, 120 by default); only a declared state hook runs. Handbook erratum: Keel-Linux/handbook#35.
  • Every hook runs within its timeout in its own session, killed whole on expiry.
  • Hooks, the overlay directory and state.d are lstat'ed: root's, not group or world writable, links only inside /usr/lib/keel/overlays; otherwise the step is refused.
  • The record holds the state and a digest of the hooks (paths and content hashes), so a hook installed later runs.
  • Under --root the step says "not run" only.
  • Tests: no record after a failing hook, dry-run lines, the timeout, ownership/mode/link refusals, the schema.
Item 1 of #62, needed by step 7 of handbook decision 0041 (Keel Web): keel converged only units, so turning `coraza` on in the spec wrote Monit's `waf-blocks` check and loaded nothing. `apply --system` now runs an overlay's state hooks with `enabled` or `disabled`: - `/usr/lib/keel/overlays/<name>/state`, which the overlay's package ships (keel-overlay-coraza has it since common#21); - then every executable in `/usr/lib/keel/overlays/<name>/state.d/`, in name order, plain names only as run-parts has it. keel-web uses `anubis/state.d/` to route its default site through Anubis while the overlay is enabled. They run after the overlay's units come up and before they go down. A hook cannot be asked for its state, so keel records it in `/var/lib/keel/overlays/<name>` once every hook passed and runs them again only when the spec differs from the record (a second apply changes nothing; a new machine runs each hook once). A failed hook fails the step and records nothing. Nothing runs under `--root`. keel 0.15.0. Items 2 to 4 of #62 stay open (diff and inspect for a unitless overlay, the Anubis key's file, Monit's re-encoding). ## Test plan - [x] `tests/test_system_overlay_hooks.py` (16 tests, written first): order around the units, the record, `--root`, `state.d` ordering and filtering; `keel/system/hooks.py` 100 percent, full suite at 99 percent - [x] on the Keel Web image of step 7 (Keel-Linux/keel-web#1): simple to cloud simple and back through the spec; Coraza's hook and keel-web's ran once each way, records written, a second apply changed nothing, Monit gained and lost `waf-blocks` and `anubis` ## After review (a510b9f) - `hooks.state: {path, timeout}` in the overlay manifest, validated (rule 12's checks; timeout 1 to 600 s, 120 by default); only a declared state hook runs. Handbook erratum: Keel-Linux/handbook#35. - Every hook runs within its timeout in its own session, killed whole on expiry. - Hooks, the overlay directory and `state.d` are lstat'ed: root's, not group or world writable, links only inside `/usr/lib/keel/overlays`; otherwise the step is refused. - The record holds the state and a digest of the hooks (paths and content hashes), so a hook installed later runs. - Under `--root` the step says "not run" only. - Tests: no record after a failing hook, dry-run lines, the timeout, ownership/mode/link refusals, the schema.
Sign in to join this conversation.
No description provided.