Author SHA1 Message Date
clawbot 3a335bbabe fix: container sets up its own data directory (closes #75)
check / check (push) Successful in 1m51s
bin/entrypoint.sh, still running as root, now creates DATA_DIR if
missing and gives it and /data to the netwatch user with mode 750
before starting the backend as that user. It stops the start instead
when a symbolic link is on the path to /data or DATA_DIR, since chown
and chmod would change what the link points to. An empty host
directory owned by root, or one holding files from another uid, works
with no step on the host, so the README no longer tells the operator
to create or chown it. The image no longer sets that ownership at
build time.

Model: opus-5-5
2026-09-29 09:59:40 +00:00
3 changed files with 17 additions and 45 deletions
+2 -4
View File
@@ -216,10 +216,8 @@ What the [upaas](https://git.eeqj.de/sneak/upaas) app for netwatch needs:
- `CORS_ALLOWED_ORIGINS`, default empty: other origins whose pages may call - `CORS_ALLOWED_ORIGINS`, default empty: other origins whose pages may call
the API the API
- `DEBUG`, default `false`: debug logging - `DEBUG`, default `false`: debug logging
- `DATA_DIR`, default `/data/reports`: the directory the reports are kept - `DATA_DIR`, default `/data/reports`: leave unset; reports kept outside
in: `/data` or a path below it, with no `.` or `..` part and no extra `/`. `/data` do not survive a redeploy
The container also stops if a part of the path that exists, `/data`
included, is a symbolic link
- `TRUSTED_PROXIES`, default empty: set it to the address the reverse proxy - `TRUSTED_PROXIES`, default empty: set it to the address the reverse proxy
in front of the container connects from, as an IP address or CIDR; several in front of the container connects from, as an IP address or CIDR; several
are separated by commas. nginx takes the client address from are separated by commas. nginx takes the client address from
-8
View File
@@ -23,14 +23,6 @@ latest run passes.
# Completed Steps # Completed Steps
- 2026-09-29: `bin/entrypoint.sh` checks `DATA_DIR` in full before it acts on it
as root (issue #80): `DATA_DIR` must be `/data` or a path below it with no
`.`, `..` or empty part, and no part of it that exists, `/data` included, may
be a symbolic link; anything else stops the start with a message naming
`DATA_DIR`. Only then is `DATA_DIR` created and `/data` given to `netwatch`,
so a refused start no longer creates directories outside `/data`, and
`DATA_DIR=/etc` no longer gives `/etc` to `netwatch`. The `README.md` section
"Running under upaas" says which values are accepted
- 2026-09-29: the container sets up its own data directory (issue #75): - 2026-09-29: the container sets up its own data directory (issue #75):
`bin/entrypoint.sh`, still as root, creates `DATA_DIR` if missing and gives it `bin/entrypoint.sh`, still as root, creates `DATA_DIR` if missing and gives it
and `/data` to the `netwatch` user with mode 750 before starting the backend and `/data` to the `netwatch` user with mode 750 before starting the backend
+15 -33
View File
@@ -63,43 +63,25 @@ done > /etc/nginx/trusted-proxies.conf
# netwatch-server keeps its report files in DATA_DIR, on the /data # netwatch-server keeps its report files in DATA_DIR, on the /data
# volume, which may be a host directory owned by root or by another # volume, which may be a host directory owned by root or by another
# uid. /data and everything in it are given to the netwatch user here, # uid. Both are given to the netwatch user here, with the mode the
# and /data and DATA_DIR get the mode the server gives a directory it # server gives a directory it creates, so the host directory needs no
# creates, so the host directory needs no preparing. # preparing.
# #
# This runs as root, so nothing is created or changed until DATA_DIR is # chown and chmod, run as root, change whatever a symbolic link on the
# known to be /data or a path below it, with no '.', '..' or empty # path points to, anywhere in the container, and the netwatch user can
# part, and no part of it that exists, /data included, is a symbolic # put one in /data. So the start stops unless readlink -f, which
# link: the netwatch user can put one in /data, and root would follow # follows every link on a path, gives /data and DATA_DIR back as they
# it anywhere in the container. Nothing else runs in the container yet, # are. It also writes a path in full, so a DATA_DIR with '.', '..' or
# so no link can appear after the check. # an extra '/' in it is refused too.
export DATA_DIR="${DATA_DIR:-/data/reports}" export DATA_DIR="${DATA_DIR:-/data/reports}"
data_dir_ok() { mkdir -p "$DATA_DIR" || exit 1
# With a / added at the end, a last part of '.' or '..', and a / at if [ "$(readlink -f /data)" != /data ] ||
# the end, match these patterns too. [ "$(readlink -f "$DATA_DIR")" != "$DATA_DIR" ]; then
case "$DATA_DIR/" in echo "entrypoint: DATA_DIR must be a full path with no '.', '..'," \
*/./* | */../* | *//*) return 1 ;; "extra '/' or symbolic link on it or on /data, not '$DATA_DIR'" >&2
/data/*) ;;
*) return 1 ;;
esac
# Each part from DATA_DIR up to /data. [ -L ] is false for a part
# that does not exist.
dir="$DATA_DIR"
while [ "$dir" != /data ]; do
[ -L "$dir" ] && return 1
dir="${dir%/*}"
done
[ ! -L /data ]
}
if ! data_dir_ok; then
echo "entrypoint: DATA_DIR must be /data or a path below it, with no" \
"'.', '..', extra '/' or symbolic link on it, not '$DATA_DIR'" >&2
exit 1 exit 1
fi fi
mkdir -p "$DATA_DIR" || exit 1 chown -R netwatch:netwatch /data "$DATA_DIR" || exit 1
# -h: a symbolic link in /data is itself given to netwatch, not what it
# points to.
chown -R -h netwatch:netwatch /data || exit 1
chmod 750 /data "$DATA_DIR" || exit 1 chmod 750 /data "$DATA_DIR" || exit 1
# A stop signal is only noted here; the loop below acts on it. # A stop signal is only noted here; the loop below acts on it.