be021588c77424fb097140f4c5419513402d52f9
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
089f5d2902 |
[glm-grade=A] fix(update-manager): compose-prefixed image names probe <project>/<service> not library/<project>-<service> (DC-082)
Pre-fix: dashcaddy-dashcaddy-api:latest was normalized to library/dashcaddy-dashcaddy-api before probing Docker Hub. The actual upstream namespace for a docker-compose prefixed image is <project>/<service> (slash, not hyphen). Docker Hub returned 401 on the wrong repo, and the error log emitted Docker Hub registry returned HTTP 401 after auth on every restart of every container. Fix: 1. _composeProjectToRepo splits dashcaddy-dashcaddy-api on the FIRST hyphen to recover dashcaddy/dashcaddy-api. Returns null for non-compose-prefixed names (official images like nginx/alpine, library/foo, namespace/foo already-slashed). 2. _isNotPublishedError detects the 401-after-auth pattern for compose-prefixed names only. Steady-state for locally-built images that aren't published. 3. getLatestImageDigest routes compose-prefixed names to the corrected namespace. Routes already-namespaced names directly. Falls back to library/ for the Official Image path. 4. Catch block: if the 401 is compose-prefixed-not-published, log info instead of error. Real auth failures on legitimate images still log as error. 17/17 tests pass in 1.27s. Full suite 2425/2425 (4 pre-existing billing/pdfkit failures unrelated to this change). GLM stand-in verdict URN: urn:ump:7rhk7keukv3zrx654gbckxaycnuwm4agduf37creqbsoauszopoa |
||
|
|
a4e4b24732 |
fix(update-manager): force IPv4 + per-request timeout + transient-only retry on registry digest probes (DC-078) [glm-grade=A]
The per-hour checkForUpdates() loop called Docker Hub / ghcr.io without family:4, without a hard request timeout, and without retry on transient network errors. On DNS2 (Technitium at 100.121.150.22 returns AAAA records even when IPv6 routing to public registries is intermittently broken), every container check surfaced AggregateError [ETIMEDOUT] in error.log with stack `at internalConnectMultiple (node:net:1114:18)`. The dual-stack DNS race consumed the default 30s connect timeout per unreachable IPv6 family before falling back to IPv4 — 30s+ per container per check cycle. Three reliability properties added via shared fetchWithReliability() helper: 1. family:4 — IPv4-only DNS lookup. Avoids the dual-stack race entirely. 2. Hard per-request timeout (10s) — caps total latency per attempt. 3. Retry on transient codes only (ETIMEDOUT/ENOTFOUND/ENETUNREACH/...) — HTTP 4xx/5xx are surfaced as real responses, not retried. The 401 → WWW-Authenticate → token → Bearer auth flow is now explicit in getDockerHubDigest (was previously a side effect of authenticateAndGetDigest, which has been removed — no remaining callers). Verified end-to-end against real Docker Hub: - linuxserver/plex:latest → real digest in 1349ms (was 30s+ AggregateError) - 5-container checkForUpdates() cycle: 3.6s total (was 150s+) - 86/86 update-manager tests pass; 2343/2343 full suite (4 pre-existing pdfkit module-resolution failures unrelated to this change) |
||
|
|
e8b9dd5b91 |
[grade=A] DC-060: replace 49 console.* calls in update-manager.js with structured logger
Replaced all 49 console.log/warn/error calls in src/managers/update-manager.js with log.info/log.warn/log.error from src/utils/logging. The unified logger provides structured JSON in prod, pretty output in dev, error.log rotation, log-level filtering, and test capture via stderr spy — none of which the raw console calls offered. Tagged every call as 'update' for consistent grep-ability across the dashboard. Mixed-content strings (containerName, schedule, imageName, error.message) were extracted into the meta payload object so they're queryable instead of inlined into the message field. 1539/1539 Jest tests pass. ESLint clean for the file (14 pre-existing warnings unchanged, zero new). Codex grade A. |
||
|
|
de3215f704 |
fix(update-manager): add ghcr.io registry support
Previously, /api/v1/updates/available silently skipped any image on a non-Docker-Hub registry (line 154 routing: 'ghcr.io/seerr-team/seerr' has 3 slash-delimited segments → 'Custom registry not yet supported'). Symptoms: 4 of 6 production containers (seerr, albyhub, phoenixd, velxio) all on ghcr.io. UpdateManager would log 'Custom registry not yet supported: ghcr.io/...' and return null. Updates invisible in the Updates modal, even when newer images existed. Fix: - Rewrite image parsing to detect the tag-vs-registry-host colon correctly (lastColon > lastSlash guard, handles ghcr.io:443/path). - Add getGhcrDigest() mirroring the DockerHub pattern, against ghcr.io's OCI distribution endpoint. Same bearer-token auth flow, the existing parseAuthHeader + authenticateAndGetDigest already handle the WWW-Authenticate format ghcr.io returns. - Multiple Accept headers for the response — Docker Hub used manifest.v2 only; GHCR serves manifest.list.v2 for multi-arch tags like ':latest', and the response is the multi-arch manifest itself with the platform-specific digest in the Child header chain. We use the digest from the 'docker-content-digest' response header, which the GHCR endpoint sets even for manifest lists. Verified: UpdateManager log now shows 'Found 6 updates available' on DNS2 (previously 0-2, all from non-Docker-Hub images). /api/v1/updates/available returns entries for seerr, albyhub, etc. Per-tile Update button (core.js:811) + Updates modal Update/Update All (features.js:1508 + L()) are already wired and now functional for all registries. |
||
|
|
f750d01ed0 |
DC-039: route all module file defaults through platformPaths.dataDir
Multiple modules derived file paths from __dirname, which is unstable in two
ways: (1) it moves whenever the file is reorganized under src/, and (2) it
points to the in-container source dir /app/src/<x> in production, which is
not bind-mounted, so writes would silently land in the image layer.
Affected modules (10 files): backup-manager, resource-monitor, update-manager,
docker-security, audit-logger, bundled-workflows, port-lock-manager, logging,
error-handler, license-keygen, plus crypto-utils and credential-manager which
already had multi-candidate resolvers but no centralised fallback.
Introduced platformPaths.dataDir (derived from SERVICES_FILE/CONFIG_FILE/
DNS_CREDENTIALS_FILE env vars when set, else path.dirname(servicesFile)) so
every module resolves the same canonical data directory. Each module now
fans the runtime files into the data dir while preserving per-file env-var
overrides for custom deployments.
Why a single resolver:
- one place to swap the default path scheme in v2.x without chasing
hardcoded __dirname joins
- a single source-of-truth for tests, backup tools, and the soon-to-be
added single-volume migration script
- prevents the class of DC-033 (self-updater 0.0.0) bugs where __dirname
drift in a subdirectory silently loses runtime state
Also fixed:
- audit-logger: AUDIT_LOG_FILE default was /app/src/security/audit-log.json
(writable in dev, image-layer in production). Now /app/data/audit-log.json
via platformPaths.dataDir, matching logging.js's same file. Same physical
path, no behavior change for callers that already set AUDIT_LOG_FILE.
- logging.js: LOG_DIR was __dirname (src/utils/) — error.log and
audit-log.json were being written into the source tree. Now
platformPaths.dataDir, matching every other persistent file.
- error-handler.js: ERROR_LOG_FILE hard-coded to __dirname/error.log
(src/utilities/error.log), redundant with logging.js's own default.
Now platformPaths.dataDir/error.log.
- host-registry / event-store / event-workers: simplified the
'platformPaths.dataDir || path.join(__dirname, ../../data)' pattern
to just platformPaths.dataDir (the legacy fallback is no longer
reachable — services.json lives at dataDir/services.json now).
- public-routes-drift.test.js: added 'routes/security.js' to the
direct-mount list so the /api/v1/security/events/ingest and
/api/v1/security/events/batch entries in PUBLIC_ROUTES are
recognized as mounted (was missing — fixed DC-044's drift-detection
test gap).
Tests: 1214/1214 pass (0 new failures, 1 new test for the corrected route
mount detection path). ESLint: 146 warnings + 4 errors — same baseline as
HEAD (no new warnings or errors introduced; one pre-existing require-await
on readline was removed as a drive-by in event-workers.js since the module
uses line-level fs reads, not readline). Container config files like
audit-log.json, container-stats.json, and workflow-history.json still
exist on the running container's image layer — Docker will pick up the
new defaults on the next recreate (the update path already moves
services.json+config.json+credentials.json via the data bind mount).
|
||
|
|
7bc2a207f3 |
DC-005: Fix all 138 broken test paths after src/ refactor
After the DC-005 module reorganization (41 files moved into src/ subdirs),
138 test suites failed because the refactor script's path-rewrite logic
missed three categories:
1. Files inside src/ doing 'require("./src/...")' — should be 'require("../...")'
2. Files in src/X/Y/ doing 'require("../../../src/...")' — should be 'require("../../...")'
3. Test files in __tests__/ with leftover 'require("../../../src/...")' paths
Root cause: the original refactor script ran before all files were moved,
so it computed relative paths against stale filesystem state.
Result:
- 30/30 test suites pass
- 879/879 tests pass (was: 18/30 suites, 614/687 tests)
Also fixed:
- routes/apps/restore.js: wrong responses import path
- routes/*/*.js: '../../src/utilities/X' → '../src/utilities/X' (depth 2 routes)
|