Files
hassio-addons/webtop_kde/rootfs/etc/cont-init.d/81-microsoft_edge.sh
Alexandre dc1044e453 fix(webtop,webtop_kde,claude_desktop): give Selkies XDG_RUNTIME_DIR and the right websocket port (#2921)
* fix(webtop,webtop_kde,claude_desktop): give Selkies XDG_RUNTIME_DIR and the right WS port

Selkies panics with `RuntimeDirNotSet` right after its data websocket server
comes up, and binds that server on 8081 while nginx proxies 8082.

Upstream relies on s6-rc ordering: init-selkies-config publishes
XDG_RUNTIME_DIR and CUSTOM_WS_PORT into the s6 envdir, and svc-selkies is
started afterwards. ha_entrypoint.sh replaces s6-overlay and launches every
s6-rc.d run script in parallel with no dependency graph, so a longrun can
snapshot the envdir (with-contenv reads it once, at exec) before the oneshot
has written to it. Port 8081 in the report is the proof: that is selkies' own
default, not the 8082 init-selkies-config writes near the end of its run.

Only the webtop images carry PIXELFLUX_WAYLAND=true, which is why the missing
runtime dir reaches a Wayland socket bind there and not on claude_desktop.

20-folders.sh now exports both variables inside each run script, where no
start ordering can lose them, and 90-ingress.sh derives the nginx CWS
substitution from the same value.

Also correct the base image's $HOME/.XDG override where that write happens
rather than appending a correction to init-selkies-config: the oneshot
tolerance block appends `exit 0`, so on every boot after the first the
appended correction sat past it and never ran.

81-microsoft_edge.sh (webtop only), addressing the open review comments on
PR #2920:
- apt-get/dpkg failures no longer abort cont-init; each is guarded, warns and
  exits 0, and apt acquisition is bounded so a stalled mirror cannot hang
  start-up
- quote ${EDGE_VERSION+x}
- gate the wrapper swap on /helpers/microsoft-edge-stable still existing, so a
  second run cannot move the installed wrapper aside with nothing to replace it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(claude_desktop): inject the run-script exports after the data_location rewrite

Two findings from an independent review of the previous commit.

The `s|$DEFAULT_LOCATION|$LOCATION|g` pass over the s6-rc.d run scripts is a
blind textual substitution, and it ran after the export injection. A
data_location *under* the image default -- /config/data_kde/foo on an image
whose default is /config/data_kde -- therefore rewrote the freshly injected
`export HOME=/config/data_kde/foo` into `.../foo/foo`. Injecting after the
rewrite instead of before removes the double substitution.

Quote the injected values so a location containing whitespace cannot produce a
broken run script. XDG_CACHE_HOME stays unquoted: the loop greps for it as its
idempotence marker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(webtop,webtop_kde,claude_desktop): address review feedback on the Selkies env fix

Refresh the injected run-script exports on every boot (codex, coderabbit).
They were guarded by the XDG_CACHE_HOME sentinel, so they were written once and
then survived in the writable layer. Raising PUID left every service exporting a
/run/user/<old-uid> the remapped abc user cannot use, and clearing a custom
CUSTOM_WS_PORT left Selkies on the old port while 90-ingress.sh moved nginx back
to 8082 -- with the envdir written at the same boot disagreeing with both. The
exports now sit in a marked managed block that is stripped and rewritten each
boot, mirroring how the ~/.bashrc block in the same script already works. The
sweep also removes the bare exports earlier versions wrote, so an upgraded
container cannot end up with two sets. No upstream run script in these images
sets any of the five, so it only ever removes our own.

Validate CUSTOM_WS_PORT once, where it enters (coderabbit). It is interpolated
into generated shell and into a sed replacement, so a non-numeric or
out-of-range value could corrupt a run script or the nginx config. 90-ingress.sh
repeats the check rather than trusting the envdir, so a malformed value cannot
reach the nginx config if 20-folders.sh did not get that far.

Download Edge to an mktemp path instead of a fixed /tmp/edge.deb (coderabbit).
This runs as root against a world-writable tmpfs, where a predictable name can
be pre-created as a symlink to redirect the download or swap what is installed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 17:05:07 +02:00

87 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# Webtop-only. Lives here rather than in the shared 80-configuration.sh so the Selkies startup
# scripts stay identical across claude_desktop, webtop and webtop_kde. It also carries the
# ownership fixup that used to sit in 20-folders.sh, which ran before this install and so
# never had anything to match.
if ! bashio::config.true 'install_ms_edge'; then
exit 0
fi
# Every step below is bounded and non-fatal. cont-init.d blocks the whole add-on, so an
# unreachable or stalled packages.microsoft.com -- or a Debian mirror having a bad day -- must
# not hang or kill startup: the desktop is useful without Edge, an add-on stuck before Selkies
# starts is not. `set -e` would turn any apt or dpkg hiccup into exactly that, so each command
# is guarded and every failure path warns and exits 0.
EDGE_DEB=""
edge_giveup() {
bashio::log.warning "$1; skipping the Microsoft Edge install"
if [ -n "$EDGE_DEB" ]; then
rm -f "$EDGE_DEB"
fi
exit 0
}
bashio::log.info "Adding microsoft edge"
# -o Acquire::*Timeout bounds the mirror handshake/transfer the same way --max-time bounds curl.
APT_TIMEOUTS=(-o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 -o Acquire::Retries=1)
apt-get "${APT_TIMEOUTS[@]}" update || edge_giveup "apt-get update failed"
apt-get "${APT_TIMEOUTS[@]}" install --no-install-recommends -y ca-certificates \
|| edge_giveup "Installing ca-certificates failed"
EDGE_REPO="https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-stable"
if [ -z "${EDGE_VERSION+x}" ]; then
EDGE_VERSION=$(curl -sL --fail --connect-timeout 15 --max-time 120 "$EDGE_REPO/" \
| awk -F'(<a href="microsoft-edge-stable_|_amd64.deb\")' '/href=/ {print $2}' | sort --version-sort | tail -1 || true)
fi
if [ -z "$EDGE_VERSION" ]; then
edge_giveup "Could not determine the latest Microsoft Edge version"
fi
# mktemp rather than a fixed /tmp/edge.deb: this runs as root, and a predictable name in a
# world-writable tmpfs is something another process could pre-create as a symlink to redirect
# the download or swap what gets installed.
EDGE_DEB="$(mktemp -t microsoft-edge.XXXXXXXXXX.deb)" || edge_giveup "Could not create a temporary file"
curl -o "$EDGE_DEB" -L --fail --connect-timeout 15 --max-time 600 \
"$EDGE_REPO/microsoft-edge-stable_${EDGE_VERSION}_amd64.deb" \
|| edge_giveup "Downloading Microsoft Edge ${EDGE_VERSION} failed"
dpkg -I "$EDGE_DEB" || edge_giveup "The downloaded Microsoft Edge package is not a valid .deb"
apt-get "${APT_TIMEOUTS[@]}" install --no-install-recommends -y "$EDGE_DEB" \
|| edge_giveup "Installing Microsoft Edge ${EDGE_VERSION} failed"
rm -f "$EDGE_DEB"
bashio::log.info "Applying edge docker tweaks"
# Gated on the helper still being in /helpers, which is where the image ships it and where it
# stops being once installed. Without the guard a second run would move the wrapper already
# sitting in /usr/bin aside as "-real" with nothing left to take its place, and Edge would
# stop launching.
if [ -f /helpers/microsoft-edge-stable ]; then
if [ -f /usr/bin/microsoft-edge-stable ]; then
mv /usr/bin/microsoft-edge-stable /usr/bin/microsoft-edge-real
elif [ -f /usr/bin/microsoft-edge ]; then
mv /usr/bin/microsoft-edge /usr/bin/microsoft-edge-real
fi
mv /helpers/microsoft-edge-stable /usr/bin/
fi
# The wrapper and the real binary must be usable by the desktop user, whose identity
# 20-folders.sh has already settled by the time this runs. Guarded against an empty glob:
# without nullglob the literal pattern would reach chown, and `set -e` would then abort
# container startup rather than just skipping a fixup that has nothing to do.
shopt -s nullglob
edge_binaries=(/usr/bin/microsoft-edge*)
shopt -u nullglob
if [ "${#edge_binaries[@]}" -gt 0 ]; then
chown "$(id -u abc):$(id -g abc)" "${edge_binaries[@]}"
chmod +x "${edge_binaries[@]}"
else
bashio::log.warning "Edge install reported success but no /usr/bin/microsoft-edge* binary is present"
fi