From 53795433ee6b0ca7e134bb719f8708e32ca949ba Mon Sep 17 00:00:00 2001 From: strandedturtle Date: Fri, 26 Jun 2026 12:39:04 +0000 Subject: [PATCH] Rebrand to DockPull; daily scheduled scan time; fix settings icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rebrand: "Diun Updater" -> "DockPull" everywhere (UI, PWA manifest, title, README, logs), plus identifiers (cookie diun_session -> dockpull_session, storage keys diun.* -> dockpull.*, theme key, GitHub UA, default container_name + SELF_CONTAINER_NAME -> dockpull, compose service + data volume, package names). The GHCR image name is derived from the repo and is left unchanged. A couple of "you don't need Diun" notes remain by design. - Scheduler: replace the every-N-hours interval with a daily scan at a configured local time (default 09:00), mirroring a cron ping — set it to when you want your morning Discord message. setSettings re-arms it. Setting renamed backgroundCheckIntervalHours -> scheduledCheckTime (HH:MM), env CHECK_INTERVAL_HOURS -> SCHEDULED_CHECK_TIME. - Fix the malformed Settings gear icon in the mobile bottom nav. Server tests 76/76; client builds clean. --- .env.example | 10 +++--- API_CONTRACT.md | 16 ++++----- README.md | 34 +++++++++---------- client/index.html | 4 +-- client/package.json | 2 +- client/src/AuthPage.jsx | 2 +- client/src/Dashboard.jsx | 2 +- client/src/components/BottomNav.jsx | 22 +++++++----- client/src/components/Header.jsx | 2 +- client/src/components/StackGroup.jsx | 2 +- client/src/hooks/useTheme.js | 4 +-- client/src/pages/SettingsPage.jsx | 32 ++++++++---------- client/src/styles/app.css | 5 +++ client/vite.config.js | 2 +- docker-compose.yml | 8 ++--- server/package.json | 2 +- server/src/auth.js | 6 ++-- server/src/changelog.js | 2 +- server/src/config.js | 2 +- server/src/containers-service.js | 2 +- server/src/index.js | 4 +-- server/src/notify.js | 2 +- server/src/reconcile.js | 2 +- server/src/registry.js | 2 +- server/src/routes/update.js | 4 +-- server/src/scheduler.js | 50 ++++++++++++++++++---------- server/src/settings.js | 27 ++++++++------- server/test/auth.test.js | 10 +++--- server/test/scheduler.test.js | 18 ++++++++++ server/test/settings.test.js | 14 ++++---- 30 files changed, 169 insertions(+), 125 deletions(-) create mode 100644 server/test/scheduler.test.js diff --git a/.env.example b/.env.example index 538d983..240cb26 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ PORT=5000 # Directory containing your docker-compose stacks. MUST be mounted at this -# exact same path on the host and inside the diun-updater container (see the +# exact same path on the host and inside the dockpull container (see the # comment in docker-compose.yml for why). STACKS_DIR=/opt/stacks @@ -32,14 +32,14 @@ BASE_URL=http://localhost:5000 # --- Background checks & notifications (all optional; also editable in the UI) --- # Whether the server checks for updates on a schedule. Default: true. # BACKGROUND_CHECK_ENABLED=true -# How often the background check runs, in hours (1-168). Default: 6. -# CHECK_INTERVAL_HOURS=6 +# Daily local time (HH:MM, 24h) for the scheduled scan. Default: 09:00. +# SCHEDULED_CHECK_TIME=09:00 # Discord (or compatible) webhook URL to notify when updates are found. # Leave unset to disable notifications. # DISCORD_WEBHOOK_URL= # Name of this app's OWN container. It is excluded from the dashboard so it # can't be told to update (and thereby restart) itself mid-update. Defaults to -# "diun-updater" (the container_name in the shipped docker-compose.yml); change +# "dockpull" (the container_name in the shipped docker-compose.yml); change # it only if you rename the service. -SELF_CONTAINER_NAME=diun-updater +SELF_CONTAINER_NAME=dockpull diff --git a/API_CONTRACT.md b/API_CONTRACT.md index af8a619..b8eda4e 100644 --- a/API_CONTRACT.md +++ b/API_CONTRACT.md @@ -10,10 +10,10 @@ All request/response bodies are JSON unless noted otherwise. - Auth is a single shared password (`ADMIN_PASSWORD`), compared in constant time, no user accounts/database. - On successful login, the server sets a signed, httpOnly cookie named - `diun_session` (`SameSite=Lax`, `Secure` when served over HTTPS, + `dockpull_session` (`SameSite=Lax`, `Secure` when served over HTTPS, `Max-Age` = `SESSION_TTL` seconds). - Protected routes (everything except `/api/auth/login` and `/api/health`) - require a valid `diun_session` cookie. If it is missing, invalid, or + require a valid `dockpull_session` cookie. If it is missing, invalid, or expired, the server responds `401 Unauthorized` with `{ "error": "unauthorized" }`. @@ -24,7 +24,7 @@ All request/response bodies are JSON unless noted otherwise. - Auth: none. - Body: `{ "password": "string" }` - Response: - - `200 { "ok": true }` + `Set-Cookie: diun_session=...` on success. + - `200 { "ok": true }` + `Set-Cookie: dockpull_session=...` on success. - `401 { "error": "invalid_password" }` on bad password. - `429 { "error": "too_many_attempts" }` after too many failed attempts from one client IP (temporary lockout). @@ -33,7 +33,7 @@ All request/response bodies are JSON unless noted otherwise. - Auth: cookie. - Body: none. -- Response: `200 { "ok": true }`, clears the `diun_session` cookie. +- Response: `200 { "ok": true }`, clears the `dockpull_session` cookie. ### `GET /api/auth/me` @@ -63,7 +63,7 @@ All request/response bodies are JSON unless noted otherwise. - Auth: cookie. - Response: `text/event-stream` (SSE). Emits `data: {"type":"containers-changed"}` whenever server state changes (a check - ran, an update finished, or a pin/hide changed) so dashboards can refresh + ran, an update finished, or a pin changed) so dashboards can refresh without a manual reload. Comment lines (`: ...`) are sent as keepalives. ### `POST /api/update/:name` @@ -149,7 +149,7 @@ separate section, but can still be updated by hand. "defaultFilter": "updates", "autoCheckOnOpen": true, "backgroundCheckEnabled": true, - "backgroundCheckIntervalHours": 6, + "scheduledCheckTime": "09:00", "discordEnabled": false, "discordWebhookUrl": "" } @@ -158,7 +158,7 @@ separate section, but can still be updated by hand. - `autoCheckOnOpen` — whether the dashboard runs a check automatically on first open. - `backgroundCheckEnabled` — whether the server runs a scheduled check. - - `backgroundCheckIntervalHours` — interval for that check (1–168). + - `scheduledCheckTime` — daily local time (HH:MM) for the scheduled scan. - `discordEnabled` — whether to send Discord notifications on new updates. - `discordWebhookUrl` — Discord (or compatible) webhook URL, or `""`. @@ -167,7 +167,7 @@ separate section, but can still be updated by hand. - Auth: cookie. - Body: a partial patch of the settings object, e.g. `{ "defaultFilter": "all" }`. Unknown keys are ignored; invalid values for known keys return - `400 { "error": "invalid_value" }`. Changing the interval/enable re-arms the + `400 { "error": "invalid_value" }`. Changing the time/enable re-arms the background scheduler immediately. - Response: `200` — the full, updated settings object. diff --git a/README.md b/README.md index 84324a4..40eca34 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Diun Web Updater +# DockPull A small, self-hosted, mobile-first web UI for updating Docker containers that are managed by `docker compose` (e.g. via [Dockge](https://github.com/louislam/dockge)). @@ -106,9 +106,9 @@ existing compose file (e.g. a `management` stack) and fill in the two secrets. ```yaml services: - diun-updater: + dockpull: image: ghcr.io/strandedturtle/diupdater:edge - container_name: diun-updater + container_name: dockpull restart: unless-stopped ports: - "5000:5000" @@ -122,16 +122,16 @@ services: # match STACKS_DIR above, or updates fail with "compose file not found" # and relative bind mounts in your other stacks break on recreate. - /opt/stacks:/opt/stacks - - diun-updater-data:/data + - dockpull-data:/data volumes: - diun-updater-data: + dockpull-data: ``` Generate the secret (`openssl rand -hex 32`), then start just this service: ```bash -docker compose up -d diun-updater +docker compose up -d dockpull ``` Then open `http://:5000`. @@ -199,7 +199,7 @@ critical part is the **same-path stacks mount**: - /var/run/docker.sock:/var/run/docker.sock # ⚠️ SAME PATH on host and in container — do not change one side only: - ${STACKS_DIR}:${STACKS_DIR} - - diun-updater-data:/data # persistent SQLite (events/history/pins) + - dockpull-data:/data # persistent SQLite (events/history/pins) ``` **Why same-path?** This app calls `docker compose` against the *host* Docker @@ -226,10 +226,10 @@ Check it's healthy: ```bash curl -s http://localhost:5000/api/health # -> {"ok":true} -docker logs diun-updater # -> "...server listening at ..." +docker logs dockpull # -> "...server listening at ..." ``` -The SQLite database is created automatically in the `diun-updater-data` volume +The SQLite database is created automatically in the `dockpull-data` volume on first start. The first time you load the UI you'll get the login screen — enter `ADMIN_PASSWORD`, and the dashboard will run an initial update check. @@ -298,17 +298,17 @@ under `errors`). ### Background checks & Discord notifications -By default the server also checks on a schedule (every 6h) so badges stay fresh +By default the server runs a daily scan (09:00, server-local time) so badges stay fresh even when the app is closed. Configure it under **Settings → Background checks & Discord**: -- **Background checks** on/off and interval. +- **Daily scan** on/off and the time of day it runs. - **Discord webhook URL** — paste a Discord channel webhook to get a message when updates are found, then use **Send test message** to verify it. Each update is announced once (no repeats on every check). These can also be seeded from the environment (`BACKGROUND_CHECK_ENABLED`, -`CHECK_INTERVAL_HOURS`, `DISCORD_WEBHOOK_URL`); the Settings UI overrides at +`SCHEDULED_CHECK_TIME`, `DISCORD_WEBHOOK_URL`); the Settings UI overrides at runtime. --- @@ -328,9 +328,9 @@ All configuration is via environment variables (see `.env.example`). | `SESSION_TTL` | `604800` | | Login cookie lifetime in seconds (7 days). | | `BASE_URL` | `http://localhost:5000` | | Public URL; if `https`, the cookie is set `Secure`. | | `DISCORD_WEBHOOK_URL` | — | | Discord webhook for update notifications (optional; also set in Settings). | -| `CHECK_INTERVAL_HOURS` | `6` | | Background check interval in hours (1–168). | +| `SCHEDULED_CHECK_TIME` | `09:00` | | Daily local time (HH:MM) for the scheduled scan. | | `BACKGROUND_CHECK_ENABLED` | `true` | | Whether the scheduled background check runs. | -| `SELF_CONTAINER_NAME` | `diun-updater` | | This app's own container name, excluded from the dashboard so it can't update itself. | +| `SELF_CONTAINER_NAME` | `dockpull` | | This app's own container name, excluded from the dashboard so it can't update itself. | The two required vars are enforced at startup — the server refuses to boot without them (a `SKIP_CONFIG_CHECK=1` escape hatch exists for skeleton @@ -354,7 +354,7 @@ smoke-tests only; never use it in production). open internet or fronting it with Cloudflare Access if exposure matters. - **The app excludes its own container** from the dashboard (it can't safely update itself). Update the updater the normal way: - `docker compose pull diun-updater && docker compose up -d diun-updater`. + `docker compose pull dockpull && docker compose up -d dockpull`. --- @@ -381,7 +381,7 @@ quay.io work. pending event automatically (this also covers multi-arch images, where the registry digest and the running digest legitimately differ). If a badge sticks, tap **Check for updates** again; if it persists, there may be a genuinely newer -image — check the History tab and `docker logs diun-updater`. +image — check the History tab and `docker logs dockpull`. **Can't log in / cookie not sticking.** If you're on `https`, make sure `BASE_URL` is your `https://` URL (otherwise the `Secure` cookie won't be set @@ -430,5 +430,5 @@ cd client && npm run build # production bundle -> client/dist/ Build the production image manually (build context must be the repo root): ```bash -docker build -f server/Dockerfile -t diun-updater . +docker build -f server/Dockerfile -t dockpull . ``` diff --git a/client/index.html b/client/index.html index 65c22f5..fccc321 100644 --- a/client/index.html +++ b/client/index.html @@ -7,10 +7,10 @@ - + - Diun Updater + DockPull
diff --git a/client/package.json b/client/package.json index f965d54..dc3f441 100644 --- a/client/package.json +++ b/client/package.json @@ -1,5 +1,5 @@ { - "name": "diun-updater-client", + "name": "dockpull-client", "version": "0.1.0", "private": true, "license": "MIT", diff --git a/client/src/AuthPage.jsx b/client/src/AuthPage.jsx index ac482ef..f34523b 100644 --- a/client/src/AuthPage.jsx +++ b/client/src/AuthPage.jsx @@ -28,7 +28,7 @@ export default function AuthPage({ onAuthed }) { return (
-

Diun Updater

+

DockPull

Sign in to manage your containers

diff --git a/client/src/Dashboard.jsx b/client/src/Dashboard.jsx index 9c098a4..e90c110 100644 --- a/client/src/Dashboard.jsx +++ b/client/src/Dashboard.jsx @@ -4,7 +4,7 @@ import UpdateCard from './components/UpdateCard.jsx'; import UpdateAllButton from './components/UpdateAllButton.jsx'; import StackGroup from './components/StackGroup.jsx'; -const AUTOCHECK_SESSION = 'diun.autochecked'; +const AUTOCHECK_SESSION = 'dockpull.autochecked'; const UNGROUPED = 'Ungrouped'; function hasUpdate(c) { diff --git a/client/src/components/BottomNav.jsx b/client/src/components/BottomNav.jsx index b913b17..11a82e4 100644 --- a/client/src/components/BottomNav.jsx +++ b/client/src/components/BottomNav.jsx @@ -23,15 +23,19 @@ const HistoryIcon = () => ( ); const SettingsIcon = () => ( - Diun Updater + DockPull {pendingCount > 0 && {pendingCount}}