feat(docker): guide clone installation and validate paired update artifacts
CI / check (push) Failing after 1m18s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

This commit is contained in:
Simo committed 2026-09-13 17:57:14 +02:00
1 parent a4266f297c
commit 8f55ff2d17
39 files changed
+473 -73

No files matched your search

+2
View File
@@ -27,6 +27,8 @@ RUN --mount=type=cache,target=/pnpm \
RUN --mount=type=cache,target=/pnpm \
pnpm install --frozen-lockfile --ignore-scripts --offline
COPY . .
ARG NEXT_DEPLOYMENT_ID="unknown"
LABEL org.opencontainers.image.revision="$NEXT_DEPLOYMENT_ID"
FROM migrations AS builder
ARG NEXT_DEPLOYMENT_ID="unknown"
ENV NEXT_DEPLOYMENT_ID="$NEXT_DEPLOYMENT_ID"
+2 -2
View File
@@ -3,7 +3,7 @@ set -Eeuo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
case "${1:-help}" in
install) shift; exec bash "$DIR/scripts/docker-install.sh" "$@" ;;
update) shift; [[ $# = 0 ]] || { echo "Usage: bash cms update" >&2; exit 1; }; exec bash "$DIR/scripts/docker-update.sh" ;;
help|--help|-h) printf '%s\n' 'bash cms install Configure and install on a Linux Docker host' 'bash cms update Update using the saved installation settings' ;;
update) shift; exec bash "$DIR/scripts/docker-update.sh" "$@" ;;
help|--help|-h) printf '%s\n' 'bash cms install Configure and install on a Linux Docker host' 'bash cms update Update using saved settings; --skip-pull uses checked-out release' ;;
*) echo "Unknown command. Use: bash cms install | update" >&2; exit 1 ;;
esac
+51
View File
@@ -0,0 +1,51 @@
# Install a clone and choose an update
## Requirements and first installation
Use a Linux host with Docker Engine, the Compose plugin, Git and `flock`. This Compose file uses host networking and port 3002. Provide an existing compatible Habbo MariaDB database, reachable Redis, persistent storage and an HTTP(S) reverse proxy. The installer does not provision the emulator, a database, TLS, or a registry account.
Clone this repository from the Gitea URL supplied by your administrator, enter the clone, then run:
```sh
bash cms install
```
The wizard asks for the public URL and delivery mode. **Source** (the default for a new installation) builds the locked source locally and only needs repository access plus access to public build dependencies. **Prebuilt** downloads the application and migrations from the repository's `docker-image.txt`; a private package needs a separate registry login with package-read permission. Git access alone may not grant package access. Existing saved mode and `.env` are preserved. `bash cms install --configure-only` saves configuration without starting containers.
Credentials are entered on the host, never in the dashboard. Do not paste `.env` into support tickets. Installation prepares `public/nitro-assets`, `public/swf`, `storage`, and `/var/www/Gamedata` for UID/GID 33 without recursively taking ownership of existing files. Existing nested assets may still need operator permission repair. The updater tests access to those mounts as the candidate container user before migrations; this checks directory access, not every nested file or filesystem capacity.
After startup, visit `/admin/devops/installation` with the appropriate permission. Verify database, Redis, storage and migration status. Worker heartbeat is a separate runtime signal: a healthy HTTP endpoint does not prove an import worker is processing jobs. Check the worker status and investigate a missing/stale heartbeat before scheduling imports. The dashboard is read-only and cannot start Docker, upgrade the host or grant registry access.
## Routine and selected-release updates
```sh
bash cms update
```
This requires a clean clone and fast-forwards its configured Git upstream, then builds/pulls artifacts for that exact commit. It validates the application and migration revision labels, validates runtime configuration and storage, runs migrations and verifies the recreated CMS locally and through the saved public URL.
To install a specific published version, fetch it and select its commit on the host first:
```sh
git fetch origin
git switch --detach <reviewed-commit-or-tag>
bash cms update --skip-pull
```
`--skip-pull` deliberately uses the checked-out commit, including detached HEAD. For routine updates again, switch back to your tracked deployment branch. The script does not invent version-to-schema compatibility or automatically change branches.
In prebuilt mode you can additionally require immutable artifacts from the configured repository:
```sh
bash cms update --skip-pull --app-digest sha256:<64-lowercase-hex> --migrations-digest sha256:<64-lowercase-hex>
```
Replace both placeholders with publisher-provided digests. Both are mandatory together. Revision labels must match the checked-out commit; a digest alone does not establish schema compatibility. Older migration images without a revision label must be republished from matching source, or the same checkout can be installed in source mode. No migration runs when the artifact or candidate validation fails.
## Compatibility and recovery
Before upgrading, read the selected release's migration changes and take a database backup with a tested restore procedure. Preserve `.env`, persistent assets and the previous release identifier. The current tooling does not provide a validated matrix of supported source/target database versions. Pinning an old commit is therefore not a supported database downgrade procedure.
On a failure after container replacement, the updater attempts to restore the previous image and checks it locally. **Image rollback does not reverse database migrations.** A migration may partially apply or make the old application incompatible, including when migration fails before container replacement. Recover the database only through the reviewed backup/restore procedure and coordinate downtime; do not assume restarting the old image recovers it. First installation has no prior image to restore. Host logs remain in `logs/docker-update.log` and may contain application/database diagnostics; restrict access.
Local Git Bash tests cover selection validation and mocked failure paths. They do not establish Linux container startup, runtime filesystem permissions, registry availability or real MariaDB upgrade compatibility.
+2 -1
View File
@@ -42,7 +42,8 @@ printf '%s\n' 'EpicNext-Cms installation' 'Requires an existing Habbo database a
read_value 'Public CMS URL (e.g. https://hotel.example)' "${CMS_PUBLIC_URL:-}"
public_url="${REPLY%/}"
http_url "$public_url" && [[ "$public_url" != *'?'* ]] || fail "Enter an HTTP(S) URL without credentials, query or fragment."
read_value 'Delivery method: prebuilt or source' "${CMS_INSTALL_MODE:-prebuilt}"
printf '%s\n' 'Source builds need repository access and public build dependencies. Prebuilt images additionally need registry package access (docker login on this host for private packages).'
read_value 'Delivery method: prebuilt or source' "${CMS_INSTALL_MODE:-source}"
mode="$REPLY"
[[ "$mode" = prebuilt || "$mode" = source ]] || fail "Choose prebuilt or source."
if [[ "$mode" = prebuilt ]]; then
+11 -13
View File
@@ -2,7 +2,7 @@
# ==============================================================================
# docker-preflight.sh — Verify a VPS is ready to run the Dockerized EpicNext-CMS.
#
# Lets any supplied .env drive the checks. Checks (all idempotent, none mutating):
# Does not execute dotenv. Endpoint probes use explicit environment overrides. Checks (all idempotent, none mutating):
# 1. Docker + compose available and usable.
# 2. Required runtime dirs exist (RW for UID 33 where the CMS writes).
# 3. Volume owners are UID/GID 33 (www-data) on the host.
@@ -73,17 +73,15 @@ for d in "${RW_DIRS[@]}"; do
continue
fi
if [ ! -d "$d" ]; then err "not a directory: $d"; continue; fi
# Test write as the target owner via a temp file drop (as root), then remove.
if [ "$(id -u)" -eq 0 ]; then
if touch "$d/.preflight-write-test" 2>/dev/null; then
rm -f "$d/.preflight-write-test"
ok "writable: $d"
else
err "not writable: $d (needs owner 33:33)"
[ "$FIX" -eq 1 ] && { chown -R 33:33 "$d" && say " chown -R 33:33 $d" || err " chown failed"; }
fi
# Check the actual runtime identity, never root's ability to write.
if [ "$(id -u)" -eq 33 ]; then
if [ -w "$d" ] && [ -r "$d" ]; then ok "runtime access: $d"; else err "runtime access denied: $d"; fi
elif [ "$(id -u)" -eq 0 ] && command -v setpriv >/dev/null 2>&1; then
if setpriv --reuid=33 --regid=33 --clear-groups sh -c 'test -r "$1" && test -w "$1"' sh "$d"; then
ok "runtime access as UID/GID 33: $d"
else err "runtime access denied for UID/GID 33: $d"; fi
else
if [ -w "$d" ]; then ok "writable: $d"; else err "not writable: $d"; fi
wrn "runtime access unverified: $d; updater checks candidate container access before migrations"
fi
done
@@ -102,8 +100,8 @@ done
doing "4. Configuration + required services (.env, host network)"
if [ -f "$ENV_FILE" ]; then
ok ".env present: $ENV_FILE"
### shellcheck disable=SC1090
set -a; . "$ENV_FILE"; set +a
say "Dotenv is not executed. Port checks below use explicit shell overrides/defaults, not DATABASE_URL or REDIS_URL."
say "The updater validates real candidate configuration and mounted storage before migrations."
else
err ".env missing: $ENV_FILE (copy your production env here)"
fi
+13
View File
@@ -0,0 +1,13 @@
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
const result = spawnSync(
process.execPath,
[
"--input-type=module",
"-e",
"import {validateRuntime} from './scripts/docker-start.mjs';try{validateRuntime({});process.exit(1)}catch(error){if(!error.message.startsWith('Invalid runtime configuration'))throw error}",
],
{ encoding: "utf8" },
);
assert.equal(result.status, 0, result.stderr);
+4 -1
View File
@@ -27,7 +27,10 @@ export function validateRuntime(settings) {
throw new Error(`Invalid runtime configuration: ${invalid.join(", ")}`);
}
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
if (
process.argv[1] &&
import.meta.url === pathToFileURL(process.argv[1]).href
) {
try {
validateRuntime(process.env);
const child = spawn(process.execPath, ["server.js"], { stdio: "inherit" });
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Parse before opening locks, logs or contacting Git/Docker.
parse_update_options() {
UPDATE_SKIP_PULL=0
UPDATE_APP_DIGEST=""
UPDATE_MIGRATIONS_DIGEST=""
while [[ $# -gt 0 ]]; do
case "$1" in
--skip-pull) UPDATE_SKIP_PULL=1; shift ;;
--app-digest|--migrations-digest)
[[ $# -ge 2 && "$2" =~ ^sha256:[0-9a-f]{64}$ ]] || { echo 'Expected a sha256 digest with 64 lowercase hex characters.' >&2; return 1; }
if [[ "$1" = --app-digest ]]; then UPDATE_APP_DIGEST="$2"; else UPDATE_MIGRATIONS_DIGEST="$2"; fi
shift 2 ;;
*) echo 'Usage: bash cms update [--skip-pull] [--app-digest sha256:HEX --migrations-digest sha256:HEX]' >&2; return 1 ;;
esac
done
[[ -z "$UPDATE_APP_DIGEST" && -z "$UPDATE_MIGRATIONS_DIGEST" || -n "$UPDATE_APP_DIGEST" && -n "$UPDATE_MIGRATIONS_DIGEST" ]] || { echo 'Supply both application and migrations digests.' >&2; return 1; }
}
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -Eeuo pipefail
source "$(dirname "$0")/docker-update-options.sh"
expect_failure() { if (parse_update_options "$@") >/dev/null 2>&1; then echo "unexpected accepted arguments: $*" >&2; exit 1; fi; }
parse_update_options
[[ "$UPDATE_SKIP_PULL" = 0 && -z "$UPDATE_APP_DIGEST" ]]
expect_failure --unknown
expect_failure --app-digest
expect_failure --skip-pull value
expect_failure --app-digest sha256:bad --migrations-digest sha256:bad
digest="sha256:$(printf '%064d' 1)"
expect_failure --app-digest "$digest"
expect_failure --migrations-digest "$digest"
parse_update_options --skip-pull --app-digest "$digest" --migrations-digest "$digest"
[[ "$UPDATE_SKIP_PULL" = 1 && "$UPDATE_APP_DIGEST" = "$digest" && "$UPDATE_MIGRATIONS_DIGEST" = "$digest" ]]
echo 'Docker update option tests passed'
+23 -10
View File
@@ -3,6 +3,8 @@
set -Eeuo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$DIR"
source "$DIR/scripts/docker-update-options.sh"
parse_update_options "$@" || exit 1
exec 9>"$DIR/.deploy.lock"
flock -w 1800 9
LOG_FILE="${LOG_FILE:-$DIR/logs/docker-update.log}"
@@ -61,17 +63,20 @@ if [ "$(docker inspect --format '{{.State.Running}}' epicnext-cms-app 2>/dev/nul
die "This host is managed by CI (epicnext-cms-app). Update through CI, not a second Compose deployment."
fi
[[ -z "$(git status --porcelain --untracked-files=normal)" ]] || die "Working tree is not clean. Commit or stash local work first."
git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' >/dev/null || die "Configure this branch's Git upstream before updating."
script_before="$(git hash-object scripts/docker-update.sh)"
git pull --ff-only >>"$LOG_FILE" 2>&1
if [ "$script_before" != "$(git hash-object scripts/docker-update.sh)" ]; then
log "Updater changed; restarting the newly pulled script."
exec 9>&-
exec bash "$DIR/scripts/docker-update.sh"
if [[ "$UPDATE_SKIP_PULL" = 0 ]]; then
git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' >/dev/null || die "Configure this branch's Git upstream before updating."
script_before="$(git hash-object scripts/docker-update.sh)"
git pull --ff-only >>"$LOG_FILE" 2>&1
if [ "$script_before" != "$(git hash-object scripts/docker-update.sh)" ]; then
log "Updater changed; restarting the newly pulled script."
exec 9>&-
exec bash "$DIR/scripts/docker-update.sh" "$@"
fi
fi
# Load after pulling so image location changes follow the repository.
source "$DIR/scripts/docker-config.sh"
load_docker_config "$DIR" || die "Invalid .docker-install: expected MODE=prebuilt or source and PUBLIC_URL=http(s)://your-host."
[[ -z "$UPDATE_APP_DIGEST" || -n "${CMS_IMAGE_REPOSITORY:-}" ]] || die "Digest selection requires prebuilt mode (registry access)."
export CMS_RELEASE="$(git rev-parse HEAD)"
[[ "$CMS_RELEASE" =~ ^[0-9a-f]{40}$ ]] || die "Invalid Git commit."
[[ -f .env ]] || die "Create .env before installing or updating."
@@ -92,11 +97,14 @@ migration_image="epicnext-cms-migrations:$CMS_RELEASE"
if [[ -n "${CMS_IMAGE_REPOSITORY:-}" ]]; then
[[ "$CMS_IMAGE_REPOSITORY" =~ ^[a-z0-9.-]+(:[0-9]+)?/[a-z0-9._/-]+$ ]] || die "Invalid CMS_IMAGE_REPOSITORY; use registry/owner/image without a tag."
log "Pulling prebuilt application and matching migrations for $CMS_RELEASE"
docker pull "$CMS_IMAGE_REPOSITORY:$CMS_RELEASE" >>"$LOG_FILE" 2>&1 || die "Application image unavailable. Publication for this commit may still be running; retry bash cms update after CI succeeds. For private packages, log in to the registry first."
app_reference="$CMS_IMAGE_REPOSITORY:$CMS_RELEASE"
[[ -z "$UPDATE_APP_DIGEST" ]] || app_reference="$CMS_IMAGE_REPOSITORY@$UPDATE_APP_DIGEST"
docker pull "$app_reference" >>"$LOG_FILE" 2>&1 || die "Application image unavailable. Publication for this commit may still be running; retry bash cms update after CI succeeds. For private packages, log in to the registry first."
remote_migration_image="$CMS_IMAGE_REPOSITORY:$CMS_RELEASE-migrations"
[[ -z "$UPDATE_MIGRATIONS_DIGEST" ]] || remote_migration_image="$CMS_IMAGE_REPOSITORY@$UPDATE_MIGRATIONS_DIGEST"
docker pull "$remote_migration_image" >>"$LOG_FILE" 2>&1 || die "Matching migrations image unavailable. Current CMS is unchanged; retry after publication succeeds."
docker tag "$CMS_IMAGE_REPOSITORY:$CMS_RELEASE" "epicnext-cms:$CMS_RELEASE"
docker tag "$CMS_IMAGE_REPOSITORY:$CMS_RELEASE-migrations" "$migration_image"
docker tag "$app_reference" "epicnext-cms:$CMS_RELEASE"
docker tag "$remote_migration_image" "$migration_image"
else
docker build --network=host --target migrations --build-arg NEXT_DEPLOYMENT_ID="$CMS_RELEASE" -t "$migration_image" . >>"$LOG_FILE" 2>&1
docker compose build --build-arg NEXT_DEPLOYMENT_ID="$CMS_RELEASE" cms >>"$LOG_FILE" 2>&1
@@ -104,6 +112,11 @@ fi
expected_image="$(docker image inspect --format '{{.Id}}' "epicnext-cms:$CMS_RELEASE")"
revision="$(docker image inspect --format '{{index .Config.Labels "org.opencontainers.image.revision"}}' "$expected_image")"
[[ "$revision" = "$CMS_RELEASE" ]] || die "Built image has revision $revision, expected $CMS_RELEASE."
migration_revision="$(docker image inspect --format '{{index .Config.Labels "org.opencontainers.image.revision"}}' "$migration_image")"
[[ "$migration_revision" = "$CMS_RELEASE" ]] || die "Migrations image has no matching release label. Rebuild/publish both artifacts from this checkout; the database was not changed."
# Compose uses the candidate image's USER and exact mounts/env without starting the server.
docker compose run --rm --no-deps --entrypoint node cms --input-type=module -e 'import {access,constants} from "node:fs/promises";import {validateRuntime} from "./docker-start.mjs";validateRuntime(process.env);for(const p of ["/app/storage","/app/public/nitro-assets","/app/public/swf","/var/www/Gamedata"]){try{await access(p,constants.R_OK|constants.W_OK|constants.X_OK)}catch{console.error("Runtime storage access denied: "+p);process.exit(1)}}' >>"$LOG_FILE" 2>&1 || die "Candidate configuration/storage validation failed; database unchanged. Check directory access for UID/GID 33."
log "Before migration: ensure a verified database backup is available. Image rollback does not undo database migrations."
migration_mounts=(--mount "type=bind,source=$DIR/.env,target=/app/.env,readonly")
if [[ -f "$DIR/.env.local" ]]; then migration_mounts+=(--mount "type=bind,source=$DIR/.env.local,target=/app/.env.local,readonly"); fi
docker run --rm --network host "${migration_mounts[@]}" --entrypoint pnpm "$migration_image" db:migrate >>"$LOG_FILE" 2>&1
@@ -21,6 +21,18 @@ export default async function InstallationPage() {
})}
</p>
<RefreshStatus label={t("recheck")} />
<section className="admin-card space-y-3">
<h2 className="font-semibold">{t("guideTitle")}</h2>
<p>{t("guideHost")}</p>
<code className="block break-all text-sm">bash cms install</code>
<p>{t("guideAccess")}</p>
<code className="block break-all text-sm">bash cms update</code>
<p>{t("guidePinned")}</p>
<p>{t("guideWorker")}</p>
<p className="text-sm text-[var(--admin-text-muted)]">
{t("guideRecovery")}
</p>
</section>
<div className="grid gap-3 md:grid-cols-2">
{result.rows.map((row) => (
<section key={row.key} className="admin-card space-y-2 min-w-0">
+48
View File
@@ -146,3 +146,51 @@ it("hands a completed installation to the existing updater", () => {
expect(result.output).toContain("Update invoked");
expect(result.profile).toContain("MODE=prebuilt");
});
it("defaults a new clone to source without requiring registry access", () => {
const result = configure(
"https://hotel.example\n\n",
"AUTH_SECRET=existing\n",
);
expect(result.status, result.output).toBe(0);
expect(result.profile).toContain("MODE=source");
});
it("keeps a saved prebuilt choice when the operator accepts defaults", () => {
const result = configure(
"\n\n",
"AUTH_SECRET=existing\n",
"MODE=prebuilt\nPUBLIC_URL=https://hotel.example\n",
);
expect(result.status, result.output).toBe(0);
expect(result.profile).toContain("MODE=prebuilt");
});
it("preflight treats dotenv as configuration data instead of executing host commands", () => {
const dir = mkdtempSync(join(tmpdir(), "cms-preflight-test-"));
try {
mkdirSync(join(dir, "scripts"));
copyFileSync(
resolve(root, "scripts/docker-preflight.sh"),
join(dir, "scripts/docker-preflight.sh"),
);
writeFileSync(join(dir, ".env"), "touch injected\n");
const result = spawnSync(bash, [join(dir, "scripts/docker-preflight.sh")], {
cwd: dir,
encoding: "utf8",
timeout: 15000,
env: {
...process.env,
ENV_FILE: join(dir, ".env"),
MYSQL_PORT: "1",
REDIS_PORT: "1",
CMS_PORT: "1",
BASH_ENV: resolve(root, "src/test/docker-install-harness.sh"),
},
});
if (result.error) throw result.error;
expect(existsSync(join(dir, "injected"))).toBe(false);
expect(result.stdout).toContain("Dotenv is not executed");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
+93 -21
View File
@@ -25,11 +25,15 @@ const bash =
.find((path) => existsSync(path)) ?? "bash")
: "bash";
const sha = "a".repeat(40);
function simulate(scenario: string) {
function simulate(scenario: string, args: string[] = []) {
const dir = mkdtempSync(join(tmpdir(), "cms-compose-test-"));
try {
mkdirSync(join(dir, "scripts"));
mkdirSync(join(dir, "logs"));
copyFileSync(
resolve(root, "scripts/docker-update-options.sh"),
join(dir, "scripts/docker-update-options.sh"),
);
copyFileSync(
resolve(root, "scripts/docker-config.sh"),
join(dir, "scripts/docker-config.sh"),
@@ -56,26 +60,30 @@ function simulate(scenario: string) {
join(dir, ".docker-install"),
`MODE=${scenario === "saved-source" ? "source" : "prebuilt"}\nPUBLIC_URL=https://saved.test\n`,
);
const result = spawnSync(bash, [join(dir, "scripts/docker-update.sh")], {
cwd: dir,
encoding: "utf8",
timeout: 25000,
env: {
...process.env,
BASH_ENV: resolve(root, "src/test/docker-update-harness.sh"),
TEST_DIR: dir.replaceAll("\\", "/"),
TEST_SHA: sha,
SCENARIO: scenario,
CMS_PUBLIC_URL: scenario.startsWith("saved-")
? undefined
: "https://example.test",
CMS_IMAGE_REPOSITORY: scenario.startsWith("saved-")
? undefined
: scenario.startsWith("registry")
? "registry.test/team/cms"
: "",
const result = spawnSync(
bash,
[join(dir, "scripts/docker-update.sh"), ...args],
{
cwd: dir,
encoding: "utf8",
timeout: 25000,
env: {
...process.env,
BASH_ENV: resolve(root, "src/test/docker-update-harness.sh"),
TEST_DIR: dir.replaceAll("\\", "/"),
TEST_SHA: sha,
SCENARIO: scenario,
CMS_PUBLIC_URL: scenario.startsWith("saved-")
? undefined
: "https://example.test",
CMS_IMAGE_REPOSITORY: scenario.startsWith("saved-")
? undefined
: scenario.startsWith("registry")
? "registry.test/team/cms"
: "",
},
},
});
);
if (result.error) throw result.error;
return {
status: result.status,
@@ -86,7 +94,12 @@ function simulate(scenario: string) {
: "",
};
} finally {
rmSync(dir, { recursive: true, force: true });
rmSync(dir, {
recursive: true,
force: true,
maxRetries: 5,
retryDelay: 100,
});
}
}
describe("Docker clone updates", () => {
@@ -212,3 +225,62 @@ it("keeps source builds available for a saved source installation", () => {
expect(r.calls).toContain("docker compose build");
expect(r.calls).not.toContain("docker pull");
});
it("checks candidate storage before any database migration", () => {
const r = simulate("storage-failure");
expect(r.status).not.toBe(0);
expect(r.calls).toContain(
"docker compose run --rm --no-deps --entrypoint node",
);
expect(r.calls).not.toContain("--entrypoint pnpm");
expect(r.restored).toBe(false);
});
it("rejects a migration artifact from another revision before database changes", () => {
const r = simulate("migration-revision-mismatch");
expect(r.status).not.toBe(0);
expect(r.calls).not.toContain("--entrypoint pnpm");
expect(r.output).toContain("no matching release label");
});
it("uses both immutable artifacts without pulling Git when a checked-out release is requested", () => {
const digest = `sha256:${"1".repeat(64)}`;
const migrations = `sha256:${"2".repeat(64)}`;
const r = simulate("registry", [
"--skip-pull",
"--app-digest",
digest,
"--migrations-digest",
migrations,
]);
expect(r.status, r.output).toBe(0);
expect(r.calls).not.toContain("git pull");
expect(r.calls).toContain(`docker pull registry.test/team/cms@${digest}`);
expect(r.calls).toContain(`docker pull registry.test/team/cms@${migrations}`);
});
it("rejects incomplete artifact selection before contacting Git or Docker", () => {
const r = simulate("registry", ["--app-digest", `sha256:${"1".repeat(64)}`]);
expect(r.status).not.toBe(0);
expect(r.calls).toBe("");
});
it("rejects a legacy migrations image without release metadata before database changes", () => {
const r = simulate("migration-revision-missing");
expect(r.status).not.toBe(0);
expect(r.calls).not.toContain("--entrypoint pnpm");
expect(r.calls).not.toContain("compose up");
expect(r.output).toContain("Rebuild/publish both artifacts");
});
it("requires prebuilt mode when selecting immutable artifacts", () => {
const digest = `sha256:${"1".repeat(64)}`;
const r = simulate("saved-source", [
"--app-digest",
digest,
"--migrations-digest",
digest,
]);
expect(r.status).not.toBe(0);
expect(r.output).toContain("Digest selection requires prebuilt mode");
expect(r.calls).not.toContain("docker pull");
expect(r.calls).not.toContain("--entrypoint pnpm");
expect(r.calls).not.toContain("compose up");
});
+7 -1
View File
@@ -377,7 +377,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4032,7 +4032,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4338,7 +4338,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"operations": {
"title": "Needs attention",
+7 -1
View File
@@ -4032,7 +4032,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -377,7 +377,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4032,7 +4032,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4307,7 +4307,13 @@
"migrationsHint": "Numero di migrazioni incluse nella versione e assenti dalla cronologia del database. Applicale attraverso il processo di rilascio.",
"workerHint": "Ultimo segnale del worker in Redis. Oltre due minuti richiede verifica; nessun segnale non permette di stabilire se il worker sia attivo.",
"rendererHint": "Il client usa l’indirizzo configurato oppure /nitro-client/ come percorso predefinito. Apri separatamente il gioco per controllare rendering e risorse.",
"registryHint": "Le credenziali del registro sono nella CI, non nel CMS. Controlla il lavoro di pubblicazione e il tag immutabile della versione in Gitea."
"registryHint": "Le credenziali del registro sono nella CI, non nel CMS. Controlla il lavoro di pubblicazione e il tag immutabile della versione in Gitea.",
"guideTitle": "Installazione e aggiornamenti",
"guideHost": "Esegui questi comandi nel clone del repository sul server Linux con Docker. Questa pagina verifica lo stato e non controlla Docker.",
"guideAccess": "La compilazione dai sorgenti richiede accesso al repository. Le immagini private richiedono anche accesso ai pacchetti del registro. La procedura conserva le impostazioni esistenti.",
"guidePinned": "Per una versione verificata, seleziona il relativo commit sul server ed esegui bash cms update --skip-pull. In modalità immagini precompilate puoi specificare entrambi i digest; consulta docs/operations/docker-installation.md.",
"guideWorker": "Dopo l’avvio verifica spazio persistente, migrazioni e segnale del worker. Lo stato HTTP da solo non conferma l’esecuzione dei processi in background.",
"guideRecovery": "Prima di aggiornare salva il database e verifica come ripristinarlo. Ripristinare l’immagine non annulla le migrazioni. La compatibilità con versioni precedenti del database non è garantita."
},
"operations": {
"title": "Da controllare",
+7 -1
View File
@@ -377,7 +377,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4235,7 +4235,13 @@
"migrationsHint": "Aantal meegeleverde migraties dat ontbreekt in de databasehistorie. Voer migraties uit via het releaseproces.",
"workerHint": "Laatste workersignaal in Redis. Ouder dan twee minuten vereist onderzoek; zonder signaal is niet vast te stellen of de worker actief is.",
"rendererHint": "De client gebruikt het ingestelde adres of standaard /nitro-client/. Open het spel apart om de weergave en assets te controleren.",
"registryHint": "Registergegevens staan in CI, niet in het CMS. Controleer de publicatietaak en onveranderlijke versietag in Gitea."
"registryHint": "Registergegevens staan in CI, niet in het CMS. Controleer de publicatietaak en onveranderlijke versietag in Gitea.",
"guideTitle": "Installatie en updates",
"guideHost": "Voer deze opdrachten uit in de repositorykloon op je Linux Docker-host. Deze pagina controleert alleen de status en bestuurt Docker niet.",
"guideAccess": "Bouwen vanuit broncode vereist toegang tot de repository. Private images vereisen ook toegang tot registerpakketten. De wizard bewaart bestaande instellingen.",
"guidePinned": "Selecteer voor een gecontroleerde versie de bijbehorende commit op de host en voer bash cms update --skip-pull uit. Bij vooraf gebouwde images kun je beide digests opgeven; zie docs/operations/docker-installation.md.",
"guideWorker": "Controleer na het starten opslag, migraties en de worker-heartbeat hieronder. Een gezonde HTTP-respons bevestigt niet dat achtergrondtaken draaien.",
"guideRecovery": "Maak voor het upgraden een databaseback-up en controleer de herstelprocedure. Een image terugzetten draait migraties niet terug. Compatibiliteit met eerdere databaseversies is niet gegarandeerd."
},
"importHistory": {
"cancelled": "Geannuleerd",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4060,7 +4060,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+7 -1
View File
@@ -4062,7 +4062,13 @@
"migrationsHint": "Number of packaged migrations absent from the database history. Apply migrations through the release process.",
"workerHint": "Last worker heartbeat in Redis. More than two minutes old needs investigation; no heartbeat cannot establish whether the worker is running.",
"rendererHint": "The client uses the configured address or /nitro-client/ by default. Open the game separately to verify rendering and assets.",
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea."
"registryHint": "Registry credentials live in CI, not in the CMS. Check the image publication job and its immutable release tag in Gitea.",
"guideTitle": "Installation and updates",
"guideHost": "Run these commands in the repository clone on your Linux Docker host. This page only checks status; it does not control Docker.",
"guideAccess": "Source builds need repository access. Private prebuilt images also require registry package access. The wizard preserves existing settings.",
"guidePinned": "For a reviewed version, check out its commit on the host and run bash cms update --skip-pull. Paired application and migrations digests are optional in prebuilt mode; see docs/operations/docker-installation.md.",
"guideWorker": "After startup, check storage, migrations and worker heartbeat below. HTTP health alone does not confirm background jobs are running.",
"guideRecovery": "Back up the database and verify its restore procedure before upgrading. Image rollback does not undo migrations. Database downgrade compatibility is not guaranteed."
},
"importHistory": {
"cancelled": "Cancelled",
+3
View File
@@ -19,8 +19,11 @@ docker() {
if [ "${@: -1}" = previous123 ] || [ -f "$TEST_DIR/restored" ]; then echo sha256:old; return 0; fi
if [ "$SCENARIO" = wrong-image ]; then echo sha256:old; else echo sha256:new; fi ;;
'image inspect')
if [[ "$SCENARIO" = migration-revision-mismatch && "$*" = *epicnext-cms-migrations* ]]; then echo unknown; return 0; fi
if [[ "$SCENARIO" = migration-revision-missing && "$*" = *epicnext-cms-migrations* ]]; then echo '<no value>'; return 0; fi
if [[ "$*" = *org.opencontainers* ]] && [[ "$*" = *sha256:old* ]]; then printf 'b%.0s' {1..40}; echo; return 0; fi
if [[ "$*" = *org.opencontainers* ]]; then echo "$TEST_SHA"; else echo sha256:new; fi ;;
'compose run') [ "$SCENARIO" != storage-failure ] ;;
'compose config') return 0 ;;
'compose build') [ "$SCENARIO" != build-failure ] ;;
'compose up')