mirror of
https://github.com/okxlin/appstore.git
synced 2026-10-30 16:05:49 +00:00
Merge pull request #7989 from renovate/ghcr.io-diced-zipline-4.x
Update Zipline from 4.8.0 to 4.8.1.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
CONTAINER_NAME=zipline
|
||||
PANEL_APP_BIND_ADDRESS=127.0.0.1
|
||||
PANEL_APP_PORT_HTTP=3000
|
||||
POSTGRES_DB=zipline
|
||||
POSTGRES_USER=zipline
|
||||
POSTGRES_PASSWORD=generate
|
||||
CORE_SECRET=generate
|
||||
FILES_MAX_FILE_SIZE=100mb
|
||||
APP_DATA_DIR=./data
|
||||
@@ -0,0 +1,135 @@
|
||||
additionalProperties:
|
||||
formFields:
|
||||
- default: 127.0.0.1
|
||||
edit: true
|
||||
envKey: PANEL_APP_BIND_ADDRESS
|
||||
labelEn: Bind Address
|
||||
labelZh: 绑定地址
|
||||
label:
|
||||
en: Bind Address
|
||||
zh: 绑定地址
|
||||
zh-Hant: 綁定位址
|
||||
ja: バインドアドレス
|
||||
ko: 바인드 주소
|
||||
ru: Адрес привязки
|
||||
ms: Alamat ikatan
|
||||
pt-br: Endereco de vinculacao
|
||||
required: true
|
||||
type: text
|
||||
- default: 3000
|
||||
edit: true
|
||||
envKey: PANEL_APP_PORT_HTTP
|
||||
labelEn: HTTP Port
|
||||
labelZh: HTTP 端口
|
||||
label:
|
||||
en: HTTP Port
|
||||
zh: HTTP 端口
|
||||
zh-Hant: HTTP 連接埠
|
||||
ja: HTTP ポート
|
||||
ko: HTTP 포트
|
||||
ru: HTTP-порт
|
||||
ms: Port HTTP
|
||||
pt-br: Porta HTTP
|
||||
required: true
|
||||
rule: paramPort
|
||||
type: number
|
||||
- default: 100mb
|
||||
edit: true
|
||||
envKey: FILES_MAX_FILE_SIZE
|
||||
labelEn: Maximum File Size
|
||||
labelZh: 最大文件大小
|
||||
label:
|
||||
en: Maximum File Size
|
||||
zh: 最大文件大小
|
||||
zh-Hant: 最大檔案大小
|
||||
ja: 最大ファイルサイズ
|
||||
ko: 최대 파일 크기
|
||||
ru: Максимальный размер файла
|
||||
ms: Saiz fail maksimum
|
||||
pt-br: Tamanho maximo do arquivo
|
||||
required: true
|
||||
type: text
|
||||
- default: zipline
|
||||
edit: true
|
||||
envKey: POSTGRES_DB
|
||||
labelEn: Database Name
|
||||
labelZh: 数据库名称
|
||||
label:
|
||||
en: Database Name
|
||||
zh: 数据库名称
|
||||
zh-Hant: 資料庫名稱
|
||||
ja: データベース名
|
||||
ko: 데이터베이스 이름
|
||||
ru: Имя базы данных
|
||||
ms: Nama pangkalan data
|
||||
pt-br: Nome do banco de dados
|
||||
random: true
|
||||
required: true
|
||||
rule: paramCommon
|
||||
type: text
|
||||
- default: zipline
|
||||
edit: true
|
||||
envKey: POSTGRES_USER
|
||||
labelEn: Database User
|
||||
labelZh: 数据库用户
|
||||
label:
|
||||
en: Database User
|
||||
zh: 数据库用户
|
||||
zh-Hant: 資料庫使用者
|
||||
ja: データベースユーザー
|
||||
ko: 데이터베이스 사용자
|
||||
ru: Пользователь базы данных
|
||||
ms: Pengguna pangkalan data
|
||||
pt-br: Usuario do banco de dados
|
||||
random: true
|
||||
required: true
|
||||
rule: paramCommon
|
||||
type: text
|
||||
- default: generate
|
||||
edit: true
|
||||
envKey: POSTGRES_PASSWORD
|
||||
labelEn: Database Password
|
||||
labelZh: 数据库密码
|
||||
label:
|
||||
en: Database Password
|
||||
zh: 数据库密码
|
||||
zh-Hant: 資料庫密碼
|
||||
ja: データベースパスワード
|
||||
ko: 데이터베이스 비밀번호
|
||||
ru: Пароль базы данных
|
||||
ms: Kata laluan pangkalan data
|
||||
pt-br: Senha do banco de dados
|
||||
required: true
|
||||
type: password
|
||||
- default: generate
|
||||
edit: true
|
||||
envKey: CORE_SECRET
|
||||
labelEn: Session Secret
|
||||
labelZh: 会话密钥
|
||||
label:
|
||||
en: Session Secret
|
||||
zh: 会话密钥
|
||||
zh-Hant: 工作階段密鑰
|
||||
ja: セッションシークレット
|
||||
ko: 세션 비밀 키
|
||||
ru: Секрет сеанса
|
||||
ms: Rahsia sesi
|
||||
pt-br: Segredo da sessao
|
||||
required: true
|
||||
type: password
|
||||
- default: ./data
|
||||
edit: true
|
||||
envKey: APP_DATA_DIR
|
||||
labelEn: Data Directory
|
||||
labelZh: 数据目录
|
||||
label:
|
||||
en: Data Directory
|
||||
zh: 数据目录
|
||||
zh-Hant: 資料目錄
|
||||
ja: データディレクトリ
|
||||
ko: 데이터 디렉터리
|
||||
ru: Каталог данных
|
||||
ms: Direktori data
|
||||
pt-br: Diretorio de dados
|
||||
required: true
|
||||
type: text
|
||||
@@ -0,0 +1,79 @@
|
||||
services:
|
||||
zipline-postgres:
|
||||
image: postgres:16-alpine@sha256:deb28ee471183cb0c303113dac9b2433c51eeeeb678def7af9a9ec5820367815
|
||||
container_name: ${CONTAINER_NAME}-postgres
|
||||
restart: unless-stopped
|
||||
user: "70:70"
|
||||
networks:
|
||||
- zipline-internal
|
||||
environment:
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
- POSTGRES_USER=${POSTGRES_USER}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- "${APP_DATA_DIR}/postgres:/var/lib/postgresql/data"
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp:mode=1777,size=64m
|
||||
- /var/run/postgresql:uid=70,gid=70,mode=0755,size=16m
|
||||
cap_drop:
|
||||
- ALL
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 20s
|
||||
labels:
|
||||
createdBy: "Apps"
|
||||
|
||||
zipline:
|
||||
image: ghcr.io/diced/zipline:4.8.1@sha256:c6ec6d72ff3d2d96cafaf673d64b17e709d0abdae20db218bd13a29348fb212f
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: unless-stopped
|
||||
user: "1000:1000"
|
||||
depends_on:
|
||||
zipline-postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- zipline-internal
|
||||
- 1panel-network
|
||||
ports:
|
||||
- "${PANEL_APP_BIND_ADDRESS}:${PANEL_APP_PORT_HTTP}:3000"
|
||||
environment:
|
||||
- CORE_HOSTNAME=0.0.0.0
|
||||
- CORE_PORT=3000
|
||||
- CORE_SECRET=${CORE_SECRET}
|
||||
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@zipline-postgres:5432/${POSTGRES_DB}
|
||||
- DATASOURCE_TYPE=local
|
||||
- DATASOURCE_LOCAL_DIRECTORY=/zipline/uploads
|
||||
- CORE_TEMP_DIRECTORY=/tmp/zipline
|
||||
- FILES_MAX_FILE_SIZE=${FILES_MAX_FILE_SIZE}
|
||||
- FEATURES_HEALTHCHECK=true
|
||||
volumes:
|
||||
- "${APP_DATA_DIR}/uploads:/zipline/uploads"
|
||||
- "${APP_DATA_DIR}/public:/zipline/public"
|
||||
- "${APP_DATA_DIR}/themes:/zipline/themes"
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp:mode=1777,size=256m
|
||||
cap_drop:
|
||||
- ALL
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api/healthcheck"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 8
|
||||
start_period: 60s
|
||||
labels:
|
||||
createdBy: "Apps"
|
||||
|
||||
networks:
|
||||
zipline-internal:
|
||||
internal: true
|
||||
1panel-network:
|
||||
external: true
|
||||
@@ -0,0 +1,290 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ZIPLINE_STORED_POSTGRES_PASSWORD=""
|
||||
ZIPLINE_STORED_CORE_SECRET=""
|
||||
ZIPLINE_SNAPSHOT_POSTGRES_PASSWORD=""
|
||||
ZIPLINE_SNAPSHOT_CORE_SECRET=""
|
||||
|
||||
zipline_fail() {
|
||||
printf '%s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
zipline_read_env_value() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
local value
|
||||
[[ -f "$file" && ! -L "$file" ]] || return 1
|
||||
value="$(awk -v key="$key" '
|
||||
index($0, key "=") == 1 {
|
||||
count++
|
||||
value = substr($0, length(key) + 2)
|
||||
}
|
||||
END {
|
||||
if (count != 1) exit 1
|
||||
print value
|
||||
}
|
||||
' "$file")" || return 1
|
||||
case "$value" in
|
||||
\"*\") value="${value#\"}"; value="${value%\"}" ;;
|
||||
\'*\') value="${value#\'}"; value="${value%\'}" ;;
|
||||
esac
|
||||
printf '%s\n' "$value"
|
||||
}
|
||||
|
||||
zipline_resolve_data_dir() {
|
||||
local root_dir="$1"
|
||||
local raw="$2"
|
||||
local clean current resolved part
|
||||
local -a parts=()
|
||||
[[ -n "$raw" && "$raw" != /* ]] || zipline_fail "APP_DATA_DIR must be a non-empty relative path"
|
||||
[[ ! "$raw" =~ [[:cntrl:]] ]] || zipline_fail "APP_DATA_DIR contains control characters"
|
||||
case "$raw" in
|
||||
*\\* | *:* | *'$'* | *'#'* | *'"'* | *"'"*)
|
||||
zipline_fail "APP_DATA_DIR contains unsupported characters"
|
||||
;;
|
||||
esac
|
||||
clean="${raw#./}"
|
||||
[[ -n "$clean" ]] || zipline_fail "APP_DATA_DIR must not resolve to the version root"
|
||||
IFS=/ read -r -a parts <<< "$clean"
|
||||
current="$root_dir"
|
||||
for part in "${parts[@]}"; do
|
||||
[[ -n "$part" && "$part" != . && "$part" != .. ]] || zipline_fail "APP_DATA_DIR contains traversal"
|
||||
current="$current/$part"
|
||||
[[ ! -L "$current" ]] || zipline_fail "APP_DATA_DIR must not contain symbolic-link components"
|
||||
done
|
||||
resolved="$(realpath -m -- "$root_dir/$clean")" || zipline_fail "APP_DATA_DIR could not be resolved"
|
||||
case "$resolved" in
|
||||
"$root_dir"/*) ;;
|
||||
*) zipline_fail "APP_DATA_DIR must stay inside the application version directory" ;;
|
||||
esac
|
||||
printf '%s\n' "$resolved"
|
||||
}
|
||||
|
||||
zipline_validate_postgres_password() {
|
||||
[[ "$1" =~ ^[A-Za-z0-9]{32,128}$ ]]
|
||||
}
|
||||
|
||||
zipline_validate_core_secret() {
|
||||
[[ "$1" =~ ^[A-Fa-f0-9]{64,128}$ ]]
|
||||
}
|
||||
|
||||
zipline_generate_postgres_password() {
|
||||
local material
|
||||
material="$(openssl rand -base64 96 | tr -dc A-Za-z0-9)"
|
||||
[[ ${#material} -ge 48 ]] || zipline_fail "unable to generate sufficient database password material"
|
||||
printf '%s\n' "${material:0:48}"
|
||||
}
|
||||
|
||||
zipline_write_env_credentials() {
|
||||
local env_file="$1"
|
||||
local postgres_password="$2"
|
||||
local core_secret="$3"
|
||||
local temp_file
|
||||
temp_file="$(mktemp "${env_file}.zipline-tmp.XXXXXX")" || zipline_fail "unable to stage Zipline environment update"
|
||||
if ! ZIPLINE_DB_PASSWORD="$postgres_password" ZIPLINE_CORE_SECRET="$core_secret" awk '
|
||||
BEGIN {
|
||||
db_password = ENVIRON["ZIPLINE_DB_PASSWORD"]
|
||||
core_secret = ENVIRON["ZIPLINE_CORE_SECRET"]
|
||||
}
|
||||
/^POSTGRES_PASSWORD=/ {
|
||||
if (!db_written++) print "POSTGRES_PASSWORD=" db_password
|
||||
next
|
||||
}
|
||||
/^CORE_SECRET=/ {
|
||||
if (!core_written++) print "CORE_SECRET=" core_secret
|
||||
next
|
||||
}
|
||||
{ print }
|
||||
END {
|
||||
if (!db_written) print "POSTGRES_PASSWORD=" db_password
|
||||
if (!core_written) print "CORE_SECRET=" core_secret
|
||||
}
|
||||
' "$env_file" > "$temp_file"; then
|
||||
rm -f -- "$temp_file"
|
||||
zipline_fail "unable to render Zipline environment update"
|
||||
fi
|
||||
chmod 600 "$temp_file"
|
||||
mv -f -- "$temp_file" "$env_file"
|
||||
chmod 600 "$env_file"
|
||||
}
|
||||
|
||||
zipline_write_secret_state() {
|
||||
local data_dir="$1"
|
||||
local postgres_password="$2"
|
||||
local core_secret="$3"
|
||||
local secret_file="$data_dir/.zipline-secrets"
|
||||
local temp_file
|
||||
[[ -d "$data_dir" && ! -L "$data_dir" ]] || zipline_fail "Zipline data directory is unavailable"
|
||||
[[ ! -L "$secret_file" ]] || zipline_fail "Zipline secret state must not be a symbolic link"
|
||||
temp_file="$(mktemp "${secret_file}.tmp.XXXXXX")" || zipline_fail "unable to stage Zipline secret state"
|
||||
if ! printf 'POSTGRES_PASSWORD=%s\nCORE_SECRET=%s\n' "$postgres_password" "$core_secret" > "$temp_file"; then
|
||||
rm -f -- "$temp_file"
|
||||
zipline_fail "unable to write Zipline secret state"
|
||||
fi
|
||||
chmod 600 "$temp_file"
|
||||
chown 0:0 -- "$temp_file"
|
||||
mv -f -- "$temp_file" "$secret_file"
|
||||
chmod 600 "$secret_file"
|
||||
chown 0:0 -- "$secret_file"
|
||||
}
|
||||
|
||||
zipline_load_secret_state() {
|
||||
local data_dir="$1"
|
||||
local secret_file="$data_dir/.zipline-secrets"
|
||||
[[ -e "$secret_file" || -L "$secret_file" ]] || return 1
|
||||
[[ -f "$secret_file" && ! -L "$secret_file" ]] || zipline_fail "Zipline secret state is not a regular file"
|
||||
ZIPLINE_STORED_POSTGRES_PASSWORD="$(zipline_read_env_value "$secret_file" POSTGRES_PASSWORD)" ||
|
||||
zipline_fail "Zipline secret state is incomplete"
|
||||
ZIPLINE_STORED_CORE_SECRET="$(zipline_read_env_value "$secret_file" CORE_SECRET)" ||
|
||||
zipline_fail "Zipline secret state is incomplete"
|
||||
zipline_validate_postgres_password "$ZIPLINE_STORED_POSTGRES_PASSWORD" ||
|
||||
zipline_fail "Zipline secret state has an invalid database password"
|
||||
zipline_validate_core_secret "$ZIPLINE_STORED_CORE_SECRET" ||
|
||||
zipline_fail "Zipline secret state has an invalid session secret"
|
||||
chmod 600 "$secret_file"
|
||||
chown 0:0 -- "$secret_file"
|
||||
}
|
||||
|
||||
zipline_init_credentials() {
|
||||
local env_file="$1"
|
||||
local data_dir="$2"
|
||||
local postgres_password core_secret stored
|
||||
local postgres_default=false core_default=false
|
||||
[[ -f "$env_file" && ! -L "$env_file" ]] || zipline_fail "Zipline .env file is unavailable"
|
||||
postgres_password="$(zipline_read_env_value "$env_file" POSTGRES_PASSWORD)" ||
|
||||
zipline_fail "POSTGRES_PASSWORD is missing from Zipline .env"
|
||||
core_secret="$(zipline_read_env_value "$env_file" CORE_SECRET)" ||
|
||||
zipline_fail "CORE_SECRET is missing from Zipline .env"
|
||||
[[ -n "$postgres_password" && "$postgres_password" != generate ]] || postgres_default=true
|
||||
[[ -n "$core_secret" && "$core_secret" != generate ]] || core_default=true
|
||||
|
||||
if zipline_load_secret_state "$data_dir"; then
|
||||
if [[ "$postgres_default" == true ]]; then
|
||||
postgres_password="$ZIPLINE_STORED_POSTGRES_PASSWORD"
|
||||
elif [[ "$postgres_password" != "$ZIPLINE_STORED_POSTGRES_PASSWORD" ]]; then
|
||||
zipline_fail "POSTGRES_PASSWORD cannot change while Zipline data is retained"
|
||||
fi
|
||||
if [[ "$core_default" == true ]]; then
|
||||
core_secret="$ZIPLINE_STORED_CORE_SECRET"
|
||||
elif [[ "$core_secret" != "$ZIPLINE_STORED_CORE_SECRET" ]]; then
|
||||
zipline_fail "CORE_SECRET cannot change while Zipline data is retained"
|
||||
fi
|
||||
else
|
||||
if [[ -f "$data_dir/postgres/PG_VERSION" && ( "$postgres_default" == true || "$core_default" == true ) ]]; then
|
||||
zipline_fail "existing PostgreSQL data has no Zipline secret state; supply its original credentials to preserve it"
|
||||
fi
|
||||
if [[ "$postgres_default" == true ]]; then
|
||||
postgres_password="$(zipline_generate_postgres_password)"
|
||||
fi
|
||||
if [[ "$core_default" == true ]]; then
|
||||
core_secret="$(openssl rand -hex 32)"
|
||||
fi
|
||||
fi
|
||||
|
||||
zipline_validate_postgres_password "$postgres_password" ||
|
||||
zipline_fail "POSTGRES_PASSWORD must contain 32 to 128 alphanumeric characters"
|
||||
zipline_validate_core_secret "$core_secret" ||
|
||||
zipline_fail "CORE_SECRET must contain 64 to 128 hexadecimal characters"
|
||||
zipline_write_env_credentials "$env_file" "$postgres_password" "$core_secret"
|
||||
zipline_write_secret_state "$data_dir" "$postgres_password" "$core_secret"
|
||||
}
|
||||
|
||||
zipline_find_upgrade_snapshot() {
|
||||
local root_dir="$1"
|
||||
local env_file="$2"
|
||||
local current_name="$3"
|
||||
local current_data_dir="$4"
|
||||
local current_db="$5"
|
||||
local current_user="$6"
|
||||
local temp_root snapshot old_env old_compose old_name old_data old_db old_user
|
||||
local snapshot_time env_time best_time=-1 tied=false snapshot_uid snapshot_mode old_env_uid old_env_mode
|
||||
local best_snapshot=""
|
||||
local -a candidates=()
|
||||
|
||||
temp_root="$(realpath -e -- "${TMPDIR:-/tmp}")" || zipline_fail "1Panel upgrade snapshot directory is unavailable"
|
||||
[[ -d "$temp_root" ]] || zipline_fail "1Panel upgrade snapshot directory is unavailable"
|
||||
env_time="$(stat -c '%Y' "$env_file")" || zipline_fail "Zipline .env timestamp is unavailable"
|
||||
shopt -s nullglob
|
||||
candidates=("$temp_root"/1panel-app-upgrade-*)
|
||||
shopt -u nullglob
|
||||
for snapshot in "${candidates[@]}"; do
|
||||
[[ -d "$snapshot" && ! -L "$snapshot" ]] || continue
|
||||
snapshot_uid="$(stat -c '%u' "$snapshot")" || continue
|
||||
snapshot_mode="$(stat -c '%a' "$snapshot")" || continue
|
||||
[[ "$snapshot_uid" == 0 ]] || continue
|
||||
(( (8#$snapshot_mode & 077) == 0 )) || continue
|
||||
old_env="$snapshot/.env"
|
||||
old_compose="$snapshot/docker-compose.yml"
|
||||
[[ -f "$old_env" && ! -L "$old_env" && -f "$old_compose" && ! -L "$old_compose" ]] || continue
|
||||
old_env_uid="$(stat -c '%u' "$old_env")" || continue
|
||||
old_env_mode="$(stat -c '%a' "$old_env")" || continue
|
||||
[[ "$old_env_uid" == 0 ]] || continue
|
||||
(( (8#$old_env_mode & 077) == 0 )) || continue
|
||||
grep -Eq 'image:[[:space:]]*"?ghcr\.io/diced/zipline:4\.(6\.5|7\.0|8\.0)@sha256:[[:xdigit:]]{64}"?[[:space:]]*$' "$old_compose" || continue
|
||||
old_name="$(zipline_read_env_value "$old_env" CONTAINER_NAME)" || continue
|
||||
[[ "$old_name" == "$current_name" ]] || continue
|
||||
old_data="$(zipline_read_env_value "$old_env" APP_DATA_DIR)" || zipline_fail "matching 1Panel snapshot lacks APP_DATA_DIR"
|
||||
old_db="$(zipline_read_env_value "$old_env" POSTGRES_DB)" || zipline_fail "matching 1Panel snapshot lacks POSTGRES_DB"
|
||||
old_user="$(zipline_read_env_value "$old_env" POSTGRES_USER)" || zipline_fail "matching 1Panel snapshot lacks POSTGRES_USER"
|
||||
[[ "$old_data" == "$current_data_dir" && "$old_db" == "$current_db" && "$old_user" == "$current_user" ]] ||
|
||||
zipline_fail "matching 1Panel snapshot does not preserve the configured data path and database identity"
|
||||
ZIPLINE_SNAPSHOT_POSTGRES_PASSWORD="$(zipline_read_env_value "$old_env" POSTGRES_PASSWORD)" ||
|
||||
zipline_fail "matching 1Panel snapshot lacks its database password"
|
||||
ZIPLINE_SNAPSHOT_CORE_SECRET="$(zipline_read_env_value "$old_env" CORE_SECRET)" ||
|
||||
zipline_fail "matching 1Panel snapshot lacks its session secret"
|
||||
zipline_validate_postgres_password "$ZIPLINE_SNAPSHOT_POSTGRES_PASSWORD" ||
|
||||
zipline_fail "matching 1Panel snapshot has an invalid database password"
|
||||
zipline_validate_core_secret "$ZIPLINE_SNAPSHOT_CORE_SECRET" ||
|
||||
zipline_fail "matching 1Panel snapshot has an invalid session secret"
|
||||
snapshot_time="$(stat -c '%Y' "$snapshot")" || zipline_fail "1Panel upgrade snapshot timestamp is unavailable"
|
||||
if (( snapshot_time > best_time )); then
|
||||
best_time="$snapshot_time"
|
||||
best_snapshot="$snapshot"
|
||||
tied=false
|
||||
elif (( snapshot_time == best_time )); then
|
||||
tied=true
|
||||
fi
|
||||
done
|
||||
[[ -n "$best_snapshot" ]] || zipline_fail "could not find this Zipline install's 1Panel upgrade snapshot"
|
||||
[[ "$tied" == false ]] || zipline_fail "multiple matching 1Panel upgrade snapshots are ambiguous"
|
||||
(( best_time <= env_time && env_time - best_time <= 600 )) ||
|
||||
zipline_fail "matching 1Panel upgrade snapshot is stale"
|
||||
}
|
||||
|
||||
zipline_restore_upgrade_credentials() {
|
||||
local root_dir="$1"
|
||||
local env_file="$2"
|
||||
local raw_data_dir data_dir current_name current_db current_user
|
||||
local postgres_password core_secret current_password current_core_secret
|
||||
[[ -f "$env_file" && ! -L "$env_file" ]] || zipline_fail "Zipline .env file is unavailable"
|
||||
current_name="$(zipline_read_env_value "$env_file" CONTAINER_NAME)" || zipline_fail "CONTAINER_NAME is missing from Zipline .env"
|
||||
[[ "$current_name" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]*$ ]] || zipline_fail "CONTAINER_NAME is invalid"
|
||||
raw_data_dir="$(zipline_read_env_value "$env_file" APP_DATA_DIR)" || zipline_fail "APP_DATA_DIR is missing from Zipline .env"
|
||||
data_dir="$(zipline_resolve_data_dir "$root_dir" "$raw_data_dir")"
|
||||
[[ -d "$data_dir" && ! -L "$data_dir" ]] || zipline_fail "configured Zipline data directory is missing"
|
||||
current_db="$(zipline_read_env_value "$env_file" POSTGRES_DB)" || zipline_fail "POSTGRES_DB is missing from Zipline .env"
|
||||
current_user="$(zipline_read_env_value "$env_file" POSTGRES_USER)" || zipline_fail "POSTGRES_USER is missing from Zipline .env"
|
||||
current_password="$(zipline_read_env_value "$env_file" POSTGRES_PASSWORD)" || zipline_fail "POSTGRES_PASSWORD is missing from Zipline .env"
|
||||
current_core_secret="$(zipline_read_env_value "$env_file" CORE_SECRET)" || zipline_fail "CORE_SECRET is missing from Zipline .env"
|
||||
|
||||
zipline_find_upgrade_snapshot "$root_dir" "$env_file" "$current_name" "$raw_data_dir" "$current_db" "$current_user"
|
||||
postgres_password="$ZIPLINE_SNAPSHOT_POSTGRES_PASSWORD"
|
||||
core_secret="$ZIPLINE_SNAPSHOT_CORE_SECRET"
|
||||
if zipline_load_secret_state "$data_dir"; then
|
||||
[[ "$ZIPLINE_STORED_POSTGRES_PASSWORD" == "$postgres_password" && "$ZIPLINE_STORED_CORE_SECRET" == "$core_secret" ]] ||
|
||||
zipline_fail "Zipline secret state does not match the 1Panel upgrade snapshot"
|
||||
fi
|
||||
if [[ -n "$current_password" && "$current_password" != generate && "$current_password" != "$postgres_password" ]]; then
|
||||
zipline_fail "POSTGRES_PASSWORD changed during upgrade; refusing to alter the existing database credential"
|
||||
fi
|
||||
if [[ -n "$current_core_secret" && "$current_core_secret" != generate && "$current_core_secret" != "$core_secret" ]]; then
|
||||
zipline_fail "CORE_SECRET changed during upgrade; refusing to rotate the existing session secret"
|
||||
fi
|
||||
zipline_validate_postgres_password "$postgres_password" || zipline_fail "saved database password is invalid"
|
||||
zipline_validate_core_secret "$core_secret" || zipline_fail "saved session secret is invalid"
|
||||
zipline_write_env_credentials "$env_file" "$postgres_password" "$core_secret"
|
||||
zipline_write_secret_state "$data_dir" "$postgres_password" "$core_secret"
|
||||
printf '%s\n' "Zipline secrets were restored from the matching 1Panel upgrade snapshot."
|
||||
}
|
||||
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
||||
ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}"
|
||||
|
||||
fail() {
|
||||
printf '%s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
read_env_value() {
|
||||
local key="$1"
|
||||
local value
|
||||
value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
|
||||
case "$value" in
|
||||
\"*\") value="${value#\"}"; value="${value%\"}" ;;
|
||||
\'*\') value="${value#\'}"; value="${value%\'}" ;;
|
||||
esac
|
||||
printf '%s\n' "$value"
|
||||
}
|
||||
|
||||
validate_ipv4() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
local octet
|
||||
local -a octets
|
||||
[[ "$value" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]] || fail "$key must be an IPv4 address"
|
||||
IFS=. read -r -a octets <<< "$value"
|
||||
for octet in "${octets[@]}"; do
|
||||
((10#$octet <= 255)) || fail "$key contains an invalid IPv4 octet"
|
||||
done
|
||||
}
|
||||
|
||||
validate_port() {
|
||||
local value="$1"
|
||||
[[ "$value" =~ ^[0-9]+$ ]] || fail "PANEL_APP_PORT_HTTP must be an integer"
|
||||
((10#$value >= 1 && 10#$value <= 65535)) || fail "PANEL_APP_PORT_HTTP must be between 1 and 65535"
|
||||
}
|
||||
|
||||
[[ -f "$ENV_FILE" ]] || fail "$ENV_FILE not found"
|
||||
[[ ! -L "$ENV_FILE" ]] || fail "$ENV_FILE must not be a symbolic link"
|
||||
[[ "$(id -u)" -eq 0 ]] || fail "Zipline init must run as root"
|
||||
command -v openssl >/dev/null 2>&1 || fail "openssl is required to generate credentials"
|
||||
source "${ROOT_DIR}/scripts/credentials.sh"
|
||||
|
||||
validate_ipv4 PANEL_APP_BIND_ADDRESS "$(read_env_value PANEL_APP_BIND_ADDRESS)"
|
||||
validate_port "$(read_env_value PANEL_APP_PORT_HTTP)"
|
||||
|
||||
postgres_db="$(read_env_value POSTGRES_DB)"
|
||||
postgres_user="$(read_env_value POSTGRES_USER)"
|
||||
[[ "$postgres_db" =~ ^[A-Za-z_][A-Za-z0-9_]{0,62}$ ]] || fail "POSTGRES_DB is invalid"
|
||||
[[ "$postgres_user" =~ ^[A-Za-z_][A-Za-z0-9_]{0,62}$ ]] || fail "POSTGRES_USER is invalid"
|
||||
|
||||
max_file_size="$(read_env_value FILES_MAX_FILE_SIZE)"
|
||||
[[ "$max_file_size" =~ ^[1-9][0-9]*(b|kb|mb|gb|tb)$ ]] ||
|
||||
fail "FILES_MAX_FILE_SIZE must be a positive byte quantity such as 100mb"
|
||||
|
||||
data_raw="$(read_env_value APP_DATA_DIR)"
|
||||
[[ -n "$data_raw" && "$data_raw" != /* ]] || fail "APP_DATA_DIR must be a non-empty relative path"
|
||||
case "$data_raw" in
|
||||
*$'\n'* | *$'\r'* | *\\* | *:* | *'$'* | *'#'* | *'"'* | *"'"*)
|
||||
fail "APP_DATA_DIR contains unsupported characters"
|
||||
;;
|
||||
esac
|
||||
|
||||
relative_data="${data_raw#./}"
|
||||
[[ -n "$relative_data" ]] || fail "APP_DATA_DIR must not resolve to the version root"
|
||||
current="$ROOT_DIR"
|
||||
IFS=/ read -r -a components <<< "$relative_data"
|
||||
for component in "${components[@]}"; do
|
||||
[[ -n "$component" && "$component" != . && "$component" != .. ]] || fail "APP_DATA_DIR contains traversal"
|
||||
current="$current/$component"
|
||||
[[ ! -L "$current" ]] || fail "APP_DATA_DIR must not contain symbolic-link components"
|
||||
done
|
||||
|
||||
data_dir="$(realpath -m -- "$ROOT_DIR/$relative_data")"
|
||||
case "$data_dir" in
|
||||
"$ROOT_DIR"/*) ;;
|
||||
*) fail "APP_DATA_DIR must stay inside the application version directory" ;;
|
||||
esac
|
||||
|
||||
install -d -m 0700 -- "$data_dir/postgres"
|
||||
install -d -m 0750 -- "$data_dir/uploads" "$data_dir/public" "$data_dir/themes"
|
||||
resolved_data="$(realpath -e -- "$data_dir")"
|
||||
case "$resolved_data" in
|
||||
"$ROOT_DIR"/*) ;;
|
||||
*) fail "APP_DATA_DIR resolves outside the application version directory" ;;
|
||||
esac
|
||||
chown -R 70:70 -- "$resolved_data/postgres"
|
||||
chown -R 1000:1000 -- "$resolved_data/uploads" "$resolved_data/public" "$resolved_data/themes"
|
||||
chmod 0700 -- "$resolved_data/postgres"
|
||||
|
||||
zipline_init_credentials "$ENV_FILE" "$resolved_data"
|
||||
chmod 600 "$ENV_FILE"
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# 1Panel removes the installation directory after this hook, including relative APP_DATA_DIR contents.
|
||||
# Back up required data outside the application directory before uninstalling.
|
||||
exit 0
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
||||
ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}"
|
||||
source "${ROOT_DIR}/scripts/credentials.sh"
|
||||
|
||||
zipline_restore_upgrade_credentials "$ROOT_DIR" "$ENV_FILE"
|
||||
|
||||
command -v docker >/dev/null 2>&1 || zipline_fail "Docker is required to verify the Zipline migration before upgrading"
|
||||
command -v timeout >/dev/null 2>&1 || zipline_fail "timeout is required to verify the Zipline migration before upgrading"
|
||||
|
||||
compose=(docker compose --project-directory "$ROOT_DIR" -f "$ROOT_DIR/docker-compose.yml")
|
||||
"${compose[@]}" up -d zipline-postgres
|
||||
|
||||
postgres_db="$(zipline_read_env_value "$ENV_FILE" POSTGRES_DB)" ||
|
||||
zipline_fail "POSTGRES_DB is missing from Zipline .env"
|
||||
postgres_user="$(zipline_read_env_value "$ENV_FILE" POSTGRES_USER)" ||
|
||||
zipline_fail "POSTGRES_USER is missing from Zipline .env"
|
||||
|
||||
ready=false
|
||||
for attempt in {1..60}; do
|
||||
if "${compose[@]}" exec -T zipline-postgres pg_isready -q -U "$postgres_user" -d "$postgres_db"; then
|
||||
ready=true
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
[[ "$ready" == true ]] || zipline_fail "Zipline PostgreSQL did not become ready for the staged upgrade"
|
||||
|
||||
drizzle_table_exists="$(timeout 15 "${compose[@]}" exec -T zipline-postgres \
|
||||
sh -ec 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Atq -c "$1"' sh \
|
||||
"SELECT to_regclass('drizzle.__drizzle_migrations') IS NOT NULL")" ||
|
||||
zipline_fail "Zipline migration history could not be verified; keep the existing version and repair the database before upgrading"
|
||||
|
||||
migration_state="prisma"
|
||||
if [[ "$drizzle_table_exists" == t ]]; then
|
||||
drizzle_history="$(timeout 15 "${compose[@]}" exec -T zipline-postgres \
|
||||
sh -ec 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Atq -c "$1"' sh \
|
||||
"SELECT EXISTS (SELECT 1 FROM drizzle.__drizzle_migrations)")" ||
|
||||
zipline_fail "Zipline Drizzle migration history could not be verified; keep the existing version and repair the database before upgrading"
|
||||
if [[ "$drizzle_history" == t ]]; then
|
||||
migration_state="drizzle"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$migration_state" != drizzle ]]; then
|
||||
prisma_migration_state="$(timeout 15 "${compose[@]}" exec -T zipline-postgres sh -ec 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Atq -c "SELECT CASE WHEN count(*) = 1 AND bool_and(finished_at IS NOT NULL AND rolled_back_at IS NULL AND applied_steps_count >= 1) THEN '\''ok'\'' ELSE '\''bad'\'' END FROM public._prisma_migrations WHERE migration_name = '\''20260806081144_remove_version_api'\'' AND checksum = '\''08368d44344f934f07757dc014bd3a2022b14a8b377e1f8f5fb2d4836c3dc1ce'\'';"')" ||
|
||||
zipline_fail "Zipline 4.7 migration history could not be verified; keep the existing version and repair the database before upgrading"
|
||||
[[ "$prisma_migration_state" == ok ]] ||
|
||||
zipline_fail "Zipline 4.7 migration is missing or incomplete; keep the existing version and allow its migration to finish before upgrading"
|
||||
migration_state="prisma"
|
||||
fi
|
||||
|
||||
if [[ "$migration_state" == drizzle ]]; then
|
||||
printf '%s\n' "Zipline Drizzle migration history verified; proceeding with the 4.8 upgrade."
|
||||
else
|
||||
printf '%s\n' "Zipline 4.7 migration verified; proceeding with the 4.8 upgrade."
|
||||
fi
|
||||
Reference in New Issue
Block a user