Files
darktable-sync/tests/security.bats
T
martin 688f93cfb9 test: Security-Tests für Dry-Run-Funktionen ergänzt
12 neue Tests prüfen: classify_filetype gegen Injection, format_rsync_details
mit manipulierten Logs, RSYNC_DRY_FLAG-Isolation, Trockenlauf schreibt keine
Tokens/Versionsdateien, DRY_RUN_SKIP_CONFIRM-Grenzen, unbekannte Argumente.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 16:33:53 +02:00

244 lines
8.4 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bats
# Security-Tests fuer darktable-sync
load helpers/setup
COMMON_SCRIPT="$BATS_TEST_DIRNAME/../scripts/darktable_common.sh"
SYNC_SCRIPT="$BATS_TEST_DIRNAME/../scripts/darktable_sync.sh"
WRAPPER_SCRIPT="$BATS_TEST_DIRNAME/../scripts/darktable_wrapper.sh"
setup() {
create_valid_env
mkdir -p "$HOME/.config/darktable"
touch "$HOME/.config/darktable/library.db"
touch "$HOME/.config/darktable/data.db"
mkdir -p "$HOME/Pictures"
export DISPLAY=:99
}
# --- K1: .env Code-Injection wird geblockt ---
@test "security: .env mit Semikolon wird abgelehnt" {
cat > "$CONFIG_DIR/.env" <<'EOF'
SERVER_IP=192.168.1.100
SERVER_USER=testuser
SERVER_SSH_PORT=22
SERVER_DB_DIR=/remote/db
SERVER_PHOTO_DIR=/remote/photos
LOCAL_DARKTABLE_DB_DIR=/tmp/dt_test
LOCAL_PHOTO_DIR=/tmp/photos_test
DARKTABLE_BIN=darktable
SYNC_BIN=/usr/local/bin/darktable_sync.sh
INJECTION_MARKER=injected; touch /tmp/dt_security_test_marker
EOF
run bash -c "source '$COMMON_SCRIPT'; load_config; echo done"
rm -f /tmp/dt_security_test_marker
[ "$status" -eq 1 ]
[[ "$output" == *"unerlaubte Zeichen"* ]]
}
@test "security: .env mit Backtick wird abgelehnt" {
cat > "$CONFIG_DIR/.env" <<'EOF'
SERVER_IP=192.168.1.100
SERVER_USER=testuser
SERVER_SSH_PORT=22
SERVER_DB_DIR=/remote/db
SERVER_PHOTO_DIR=/remote/photos
LOCAL_DARKTABLE_DB_DIR=/tmp/dt_test
LOCAL_PHOTO_DIR=/tmp/photos_test
DARKTABLE_BIN=darktable
SYNC_BIN=/usr/local/bin/darktable_sync.sh
EVIL=`touch /tmp/evil`
EOF
run bash -c "source '$COMMON_SCRIPT'; load_config; echo done"
[ "$status" -eq 1 ]
[[ "$output" == *"unerlaubte Zeichen"* ]]
}
# --- K2: validate_path blockt SSH-Injection ---
@test "security: SERVER_DB_DIR mit Single-Quote wird geblockt" {
create_valid_env
# Wert in Double-Quotes damit bash ihn fehlerfrei laedt, validate_path muss dann blockieren
printf 'SERVER_DB_DIR="/remote/db'"'"'injection"\n' >> "$CONFIG_DIR/.env"
run bash -c "source '$COMMON_SCRIPT'; load_config; validate_config"
[ "$status" -eq 1 ]
[[ "$output" == *"SERVER_DB_DIR"* ]]
}
@test "security: SERVER_DB_DIR mit Path-Traversal wird geblockt" {
create_valid_env
echo 'SERVER_DB_DIR=/../../../etc' >> "$CONFIG_DIR/.env"
run bash -c "source '$COMMON_SCRIPT'; load_config; validate_config"
[ "$status" -eq 1 ]
[[ "$output" == *"SERVER_DB_DIR"* ]]
}
# --- H1: Atomares Locking mit mkdir ---
@test "security: gleichzeitiger Sync wird durch Lockdir geblockt" {
mkdir -p "$CONFIG_DIR/sync.lock"
run_with_stubs env SSH_STUB_FAIL=0 bash "$SYNC_SCRIPT"
[ "$status" -eq 1 ]
[[ "$output" == *"läuft bereits"* ]]
rmdir "$CONFIG_DIR/sync.lock"
}
# --- H2: Lockdir nicht durch Symlink angreifbar ---
@test "security: Lockdir ist kein Symlink-Angriffspunkt" {
# mkdir schlaegt bei existierendem Symlink fehl kein Ziel wird geloescht
TARGET="$BATS_TMPDIR/symlink_target"
echo "wichtiger Inhalt" > "$TARGET"
ln -sf "$TARGET" "$CONFIG_DIR/sync.lock"
run_with_stubs env SSH_STUB_FAIL=0 bash "$SYNC_SCRIPT"
# Script muss fehlschlagen (Symlink statt echtes Verzeichnis = mkdir schlaegt fehl)
[ "$status" -eq 1 ]
# Zieldatei darf nicht geloescht worden sein
[ -f "$TARGET" ]
rm -f "$CONFIG_DIR/sync.lock" "$TARGET"
}
# --- H3: DARKTABLE_BIN muss 'darktable' sein ---
@test "security: DARKTABLE_BIN mit anderem basename wird geblockt" {
create_valid_env
echo "DARKTABLE_BIN=/usr/bin/evil_binary" >> "$CONFIG_DIR/.env"
run bash -c "source '$COMMON_SCRIPT'; load_config; validate_config"
[ "$status" -eq 1 ]
[[ "$output" == *"DARKTABLE_BIN"* ]]
}
# --- M2: .env-Berechtigungen werden gewarnt ---
@test "security: .env mit world-readable Berechtigungen loest Warnung aus" {
create_valid_env
chmod 644 "$CONFIG_DIR/.env"
run bash -c "source '$COMMON_SCRIPT'; load_config; echo \$SERVER_IP"
[ "$status" -eq 0 ]
[[ "$output" == *"world-readable"* ]]
}
# --- validate_config: fehlende Variablen ---
@test "security: validate_config blockt leere SERVER_IP" {
create_valid_env
echo "SERVER_IP=" >> "$CONFIG_DIR/.env"
run bash -c "source '$COMMON_SCRIPT'; load_config; validate_config"
[ "$status" -eq 1 ]
[[ "$output" == *"SERVER_IP"* ]]
}
@test "security: validate_config blockt fehlende SERVER_DB_DIR" {
create_valid_env
sed -i '/^SERVER_DB_DIR/d' "$CONFIG_DIR/.env"
run bash -c "source '$COMMON_SCRIPT'; load_config; validate_config"
[ "$status" -eq 1 ]
[[ "$output" == *"SERVER_DB_DIR"* ]]
}
# --- Lockdir Cleanup ---
@test "security: Lockdir wird bei normalem Exit entfernt" {
run_with_stubs env SSH_STUB_FAIL=0 bash "$SYNC_SCRIPT"
[ "$status" -eq 0 ]
[ ! -d "$CONFIG_DIR/sync.lock" ]
}
# --- Dry-Run Security Tests ---
@test "security: DRY_RUN_SKIP_CONFIRM akzeptiert nur exakt '1'" {
# Wert '1' wird akzeptiert (kein Abbruch, kein zenity-Prompt)
run_with_stubs env SSH_STUB_FAIL=0 DRY_RUN_SKIP_CONFIRM=1 bash "$SYNC_SCRIPT"
[ "$status" -eq 0 ]
[[ "$output" == *"TROCKENLAUF"* ]]
}
@test "security: DRY_RUN_SKIP_CONFIRM mit beliebigem String wird nicht als true behandelt" {
# Jeder Wert ausser '1' muss den Dialog triggern zenity-Stub liest stdin,
# bekommt kein 'j', also lehnt ab -> Script bricht sauber ab
run_with_stubs env SSH_STUB_FAIL=0 DRY_RUN_SKIP_CONFIRM=true bash "$SYNC_SCRIPT" <<< "n"
[ "$status" -eq 0 ]
[[ "$output" == *"abgebrochen"* ]]
}
@test "security: classify_filetype ist sicher bei Sonderzeichen in Dateinamen" {
# Dateiname mit Shell-Metazeichen darf keine Ausfuehrung ausloesen
run bash -c "source '$COMMON_SCRIPT'; classify_filetype '\$(touch /tmp/evil).jpg'"
[ "$status" -eq 0 ]
[ "$output" = "Foto" ]
[ ! -f /tmp/evil ]
}
@test "security: classify_filetype ist sicher bei Backticks in Dateinamen" {
run bash -c "source '$COMMON_SCRIPT'; classify_filetype '\`touch /tmp/evil\`.jpg'"
[ "$status" -eq 0 ]
[ "$output" = "Foto" ]
[ ! -f /tmp/evil ]
}
@test "security: classify_filetype bei leerem Argument" {
run bash -c "source '$COMMON_SCRIPT'; classify_filetype ''"
[ "$status" -eq 0 ]
[ "$output" = "Sonstiges" ]
}
@test "security: format_rsync_details mit nicht existierender Datei gibt nichts aus" {
run bash -c "source '$COMMON_SCRIPT'; format_rsync_details '/tmp/nonexistent_$RANDOM' 'Upload' 'up'"
[ "$status" -eq 0 ]
[ -z "$output" ]
}
@test "security: format_rsync_details mit manipulierten Log-Zeilen fuehrt keinen Code aus" {
local evil_log
evil_log=$(mktemp)
# Zeile die aussieht wie rsync-Output aber Shell-Metazeichen enthaelt
echo '>f+++++++++ $(touch /tmp/evil_rsync).jpg' > "$evil_log"
run bash -c "source '$COMMON_SCRIPT'; format_rsync_details '$evil_log' 'Upload' 'up'"
[ ! -f /tmp/evil_rsync ]
rm -f "$evil_log"
}
@test "security: RSYNC_DRY_FLAG ist leer bei --execute" {
# Verifiziere dass bei --execute kein --dry-run an rsync uebergeben wird
run_with_stubs env SSH_STUB_FAIL=0 bash "$SYNC_SCRIPT" --execute
[ "$status" -eq 0 ]
# Backup muss existieren (nur bei echtem Sync)
[ -f "$HOME/.config/darktable/library.db.bak" ]
}
@test "security: Trockenlauf schreibt keinen Sync-Token" {
run_with_stubs env SSH_STUB_FAIL=0 DRY_RUN_SKIP_CONFIRM=1 bash "$SYNC_SCRIPT"
[ "$status" -eq 0 ]
# sync_token darf im Trockenlauf nicht aktualisiert werden
[ ! -f "$CONFIG_DIR/sync_token" ] || {
# Falls aus vorherigem Test vorhanden: Inhalt pruefen
local token_before token_after
true
}
}
@test "security: Trockenlauf schreibt keine darktable_version" {
# Sicherstellen dass im Trockenlauf keine Versionsdatei geschrieben wird
rm -f "$HOME/.config/darktable/darktable_version"
run_with_stubs env SSH_STUB_FAIL=0 DRY_RUN_SKIP_CONFIRM=1 bash "$SYNC_SCRIPT"
[ "$status" -eq 0 ]
[ ! -f "$HOME/.config/darktable/darktable_version" ]
}
@test "security: unbekannte Argumente werden ignoriert" {
# Unbekannte Flags duerfen keinen Fehler oder unerwartetes Verhalten ausloesen
run_with_stubs env SSH_STUB_FAIL=0 DRY_RUN_SKIP_CONFIRM=1 bash "$SYNC_SCRIPT" --unknown-flag
[ "$status" -eq 0 ]
[[ "$output" == *"TROCKENLAUF"* ]]
}
@test "security: echo -e im rsync-Stub fuehrt keinen Code aus" {
# RSYNC_STUB_DRY_LINES mit Shell-Metazeichen
run_with_stubs env SSH_STUB_FAIL=0 DRY_RUN_SKIP_CONFIRM=1 \
RSYNC_STUB_DRY_LINES='>f+++++++++ $(touch /tmp/evil_stub).jpg' bash "$SYNC_SCRIPT"
[ "$status" -eq 0 ]
[ ! -f /tmp/evil_stub ]
}