From 3939a5f1bd69c2c8260c126217424abb5a0e7e0b Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 11:58:17 +0100 Subject: [PATCH 01/12] repro: re-run no-email login spec after upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test-ui-after-upgrade step running no-email-login.spec.ts against the device left by test-upgrade (snap-refreshed from 0.8.9 to local build). Forum t/616 says non-admin users still hit "no permission" after the 0.9.2 upgrade — confirming whether the upgrade boundary itself (not fresh install) is what differentiates Dan's device from CI. ci/ui.sh now takes an optional artifact-dir tag and spec filter so this step's results don't overwrite test-ui-desktop's. --- .drone.jsonnet | 8 ++++++++ ci/ui.sh | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 37656cc..434430c 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -124,6 +124,14 @@ local build(arch, test_ui, dind) = [{ ], privileged: true, }, + { + name: 'test-ui-after-upgrade', + image: 'mcr.microsoft.com/playwright:' + playwright, + environment: { DEVICE_USER: 'user', DEVICE_PASSWORD: 'Password1' }, + commands: [ + './ci/ui.sh desktop ' + name + ' ' + distro_default + ' $DRONE_BUILD_NUMBER after-upgrade no-email-login.spec.ts', + ], + }, ] else []) + [ { name: 'upload', diff --git a/ci/ui.sh b/ci/ui.sh index a67720a..9eb8e9f 100755 --- a/ci/ui.sh +++ b/ci/ui.sh @@ -4,10 +4,12 @@ PROJECT=$1 APP=$2 DISTRO=$3 VERSION=$4 +TAG=${5:-} +SPEC=${6:-} getent hosts ${APP}.${DISTRO}.com | sed "s/${APP}.${DISTRO}.com/auth.${DISTRO}.com/g" | tee -a /etc/hosts -ART=/drone/src/artifact/${PROJECT} +ART=/drone/src/artifact/${PROJECT}${TAG:+-${TAG}} mkdir -p "$ART" trap 'cp -r /drone/src/web/test-results "$ART/" 2>/dev/null; cp -r /drone/src/web/playwright-report "$ART/" 2>/dev/null; chmod -R a+r "$ART" 2>/dev/null; exit' EXIT INT TERM @@ -18,4 +20,4 @@ PLAYWRIGHT_APP=${APP} \ PLAYWRIGHT_VERSION=${VERSION} \ NO_EMAIL_USER=noemail \ NO_EMAIL_PASSWORD=Password1 \ - npx playwright test --project=${PROJECT} + npx playwright test --project=${PROJECT} ${SPEC} From 49ed9f64358e7c640a79be7c635924fe903ca968 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 12:35:31 +0100 Subject: [PATCH 02/12] retrigger CI: build 149 amd64 flaked on test_activate_device with snap auto-refresh in progress From 4df1f6954d84080422e83f91a2aaecd9eb768e08 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 13:31:00 +0100 Subject: [PATCH 03/12] test: wait for in-progress snap auto-refresh before activation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build 149 and 150 both flaked on test_activate_device with 'snap platform has auto-refresh change in progress' — 21 retries × 10s isn't enough when the platform snap is mid-refresh. `snap watch --last=auto-refresh` blocks until the latest auto-refresh change finishes, then activation can proceed. --- test/test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test.py b/test/test.py index a07f47f..7cf56dc 100644 --- a/test/test.py +++ b/test/test.py @@ -58,6 +58,7 @@ def test_start(module_setup, device, device_host, app, domain): @pytest.mark.flaky(retries=20, delay=10) def test_activate_device(device): device.run_ssh('rm -f /var/snap/platform/current/syncloud.crt', throw=False) + device.run_ssh('snap watch --last=auto-refresh 2>/dev/null || true', throw=False) response = retry(device.activate_custom) assert response.status_code == 200, response.text From 65478c85fb6d420ee09e3fd90ba2163f8489e4f8 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 13:48:41 +0100 Subject: [PATCH 04/12] ci: disable snap auto-refresh in device service; unify platform version; extract cli build.sh - Device service entrypoint now drops a systemd drop-in that holds snap refresh until 2099 before snapd starts auto-refreshing, mirroring the pattern already used in nextcloud/photoprism. Removes the test_activate_device flake under "snap platform has auto-refresh change in progress" without needing snap watch --last=auto-refresh. - Collapse platforms = { bookworm, buster } dict into a single platform = '26.04.9' string; buster image now uses the same tag. - Move inline cli go-build commands into cli/build.sh. --- .drone.jsonnet | 23 ++++++++--------------- cli/build.sh | 11 +++++++++++ test/test.py | 1 - 3 files changed, 19 insertions(+), 16 deletions(-) create mode 100755 cli/build.sh diff --git a/.drone.jsonnet b/.drone.jsonnet index 434430c..28003f0 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -3,10 +3,7 @@ local openwebui = '0.9.2'; local ollama = '0.14.2'; local nginx = '1.29.3-alpine3.22'; local debian = 'bookworm-slim'; -local platforms = { - bookworm: '26.04.9', - buster: '25.02', -}; +local platform = '26.04.9'; local playwright = 'v1.59.1-jammy'; local deployer = 'https://github.com/syncloud/store/releases/download/4/syncloud-release'; local python = '3.12-slim-bookworm'; @@ -40,14 +37,14 @@ local build(arch, test_ui, dind) = [{ }, { name: 'ollama test', - image: 'syncloud/platform-' + distro_default + '-' + arch + ':' + platforms[distro_default], + image: 'syncloud/platform-' + distro_default + '-' + arch + ':' + platform, commands: [ './ollama/test.sh', ], }, { name: 'ollama test buster', - image: 'syncloud/platform-buster-' + arch + ':' + platforms.buster, + image: 'syncloud/platform-buster-' + arch + ':' + platform, commands: [ './ollama/test.sh', ], @@ -61,14 +58,14 @@ local build(arch, test_ui, dind) = [{ }, { name: 'openwebui test', - image: 'syncloud/platform-' + distro_default + '-' + arch + ':' + platforms[distro_default], + image: 'syncloud/platform-' + distro_default + '-' + arch + ':' + platform, commands: [ './openwebui/test.sh', ], }, { name: 'openwebui test buster', - image: 'syncloud/platform-buster-' + arch + ':' + platforms.buster, + image: 'syncloud/platform-buster-' + arch + ':' + platform, commands: [ './openwebui/test.sh', ], @@ -78,12 +75,7 @@ local build(arch, test_ui, dind) = [{ name: 'cli', image: 'golang:' + go, commands: [ - 'cd cli', - 'CGO_ENABLED=0 go build -o ../build/snap/meta/hooks/install ./cmd/install', - 'CGO_ENABLED=0 go build -o ../build/snap/meta/hooks/configure ./cmd/configure', - 'CGO_ENABLED=0 go build -o ../build/snap/meta/hooks/pre-refresh ./cmd/pre-refresh', - 'CGO_ENABLED=0 go build -o ../build/snap/meta/hooks/post-refresh ./cmd/post-refresh', - 'CGO_ENABLED=0 go build -o ../build/snap/bin/cli ./cmd/cli', + './cli/build.sh', ], }, { @@ -228,8 +220,9 @@ local build(arch, test_ui, dind) = [{ ] + [ { name: name + '.' + distro + '.com', - image: 'syncloud/platform-' + distro + '-' + arch + ':' + platforms[distro], + image: 'syncloud/platform-' + distro + '-' + arch + ':' + platform, privileged: true, + entrypoint: ['/bin/sh', '-c', "mkdir -p /etc/systemd/system/snapd.service.d && printf '[Service]\\nExecStartPost=/bin/sh -c \"/usr/bin/snap set system refresh.hold=2099-01-01T00:00:00Z\"\\n' > /etc/systemd/system/snapd.service.d/disable-refresh.conf && exec /sbin/init"], volumes: [ { name: 'dbus', diff --git a/cli/build.sh b/cli/build.sh new file mode 100755 index 0000000..aca21f1 --- /dev/null +++ b/cli/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash -ex + +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +cd ${DIR} +BUILD_DIR=${DIR}/../build/snap + +CGO_ENABLED=0 go build -o ${BUILD_DIR}/meta/hooks/install ./cmd/install +CGO_ENABLED=0 go build -o ${BUILD_DIR}/meta/hooks/configure ./cmd/configure +CGO_ENABLED=0 go build -o ${BUILD_DIR}/meta/hooks/pre-refresh ./cmd/pre-refresh +CGO_ENABLED=0 go build -o ${BUILD_DIR}/meta/hooks/post-refresh ./cmd/post-refresh +CGO_ENABLED=0 go build -o ${BUILD_DIR}/bin/cli ./cmd/cli diff --git a/test/test.py b/test/test.py index 7cf56dc..a07f47f 100644 --- a/test/test.py +++ b/test/test.py @@ -58,7 +58,6 @@ def test_start(module_setup, device, device_host, app, domain): @pytest.mark.flaky(retries=20, delay=10) def test_activate_device(device): device.run_ssh('rm -f /var/snap/platform/current/syncloud.crt', throw=False) - device.run_ssh('snap watch --last=auto-refresh 2>/dev/null || true', throw=False) response = retry(device.activate_custom) assert response.status_code == 200, response.text From 98af2b8d929217896de033e469f22781bc981b12 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 14:56:45 +0100 Subject: [PATCH 05/12] =?UTF-8?q?ci:=20bump=20platform=2026.04.9=20?= =?UTF-8?q?=E2=86=92=2026.04.10=20(exists=20for=20both=20bookworm=20and=20?= =?UTF-8?q?buster),=20lift=20dind=20to=20global?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build 152 errored on 'ollama test buster' with manifest unknown: syncloud/platform-buster-amd64:26.04.9 doesn't exist — bookworm and buster are released independently and 26.04.9 only shipped for bookworm. 26.04.10 is the latest tag published for both arches and both distros, so the unified version works. Also lifts dind from a per-build parameter to a global, matching the style of the other version locals. --- .drone.jsonnet | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 28003f0..de507a6 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -3,7 +3,8 @@ local openwebui = '0.9.2'; local ollama = '0.14.2'; local nginx = '1.29.3-alpine3.22'; local debian = 'bookworm-slim'; -local platform = '26.04.9'; +local platform = '26.04.10'; +local dind = '20.10.21-dind'; local playwright = 'v1.59.1-jammy'; local deployer = 'https://github.com/syncloud/store/releases/download/4/syncloud-release'; local python = '3.12-slim-bookworm'; @@ -12,7 +13,7 @@ local distro_default = 'bookworm'; local distros = ['bookworm', 'buster']; -local build(arch, test_ui, dind) = [{ +local build(arch, test_ui) = [{ kind: 'pipeline', type: 'docker', name: arch, @@ -257,5 +258,5 @@ local build(arch, test_ui, dind) = [{ }, ]; -build('amd64', true, '20.10.21-dind') + -build('arm64', false, '20.10.21-dind') +build('amd64', true) + +build('arm64', false) From 7260977c5b325dd411650b559968cb7dc404a8c3 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 16:39:21 +0100 Subject: [PATCH 06/12] ci: collapse per-distro test steps into for-comprehensions with platform_image helper Mirror photoprism's pattern: - platform_image(distro, arch) returns the syncloud/platform-* image tag. - ollama test / ollama test buster -> 'ollama test ' + distro in a for-comprehension. - openwebui test / openwebui test buster -> same. - Device service uses platform_image() too. Also tidies the inherited stray indentation in the steps array. --- .drone.jsonnet | 63 ++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index de507a6..96855fe 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -12,6 +12,8 @@ local go = '1.25'; local distro_default = 'bookworm'; local distros = ['bookworm', 'buster']; +local platform_image(distro, arch) = + 'syncloud/platform-' + distro + '-' + arch + ':' + platform; local build(arch, test_ui) = [{ kind: 'pipeline', @@ -31,63 +33,54 @@ local build(arch, test_ui) = [{ }, { name: 'ollama', - image: "ollama/ollama:" + ollama, + image: 'ollama/ollama:' + ollama, commands: [ './ollama/build.sh', ], }, + ] + [ { - name: 'ollama test', - image: 'syncloud/platform-' + distro_default + '-' + arch + ':' + platform, + name: 'ollama test ' + distro, + image: platform_image(distro, arch), commands: [ './ollama/test.sh', ], - }, - { - name: 'ollama test buster', - image: 'syncloud/platform-buster-' + arch + ':' + platform, - commands: [ - './ollama/test.sh', - ], - }, + } + for distro in distros + ] + [ { name: 'openwebui', - image: "ghcr.io/open-webui/open-webui:" + openwebui, + image: 'ghcr.io/open-webui/open-webui:' + openwebui, commands: [ './openwebui/build.sh', ], }, + ] + [ { - name: 'openwebui test', - image: 'syncloud/platform-' + distro_default + '-' + arch + ':' + platform, + name: 'openwebui test ' + distro, + image: platform_image(distro, arch), commands: [ './openwebui/test.sh', ], + } + for distro in distros + ] + [ + { + name: 'cli', + image: 'golang:' + go, + commands: [ + './cli/build.sh', + ], }, { - name: 'openwebui test buster', - image: 'syncloud/platform-buster-' + arch + ':' + platform, + name: 'package', + image: 'debian:' + debian, commands: [ - './openwebui/test.sh', + 'VERSION=$(cat version)', + './package.sh ' + name + ' $VERSION ', ], }, - - { - name: 'cli', - image: 'golang:' + go, - commands: [ - './cli/build.sh', - ], - }, - { - name: 'package', - image: 'debian:' + debian, - commands: [ - 'VERSION=$(cat version)', - './package.sh ' + name + ' $VERSION ', - ], - }, - ] + [ + ] + [ { name: 'test ' + distro, image: 'python:' + python, @@ -221,7 +214,7 @@ local build(arch, test_ui) = [{ ] + [ { name: name + '.' + distro + '.com', - image: 'syncloud/platform-' + distro + '-' + arch + ':' + platform, + image: platform_image(distro, arch), privileged: true, entrypoint: ['/bin/sh', '-c', "mkdir -p /etc/systemd/system/snapd.service.d && printf '[Service]\\nExecStartPost=/bin/sh -c \"/usr/bin/snap set system refresh.hold=2099-01-01T00:00:00Z\"\\n' > /etc/systemd/system/snapd.service.d/disable-refresh.conf && exec /sbin/init"], volumes: [ From 7e53e5e37549b1584f82b5d803104a0f6c7c987d Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 18:32:43 +0100 Subject: [PATCH 07/12] =?UTF-8?q?ci:=20simulate=20full=20upgrade=20flow=20?= =?UTF-8?q?=E2=80=94=20login=20on=200.8.9=20then=20re-login=20after=20refr?= =?UTF-8?q?esh;=20drop=20PR=20trigger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build 154 ran no-email-login.spec.ts after snap-remove + install-old + local-install-new and passed cleanly. Dan reports the failure on a real upgrade, so the missing ingredient is openwebui DB state that pre-dates the refresh. - Split upgrade.py test_upgrade into test_install_old (snap remove + install store) and test_refresh_to_new (local_install + wait). - New test-ui-on-old step runs login.spec.ts against 0.8.9 so the admin account is provisioned in openwebui's DB before the refresh. - test-ui-after-upgrade still runs no-email-login.spec.ts post-refresh; with the admin row already in the DB the OAUTH path now has prior state to reconcile, which more closely mirrors Dan's device. - Drop pull_request trigger event so PR sync no longer queues duplicate builds. --- .drone.jsonnet | 23 ++++++++++++++++++++--- test/upgrade.py | 6 +++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 96855fe..f783f5e 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -101,12 +101,30 @@ local build(arch, test_ui) = [{ ], }, { - name: 'test-upgrade', + name: 'test-upgrade-install-old', image: 'python:' + python, commands: [ 'cd test', './deps.sh', - 'py.test -x -s upgrade.py --distro=' + distro_default + ' --ver=$DRONE_BUILD_NUMBER --app=' + name, + 'py.test -x -s upgrade.py -k "test_start or test_install_old" --distro=' + distro_default + ' --ver=$DRONE_BUILD_NUMBER --app=' + name, + ], + privileged: true, + }, + { + name: 'test-ui-on-old', + image: 'mcr.microsoft.com/playwright:' + playwright, + environment: { DEVICE_USER: 'user', DEVICE_PASSWORD: 'Password1' }, + commands: [ + './ci/ui.sh desktop ' + name + ' ' + distro_default + ' $DRONE_BUILD_NUMBER on-old login.spec.ts', + ], + }, + { + name: 'test-upgrade-refresh-new', + image: 'python:' + python, + commands: [ + 'cd test', + './deps.sh', + 'py.test -x -s upgrade.py -k "test_start or test_refresh_to_new" --distro=' + distro_default + ' --ver=$DRONE_BUILD_NUMBER --app=' + name, ], privileged: true, }, @@ -196,7 +214,6 @@ local build(arch, test_ui) = [{ trigger: { event: [ 'push', - 'pull_request', ], }, services: [ diff --git a/test/upgrade.py b/test/upgrade.py index 7dcb448..2894bec 100644 --- a/test/upgrade.py +++ b/test/upgrade.py @@ -25,9 +25,13 @@ def test_start(module_setup, app, device_host, domain, device): device.run_ssh('mkdir {0}'.format(TMP_DIR), throw=False) -def test_upgrade(device, device_user, device_password, device_host, app_archive_path, app_domain, app_dir): +def test_install_old(device, app_domain): device.run_ssh('snap remove openwebui') device.run_ssh('snap install openwebui', retries=10) + wait_for_rest(requests.session(), "https://{0}".format(app_domain), 200, 100) + + +def test_refresh_to_new(device, device_host, device_password, app_archive_path, app_domain): local_install(device_host, device_password, app_archive_path) wait_for_rest(requests.session(), "https://{0}".format(app_domain), 200, 100) From c978a3a12b0be898afb840e1c70a1c3e9522c423 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 20:49:21 +0100 Subject: [PATCH 08/12] ci: install rev 121 (0.8.9) from apps.syncloud.org for old-install step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit snap install openwebui pulls latest/stable which is rev 147 = 0.9.2 (our build) — making test-upgrade-install-old → test-upgrade-refresh-new a 0.9.2 → 0.9.2 no-op, not a real upgrade. That's why test-ui-after-upgrade in build 154 passed cleanly while Dan's actual 0.8.9 → 0.9.2 path still breaks. Download the rev 121 .snap directly from the store mirror and snap install --dangerous it. Also bypasses the slow store-channel download path (build 154 spent ~2hr on it). --- test/upgrade.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/upgrade.py b/test/upgrade.py index 2894bec..64b311e 100644 --- a/test/upgrade.py +++ b/test/upgrade.py @@ -25,9 +25,18 @@ def test_start(module_setup, app, device_host, domain, device): device.run_ssh('mkdir {0}'.format(TMP_DIR), throw=False) +OLD_REV = '121' + + def test_install_old(device, app_domain): - device.run_ssh('snap remove openwebui') - device.run_ssh('snap install openwebui', retries=10) + device.run_ssh('snap remove openwebui', throw=False) + device.run_ssh( + 'ARCH=$(dpkg --print-architecture); ' + 'curl -fsSL -o /tmp/openwebui_old.snap ' + 'http://apps.syncloud.org/apps/openwebui_{rev}_${{ARCH}}.snap'.format(rev=OLD_REV), + retries=5, + ) + device.run_ssh('snap install --dangerous /tmp/openwebui_old.snap') wait_for_rest(requests.session(), "https://{0}".format(app_domain), 200, 100) From dfc697de1c4427e5112dc94d48aeb73d753f55fe Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Sun, 17 May 2026 22:50:47 +0100 Subject: [PATCH 09/12] ci: use curl's --retry-all-errors + 10s backoff for rev 121 download MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build 159 step 17 hit a 404 from apps.syncloud.org (S3 round-robin transient — the URL returns 200 from outside, just unlucky timing inside the device). syncloudlib's retries=5 fires retries with no delay so they all hit the same transient state. curl --retry 10 --retry-delay 10 --retry-all-errors covers transient 4xx and 5xx with a real backoff. Also switch http -> https for a more modern S3 endpoint. --- test/upgrade.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/upgrade.py b/test/upgrade.py index 64b311e..d5443e1 100644 --- a/test/upgrade.py +++ b/test/upgrade.py @@ -32,9 +32,9 @@ def test_install_old(device, app_domain): device.run_ssh('snap remove openwebui', throw=False) device.run_ssh( 'ARCH=$(dpkg --print-architecture); ' - 'curl -fsSL -o /tmp/openwebui_old.snap ' - 'http://apps.syncloud.org/apps/openwebui_{rev}_${{ARCH}}.snap'.format(rev=OLD_REV), - retries=5, + 'curl -fsSL --retry 10 --retry-delay 10 --retry-all-errors ' + '-o /tmp/openwebui_old.snap ' + 'https://apps.syncloud.org/apps/openwebui_{rev}_${{ARCH}}.snap'.format(rev=OLD_REV), ) device.run_ssh('snap install --dangerous /tmp/openwebui_old.snap') wait_for_rest(requests.session(), "https://{0}".format(app_domain), 200, 100) From 393b45c3aea7d1872248a18d4b2c8bc37bad73f8 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Mon, 18 May 2026 01:07:48 +0100 Subject: [PATCH 10/12] =?UTF-8?q?ci:=20hardcode=20amd64=20in=20old-snap=20?= =?UTF-8?q?URL=20=E2=80=94=20ARCH=20expansion=20was=20getting=20eaten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build 160's curl ended up requesting openwebui_121_.snap — \${ARCH} from \$(dpkg --print-architecture) expanded to empty (either eaten by the double-quoted ssh wrapping or dpkg missing from the path in use). test-upgrade-install-old only runs on amd64 (test_ui=false on arm64), so just hardcode amd64 — no need for runtime detection. --- test/upgrade.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/upgrade.py b/test/upgrade.py index d5443e1..ece8c7b 100644 --- a/test/upgrade.py +++ b/test/upgrade.py @@ -31,10 +31,9 @@ def test_start(module_setup, app, device_host, domain, device): def test_install_old(device, app_domain): device.run_ssh('snap remove openwebui', throw=False) device.run_ssh( - 'ARCH=$(dpkg --print-architecture); ' 'curl -fsSL --retry 10 --retry-delay 10 --retry-all-errors ' '-o /tmp/openwebui_old.snap ' - 'https://apps.syncloud.org/apps/openwebui_{rev}_${{ARCH}}.snap'.format(rev=OLD_REV), + 'https://apps.syncloud.org/apps/openwebui_{rev}_amd64.snap'.format(rev=OLD_REV), ) device.run_ssh('snap install --dangerous /tmp/openwebui_old.snap') wait_for_rest(requests.session(), "https://{0}".format(app_domain), 200, 100) From bd69c1ce4cbfea630218de26dad0fa653ad5926a Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Mon, 18 May 2026 02:55:28 +0100 Subject: [PATCH 11/12] =?UTF-8?q?ci:=20switch=20rev=20121=20download=20to?= =?UTF-8?q?=20http=20=E2=80=94=20apps.syncloud.org=20S3=20website=20endpoi?= =?UTF-8?q?nt=20has=20no=20valid=20HTTPS=20cert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build 161 step 17 hung on TLS handshake — TCP connection to S3 established, but server hello never came (Client hello sent, then 15s timeout). apps.syncloud.org is fronted by an S3 website-mode endpoint which only serves HTTP. Plain http works (verified live, 200 with 3.9GB Content-Length). --- test/upgrade.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/upgrade.py b/test/upgrade.py index ece8c7b..c3a1d92 100644 --- a/test/upgrade.py +++ b/test/upgrade.py @@ -33,7 +33,7 @@ def test_install_old(device, app_domain): device.run_ssh( 'curl -fsSL --retry 10 --retry-delay 10 --retry-all-errors ' '-o /tmp/openwebui_old.snap ' - 'https://apps.syncloud.org/apps/openwebui_{rev}_amd64.snap'.format(rev=OLD_REV), + 'http://apps.syncloud.org/apps/openwebui_{rev}_amd64.snap'.format(rev=OLD_REV), ) device.run_ssh('snap install --dangerous /tmp/openwebui_old.snap') wait_for_rest(requests.session(), "https://{0}".format(app_domain), 200, 100) From 2a700bc75a14b5e04fde55d30375cc3c275eccf5 Mon Sep 17 00:00:00 2001 From: Boris Rybalkin Date: Mon, 18 May 2026 05:37:51 +0100 Subject: [PATCH 12/12] ci: rename login.spec.ts -> admin-login.spec.ts so test-ui-on-old filter is unique MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Playwright's positional spec filter does substring matching, so passing 'login.spec.ts' to test-ui-on-old matched both login.spec.ts and no-email-login.spec.ts. The no-email-login spec ran against 0.8.9 where the bug exists and failed, which masked admin-login working fine. Build 162 step 18 incidentally confirms in CI what Dan's original report said — noemail users genuinely can't log in on 0.8.9. Build 154 step 18 already showed they CAN log in on 0.9.2 fresh install, so the 0.8.9-only no-email bug is fixed. Dan must be hitting a separate failure mode on his real device. --- .drone.jsonnet | 2 +- web/e2e/{login.spec.ts => admin-login.spec.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename web/e2e/{login.spec.ts => admin-login.spec.ts} (100%) diff --git a/.drone.jsonnet b/.drone.jsonnet index f783f5e..d51df79 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -115,7 +115,7 @@ local build(arch, test_ui) = [{ image: 'mcr.microsoft.com/playwright:' + playwright, environment: { DEVICE_USER: 'user', DEVICE_PASSWORD: 'Password1' }, commands: [ - './ci/ui.sh desktop ' + name + ' ' + distro_default + ' $DRONE_BUILD_NUMBER on-old login.spec.ts', + './ci/ui.sh desktop ' + name + ' ' + distro_default + ' $DRONE_BUILD_NUMBER on-old admin-login.spec.ts', ], }, { diff --git a/web/e2e/login.spec.ts b/web/e2e/admin-login.spec.ts similarity index 100% rename from web/e2e/login.spec.ts rename to web/e2e/admin-login.spec.ts