Two bugs fixed:
1. audit_service.py: log_action() inserted into audit_logs using the
caller's DB session but never committed. Any router that called
db.commit() before log_action() (firmware, devices, config_editor,
alerts, certificates) had its audit rows silently rolled back when
the request session closed.
Fix: log_action now opens its own AdminAsyncSessionLocal and self-
commits, making audit persistence independent of the caller's
transaction. The 'db' parameter is kept for backward compat but
unused. Affects 5 routers (firmware, devices, config_editor,
alerts, certificates).
2. docker-compose.override.yml: /data/firmware-cache had no volume
mount so the directory didn't exist in the container, causing
firmware downloads to fail with Permission denied.
Fix: bind-mount docker-data/firmware-cache:/data/firmware-cache
so firmware images survive container restarts.
- poller/docker-entrypoint.sh: convert from CRLF+BOM to LF (UTF-8 no BOM)
Windows saved the file with a UTF-8 BOM which made the Linux kernel
reject the shebang with 'exec format error', crashing the poller.
- infrastructure/openbao/init.sh: same CRLF -> LF fix
- poller/Dockerfile: add sed to strip CRLF and BOM at image build time
as a defensive measure for future Windows edits
- docker-compose.override.yml: add 'restart: on-failure' to api and poller
so they recover from the postgres startup race (TimescaleDB restarts
postgres after initdb, briefly causing connection refused on first boot)
- .gitattributes: enforce LF for all text/script/code files so git
normalises line endings on checkout and prevents this class of bug