Prevent terminal job-control signals from suspending the script during recovery by trapping TSTP, TTIN and TTOU (instead of only TSTP) and restoring them on exit. Also clear the terminal 'tostop' flag in stop_spinner() with `stty -tostop` to avoid background spinner I/O from stopping the process group.
* fix(zammad): configure Elasticsearch for LXC container startup
- Set discovery.type: single-node (required for single-node ES)
- Set xpack.security.enabled: false (not needed in local LXC)
- Set bootstrap.memory_lock: false (fails in unprivileged LXC)
- Add startup wait loop (up to 60s) to ensure ES is ready before
Zammad installation continues
Fixes #12301-related recurring Elasticsearch startup failures
* refactor(api): eliminate duplicate traps, harden error handling & telemetry
Phase 1 - Structural:
- Remove api_exit_script() and 5 inline traps from build.func
- error_handler.func is now the sole trap owner via catch_errors()
- Update api.func comment reference (api_exit_script -> on_exit)
Phase 2 - Quality:
- Add stop_spinner() + cursor restore to error_handler(), on_interrupt(),
on_terminate(), on_hangup() to prevent spinner/cursor artifacts
- Enhance _send_abort_telemetry() with error text (last 20 log lines),
duration calculation, and 2 retry attempts (was fire-and-forget)
- Harden json_escape() to also strip DEL (0x7F) character
* fix(build): show spinner during post_update_to_api to prevent Ctrl+Z abort
post_update_to_api can take up to 33 seconds worst-case (3 curl attempts
x 10s timeout + sleep delays). Without any terminal output during this
time, users think the script is stuck and press Ctrl+Z, which prevents
the recovery menu from ever appearing.
Add msg_info spinner before both post_update_to_api calls in the failure
path (initial report + final force retry after recovery menu).
* fix(build): prevent SIGTSTP from killing recovery dialog
- Replace msg_info/stop_spinner with plain echo for telemetry reporting
The background spinner process in non-interactive shells (bash -c)
can trigger SIGTSTP, stopping the entire process group before the
recovery dialog appears. Plain echo avoids this.
- Add trap '' TSTP at failure path entry to ignore suspension signals
Prevents Ctrl+Z or terminal-related SIGTSTP from interrupting the
recovery menu. Restored with trap - TSTP before exit.
- Root cause: msg_info starts a background process (spinner &) that
is not properly detached in non-interactive shells where job control
(set -m) is OFF. The disown builtin has no effect without job
control, leaving the spinner in the same process group. This can
cause terminal I/O conflicts during the 33-second post_update_to_api
retry window, resulting in [2]+ Stopped.
* fix(test): initialize colors and remove illegal local in test harness
- Call load_functions() after sourcing core.func to initialize
color/formatting/icon variables (RD, GN, YW, CL, TAB, etc.)
- Remove 'local' keyword from top-level scope (not inside function)
- Default REPO_SOURCE to ref_api instead of main
* chore: remove test-recovery-dialog.sh from branch
* Revert "fix(zammad): configure Elasticsearch for LXC container startup"
This reverts commit 10e450b72f.
* fix(build): show telemetry status only in verbose mode
Telemetry reporting is an implementation detail that doesn't help
the user during failure recovery. Wrap echo statements with
VERBOSE check so they only appear when verbose mode is enabled.
* fix(workflow): improve Node.js version drift detection accuracy
1. Fix source URL regex: now captures 'Github: https://github.com/...'
pattern (pipe-separated), not just '# Source: https://github.com/...'
This was causing ~50 scripts to show 'No GitHub source'
2. Fix semver comparison: engines.node constraints like '>=18.0.0'
no longer flag version 22 as drift. >= and ^ constraints are now
properly evaluated (our_version >= min_major = satisfied)
3. Add fallback detection: when no Dockerfile or engines.node is found,
check .nvmrc and .node-version files for Node version hints
4. Add subdirectory search: Dockerfile and package.json are now found
via GitHub API tree search, not just in repo root
5. Use GitHub API to detect default branch instead of guessing
main/master/dev with multiple HEAD requests
* fix typos in node_version
* runs on vps
* fix(error-handler): prevent silent() from re-enabling error handling during recovery
Root cause: silent() (core.func) unconditionally calls set -Eeuo pipefail
and trap 'error_handler' ERR after every command. When build_container()
intentionally disables error handling for its recovery section, any
intermediate call through silent()/ re-enables it. This causes the
grep/sed pipeline for missing_cmd extraction to trigger error_handler
(grep returns exit code 1 on no match + pipefail = fatal).
Fixes:
1. silent(): Save errexit state before disabling, only restore if it was
active. Callers that intentionally disabled error handling (e.g.
build_container recovery) are no longer silently re-enabled.
2. build.func: Add || true to missing_cmd grep pipeline as defense-in-depth
against pipeline failure propagation.
3. build.func: Add explicit set +Eeuo pipefail / trap - ERR after
post_update_to_api() call, before error classification grep/sed section.
4. build.func: Remove stale global combined_log variable from variables()
that used a different path format (/tmp/install-SESSION-combined.log)
than the actual local variable (/tmp/NSAPP-CTID-SESSION.log). The global
was never written to and caused confusion when error_handler displayed it.
* Update build.func
* chore(install): add Github source links to all setup_nodejs scripts
52 install scripts had a project website in '# Source:' but no GitHub
link. Merged the GitHub repo URL into the Source header as:
# Source: https://website.com/ | Github: https://github.com/OWNER/REPO
Repos sourced from fetch_and_deploy_gh_release calls, get_latest_github_release
calls, or known project repos for npm/pip installed apps.
Two scripts (fumadocs, pve-scripts-local) had no Source line at all —
added one. Shinobi skipped (GitLab-only, no GitHub repo).
* chore(install): add Github source links to all fetch_and_deploy scripts
77 additional install scripts had fetch_and_deploy_gh_release calls but
no GitHub link in the Source header. Merged the primary app repo into
the Source header as:
# Source: https://website.com/ | Github: https://github.com/OWNER/REPO
Where multiple fetch_and_deploy calls existed (app + dependency), the
primary app repo was selected:
- ersatztv: ErsatzTV/ErsatzTV (not ffmpeg)
- firefly: firefly-iii/firefly-iii (not data-importer)
- komga: gotson/komga (not kepubify dep)
- sabnzbd: sabnzbd/sabnzbd (not par2cmdline-turbo dep)
- signoz: SigNoz/signoz (not otel-collector)
- tunarr: chrisbenincasa/tunarr (not ffmpeg dep)
Also fixed cosmos-install.sh double https:// in Source URL.
Skipped: autocaliweb (source already on codeberg, GitHub repos are deps only)
* revert: restore misc/build.func and misc/core.func to main state
These error-handler fixes belong to fix/error-handler-recovery, not to
this sources-only branch.
* chore(ct,tools): sync Source headers with install/ and add Github links to addon scripts
Scans all install scripts using setup_nodejs and compares our
NODE_VERSION with upstream Dockerfile and package.json values.
Features:
- Detects FROM node:XX, nodesource/setup_XX, FROM alpine:X.Y
- Resolves Alpine package registry for nodejs version when
upstream uses alpine base images
- Caches Alpine version lookups to minimize requests
- Creates individual GitHub issues per script with investigation
checklist when drift is detected
- Rate-limited to avoid GitHub API throttling
- Runs weekly on Monday at 06:00 UTC + manual dispatch