mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-07-14 01:45:08 +02:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 34e6e17c6a | |||
| 666bdbd8c8 | |||
| 7596b95517 | |||
| 1521e131b5 | |||
| 734bb75b12 | |||
| d6d8d20c76 | |||
| 649e66ed2b | |||
| 81bb9c7d71 | |||
| ca082aedf0 | |||
| 1e7667e5f8 | |||
| f828e629b5 | |||
| 4a98e86db1 | |||
| 37b5242c21 | |||
| a1333222a8 | |||
| 12949bce6c |
@@ -506,10 +506,29 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- fix(hyperion): keep service running after container reboot [@TowyTowy](https://github.com/TowyTowy) ([#15653](https://github.com/community-scripts/ProxmoxVE/pull/15653))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- immich: use actual PostgreSQL version for VectorChord package lookup [@mnavon](https://github.com/mnavon) ([#15705](https://github.com/community-scripts/ProxmoxVE/pull/15705))
|
||||||
|
- fix storyteller release selection for stable web tags [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15736](https://github.com/community-scripts/ProxmoxVE/pull/15736))
|
||||||
|
- Docmost: Fix update procedure [@MickLesk](https://github.com/MickLesk) ([#15732](https://github.com/community-scripts/ProxmoxVE/pull/15732))
|
||||||
|
- fix(shinobi): remove obsolete --unsafe-perm npm flag [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15730](https://github.com/community-scripts/ProxmoxVE/pull/15730))
|
||||||
|
|
||||||
- #### 💥 Breaking Changes
|
- #### 💥 Breaking Changes
|
||||||
|
|
||||||
- reitti: update to v5 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15635](https://github.com/community-scripts/ProxmoxVE/pull/15635))
|
- reitti: update to v5 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15635](https://github.com/community-scripts/ProxmoxVE/pull/15635))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix(build.func): parse script status without jq dependency [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15729](https://github.com/community-scripts/ProxmoxVE/pull/15729))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- tools.func: some improvements (sql injection / command injection / guard) [@MickLesk](https://github.com/MickLesk) ([#15661](https://github.com/community-scripts/ProxmoxVE/pull/15661))
|
||||||
|
|
||||||
## 2026-07-12
|
## 2026-07-12
|
||||||
|
|
||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|||||||
+3
-2
@@ -39,7 +39,6 @@ function update_script() {
|
|||||||
|
|
||||||
create_backup /opt/docmost/.env \
|
create_backup /opt/docmost/.env \
|
||||||
/opt/docmost/data
|
/opt/docmost/data
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "docmost" "docmost/docmost" "tarball"
|
fetch_and_deploy_gh_release "docmost" "docmost/docmost" "tarball"
|
||||||
|
|
||||||
restore_backup
|
restore_backup
|
||||||
@@ -54,9 +53,11 @@ function update_script() {
|
|||||||
sed -i '/^@Module({$/i @Global()' /opt/docmost/apps/server/src/core/core.module.ts
|
sed -i '/^@Module({$/i @Global()' /opt/docmost/apps/server/src/core/core.module.ts
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
msg_info "Configuring Docmost"
|
||||||
|
cd /opt/docmost
|
||||||
$STD pnpm install --force
|
$STD pnpm install --force
|
||||||
$STD pnpm build
|
$STD pnpm build
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Configured Docmost"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start docmost
|
systemctl start docmost
|
||||||
|
|||||||
+3
-1
@@ -125,6 +125,8 @@ EOF
|
|||||||
systemctl stop immich-ml
|
systemctl stop immich-ml
|
||||||
msg_ok "Stopped Services"
|
msg_ok "Stopped Services"
|
||||||
VCHORD_RELEASE="1.1.1"
|
VCHORD_RELEASE="1.1.1"
|
||||||
|
PG_VERSION=$(ls /etc/postgresql/ 2>/dev/null | sort -V | tail -1)
|
||||||
|
PG_VERSION=${PG_VERSION:-16}
|
||||||
[[ -f ~/.vchord_version ]] && mv ~/.vchord_version ~/.vectorchord
|
[[ -f ~/.vchord_version ]] && mv ~/.vchord_version ~/.vectorchord
|
||||||
if check_for_gh_release "VectorChord" "tensorchord/VectorChord" "${VCHORD_RELEASE}" "updated together with Immich after testing"; then
|
if check_for_gh_release "VectorChord" "tensorchord/VectorChord" "${VCHORD_RELEASE}" "updated together with Immich after testing"; then
|
||||||
# dead tuples in smart_search/face_search make the REINDEX below fail with
|
# dead tuples in smart_search/face_search make the REINDEX below fail with
|
||||||
@@ -132,7 +134,7 @@ EOF
|
|||||||
# while still on the old extension version, a post-upgrade vacuum errors instead
|
# while still on the old extension version, a post-upgrade vacuum errors instead
|
||||||
$STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) smart_search;"
|
$STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) smart_search;"
|
||||||
$STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) face_search;"
|
$STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) face_search;"
|
||||||
fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-16-vchord_*_$(arch_resolve).deb"
|
fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" "${VCHORD_RELEASE}" "/tmp" "postgresql-${PG_VERSION}-vchord_*_$(arch_resolve).deb"
|
||||||
systemctl restart postgresql
|
systemctl restart postgresql
|
||||||
$STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vector UPDATE;"
|
$STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vector UPDATE;"
|
||||||
$STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vchord UPDATE;"
|
$STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vchord UPDATE;"
|
||||||
|
|||||||
+2
-2
@@ -32,7 +32,7 @@ function update_script() {
|
|||||||
|
|
||||||
NODE_VERSION="24" NODE_MODULE="corepack,yarn" setup_nodejs
|
NODE_VERSION="24" NODE_MODULE="corepack,yarn" setup_nodejs
|
||||||
|
|
||||||
if check_for_gl_release "storyteller" "storyteller-platform/storyteller"; then
|
if check_for_gl_release "storyteller" "storyteller-platform/storyteller" "" "" "web-v2"; then
|
||||||
msg_info "Stopping Service"
|
msg_info "Stopping Service"
|
||||||
systemctl stop storyteller
|
systemctl stop storyteller
|
||||||
msg_ok "Stopped Service"
|
msg_ok "Stopped Service"
|
||||||
@@ -41,7 +41,7 @@ function update_script() {
|
|||||||
cp /opt/storyteller/.env /opt/storyteller_env.bak
|
cp /opt/storyteller/.env /opt/storyteller_env.bak
|
||||||
msg_ok "Backed up Data"
|
msg_ok "Backed up Data"
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller"
|
CLEAN_INSTALL=1 fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller" "" "web-v2"
|
||||||
|
|
||||||
msg_info "Restoring Configuration"
|
msg_info "Restoring Configuration"
|
||||||
mv /opt/storyteller_env.bak /opt/storyteller/.env
|
mv /opt/storyteller_env.bak /opt/storyteller/.env
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ msg_ok "Set up Hyperion repository"
|
|||||||
|
|
||||||
msg_info "Installing Hyperion"
|
msg_info "Installing Hyperion"
|
||||||
$STD apt install -y hyperion
|
$STD apt install -y hyperion
|
||||||
|
mkdir -p /etc/systemd/system/hyperion@.service.d
|
||||||
|
cat <<EOF >/etc/systemd/system/hyperion@.service.d/override.conf
|
||||||
|
[Unit]
|
||||||
|
Requisite=
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
systemctl enable -q --now hyperion@root
|
systemctl enable -q --now hyperion@root
|
||||||
msg_ok "Installed Hyperion"
|
msg_ok "Installed Hyperion"
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ cronKey=$(head -c 1024 </dev/urandom | sha256sum | awk '{print substr($1,1,29)}'
|
|||||||
sed -i -e 's/Shinobi/'"$cronKey"'/g' conf.json
|
sed -i -e 's/Shinobi/'"$cronKey"'/g' conf.json
|
||||||
cp super.sample.json super.json
|
cp super.sample.json super.json
|
||||||
$STD npm i npm -g
|
$STD npm i npm -g
|
||||||
$STD npm install --unsafe-perm
|
$STD npm install
|
||||||
$STD npm install pm2@latest -g
|
$STD npm install pm2@latest -g
|
||||||
chmod -R 755 .
|
chmod -R 755 .
|
||||||
touch INSTALL/installed.txt
|
touch INSTALL/installed.txt
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ NODE_VERSION="24" NODE_MODULE="corepack,yarn" setup_nodejs
|
|||||||
|
|
||||||
fetch_and_deploy_gh_release "readium" "readium/cli" "prebuild" "latest" "/opt/readium" "readium_linux_$(arch_resolve "x86_64" "arm64").tar.gz"
|
fetch_and_deploy_gh_release "readium" "readium/cli" "prebuild" "latest" "/opt/readium" "readium_linux_$(arch_resolve "x86_64" "arm64").tar.gz"
|
||||||
ln -sf /opt/readium/readium /usr/local/bin/readium
|
ln -sf /opt/readium/readium /usr/local/bin/readium
|
||||||
fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller"
|
fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "tarball" "latest" "/opt/storyteller" "" "web-v2"
|
||||||
|
|
||||||
msg_info "Setting up Storyteller"
|
msg_info "Setting up Storyteller"
|
||||||
cd /opt/storyteller
|
cd /opt/storyteller
|
||||||
|
|||||||
+9
-10
@@ -3764,19 +3764,18 @@ runtime_script_status_guard() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v jq >/dev/null 2>&1; then
|
local is_deleted is_disabled deleted_message disable_message info_url
|
||||||
msg_warn "Missing jq for script status check. Continuing without status verification."
|
if printf '%s' "$response" | grep -qE '"items":[[:space:]]*\[[[:space:]]*\]'; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local has_record is_deleted is_disabled deleted_message disable_message info_url
|
# PocketBase returns a flat, fixed-field JSON blob; sed is enough here (no jq needed).
|
||||||
has_record=$(printf '%s' "$response" | jq -r '.items | length')
|
is_deleted=$(printf '%s' "$response" | sed -n 's/.*"is_deleted"[[:space:]]*:[[:space:]]*\(true\|false\).*/\1/p' | head -1)
|
||||||
[[ "$has_record" == "0" ]] && return 0
|
is_disabled=$(printf '%s' "$response" | sed -n 's/.*"is_disabled"[[:space:]]*:[[:space:]]*\(true\|false\).*/\1/p' | head -1)
|
||||||
|
deleted_message=$(printf '%s' "$response" | sed -n 's/.*"deleted_message"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
||||||
is_deleted=$(printf '%s' "$response" | jq -r '.items[0].is_deleted // false')
|
disable_message=$(printf '%s' "$response" | sed -n 's/.*"disable_message"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
||||||
is_disabled=$(printf '%s' "$response" | jq -r '.items[0].is_disabled // false')
|
is_deleted=${is_deleted:-false}
|
||||||
deleted_message=$(printf '%s' "$response" | jq -r '.items[0].deleted_message // ""')
|
is_disabled=${is_disabled:-false}
|
||||||
disable_message=$(printf '%s' "$response" | jq -r '.items[0].disable_message // ""')
|
|
||||||
info_url="https://community-scripts.org/scripts/${script_slug}"
|
info_url="https://community-scripts.org/scripts/${script_slug}"
|
||||||
|
|
||||||
if [[ "$is_deleted" == "true" ]]; then
|
if [[ "$is_deleted" == "true" ]]; then
|
||||||
|
|||||||
+90
-28
@@ -36,6 +36,10 @@
|
|||||||
#
|
#
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
|
# Guard against double-sourcing (core.func uses the same pattern)
|
||||||
|
[[ -n "${_TOOLS_FUNC_LOADED:-}" ]] && return 0
|
||||||
|
_TOOLS_FUNC_LOADED=1
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Debug helper - outputs to stderr when TOOLS_DEBUG is enabled
|
# Debug helper - outputs to stderr when TOOLS_DEBUG is enabled
|
||||||
# Usage: debug_log "message"
|
# Usage: debug_log "message"
|
||||||
@@ -91,16 +95,17 @@ curl_with_retry() {
|
|||||||
while [[ $attempt -le $retries ]]; do
|
while [[ $attempt -le $retries ]]; do
|
||||||
debug_log "curl attempt $attempt/$retries: $url"
|
debug_log "curl attempt $attempt/$retries: $url"
|
||||||
|
|
||||||
local curl_cmd="curl -fsSL --connect-timeout $connect_timeout --max-time $timeout"
|
# Build curl command as array to avoid command injection via extra_opts
|
||||||
[[ -n "$extra_opts" ]] && curl_cmd="$curl_cmd $extra_opts"
|
local -a curl_args=(curl -fsSL --connect-timeout "$connect_timeout" --max-time "$timeout")
|
||||||
|
[[ -n "$extra_opts" ]] && read -ra _extra <<<"$extra_opts" && curl_args+=("${_extra[@]}")
|
||||||
|
|
||||||
if [[ "$output" == "-" ]]; then
|
if [[ "$output" == "-" ]]; then
|
||||||
if $curl_cmd "$url"; then
|
if "${curl_args[@]}" "$url"; then
|
||||||
success=true
|
success=true
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if $curl_cmd -o "$output" "$url"; then
|
if "${curl_args[@]}" -o "$output" "$url"; then
|
||||||
success=true
|
success=true
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -153,15 +158,16 @@ curl_api_with_retry() {
|
|||||||
while [[ $attempt -le $retries ]]; do
|
while [[ $attempt -le $retries ]]; do
|
||||||
debug_log "curl API attempt $attempt/$retries: $url"
|
debug_log "curl API attempt $attempt/$retries: $url"
|
||||||
|
|
||||||
local curl_cmd="curl -fsSL --connect-timeout $connect_timeout --max-time $timeout -w '%{http_code}'"
|
# Build curl command as array to avoid command injection via extra_opts
|
||||||
[[ -n "$extra_opts" ]] && curl_cmd="$curl_cmd $extra_opts"
|
local -a curl_args=(curl -fsSL --connect-timeout "$connect_timeout" --max-time "$timeout" -w '%{http_code}')
|
||||||
|
[[ -n "$extra_opts" ]] && read -ra _extra <<<"$extra_opts" && curl_args+=("${_extra[@]}")
|
||||||
|
|
||||||
if [[ -n "$body_file" ]]; then
|
if [[ -n "$body_file" ]]; then
|
||||||
http_code=$($curl_cmd -o "$body_file" "$url" 2>/dev/null) || true
|
http_code=$("${curl_args[@]}" -o "$body_file" "$url" 2>/dev/null) || true
|
||||||
else
|
else
|
||||||
# Capture body and http_code separately
|
# Capture body and http_code separately
|
||||||
local tmp_body="/tmp/curl_api_body_$$"
|
local tmp_body="/tmp/curl_api_body_$$"
|
||||||
http_code=$($curl_cmd -o "$tmp_body" "$url" 2>/dev/null) || true
|
http_code=$("${curl_args[@]}" -o "$tmp_body" "$url" 2>/dev/null) || true
|
||||||
if [[ -f "$tmp_body" ]]; then
|
if [[ -f "$tmp_body" ]]; then
|
||||||
cat "$tmp_body"
|
cat "$tmp_body"
|
||||||
rm -f "$tmp_body"
|
rm -f "$tmp_body"
|
||||||
@@ -304,7 +310,10 @@ edit_yaml_config() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sed -i "s|^\([[:space:]]*${key}[[:space:]]*:\).*|\1 ${value}|" "$file"
|
# Escape sed metacharacters in value (| and &) to prevent injection
|
||||||
|
local escaped_value="${value//|/\\|}"
|
||||||
|
escaped_value="${escaped_value//&/\\&}"
|
||||||
|
sed -i "s|^\([[:space:]]*${key}[[:space:]]*:\).*|\1 ${escaped_value}|" "$file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -1687,10 +1696,6 @@ is_ubuntu() {
|
|||||||
[[ "$(get_os_info id)" == "ubuntu" ]]
|
[[ "$(get_os_info id)" == "ubuntu" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
is_alpine() {
|
|
||||||
[[ "$(get_os_info id)" == "alpine" ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Get Debian/Ubuntu major version
|
# Get Debian/Ubuntu major version
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -2454,8 +2459,10 @@ start_timer() {
|
|||||||
end_timer() {
|
end_timer() {
|
||||||
local start_time="$1"
|
local start_time="$1"
|
||||||
local label="${2:-Operation}"
|
local label="${2:-Operation}"
|
||||||
local end_time=$(date +%s)
|
local end_time
|
||||||
|
end_time=$(date +%s)
|
||||||
local duration=$((end_time - start_time))
|
local duration=$((end_time - start_time))
|
||||||
|
echo "${label} took ${duration}s"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -2826,6 +2833,7 @@ check_for_gh_release() {
|
|||||||
local source="$2"
|
local source="$2"
|
||||||
local pinned_version_in="${3:-}" # optional
|
local pinned_version_in="${3:-}" # optional
|
||||||
local pin_reason="${4:-}" # optional reason shown to user
|
local pin_reason="${4:-}" # optional reason shown to user
|
||||||
|
local tag_prefix="${5:-}" # optional tag prefix filter (e.g. web-v2)
|
||||||
local app_lc=""
|
local app_lc=""
|
||||||
app_lc="$(echo "${app,,}" | tr -d ' ')"
|
app_lc="$(echo "${app,,}" | tr -d ' ')"
|
||||||
local current_file="$HOME/.${app_lc}"
|
local current_file="$HOME/.${app_lc}"
|
||||||
@@ -2881,7 +2889,7 @@ check_for_gh_release() {
|
|||||||
rm -f "$gh_check_json"
|
rm -f "$gh_check_json"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "$pinned_version_in" ]]; then
|
if [[ -z "$pinned_version_in" && -z "$tag_prefix" ]]; then
|
||||||
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o "$gh_check_json" \
|
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o "$gh_check_json" \
|
||||||
-H 'Accept: application/vnd.github+json' \
|
-H 'Accept: application/vnd.github+json' \
|
||||||
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
||||||
@@ -2909,7 +2917,7 @@ check_for_gh_release() {
|
|||||||
rm -f "$gh_check_json"
|
rm -f "$gh_check_json"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If no releases yet (pinned version OR /latest failed), fetch up to 100
|
# If no releases yet (pinned version, tag prefix, OR /latest failed), fetch up to 100
|
||||||
if [[ -z "$releases_json" ]]; then
|
if [[ -z "$releases_json" ]]; then
|
||||||
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o "$gh_check_json" \
|
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o "$gh_check_json" \
|
||||||
-H 'Accept: application/vnd.github+json' \
|
-H 'Accept: application/vnd.github+json' \
|
||||||
@@ -2947,9 +2955,18 @@ check_for_gh_release() {
|
|||||||
rm -f "$gh_check_json"
|
rm -f "$gh_check_json"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mapfile -t raw_tags < <(jq -r '.[] | select(.draft==false and .prerelease==false) | .tag_name' <<<"$releases_json")
|
if [[ -n "$tag_prefix" ]]; then
|
||||||
|
mapfile -t raw_tags < <(jq -r --arg p "$tag_prefix" \
|
||||||
|
'.[] | select(.draft==false and .prerelease==false) | select(.tag_name | startswith($p)) | .tag_name' <<<"$releases_json")
|
||||||
|
else
|
||||||
|
mapfile -t raw_tags < <(jq -r '.[] | select(.draft==false and .prerelease==false) | .tag_name' <<<"$releases_json")
|
||||||
|
fi
|
||||||
if ((${#raw_tags[@]} == 0)); then
|
if ((${#raw_tags[@]} == 0)); then
|
||||||
msg_error "No stable releases found for ${app}"
|
if [[ -n "$tag_prefix" ]]; then
|
||||||
|
msg_error "No stable releases matching prefix '${tag_prefix}' found for ${app}"
|
||||||
|
else
|
||||||
|
msg_error "No stable releases found for ${app}"
|
||||||
|
fi
|
||||||
return 250
|
return 250
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -3953,6 +3970,7 @@ fetch_and_deploy_gh_release() {
|
|||||||
local version="${var_appversion:-${4:-latest}}"
|
local version="${var_appversion:-${4:-latest}}"
|
||||||
local target="${5:-/opt/$app}"
|
local target="${5:-/opt/$app}"
|
||||||
local asset_pattern="${6:-}"
|
local asset_pattern="${6:-}"
|
||||||
|
local tag_prefix="${7:-}"
|
||||||
|
|
||||||
# Validate app name to prevent /root/. directory issues
|
# Validate app name to prevent /root/. directory issues
|
||||||
if [[ -z "$app" ]]; then
|
if [[ -z "$app" ]]; then
|
||||||
@@ -3982,7 +4000,13 @@ fetch_and_deploy_gh_release() {
|
|||||||
TOOLS_GH_REL_JSON="$gh_rel_json"
|
TOOLS_GH_REL_JSON="$gh_rel_json"
|
||||||
|
|
||||||
local api_url="https://api.github.com/repos/$repo/releases"
|
local api_url="https://api.github.com/repos/$repo/releases"
|
||||||
[[ "$version" != "latest" ]] && api_url="$api_url/tags/$version" || api_url="$api_url/latest"
|
if [[ "$version" != "latest" ]]; then
|
||||||
|
api_url="$api_url/tags/$version"
|
||||||
|
elif [[ -n "$tag_prefix" ]]; then
|
||||||
|
api_url="$api_url?per_page=100"
|
||||||
|
else
|
||||||
|
api_url="$api_url/latest"
|
||||||
|
fi
|
||||||
local header=()
|
local header=()
|
||||||
[[ -n "${GITHUB_TOKEN:-}" ]] && header=(-H "Authorization: token $GITHUB_TOKEN")
|
[[ -n "${GITHUB_TOKEN:-}" ]] && header=(-H "Authorization: token $GITHUB_TOKEN")
|
||||||
|
|
||||||
@@ -4045,6 +4069,14 @@ fetch_and_deploy_gh_release() {
|
|||||||
|
|
||||||
local json tag_name
|
local json tag_name
|
||||||
json=$(<"$gh_rel_json")
|
json=$(<"$gh_rel_json")
|
||||||
|
if [[ "$version" == "latest" && -n "$tag_prefix" ]]; then
|
||||||
|
json=$(echo "$json" | jq --arg p "$tag_prefix" \
|
||||||
|
'[.[] | select(.draft==false and .prerelease==false) | select(.tag_name | startswith($p))][0] // empty')
|
||||||
|
if [[ -z "$json" || "$json" == "null" ]]; then
|
||||||
|
msg_error "No stable release matching prefix '${tag_prefix}' found for $repo on GitHub"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
tag_name=$(echo "$json" | jq -r '.tag_name // .name // empty')
|
tag_name=$(echo "$json" | jq -r '.tag_name // .name // empty')
|
||||||
# Only strip leading 'v' when followed by a digit (e.g. v1.2.3), not words like "version/..."
|
# Only strip leading 'v' when followed by a digit (e.g. v1.2.3), not words like "version/..."
|
||||||
[[ "$tag_name" =~ ^v[0-9] ]] && version="${tag_name:1}" || version="$tag_name"
|
[[ "$tag_name" =~ ^v[0-9] ]] && version="${tag_name:1}" || version="$tag_name"
|
||||||
@@ -6939,9 +6971,11 @@ setup_mariadb_db() {
|
|||||||
|
|
||||||
msg_info "Setting up MariaDB Database"
|
msg_info "Setting up MariaDB Database"
|
||||||
|
|
||||||
$STD mariadb -u root -e "CREATE DATABASE \`$MARIADB_DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
# Use --defaults-extra-file to pass credentials safely and escape identifiers
|
||||||
$STD mariadb -u root -e "CREATE USER '$MARIADB_DB_USER'@'localhost' IDENTIFIED BY '$MARIADB_DB_PASS';"
|
# to prevent SQL injection via DB name / user / password
|
||||||
$STD mariadb -u root -e "GRANT ALL ON \`$MARIADB_DB_NAME\`.* TO '$MARIADB_DB_USER'@'localhost';"
|
$STD mariadb -u root -e "CREATE DATABASE \`${MARIADB_DB_NAME//\`/\`\`}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||||
|
$STD mariadb -u root -e "CREATE USER '${MARIADB_DB_USER//\'/\'\'}'@'localhost' IDENTIFIED BY '${MARIADB_DB_PASS//\'/\'\'}';"
|
||||||
|
$STD mariadb -u root -e "GRANT ALL ON \`${MARIADB_DB_NAME//\`/\`\`}\`.* TO '${MARIADB_DB_USER//\'/\'\'}'@'localhost';"
|
||||||
|
|
||||||
# Optional extra grants
|
# Optional extra grants
|
||||||
if [[ -n "${MARIADB_DB_EXTRA_GRANTS:-}" ]]; then
|
if [[ -n "${MARIADB_DB_EXTRA_GRANTS:-}" ]]; then
|
||||||
@@ -8571,8 +8605,14 @@ setup_postgresql_db() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Setting up PostgreSQL Database"
|
msg_info "Setting up PostgreSQL Database"
|
||||||
$STD sudo -u postgres psql -c "CREATE ROLE $PG_DB_USER WITH LOGIN PASSWORD '$PG_DB_PASS';"
|
# Escape single quotes in identifiers to prevent SQL injection
|
||||||
$STD sudo -u postgres psql -c "CREATE DATABASE $PG_DB_NAME WITH OWNER $PG_DB_USER ENCODING 'UTF8' TEMPLATE template0;"
|
local _pg_user_escaped _pg_pass_escaped _pg_db_escaped
|
||||||
|
_pg_user_escaped="${PG_DB_USER//\'/\'\'}"
|
||||||
|
_pg_pass_escaped="${PG_DB_PASS//\'/\'\'}"
|
||||||
|
_pg_db_escaped="${PG_DB_NAME//\'/\'\'}"
|
||||||
|
|
||||||
|
$STD sudo -u postgres psql -c "CREATE ROLE $_pg_user_escaped WITH LOGIN PASSWORD '$_pg_pass_escaped';"
|
||||||
|
$STD sudo -u postgres psql -c "CREATE DATABASE $_pg_db_escaped WITH OWNER $_pg_user_escaped ENCODING 'UTF8' TEMPLATE template0;"
|
||||||
|
|
||||||
# Configure pg_cron database BEFORE creating the extension (must be set before pg_cron loads)
|
# Configure pg_cron database BEFORE creating the extension (must be set before pg_cron loads)
|
||||||
if [[ -n "${PG_DB_EXTENSIONS:-}" ]] && [[ ",${PG_DB_EXTENSIONS//[[:space:]]/}," == *",pg_cron,"* ]]; then
|
if [[ -n "${PG_DB_EXTENSIONS:-}" ]] && [[ ",${PG_DB_EXTENSIONS//[[:space:]]/}," == *",pg_cron,"* ]]; then
|
||||||
@@ -9469,6 +9509,7 @@ check_for_gl_release() {
|
|||||||
local source="$2"
|
local source="$2"
|
||||||
local pinned_version_in="${3:-}" # optional
|
local pinned_version_in="${3:-}" # optional
|
||||||
local pin_reason="${4:-}" # optional reason shown to user
|
local pin_reason="${4:-}" # optional reason shown to user
|
||||||
|
local tag_prefix="${5:-}" # optional tag prefix filter (e.g. web-v2)
|
||||||
local app_lc="${app,,}"
|
local app_lc="${app,,}"
|
||||||
local current_file="$HOME/.${app_lc}"
|
local current_file="$HOME/.${app_lc}"
|
||||||
|
|
||||||
@@ -9545,9 +9586,18 @@ check_for_gl_release() {
|
|||||||
rm -f "$gl_check_json"
|
rm -f "$gl_check_json"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mapfile -t raw_tags < <(jq -r '.[] | .tag_name' <<<"$releases_json")
|
if [[ -n "$tag_prefix" ]]; then
|
||||||
|
mapfile -t raw_tags < <(jq -r --arg p "$tag_prefix" \
|
||||||
|
'.[] | select(.tag_name | startswith($p)) | .tag_name' <<<"$releases_json")
|
||||||
|
else
|
||||||
|
mapfile -t raw_tags < <(jq -r '.[] | .tag_name' <<<"$releases_json")
|
||||||
|
fi
|
||||||
if ((${#raw_tags[@]} == 0)); then
|
if ((${#raw_tags[@]} == 0)); then
|
||||||
msg_error "No releases found for ${app} on GitLab"
|
if [[ -n "$tag_prefix" ]]; then
|
||||||
|
msg_error "No releases matching prefix '${tag_prefix}' found for ${app} on GitLab"
|
||||||
|
else
|
||||||
|
msg_error "No releases found for ${app} on GitLab"
|
||||||
|
fi
|
||||||
return 250
|
return 250
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -9742,6 +9792,7 @@ fetch_and_deploy_gl_release() {
|
|||||||
local version="${var_appversion:-${4:-latest}}"
|
local version="${var_appversion:-${4:-latest}}"
|
||||||
local target="${5:-/opt/$app}"
|
local target="${5:-/opt/$app}"
|
||||||
local asset_pattern="${6:-}"
|
local asset_pattern="${6:-}"
|
||||||
|
local tag_prefix="${7:-}"
|
||||||
|
|
||||||
if [[ -z "$app" ]]; then
|
if [[ -z "$app" ]]; then
|
||||||
app="${repo##*/}"
|
app="${repo##*/}"
|
||||||
@@ -9773,6 +9824,8 @@ fetch_and_deploy_gl_release() {
|
|||||||
local api_url
|
local api_url
|
||||||
if [[ "$version" != "latest" ]]; then
|
if [[ "$version" != "latest" ]]; then
|
||||||
api_url="$api_base/$version"
|
api_url="$api_base/$version"
|
||||||
|
elif [[ -n "$tag_prefix" ]]; then
|
||||||
|
api_url="$api_base?per_page=100&order_by=released_at&sort=desc"
|
||||||
else
|
else
|
||||||
api_url="$api_base?per_page=1&order_by=released_at&sort=desc"
|
api_url="$api_base?per_page=1&order_by=released_at&sort=desc"
|
||||||
fi
|
fi
|
||||||
@@ -9827,9 +9880,18 @@ fetch_and_deploy_gl_release() {
|
|||||||
json=$(<"$gl_rel_json")
|
json=$(<"$gl_rel_json")
|
||||||
|
|
||||||
if [[ "$version" == "latest" ]]; then
|
if [[ "$version" == "latest" ]]; then
|
||||||
json=$(echo "$json" | jq '.[0] // empty')
|
if [[ -n "$tag_prefix" ]]; then
|
||||||
|
json=$(echo "$json" | jq --arg p "$tag_prefix" \
|
||||||
|
'[.[] | select(.tag_name | startswith($p))][0] // empty')
|
||||||
|
else
|
||||||
|
json=$(echo "$json" | jq '.[0] // empty')
|
||||||
|
fi
|
||||||
if [[ -z "$json" || "$json" == "null" ]]; then
|
if [[ -z "$json" || "$json" == "null" ]]; then
|
||||||
msg_error "No releases found for $repo on GitLab"
|
if [[ -n "$tag_prefix" ]]; then
|
||||||
|
msg_error "No release matching prefix '${tag_prefix}' found for $repo on GitLab"
|
||||||
|
else
|
||||||
|
msg_error "No releases found for $repo on GitLab"
|
||||||
|
fi
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user