π release(v1.5.1-rc.3): intermediate release notes, i18n re-sync, web shell + renovate#459
Conversation
Re-syncs the 16 target-locale containerComponents.json catalogs and normalizes their key order to match the English source. Generated by the Crowdin sync workflow (run 28319493351).
Guards against locale-directory drift under ui/src/locales/. A recent Crowdin misconfiguration wrote a stray en-US/ directory that only surfaced in a sync PR; this fails CI fast if the on-disk locale set ever diverges from SUPPORTED_LOCALES (extra or missing locale).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
β¦oundary The OIDC authorization_endpoint, rate-limit peer-keying, and HTTP-trigger proxy-scheme changes shipped in 1.4.6 and persist through all of 1.5, so anyone updating from a pre-1.4.6 release hits them no matter which current version they land on. Reworded the README warning + UPGRADE-NOTES lead so a user who skipped 1.4.6 (e.g. 1.4.3 -> 1.5.1) doesn't assume they're exempt.
β¦16.2.9 - loader() to v15 positional form in lib/source.ts - docs page imports canonical fumadocs-ui/page (matches target shell) - drop dead fumadocs-mdx:collections/* tsconfig alias - aligns apps/web with sockguard/portwing shell architecture Part of CodesWhat shared shell extraction (Phase A).
- react/react-dom 19.2.7, tailwindcss + @tailwindcss/postcss 4.3.1 - tailwind-merge 3.6, lefthook 2.1.9, @types/* latest - align @biomejs/biome to root 2.4.16 (shared biome.json $schema), not 2.5.x - @types/node held at 25.x to match the Node 24 runtime Part of CodesWhat shared shell extraction.
Single source of truth for site identity (name, repo slug, domain, logo, demo url, docker image, twitter, aurora palette, storage prefix) plus derived BASE_URL/GITHUB_URL/DEMO_URL/DOCKER_HUB_URL/REPO_SLUG helpers. Wired ~50 call sites across 17 files (app routes metadata + JSON-LD, chrome components, lab components, comparison-route) to import from it. Resolved runtime values unchanged β de-duplication only. MarketingShell gains an optional aurora prop defaulting to SITE_CONFIG.aurora. This is the per-site re-skin point for the shared CodesWhat shell. Part of CodesWhat shared shell extraction (Phase B).
- starhistory: star-history.com chart URLs now use REPO_SLUG (were raw CodesWhat/drydock) - footer: visible brand span -> SITE_CONFIG.name; logo alt -> "" (decorative, matches header) - demo: share payload pinned to SITE_CONFIG.demoUrl (production, not env preview); share/iframe titles -> SITE_CONFIG.name - compare-variants: cellValue map key + eyebrow -> SITE_CONFIG.name - wire logoInvertOnDark at header/footer/hero logo sites (field was inert) Part of CodesWhat shared shell extraction (Phase B review pass).
- remove Drydock-specific FAQ JSON-LD from the docs renderer (was a
coupling trap, incomplete β 1 of ~40 Qs β and FAQ rich results are
no longer shown for non-gov/health sites); keep BreadcrumbList JSON-LD
- delete now-dead lib/docs-faq-route.ts + its (non-running) test
- typed docs data via getDocsPage/DocsPageData (drops page.data as any);
this surfaced + fixed a latent MdxImage prop-variance bug
- docs metadata: BASE_URL/SITE_CONFIG, twitter card summary_large_image, twitter.creator
- root layout: title template '%s | Drydock' + default; docs tabs/Google
now show 'Title | Drydock' instead of bare titles
- compare/security/comparison-route titles use { absolute } to opt out of
the template (they already carry the brand) β verified no double-branding
- og image + locale sourced from SITE_CONFIG
Part of CodesWhat shared shell extraction (Phase C).
β¦ecture Relocate the Next.js App Router tree under src/ so apps/web matches the canonical CodesWhat shell layout (sockguard's architecture). No behavior change β every move is a git rename. - π refactor(web): git mv app/ lib/ components/ β src/ - π§ config(web): drop deprecated tsconfig baseUrl (TS6 TS5101); paths resolve relative to tsconfig dir, "@/*" β "./src/*" - π§ config(root): repoint biome globals.css ignore to src/app/globals.css - β test(web): update compare-pages helper test paths to src/ Gate: type-check β lint β build β test:scripts β (240+ docs routes prerender)
Move the 9 chosen homepage/footer sections out of the exploration src/components/lab/ folder into flat src/components/ with clean names, matching the shell's flat component convention. Drops the leftover "-variants"/lab scaffolding from the design-exploration phase. - hero-variantsβhero (Hero), features-variantsβfeatures (Features), compare-variantsβcompare-section (CompareSection), demo-variantsβdemo (Demo), ecosystem-variantsβecosystem (Ecosystem), roadmap-variantsβroadmap (Roadmap), starhistory-variantsβstar-history (StarHistory), getstarted-secure-toggleβget-started (GetStarted), footer-variantsβfooter (Footer) - update importers: app/page.tsx, docs-shell.tsx, marketing-shell.tsx - remove now-empty src/components/lab/ Gate: type-check + lint + build + test:scripts all green.
- add skip-to-content link + id="main-content" to DocsShell (mirrors MarketingShell; fumadocs nav is disabled so its built-in skip link was suppressed) - add focus-visible rings to nav links, icon buttons, and ThemeToggle - ThemeToggle aria-label now reflects the action (Switch to light/dark) - extract navLinkCn/iconButtonCn to src/lib/class-names.ts; site-header and footer import them instead of duplicating the strings Gate: type-check + lint + build + test:scripts green.
β¦elf) The comparison-route/comparison-page scaffold baked "drydock" into the ComparisonRow field, verdict enum, and badge prop, so a sibling site copying the scaffold would carry Drydock's identity at the type level. Rename to the agnostic `self`: - ComparisonRow.drydock β .self; verdict "drydock" β "self" - drydockBadge prop/const/className β selfBadge - pipe-table verdict column values drydock β self across all competitors - CTA "Ready to try Drydock?" now derives from SITE_CONFIG.name Per-competitor content stays Drydock-flavored; only the reusable type surface and enum became agnostic. Gate: type-check+lint+build+scripts green.
β¦ slugs - extract ComparisonCellIcon (yes/partial/no) to one component used by compare-matrix and compare-section; reconcile the drifted "No" color - icon SVGs are aria-hidden with sr-only state text (bare-SVG aria-label is unreliable in JAWS+Chrome) - sitemap compare list now derives from getComparisonRouteSlugs() instead of a hardcoded array, so new compare pages can't drift out of the sitemap Gate: type-check + lint + build + test:scripts green (all 9 compare routes).
β¦hRange - π #452: the dedicated DD_RELEASE_NOTES_GITHUB_TOKEN is now forwarded even for untrusted source repos (dd.source.repo container label / persisted container.sourceRepo). The GHCR PAT fallback stays gated by trust, so the broadly-scoped credential is never sent to an attacker-controllable repo. - β¨ #453: GithubProvider.fetchRange enumerates releases in (current, target] via the paginated /releases endpoint, strict-semver ordered newest-first (date/rolling tags fall back), each page through withRetry, 10-page cap. - β 64 provider tests, GithubProvider.ts at 100% coverage. Refs #452, #453
β¦ tooling - delete nine identical passthrough src/app/compare/*/layout.tsx (App Router applies the parent layout; they add zero behavior) - delete unused AnnouncementBanner component (no importers) - delete historical migrate-docs.mjs + migrate-docs.test.mjs (Docsify migration is complete; it reads a ../../docs/ tree that no longer exists) Gate: type-check + lint + build + test:scripts green (all 9 compare routes intact).
β¦e_color - add SITE_CONFIG.version; Hero badge reads it instead of a hardcoded "v1.5.0" string that staled every release - web manifest icons use "any maskable" so non-maskable environments get a usable icon; theme_color aligned to #0a0a0a (matches viewport dark) - add globals.d.ts ambient CSS shims (TS6 noUncheckedSideEffectImports) Gate: type-check + lint + build + test:scripts green.
- guard the root CHANGELOG.md read (DD_CHANGELOG_PATH override); a sibling site without one now logs a warning and skips instead of crashing the build - write the generated changelog into the build target under the active version slug instead of into content/docs/current/ β no more source-tree mutation as a build side-effect - build into content/docs.tmp and renameSync into place so a mid-run crash can't leave a blank content/docs/ (and thus a blank docs site) - update content/docs/README.md to describe the actual sync pipeline Gate: build (runs sync:docs) + type-check + lint + test:scripts green; changelog renders under /docs/v1.5; missing-CHANGELOG path verified non-fatal.
β¦ orchestration - π #452: cache key is now three-tier (#auth / #token / #anon) so an untrusted source fetched WITH the dedicated token no longer poisons the anonymous bucket now that the token is forwarded to untrusted sources. - π #452: warn when a dd.source.repo container label shadows a trusted image source label (silent trustedβuntrusted downgrade that drops the GHCR fallback). - β¨ #453: getIntermediateReleaseNotes orchestrates a cached, capped range fetch (DD_RELEASE_NOTES_MAX_INTERMEDIATE, default 20, 0 disables; cap applied at read time with a non-silent hiddenCount; interrupted fetches are not cached). - β 131 release-notes tests, index.ts + GithubProvider.ts at 100% coverage. Refs #452, #453
Lazy-load endpoint backing #453. `from` (current tag) is required; `to` defaults to the container's pending update tag (422 if neither is available). Returns { releaseNotes, hiddenCount } β an empty list is valid, never a 404 β so intermediate notes stay off the container model and the agent SSE snapshot, keeping that payload bounded. OpenAPI documented; handler at 100% coverage. Refs #453
ReleaseNotesLink now fetches the releases between a container's current and target tag on demand (popover open / inline mount) from the new endpoint, and renders them newest-first as collapsible rows with a non-silent "N older releases not shown" indicator. Notes stay off the container model, so the list never weighs down the container payload or the agent snapshot. - export normalizeReleaseNotes for reuse by the new service call - getContainerIntermediateReleaseNotes service wrapper (404 β null, maps + validates each note through normalizeReleaseNotes) - 3 new i18n keys across all 17 locales (en source; Crowdin localizes later) - wired container-id/from-tag/to-tag through the container + dashboard callers (security views aggregate across containers, left on the two-panel view) - full ui suite 3661 tests, 100% coverage Refs #453
β¦452, #453) - watcher docs: the DD_RELEASE_NOTES_GITHUB_TOKEN trust override with narrow PAT-scoping guidance, a warn callout for the dd.source.repo silent downgrade, and the intermediate release notes feature + DD_RELEASE_NOTES_MAX_INTERMEDIATE - ghcr docs: clarify the GHCR fallback is trusted-sources-only - CHANGELOG [1.5.1-rc.3] entries for both issues Refs #452, #453
Extends local>CodesWhat/.github:renovate-config for org-wide policy (14-day soak, internalChecksFilter strict, config:best-practices). Keeps drydock's npm-per-workspace + Playwright groupings, the Playwright Docker custom manager, and the patch-only GitHub Actions auto-merge rule (enforced by app/renovate-config.test.ts).
Adversarial review of the #452/#453 implementation surfaced two high-severity caching bugs that 100% coverage masked (tests matched the buggy behavior): - π fix(release-notes): mark cooldown short-circuit as interrupted so the empty range result is not cached as complete for the 1h TTL, matching fetchByTag's undefined-on-cooldown contract - π fix(release-notes): mark page-cap exhaustion (all 10 pages full) as interrupted so a truncated range is never cached as the full set - π fix(release-notes): normalize from/to tags (trim, strip v-prefix, lowercase) in the intermediate cache key so v1.2.0 and 1.2.0 share a slot - π fix(ui): gate intermediate-notes fetch on hasStructuredNotes so the link never lazy-loads a range it cannot render - π chore(release-notes): debug-log when DD_RELEASE_NOTES_GITHUB_TOKEN is forwarded to an untrusted source in the range path (audit parity) - β test: cover #anon cache-bucket isolation and the interrupted contracts
The fumadocs v15 upgrade (this RC) is stricter about JSX in MDX: a <Callout> whose content starts inline on the opening-tag line can't span blank-line-separated paragraphs. The release-notes popover callout in the watchers docs did exactly that, breaking the apps/web Turbopack build. Move the open/close tags onto their own lines (block form) so the multi- paragraph body parses. Rendered output is unchanged.
The release-notes feature commits predate this RC's biome 2.4.16 bump (in the shell upgrade) and carried import-sort/format drift that the newer biome flags. Apply the safe fixes so the root biome gate passes.
biggest-littlest
left a comment
There was a problem hiding this comment.
RC consolidation looks clean β intermediate release-notes endpoint + UI, the Crowdin re-sync with the locale guard test, the fumadocs v15 web-shell move, and the renovate preset all accounted for, full gate green. LGTM.
ALARGECOMPANY
left a comment
There was a problem hiding this comment.
Went through the four streams and the build/coverage/e2e gate. Scope matches the changelog, nothing dangling. Good to merge.
CodeQL js/incomplete-sanitization (high): `REPO_SLUG.replace("/", "%2F")`
only rewrites the first slash. REPO_SLUG has one slash today so the badge
URL is correct, but the single-occurrence replace is brittle and trips the
scanner. encodeURIComponent is a recognized sanitizer and encodes every
reserved char, so the URL stays correct for any owner/repo shape.
76c108d
biggest-littlest
left a comment
There was a problem hiding this comment.
Re-approving after the CodeQL sanitization fix β encodeURIComponent on the repo slug clears the incomplete-sanitization alert, badge URL unchanged for the real owner/repo. All required checks green.
ALARGECOMPANY
left a comment
There was a problem hiding this comment.
Re-approve post-fix. CodeQL clean, full gate green, scope unchanged.
This RC consolidates four streams of held work plus the docs/build fixes they surfaced. One branch, one PR, one cut.
Release notes β intermediate range (#452, #453)
GET /api/containers/{id}/intermediate-release-notesendpoint, lazy-loaded when the popover opens β not embedded in the container model or agent snapshot, so it adds no ongoing payload weight. Acceptsfrom(required) andto(defaults to the pending update tag).latest,stable) fall back to the two-panel current/target view. Cap viaDD_RELEASE_NOTES_MAX_INTERMEDIATE(default20,0disables);__FILEsecret-file convention supported. Over the cap, the popover shows a non-silent "N older releases not shown" notice.DD_RELEASE_NOTES_GITHUB_TOKENis now forwarded to repos resolved from add.source.repocontainer label or persistedcontainer.sourceRepo. The GHCR token fallback stays restricted to trusted sources (OCI labels, GHCR image paths) and is never sent to a container-label source. Awarnline fires each watch cycle when add.source.repolabel shadows a trusted OCI source label.i18n / Crowdin re-sync (supersedes #458)
containerComponents.jsoncatalogs from Crowdin so key order tracks the English source.SUPPORTED_LOCALES.CodesWhat web shell β apps/web
src/to match the shared shell architecture; promoted lab section components to flatsrc/components.src/lib/site-config.tsis the single reskin point; all brand couplings wired to it. Comparison scaffold made product-agnostic.sync-docsmade portable + atomic (stops mutating the source tree).Renovate (supersedes #460)
Gate
Full pre-push gate green: biome, qlty, qlty-smells, coverage (app + ui, 100%), build, e2e, playwright, zizmor. apps/web build verified green through the real
sync:docspath.Closes #452, #453. Supersedes #458 and #460 (closed in favor of this consolidated RC).