Compare commits

...

4 Commits

Author SHA1 Message Date
hugoo ༄ ˚。⋆★
f70fbe9705 Portainer Agent: use alpine-sts upstream image (#3011)
* fix(portainer-agent): use alpine-sts upstream image

* fix(portainer-agent): align STS updater versioning
2026-08-23 18:44:19 +02:00
Alexandre
9204b31af8 fix(calibre-web): trust the supervisor range for the ingress auth header (#3010)
* fix(calibre-web): trust the supervisor range for the ingress auth header

Reimplements #3004 from the code as it stood before it, in one statement.

#3004 derived the addon's own address and wrote it unconditionally on every
start. That address changes across restarts, so the value had to be rewritten
each boot, which erased anything the user had added to the same field from the
calibre-web admin page -- and a follow-up that preserved their entries needed a
merge pass and a record of what had been injected, because a preserved stale
address stays trusted after supervisor hands it to another addon.

Trusting 172.30.32.0/23 removes the reason for all of it: the range covers
whichever address the addon gets, so the value is constant and can be written
once. Both forms are listed because calibre-web listens dual-stack and an ipv4
entry never matches an ipv4-mapped address; /119 is the mapped equivalent of
/23.

The WHERE clause is what keeps it out of the user's way. The list is written
only when the range is absent, which is true on a fresh 0.6.27 install and on
an install still carrying #3004's per-address list, and false afterwards -- so
an entry added in the admin page for a reverse proxy outside the supervisor
network survives every later start.

The trade-off is that any addon on the supervisor network can now present
X-WebAuth-User to port 8083 and be logged in. Maintainer's call, taken
knowingly in preference to the machinery the narrow list required.

The tolerated failure from #3004 is kept: the column only exists once
calibre-web 0.6.27+ has migrated app.db and cont-init runs first, so the
statement is allowed to fail and the next start applies it. The sqlite error
is now included in the warning rather than dropped.

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

* fix(calibre-web): guard on the mapped range and keep existing entries

Addresses the review on #3010, both findings inside the one statement.

Codex, Copilot and CodeRabbit all noted the WHERE clause tested only
172.30.32.0/23, so a value carrying the ipv4 range without the mapped form
would skip the update forever while ingress stayed rejected -- a plausible
state, since that is exactly what someone adds by hand after reading that the
supervisor network is the source. Rather than test both, the guard now tests
::ffff:172.30.32.0/119 alone. That is the form ingress actually needs, given
calibre-web listens dual-stack, and the form nobody types by hand, so it
serves as the marker that this already ran. One substring either way.

Copilot and CodeRabbit also noted the assignment replaced the whole column,
losing an administrator entry on the first start. The required list is now
prepended to the existing value instead of replacing it. No case expression
is needed for the empty and NULL cases : the trailing comma that leaves
behind is an empty entry, which calibre-web's parser skips.

Both together cost one `||coalesce(...)` and a different substring. The
statement still runs at most once, and the duplicates it can leave behind are
entries calibre-web skips, or addresses inside the range now trusted anyway.

Checked against a transcription of cps/reverse_proxy_auth.py from 0.6.27 :
every produced value parses with nothing ignored, ::ffff:172.30.33.10 is
trusted and ::ffff:192.168.1.99 is not.

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 15:08:03 +02:00
Alexandre
c697ed2c06 fix(calibre-web): trust the addon ip so ingress login works on 0.6.27 (#3004)
* fix(calibre-web): trust the addon ip so ingress login works on 0.6.27

Calibre-web 0.6.27 added a trusted-source check for the reverse proxy auth
header (cps/reverse_proxy_auth.py:is_trusted_proxy_source) and defaults
config_reverse_proxy_trusted_ips to "127.0.0.1,::1". The ingress nginx binds
its upstream socket to the addon ip (proxy_bind $server_addr,
rootfs/etc/nginx/servers/ingress.conf:13), so calibre-web sees
::ffff:<addon ip> and discards X-WebAuth-User, leaving ingress at the login
page.

80-configuration.sh now writes that address - plain and ipv4-mapped, plus the
loopback forms - into config_reverse_proxy_trusted_ips next to the two
settings it already applies. The update is tolerated failing because the
column only exists after calibre-web 0.6.27+ has migrated app.db.

Closes #3003

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

* fix: address CodeRabbit review

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 14:02:45 +02:00
Alexandre
1d70eca70a fix(portainer_agent): make the healthcheck runnable again (needs version bump before merge) (#3005)
* fix(portainer_agent): make the healthcheck runnable again

rootfs/usr/sbin/healthcheck line 1 was `#!/usr/bin/with-contenv bash`.
with-contenv runs `s6-envdir -Lf -- /run/s6/container_environment`, which
fails when that directory does not exist. This addon overrides the base
image's `ENTRYPOINT ["/init"]` with `/usr/bin/env /ha_entrypoint.sh`
(Dockerfile:88-89), and ha_entrypoint.sh runs the cont-init and services.d
scripts itself instead of handing over to s6-overlay, so s6 stage 1 never
runs and that directory is never created.

ha_entrypoint.sh rewrites the shebang of everything under /etc/cont-init.d
and /etc/services.d, which is why the service `run` script works. Nothing
rewrites /usr/sbin/healthcheck, so Docker's HEALTHCHECK died on the shebang
before reaching the curl - exit 1, no output, forever unhealthy.

The script only needs curl and hardcoded values, so plain bash is enough.

Closes #3002

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

* fix(portainer_agent): bump version, remove unused wait-for-signal script

Delete rootfs/usr/sbin/wait-for-signal (unused, broken expr, same bad
shebang) and its chmod in the Dockerfile. Bump version to 2025.12.7 to
match the CHANGELOG entry so Supervisor offers the healthcheck fix.

Co-authored-by: Alexandre <44178713+alexbelgium@users.noreply.github.com>

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 13:59:33 +02:00
9 changed files with 41 additions and 29 deletions

View File

@@ -1,4 +1,10 @@
## 0.6.27.2 (2026-08-23)
- Fix: trust the whole supervisor network range for the ingress auth header instead of the addon's own address, which changes across restarts. The list is only written when that range is missing, so an entry added in the calibre-web admin page is no longer erased on every start (https://github.com/alexbelgium/hassio-addons/pull/3010)
## 0.6.27.1 (2026-08-23)
- Fix: Ingress login was rejected since 0.6.27, which only accepts the reverse proxy auth header from trusted source addresses. The addon now adds its own ip to that list (https://github.com/alexbelgium/hassio-addons/issues/3003)
## 0.6.27 (2026-08-13)
- Update to latest version from linuxserver/docker-calibre-web (changelog : https://github.com/linuxserver/docker-calibre-web/releases)

View File

@@ -116,5 +116,5 @@ schema:
slug: calibre-web
udev: true
url: https://github.com/alexbelgium/hassio-addons/tree/master/calibre_web
version: "0.6.27"
version: "0.6.27.2"
video: true

View File

@@ -18,6 +18,20 @@ if [ ! -f /config/app.db ]; then
bashio::log.warning "First boot : disabling Ingress until addon restart"
else
sqlite3 /config/app.db 'update settings set config_reverse_proxy_login_header_name="X-WebAuth-User",config_allow_reverse_proxy_header_login=1'
# Calibre-web 0.6.27 only accepts that header from a trusted source address, and defaults the
# list to "127.0.0.1,::1". Ingress reaches calibre-web from the addon's own address on the
# supervisor network (proxy_bind $server_addr in ingress.conf) and calibre-web listens
# dual-stack, so it sees ::ffff:<addon ip> and drops the header. The supervisor range is
# listed in both forms because an ipv4 entry never matches an ipv4-mapped address.
# Prepended to whatever is already there, and only when the mapped form is missing : that form
# is the one ingress needs and the one nobody types by hand, so it doubles as the marker that
# this already ran. Anything the user added is kept, the statement runs at most once, and the
# duplicates it can leave behind are entries calibre-web skips or already trusts.
# The column only exists once calibre-web 0.6.27+ has migrated app.db and cont-init runs
# before calibre-web, so a failure here is not fatal : the next start applies it.
trusted_ips_error=$(sqlite3 /config/app.db "update settings set config_reverse_proxy_trusted_ips='127.0.0.1,::1,::ffff:127.0.0.1,172.30.32.0/23,::ffff:172.30.32.0/119,'||coalesce(config_reverse_proxy_trusted_ips,'') where coalesce(config_reverse_proxy_trusted_ips,'') not like '%::ffff:172.30.32.0/119%'" 2>&1) ||
bashio::log.warning "Could not set the ingress trusted ip list, it will be applied at next start (${trusted_ips_error})"
fi
bashio::log.info "Default username:password is admin:admin123"

View File

@@ -1,3 +1,13 @@
## 2.44.0 (2026-08-23)
- Fix: Use `portainer/agent:alpine-sts` to match the STS release channel configured in `updater.json`
- Fix: Align add-on versioning with Portainer STS releases
## 2025.12.7 (2026-08-23)
- Fix: Docker reported the addon as `unhealthy` in Portainer. The healthcheck script could never run because its shebang required the s6-overlay environment, which this addon's entrypoint does not set up (https://github.com/alexbelgium/hassio-addons/issues/3002)
- Remove the unused and broken `wait-for-signal` script; nothing invoked it
## 2025.12.6 (2026-08-01)
- Version renamed from `2025.12-6`, which Home Assistant could not order and therefore could not reliably offer as an update: every number of the previous version is kept, as a section of its own. The addon itself and the upstream version it tracks are unchanged

View File

@@ -18,7 +18,7 @@
ARG BUILD_FROM
# Get agent
FROM portainer/agent:alpine as original_agent
FROM portainer/agent:alpine-sts as original_agent
ENV PORTAINER_AGENT_ARGS=""
# Build using base
@@ -81,8 +81,7 @@ RUN chmod 777 /ha_entrypoint.sh
COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh
RUN chmod 0755 /usr/local/lib/bashio-standalone.sh
RUN chmod a+x /usr/sbin/healthcheck && \
chmod a+x /usr/sbin/wait-for-signal
RUN chmod a+x /usr/sbin/healthcheck
WORKDIR "/app"
ENTRYPOINT [ "/usr/bin/env" ]

View File

@@ -41,4 +41,4 @@ schema:
slug: portainer_agent
udev: true
url: https://github.com/alexbelgium/hassio-addons
version: "2025.12.6"
version: "2.44.0"

View File

@@ -1,4 +1,8 @@
#!/usr/bin/with-contenv bash
#!/usr/bin/env bash
# shellcheck shell=bash
# Plain bash on purpose : ha_entrypoint.sh replaces s6-overlay's /init, so
# /run/s6/container_environment is never created and a with-contenv shebang
# would fail before this script runs. Nothing here needs the s6 environment.
if [ -f "/tmp/healthcheck-signal" ]; then
curl -k --fail https://127.0.0.1:9001/ping || exit 1

View File

@@ -1,21 +0,0 @@
#!/usr/bin/with-contenv bashio
START_TIME="$(date +%s)"
echo "Waiting for first healthcheck execution (max $FIRST_HEALTHCHECK_TIMEOUT seconds)..."
while [ ! -f "/tmp/healthcheck-signal" ];
do
sleep 1
ELAPSED_TIME="$(expr \date +%s\ - $START_TIME)"
if [ $ELAPSED_TIME -gt $FIRST_HEALTHCHECK_TIMEOUT ]
then
echo "Signal from healthcheck not received in time, failing the execution..."
exit 20
fi
done
echo "Signal from healthcheck received"
exit 0

View File

@@ -1,6 +1,6 @@
{
"github_tagfilter": "alpine",
"last_update": "24-12-2025",
"github_tagfilter": "sts",
"last_update": "23-08-2026",
"repository": "alexbelgium/hassio-addons",
"slug": "portainer_agent",
"source": "dockerhub",