When using combined image:tag@digest references, parse_repository_tag
returns (repo, "tag@digest"). The Docker SDK and API don't accept
tag@digest in the tag parameter, causing "invalid tag format" errors.
This fix:
1. Adds build_pull_arguments() helper function to _util.py
2. Uses the helper in both pull_image implementations
3. When tag contains @ (but isn't a pure digest), passes the full
reference as the repository/fromImage parameter instead of splitting
Tested formats:
- portainer/portainer-ee:2.35.0-alpine@sha256:abc...
- ghcr.io/gethomepage/homepage:v1.7@sha256:abc...
- localhost:5000/myapp:v2.0@sha256:abc...
The existing filter_images_by_tag already handles tag@digest for
lookups, so find_image continues to work correctly.
Includes comprehensive unit tests for build_pull_arguments().
The parse_repository_tag fix alone is not sufficient because Docker stores
RepoTags and RepoDigests separately. When looking up an image with combined
tag@digest (e.g., nginx:1.21@sha256:abc...), the _image_lookup function must
split the combined format and match BOTH RepoTags (for the tag) AND
RepoDigests (for the digest).
Docker stores:
- RepoTags: ["nginx:1.21"]
- RepoDigests: ["nginx@sha256:abc..."]
But NEVER stores the combined format. The previous code would construct:
- lookup = "nginx:1.21@sha256:abc..." (never matches RepoTags)
- lookup_digest = "nginx@1.21@sha256:abc..." (never matches RepoDigests)
This fix:
1. Adds filter_images_by_tag() helper function to _util.py to avoid code
duplication between _common.py and _common_api.py
2. Detects combined tag@digest format in the tag parameter
3. Splits into tag_part and digest_part
4. Constructs proper lookups for both RepoTags and RepoDigests
5. Requires BOTH to match for successful image lookup
Without this fix, image_label_mismatch: ignore fails because the image
cannot be found, resulting in no image labels being included in expected
labels comparison.
Includes comprehensive unit tests in test__util.py covering all scenarios
including edge cases for multiple @ symbols and empty tag parts.
* Re-enable typing and improve config.
* Make mypy pass.
* Improve settings.
* First batch of types.
* Add more type hints.
* Fixes.
* Format.
* Fix split_port() without returning to previous type chaos.
* Continue with type hints (and ignores).
* Remove __metaclass__ = type.
for i in $(grep -REl '__metaclass__ = type' plugins/ tests/); do
sed -e '/^__metaclass__ = type/d' -i $i;
done
* Remove super arguments, and stop inheriting from object.
* Make all doc fragments, module utils, and plugin utils private.
* Remove some unused and no longer needed imports.
This hopefully also fixes the CI issues, which do not happen locally for me...
* Fix formatting.
* Try to make CI happy, again.
* Fix imports.
* Lint.