mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-10-07 00:31:35 +02:00
Compare commits
1 Commits
docs/skill
...
docs/skill
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9b92f4e70 |
@@ -116,10 +116,9 @@ Attack your own plan before implementing:
|
|||||||
- What is the **blast radius** if the assumption underneath it is wrong?
|
- What is the **blast radius** if the assumption underneath it is wrong?
|
||||||
- What am I **inferring** that I could instead **detect at runtime** or **record explicitly**?
|
- What am I **inferring** that I could instead **detect at runtime** or **record explicitly**?
|
||||||
Highest-yield question here — see `references/evidence.md`'s failure-mode section.
|
Highest-yield question here — see `references/evidence.md`'s failure-mode section.
|
||||||
- For every branch that exists **only to survive something going wrong**: name the image or host
|
- For every branch that exists **only to survive something going wrong**: what input reaches it,
|
||||||
where that input actually arrives, and go and look. Naming is the bar, not reproducing it here —
|
on which image? Go and look. A fallback for a configuration you cannot find an instance of is
|
||||||
`references/simplify.md` works the `/dev/shm` guard and the `s6-dumpenv` fallback through that
|
not robustness, it is a second code path nobody will ever exercise or notice rotting.
|
||||||
distinction.
|
|
||||||
|
|
||||||
Full loop only, before writing code: get Codex's independent read on the plan. Spawn a subagent
|
Full loop only, before writing code: get Codex's independent read on the plan. Spawn a subagent
|
||||||
whose prompt includes the path `references/codex-review.md` and tells it to follow that file's
|
whose prompt includes the path `references/codex-review.md` and tells it to follow that file's
|
||||||
@@ -159,19 +158,13 @@ defends one you have now demonstrated, or one you have merely been told about? T
|
|||||||
correctness objection often deletes the code that made it necessary, and a fix that collapses back
|
correctness objection often deletes the code that made it necessary, and a fix that collapses back
|
||||||
to fewer lines than you started the review with is the normal outcome, not a suspicious one.
|
to fewer lines than you started the review with is the normal outcome, not a suspicious one.
|
||||||
|
|
||||||
These edits land after step 4's checks already ran, so re-run them: `scripts/validate.sh <addon>
|
|
||||||
--vs-master` plus the behavioural tests, over the final diff. Deleting a branch is exactly the
|
|
||||||
kind of edit that leaves a stray `fi` behind.
|
|
||||||
|
|
||||||
## 7. Open the PR
|
## 7. Open the PR
|
||||||
|
|
||||||
CI gates on a PR: **`CHANGELOG.md` updated** (hard fail), the **HA add-on linter**
|
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
|
(`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
|
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
|
`references/traps.md#versioning`) — Supervisor won't offer a rebuild without it. Update
|
||||||
`README.md` if you added options; write the CHANGELOG heading as `## <version> (<date>)`,
|
`README.md` if you added options; match the CHANGELOG heading format `## X.Y (DD-MM-YYYY)`.
|
||||||
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,
|
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.
|
**what is not verified**, and how to roll back the riskiest hunk alone.
|
||||||
@@ -192,12 +185,7 @@ work" — either it was exercised, or say plainly it wasn't.
|
|||||||
|
|
||||||
Light path: verification is `validate.sh` plus CI; anything beyond that is Assumed. Full loop: CI
|
Light path: verification is `validate.sh` plus CI; anything beyond that is Assumed. Full loop: CI
|
||||||
passing proves the build works, not that the change does anything — re-run the measurement that
|
passing proves the build works, not that the change does anything — re-run the measurement that
|
||||||
motivated the work once the rebuilt add-on is running. After merge, `git fetch origin master`
|
motivated the work once the rebuilt add-on is running. Real "merged and inert" examples, and what
|
||||||
(the tracking ref is stale otherwise), then confirm the *changes* survived — `git diff
|
|
||||||
origin/master -- <the paths you touched>` comes back empty. Ancestry is not the check: a revert
|
|
||||||
leaves your commit in history and undoes its tree, so `--contains` reports success either way. The
|
|
||||||
builder's revert-on-failure job can revert a merge for reasons unrelated to your diff (see
|
|
||||||
`references/traps.md#ci-and-review-bots`). Real "merged and inert" examples, and what
|
|
||||||
to do when a fix can't be self-verified: `references/evidence.md`.
|
to do when a fix can't be self-verified: `references/evidence.md`.
|
||||||
|
|
||||||
## 10. Calibrate and report
|
## 10. Calibrate and report
|
||||||
@@ -216,9 +204,5 @@ Risk + rollback — the riskiest hunk and how to revert it alone
|
|||||||
Lead with anything that did not work — a merged PR that achieved nothing is the single most
|
Lead with anything that did not work — a merged PR that achieved nothing is the single most
|
||||||
important sentence in the report. Give confidence per claim, not one blanket number.
|
important sentence in the report. Give confidence per claim, not one blanket number.
|
||||||
|
|
||||||
**Feed the skill.** When a shipped fix needed a follow-up PR, or a reviewer caught something this
|
|
||||||
skill should have, add the distilled lesson to the matching `references/` file in that follow-up
|
|
||||||
PR — one entry, with the PR numbers. That loop is what keeps this file short and the traps real.
|
|
||||||
|
|
||||||
Scripts are meant to be **run, not read** — each is cited at its point of use above; read one
|
Scripts are meant to be **run, not read** — each is cited at its point of use above; read one
|
||||||
only if its output surprises you.
|
only if its output surprises you.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Simplify — case studies
|
# Simplify — case studies
|
||||||
|
|
||||||
Evidence for why the mechanism ladder in SKILL.md step 3 exists, and why levels 4-6 need a reason
|
Evidence for why the mechanism ladder in SKILL.md step 3 exists, and why levels 4-6 need a reason
|
||||||
that survives being said out loud. In each case the simpler option existed and was skipped.
|
that survives being said out loud. In all three cases the simpler option existed and was skipped.
|
||||||
Being able to build the complicated thing is not a reason to.
|
Being able to build the complicated thing is not a reason to.
|
||||||
|
|
||||||
- A rejected PR spent a **388-line TCP proxy plus a 142-line monkeypatch of a private upstream
|
- A rejected PR spent a **388-line TCP proxy plus a 142-line monkeypatch of a private upstream
|
||||||
@@ -13,13 +13,6 @@ Being able to build the complicated thing is not a reason to.
|
|||||||
- A resolution cap shipped as a **new init script writing an s6 envdir** — the wrong mechanism
|
- A resolution cap shipped as a **new init script writing an s6 envdir** — the wrong mechanism
|
||||||
entirely (ladder level 4). Renaming the option to the env var the service already reads
|
entirely (ladder level 4). Renaming the option to the env var the service already reads
|
||||||
(level 1) would have worked, and the new script did not.
|
(level 1) would have worked, and the new script did not.
|
||||||
- A calibre-web trusted-ips fix injected the add-on's **per-boot IP**, which forced a
|
|
||||||
rewrite-every-boot design that erased user entries; preserving them then needed merge logic
|
|
||||||
plus a state file recording what was injected (+34 lines, PR #3009 — closed unmerged). Asking
|
|
||||||
"is there a constant that makes the rewrite unnecessary?" gave the shipped fix: trust the
|
|
||||||
static supervisor range `172.30.32.0/23`, one idempotent statement, **net −6 lines**
|
|
||||||
(PR #3010). Complexity spent working around a changing value is a sign to hunt for the
|
|
||||||
constant instead.
|
|
||||||
- A `.templates/ha_entrypoint.sh` fix went to review at 25 lines of code and merged at 10. Two
|
- A `.templates/ha_entrypoint.sh` fix went to review at 25 lines of code and merged at 10. Two
|
||||||
sources of the excess, and neither was caught by the loop: a **pure-bash fallback** written at
|
sources of the excess, and neither was caught by the loop: a **pure-bash fallback** written at
|
||||||
implement time for images shipping `with-contenv` but not `s6-dumpenv` — reasoned from the two
|
implement time for images shipping `with-contenv` but not `s6-dumpenv` — reasoned from the two
|
||||||
@@ -42,16 +35,10 @@ Being able to build the complicated thing is not a reason to.
|
|||||||
- **Is the fix bigger than the thing it fixes?** That is a smell, not a rule — but it usually
|
- **Is the fix bigger than the thing it fixes?** That is a smell, not a rule — but it usually
|
||||||
means the problem was framed one level too deep.
|
means the problem was framed one level too deep.
|
||||||
- **For each defensive branch: what input reaches it, on which image or host?** Go and check,
|
- **For each defensive branch: what input reaches it, on which image or host?** Go and check,
|
||||||
the way you would check a measurement. The bar is being able to **name** the case, not to
|
the way you would check a measurement. If you cannot produce the case, delete the branch — the
|
||||||
reproduce it here: Docker's 64 MB `/dev/shm` default is documented behaviour that HA does not
|
situation then fails the way it already fails today, visibly, instead of through a second path
|
||||||
override, so the bullet above keeps that guard even though this host measured 7.7 GB. Nobody
|
that is never exercised and silently rots as the base images move. Write down in the PR body
|
||||||
could name a single image shipping `with-contenv` without `s6-dumpenv`, so that fallback went.
|
what you cut and why, so the next person does not re-add it from the same reasoning.
|
||||||
If you cannot name the case, delete the branch — the situation then fails the way it already
|
|
||||||
fails today, visibly, instead of through a second path that is never exercised and silently
|
|
||||||
rots as the base images move. Weigh the cost too: a one-flag guard against a crash you cannot
|
|
||||||
rule out is cheap, a second code path that degrades to the pre-fix behaviour anyway is not.
|
|
||||||
Write down in the PR body what you cut and why, so the next person does not re-add it from the
|
|
||||||
same reasoning.
|
|
||||||
- **How does this fail in three years**, when the base image, Electron, or upstream has moved?
|
- **How does this fail in three years**, when the base image, Electron, or upstream has moved?
|
||||||
Code that reads a documented knob keeps working. Code that reaches into private internals
|
Code that reads a documented knob keeps working. Code that reaches into private internals
|
||||||
does not.
|
does not.
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ workflows and lint rules — that is not repeated here.
|
|||||||
- [Environment and workspace](#environment-and-workspace)
|
- [Environment and workspace](#environment-and-workspace)
|
||||||
- [Measurement](#measurement)
|
- [Measurement](#measurement)
|
||||||
- [Passing values into base-image services](#passing-values-into-base-image-services)
|
- [Passing values into base-image services](#passing-values-into-base-image-services)
|
||||||
- [Writing into an app's own config](#writing-into-an-apps-own-config)
|
|
||||||
- [Shell and bashio](#shell-and-bashio)
|
- [Shell and bashio](#shell-and-bashio)
|
||||||
- [Dockerfile and architecture](#dockerfile-and-architecture)
|
- [Dockerfile and architecture](#dockerfile-and-architecture)
|
||||||
- [Versioning](#versioning)
|
- [Versioning](#versioning)
|
||||||
@@ -117,26 +116,6 @@ place for filesystem and permission setup.
|
|||||||
the openbox autostart. (ANGLE's OpenGL backend, for instance, fails with "Could not open the
|
the openbox autostart. (ANGLE's OpenGL backend, for instance, fails with "Could not open the
|
||||||
default X display".)
|
default X display".)
|
||||||
|
|
||||||
## Writing into an app's own config
|
|
||||||
|
|
||||||
**A field your cont-init script writes may also be user-editable in the app's UI.** An
|
|
||||||
unconditional `UPDATE`/overwrite on every boot silently erases whatever the user added there,
|
|
||||||
and containers are recreated on restart so it re-erases forever (calibre-web
|
|
||||||
`config_reverse_proxy_trusted_ips`, #3004 — flagged by two review bots, fixed in #3010).
|
|
||||||
Prepend/merge with an idempotence guard instead of assigning.
|
|
||||||
|
|
||||||
**Prefer values that are constant across boots.** The add-on's own IP changes every restart,
|
|
||||||
so injecting it forces a rewrite-every-boot design plus stale-entry cleanup (a stale trusted IP
|
|
||||||
can be handed to a *different* add-on later). Trusting the whole supervisor range
|
|
||||||
`172.30.32.0/23` is constant, written once. For dual-stack listeners the IPv4 form never
|
|
||||||
matches IPv4-mapped addresses — also list the mapped form (`::ffff:172.30.32.0/119`).
|
|
||||||
|
|
||||||
Constant is not free when the value gates **authentication**: trusting the whole range means any
|
|
||||||
add-on on the supervisor network can send the auth header and impersonate a user. #3010 shipped
|
|
||||||
that as an explicit, stated trade-off with the maintainer's sign-off. State the blast radius in
|
|
||||||
the PR body and get the maintainer's call before widening trust — never present it as a neutral
|
|
||||||
simplification.
|
|
||||||
|
|
||||||
## Shell and bashio
|
## Shell and bashio
|
||||||
|
|
||||||
**`bashio::config` for lists**: `while read ... < <(bashio::config ...)` silently yields an empty
|
**`bashio::config` for lists**: `while read ... < <(bashio::config ...)` silently yields an empty
|
||||||
@@ -216,17 +195,6 @@ All three hard gates below are matrixed over `check-addon-changes.outputs.change
|
|||||||
- **Version bump** — no workflow checks it. It is repo convention, and required for Supervisor to
|
- **Version bump** — no workflow checks it. It is repo convention, and required for Supervisor to
|
||||||
offer the rebuild, but it will not fail CI.
|
offer the rebuild, but it will not fail CI.
|
||||||
|
|
||||||
**"Merged" is not "on master".** The push builder's revert-on-failure job reverts the merge
|
|
||||||
commit when its prebuild step fails — including failures unrelated to your diff. A seerr fix
|
|
||||||
merged at 05:15 and was reverted one minute later because `EndBug/add-and-commit`'s floating
|
|
||||||
`v11` tag had moved to a broken release (#2993, reapplied verbatim in #2997). After merge,
|
|
||||||
`git fetch origin master` first — the remote-tracking ref is stale otherwise and would "confirm"
|
|
||||||
against pre-merge state — then check that `git diff origin/master -- <the paths you touched>` is
|
|
||||||
empty before declaring done. Scope it to your paths: master moves under you, so whole-tree
|
|
||||||
equality fails on unrelated commits. Ancestry is not the check either — this repo squash-merges,
|
|
||||||
so a merged PR head is never an ancestor of `master` (verified on #3010, whose fix is live), and
|
|
||||||
a revert leaves the original commit an ancestor anyway.
|
|
||||||
|
|
||||||
**CI rewrites your shell scripts.** `lint.yml` runs `shfmt -w -i 4 -ci -bn -sr` over every `*.sh`
|
**CI rewrites your shell scripts.** `lint.yml` runs `shfmt -w -i 4 -ci -bn -sr` over every `*.sh`
|
||||||
and `run`, plus a `chmod +x` pass, on schedule. Repo-wide reformatting commits land on master
|
and `run`, plus a `chmod +x` pass, on schedule. Repo-wide reformatting commits land on master
|
||||||
without your involvement — another reason a shared checkout goes stale mid-task.
|
without your involvement — another reason a shared checkout goes stale mid-task.
|
||||||
@@ -241,18 +209,6 @@ account. Note it and move on rather than guessing.
|
|||||||
**Resolving a review thread requires GraphQL** (`resolveReviewThread`); the REST API cannot do it.
|
**Resolving a review thread requires GraphQL** (`resolveReviewThread`); the REST API cannot do it.
|
||||||
`scripts/pr_review.sh` wraps fetch / reply / resolve.
|
`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
|
**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`,
|
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.
|
not because the config exempts them — don't cite the config as a reason to ignore a finding.
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ resolve)
|
|||||||
;;
|
;;
|
||||||
watch)
|
watch)
|
||||||
MINS="${3:-180}" # the addon build alone has taken ~3h; 20 was far too short
|
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
|
for i in $(seq 1 "$MINS"); do
|
||||||
c=$(gh pr checks "$PR" 2> /dev/null | awk '{print $1"="$2}' | tr '\n' ' ')
|
c=$(gh pr checks "$PR" 2> /dev/null | awk '{print $1"="$2}' | tr '\n' ' ')
|
||||||
if [ -z "$c" ]; then
|
if [ -z "$c" ]; then
|
||||||
@@ -103,14 +102,11 @@ watch)
|
|||||||
case "$c" in
|
case "$c" in
|
||||||
*pending*) sleep 60 ;;
|
*pending*) sleep 60 ;;
|
||||||
*fail* | *error* | *cancel*) echo "settled — with FAILURES (see above)"; wfail=1; break ;;
|
*fail* | *error* | *cancel*) echo "settled — with FAILURES (see above)"; wfail=1; break ;;
|
||||||
*) echo "settled — all passing"; wfail=0; break ;;
|
*) echo "settled — all passing"; break ;;
|
||||||
esac
|
esac
|
||||||
done
|
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."
|
echo "note: long queues here are usually account runner contention, not your diff."
|
||||||
exit "$wfail"
|
exit "${wfail:-0}"
|
||||||
;;
|
;;
|
||||||
*) echo "unknown: $CMD"; exit 1 ;;
|
*) echo "unknown: $CMD"; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -64,8 +64,7 @@ if [ -n "${BUILD_VERSION:-}" ]; then
|
|||||||
echo " $SLUG/config.yaml version = $here"
|
echo " $SLUG/config.yaml version = $here"
|
||||||
echo " running image BUILD_VERSION = $BUILD_VERSION"
|
echo " running image BUILD_VERSION = $BUILD_VERSION"
|
||||||
if [ "$here" = "$BUILD_VERSION" ]; then
|
if [ "$here" = "$BUILD_VERSION" ]; then
|
||||||
# version is bumped once per PR, so a later commit or a dirty tree matches here.
|
echo " MATCH — this checkout corresponds to the running image."
|
||||||
echo " VERSION MATCH — source revision itself is not verified."
|
|
||||||
else
|
else
|
||||||
echo " MISMATCH — this branch is NOT what is running."
|
echo " MISMATCH — this branch is NOT what is running."
|
||||||
git fetch origin master --quiet 2> /dev/null
|
git fetch origin master --quiet 2> /dev/null
|
||||||
|
|||||||
@@ -4,13 +4,10 @@
|
|||||||
# rather than implying the build was checked.
|
# rather than implying the build was checked.
|
||||||
#
|
#
|
||||||
# --vs-master re-lints each changed file at origin/master and prints only findings your diff
|
# --vs-master re-lints each changed file at origin/master and prints only findings your diff
|
||||||
# ADDED, and fails if there are any. Without it you will chase warnings that were already there.
|
# ADDED. Without it you will chase warnings that were already in the file.
|
||||||
#
|
#
|
||||||
# Usage: validate.sh [addon-dir] [--vs-master]
|
# Usage: validate.sh [addon-dir] [--vs-master]
|
||||||
set -uo pipefail
|
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="${1:-}"
|
||||||
[ "${ADDON:-}" = "--vs-master" ] && { ADDON=""; set -- --vs-master; }
|
[ "${ADDON:-}" = "--vs-master" ] && { ADDON=""; set -- --vs-master; }
|
||||||
@@ -34,21 +31,17 @@ echo "== validating $ADDON =="
|
|||||||
|
|
||||||
fail=0
|
fail=0
|
||||||
note() { printf ' %-13s %s\n' "$1" "$2"; }
|
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). One list for both.
|
# Shell: bash -n then shellcheck -x (follows sourced files, as CI does).
|
||||||
files=()
|
while IFS= read -r f; do
|
||||||
while IFS= read -r f; do is_execline "$f" || files+=("$f"); done \
|
[ -f "$f" ] || continue
|
||||||
< <(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
|
if ! out=$(bash -n "$f" 2>&1); then note "bash -n" "FAIL $f"; echo "$out" | sed 's/^/ /'; fail=1; fi
|
||||||
done
|
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" "${#files[@]} file(s) checked"
|
[ "$fail" -eq 0 ] && note "bash -n" "ok"
|
||||||
|
|
||||||
if [ "${#files[@]}" -gt 0 ] && command -v shellcheck > /dev/null 2>&1; then
|
if command -v shellcheck > /dev/null 2>&1; then
|
||||||
sc=$(shellcheck -x -f gcc "${files[@]}" 2>&1)
|
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 [ -n "$sc" ]; then
|
if [ -n "$sc" ]; then
|
||||||
note "shellcheck" "$(printf '%s\n' "$sc" | grep -c .) finding(s)"
|
note "shellcheck" "$(printf '%s\n' "$sc" | grep -c .) finding(s)"
|
||||||
printf '%s\n' "$sc" | sed 's/^/ /' | head -20
|
printf '%s\n' "$sc" | sed 's/^/ /' | head -20
|
||||||
@@ -57,10 +50,7 @@ fi
|
|||||||
|
|
||||||
command -v hadolint > /dev/null 2>&1 && [ -f "$ADDON/Dockerfile" ] && {
|
command -v hadolint > /dev/null 2>&1 && [ -f "$ADDON/Dockerfile" ] && {
|
||||||
hl=$(hadolint "$ADDON/Dockerfile" 2>&1)
|
hl=$(hadolint "$ADDON/Dockerfile" 2>&1)
|
||||||
if [ -n "$hl" ]; then
|
[ -n "$hl" ] && { note "hadolint" "$(printf '%s\n' "$hl" | grep -c .) finding(s)"; printf '%s\n' "$hl" | sed 's/^/ /' | head -10; } || note "hadolint" "clean"
|
||||||
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
|
if [ -f "$ADDON/config.yaml" ]; then
|
||||||
@@ -89,14 +79,11 @@ $VS_MASTER && command -v npx > /dev/null 2>&1 && [ -f "$ADDON/CHANGELOG.md" ] &&
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
echo "== CI requirements =="
|
echo "== CI requirements =="
|
||||||
# -Fxq, not -q: unanchored, seerr's is matched by zzz_archived_overseerr's, and . is a wildcard.
|
if git diff --name-only origin/master...HEAD 2> /dev/null | grep -q "$ADDON/CHANGELOG.md"; then
|
||||||
# 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"
|
note "CHANGELOG" "updated"
|
||||||
else
|
else
|
||||||
# This one IS gated: onpr_check-pr.yaml exits 1 without it.
|
# This one IS gated: onpr_check-pr.yaml exits 1 without it.
|
||||||
note "CHANGELOG" "NOT UPDATED for $ADDON — CI hard-gates this"; fail=1
|
note "CHANGELOG" "NOT UPDATED — this is the one CI hard-gate"; fail=1
|
||||||
fi
|
fi
|
||||||
if git diff origin/master...HEAD -- "$ADDON/config.yaml" 2> /dev/null | grep -q '^+version:'; then
|
if git diff origin/master...HEAD -- "$ADDON/config.yaml" 2> /dev/null | grep -q '^+version:'; then
|
||||||
note "version" "bumped"
|
note "version" "bumped"
|
||||||
@@ -111,15 +98,8 @@ if $VS_MASTER; then
|
|||||||
echo
|
echo
|
||||||
echo "== findings ADDED by this diff (pre-existing ones filtered out) =="
|
echo "== findings ADDED by this diff (pre-existing ones filtered out) =="
|
||||||
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
|
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
|
||||||
added=0
|
git diff --name-only origin/master...HEAD -- "$ADDON" 2> /dev/null | while IFS= read -r f; do
|
||||||
# Fed by process substitution, not a pipe: a pipeline runs this in a subshell, where the
|
git show "origin/master:$f" > "$tmp/base" 2> /dev/null || continue
|
||||||
# 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":
|
# 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
|
# its "command not found" error is identical for base and head, so comm would
|
||||||
# cancel it out and report a false clean.
|
# cancel it out and report a false clean.
|
||||||
@@ -135,16 +115,12 @@ if $VS_MASTER; then
|
|||||||
cmd() { hadolint "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*//'; } ;;
|
cmd() { hadolint "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*//'; } ;;
|
||||||
*) continue ;;
|
*) continue ;;
|
||||||
esac
|
esac
|
||||||
b=$(cmd "$tmp/base" | sort)
|
cp "$tmp/base" "$tmp/base_f"; b=$(cmd "$tmp/base_f" | sort)
|
||||||
a=$(cmd "$f" | sort)
|
a=$(cmd "$f" | sort)
|
||||||
new=$(comm -13 <(printf '%s\n' "$b") <(printf '%s\n' "$a"))
|
new=$(comm -13 <(printf '%s\n' "$b") <(printf '%s\n' "$a") | grep -c .)
|
||||||
[ -n "$new" ] && {
|
[ "$new" -gt 0 ] && { echo " $f: $new NEW finding(s)"; comm -13 <(printf '%s\n' "$b") <(printf '%s\n' "$a") | sed 's/^/ /' | head -5; }
|
||||||
echo " $f: $(printf '%s\n' "$new" | grep -c .) NEW finding(s)"
|
done
|
||||||
printf '%s\n' "$new" | sed 's/^/ /' | head -5
|
echo " (nothing listed above = your diff introduced no new lint findings)"
|
||||||
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
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|||||||
2
.github/workflows/daily_README.yaml
vendored
2
.github/workflows/daily_README.yaml
vendored
@@ -228,7 +228,7 @@ jobs:
|
|||||||
echo "... done"
|
echo "... done"
|
||||||
|
|
||||||
- name: Commit if needed
|
- name: Commit if needed
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
message: "GitHub bot : README updated"
|
message: "GitHub bot : README updated"
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
|
|||||||
2
.github/workflows/daily_ai_fix.yaml
vendored
2
.github/workflows/daily_ai_fix.yaml
vendored
@@ -125,7 +125,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Analyse and fix
|
- name: Analyse and fix
|
||||||
if: steps.batch.outputs.count != '0'
|
if: steps.batch.outputs.count != '0'
|
||||||
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
|
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# Skip the OIDC -> Claude App token exchange. The scheduled path
|
# Skip the OIDC -> Claude App token exchange. The scheduled path
|
||||||
|
|||||||
2
.github/workflows/helper_stats_graphs.yaml
vendored
2
.github/workflows/helper_stats_graphs.yaml
vendored
@@ -237,7 +237,7 @@ jobs:
|
|||||||
# Get stars evolution
|
# Get stars evolution
|
||||||
wget -S -O .github/starsevol.svg "https://api.star-history.com/svg?repos=alexbelgium/hassio-addons&type=Date" || true
|
wget -S -O .github/starsevol.svg "https://api.star-history.com/svg?repos=alexbelgium/hassio-addons&type=Date" || true
|
||||||
- name: Commit if needed
|
- name: Commit if needed
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
message: "GitHub bot : graphs updated"
|
message: "GitHub bot : graphs updated"
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
|
|||||||
2
.github/workflows/on_claude_mention.yml
vendored
2
.github/workflows/on_claude_mention.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
|||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Run Claude Code
|
- name: Run Claude Code
|
||||||
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
|
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# AI_PR_TOKEN, not GITHUB_TOKEN, so a PR Claude opens triggers CI.
|
# AI_PR_TOKEN, not GITHUB_TOKEN, so a PR Claude opens triggers CI.
|
||||||
|
|||||||
2
.github/workflows/on_issue_approved.yaml
vendored
2
.github/workflows/on_issue_approved.yaml
vendored
@@ -135,7 +135,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Execute the plan
|
- name: Execute the plan
|
||||||
if: steps.bundle.outputs.has_plan == 'true'
|
if: steps.bundle.outputs.has_plan == 'true'
|
||||||
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
|
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
||||||
|
|||||||
2
.github/workflows/on_issues.yml
vendored
2
.github/workflows/on_issues.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
|||||||
# Remove issues list
|
# Remove issues list
|
||||||
rm issueslist
|
rm issueslist
|
||||||
- name: Commit if needed
|
- name: Commit if needed
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
message: "Github bot : issues linked to readme"
|
message: "Github bot : issues linked to readme"
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
|
|||||||
2
.github/workflows/on_issues_ai_triage.yaml
vendored
2
.github/workflows/on_issues_ai_triage.yaml
vendored
@@ -166,7 +166,7 @@ jobs:
|
|||||||
id: classify
|
id: classify
|
||||||
if: github.event_name != 'issue_comment' || steps.claim.outputs.go == 'true'
|
if: github.event_name != 'issue_comment' || steps.claim.outputs.go == 'true'
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
|
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# Without this the action falls back to the OIDC -> Claude App token
|
# Without this the action falls back to the OIDC -> Claude App token
|
||||||
|
|||||||
2
.github/workflows/on_pr_coderabbit.yml
vendored
2
.github/workflows/on_pr_coderabbit.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Address CodeRabbit comments
|
- name: Address CodeRabbit comments
|
||||||
if: steps.claim.outputs.go == 'true'
|
if: steps.claim.outputs.go == 'true'
|
||||||
uses: anthropics/claude-code-action@dcb57747bfceeaa1fa72638cae52295d1d853d4a # v1
|
uses: anthropics/claude-code-action@9d7150bc8a3dae8149739a88019d192b579ad90c # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
||||||
|
|||||||
4
.github/workflows/onpush_builder.yaml
vendored
4
.github/workflows/onpush_builder.yaml
vendored
@@ -95,7 +95,7 @@ jobs:
|
|||||||
- name: Commit sanitize changes
|
- name: Commit sanitize changes
|
||||||
id: sanitize_commit
|
id: sanitize_commit
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
commit: -u
|
commit: -u
|
||||||
message: "GitHub bot: sanitize (spaces + LF endings) & chmod [nobuild]"
|
message: "GitHub bot: sanitize (spaces + LF endings) & chmod [nobuild]"
|
||||||
@@ -410,7 +410,7 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
- name: Commit changelog changes
|
- name: Commit changelog changes
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
commit: -u
|
commit: -u
|
||||||
message: "GitHub bot: changelog [nobuild]"
|
message: "GitHub bot: changelog [nobuild]"
|
||||||
|
|||||||
4
.github/workflows/weekly_crlftolf.yaml
vendored
4
.github/workflows/weekly_crlftolf.yaml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
uses: erclu/check-crlf@v1
|
uses: erclu/check-crlf@v1
|
||||||
|
|
||||||
- name: Commit if needed
|
- name: Commit if needed
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
message: "Github bot : CRLF corrected"
|
message: "Github bot : CRLF corrected"
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
dos2unix -k "$f"
|
dos2unix -k "$f"
|
||||||
done
|
done
|
||||||
- name: Commit if needed
|
- name: Commit if needed
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
message: "Github bot : CRLF corrected"
|
message: "Github bot : CRLF corrected"
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
|
|||||||
2
.github/workflows/weekly_reduceimagesize.yml
vendored
2
.github/workflows/weekly_reduceimagesize.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Commit if needed
|
- name: Commit if needed
|
||||||
if: steps.calibre.outputs.markdown != ''
|
if: steps.calibre.outputs.markdown != ''
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
message: "Github bot : image compressed"
|
message: "Github bot : image compressed"
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
|
|||||||
2
.github/workflows/weekly_stats.yaml
vendored
2
.github/workflows/weekly_stats.yaml
vendored
@@ -109,7 +109,7 @@ jobs:
|
|||||||
#TOTAL3="$(awk '{SUM+=$2}END{print SUM}' Stats)"
|
#TOTAL3="$(awk '{SUM+=$2}END{print SUM}' Stats)"
|
||||||
|
|
||||||
- name: Commit if needed
|
- name: Commit if needed
|
||||||
uses: EndBug/add-and-commit@v11.1.1
|
uses: EndBug/add-and-commit@v11.0.0
|
||||||
with:
|
with:
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
message : "Github bot : stats updated"
|
message : "Github bot : stats updated"
|
||||||
|
|||||||
@@ -168,59 +168,6 @@ if [ -z "$shebang" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#####################################
|
|
||||||
# Seed the s6 container environment #
|
|
||||||
#####################################
|
|
||||||
|
|
||||||
# s6-overlay's stage 1 dumps the container's environment into /run/s6/container_environment, and
|
|
||||||
# `with-contenv` reads it back (emptyenv -p; s6-envdir). Add-ons that override the base image's
|
|
||||||
# ENTRYPOINT ["/init"] with ENTRYPOINT ["/usr/bin/env"] plus CMD ["/ha_entrypoint.sh"] never run
|
|
||||||
# stage 1, so nothing creates that directory and every #!/usr/bin/with-contenv script outside the
|
|
||||||
# three globs whose shebang is rewritten below either exits non-zero before its first line
|
|
||||||
# (directory missing: s6-envdir errors) or runs against whatever a cont-init script happened to
|
|
||||||
# leave there -- measured at 16 variables instead of 110, SUPERVISOR_TOKEN among the missing.
|
|
||||||
# Neither says anything, so all that surfaces is what the caller makes of it: a HEALTHCHECK
|
|
||||||
# reporting "unhealthy", a cron job doing nothing. So dump the environment here instead.
|
|
||||||
#
|
|
||||||
# Deliberately after the shebang probe above, not next to the other PID 1 setup: the probe's first
|
|
||||||
# candidate is "/command/with-contenv bashio" and it fails today in exactly these add-ons, so the
|
|
||||||
# probe falls through to "/usr/bin/env bashio". Seeding earlier would make that candidate start
|
|
||||||
# succeeding and flip the shebang of every cont-init and service script here, so scripts launched
|
|
||||||
# directly would lose what an earlier sourced script exported -- a far larger change than this.
|
|
||||||
#
|
|
||||||
# It does switch on two dormant writes: 00-global_var.sh and 01-config_yaml.sh push their values
|
|
||||||
# into the envdir, but only `if [ -d ]`. That is what those lines are for, and it means out-of-glob
|
|
||||||
# scripts now see the user's configured options too.
|
|
||||||
|
|
||||||
S6_CONTAINER_ENV="/run/s6/container_environment"
|
|
||||||
|
|
||||||
# Only when this script is PID 1 -- under /init it is the stage-2 hook and stage 1 has already
|
|
||||||
# written the directory -- and only where with-contenv exists to care.
|
|
||||||
if $PID1 && { [ -x /command/with-contenv ] || [ -x /usr/bin/with-contenv ]; }; then
|
|
||||||
# Filled in a sibling and renamed into place, never written to live. A half-populated envdir is
|
|
||||||
# worse than an absent one: s6-envdir accepts it, so a with-contenv script starts and runs
|
|
||||||
# against an environment quietly missing SUPERVISOR_TOKEN, where an absent one stops it at its
|
|
||||||
# shebang. rename(2) means a concurrent reader -- a HEALTHCHECK can run alongside PID 1 -- sees
|
|
||||||
# the directory either absent or complete, never mid-dump.
|
|
||||||
#
|
|
||||||
# Cleared rather than written over: /run is not a tmpfs here, so an image layer can persist
|
|
||||||
# entries, and writing name by name would merge into them and leave variables PID 1 does not
|
|
||||||
# have, a stale SUPERVISOR_TOKEN among them. A failed rm has to abort the chain, because mkdir -p
|
|
||||||
# accepts a surviving symlink-to-directory and would let the dump follow it. rm does not traverse
|
|
||||||
# a symlink, but it would empty anything bind-mounted at this exact path -- not a configuration
|
|
||||||
# any add-on uses, and not one s6 would tolerate either.
|
|
||||||
if rm -rf "$S6_CONTAINER_ENV" "$S6_CONTAINER_ENV.tmp" && mkdir -p "$S6_CONTAINER_ENV.tmp" &&
|
|
||||||
s6-dumpenv -- "$S6_CONTAINER_ENV.tmp" && mv "$S6_CONTAINER_ENV.tmp" "$S6_CONTAINER_ENV"; then
|
|
||||||
echo "Populated $S6_CONTAINER_ENV for with-contenv"
|
|
||||||
else
|
|
||||||
# Leaves the directory absent, which is exactly how this fails today -- so the failure mode is
|
|
||||||
# unchanged, not newly degraded. Never fatal, a read-only /run must still let the add-on boot,
|
|
||||||
# but never silent either, since the shebang failure it leaves behind says nothing on its own.
|
|
||||||
rm -rf "$S6_CONTAINER_ENV" "$S6_CONTAINER_ENV.tmp" 2>/dev/null || true
|
|
||||||
echo -e "\e[38;5;214m$(date) WARNING: could not populate $S6_CONTAINER_ENV; scripts with a with-contenv shebang will fail at their shebang, as they did before this was attempted\e[0m"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
####################################
|
####################################
|
||||||
# Bashio library for source fallback
|
# Bashio library for source fallback
|
||||||
####################################
|
####################################
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ If you want to do add the repository manually, please follow the procedure highl
|
|||||||
![aarch64][aarch64-badge]
|
![aarch64][aarch64-badge]
|
||||||
![amd64][amd64-badge]
|
![amd64][amd64-badge]
|
||||||
|
|
||||||
✓ [Free Games Claimer](free_games_claimer/) : Claims free games from Epic, Prime, GOG, Steam, Ubisoft and more
|
✓ [Free Games Claimer](free_games_claimer/) : Automatically claims free games from Epic Games Store, Amazon Prime Gaming, GOG, Steam, and optional GamerPower-supported stores
|
||||||
|
|
||||||
  
|
  
|
||||||

|

|
||||||
|
|||||||
@@ -1,28 +1,3 @@
|
|||||||
## 2.1.0 (2026-08-24)
|
|
||||||
|
|
||||||
- Updated the pinned upstream from Free Games Claimer Remaster 1.1 to 1.6,
|
|
||||||
which adds the Ubisoft giveaway, Fab, AliExpress and Epic mobile stores,
|
|
||||||
fixed daily scheduler times, the `VNC_URL` notification link override, and a
|
|
||||||
fix for the `--accept-lang` flag that made every store's browser detectable
|
|
||||||
as automated.
|
|
||||||
- Mirrored upstream's Chromium hardening: `xdg-open` is neutralised and an
|
|
||||||
`AutoLaunchProtocolsFromOrigins` policy is installed, so app-scheme links
|
|
||||||
cannot open a blocking dialog in the VNC session.
|
|
||||||
- Disabled upstream's release-update notification by default. It tells the user
|
|
||||||
to run `docker compose pull`, while the add-on is updated through the Home
|
|
||||||
Assistant add-on store. Set `NOTIFY_UPDATES=true` in `config.env` to receive
|
|
||||||
it anyway.
|
|
||||||
- Reworded the add-on description so the store list reads as partial rather
|
|
||||||
than exhaustive; the full list is in the README.
|
|
||||||
- The default store selection is unchanged: existing installations keep
|
|
||||||
claiming from Epic, Prime Gaming and GOG until `STORES` is edited.
|
|
||||||
- Replaced the pinned upstream commit with `ARG BUILD_UPSTREAM`, which names an
|
|
||||||
upstream release tag, and re-enabled the repository updater for this add-on.
|
|
||||||
Upstream releases are now picked up automatically instead of requiring a
|
|
||||||
manual commit pin. Upstream's development tags are excluded: `lastversion`
|
|
||||||
reports the `v1.7d` development tag as release `1.7`, for which no source
|
|
||||||
archive exists, so an unfiltered update would have broken the build.
|
|
||||||
|
|
||||||
## 2.0.1 (2026-07-17)
|
## 2.0.1 (2026-07-17)
|
||||||
|
|
||||||
- Aligned the pull-request build context with the production builder by copying
|
- Aligned the pull-request build context with the production builder by copying
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ ARG BUILD_REF
|
|||||||
ARG BUILD_REPOSITORY
|
ARG BUILD_REPOSITORY
|
||||||
ARG BUILD_VERSION
|
ARG BUILD_VERSION
|
||||||
ARG UPSTREAM_REPOSITORY="P-Adamiec/Free-Games-Claimer-Remaster"
|
ARG UPSTREAM_REPOSITORY="P-Adamiec/Free-Games-Claimer-Remaster"
|
||||||
ARG BUILD_UPSTREAM="1.6"
|
ARG UPSTREAM_REF="cca4992354215cef8807b748575af797606627f4"
|
||||||
|
|
||||||
ENV S6_CMD_WAIT_FOR_SERVICES="1" \
|
ENV S6_CMD_WAIT_FOR_SERVICES="1" \
|
||||||
S6_CMD_WAIT_FOR_SERVICES_MAXTIME="0" \
|
S6_CMD_WAIT_FOR_SERVICES_MAXTIME="0" \
|
||||||
@@ -27,7 +27,10 @@ ENV S6_CMD_WAIT_FOR_SERVICES="1" \
|
|||||||
WIDTH="1280" \
|
WIDTH="1280" \
|
||||||
HEIGHT="720" \
|
HEIGHT="720" \
|
||||||
DEPTH="24" \
|
DEPTH="24" \
|
||||||
SHOW="1"
|
SHOW="1" \
|
||||||
|
COMMIT="${UPSTREAM_REF}" \
|
||||||
|
BRANCH="main" \
|
||||||
|
NOW="${BUILD_DATE}"
|
||||||
|
|
||||||
# Install the dependencies used by Free Games Claimer Remaster. The upstream
|
# Install the dependencies used by Free Games Claimer Remaster. The upstream
|
||||||
# Dockerfile supports both amd64 (Google Chrome) and arm64 (Chromium), so the
|
# Dockerfile supports both amd64 (Google Chrome) and arm64 (Chromium), so the
|
||||||
@@ -84,11 +87,6 @@ RUN apt-get update \
|
|||||||
else \
|
else \
|
||||||
apt-get install -y --no-install-recommends chromium; \
|
apt-get install -y --no-install-recommends chromium; \
|
||||||
fi \
|
fi \
|
||||||
&& printf '#!/bin/sh\nexit 0\n' > /usr/bin/xdg-open \
|
|
||||||
&& chmod +x /usr/bin/xdg-open \
|
|
||||||
&& mkdir -p /etc/opt/chrome/policies/managed /etc/chromium/policies/managed \
|
|
||||||
&& printf '%s\n' '{"AutoLaunchProtocolsFromOrigins":[{"protocol":"aliexpress","allowed_origins":["*"]},{"protocol":"aliexpresshd","allowed_origins":["*"]},{"protocol":"aecmd","allowed_origins":["*"]},{"protocol":"alibaba","allowed_origins":["*"]},{"protocol":"alipay","allowed_origins":["*"]},{"protocol":"alipays","allowed_origins":["*"]},{"protocol":"tmall","allowed_origins":["*"]},{"protocol":"taobao","allowed_origins":["*"]},{"protocol":"market","allowed_origins":["*"]},{"protocol":"intent","allowed_origins":["*"]}]}' \
|
|
||||||
| tee /etc/opt/chrome/policies/managed/fgc-autolaunch.json /etc/chromium/policies/managed/fgc-autolaunch.json > /dev/null \
|
|
||||||
&& ln -sf /usr/share/novnc/vnc_auto.html /usr/share/novnc/index.html \
|
&& ln -sf /usr/share/novnc/vnc_auto.html /usr/share/novnc/index.html \
|
||||||
&& ln -sf /usr/bin/python3 /usr/bin/python \
|
&& ln -sf /usr/bin/python3 /usr/bin/python \
|
||||||
&& apt-get purge -y gnupg \
|
&& apt-get purge -y gnupg \
|
||||||
@@ -96,20 +94,13 @@ RUN apt-get update \
|
|||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/* /var/cache/* /var/tmp/* /tmp/* /usr/share/doc/*
|
&& rm -rf /var/lib/apt/lists/* /var/cache/* /var/tmp/* /tmp/* /usr/share/doc/*
|
||||||
|
|
||||||
# Install the upstream release named by BUILD_UPSTREAM. The repository updater
|
# Install a deterministic snapshot of the replacement upstream. Updating the
|
||||||
# bumps that value together with the add-on version. A release tag is a mutable
|
# upstream reference is intentionally explicit so image contents cannot change
|
||||||
# reference: rebuilding the same BUILD_UPSTREAM installs whatever the tag points
|
# without an add-on version bump.
|
||||||
# at today, which is the accepted cost of tracking upstream automatically.
|
|
||||||
# Upstream tags its releases "v1.6", but the tag name is downloaded without the
|
|
||||||
# prefix as well so that an unattended update does not fail the build if
|
|
||||||
# upstream ever drops it.
|
|
||||||
WORKDIR /fgc
|
WORKDIR /fgc
|
||||||
RUN (curl --proto "=https" --tlsv1.2 -fsSL \
|
RUN curl --proto "=https" --tlsv1.2 -fsSL \
|
||||||
"https://github.com/${UPSTREAM_REPOSITORY}/archive/v${BUILD_UPSTREAM}.tar.gz" \
|
"https://github.com/${UPSTREAM_REPOSITORY}/archive/${UPSTREAM_REF}.tar.gz" \
|
||||||
-o /tmp/free-games-claimer-remaster.tar.gz \
|
-o /tmp/free-games-claimer-remaster.tar.gz \
|
||||||
|| curl --proto "=https" --tlsv1.2 -fsSL \
|
|
||||||
"https://github.com/${UPSTREAM_REPOSITORY}/archive/${BUILD_UPSTREAM}.tar.gz" \
|
|
||||||
-o /tmp/free-games-claimer-remaster.tar.gz) \
|
|
||||||
&& tar -xzf /tmp/free-games-claimer-remaster.tar.gz --strip-components=1 -C /fgc \
|
&& tar -xzf /tmp/free-games-claimer-remaster.tar.gz --strip-components=1 -C /fgc \
|
||||||
&& python3 -m pip install --no-cache-dir --break-system-packages -r requirements.txt \
|
&& python3 -m pip install --no-cache-dir --break-system-packages -r requirements.txt \
|
||||||
&& dos2unix ./*.sh \
|
&& dos2unix ./*.sh \
|
||||||
@@ -164,4 +155,4 @@ LABEL \
|
|||||||
org.opencontainers.image.created="${BUILD_DATE}" \
|
org.opencontainers.image.created="${BUILD_DATE}" \
|
||||||
org.opencontainers.image.revision="${BUILD_REF}" \
|
org.opencontainers.image.revision="${BUILD_REF}" \
|
||||||
org.opencontainers.image.version="${BUILD_VERSION}" \
|
org.opencontainers.image.version="${BUILD_VERSION}" \
|
||||||
io.hass.upstream="https://github.com/${UPSTREAM_REPOSITORY}/releases"
|
io.hass.upstream="https://github.com/${UPSTREAM_REPOSITORY}/tree/${UPSTREAM_REF}"
|
||||||
|
|||||||
@@ -24,19 +24,14 @@ This add-on is based on
|
|||||||
[Free Games Claimer Remaster](https://github.com/P-Adamiec/Free-Games-Claimer-Remaster).
|
[Free Games Claimer Remaster](https://github.com/P-Adamiec/Free-Games-Claimer-Remaster).
|
||||||
It can claim free games from:
|
It can claim free games from:
|
||||||
|
|
||||||
- Epic Games Store, including its weekly free mobile game
|
- Epic Games Store
|
||||||
- Fab, Epic's asset marketplace (`fab`)
|
|
||||||
- Amazon Prime Gaming
|
- Amazon Prime Gaming
|
||||||
- GOG
|
- GOG
|
||||||
- Steam
|
- Steam
|
||||||
- Ubisoft giveaways (`ubisoft`)
|
|
||||||
- AliExpress daily coin check-in (`aliexpress`)
|
|
||||||
- GamerPower-supported stores, when explicitly enabled
|
- GamerPower-supported stores, when explicitly enabled
|
||||||
|
|
||||||
For compatibility with previous add-on releases, the default store selection
|
For compatibility with previous add-on releases, the default store selection
|
||||||
remains Epic Games, Prime Gaming, and GOG. The other stores are enabled by
|
remains Epic Games, Prime Gaming, and GOG.
|
||||||
adding them to `STORES`, for example `epic,prime,gog,fab,ubisoft`, and each
|
|
||||||
needs its own credentials in `config.env`.
|
|
||||||
|
|
||||||
## Web interface
|
## Web interface
|
||||||
|
|
||||||
@@ -103,11 +98,6 @@ NOTIFY=tgram://bot-token/chat-id
|
|||||||
# DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
|
# DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
|
||||||
```
|
```
|
||||||
|
|
||||||
Upstream's release-update notification (`NOTIFY_UPDATES`) is disabled by the
|
|
||||||
add-on, because it advises running `docker compose pull` while the add-on is
|
|
||||||
actually updated through the Home Assistant add-on store. Setting
|
|
||||||
`NOTIFY_UPDATES=true` in `config.env` re-enables it.
|
|
||||||
|
|
||||||
Existing variables such as `EG_EMAIL`, `EG_PASSWORD`, `PG_EMAIL`,
|
Existing variables such as `EG_EMAIL`, `EG_PASSWORD`, `PG_EMAIL`,
|
||||||
`PG_PASSWORD`, `PG_OTPKEY`, `GOG_EMAIL`, `GOG_PASSWORD`, `SHOW`, `WIDTH`,
|
`PG_PASSWORD`, `PG_OTPKEY`, `GOG_EMAIL`, `GOG_PASSWORD`, `SHOW`, `WIDTH`,
|
||||||
`HEIGHT`, `TIMEOUT`, `LOGIN_TIMEOUT`, `DRYRUN`, and `NOTIFY` remain compatible.
|
`HEIGHT`, `TIMEOUT`, `LOGIN_TIMEOUT`, `DRYRUN`, and `NOTIFY` remain compatible.
|
||||||
@@ -142,31 +132,16 @@ normally uses port `7080`.
|
|||||||
|
|
||||||
## Upstream update policy
|
## Upstream update policy
|
||||||
|
|
||||||
The image is built from the upstream release named by `ARG BUILD_UPSTREAM` in
|
The image is built from an explicit upstream commit in the Dockerfile. This
|
||||||
the Dockerfile, downloaded as the matching `v<version>` source tarball. The
|
keeps amd64 and aarch64 images reproducible and prevents an upstream branch or
|
||||||
repository updater tracks upstream releases and bumps that value, the add-on
|
container tag from changing without an add-on review and version bump.
|
||||||
version and `CHANGELOG.md` together, so a new upstream release reaches the
|
|
||||||
add-on without a manual edit.
|
|
||||||
|
|
||||||
A release tag is a mutable reference. Rebuilding the same `BUILD_UPSTREAM`
|
The repository updater is intentionally paused for this add-on because the
|
||||||
installs whatever that tag points at, so an upstream tag that is force-moved or
|
add-on uses its own `2.x` version series while the replacement upstream uses a
|
||||||
deleted would change or fail the build without an add-on change. That is the
|
`1.x` version series. An automatic replacement would risk a Home Assistant
|
||||||
accepted cost of automatic tracking, and it is the same trade-off every other
|
version regression and would not safely update the pinned commit. A maintainer
|
||||||
automatically updated add-on in this repository makes; the previous commit pin
|
upstream update must therefore update `UPSTREAM_REF`, `upstream_version`, the
|
||||||
was immutable but could only be advanced by hand.
|
add-on version, and `CHANGELOG.md` together.
|
||||||
|
|
||||||
Upstream's development tags (`v1.7d` and similar) are filtered out through
|
|
||||||
`"github_exclude": "d"` in `updater.json`. Without it the updater reports the
|
|
||||||
`v1.7d` tag as release `1.7`, for which GitHub serves no source archive, and
|
|
||||||
the build would fail.
|
|
||||||
|
|
||||||
The add-on version does not track the upstream version. The add-on uses a `2.x`
|
|
||||||
series while upstream is on `1.x`, and Home Assistant only offers an update
|
|
||||||
when the new version sorts strictly higher, so the updater increments the
|
|
||||||
add-on version (`2.1.0` to `2.1.1`) instead of publishing a lower-sorting
|
|
||||||
upstream number. The upstream release actually installed is recorded in
|
|
||||||
`upstream_version` in `updater.json`, in `CHANGELOG.md`, and in the add-on's
|
|
||||||
startup banner.
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
arch:
|
arch:
|
||||||
- aarch64
|
- aarch64
|
||||||
- amd64
|
- amd64
|
||||||
description: "Claims free games from Epic, Prime, GOG, Steam, Ubisoft and more"
|
description: "Automatically claims free games from Epic Games Store, Amazon Prime Gaming, GOG, Steam, and optional GamerPower-supported stores"
|
||||||
devices:
|
devices:
|
||||||
- /dev/dri
|
- /dev/dri
|
||||||
- /dev/dri/card0
|
- /dev/dri/card0
|
||||||
@@ -96,5 +96,5 @@ schema:
|
|||||||
slug: free_games_claimer
|
slug: free_games_claimer
|
||||||
udev: true
|
udev: true
|
||||||
url: https://github.com/alexbelgium/hassio-addons
|
url: https://github.com/alexbelgium/hassio-addons
|
||||||
version: "2.1.0"
|
version: "2.0.1"
|
||||||
webui: "[PROTO:ssl]://[HOST]:[PORT:6080]"
|
webui: "[PROTO:ssl]://[HOST]:[PORT:6080]"
|
||||||
|
|||||||
@@ -36,12 +36,6 @@ set -a
|
|||||||
source "${RUNTIME_CONFIG}"
|
source "${RUNTIME_CONFIG}"
|
||||||
set +a
|
set +a
|
||||||
|
|
||||||
# Upstream checks GitHub for newer releases and then tells the user to run
|
|
||||||
# "docker compose pull", which is wrong here: the add-on is updated through the
|
|
||||||
# Home Assistant add-on store. Default the check off, but honour an explicit
|
|
||||||
# NOTIFY_UPDATES from config.env.
|
|
||||||
export NOTIFY_UPDATES="${NOTIFY_UPDATES:-false}"
|
|
||||||
|
|
||||||
# The Home Assistant port mapping is intentionally kept at 6080 for a seamless
|
# The Home Assistant port mapping is intentionally kept at 6080 for a seamless
|
||||||
# upgrade from the previous add-on, even though the new upstream defaults to 7080.
|
# upgrade from the previous add-on, even though the new upstream defaults to 7080.
|
||||||
if [ -n "${NOVNC_PORT:-}" ] && [ "${NOVNC_PORT}" != "6080" ]; then
|
if [ -n "${NOVNC_PORT:-}" ] && [ "${NOVNC_PORT}" != "6080" ]; then
|
||||||
|
|||||||
@@ -10,17 +10,12 @@ TIMEOUT=60
|
|||||||
LOGIN_TIMEOUT=180
|
LOGIN_TIMEOUT=180
|
||||||
VNC_LOGIN_TIMEOUT=180
|
VNC_LOGIN_TIMEOUT=180
|
||||||
NOVNC_PORT=6080
|
NOVNC_PORT=6080
|
||||||
# Public address used in notification links when behind a reverse proxy.
|
|
||||||
# VNC_URL=https://fgc.example.tld
|
|
||||||
|
|
||||||
# Keep the previous add-on's default stores. The upstream also supports
|
# Keep the previous add-on's default stores. Add steam or gamerpower if wanted.
|
||||||
# steam, fab, ubisoft, aliexpress and gamerpower; add them here if wanted.
|
|
||||||
STORES=epic,prime,gog
|
STORES=epic,prime,gog
|
||||||
|
|
||||||
# Used only when RUN_ONCE is disabled in the add-on options.
|
# Used only when RUN_ONCE is disabled in the add-on options.
|
||||||
SCHEDULER_HOURS=12
|
SCHEDULER_HOURS=12
|
||||||
# SCHEDULER_TIMEZONE=UTC
|
|
||||||
# SCHEDULER_FIXED_TIMES=17:00,21:30
|
|
||||||
|
|
||||||
# Common credentials can be used as fallbacks for all stores.
|
# Common credentials can be used as fallbacks for all stores.
|
||||||
# EMAIL=
|
# EMAIL=
|
||||||
@@ -38,27 +33,7 @@ SCHEDULER_HOURS=12
|
|||||||
# GOG_PASSWORD=
|
# GOG_PASSWORD=
|
||||||
# STEAM_USERNAME=
|
# STEAM_USERNAME=
|
||||||
# STEAM_PASSWORD=
|
# STEAM_PASSWORD=
|
||||||
# UBI_EMAIL=
|
|
||||||
# UBI_PASSWORD=
|
|
||||||
# UBI_OTPKEY=
|
|
||||||
# AE_EMAIL=
|
|
||||||
# AE_PASSWORD=
|
|
||||||
|
|
||||||
# Epic's weekly free mobile game, claimed with the epic store.
|
|
||||||
# EG_MOBILE=true
|
|
||||||
# EG_MOBILE_PLATFORMS=android,ios
|
|
||||||
|
|
||||||
# Fab assets sign in with the Epic account. Accepting the licence agreement is
|
|
||||||
# required to claim; set to false to be notified instead of accepting.
|
|
||||||
# FAB_ACCEPT_EULA=true
|
|
||||||
|
|
||||||
# Notifications (Apprise or Discord)
|
# Notifications (Apprise or Discord)
|
||||||
# NOTIFY=
|
# NOTIFY=
|
||||||
# DISCORD_WEBHOOK=
|
# DISCORD_WEBHOOK=
|
||||||
# NOTIFY_ALREADY_CLAIMED=false
|
|
||||||
# NOTIFY_SKIP_STORES=
|
|
||||||
|
|
||||||
# Upstream release notifications are disabled by the add-on: updates are
|
|
||||||
# delivered through the Home Assistant add-on store, not by docker compose.
|
|
||||||
# Set to true to receive them anyway.
|
|
||||||
# NOTIFY_UPDATES=false
|
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
{
|
{
|
||||||
"dockerhub_by_date": false,
|
"dockerhub_by_date": false,
|
||||||
"dockerhub_list_size": 2,
|
"dockerhub_list_size": 2,
|
||||||
"github_exclude": "d",
|
"last_update": "17-07-2026",
|
||||||
"github_fulltag": false,
|
"paused": true,
|
||||||
"last_update": "24-08-2026",
|
|
||||||
"paused": false,
|
|
||||||
"repository": "alexbelgium/hassio-addons",
|
"repository": "alexbelgium/hassio-addons",
|
||||||
"slug": "free_games_claimer",
|
"slug": "free_games_claimer",
|
||||||
"source": "github",
|
"source": "github",
|
||||||
"upstream_repo": "P-Adamiec/Free-Games-Claimer-Remaster",
|
"upstream_repo": "P-Adamiec/Free-Games-Claimer-Remaster",
|
||||||
"upstream_version": "1.6"
|
"upstream_version": "1.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
## 2.44.0.1 (2026-08-24)
|
|
||||||
|
|
||||||
- Rebuild to pick up a fix in the shared entrypoint: when `ha_entrypoint.sh` runs as PID 1, as it does in this add-on, it now populates `/run/s6/container_environment`, so a script carrying a `#!/usr/bin/with-contenv` shebang gets a populated environment including `SUPERVISOR_TOKEN` instead of failing at its shebang. Nothing shipped in this add-on still uses that shebang (the healthcheck moved to plain bash in 2.44.0), so this changes nothing about the agent itself; it matters for a `script.sh` added by the user, and it is the add-on that build-tests the shared change
|
|
||||||
|
|
||||||
## 2.44.0 (2026-08-23)
|
## 2.44.0 (2026-08-23)
|
||||||
|
|
||||||
- Fix: Use `portainer/agent:alpine-sts` to match the STS release channel configured in `updater.json`
|
- Fix: Use `portainer/agent:alpine-sts` to match the STS release channel configured in `updater.json`
|
||||||
|
|||||||
@@ -41,4 +41,4 @@ schema:
|
|||||||
slug: portainer_agent
|
slug: portainer_agent
|
||||||
udev: true
|
udev: true
|
||||||
url: https://github.com/alexbelgium/hassio-addons
|
url: https://github.com/alexbelgium/hassio-addons
|
||||||
version: "2.44.0.1"
|
version: "2.44.0"
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
|
|
||||||
## 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)
|
## 5.1.1 (2026-08-22)
|
||||||
- Update to latest version from linuxserver/docker-sabnzbd (changelog : https://github.com/linuxserver/docker-sabnzbd/releases)
|
- Update to latest version from linuxserver/docker-sabnzbd (changelog : https://github.com/linuxserver/docker-sabnzbd/releases)
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ environment:
|
|||||||
PGID: "0"
|
PGID: "0"
|
||||||
PUID: "0"
|
PUID: "0"
|
||||||
image: ghcr.io/alexbelgium/sabnzbd-{arch}
|
image: ghcr.io/alexbelgium/sabnzbd-{arch}
|
||||||
ingress: true
|
ingress_entry: sabnzbd
|
||||||
init: false
|
init: false
|
||||||
map:
|
map:
|
||||||
- addon_config:rw
|
- addon_config:rw
|
||||||
@@ -106,4 +106,5 @@ schema:
|
|||||||
slug: sabnzbd
|
slug: sabnzbd
|
||||||
udev: true
|
udev: true
|
||||||
url: https://github.com/alexbelgium/hassio-addons
|
url: https://github.com/alexbelgium/hassio-addons
|
||||||
version: "5.1.1.2"
|
version: "5.1.1"
|
||||||
|
webui: http://[HOST]:[PORT:8080]
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
#!/usr/bin/with-contenv bashio
|
#!/usr/bin/with-contenv bashio
|
||||||
# shellcheck shell=bash
|
# shellcheck shell=bash
|
||||||
|
# shellcheck disable=SC2317
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# NGINX SETTING #
|
# NGINX SETTING #
|
||||||
#################
|
#################
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
ingress_port=$(bashio::addon.ingress_port)
|
ingress_port=$(bashio::addon.ingress_port)
|
||||||
ingress_interface=$(bashio::addon.ip_address)
|
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/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf
|
||||||
sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf
|
sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf
|
||||||
sed -i "s|%%ingress_entry%%|${ingress_entry}|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
|
||||||
|
|||||||
@@ -2,34 +2,22 @@ server {
|
|||||||
listen %%interface%%:%%port%% default_server;
|
listen %%interface%%:%%port%% default_server;
|
||||||
|
|
||||||
include /etc/nginx/includes/server_params.conf;
|
include /etc/nginx/includes/server_params.conf;
|
||||||
|
include /etc/nginx/includes/proxy_params.conf;
|
||||||
|
|
||||||
client_max_body_size 0;
|
client_max_body_size 0;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://127.0.0.1:8080;
|
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;
|
||||||
|
|
||||||
# SABnzbd refuses any request whose Host is not an IP literal
|
proxy_set_header Accept-Encoding "";
|
||||||
# ("Access denied - Hostname verification failed"), so send the
|
# Correct url without port when using https
|
||||||
# upstream socket rather than the browser's host. X-Forwarded-For is
|
sub_filter_once off;
|
||||||
# the only other header it reads (for its verify_xff_header option).
|
sub_filter_types *;
|
||||||
proxy_set_header Host $proxy_host;
|
sub_filter /sabnzbd %%ingress_entry%%/sabnzbd;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/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
|
|
||||||
Reference in New Issue
Block a user