mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-09-03 08:23:33 +02:00
Merge pull request #2813 from alexbelgium/claude/birdnet-db-reboot-persistence-dzku9z
fix(birdnet-go): harden sqlite path rewrite (traversal + parent dir)
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
## source-20260705-3 (05-07-2026)
|
||||||
|
- Harden the `output.sqlite.path` rewrite added for the persistence fix: reject paths containing `..` traversal segments (shared `validate_safe_path` check), and create the destination's parent directory under `/config` when the relative path includes a subdirectory (e.g. `db/birdnet.db`), since SQLite does not create missing parent directories itself.
|
||||||
|
|
||||||
## source-20260705-2 (05-07-2026)
|
## source-20260705-2 (05-07-2026)
|
||||||
- Fix detections/database not persisting across restarts on a fresh install: upstream's default `config.yaml` ships `output.sqlite.path: birdnet.db` (relative) explicitly, so the missing-only (`//=`) seeding introduced previously never rewrote it to an absolute path. A relative path resolves against the app's ephemeral working directory, so the database was silently recreated empty on every restart. Any relative `output.sqlite.path` is now rewritten to live under the persistent `/config` on startup; values already set to an absolute path are left untouched. (https://github.com/tphakala/birdnet-go/discussions/3774)
|
- Fix detections/database not persisting across restarts on a fresh install: upstream's default `config.yaml` ships `output.sqlite.path: birdnet.db` (relative) explicitly, so the missing-only (`//=`) seeding introduced previously never rewrote it to an absolute path. A relative path resolves against the app's ephemeral working directory, so the database was silently recreated empty on every restart. Any relative `output.sqlite.path` is now rewritten to live under the persistent `/config` on startup; values already set to an absolute path are left untouched. (https://github.com/tphakala/birdnet-go/discussions/3774)
|
||||||
|
|
||||||
|
|||||||
@@ -127,5 +127,5 @@ slug: birdnet-go-dev
|
|||||||
udev: true
|
udev: true
|
||||||
url: https://github.com/alexbelgium/hassio-addons
|
url: https://github.com/alexbelgium/hassio-addons
|
||||||
usb: true
|
usb: true
|
||||||
version: "source-20260705-2"
|
version: "source-20260705-3"
|
||||||
video: true
|
video: true
|
||||||
|
|||||||
@@ -17,12 +17,22 @@ normalize_path() {
|
|||||||
|
|
||||||
# Reject paths containing characters that would break the SQL/YAML literals
|
# Reject paths containing characters that would break the SQL/YAML literals
|
||||||
# we substitute into below. We deliberately allow only "safe" filename chars.
|
# we substitute into below. We deliberately allow only "safe" filename chars.
|
||||||
|
# Also reject ".." path segments so a relative path can't traverse outside
|
||||||
|
# the directory we prefix it with (e.g. "/config") when we rewrite it below.
|
||||||
validate_safe_path() {
|
validate_safe_path() {
|
||||||
local p="$1"
|
local p="$1"
|
||||||
if [[ ! "$p" =~ ^[A-Za-z0-9._/-]+$ ]]; then
|
if [[ ! "$p" =~ ^[A-Za-z0-9._/-]+$ ]]; then
|
||||||
bashio::log.fatal "Refusing unsafe path: '$p' (only [A-Za-z0-9._/-] allowed)"
|
bashio::log.fatal "Refusing unsafe path: '$p' (only [A-Za-z0-9._/-] allowed)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
local segment
|
||||||
|
local IFS=/
|
||||||
|
for segment in $p; do
|
||||||
|
if [[ "$segment" == ".." ]]; then
|
||||||
|
bashio::log.fatal "Refusing unsafe path: '$p' (path traversal '..' is not allowed)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ ! -f "$CONFIG_LOCATION" ]; then
|
if [ ! -f "$CONFIG_LOCATION" ]; then
|
||||||
@@ -149,8 +159,12 @@ bashio::log.info "Seeding default configuration values (only if missing)"
|
|||||||
CURRENT_SQLITE_PATH="$(yq -r '.output.sqlite.path // ""' "$CONFIG_LOCATION")"
|
CURRENT_SQLITE_PATH="$(yq -r '.output.sqlite.path // ""' "$CONFIG_LOCATION")"
|
||||||
if [[ -n "$CURRENT_SQLITE_PATH" && "$CURRENT_SQLITE_PATH" != /* ]]; then
|
if [[ -n "$CURRENT_SQLITE_PATH" && "$CURRENT_SQLITE_PATH" != /* ]]; then
|
||||||
validate_safe_path "$CURRENT_SQLITE_PATH"
|
validate_safe_path "$CURRENT_SQLITE_PATH"
|
||||||
bashio::log.warning "output.sqlite.path ('$CURRENT_SQLITE_PATH') is relative and would not persist across restarts; rewriting to /config/$CURRENT_SQLITE_PATH"
|
NEW_SQLITE_PATH="/config/${CURRENT_SQLITE_PATH}"
|
||||||
yq -i -y ".output.sqlite.path = \"/config/${CURRENT_SQLITE_PATH}\"" "$CONFIG_LOCATION"
|
bashio::log.warning "output.sqlite.path ('$CURRENT_SQLITE_PATH') is relative and would not persist across restarts; rewriting to $NEW_SQLITE_PATH"
|
||||||
|
# SQLite does not create missing parent directories, so ensure one exists
|
||||||
|
# if the (validated, traversal-free) path includes a subdirectory.
|
||||||
|
mkdir -p "$(dirname "$NEW_SQLITE_PATH")"
|
||||||
|
yq -i -y ".output.sqlite.path = \"${NEW_SQLITE_PATH}\"" "$CONFIG_LOCATION"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
yq -i -y '.output.sqlite.path //= "/config/birdnet.db"' "$CONFIG_LOCATION"
|
yq -i -y '.output.sqlite.path //= "/config/birdnet.db"' "$CONFIG_LOCATION"
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
## nightly-20260615-3 (05-07-2026)
|
||||||
|
- Harden the `output.sqlite.path` rewrite added for the persistence fix: reject paths containing `..` traversal segments (shared `validate_safe_path` check), and create the destination's parent directory under `/config` when the relative path includes a subdirectory (e.g. `db/birdnet.db`), since SQLite does not create missing parent directories itself.
|
||||||
|
|
||||||
## nightly-20260615-2 (05-07-2026)
|
## nightly-20260615-2 (05-07-2026)
|
||||||
- Minor bugs fixed
|
- Minor bugs fixed
|
||||||
- Fix detections/database not persisting across restarts on a fresh install: upstream's default `config.yaml` ships `output.sqlite.path: birdnet.db` (relative) explicitly, so the missing-only (`//=`) seeding introduced previously never rewrote it to an absolute path. A relative path resolves against the app's ephemeral working directory, so the database was silently recreated empty on every restart. Any relative `output.sqlite.path` is now rewritten to live under the persistent `/config` on startup; values already set to an absolute path are left untouched. (https://github.com/tphakala/birdnet-go/discussions/3774)
|
- Fix detections/database not persisting across restarts on a fresh install: upstream's default `config.yaml` ships `output.sqlite.path: birdnet.db` (relative) explicitly, so the missing-only (`//=`) seeding introduced previously never rewrote it to an absolute path. A relative path resolves against the app's ephemeral working directory, so the database was silently recreated empty on every restart. Any relative `output.sqlite.path` is now rewritten to live under the persistent `/config` on startup; values already set to an absolute path are left untouched. (https://github.com/tphakala/birdnet-go/discussions/3774)
|
||||||
|
|||||||
@@ -128,4 +128,4 @@ slug: birdnet-go
|
|||||||
udev: true
|
udev: true
|
||||||
url: https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-go
|
url: https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-go
|
||||||
usb: true
|
usb: true
|
||||||
version: "nightly-20260615-2"
|
version: "nightly-20260615-3"
|
||||||
|
|||||||
@@ -17,12 +17,22 @@ normalize_path() {
|
|||||||
|
|
||||||
# Reject paths containing characters that would break the SQL/YAML literals
|
# Reject paths containing characters that would break the SQL/YAML literals
|
||||||
# we substitute into below. We deliberately allow only "safe" filename chars.
|
# we substitute into below. We deliberately allow only "safe" filename chars.
|
||||||
|
# Also reject ".." path segments so a relative path can't traverse outside
|
||||||
|
# the directory we prefix it with (e.g. "/config") when we rewrite it below.
|
||||||
validate_safe_path() {
|
validate_safe_path() {
|
||||||
local p="$1"
|
local p="$1"
|
||||||
if [[ ! "$p" =~ ^[A-Za-z0-9._/-]+$ ]]; then
|
if [[ ! "$p" =~ ^[A-Za-z0-9._/-]+$ ]]; then
|
||||||
bashio::log.fatal "Refusing unsafe path: '$p' (only [A-Za-z0-9._/-] allowed)"
|
bashio::log.fatal "Refusing unsafe path: '$p' (only [A-Za-z0-9._/-] allowed)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
local segment
|
||||||
|
local IFS=/
|
||||||
|
for segment in $p; do
|
||||||
|
if [[ "$segment" == ".." ]]; then
|
||||||
|
bashio::log.fatal "Refusing unsafe path: '$p' (path traversal '..' is not allowed)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ ! -f "$CONFIG_LOCATION" ]; then
|
if [ ! -f "$CONFIG_LOCATION" ]; then
|
||||||
@@ -145,8 +155,12 @@ bashio::log.info "Seeding default configuration values (only if missing)"
|
|||||||
CURRENT_SQLITE_PATH="$(yq -r '.output.sqlite.path // ""' "$CONFIG_LOCATION")"
|
CURRENT_SQLITE_PATH="$(yq -r '.output.sqlite.path // ""' "$CONFIG_LOCATION")"
|
||||||
if [[ -n "$CURRENT_SQLITE_PATH" && "$CURRENT_SQLITE_PATH" != /* ]]; then
|
if [[ -n "$CURRENT_SQLITE_PATH" && "$CURRENT_SQLITE_PATH" != /* ]]; then
|
||||||
validate_safe_path "$CURRENT_SQLITE_PATH"
|
validate_safe_path "$CURRENT_SQLITE_PATH"
|
||||||
bashio::log.warning "output.sqlite.path ('$CURRENT_SQLITE_PATH') is relative and would not persist across restarts; rewriting to /config/$CURRENT_SQLITE_PATH"
|
NEW_SQLITE_PATH="/config/${CURRENT_SQLITE_PATH}"
|
||||||
yq -i -y ".output.sqlite.path = \"/config/${CURRENT_SQLITE_PATH}\"" "$CONFIG_LOCATION"
|
bashio::log.warning "output.sqlite.path ('$CURRENT_SQLITE_PATH') is relative and would not persist across restarts; rewriting to $NEW_SQLITE_PATH"
|
||||||
|
# SQLite does not create missing parent directories, so ensure one exists
|
||||||
|
# if the (validated, traversal-free) path includes a subdirectory.
|
||||||
|
mkdir -p "$(dirname "$NEW_SQLITE_PATH")"
|
||||||
|
yq -i -y ".output.sqlite.path = \"${NEW_SQLITE_PATH}\"" "$CONFIG_LOCATION"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
yq -i -y '.output.sqlite.path //= "/config/birdnet.db"' "$CONFIG_LOCATION"
|
yq -i -y '.output.sqlite.path //= "/config/birdnet.db"' "$CONFIG_LOCATION"
|
||||||
|
|||||||
Reference in New Issue
Block a user