Files
felhom.eu/documentation/audits/burndown-3-2026-10-17/tools/damage.sh
T
admin e1dd1cadd3
gates / gates (push) Successful in 7m2s
burndown 3: report, evidence, register (174 -> 168), 07 Redis RDB [DESIGN], 04 §6.3 the box's password doors
Closed R-1115, R-1111, R-1112, R-1113, R-1109, R-1110, R-1114, R-1096; opened R-1116 (decoy suites in the other
runners), R-1117 (Immich/Nextcloud Redis volume, deferred). Controller 0.325.0 is the floor since 08:21 UTC.

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-17 10:28:03 +02:00

49 lines
3.7 KiB
Bash
Executable File

#!/bin/bash
# damage.sh — R-1096 step 3, inside scratch guest 9202. Throwaway containers named r1096-*, removed at the end.
# Input: /root/r1096/aof-copy = docmost-redis's /data copied while it ran the OLD form (AOF), taken before the switch.
set -u
IMG=redis:7-alpine
W=/root/r1096/work; rm -rf $W; mkdir -p $W
say() { echo "== $*"; }
run_on() { # run_on <dir> <args...>: start redis on a COPY of <dir>, report whether it serves and its last log lines
local d=$1; shift
docker rm -f r1096-probe >/dev/null 2>&1
docker run -d --name r1096-probe -v $d:/data $IMG redis-server "$@" >/dev/null
sleep 4
echo " state: $(docker inspect -f '{{.State.Status}} exit={{.State.ExitCode}}' r1096-probe)"
echo " dbsize: $(docker exec r1096-probe redis-cli DBSIZE 2>&1 | head -1) probe key 7: $(docker exec r1096-probe redis-cli GET felhom:probe:7 2>&1 | cut -c1-6)…"
docker logs r1096-probe 2>&1 | grep -iE 'Bad file|Unrecoverable|Short read|corrupt|loaded|fix|Ready|aborting|error|Done loading' | tail -4 | sed 's/^/ log: /'
docker rm -f r1096-probe >/dev/null 2>&1
}
say "A1 CONTROL: the old-form copy, undamaged, --appendonly yes"
cp -a /root/r1096/aof-copy $W/a1; chown -R 999:1000 $W/a1
run_on $W/a1 --appendonly yes
say "A2 the old form, damaged the 2026-09-24 way: 64 zero bytes written INTO the AOF, 400 bytes before its end"
cp -a /root/r1096/aof-copy $W/a2; chown -R 999:1000 $W/a2
F=$W/a2/appendonlydir/appendonly.aof.1.incr.aof; S=$(stat -c %s $F)
dd if=/dev/zero of=$F bs=1 seek=$((S-400)) count=64 conv=notrunc status=none
echo " file $S bytes, zeros at $((S-400))..$((S-337)); size after $(stat -c %s $F)"
run_on $W/a2 --appendonly yes
say "R1 the NEW form on a FULL disk (tmpfs 1 MiB): a save that cannot be written"
docker rm -f r1096-full >/dev/null 2>&1
docker run -d --name r1096-full --tmpfs /data:rw,size=1m,uid=999,gid=1000 $IMG sleep infinity >/dev/null
docker exec r1096-full sh -c 'mkdir -p /data/r && chown redis /data/r && su redis -s /bin/sh -c "redis-server --port 6390 --dir /data/r --appendonly no --daemonize yes --logfile /data/r.log" ' ; sleep 1
docker exec r1096-full sh -c 'for i in $(seq 1 50); do redis-cli -p 6390 SET felhom:probe:$i v$i >/dev/null; done; redis-cli -p 6390 SAVE; sha256sum /data/r/dump.rdb; ls -la /data/r'
echo " now 1.2 MB of new data, which cannot fit:"
docker exec r1096-full sh -c 'head -c 900000 /dev/urandom | base64 -w0 | redis-cli -p 6390 -x SET big >/dev/null; redis-cli -p 6390 BGSAVE; sleep 2; redis-cli -p 6390 INFO persistence | grep -E "rdb_last_bgsave_status|rdb_changes_since"; redis-cli -p 6390 SET after-fail 1; sha256sum /data/r/dump.rdb; ls -la /data/r; df -k /data | tail -1; tail -3 /data/r.log'
echo " stop WITHOUT saving (what a kill does), start again on the same folder:"
docker exec r1096-full sh -c 'redis-cli -p 6390 SHUTDOWN NOSAVE; sleep 1; su redis -s /bin/sh -c "redis-server --port 6390 --dir /data/r --appendonly no --daemonize yes --logfile /data/r2.log"; sleep 1; echo " dbsize after start: $(redis-cli -p 6390 DBSIZE) probe 7: $(redis-cli -p 6390 GET felhom:probe:7)"; grep -E "Done loading|Short read|Unrecoverable" /data/r2.log | tail -2'
docker rm -f r1096-full >/dev/null
say "R2 what a TRUNCATED dump.rdb does (half the file) — the shape the temp-file-and-rename write never leaves behind"
mkdir -p $W/r2; cp /var/lib/docker/volumes/docmost_docmost_redis_data/_data/dump.rdb $W/r2/full.rdb
S=$(stat -c %s $W/r2/full.rdb); head -c $((S/2)) $W/r2/full.rdb > $W/r2/dump.rdb; rm $W/r2/full.rdb; chown -R 999:1000 $W/r2
echo " dump.rdb cut from $S to $(stat -c %s $W/r2/dump.rdb) bytes"
run_on $W/r2 --appendonly no
rm -rf $W
say "cleanup: $(docker ps -a --filter name=r1096- --format '{{.Names}}' | wc -l) r1096-* containers left"