π fix(watcher): anchor digest comparison to repo-matched RepoDigests candidates - #670
Conversation
β¦candidates A local Docker image can carry multiple repo@digest entries for one Image ID (pull/retag accumulation, no ordering guarantee). getRepoDigest blindly took RepoDigests[0], so a stale or foreign-repo entry landing first anchored digest.repo -> digest.value to the wrong manifest and produced a persistent digest-update false positive that survived applying the update. - π getOrderedRepoDigests filters RepoDigests to entries whose repo component matches the container's own image reference (reusing the imgset docker.io/library aliasing normalization), falling back to the full list when nothing matches - β¨ image.digest.repoDigests (optional, additive) carries the ordered candidate list, re-derived from the live inspect every discovery and refresh cycle - π handleDigestWatch walks every candidate (cheap raw match first, then a poll-cycle-cached normalize-and-compare per anchor, skipping anchors whose manifest fetch fails) and re-anchors digest.repo to the candidate that matched, so a poisoned store self-heals; a genuine same-tag republish still flags an update, and total normalization failure still propagates instead of coercing into a false "no update" - π refresh keeps a stored anchor that is still among the fresh candidates, so it does not ping-pong with the watch-cycle re-anchor Fixes #669
Fresh advisory (CVE-2026-59870 backport gap, quadratic CPU in !!omap resolution) published against js-yaml 3.x < 3.15.1 / 4.x < 4.3.1 turned the qlty medium+ gate red repo-wide. e2e is the only workspace carrying js-yaml (3.15.0, transitive via artillery); exact-version override edited per the established pattern since npm update cannot move overrides.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. π βΉοΈ Recent review infoβοΈ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: π Files selected for processing (2)
π§ Files skipped from review as they are similar to previous changes (2)
π WalkthroughWalkthroughDocker image metadata now stores ordered repository digests. Helpers match digest entries to image-reference candidates and retain fallback ordering. Image orchestration refreshes and preserves valid digest anchors during discovery and updates. V2 digest comparison checks multiple raw and normalized anchors, re-anchors matches, and retains legacy behavior for older data and non-v2 manifests. The E2E package pins Possibly related PRs
π₯ Pre-merge checks | β 2β Passed checks (2 passed)
β¨ Finishing Touchesπ Generate docstrings
π§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
π€ Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/watchers/providers/docker/docker-helpers.ts`:
- Around line 430-440: Update the mapping/filtering flow around the fullDigest
parser to reject entries when either the repository portion or digest portion is
empty, including repo@ and `@sha256`:...; only return entries with both non-empty
components, and add coverage for both cases.
πͺ Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
βΉοΈ Review info
βοΈ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 13fc5e6b-9f10-49d4-9452-90dc6dc3f0df
β Files ignored due to path filters (2)
CHANGELOG.mdis excluded by!CHANGELOG.mde2e/package-lock.jsonis excluded by!**/package-lock.json,!**/package-lock.json
π Files selected for processing (8)
app/model/container.tsapp/watchers/providers/docker/docker-helpers.test.tsapp/watchers/providers/docker/docker-helpers.tsapp/watchers/providers/docker/docker-image-details-orchestration.test.tsapp/watchers/providers/docker/docker-image-details-orchestration.tsapp/watchers/providers/docker/image-comparison.test.tsapp/watchers/providers/docker/image-comparison.tse2e/package.json
β¦component CodeRabbit: repo@ parsed to an empty digest, which passes the model's !== undefined guards and would compare as a phantom change; @sha256:... parsed to an empty repo. Both now filtered with the other malformed shapes.
biggest-littlest
left a comment
There was a problem hiding this comment.
Reviewed the digest-anchor selection change and the CodeRabbit round: candidate filtering falls back safely, the re-anchor path is registry-verified, and failure propagation is preserved. LGTM.
17-file identity roll-forward from rc.12 to rc.13, dated 2026-08-08. - CHANGELOG: new `[1.6.0-rc.13]` section from Unreleased content β #670 digest re-anchoring, #672 self-hosted Star History, #673 nanoid pin, #682 node 24.19.0 + trivy 0.73.0 base-image bumps, #683 icon-bundle alias resolution β plus compare-link rotation - README: version badge + rc.13 highlights block - Demo mocks, site config/content, docs API pages, quickstart, updates highlights, identity-test constants, changelog-link pairs Guarded by `scripts/release-identity.test.mjs` (4/4) and the web scripts suite (56/56). Once merged: devβmain wholesale-tree sync, then dispatch `release-cut.yml` for `v1.6.0-rc.13`. GA candidate clock restarts β earliest GA β Aug 16. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Changelog π§ **Changed** - Advanced the release identity from `1.6.0-rc.12` to `1.6.0-rc.13`, dated August 8, 2026. - Updated README, demo mocks, site configuration, roadmap content, API examples, quickstart, and update highlights. - Updated changelog comparison links and release identity test constants. - Added release notes for digest re-anchoring, self-hosted Star History, `nanoid` pins, Node 24.19.0 and Trivy 0.73.0 base images, and icon-bundle alias resolution. π **Security** - Documented workspace-wide `nanoid` security pinning. - Documented base-image CVE remediation. ## Concerns - Sync the `dev` tree to `main` after merge. - Dispatch `release-cut.yml` for `v1.6.0-rc.13`. - Confirm the expected GA date remains approximately August 16. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Wholesale-tree sync ahead of the v1.6.0-rc.13 cut (same pattern as #667). The single commit carries the exact tree of `dev/v1.6` at b98808e onto `main` β after merge, `git diff --quiet origin/main origin/dev/v1.6` holds. Content on dev since rc.12: - #669/#670 β release-cut digest re-anchoring - #672 β self-hosted Star History chart - #673 β NAS acceptance follow-ups - #681 β v1.7 dependency ordering (forward-ported) - #682 β CVE base-image bumps + digest-pinned Node base guard test - #683 β icon-bundle alias resolution (fixes blank Audit/registry icons shipped in rc.12) - #684 β rc.13 identity roll-forward (17 files, CHANGELOG, README) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Changelog - β¨ Added repository-aware Docker digest selection and multi-anchor comparison. - β¨ Added self-hosted, theme-aware Star History SVG API with pagination, caching, deadlines, and fallback rendering. - β¨ Added icon alias resolution and bundle coverage tests. - β¨ Added required icon bundle entries and updated icon mappings. - π§ Updated Node and Trivy image digests. - π Pinned `nanoid` to `3.3.18` across workspaces. - π Added a digest-pinned Node 24 Alpine base-image guard test. - π§ Updated `js-yaml` override to `3.15.1`. - π§ Updated release documentation, examples, mocks, badges, and tests to `1.6.0-rc.13`. - π§ Removed the external Star History CSP allowlist and embed. ## Concerns - Verify the Star History route stays within GitHub API rate limits under concurrent requests. - Verify cache headers do not serve incomplete or repository-specific fallback responses incorrectly. - Verify Docker digest re-anchoring preserves legacy behavior for stored containers without `repoDigests`. - Verify icon aliases with rotation or flipping have acceptable fallback behavior. - Run the Docker, Star History, icon-bundle, release-identity, and workspace dependency tests. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixes #669 β found by the adversarially-verified digest-pipeline audit behind discussion #657.
The bug
getRepoDigest()blindly tookRepoDigests[0]. A local Docker image can carry multiplerepo@digestentries for one Image ID (pull/retag accumulation, no ordering guarantee), so a stale or foreign-repo entry at index 0 anchoreddigest.repoβdigest.valueto the wrong manifest and produced a persistent digest-update false positive that survived applying the update β the refresh path re-derived from the same index every cycle, so it never self-healed.The fix
getOrderedRepoDigests(docker-helpers): returns RepoDigests entries whose repo component matches the container's own image reference (reusing the imgsetdocker.io/library//registry-1aliasing normalization), in original order; falls back to the full list when nothing matches so behavior never regresses toundefined.image.digest.repoDigests(optional, additive model field): carries the ordered candidate list, re-derived from the live inspect at discovery and on every refresh cycle. Old stored containers lack it and keep single-anchor behavior.handleDigestWatchwalks the candidates: cheap raw-equality check first (no registry call), then a poll-cycle-cached normalize-and-compare per anchor, skipping anchors whose manifest fetch fails (a GC'd manifest is itself evidence the anchor is stale). It re-anchorsdigest.repoto the candidate that matched, so an already-poisoned store self-heals. A genuine same-tag republish (no candidate matches) still flags an update exactly as before; if every candidate fails to normalize, the failure propagates (findNewVersion rejects, watchContainer keeps the previous verdict) instead of coercing into a false "no update" β deliberately avoiding the Manifest "created" fetch failures are swallowed, making result.created nondeterministicΒ #606 anti-pattern.Deliberately untouched:
getRawDigestUpdate/getRawUpdateKind/hasRawUpdate, the watch-decision logic, registry providers, UI.Also in this PR
π Pinned
js-yaml3.15.1 in e2e (override) for GHSA-5p4m-2wfm-xmqj, published mid-soak and turning the qlty medium+ gate red repo-wide β same handling as the rc.12 brace-expansion/ip-address pins. e2e is the only workspace carrying js-yaml.Verification
repoDigestscontainer unchanged, self-heal of a poisoned store, refresh anchor stickiness,version !== 2fallback unchanged.Not GA-gating: 1.5.x-era bug, ships in v1.6.1.
Changelog
RepoDigestsentries.js-yamlto3.15.1in the e2e workspace for GHSA-5p4m-2wfm-xmqj.Concerns
getImageReferenceCandidatesuses the same normalization rules as image-set matching.repoDigestsschema remains compatible with legacy containers that lack the field.