✨ feat(ui): display-honesty batch — update-status vocabulary, pin glyph, one-clock maturity panel#566
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThe changes centralize maturity-clock resolution, expose backend maturity metadata, and add shared pin-gate governance. Frontend container types, mapping, status panels, badges, update-kind labels, responsive column pickers, registry search, tooltips, and dashboard freshness calculations were updated. Localizations now reflect revised maturity, pinned-tag, security-hold, update-kind, and pluralized banner text. Tests cover backend decisions, frontend rendering, localization, and edge cases. 🚥 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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
ui/src/locales/ja/containerComponents.json (2)
199-203: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRestore or replace
blockedByBouncerbefore removing it.ContainersGroupedViews.vuestill requests this key.
ui/src/locales/ja/containerComponents.json#L199-L203: preserve or replace the grouped-view bouncer label.ui/src/locales/ko/containerComponents.json#L201-L201: preserve or replace the grouped-view bouncer label.ui/src/locales/nl/containerComponents.json#L200-L201: preserve or replace the grouped-view bouncer label.ui/src/locales/pl/containerComponents.json#L198-L203: preserve or replace the grouped-view bouncer label.ui/src/locales/pt-BR/containerComponents.json#L198-L203: preserve or replace the grouped-view bouncer label.ui/src/locales/ru/containerComponents.json#L199-L204: preserve or replace the grouped-view bouncer label.ui/src/locales/tr/containerComponents.json#L198-L201: preserve or replace the grouped-view bouncer label.ui/src/locales/uk/containerComponents.json#L198-L201: preserve or replace the grouped-view bouncer label.ui/src/locales/vi/containerComponents.json#L198-L203: preserve or replace the grouped-view bouncer label.ui/src/locales/zh-CN/containerComponents.json#L201-L201: preserve or replace the grouped-view bouncer label.🤖 Prompt for 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. In `@ui/src/locales/ja/containerComponents.json` around lines 199 - 203, Restore or replace the blockedByBouncer translation key used by ContainersGroupedViews.vue in ui/src/locales/ja/containerComponents.json lines 199-203, ui/src/locales/ko/containerComponents.json lines 201-201, ui/src/locales/nl/containerComponents.json lines 200-201, ui/src/locales/pl/containerComponents.json lines 198-203, ui/src/locales/pt-BR/containerComponents.json lines 198-203, ui/src/locales/ru/containerComponents.json lines 199-204, ui/src/locales/tr/containerComponents.json lines 198-201, ui/src/locales/uk/containerComponents.json lines 198-201, ui/src/locales/vi/containerComponents.json lines 198-203, and ui/src/locales/zh-CN/containerComponents.json lines 201-201, preserving the grouped-view bouncer label in each locale.
475-477: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winKeep the
updateAgecontract synchronized withupdate-maturity.ts. The formatter still resolvescontainerComponents.updateAge.available*andjustNow.
ui/src/locales/ja/containerComponents.json#L475-L477: restore the required age translations or update the formatter.ui/src/locales/ko/containerComponents.json#L478-L478: restore the required age translations or update the formatter.ui/src/locales/nl/containerComponents.json#L477-L478: restore the required age translations or update the formatter.ui/src/locales/pl/containerComponents.json#L475-L478: restore the required age translations or update the formatter.ui/src/locales/pt-BR/containerComponents.json#L470-L478: restore the required age translations or update the formatter.ui/src/locales/ru/containerComponents.json#L477-L478: restore the required age translations or update the formatter.ui/src/locales/tr/containerComponents.json#L474-L478: restore the required age translations or update the formatter.ui/src/locales/uk/containerComponents.json#L477-L478: restore the required age translations or update the formatter.ui/src/locales/vi/containerComponents.json#L476-L479: restore the required age translations or update the formatter.ui/src/locales/zh-CN/containerComponents.json#L478-L478: restore the required age translations or update the formatter.🤖 Prompt for 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. In `@ui/src/locales/ja/containerComponents.json` around lines 475 - 477, Synchronize the updateAge locale contract with the formatter in update-maturity.ts by restoring translations for all required containerComponents.updateAge.available* keys and justNow. Apply the same correction in ui/src/locales/ja/containerComponents.json lines 475-477, ui/src/locales/ko/containerComponents.json line 478, ui/src/locales/nl/containerComponents.json lines 477-478, ui/src/locales/pl/containerComponents.json lines 475-478, ui/src/locales/pt-BR/containerComponents.json lines 470-478, ui/src/locales/ru/containerComponents.json lines 477-478, ui/src/locales/tr/containerComponents.json lines 474-478, ui/src/locales/uk/containerComponents.json lines 477-478, ui/src/locales/vi/containerComponents.json lines 476-479, and ui/src/locales/zh-CN/containerComponents.json line 478; preserve the formatter’s existing key expectations rather than removing or renaming them.ui/src/utils/container-mapper.ts (1)
516-555: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winDuplicate backend-verdict logic — see consolidated comment.
findBackendMaturityBlockedhere is duplicated (with a gating divergence) inui/src/views/containers/useContainerPolicy.ts. Addressed in the consolidated comment below.🤖 Prompt for 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. In `@ui/src/utils/container-mapper.ts` around lines 516 - 555, Remove the duplicated findBackendMaturityBlocked logic from isMaturityBlocked and reuse the consolidated backend-verdict helper shared with useContainerPolicy. Ensure both callers apply identical gating and return undefined when eligibility blockers are unavailable, preserving the fallback maturity heuristic only when no backend verdict exists.
🧹 Nitpick comments (1)
ui/src/utils/update-maturity.ts (1)
31-55: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTriplicated singular/plural key selection — extract a helper.
The days/hours/minutes branches repeat the same
t ? (count === 1 ? singular : plural) : fallbackshape three times.♻️ Proposed refactor
+function pluralDuration( + count: number, + singularKey: string, + pluralKey: string, + fallbackUnit: string, + t?: TranslateFn, +): string { + if (t) { + return count === 1 ? t(singularKey) : t(pluralKey, { count }); + } + return `${count} ${fallbackUnit}${count === 1 ? '' : 's'}`; +} + let duration: string | undefined; if (days > 0) { - duration = t - ? days === 1 - ? t('containerComponents.updateAge.availableDaysSingular') - : t('containerComponents.updateAge.availableDaysPlural', { count: days }) - : `${days} day${days === 1 ? '' : 's'}`; + duration = pluralDuration( + days, + 'containerComponents.updateAge.availableDaysSingular', + 'containerComponents.updateAge.availableDaysPlural', + 'day', + t, + ); } else if (hours > 0) { - duration = t - ? hours === 1 - ? t('containerComponents.updateAge.availableHoursSingular') - : t('containerComponents.updateAge.availableHoursPlural', { count: hours }) - : `${hours} hour${hours === 1 ? '' : 's'}`; + duration = pluralDuration( + hours, + 'containerComponents.updateAge.availableHoursSingular', + 'containerComponents.updateAge.availableHoursPlural', + 'hour', + t, + ); } else if (minutes > 0) { - duration = t - ? minutes === 1 - ? t('containerComponents.updateAge.availableMinutesSingular') - : t('containerComponents.updateAge.availableMinutesPlural', { count: minutes }) - : `${minutes} minute${minutes === 1 ? '' : 's'}`; + duration = pluralDuration( + minutes, + 'containerComponents.updateAge.availableMinutesSingular', + 'containerComponents.updateAge.availableMinutesPlural', + 'minute', + t, + ); }🤖 Prompt for 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. In `@ui/src/utils/update-maturity.ts` around lines 31 - 55, Extract the repeated singular/plural translation and fallback selection from the duration branches into a helper near the existing duration logic, parameterized by count, singular key, plural key, and fallback text. Update the days, hours, and minutes branches to use this helper while preserving their current translation keys, counts, and singular/plural fallback behavior.
🤖 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 `@ui/src/components/containers/ContainersGroupedViews.vue`:
- Around line 372-397: Centralize UPDATE_KIND_LABEL_KEYS and the robust
getUpdateKindLabel implementation in useContainersViewTemplateContext or a
shared utility, then remove the duplicated definition from
ContainersGroupedViews.vue. In
ui/src/components/containers/ContainersGroupedViews.vue lines 372-397, use the
shared implementation; in
ui/src/components/containers/ContainerFullPageOverviewTab.vue lines 131-132,
replace the raw updateKind span with an AppBadge using the shared localized
label; in ui/src/components/containers/ContainerFullPageTabContent.vue lines
320-328 and ui/src/components/containers/ContainerSideTabContent.vue lines
313-319, replace each local resolver with the shared utility while preserving
the unknown-kind fallback.
In `@ui/src/locales/ja/containerComponents.json`:
- Line 539: Define the missing groupedViews.pinnedLabel key alongside
pinnedTooltip in each affected locale:
ui/src/locales/ja/containerComponents.json (539-539),
ui/src/locales/ko/containerComponents.json (539-539),
ui/src/locales/nl/containerComponents.json (539-539),
ui/src/locales/pl/containerComponents.json (539-540),
ui/src/locales/pt-BR/containerComponents.json (539-539),
ui/src/locales/ru/containerComponents.json (539-539),
ui/src/locales/tr/containerComponents.json (539-540),
ui/src/locales/uk/containerComponents.json (539-540),
ui/src/locales/vi/containerComponents.json (539-539), and
ui/src/locales/zh-CN/containerComponents.json (539-539). Use the established
translation structure and provide the appropriate localized pinned-summary label
in every file so useUpdateStatus.ts can resolve
containerComponents.groupedViews.pinnedLabel.
In `@ui/src/views/containers/useContainerPolicy.ts`:
- Around line 152-170: Remove the duplicate findBackendMaturityBlocked
implementation from useContainerPolicy.ts and reuse the existing shared utility
from container-mapper.ts instead. Update its callers/imports so backend maturity
verdict handling remains centralized and follows the consolidated gating
behavior.
---
Outside diff comments:
In `@ui/src/locales/ja/containerComponents.json`:
- Around line 199-203: Restore or replace the blockedByBouncer translation key
used by ContainersGroupedViews.vue in ui/src/locales/ja/containerComponents.json
lines 199-203, ui/src/locales/ko/containerComponents.json lines 201-201,
ui/src/locales/nl/containerComponents.json lines 200-201,
ui/src/locales/pl/containerComponents.json lines 198-203,
ui/src/locales/pt-BR/containerComponents.json lines 198-203,
ui/src/locales/ru/containerComponents.json lines 199-204,
ui/src/locales/tr/containerComponents.json lines 198-201,
ui/src/locales/uk/containerComponents.json lines 198-201,
ui/src/locales/vi/containerComponents.json lines 198-203, and
ui/src/locales/zh-CN/containerComponents.json lines 201-201, preserving the
grouped-view bouncer label in each locale.
- Around line 475-477: Synchronize the updateAge locale contract with the
formatter in update-maturity.ts by restoring translations for all required
containerComponents.updateAge.available* keys and justNow. Apply the same
correction in ui/src/locales/ja/containerComponents.json lines 475-477,
ui/src/locales/ko/containerComponents.json line 478,
ui/src/locales/nl/containerComponents.json lines 477-478,
ui/src/locales/pl/containerComponents.json lines 475-478,
ui/src/locales/pt-BR/containerComponents.json lines 470-478,
ui/src/locales/ru/containerComponents.json lines 477-478,
ui/src/locales/tr/containerComponents.json lines 474-478,
ui/src/locales/uk/containerComponents.json lines 477-478,
ui/src/locales/vi/containerComponents.json lines 476-479, and
ui/src/locales/zh-CN/containerComponents.json line 478; preserve the formatter’s
existing key expectations rather than removing or renaming them.
In `@ui/src/utils/container-mapper.ts`:
- Around line 516-555: Remove the duplicated findBackendMaturityBlocked logic
from isMaturityBlocked and reuse the consolidated backend-verdict helper shared
with useContainerPolicy. Ensure both callers apply identical gating and return
undefined when eligibility blockers are unavailable, preserving the fallback
maturity heuristic only when no backend verdict exists.
---
Nitpick comments:
In `@ui/src/utils/update-maturity.ts`:
- Around line 31-55: Extract the repeated singular/plural translation and
fallback selection from the duration branches into a helper near the existing
duration logic, parameterized by count, singular key, plural key, and fallback
text. Update the days, hours, and minutes branches to use this helper while
preserving their current translation keys, counts, and singular/plural fallback
behavior.
🪄 Autofix (Beta)
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: 4b2a0783-a4e6-4903-ace5-bd5b21366c88
📒 Files selected for processing (65)
app/model/maturity-policy.test.tsapp/model/maturity-policy.tsapp/model/update-eligibility.test.tsapp/model/update-eligibility.tsui/src/components/DataTableColumnPicker.vueui/src/components/containers/ContainerFullPageOverviewTab.vueui/src/components/containers/ContainerFullPageTabContent.vueui/src/components/containers/ContainerSideTabContent.vueui/src/components/containers/ContainersGroupedViews.vueui/src/components/containers/ContainersListContent.vueui/src/components/containers/UpdateMaturityBadge.vueui/src/components/containers/UpdateStatusPanel.vueui/src/components/containers/containersViewTemplateContext.tsui/src/composables/useUpdateStatus.tsui/src/locales/ar/containerComponents.jsonui/src/locales/de/containerComponents.jsonui/src/locales/en/containerComponents.jsonui/src/locales/en/sharedComponents.jsonui/src/locales/es/containerComponents.jsonui/src/locales/fr/containerComponents.jsonui/src/locales/it/containerComponents.jsonui/src/locales/ja/containerComponents.jsonui/src/locales/ko/containerComponents.jsonui/src/locales/nl/containerComponents.jsonui/src/locales/pl/containerComponents.jsonui/src/locales/pt-BR/containerComponents.jsonui/src/locales/ru/containerComponents.jsonui/src/locales/tr/containerComponents.jsonui/src/locales/uk/containerComponents.jsonui/src/locales/vi/containerComponents.jsonui/src/locales/zh-CN/containerComponents.jsonui/src/locales/zh-TW/containerComponents.jsonui/src/types/container.d.tsui/src/utils/container-mapper.tsui/src/utils/dashboard-container-metrics.tsui/src/utils/display.tsui/src/utils/update-maturity.tsui/src/views/ContainersView.vueui/src/views/containers/useContainerPolicy.tsui/tests/boot/i18n.spec.tsui/tests/components/ContainerSideTabContent.spec.tsui/tests/components/DataTableColumnPicker.spec.tsui/tests/components/containers/ContainersGroupedViews.button-states.spec.tsui/tests/components/containers/ContainersGroupedViews.spec.tsui/tests/components/containers/ContainersListContent.spec.tsui/tests/components/containers/UpdateMaturityBadge.spec.tsui/tests/components/containers/UpdateStatusPanel.spec.tsui/tests/composables/useContainerFilters.spec.tsui/tests/composables/useDetailPanel.spec.tsui/tests/composables/useOperationDisplayHold.spec.tsui/tests/composables/useUpdateStatus.spec.tsui/tests/composables/useVulnerabilities.spec.tsui/tests/utils/container-mapper.spec.tsui/tests/utils/dashboard-container-metrics.spec.tsui/tests/utils/display.spec.tsui/tests/utils/hide-pinned.spec.tsui/tests/utils/update-maturity.spec.tsui/tests/views/ContainersView.applyContainerPatch.spec.tsui/tests/views/ContainersView.spec.tsui/tests/views/DashboardView.spec.tsui/tests/views/containers/useContainerActions.spec.tsui/tests/views/containers/useContainerLogs.spec.tsui/tests/views/containers/useContainerPolicy.spec.tsui/tests/views/dashboard/useDashboardComputed.spec.tsui/tests/views/dashboard/useDashboardData.spec.ts
💤 Files with no reviewable changes (17)
- ui/tests/composables/useDetailPanel.spec.ts
- ui/tests/composables/useContainerFilters.spec.ts
- ui/src/components/containers/UpdateMaturityBadge.vue
- ui/tests/components/containers/UpdateMaturityBadge.spec.ts
- ui/tests/components/containers/ContainersGroupedViews.button-states.spec.ts
- ui/tests/views/dashboard/useDashboardComputed.spec.ts
- ui/tests/components/ContainerSideTabContent.spec.ts
- ui/tests/utils/hide-pinned.spec.ts
- ui/tests/views/containers/useContainerLogs.spec.ts
- ui/tests/views/dashboard/useDashboardData.spec.ts
- ui/tests/views/containers/useContainerActions.spec.ts
- ui/tests/views/ContainersView.applyContainerPatch.spec.ts
- ui/tests/composables/useOperationDisplayHold.spec.ts
- ui/tests/views/ContainersView.spec.ts
- ui/tests/views/DashboardView.spec.ts
- ui/src/types/container.d.ts
- ui/tests/composables/useVulnerabilities.spec.ts
…erdict lookup - Extract shared update-kind-labels.ts (map, localized resolver with unknown-kind fallback, hasUnresolvedUpdateKind) and consume it from ContainersGroupedViews, ContainerFullPageTabContent, ContainerSideTabContent, ContainerFullPageDetail, and ContainerFullPageOverviewTab — the last of which previously rendered the raw updateKind string with no localization at all - Dedupe findBackendMaturityBlocked() into update-eligibility.ts; container-mapper.ts and useContainerPolicy.ts now import the shared function and keep their existing outer gating (maturityMode check / unconditional verdict use) unchanged - Extract a private formatDurationUnit() helper in update-maturity.ts to collapse the triplicated day/hour/minute t()-vs-fallback branches Addresses CodeRabbit review comments on PR #566.
|
Outside-diff and nitpick sweep:
While fixing the label duplication we also found and folded in a fourth local |
…erdict lookup - Extract shared update-kind-labels.ts (map, localized resolver with unknown-kind fallback, hasUnresolvedUpdateKind) and consume it from ContainersGroupedViews, ContainerFullPageTabContent, ContainerSideTabContent, ContainerFullPageDetail, and ContainerFullPageOverviewTab — the last of which previously rendered the raw updateKind string with no localization at all - Dedupe findBackendMaturityBlocked() into update-eligibility.ts; container-mapper.ts and useContainerPolicy.ts now import the shared function and keep their existing outer gating (maturityMode check / unconditional verdict use) unchanged - Extract a private formatDurationUnit() helper in update-maturity.ts to collapse the triplicated day/hour/minute t()-vs-fallback branches Addresses CodeRabbit review comments on PR #566.
cf91ade to
3d86839
Compare
…delta (#569) ## What Docs/copy freshness pass for the v1.6.1 delta (the #567 security batch, the #566 display batch, and the #568 maturity-clock fix). 30 findings from an adversarially-verified audit workflow (8 surface auditors, every finding independently re-verified against the shipped code before it counted; 1 rejected in verification), applied as one coherent edit per doc region: - **Anonymous-auth fail-closed (A1)**: the authentications page (callout, behavior matrix, and the "Upgrading from v1.3.x" section), the security guide, the README banner + quickstart line, and DEPRECATIONS.md all still promised upgraders a warn-and-serve grace period. Rewritten everywhere: upgrades now fail closed exactly like fresh installs; `DD_ANONYMOUS_AUTH_CONFIRM=true` is the opt-in. - **Session cookie rename (A4)**: `connect.sid` → `drydock.sid` one-time sign-out documented in DEPRECATIONS.md, the upgrading section, and the README banner. - **SSRF hardening (A2)**: the HTTP trigger page now documents the guarded DNS lookup, redirect refusal, and the `ALLOWMETADATA` escape hatch. - **WebSocket origin checks (A3)**: server config, FAQ, quickstart reverse-proxy warning, `api/log.mdx`, and `api/container.mdx` now state that origin validation covers scheme/host/port and that forwarded headers are honored only with `DD_SERVER_TRUSTPROXY`. - **UI vocabulary (B3/B4/B5)**: watchers page and FAQ updated for the pin-glyph/"Current" pinned treatment; eligibility + API docs document the new additive `clockSource`/`clockStartAt` blocker fields; the UI page covers the column-picker auto-hidden annotation. Wording grounded in the actual #566 locale strings, not paraphrased. - **Website quickstarts actually start**: the shared `DockerRunSnippet` (all 7 comparison pages) and the FAQ quickstart now include the auth opt-in env var — without it the one-liner produces a container that refuses to start on the v1.6 line. Also rides along: `protobufjs` pinned to 7.6.5 (CVE-2026-59877 / GHSA-j3f2-48v5-ccww, third fresh advisory today) in app (new override) and e2e (existing override bumped) — it began failing the qlty osv-scanner gate mid-push. Deliberately skipped: `content/docs/current/updates/index.mdx` (strictly per-release curated notes; rc.3 highlights belong to the actual cut) and `UPGRADE-NOTES.md` (version-gated to 1.4.6–1.5.x by `scripts/append-upgrade-notes.mjs`; v1.6 content there would leak into 1.5.x release notes). ## Why The security batch merged with zero docs changes, leaving the auth docs actively contradicting shipped behavior. Docs on `dev/v1.6` publish at the GA dev→main merge, so these corrections go live exactly when the behavior does. ## Tests Full pre-push gate green. apps/web script tests 43/43; MDX parse validated via sync-docs + fumadocs-mdx; biome clean. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Changelog - 🔒 Documented fail-closed anonymous authentication for both fresh installs and upgrades; require `DD_ANONYMOUS_AUTH_CONFIRM=true` (and clarified `/health` vs API response behavior). -⚠️ Security documented “no deprecation window” enforcement: removed upgrade grandfather path when anonymous auth isn’t configured/confirmed; upgrades stop serving/fail closed. -⚠️ 🔒 Documented `connect.sid` → `drydock.sid` session cookie rename and one-time sign-out on upgrade. - 🔒 Documented SSRF protections for guarded DNS lookup, redirect refusal (3xx never followed), and `ALLOWMETADATA` escape hatch. - 🔒 Documented WebSocket `Origin` validation (scheme/host/port) and clarified reverse-proxy requirements via `DD_SERVER_TRUSTPROXY` + forwarded headers (`X-Forwarded-Proto`/`X-Forwarded-Host`), including log-stream connection failures when misconfigured. - ✨ Documented maturity-clock details for `maturity-not-reached` (clock source + ISO-8601 start timestamp payload) and UI countdown rendering behavior. - ✨ Updated UI copy/annotations for column visibility and “hidden to fit” behavior. - ✨ Updated watcher UI description for fully-pinned tags to reflect `updateInsight` chip styling + persistent pin glyph/tooltips. - 🔧 Added `DD_ANONYMOUS_AUTH_CONFIRM=true` to website quickstarts and updated Docker run snippet wording. - 🔧 Pinned `protobufjs` to `7.6.5` in both app and e2e dependencies. - 🔧 Updated doc identity/release tests to assert current fail-closed semantics for `content/docs/current` while preserving legacy v1.5 behavior. ## Concerns - Confirm `DD_SERVER_TRUSTPROXY` docs explicitly require forwarding `X-Forwarded-Proto` and `X-Forwarded-Host` for scheme/host matching. - Validate that the documented fail-closed behavior matches the actual endpoints: API 401 behavior vs `/health` 503 reporting. - Ensure the “redirects never followed” documentation aligns with the actual redirect-following disablement and how `ALLOWMETADATA` is evaluated. - Verify cookie rename handling is documented consistently across all relevant upgrade/install docs (including one-time sign-out semantics). - Check that WebSocket origin validation requirements cover both dashboard log viewer and container log streaming endpoints (upgrade vs steady-state behavior). <!-- end of auto-generated comment: release notes by coderabbit.ai -->
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@ui/src/locales/ar/appShell.json`:
- Around line 160-161: Remove the manually seeded legacyApiPathTitleSingular and
legacyApiPathTitlePlural keys from ui/src/locales/ar/appShell.json lines
160-161, ui/src/locales/de/appShell.json lines 160-161,
ui/src/locales/es/appShell.json lines 160-161,
ui/src/locales/zh-CN/appShell.json lines 160-161, and
ui/src/locales/zh-TW/appShell.json lines 160-161; rely on fallbackLocale to
provide the English values.
In `@ui/src/locales/fr/appShell.json`:
- Around line 160-161: Remove the legacyApiPathTitleSingular and
legacyApiPathTitlePlural entries from ui/src/locales/fr/appShell.json (160-161),
ui/src/locales/it/appShell.json (160-161), ui/src/locales/ja/appShell.json
(160-161), ui/src/locales/ko/appShell.json (160-161),
ui/src/locales/nl/appShell.json (160-161), ui/src/locales/pl/appShell.json
(160-161), ui/src/locales/pt-BR/appShell.json (160-161),
ui/src/locales/ru/appShell.json (160-161), and ui/src/locales/tr/appShell.json
(160-161). Leave these keys absent so fallbackLocale supplies the English values
until Crowdin provides translations.
In `@ui/src/locales/uk/appShell.json`:
- Around line 160-161: Remove the manually seeded English keys
legacyApiPathTitleSingular and legacyApiPathTitlePlural from
ui/src/locales/uk/appShell.json lines 160-161 and
ui/src/locales/vi/appShell.json lines 160-161; rely on the runtime English
fallback so Crowdin can manage these translations.
🪄 Autofix (Beta)
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: 62344200-47d9-4dec-bc77-f143cd6a67ea
⛔ Files ignored due to path filters (3)
CHANGELOG.mdis excluded by!CHANGELOG.mdapp/package-lock.jsonis excluded by!**/package-lock.json,!**/package-lock.jsone2e/package-lock.jsonis excluded by!**/package-lock.json,!**/package-lock.json
📒 Files selected for processing (102)
app/model/container.test.tsapp/model/container.tsapp/model/maturity-policy.test.tsapp/model/maturity-policy.tsapp/model/update-eligibility.test.tsapp/model/update-eligibility.tsapp/package.jsonapp/tag/family.test.tsapp/tag/family.tsapp/watchers/providers/docker/tag-candidates.tse2e/package.jsonui/src/components/DataTableColumnPicker.vueui/src/components/containers/ContainerFullPageDetail.vueui/src/components/containers/ContainerFullPageOverviewTab.vueui/src/components/containers/ContainerFullPageTabContent.vueui/src/components/containers/ContainerSideTabContent.vueui/src/components/containers/ContainersGroupedViews.vueui/src/components/containers/ContainersListContent.vueui/src/components/containers/UpdateMaturityBadge.vueui/src/components/containers/UpdateStatusPanel.vueui/src/components/containers/containersViewTemplateContext.tsui/src/composables/useUpdateStatus.tsui/src/directives/tooltip.tsui/src/layouts/AppLayout.vueui/src/locales/ar/appShell.jsonui/src/locales/ar/containerComponents.jsonui/src/locales/de/appShell.jsonui/src/locales/de/containerComponents.jsonui/src/locales/en/appShell.jsonui/src/locales/en/containerComponents.jsonui/src/locales/en/sharedComponents.jsonui/src/locales/es/appShell.jsonui/src/locales/es/containerComponents.jsonui/src/locales/fr/appShell.jsonui/src/locales/fr/containerComponents.jsonui/src/locales/it/appShell.jsonui/src/locales/it/containerComponents.jsonui/src/locales/ja/appShell.jsonui/src/locales/ja/containerComponents.jsonui/src/locales/ko/appShell.jsonui/src/locales/ko/containerComponents.jsonui/src/locales/nl/appShell.jsonui/src/locales/nl/containerComponents.jsonui/src/locales/pl/appShell.jsonui/src/locales/pl/containerComponents.jsonui/src/locales/pt-BR/appShell.jsonui/src/locales/pt-BR/containerComponents.jsonui/src/locales/ru/appShell.jsonui/src/locales/ru/containerComponents.jsonui/src/locales/tr/appShell.jsonui/src/locales/tr/containerComponents.jsonui/src/locales/uk/appShell.jsonui/src/locales/uk/containerComponents.jsonui/src/locales/vi/appShell.jsonui/src/locales/vi/containerComponents.jsonui/src/locales/zh-CN/appShell.jsonui/src/locales/zh-CN/containerComponents.jsonui/src/locales/zh-TW/appShell.jsonui/src/locales/zh-TW/containerComponents.jsonui/src/types/container.d.tsui/src/utils/container-mapper.tsui/src/utils/dashboard-container-metrics.tsui/src/utils/display.tsui/src/utils/update-eligibility.tsui/src/utils/update-kind-labels.tsui/src/utils/update-maturity.tsui/src/views/ContainersView.vueui/src/views/RegistriesView.vueui/src/views/containers/useContainerPolicy.tsui/tests/boot/i18n.spec.tsui/tests/components/ContainerSideTabContent.spec.tsui/tests/components/DataTableColumnPicker.spec.tsui/tests/components/containers/ContainerFullPageDetail.spec.tsui/tests/components/containers/ContainerFullPageOverviewTab.spec.tsui/tests/components/containers/ContainerFullPageTabContent.spec.tsui/tests/components/containers/ContainersGroupedViews.button-states.spec.tsui/tests/components/containers/ContainersGroupedViews.spec.tsui/tests/components/containers/ContainersListContent.spec.tsui/tests/components/containers/UpdateMaturityBadge.spec.tsui/tests/components/containers/UpdateStatusPanel.spec.tsui/tests/composables/useContainerFilters.spec.tsui/tests/composables/useDetailPanel.spec.tsui/tests/composables/useOperationDisplayHold.spec.tsui/tests/composables/useUpdateStatus.spec.tsui/tests/composables/useVulnerabilities.spec.tsui/tests/directives/tooltip.spec.tsui/tests/utils/container-mapper.spec.tsui/tests/utils/dashboard-container-metrics.spec.tsui/tests/utils/display.spec.tsui/tests/utils/hide-pinned.spec.tsui/tests/utils/update-eligibility.spec.tsui/tests/utils/update-kind-labels.spec.tsui/tests/utils/update-maturity.spec.tsui/tests/views/ContainersView.applyContainerPatch.spec.tsui/tests/views/ContainersView.spec.tsui/tests/views/DashboardView.spec.tsui/tests/views/RegistriesView.spec.tsui/tests/views/containers/useContainerActions.spec.tsui/tests/views/containers/useContainerLogs.spec.tsui/tests/views/containers/useContainerPolicy.spec.tsui/tests/views/dashboard/useDashboardComputed.spec.tsui/tests/views/dashboard/useDashboardData.spec.ts
💤 Files with no reviewable changes (15)
- ui/tests/views/ContainersView.applyContainerPatch.spec.ts
- ui/tests/views/containers/useContainerLogs.spec.ts
- ui/tests/utils/hide-pinned.spec.ts
- ui/tests/composables/useDetailPanel.spec.ts
- ui/src/components/containers/UpdateMaturityBadge.vue
- ui/tests/composables/useContainerFilters.spec.ts
- ui/tests/components/containers/UpdateMaturityBadge.spec.ts
- ui/tests/composables/useOperationDisplayHold.spec.ts
- ui/tests/views/dashboard/useDashboardData.spec.ts
- ui/tests/views/ContainersView.spec.ts
- ui/tests/views/dashboard/useDashboardComputed.spec.ts
- ui/tests/components/containers/ContainersGroupedViews.button-states.spec.ts
- ui/tests/views/DashboardView.spec.ts
- ui/tests/views/containers/useContainerActions.spec.ts
- ui/tests/composables/useVulnerabilities.spec.ts
🚧 Files skipped from review as they are similar to previous changes (41)
- ui/src/locales/en/sharedComponents.json
- ui/tests/boot/i18n.spec.ts
- ui/src/components/containers/containersViewTemplateContext.ts
- ui/src/components/DataTableColumnPicker.vue
- ui/src/components/containers/UpdateStatusPanel.vue
- ui/tests/composables/useUpdateStatus.spec.ts
- ui/src/composables/useUpdateStatus.ts
- app/model/maturity-policy.ts
- ui/tests/utils/display.spec.ts
- ui/src/utils/display.ts
- ui/tests/components/containers/UpdateStatusPanel.spec.ts
- ui/src/views/ContainersView.vue
- app/model/maturity-policy.test.ts
- ui/src/locales/ko/containerComponents.json
- ui/src/locales/fr/containerComponents.json
- ui/src/components/containers/ContainerFullPageOverviewTab.vue
- ui/src/components/containers/ContainersListContent.vue
- ui/tests/components/DataTableColumnPicker.spec.ts
- ui/src/utils/dashboard-container-metrics.ts
- ui/tests/utils/update-maturity.spec.ts
- ui/src/components/containers/ContainerSideTabContent.vue
- ui/src/locales/en/containerComponents.json
- ui/tests/utils/dashboard-container-metrics.spec.ts
- ui/src/locales/de/containerComponents.json
- ui/src/locales/pl/containerComponents.json
- ui/src/locales/uk/containerComponents.json
- ui/src/locales/ar/containerComponents.json
- ui/src/utils/update-maturity.ts
- ui/src/locales/tr/containerComponents.json
- ui/tests/views/containers/useContainerPolicy.spec.ts
- ui/src/locales/zh-CN/containerComponents.json
- ui/src/locales/pt-BR/containerComponents.json
- ui/src/locales/ja/containerComponents.json
- ui/src/locales/es/containerComponents.json
- ui/src/locales/ru/containerComponents.json
- ui/src/locales/vi/containerComponents.json
- ui/src/locales/zh-TW/containerComponents.json
- ui/src/locales/nl/containerComponents.json
- ui/src/locales/it/containerComponents.json
- ui/tests/components/containers/ContainersGroupedViews.spec.ts
- app/model/update-eligibility.ts
The new legacyApiPathTitleSingular/Plural keys were seeded verbatim into all 16 translated catalogs, which Crowdin would treat as done translations. Missing keys fall back to en via fallbackLocale until Crowdin fills them — same as every other new key. (CodeRabbit #566 round 4.)
computeUpdateEligibility() picked between a trusted registry publishedAt
and updateDetectedAt internally (getMaturityStartMs), but never told
callers which clock it used or when it started — the UI had no choice
but to re-derive "is this maturity-blocked?" from updateDetectedAt alone
in two separate places, drifting from the server's actual verdict.
- Extract resolveMaturityClock() alongside the existing getMaturityStartMs()
(now a thin wrapper), returning both the resolved startMs and which
clock ('publishedAt' | 'detectedAt') won
- Add clockSource/clockStartAt to the maturity-not-reached blocker's
`details` (additive only — /api/v1 stays frozen for breaking changes)
- Drop the redundant "(N days remaining)" clause from the blocker message
now that the UI composes its own countdown from `details.remainingMs`
Display-honesty batch, part 1 — the container table/card and detail panels stop lying about update state: - Remove the separate NEW/MATURE freshness badge and Container.updateMaturity field entirely; the same freshness fact now lives in a tooltip on the update-type badge (formatUpdateAge() -> maturityBadge.new template) - "Digest" -> "Digest update" in the update-kind label (listContent.digest), fixing both the table and card render branches via the shared getUpdateKindLabel() helper - Drop the dedicated "Pinned" state + its own insight-kind badge from the Update column; a pinned row with a newer same-family version now shows a plain Major/Minor/Patch chip like any other update, and up-to-date pinned rows show "Current" — no more separate pinned vocabulary there - Add a persistent pin glyph (existing `pin` icon) to the Tag cell for tagPinned rows, with a tooltip naming the remedy (dd.tag.family=loose / dd.tag.include) - Give the previously-silent unknown-update-kind fallback a visible neutral "Unknown" badge instead of an invisible transparent one (updateKindColor's fallback branch) - Bouncer-blocked pill now reads "Security hold" (groupedViews.blockedByBouncer, listContent.blocked) instead of the generic "Blocked" — scoped to the vulnerability-bouncer state only; the maturity blocker's "Blocked" text is untouched - Collapse updateInsight.tooltipMajor/Minor/Patch into one updateInsight.tooltip template dashboard-container-metrics.ts keeps its own small isFreshUpdate() helper (7-day threshold) for the dashboard KPI, now independent of the removed badge classification it used to borrow from update-maturity.ts.
Display-honesty batch, part 2 — the maturity panel stops showing two
different clocks for the same wait:
- useContainerPolicy.ts's buildContainerListPolicyStateFromPolicy() now
prefers the backend's maturity-not-reached blocker verdict (mirrors
container-mapper.ts's findBackendMaturityBlocked from part 1) instead
of re-deriving "maturity-blocked" from updateDetectedAt alone; falls
back to the old computation only when no eligibility payload is present
- The maturity condition's body names its clock explicitly — "Candidate
published {date} — {n} more day(s) until the {days}-day minimum" for a
trusted registry publishedAt, with a "Candidate detected {date} …"
fallback when the clock is updateDetectedAt (maturitySentence(), using
the clockSource/clockStartAt/minAgeDays/remainingMs details added
server-side in part 0)
- Collapse the duplicated countdown ("(N days remaining)" in the message
+ "2d 0h 18m · Lifts at …" below it) into one liftCountdown line:
"{countdown} · unlocks {date}"
Display-honesty batch, part 3 — a column the user checked "on" but that
responsive sizing pushed off the table for width used to render as
plainly checked in the picker, with no hint it isn't actually showing.
- Thread useColumnVisibility's autoHiddenColumns through
containersViewTemplateContext.ts and ContainersView.vue's provide()
- DataTableColumnPicker.vue gains an optional autoHiddenKeys prop
(defaults to none — a no-op for the other 5 consumers: Agents,
Security, Audit, Watchers, Servers); a checked-but-auto-hidden row
renders muted "{column} — hidden to fit" instead of the plain label
- The "+N" badge count now includes checked-but-auto-hidden columns, and
its tooltip names them ("Host hidden to fit your screen.") instead of
just showing a generic count
- ContainersListContent.vue's pickerHiddenColumnKeys (checkbox state)
is unchanged — still user-driven only; the new
pickerAutoHiddenColumnKeys is a separate signal for the annotation
…erdict lookup - Extract shared update-kind-labels.ts (map, localized resolver with unknown-kind fallback, hasUnresolvedUpdateKind) and consume it from ContainersGroupedViews, ContainerFullPageTabContent, ContainerSideTabContent, ContainerFullPageDetail, and ContainerFullPageOverviewTab — the last of which previously rendered the raw updateKind string with no localization at all - Dedupe findBackendMaturityBlocked() into update-eligibility.ts; container-mapper.ts and useContainerPolicy.ts now import the shared function and keep their existing outer gating (maturityMode check / unconditional verdict use) unchanged - Extract a private formatDurationUnit() helper in update-maturity.ts to collapse the triplicated day/hour/minute t()-vs-fallback branches Addresses CodeRabbit review comments on PR #566.
The tag-candidates pin gate (specific-precision tag, no dd.tag.include, non-loose dd.tag.family) now shares its entry condition with the container model via app/tag/family.ts isPinGateGoverned(), and validate() materializes the verdict as a tagPinGated data property. Distinct from shape-based tagPinned, which keeps feeding the hide-pinned filter.
…rdict The glyph was 9px and absolutely positioned at the version cell's top-left corner, clipping to a near-invisible sliver, and it keyed on shape-based tagPinned — true for every exact-version tag, including rows with actionable updates, making its "won't climb to newer versions" tooltip false. It now renders inline at 12px grouped with the current tag (surviving the narrow-cell column stack) on tagPinGated rows only, and insight-only rows read "Current" in the update-state column instead of the insight's kind styled as actionable (#498 pinned-chip inconsistency; matches the approved display-honesty spec). Tooltip remedy now says "add a dd.tag.include filter" — gated rows have none to relax.
"1 requests to the removed API path detected" — the title used a single interpolated string for every count. Split into Singular/Plural keys (the catalog's established idiom, e.g. legacyConfigTitle*) across all 17 locales, selected by total in AppLayout.
updated() adopted whatever title the element currently carried as the new component-owned fallback, but that title was usually one our own syncTitle wrote, so the fallback froze at first render and assistive tech read stale text (e.g. the column-picker +N badge announcing only its first hidden column). Only adopt a title that differs from the last-synced fallback.
The #556 deep-link (?q=gcr.public) matched nothing because the filter only checked type and name separately. Also match the combined type.name form so provider deep-links land on the intended row.
- 🐛 pin glyph now gate-driven (tagPinGated) and inline beside the tag - 🐛 registries ?q= deep-link matches dotted type.name (#556) - 🐛 banner pluralization + tooltip native-title freshness - 📝 correct the auth fail-closed wording to the 401/503 behavior
The new legacyApiPathTitleSingular/Plural keys were seeded verbatim into all 16 translated catalogs, which Crowdin would treat as done translations. Missing keys fall back to en via fallbackLocale until Crowdin fills them — same as every other new key. (CodeRabbit #566 round 4.)
The panel still derived a dedicated 'pinned' state (info tone, "Pinned — {tag}
is available…") for insight-only containers, so the same container read
"Current" in the table but "Pinned" in its own detail view. The state is
retired: insight-only containers read up to date like everywhere else, and the
held-back newer tag surfaces as an informational detail row reusing the
table's updateInsight.tooltip vocabulary. The now-unused groupedViews
.pinnedLabel key is removed (en was its only catalog).
The tighter current-tag max-width keyed on :first-child inside the version flow; the glyph wrapper made the tag the wrapper's second child on pinned rows, silently widening them to the target-tag budget. The budget is now class-scoped to the wrapper (container-version-current) so it applies regardless of glyph presence.
…ned state watchers and FAQ pages still told readers to look for a neutral "Pinned" update state with a Major/Minor/Patch chip; the UI now keeps insight-only rows at Current with the pin glyph beside the tag. CHANGELOG notes the detail-panel alignment.
a99cf0d to
43804ec
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ui/src/locales/tr/containerComponents.json (1)
198-200: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDo not hand-seed new keys in the Turkish catalog.
Remove
emptyState,currentLabel,latestLabel,allBouncer,safe, andunsafehere. These catalogs are Crowdin-managed; missing keys intentionally fall back to English until retranslated.Based on learnings, non-English catalogs must not manually add new translation keys.
Proposed diff
- "emptyState": "Filtrelerinizle eşleşen kapsayıcı yok", - "currentLabel": "Mevcut", - "latestLabel": "En son", ... - "allBouncer": "Tüm Bouncer", - "safe": "Güvenli", - "unsafe": "Güvenli değil",Also applies to: 258-260
🤖 Prompt for 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. In `@ui/src/locales/tr/containerComponents.json` around lines 198 - 200, Remove the newly added emptyState, currentLabel, latestLabel, allBouncer, safe, and unsafe keys from the Turkish locale catalog, leaving missing entries to fall back to English under Crowdin management.Source: Learnings
🤖 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.
Outside diff comments:
In `@ui/src/locales/tr/containerComponents.json`:
- Around line 198-200: Remove the newly added emptyState, currentLabel,
latestLabel, allBouncer, safe, and unsafe keys from the Turkish locale catalog,
leaving missing entries to fall back to English under Crowdin management.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: efd9c7af-b120-4a4a-aaef-6013f5e159ea
⛔ Files ignored due to path filters (1)
CHANGELOG.mdis excluded by!CHANGELOG.md
📒 Files selected for processing (100)
app/model/container.test.tsapp/model/container.tsapp/model/maturity-policy.test.tsapp/model/maturity-policy.tsapp/model/update-eligibility.test.tsapp/model/update-eligibility.tsapp/tag/family.test.tsapp/tag/family.tsapp/watchers/providers/docker/tag-candidates.tsui/src/components/DataTableColumnPicker.vueui/src/components/containers/ContainerFullPageDetail.vueui/src/components/containers/ContainerFullPageOverviewTab.vueui/src/components/containers/ContainerFullPageTabContent.vueui/src/components/containers/ContainerSideTabContent.vueui/src/components/containers/ContainersGroupedViews.vueui/src/components/containers/ContainersListContent.vueui/src/components/containers/UpdateMaturityBadge.vueui/src/components/containers/UpdateStatusPanel.vueui/src/components/containers/containersViewTemplateContext.tsui/src/composables/useUpdateStatus.tsui/src/directives/tooltip.tsui/src/layouts/AppLayout.vueui/src/locales/ar/appShell.jsonui/src/locales/ar/containerComponents.jsonui/src/locales/de/appShell.jsonui/src/locales/de/containerComponents.jsonui/src/locales/en/appShell.jsonui/src/locales/en/containerComponents.jsonui/src/locales/en/sharedComponents.jsonui/src/locales/es/appShell.jsonui/src/locales/es/containerComponents.jsonui/src/locales/fr/appShell.jsonui/src/locales/fr/containerComponents.jsonui/src/locales/it/appShell.jsonui/src/locales/it/containerComponents.jsonui/src/locales/ja/appShell.jsonui/src/locales/ja/containerComponents.jsonui/src/locales/ko/appShell.jsonui/src/locales/ko/containerComponents.jsonui/src/locales/nl/appShell.jsonui/src/locales/nl/containerComponents.jsonui/src/locales/pl/appShell.jsonui/src/locales/pl/containerComponents.jsonui/src/locales/pt-BR/appShell.jsonui/src/locales/pt-BR/containerComponents.jsonui/src/locales/ru/appShell.jsonui/src/locales/ru/containerComponents.jsonui/src/locales/tr/appShell.jsonui/src/locales/tr/containerComponents.jsonui/src/locales/uk/appShell.jsonui/src/locales/uk/containerComponents.jsonui/src/locales/vi/appShell.jsonui/src/locales/vi/containerComponents.jsonui/src/locales/zh-CN/appShell.jsonui/src/locales/zh-CN/containerComponents.jsonui/src/locales/zh-TW/appShell.jsonui/src/locales/zh-TW/containerComponents.jsonui/src/types/container.d.tsui/src/utils/container-mapper.tsui/src/utils/dashboard-container-metrics.tsui/src/utils/display.tsui/src/utils/update-eligibility.tsui/src/utils/update-kind-labels.tsui/src/utils/update-maturity.tsui/src/views/ContainersView.vueui/src/views/RegistriesView.vueui/src/views/containers/useContainerPolicy.tsui/tests/boot/i18n.spec.tsui/tests/components/ContainerSideTabContent.spec.tsui/tests/components/DataTableColumnPicker.spec.tsui/tests/components/containers/ContainerFullPageDetail.spec.tsui/tests/components/containers/ContainerFullPageOverviewTab.spec.tsui/tests/components/containers/ContainerFullPageTabContent.spec.tsui/tests/components/containers/ContainersGroupedViews.button-states.spec.tsui/tests/components/containers/ContainersGroupedViews.spec.tsui/tests/components/containers/ContainersListContent.spec.tsui/tests/components/containers/UpdateMaturityBadge.spec.tsui/tests/components/containers/UpdateStatusPanel.spec.tsui/tests/composables/useContainerFilters.spec.tsui/tests/composables/useDetailPanel.spec.tsui/tests/composables/useOperationDisplayHold.spec.tsui/tests/composables/useUpdateStatus.spec.tsui/tests/composables/useVulnerabilities.spec.tsui/tests/directives/tooltip.spec.tsui/tests/utils/container-mapper.spec.tsui/tests/utils/dashboard-container-metrics.spec.tsui/tests/utils/display.spec.tsui/tests/utils/hide-pinned.spec.tsui/tests/utils/update-eligibility.spec.tsui/tests/utils/update-kind-labels.spec.tsui/tests/utils/update-maturity.spec.tsui/tests/views/ContainersView.applyContainerPatch.spec.tsui/tests/views/ContainersView.spec.tsui/tests/views/DashboardView.spec.tsui/tests/views/RegistriesView.spec.tsui/tests/views/containers/useContainerActions.spec.tsui/tests/views/containers/useContainerLogs.spec.tsui/tests/views/containers/useContainerPolicy.spec.tsui/tests/views/dashboard/useDashboardComputed.spec.tsui/tests/views/dashboard/useDashboardData.spec.ts
💤 Files with no reviewable changes (31)
- ui/tests/composables/useDetailPanel.spec.ts
- ui/tests/views/dashboard/useDashboardData.spec.ts
- ui/tests/components/containers/UpdateMaturityBadge.spec.ts
- ui/src/locales/ja/appShell.json
- ui/tests/utils/hide-pinned.spec.ts
- ui/tests/components/containers/ContainersGroupedViews.button-states.spec.ts
- ui/src/locales/pl/appShell.json
- ui/tests/composables/useContainerFilters.spec.ts
- ui/tests/views/containers/useContainerActions.spec.ts
- ui/src/locales/zh-TW/appShell.json
- ui/src/locales/pt-BR/appShell.json
- ui/tests/views/ContainersView.applyContainerPatch.spec.ts
- ui/src/locales/ko/appShell.json
- ui/src/locales/uk/appShell.json
- ui/src/locales/vi/appShell.json
- ui/src/locales/zh-CN/appShell.json
- ui/tests/views/ContainersView.spec.ts
- ui/tests/composables/useOperationDisplayHold.spec.ts
- ui/tests/views/containers/useContainerLogs.spec.ts
- ui/src/locales/fr/appShell.json
- ui/src/components/containers/UpdateMaturityBadge.vue
- ui/src/locales/de/appShell.json
- ui/src/locales/es/appShell.json
- ui/src/locales/nl/appShell.json
- ui/tests/views/dashboard/useDashboardComputed.spec.ts
- ui/src/locales/ru/appShell.json
- ui/src/locales/tr/appShell.json
- ui/src/locales/ar/appShell.json
- ui/tests/views/DashboardView.spec.ts
- ui/src/locales/it/appShell.json
- ui/tests/composables/useVulnerabilities.spec.ts
🚧 Files skipped from review as they are similar to previous changes (67)
- ui/src/locales/en/appShell.json
- ui/tests/views/RegistriesView.spec.ts
- ui/src/components/containers/UpdateStatusPanel.vue
- ui/src/utils/update-kind-labels.ts
- app/tag/family.test.ts
- ui/src/components/containers/containersViewTemplateContext.ts
- ui/src/layouts/AppLayout.vue
- ui/tests/components/containers/ContainerFullPageTabContent.spec.ts
- ui/src/locales/en/sharedComponents.json
- ui/tests/directives/tooltip.spec.ts
- ui/src/components/DataTableColumnPicker.vue
- ui/src/components/containers/ContainerFullPageOverviewTab.vue
- ui/tests/components/containers/ContainerFullPageDetail.spec.ts
- app/tag/family.ts
- ui/src/components/containers/ContainersListContent.vue
- ui/tests/utils/update-eligibility.spec.ts
- ui/tests/utils/dashboard-container-metrics.spec.ts
- app/model/maturity-policy.test.ts
- ui/src/locales/uk/containerComponents.json
- ui/src/types/container.d.ts
- ui/tests/components/containers/ContainersListContent.spec.ts
- ui/src/views/containers/useContainerPolicy.ts
- ui/src/views/RegistriesView.vue
- ui/tests/views/containers/useContainerPolicy.spec.ts
- ui/tests/composables/useUpdateStatus.spec.ts
- ui/src/utils/dashboard-container-metrics.ts
- ui/src/utils/display.ts
- ui/src/utils/update-maturity.ts
- ui/tests/boot/i18n.spec.ts
- ui/tests/utils/update-kind-labels.spec.ts
- ui/src/locales/ko/containerComponents.json
- ui/src/locales/zh-TW/containerComponents.json
- ui/tests/utils/display.spec.ts
- app/model/container.ts
- ui/tests/components/DataTableColumnPicker.spec.ts
- ui/src/locales/ar/containerComponents.json
- app/watchers/providers/docker/tag-candidates.ts
- app/model/maturity-policy.ts
- ui/tests/components/containers/ContainerFullPageOverviewTab.spec.ts
- ui/tests/components/containers/UpdateStatusPanel.spec.ts
- ui/src/locales/vi/containerComponents.json
- ui/src/locales/pl/containerComponents.json
- ui/src/utils/update-eligibility.ts
- ui/src/locales/en/containerComponents.json
- app/model/container.test.ts
- app/model/update-eligibility.test.ts
- ui/tests/components/ContainerSideTabContent.spec.ts
- ui/src/locales/ru/containerComponents.json
- ui/src/locales/it/containerComponents.json
- ui/src/directives/tooltip.ts
- ui/src/components/containers/ContainerFullPageDetail.vue
- ui/src/components/containers/ContainerFullPageTabContent.vue
- ui/src/utils/container-mapper.ts
- ui/src/locales/zh-CN/containerComponents.json
- ui/src/locales/nl/containerComponents.json
- ui/src/locales/de/containerComponents.json
- ui/tests/utils/update-maturity.spec.ts
- ui/src/locales/pt-BR/containerComponents.json
- app/model/update-eligibility.ts
- ui/src/locales/ja/containerComponents.json
- ui/src/locales/fr/containerComponents.json
- ui/src/components/containers/ContainerSideTabContent.vue
- ui/tests/components/containers/ContainersGroupedViews.spec.ts
- ui/src/composables/useUpdateStatus.ts
- ui/src/locales/es/containerComponents.json
- ui/src/views/ContainersView.vue
- ui/src/components/containers/ContainersGroupedViews.vue
Release plumbing for the v1.6.0-rc.3 cut — the full identity bump the guard tests enforce. - Dated `[1.6.0-rc.3] — 2026-07-21` CHANGELOG heading, fresh empty `[Unreleased]` section, matching link-reference definitions - rc.3 across README badge/highlights summary, website site-config + timeline, updates page (new rc.3 highlights section), API doc example payloads, quickstart tag matrix, and the demo runtime fixtures - Guard tests updated in lockstep: release-identity, release-docs-identity (compare base now `v1.6.0-rc.2...v1.6.0-rc.3`), changelog-links rc.3 delta over rc.2: #566 display-honesty batch, #567 security hardening, #568 maturity-clock restart fix (#565), #569 docs freshness. Verified: 105/105 script tests, 43/43 web-script tests, full pre-push gate green. Last dev-side change before the release head freeze. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Changelog 🔧 **Changed** - Updated release identity from `v1.6.0-rc.2` to `v1.6.0-rc.3` across README, website metadata, roadmap, docs, API examples, quickstart tags, and demo fixtures. - Added the dated `v1.6.0-rc.3` updates section and refreshed changelog link references. - Updated release identity and documentation guard tests, including rc comparison ranges and candidate fixtures. ✨ **Added** - Documented the rc.3 changes covering issues `#566`, `#567`, `#568/`#565, and `#569`. 🔒 **Security** - Documented the rc.3 security hardening batch. ## Verification - Script tests: 105/105 passed - Web-script tests: 43/43 passed - Full pre-push gate: passed ## Concerns - Verify the release date `July 21, 2026` is correct. - Confirm all remaining `1.6.0-rc.2` references are intentional. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Promotes the v1.6.0-rc.3 content from `dev/v1.6` to `main` for the release cut. rc.3 delta over rc.2: - **#566 display-honesty batch** — update-status vocabulary ("Digest update", Unknown badge, "Security hold"), pin glyph driven by the real pin-gate verdict (`tagPinGated`), insight-only pinned rows read Current everywhere (table + detail panel), one-clock maturity panel, column-picker auto-hide annotations, registries deep-link fix (#556), banner pluralization, tooltip freshness. - **#567 security hardening** — anonymous auth fails closed on upgrades, HTTP trigger SSRF guards, full WebSocket origin validation, `drydock.sid` session cookie, owner-only store perms, pinned icon CDN revisions, CI secret scans. - **#568 maturity-clock restart fix** (#565) — the soak clock restarts only when the update candidate identity changes. - **#569 docs freshness** — auth/SSRF/WS/UI copy corrected to shipped v1.6 behavior. - **#571 release identity bump** — dated CHANGELOG heading, rc.3 across all public version surfaces, guard tests in lockstep. After merge: dispatch `release-cut.yml` from `main` with `release_tag=v1.6.0-rc.3`.
What
The display-honesty batch: renames and removes the update-status vocabulary that #498 and #556 reported as unreadable, based on a peer-tool UX research pass (WUD, Diun, Watchtower, Cup, Dockge, Arcane, Portainer, Komodo, Home Assistant, Renovate/Dependabot) and an owner-approved design.
UpdateMaturityBadge.vuedeleted.pinicon-map entry, not the padlock — that's a live action affordance), with a tooltip carrying thedd.tag.family=looseremedy. Up-to-date pinned rows read "Current" like everything else.resolveMaturityClock()inapp/model/maturity-policy.ts(behavior-preserving refactor ofgetMaturityStartMs) now exposesclockSource/clockStartAtas additive optional fields on the maturity blocker'sdetails, and both UI call sites (container-mapper.ts,useContainerPolicy.ts) consume the backend verdict instead of re-deriving maturity-blocked fromupdateDetectedAtalone — three drifting formulas become one.i18n: net 12 keys added / 7 removed / 12 values changed, English catalogs only per convention, plus stale values for the repurposed keys dropped from all 16 non-English locales so they fall back to English until Crowdin retranslates (otherwise German would render the old badge text "NEU" as a tooltip).
Why
Direct follow-up to the rc.2 field feedback in #498 (Cesc1986) and the #556 display cluster. Design researched and approved before implementation; targets v1.6.1/rc.3 — nothing here touches the rc.2 soak.
Tests
TDD gates green in full: app 100/100/100/100 (12,244 tests), ui 100/100/100/100 (4,236 tests). New coverage for the clock resolution (source precedence + tie-breaks), blocker serialization, pin glyph, unknown-kind fallback, column-picker annotation branches, collapsed countdown, and both
useContainerPolicypaths (backend-verdict preferred, legacy fallback).Notes for review
dashboard-container-metrics.tskept itsfreshUpdatesKPI via a localisFreshUpdate()helper (same 7-day threshold) after the badge helper's deletion — dashboard behavior unchanged.Changelog
Unknownfallback.tagPinGatedpropagation from backend to UI.UpdateMaturityBadge,getUpdateMaturity, separate NEW/MATURE badges, and the dedicated pinned update-status state.blockedByBouncer,updateAge, maturity-badge, and pinned-summary values.Containercontract: removedupdateMaturity; addedupdateMaturityTooltip,updatePolicyState, andtagPinGated.Concerns
updateEligibilitypayloads expose sufficiently reliable maturity clock metadata.getUpdateMaturity,updateMaturity, andpinnedAPIs.