Commit graph

3 commits

Author SHA1 Message Date
Roland
aeebe8d833
zim: address PR review — config race, YAML null, path traversal, pinned build
Triage of Greptile findings on the default-Zim / configurable-directory PR:

- Stale config on restart (P1): settings update() only queues an async
  background_save, and the restart switch has no ordering guarantee (the switch
  worker pops LIFO), so start_kiwix_serve.sh could read the old zims_destination.
  Save the config synchronously before activating the restart switch.
- YAML null (P1): read_config_value.sh now treats an unquoted null/~ as unset
  (returns the default), matching PyYAML/the Python config layer.  A quoted
  "null" remains the literal string.
- Path traversal (P1/security): the settings API now rejects a zims_destination
  containing "..", and start_kiwix_serve.sh defends in depth by falling back to
  `zims` for any absolute/traversal/empty value, so Kiwix can never scan or
  rewrite library.xml outside the media root.
- Reproducible build (P2): pin the zim-tools image to 3.7.0 instead of :latest.

Tests added for null handling, traversal rejection (API + script).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 19:10:09 -06:00
Roland
19f4958fb5 zim: ship a default fallback Zim and honor the configured Zim directory
Two related gaps in how WROLPi serves Kiwix content:

1. A fresh WROLPi (or one whose zims are all corrupt/absent) showed a blank
   Kiwix.  Every image now ships a small built-in default Zim that Kiwix falls
   back to, telling the user to download real Zim files.

2. The startup scripts hardcoded the `/zims` directory, ignoring wrolpi.yaml's
   `zims_destination` (which the Python side already honors).

Changes:
- New wrolpi/scripts/read_config_value.sh: a zero-dependency (awk) reader so
  non-Python scripts can reliably read top-level wrolpi.yaml scalars.  Also a
  config_value() wrapper in wrolpi/scripts/lib.sh.
- New wrolpi/scripts/default_zim/: HTML source + a reproducible builder
  (ghcr.io/openzim/zim-tools) that outputs the committed wrolpi/blobs/default.zim.
- New wrolpi/blobs/: any committed blob here is copied to /opt/wrolpi-blobs by
  the pi-gen and debian-live builds; the Docker zim image bakes it in.
- start_kiwix_serve.sh honors zims_destination and falls back to the default
  Zim when no functioning zim is found.
- docker/zim/entrypoint.sh gains the same default-Zim fallback.  It needs no
  config read: it already scans the whole mounted media dir, and
  zims_destination is always a subdirectory of that mount.
- Changing zims_destination via the settings API now restarts Kiwix so it
  serves the new directory without a reboot.

Tests: new test_read_config_value.py, extended test_start_kiwix_serve.py
(configured dir + default-Zim fallback), and a root_api test for the restart.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 19:09:57 -06:00
Roland
cdcf771ffa kiwix: a corrupt zim must not bring down the whole server
A corrupt or partial *.zim (e.g. an interrupted download) is rejected by
kiwix-manage ("Cannot add zim ..."). start_kiwix_serve.sh could then leave
Kiwix down and reported a misleading "Could not find any Zim files" — and
if the bad zim was the only one, exit 2 killed the service with no restart.

- Import each zim independently; log and skip a failed add so the remaining
  valid zims are still served.
- Always ensure a library.xml exists (empty if needed) and exec kiwix-serve
  unconditionally, so a corrupt/absent zim never stops the server starting.
- Fix the mount-wait loop, which never incremented COUNT (infinite wait
  instead of a 30s timeout).
- Add MEDIA_DIRECTORY override so the script is testable.
- Add Restart=on-failure to wrolpi-kiwix.service (matches wrolpi-api.service)
  so transient failures self-heal.
- New test harness runs the script with fake kiwix-manage/kiwix-serve shims.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 13:06:46 -06:00