Compare commits

...
Author SHA1 Message Date
alexbelgiumandClaude Opus 5 833d0d3758 docs(skill): narrow the ISO claim and correct the grep description
Review fixes. The bolded lead read as an absolute while the body reported 363
DD-MM-YYYY headings and told you to match the file — it now says "most", and
says outright that a DD-MM-YYYY file stays DD-MM-YYYY. The counts are stamped
as of 2026-08-25 so a future reader knows they are a snapshot.

CodeRabbit is right that `grep -q "^## ${version} ("` is not an exact-version
check. Reproduced: with version 5.1.1.2 the pattern matches a heading reading
`## 5X1Y1Z2 (`, because BRE dots match any character; `grep -qF` does not.
Described as an unescaped BRE instead. The conclusion is unchanged, since the
date is not in the pattern either way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 15:53:31 +02:00
alexbelgiumandClaude Opus 5 138e7d7c33 docs(skill): correct the CHANGELOG heading date format
SKILL.md's step 7 said to match `## X.Y (DD-MM-YYYY)`. The repo does not use
that: 7705 dated CHANGELOG headings are ISO `YYYY-MM-DD` against 363 in
`DD-MM-YYYY`, and the newest entry is ISO in 125 of 135 add-ons. Following the
instruction cost a Copilot review round on #3019.

`DD-MM-YYYY` is not invented, which is presumably how it got written down. It
is what `onpush_builder.yaml` inserts with `date '+%d-%m-%Y'` when a push
arrives with no heading for the config.yaml version, and it is the addons_updater
bot's default in `99-run.sh` — but that bot runs here with `date_iso8601: true`
(confirmed against the running add-on's options), which is why almost everything
on master is ISO. Neither is a reason to write `DD-MM-YYYY` by hand.

The traps.md entry also records that the builder's duplicate check is
`grep -q "^## ${version} ("` — keyed on the exact config.yaml version and blind
to the date — so an ISO heading you wrote yourself still suppresses the bot's
insertion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 15:48:00 +02:00
AlexandreandClaude Opus 5 8341e542fb feat(sabnzbd): enable Home Assistant ingress (#3019)
* feat(sabnzbd): enable Home Assistant ingress

The add-on already carried a complete but disabled nginx ingress scaffold:
`etc/nginx/` with its includes and a `servers/ingress.conf`, a
`cont-init.d/32-nginx_ingress.sh` short-circuited by `exit 0`, and
`ENV PACKAGES="nginx"` in a Dockerfile byte-identical to nzbget's. Only
`ingress: true` and the s6 service that starts nginx were missing.

What SABnzbd 5.1.1 actually needs from the proxy, measured against the
running add-on rather than assumed:

- Its interface emits only relative links (`href="../../config/general/"`,
  `href="../../staticcfg/css/Auto.css"`, `action="./one"`), and grepping the
  5.1.1 source for `(href|src|action)="/` across `interfaces/{Glitter,Config,
  wizard}` and for absolute `url:` literals in the Glitter JavaScript returns
  nothing. A plain pass-through proxy preserves path depth, so no `sub_filter`
  is warranted. The previous config's `sub_filter /sabnzbd ...` would also have
  mangled the `https://sabnzbd.org/wiki/...` help links present on every
  config page.
- Redirects are the one exception: `Raiser()` prefixes `cfg.url_base()`, so
  `GET /` answers `303 Location: /sabnzbd/wizard/`. One `proxy_redirect`
  handles every observed case; all of them were path-absolute, never a full
  URL. Login redirects and logout go through the same `Raiser()`, and the
  session cookie's path is hardcoded to `/` (`interface.py:316`), so it is
  still sent under the ingress path.
- SABnzbd rejects a Host header that is not an IP literal:
  `Host: homeassistant` answers 403 "Hostname verification failed", while
  `Host: 192.168.1.5:8123` answers 200. nginx therefore sends `$proxy_host`
  instead of including the shared `proxy_params.conf`, which forwards
  `$http_host`.

`ingress_entry: sabnzbd` is dropped rather than kept: Supervisor appends it to
the ingress URL, which only resolves while the user's `url_base` is literally
`/sabnzbd`, and that is a setting they can change. SABnzbd serves the same
interface at `/` as under its `url_base` (verified for `/config/general/`,
`/static/`, `/staticcfg/` and `/wizard/`), so entering at the ingress root
works for any value, including the empty code default.

Ingress traffic reaches SABnzbd as `127.0.0.1:8080` and so is not filtered by
a user's host whitelist; direct ip:port access is unchanged and still is.

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

* fix(sabnzbd): keep the ingress Location relative and scope the login cookie

Exercising the shipped config against the running add-on caught a bug that
reading it did not. With nginx's default `absolute_redirect on`, rewriting
`Location: /sabnzbd/wizard/` produced
`http://homeassistant.local:18099/api/hassio_ingress/<token>/sabnzbd/wizard/`
— nginx expands a scheme-less replacement using the browser's Host and its own
listen port, which is the add-on's internal ingress port and is not reachable
from the browser. `absolute_redirect off` keeps it a path, which the browser
resolves against the Home Assistant origin.

`proxy_cookie_path` comes from Codex's review of the diff. SABnzbd hardcodes
the login cookie to `Path=/` (`interface.py:316`), so on the shared ingress
origin the browser would send it to every other add-on's ingress path as well.

Verified end to end by running the shipped nginx.conf and ingress.conf against
the live add-on, with the browser Host set to a non-IP hostname throughout:
all five redirect cases return a path under the ingress entry, the config
pages, wizard, API and both static roots return 200, and a stub upstream
emitting `Path=/` comes back rewritten to the ingress path.

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

* fix(sabnzbd): drop webui, which the add-on linter forbids alongside ingress

frenck/action-addon-linter fails the PR with "'webui' should be removed,
Ingress is enabled." No other ingress add-on in this repo keeps the key. The
"Open Web UI" button now opens ingress; the ports mapping is untouched, so
direct ip:port still works, it just has to be typed.

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

* fix(sabnzbd): make the nginx finish script actually work on s6-overlay v3

CodeRabbit is right that the execline finish script copied from nzbget is
inert on this image. s6-portable-utils dropped `s6-test` in favour of
execline's `eltest` — s6-overlay 3.2.1.0 ships no `s6-test` at all — so
execlineb cannot run the first `if` block and never reaches s6-svscanctl.
`/var/run/s6/services` is also the v2 scandir path; v3's legacy services.d
compatibility layer uses /run/service.

Rather than port it to eltest, use the shell form the scrutiny add-on already
ships: `kill -15 1` signals s6-overlay's init directly, so it depends on
neither the s6 tool set nor the scandir path, and it is three lines shorter.
The 0 and 256 exclusions are kept, so a normal shutdown does not trigger it.

Also fix the CHANGELOG date to YYYY-MM-DD per Copilot: that is what this file
and 7705 of the repo's 8068 dated headings use.

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 15:46:36 +02:00
AlexandreandClaude Opus 5 a68ef0dde2 fix(skill): stop the workflow scripts reporting verdicts they have not established (#3018)
* fix(skill): stop the workflow scripts reporting verdicts they have not established

Every defect here is the same species: a check printed as passed that never ran, or
never proved what it claims. All six were reproduced before and after.

validate.sh
- `run`/`finish` were selected by filename and fed to bash -n and shellcheck. 25 of the
  97 such files here are `#!/usr/bin/execlineb`, so 21 add-ons -- calibre_web and seerr
  among them -- reported `local validation FAILED` and a wall of parse errors no matter
  what the diff contained. One list, filtered by shebang, now feeds both checks; seerr
  went from 15 shellcheck findings and two bash -n failures to the single finding the
  test diff actually introduced.
- `grep -q "$ADDON/CHANGELOG.md"` was unanchored with `.` as a wildcard, so a diff
  bumping zzz_archived_overseerr/CHANGELOG.md reported seerr's as updated -- a false
  green on the one hard CI gate. Five such name collisions exist in this repo
  (also birdnet-pi/battybirdnet-pi, mealie/social_to_mealie, plex/spotify_to_plex).
  `grep -Fxq`.
- The --vs-master section skipped any file absent from origin/master, so a newly added
  script's findings -- all of which are by definition added by the diff -- were never
  reported, under a line reading "your diff introduced no new lint findings". An added
  file now compares against an empty base. A deleted one is skipped: it was being linted
  at a path that no longer exists, which turned every deletion into a fabricated
  `openBinaryFile: does not exist` finding.
- That loop ran as the right-hand side of a pipe, so it could not have reached `fail`
  even had it tried. It now runs in this shell and new findings fail the script; the
  all-clear line is printed only when nothing was listed. Findings that merely moved
  lines still cancel -- the comparison strips file:line:col before comm.
- `bash -n ok` stood for an add-on with no shell files at all, and hadolint could print
  `clean` directly after printing findings (`A && {...} || C` with pipefail). Counted
  and branched properly.

preflight.sh
- `MATCH -- this checkout corresponds to the running image` was concluded from
  config.yaml's version equalling $BUILD_VERSION. Version is bumped once per PR, so any
  later commit or a dirty tree matches while differing from what runs -- the one
  conclusion the script exists to establish was the one it overstated.

pr_review.sh
- `watch` exhausting its minutes with checks still pending fell out of the loop and
  exited 0, reporting success for checks that never settled. Unsettled is now exit 2.
  Checks reported as `skipping` still count as passing, which is correct -- for this PR
  itself, three jobs skipped because no */config.* changed, and that is the right
  outcome, not a failure. But a skipped job tested nothing, so `watch` now says so.

Reviewed by Codex (gpt-5.6-sol), which corrected two claims in the audit behind this:
the .templates CHANGELOG assertion (CI skips the gate entirely for a template-only PR,
so that fix is not in this diff) and a tradeoff that did not exist. The deleted-file and
watch-timeout defects are its finds.

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

* fix(skill): address review — cwd independence, no pass verdict for an empty check

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 11:01:24 +02:00
dependabot[bot] 23fad482b8 build(deps): bump EndBug/add-and-commit from 11.0.0 to 11.1.1 (#3017)
Bumps [EndBug/add-and-commit](https://github.com/endbug/add-and-commit) from 11.0.0 to 11.1.1.
- [Release notes](https://github.com/endbug/add-and-commit/releases)
- [Commits](https://github.com/endbug/add-and-commit/compare/v11.0.0...v11.1.1)

---
updated-dependencies:
- dependency-name: EndBug/add-and-commit
  dependency-version: 11.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-25 10:15:55 +02:00
dependabot[bot] 5a87daf3e4 build(deps): bump anthropics/claude-code-action from 1.0.193 to 1.0.199 (#3016)
Bumps [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action) from 1.0.193 to 1.0.199.
- [Release notes](https://github.com/anthropics/claude-code-action/releases)
- [Commits](https://github.com/anthropics/claude-code-action/compare/9d7150bc8a3dae8149739a88019d192b579ad90c...dcb57747bfceeaa1fa72638cae52295d1d853d4a)

---
updated-dependencies:
- dependency-name: anthropics/claude-code-action
  dependency-version: 1.0.199
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-25 10:15:47 +02:00
23 changed files with 133 additions and 62 deletions

No files matched your search

@@ -169,7 +169,9 @@ CI gates on a PR: **`CHANGELOG.md` updated** (hard fail), the **HA add-on linter
(`frenck/action-addon-linter`, blocking — not the weekly Super-Linter, which is non-blocking), and
the **add-on image build**. Bump `version` anyway (`X.Y.Z.N`, never `X.Y.Z-N`, see
`references/traps.md#versioning`) — Supervisor won't offer a rebuild without it. Update
`README.md` if you added options; match the CHANGELOG heading format `## X.Y (DD-MM-YYYY)`.
`README.md` if you added options; write the CHANGELOG heading as `## <version> (<date>)`,
matching the date format already in that file — almost always ISO `YYYY-MM-DD`, see
`references/traps.md#ci-and-review-bots`.
Write the body to a file, `gh pr create --body-file`: state what was measured, what changed,
**what is not verified**, and how to roll back the riskiest hunk alone.
@@ -241,6 +241,18 @@ account. Note it and move on rather than guessing.
**Resolving a review thread requires GraphQL** (`resolveReviewThread`); the REST API cannot do it.
`scripts/pr_review.sh` wraps fetch / reply / resolve.
**Most CHANGELOG heading dates are ISO, whatever the bots' defaults say.** Match the format
already in the add-on's file — a `DD-MM-YYYY` file stays `DD-MM-YYYY`. Where you have no
precedent, ISO is the house style: as of 2026-08-25, `## <version> (YYYY-MM-DD)` accounts for
7705 dated headings against 363 in `DD-MM-YYYY`, and the newest entry is ISO in 125 of 135
add-ons. Copilot flags an ISO file that gets a `DD-MM-YYYY` entry (#3019). `DD-MM-YYYY` is not
invented — it is what `onpush_builder.yaml` writes with `date '+%d-%m-%Y'` when it has to insert
a heading you forgot, and what the addons_updater bot writes when its `date_iso8601` option is
off (`99-run.sh`; it is on in production here) — but neither is a reason to write it yourself.
The builder's duplicate check is `grep -q "^## ${version} ("` — an unescaped BRE, so the dots in
a version match any character, and it does not look at the date at all. Either way an ISO heading
you wrote yourself still suppresses the bot's insertion.
**The repo's `.markdownlint.yaml` does not disable MD022/MD032**, so a CHANGELOG will show
dozens of pre-existing heading/list findings. They are noise because lint is `continue-on-error`,
not because the config exempts them — don't cite the config as a reason to ignore a finding.
@@ -90,6 +90,7 @@ resolve)
;;
watch)
MINS="${3:-180}" # the addon build alone has taken ~3h; 20 was far too short
wfail=2 # not 0: running out of minutes with checks still pending is not a pass
for i in $(seq 1 "$MINS"); do
c=$(gh pr checks "$PR" 2> /dev/null | awk '{print $1"="$2}' | tr '\n' ' ')
if [ -z "$c" ]; then
@@ -102,11 +103,14 @@ watch)
case "$c" in
*pending*) sleep 60 ;;
*fail* | *error* | *cancel*) echo "settled — with FAILURES (see above)"; wfail=1; break ;;
*) echo "settled — all passing"; break ;;
*) echo "settled — all passing"; wfail=0; break ;;
esac
done
[ "$wfail" -eq 2 ] && echo "gave up after ${MINS}m, checks still unsettled — NOT a pass"
# A PR touching no */config.* skips the CHANGELOG, linter and build jobs outright (#3018).
case "${c:-}" in *skipping*) echo " ...of which some were SKIPPED — a skipped job tested nothing" ;; esac
echo "note: long queues here are usually account runner contention, not your diff."
exit "${wfail:-0}"
exit "$wfail"
;;
*) echo "unknown: $CMD"; exit 1 ;;
esac
@@ -64,7 +64,8 @@ if [ -n "${BUILD_VERSION:-}" ]; then
echo " $SLUG/config.yaml version = $here"
echo " running image BUILD_VERSION = $BUILD_VERSION"
if [ "$here" = "$BUILD_VERSION" ]; then
echo " MATCH — this checkout corresponds to the running image."
# version is bumped once per PR, so a later commit or a dirty tree matches here.
echo " VERSION MATCH — source revision itself is not verified."
else
echo " MISMATCH — this branch is NOT what is running."
git fetch origin master --quiet 2> /dev/null
@@ -4,10 +4,13 @@
# rather than implying the build was checked.
#
# --vs-master re-lints each changed file at origin/master and prints only findings your diff
# ADDED. Without it you will chase warnings that were already in the file.
# ADDED, and fails if there are any. Without it you will chase warnings that were already there.
#
# Usage: validate.sh [addon-dir] [--vs-master]
set -uo pipefail
# git diff prints repo-root-relative paths and $ADDON is a top-level directory name: neither
# resolves from a subdirectory, where the -f guard below would skip every file and report clean.
if root=$(git rev-parse --show-toplevel 2> /dev/null); then cd "$root" || exit 1; fi
ADDON="${1:-}"
[ "${ADDON:-}" = "--vs-master" ] && { ADDON=""; set -- --vs-master; }
@@ -31,17 +34,21 @@ echo "== validating $ADDON =="
fail=0
note() { printf ' %-13s %s\n' "$1" "$2"; }
# execline `run`/`finish` files are not shell (25 of them here, across 21 add-ons). Neither
# linter below can read one, so anything either says about it is noise.
is_execline() { local l; IFS= read -r l < "$1" 2> /dev/null; [[ $l == '#!'*execlineb* ]]; }
# Shell: bash -n then shellcheck -x (follows sourced files, as CI does).
while IFS= read -r f; do
[ -f "$f" ] || continue
# Shell: bash -n then shellcheck -x (follows sourced files, as CI does). One list for both.
files=()
while IFS= read -r f; do is_execline "$f" || files+=("$f"); done \
< <(find "$ADDON" -type f \( -name '*.sh' -o -name 'run' -o -name 'finish' -o -name 'autostart' \) 2> /dev/null)
for f in "${files[@]}"; do
if ! out=$(bash -n "$f" 2>&1); then note "bash -n" "FAIL $f"; echo "$out" | sed 's/^/ /'; fail=1; fi
done < <(find "$ADDON" -type f \( -name '*.sh' -o -name 'run' -o -name 'finish' -o -name 'autostart' \) 2> /dev/null)
[ "$fail" -eq 0 ] && note "bash -n" "ok"
done
[ "$fail" -eq 0 ] && note "bash -n" "${#files[@]} file(s) checked"
if command -v shellcheck > /dev/null 2>&1; then
sc=$(find "$ADDON" -type f \( -name '*.sh' -o -name 'autostart' -o -name 'run' -o -name 'finish' \) -print0 2> /dev/null |
xargs -0 -r shellcheck -x -f gcc 2>&1)
if [ "${#files[@]}" -gt 0 ] && command -v shellcheck > /dev/null 2>&1; then
sc=$(shellcheck -x -f gcc "${files[@]}" 2>&1)
if [ -n "$sc" ]; then
note "shellcheck" "$(printf '%s\n' "$sc" | grep -c .) finding(s)"
printf '%s\n' "$sc" | sed 's/^/ /' | head -20
@@ -50,7 +57,10 @@ fi
command -v hadolint > /dev/null 2>&1 && [ -f "$ADDON/Dockerfile" ] && {
hl=$(hadolint "$ADDON/Dockerfile" 2>&1)
[ -n "$hl" ] && { note "hadolint" "$(printf '%s\n' "$hl" | grep -c .) finding(s)"; printf '%s\n' "$hl" | sed 's/^/ /' | head -10; } || note "hadolint" "clean"
if [ -n "$hl" ]; then
note "hadolint" "$(printf '%s\n' "$hl" | grep -c .) finding(s)"
printf '%s\n' "$hl" | sed 's/^/ /' | head -10
else note "hadolint" "clean"; fi
}
if [ -f "$ADDON/config.yaml" ]; then
@@ -79,11 +89,14 @@ $VS_MASTER && command -v npx > /dev/null 2>&1 && [ -f "$ADDON/CHANGELOG.md" ] &&
echo
echo "== CI requirements =="
if git diff --name-only origin/master...HEAD 2> /dev/null | grep -q "$ADDON/CHANGELOG.md"; then
# -Fxq, not -q: unanchored, seerr's is matched by zzz_archived_overseerr's, and . is a wildcard.
# Stricter than the gate itself, whose quoted =~ accepts that same collision
# (onpr_check-pr.yaml:75), so this can fail where CI passes — the wrong add-on's is still wrong.
if git diff --name-only origin/master...HEAD 2> /dev/null | grep -Fxq "$ADDON/CHANGELOG.md"; then
note "CHANGELOG" "updated"
else
# This one IS gated: onpr_check-pr.yaml exits 1 without it.
note "CHANGELOG" "NOT UPDATED — this is the one CI hard-gate"; fail=1
note "CHANGELOG" "NOT UPDATED for $ADDON — CI hard-gates this"; fail=1
fi
if git diff origin/master...HEAD -- "$ADDON/config.yaml" 2> /dev/null | grep -q '^+version:'; then
note "version" "bumped"
@@ -98,8 +111,15 @@ if $VS_MASTER; then
echo
echo "== findings ADDED by this diff (pre-existing ones filtered out) =="
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
git diff --name-only origin/master...HEAD -- "$ADDON" 2> /dev/null | while IFS= read -r f; do
git show "origin/master:$f" > "$tmp/base" 2> /dev/null || continue
added=0
# Fed by process substitution, not a pipe: a pipeline runs this in a subshell, where the
# findings below could never reach $fail and the verdict would contradict the list.
while IFS= read -r f; do
# Deleted: linting the path that is gone invents a finding. Added: no base, and an
# empty one says the right thing — every finding in it is one this diff added.
[ -f "$f" ] || continue
is_execline "$f" && continue
git show "origin/master:$f" > "$tmp/base" 2> /dev/null || : > "$tmp/base"
# A missing linter must be a visible skip, not a silent "no new findings":
# its "command not found" error is identical for base and head, so comm would
# cancel it out and report a false clean.
@@ -115,12 +135,16 @@ if $VS_MASTER; then
cmd() { hadolint "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*//'; } ;;
*) continue ;;
esac
cp "$tmp/base" "$tmp/base_f"; b=$(cmd "$tmp/base_f" | sort)
b=$(cmd "$tmp/base" | sort)
a=$(cmd "$f" | sort)
new=$(comm -13 <(printf '%s\n' "$b") <(printf '%s\n' "$a") | grep -c .)
[ "$new" -gt 0 ] && { echo " $f: $new NEW finding(s)"; comm -13 <(printf '%s\n' "$b") <(printf '%s\n' "$a") | sed 's/^/ /' | head -5; }
done
echo " (nothing listed above = your diff introduced no new lint findings)"
new=$(comm -13 <(printf '%s\n' "$b") <(printf '%s\n' "$a"))
[ -n "$new" ] && {
echo " $f: $(printf '%s\n' "$new" | grep -c .) NEW finding(s)"
printf '%s\n' "$new" | sed 's/^/ /' | head -5
added=1; fail=1
}
done < <(git diff --name-only origin/master...HEAD -- "$ADDON" 2> /dev/null)
[ "$added" -eq 0 ] && echo " (none — this diff introduced no new lint findings)"
fi
echo
+1 -1
View File
@@ -228,7 +228,7 @@ jobs:
echo "... done"
- name: Commit if needed
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
message: "GitHub bot : README updated"
default_author: github_actions
+1 -1
View File
@@ -125,7 +125,7 @@ jobs:
- name: Analyse and fix
if: steps.batch.outputs.count != '0'
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Skip the OIDC -> Claude App token exchange. The scheduled path
+1 -1
View File
@@ -237,7 +237,7 @@ jobs:
# Get stars evolution
wget -S -O .github/starsevol.svg "https://api.star-history.com/svg?repos=alexbelgium/hassio-addons&type=Date" || true
- name: Commit if needed
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
message: "GitHub bot : graphs updated"
default_author: github_actions
+1 -1
View File
@@ -64,7 +64,7 @@ jobs:
fetch-depth: 1
- name: Run Claude Code
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# AI_PR_TOKEN, not GITHUB_TOKEN, so a PR Claude opens triggers CI.
+1 -1
View File
@@ -135,7 +135,7 @@ jobs:
- name: Execute the plan
if: steps.bundle.outputs.has_plan == 'true'
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Skip the OIDC -> Claude App token exchange, which 401s whenever
+1 -1
View File
@@ -59,7 +59,7 @@ jobs:
# Remove issues list
rm issueslist
- name: Commit if needed
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
message: "Github bot : issues linked to readme"
default_author: github_actions
+1 -1
View File
@@ -166,7 +166,7 @@ jobs:
id: classify
if: github.event_name != 'issue_comment' || steps.claim.outputs.go == 'true'
continue-on-error: true
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Without this the action falls back to the OIDC -> Claude App token
+1 -1
View File
@@ -79,7 +79,7 @@ jobs:
- name: Address CodeRabbit comments
if: steps.claim.outputs.go == 'true'
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Skip the OIDC -> Claude App token exchange, which 401s whenever
+2 -2
View File
@@ -95,7 +95,7 @@ jobs:
- name: Commit sanitize changes
id: sanitize_commit
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
commit: -u
message: "GitHub bot: sanitize (spaces + LF endings) & chmod [nobuild]"
@@ -410,7 +410,7 @@ jobs:
done
- name: Commit changelog changes
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
commit: -u
message: "GitHub bot: changelog [nobuild]"
+2 -2
View File
@@ -18,7 +18,7 @@ jobs:
uses: erclu/check-crlf@v1
- name: Commit if needed
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
message: "Github bot : CRLF corrected"
default_author: github_actions
@@ -50,7 +50,7 @@ jobs:
dos2unix -k "$f"
done
- name: Commit if needed
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
message: "Github bot : CRLF corrected"
default_author: github_actions
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
- name: Commit if needed
if: steps.calibre.outputs.markdown != ''
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
message: "Github bot : image compressed"
default_author: github_actions
+1 -1
View File
@@ -109,7 +109,7 @@ jobs:
#TOTAL3="$(awk '{SUM+=$2}END{print SUM}' Stats)"
- name: Commit if needed
uses: EndBug/add-and-commit@v11.0.0
uses: EndBug/add-and-commit@v11.1.1
with:
default_author: github_actions
message : "Github bot : stats updated"
+4
View File
@@ -1,4 +1,8 @@
## 5.1.1.2 (2026-08-25)
- Ingress is now enabled: the WebUI opens directly in the Home Assistant sidebar, and the "Open Web UI" button now goes there. Access by ip:port is unchanged, but has to be typed rather than clicked, as Home Assistant does not allow an add-on to offer both.
- Note for users who set a "Host verification" whitelist in SABnzbd: ingress sends `Host: 127.0.0.1:8080` upstream, because SABnzbd rejects any Host that is not an IP literal. That whitelist therefore no longer filters the ingress route, which is gated by Home Assistant authentication instead. Direct ip:port access is unchanged and still filtered.
## 5.1.1 (2026-08-22)
- Update to latest version from linuxserver/docker-sabnzbd (changelog : https://github.com/linuxserver/docker-sabnzbd/releases)
+2 -3
View File
@@ -70,7 +70,7 @@ environment:
PGID: "0"
PUID: "0"
image: ghcr.io/alexbelgium/sabnzbd-{arch}
ingress_entry: sabnzbd
ingress: true
init: false
map:
- addon_config:rw
@@ -106,5 +106,4 @@ schema:
slug: sabnzbd
udev: true
url: https://github.com/alexbelgium/hassio-addons
version: "5.1.1"
webui: http://[HOST]:[PORT:8080]
version: "5.1.1.2"
@@ -1,21 +1,14 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
# shellcheck disable=SC2317
set -e
#################
# NGINX SETTING #
#################
exit 0
ingress_port=$(bashio::addon.ingress_port)
ingress_interface=$(bashio::addon.ip_address)
ingress_entry=$(bashio::addon.ingress_entry)
sed -i "s/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf
sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf
# Allows serving js
sed -i 's/<!-- %if-not-debug% -->/<!-- %if-not-debug% /g' /app/sabnzbd/webui/index.html
sed -i 's/<!-- %end% -->/ %end% -->/g' /app/sabnzbd/webui/index.html
sed -i 's/<!-- %if-debug%/<!-- %if-debug% -->/g' /app/sabnzbd/webui/index.html
sed -i 's/ %end% -->/<!-- %end% -->/g' /app/sabnzbd/webui/index.html
sed -i "s|%%ingress_entry%%|${ingress_entry}|g" /etc/nginx/servers/ingress.conf
+25 -13
View File
@@ -2,22 +2,34 @@ server {
listen %%interface%%:%%port%% default_server;
include /etc/nginx/includes/server_params.conf;
include /etc/nginx/includes/proxy_params.conf;
client_max_body_size 0;
location / {
add_header Access-Control-Allow-Origin *;
proxy_connect_timeout 30m;
proxy_send_timeout 30m;
proxy_read_timeout 30m;
proxy_pass http://127.0.0.1:8080;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Accept-Encoding "";
# Correct url without port when using https
sub_filter_once off;
sub_filter_types *;
sub_filter /sabnzbd %%ingress_entry%%/sabnzbd;
}
# SABnzbd refuses any request whose Host is not an IP literal
# ("Access denied - Hostname verification failed"), so send the
# upstream socket rather than the browser's host. X-Forwarded-For is
# the only other header it reads (for its verify_xff_header option).
proxy_set_header Host $proxy_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# The interface itself only emits relative links, so no body
# rewriting is needed. Redirects are the exception: Raiser() emits
# a path under url_base, so prefix them with the ingress entry.
# absolute_redirect must stay off, or nginx expands the rewritten
# Location into http://<browser host>:<ingress port>/..., a port the
# browser cannot reach.
proxy_redirect / %%ingress_entry%%/;
absolute_redirect off;
# The login cookie is hardcoded to Path=/, which on the ingress
# origin would send it to every other add-on's ingress path too.
proxy_cookie_path / %%ingress_entry%%/;
proxy_http_version 1.1;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Stop the container when Nginx fails, so ingress does not silently go dead
# ==============================================================================
if [[ "$1" -ne 0 && "$1" -ne 256 ]]; then
bashio::log.error "Nginx exited with code $1"
kill -15 1
fi
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# ==============================================================================
# Wait for sabnzbd to become available
bashio::net.wait_for 8080 localhost 900
bashio::log.info "Starting NGinx..."
exec nginx