fix(icon): serve icons from cache and repair Docker Manager icon cache - #144
Conversation
Stabilize stack lifecycle, improve update accuracy, and expand E2E safety coverage
There was a problem hiding this comment.
🟡 Changes recommended
There are concrete reliability/concurrency issues in the new cache/seed file-writing logic (non-atomic cache writes and non-unique temp filenames) plus test cleanup gaps that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR hardens icon handling by ensuring only valid PNG bytes are cached/served, routing eligible icon sources through a cache proxy, and repairing Docker Manager’s icon cache/metadata so broken icons don’t permanently stick.
Changes:
- Add PNG validation + staleness rules to the icon cache, and serve icons strictly from cached PNGs via
IconCache.php. - Seed/repair Docker Manager icon files and
docker.jsonmetadata based on the plugin cache (including container-context routing from UI). - Extend unit tests and test bootstrap constants to cover Docker Manager icon repair flows.
File summaries
| File | Description |
|---|---|
| tests/unit/StackInfoTest.php | Adds tests for replacing corrupt DM icon files and repairing docker.json icon metadata; updates constants usage. |
| tests/bootstrap.php | Defines temp paths for Docker Manager icon RAM/persist dirs and docker.json in unit tests. |
| source/compose.manager/README.md | Removes “(Beta)” label from plugin name. |
| source/compose.manager/javascript/composeManagerMain.js | Routes eligible icon sources through IconCache.php and passes container context when available. |
| source/compose.manager/include/Util.php | Adds PNG detection/staleness helpers; enforces PNG-only caching; seeds/repairs Docker Manager icons and metadata. |
| source/compose.manager/include/Exec.php | Seeds Docker Manager icon cache during container icon resolution. |
| source/compose.manager/include/Defines.php | Adds constants for DM icon paths and the net.unraid.docker.icon label key. |
| source/compose.manager/IconCache.php | Serves only from cache, supports refresh, and optionally repairs DM icon cache/metadata for a container. |
| source/compose.manager/compose.manager.dashboard.page | Passes container name into composeIconSrc() so the cache proxy can repair DM cache. |
| compose.manager.plg | Updates version/pluginURL and changelog entry for the release. |
Review details
Suppressed comments (2)
tests/unit/StackInfoTest.php:782
- This test replaces a corrupt RAM icon but doesn’t remove the corresponding persistent Docker Manager icon file that may also be created by compose_seed_docker_manager_icon(). Cleaning both locations keeps the test isolated.
$this->assertTrue(compose_file_is_png($ramPath), 'corrupt Docker Manager icon must be replaced with real PNG');
@unlink($ramPath);
}
tests/unit/StackInfoTest.php:813
- This cleanup removes the RAM icon and docker.json, but compose_seed_docker_manager_icon() also writes a persistent icon file. Remove that as well to avoid cross-test pollution in the temp COMPOSE_DM_ICON_PERSIST_DIR.
@unlink(COMPOSE_DM_ICON_RAM_DIR . '/' . $name . '-icon.png');
@unlink(COMPOSE_DM_WEBUI_INFO_FILE);
}
- Files reviewed: 10/10 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
A failed refresh could truncate a previously good cache entry, and the shared `<dest>.tmp` name let concurrent seeds race on the same path. - Write the icon cache through a unique temp file and rename into place - Use a per-destination unique temp file when seeding Docker Manager - chmod 0644 before rename since tempnam() creates files as 0600 Refs #129
Seeding writes a persistent copy as well as the RAM one, so tests left files behind and could become order-dependent. Refs #129
Three separate refactors shared one bullet, breaking the one-change-per- line format of the surrounding release notes.
Docker Manager downloads net.unraid.docker.icon URLs verbatim, so an SVG
source left raw SVG bytes in -icon.png. The browser could not
render that file and fell back to question.png, which docker.json then
recorded permanently because DM only re-resolves an icon when the stored
path is missing.
conversion result that is not a real PNG
staleness, or corrupt entries, and keep the last good PNG when a
refresh fails
instead of skipping any existing file, using an atomic write
the label URL and stops sticking to question.png
populated, and pass container context from the stack and dashboard
views so both caches stay aligned
proxy in PHP and JS
Fixes #129