Skip to content

Commit e2fa6fe

Browse files
Merge: Phase 1 — self-contained, update-bug fix, dashboard UX (#7)
Phase 1: drop Diun, fix update bug, dashboard UX overhaul
2 parents 6618989 + 2d7e84b commit e2fa6fe

20 files changed

Lines changed: 759 additions & 509 deletions

.env.example

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ ADMIN_PASSWORD=change-me
2222
# Generate one with: openssl rand -hex 32
2323
SESSION_SECRET=
2424

25-
# Bearer token Diun must send in the Authorization header when posting
26-
# webhook events to /api/diun/webhook.
27-
# Generate one with: openssl rand -hex 32
28-
DIUN_WEBHOOK_TOKEN=
29-
3025
# Session cookie lifetime, in seconds. Default is 7 days.
3126
SESSION_TTL=604800
3227

API_CONTRACT.md

Lines changed: 32 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,10 @@ All request/response bodies are JSON unless noted otherwise.
1212
- On successful login, the server sets a signed, httpOnly cookie named
1313
`diun_session` (`SameSite=Lax`, `Secure` when served over HTTPS,
1414
`Max-Age` = `SESSION_TTL` seconds).
15-
- Protected routes (everything except `/api/auth/login`, `/api/health`, and
16-
`/api/diun/webhook`) require a valid `diun_session` cookie. If it is
17-
missing, invalid, or expired, the server responds `401 Unauthorized` with
15+
- Protected routes (everything except `/api/auth/login` and `/api/health`)
16+
require a valid `diun_session` cookie. If it is missing, invalid, or
17+
expired, the server responds `401 Unauthorized` with
1818
`{ "error": "unauthorized" }`.
19-
- The Diun webhook route uses a separate auth mechanism: a static bearer
20-
token (`DIUN_WEBHOOK_TOKEN`) in the `Authorization` header. It does not
21-
use the session cookie.
2219

2320
## Endpoints
2421

@@ -43,19 +40,20 @@ All request/response bodies are JSON unless noted otherwise.
4340
- Auth: cookie (optional — never errors, reports status).
4441
- Response: `200 { "authenticated": boolean }`
4542

46-
### `POST /api/diun/webhook`
47-
48-
- Auth: token — header `Authorization: Bearer <DIUN_WEBHOOK_TOKEN>`. `401`
49-
if missing/invalid.
50-
- Body: Diun webhook payload (see below).
51-
- Response: `204 No Content` on successful ingest. `400` if the payload is
52-
malformed.
53-
5443
### `GET /api/containers`
5544

5645
- Auth: cookie.
5746
- Response: `200` — array of container items (shape below).
5847

48+
### `GET /api/diagnostics`
49+
50+
- Auth: cookie.
51+
- Response: `200 { "stacks": { "stacksDir": "/opt/stacks", "mounted": true } }`.
52+
`mounted` is `false` when the configured `STACKS_DIR` isn't present inside
53+
the container (the host stacks dir isn't mounted, or is mounted at a
54+
different path) — which breaks compose-based updates. The dashboard uses
55+
this to warn before an update is attempted.
56+
5957
### `POST /api/check`
6058

6159
- Auth: cookie.
@@ -162,13 +160,15 @@ always returns normalized refs.
162160
"project": "web",
163161
"service": "nginx",
164162
"image": "nginx:latest",
163+
"tag": "latest",
164+
"currentVersion": "1.27.3",
165165
"currentDigest": "sha256:...",
166166
"updateAvailable": true,
167167
"availableDigest": "sha256:...",
168168
"pinned": false,
169169
"state": "running",
170-
"composeFile": "/stacks/web/docker-compose.yml",
171-
"workingDir": "/stacks/web"
170+
"composeFile": "/opt/stacks/web/compose.yaml",
171+
"workingDir": "/opt/stacks/web"
172172
}
173173
```
174174

@@ -178,56 +178,30 @@ Field notes:
178178
- `project` / `service` — derived from the `com.docker.compose.project` /
179179
`com.docker.compose.service` labels.
180180
- `image` — image ref as configured (tag, not digest).
181+
- `tag` — the tag portion of `image` (e.g. `latest`, `1.27`), or `null` if
182+
the ref is digest-pinned.
183+
- `currentVersion` — human-readable version from the running image's
184+
`org.opencontainers.image.version` label, if it sets one (else `null`).
181185
- `currentDigest` — digest of the image the running container was created
182186
from.
183-
- `updateAvailable``true` if the most recent unresolved Diun event for
184-
this image's normalized ref reports a digest different from
185-
`currentDigest`.
187+
- `updateAvailable``true` if the most recent unresolved update event
188+
(from the registry check) for this image's normalized ref reports a digest
189+
different from `currentDigest`.
186190
- `availableDigest` — the digest from that unresolved event, if any (else
187191
`null`).
188-
- `pinned``true` if the image ref is in the `pinned` table (update
189-
indicator is suppressed, but manual update is still allowed).
192+
- `pinned``true` if the image ref is in the `pinned` table ("Pin Version":
193+
update indicator is suppressed and the container is grouped separately, but
194+
a manual update is still allowed).
190195
- `state` — Docker container state (`running`, `exited`, etc.).
191196
- `composeFile` / `workingDir` — derived from
192197
`com.docker.compose.project.config_files` /
193198
`com.docker.compose.project.working_dir` labels; used to run `docker
194199
compose` commands for that container.
195200

196-
## Diun webhook payload
197-
198-
Diun's webhook notifier posts a JSON body shaped roughly like:
199-
200-
```json
201-
{
202-
"status": "update",
203-
"image": "nginx:latest",
204-
"digest": "sha256:abc123...",
205-
"provider": "docker",
206-
"hub_link": "https://hub.docker.com/_/nginx",
207-
"platform": "linux/amd64",
208-
"metadata": {
209-
"hostname": "docker-host-1",
210-
"container": "nginx",
211-
"...": "additional Diun metadata fields"
212-
}
213-
}
214-
```
201+
## Update events
215202

216-
Fields we read:
217-
218-
- `status``"new"` (first time Diun sees this image) or `"update"` (a
219-
newer digest was found). Both are recorded; only `"update"` events are
220-
meaningful for the update indicator.
221-
- `image` — the image ref Diun checked, used to derive `normalized_ref`
222-
(registry/repo without tag-specific noise, used to key
223-
`update_events.normalized_ref`).
224-
- `digest` — the new digest Diun observed.
225-
- `provider` — Diun provider (`docker`, `swarm`, etc.) — stored for
226-
reference.
227-
- `hub_link` — informational link, stored for reference.
228-
- `platform` — image platform string, stored for reference.
229-
- `metadata` — passthrough object with additional Diun-provided context;
230-
stored as part of `raw_json`, not parsed individually.
231-
232-
The full raw payload is stored as `raw_json` in `update_events` for
233-
debugging/audit, regardless of which fields are explicitly parsed.
203+
`update_events` rows are produced solely by the active registry check
204+
(`POST /api/check` and the background scheduler). Each records the
205+
`normalized_ref` and the registry-reported `digest`; a row is `resolved` once
206+
the running container's digest matches it (the update was applied). There is
207+
no external notifier — the app queries registries directly.

0 commit comments

Comments
 (0)