Skip to content

Release v1.5.0-rc.22 prep#369

Merged
scttbnsn merged 8 commits into
mainfrom
feature/v1.5-rc22
May 15, 2026
Merged

Release v1.5.0-rc.22 prep#369
scttbnsn merged 8 commits into
mainfrom
feature/v1.5-rc22

Conversation

@scttbnsn

@scttbnsn scttbnsn commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Cutting v1.5.0-rc.22. Two user-facing bug fixes (a remote-agent SSE reconnect storm and the rc.20 Authentik SSO regression), one diagnostic improvement on the OIDC code path, one CI architecture fix that prevents an OSSF Scorecard alert pattern from recurring, and a 16-locale i18n top-up.

Fixes

  • 🐛 Agents displaying 0 running containers #362 — SSE reconnect backoff no longer collapses to a flat 1 s loop against a struggling agent. The Agents displaying 0 running containers #362 reporter's rc.20 controller logs showed SSE stream ended. Reconnecting... every ~1.00 s indefinitely. AgentClient.startSse() reset reconnectAttempts to 0 the instant the axios response headers arrived — before the SSE stream proved it could stay open. A stream that returned HTTP 200 then ended immediately (crash-looping agent, reverse-proxy idle timeout) reset the backoff on every cycle, so exponential backoff never engaged and the controller hammered the agent at 1 req/s. The reset is now deferred — a stability timer armed on response is cancelled by scheduleReconnect() if the stream ends early, so reconnectAttempts clears only after the stream stays open for SSE_STABLE_CONNECTION_MS (30 s) and the delay escalates to the 60 s cap as intended. (The core "0 running containers" snapshot-wipe was fixed in rc.20 via 4cd6b8be; this closes the remaining reconnect-storm symptom from the same thread.)
  • 🐛 Regression: Authentik SSO not working with 1.5.0-rc.21 #368 — Authentik OIDC regression for self-signed / CAFILE setups. rc.20 bumped undici 7.24.6 → 8.2.0 (e763e09f). Node 24 ships built-in undici@7.21.0 (v1 dispatcher interface); the userland undici@8 Agent exposes the v2 interface. The OIDC custom-fetch path constructed the Agent from userland undici and passed it as dispatcher to Node's global fetch, which is bound to the built-in undici 7. The v2 Agent's handlers don't satisfy the v1 contract, so the request fails with the opaque TypeError: fetch failed. (nodejs/undici#4827 describes this exact mismatch — the Node 22 Dispatcher1Wrapper bridge isn't on Node 24.) Fix imports fetch from undici and uses it in the custom-dispatcher branch so both halves stay on the same dispatcher version. Default fetch path (no CAFILE/INSECURE) is unchanged.

Diagnostics

  • 🐛 OIDC error logs surface error.cause chain. Previously OIDC failures logged only Unable to initialize OIDC session (fetch failed) — undici's surface message hides the actionable detail. New getErrorChainMessage helper walks error.cause up to depth 5, joins with , appends [code] from each Error-like node, handles cycles. Future failures now log e.g. fetch failed ← getaddrinfo ENOTFOUND host.tld [ENOTFOUND] or fetch failed ← self signed certificate in certificate chain [UNABLE_TO_VERIFY_LEAF_SIGNATURE], after the existing URL/token redaction.

CI hygiene

  • 🔧 Playwright moved to its own workflow file (e2e-playwright.yml). OSSF Scorecard's CI-Tests check derives its score from the github-actions Check Suite conclusion (via GraphQL), not individual check-run conclusions. Because every job in ci-verify.yml rolled into one suite, a single failing Playwright assertion (e.g. the "No pending entries" casing bug on PR Release v1.5.0-rc.21 tail: i18n + Dockerfile arch-drift fix #366) flipped the entire suite to failure and made Scorecard mark the merged PR as untested — that's alert #43. Each workflow file gets its own Check Suite per commit, so isolating Playwright keeps ci-verify's suite reliably green for Scorecard. Branch protection still gates on the 🎭 E2E: Playwright status check (matched by job name, not workflow file), and release-cut.yml now polls both workflows on the target SHA so releases continue to require Playwright success. Both workflows share the drydock GHA cache scope, so whichever runs second hits a warm cache.

Translations

  • 6 stub locales translated from scratch (ar, ja, ko, ru, uk, vi). These were scaffolded earlier with English placeholders. Full translation pass covering all 14 source files (~2,400 source words each), preserving brand/proper nouns, acronyms, interpolation placeholders, and ICU plural syntax per language conventions.
  • 10 seeded locales gap-filled (de, es, fr, it, nl, pl, pt-BR, tr, zh-CN, zh-TW) to match the catalog extractions that landed in rc.21. New notificationOutboxView.json in every locale; backfilled notificationsView.rules, securityView.deltaTooltips, registriesView.status, serversView.status, and the recent containerComponents / containersView / dashboardView keys. All 16 non-English locales now have zero missing keys versus en/.

Test plan

  • App unit suite green — 8087/8087 pass, 100% coverage; tsc build + biome lint clean
  • CI Verify passes on this PR (now also expecting a separate E2E Playwright workflow run since the split)
  • E2E Playwright passes on this PR — first run on the new workflow file
  • Manual: redeploy @begunfx's Authentik setup (DD_AUTH_OIDC_AUTHENTIK_INSECURE=true against self-signed cert) on the rc.22 image and confirm SSO login succeeds; if it still fails, the new error.cause chain will surface the actual reason (DNS / cert / connect)
  • Spot-check at least one of the freshly-translated stub locales in the UI (e.g., switch to ja and walk Dashboard → Containers → Settings) to confirm no key collisions or layout regressions
  • After merge: dispatch release-cut.yml from main with release_tag=v1.5.0-rc.22

scttbnsn added 5 commits May 15, 2026 10:57
These six locales were scaffolded with English placeholders and never
received a translation pass. All 13 existing files now contain real
translations and the missing notificationOutboxView.json has been added
to each, bringing them to full key parity with the English source.

Conventions:
- Brand/proper nouns kept in Latin (Drydock, Docker, Slack, Discord, etc.)
- Acronyms kept in English (API, URL, HTTP, JSON, YAML, TLS, etc.)
- DevOps terminology uses each language's established conventions
- All interpolation placeholders ({name}, {count}) and ICU plurals preserved
…/zh-CN/zh-TW)

These ten locales were already mostly translated but had drifted behind
recent string extractions and were missing notificationOutboxView.json
entirely.

Filled across the affected files:
- notificationOutboxView.json — new file in every locale (heading, tabs,
  columns, actions, status, empty states, toast messages).
- listViews.json — notificationsView.rules (6 rule name/description pairs),
  securityView.deltaTooltips, updateOneOfButton, updateThisContainerButton,
  registriesView.status, serversView.status.
- containerComponents.json — digestLabel, blockedTag variants,
  manualUpdateOnly variants, narrowViewportSuffix, autoHiddenBadgeTooltip,
  clearContainerIdFilter, suggestedTag.tooltipWithTag.
- containersView.json — updateStarted, forceUpdateStarted, alreadyUpToDate,
  queuedUpdate* and countAlreadyUpToDate* toast variants.
- dashboardView.json — recentUpdates.widgetAria.

Also fixes a typo in de/dashboardView.json where the closing curly quote
was rendered as a straight quote, breaking JSON parsing.

All 16 non-English locales now have zero missing keys versus en/.
Scorecard's CI-Tests check derives its score from the github-actions
Check Suite conclusion (via GraphQL), not individual check-run
conclusions. Because every job in ci-verify.yml rolled into a single
github-actions suite, one failing Playwright assertion (e.g. the
"No pending entries" casing bug on PR #366) was flipping the entire
suite to "failure" and making Scorecard mark the merged PR as
untested — even though 9+ other jobs in the same suite were green.
That manifested as code-scanning alert #43 (CI-Tests score 9/10).

Each workflow file gets its own Check Suite per commit. Moving
Playwright into e2e-playwright.yml isolates its failures into a
separate suite, so a Playwright bug no longer drags ci-verify's
suite down for Scorecard's purposes. Branch protection still
gates on the "🎭 E2E: Playwright" status check (matched by job
name, not workflow file), and release-cut.yml now polls both
workflows on the target SHA so releases continue to require
Playwright success.

Notes:
- The new workflow builds its own QA image inline rather than
  consuming the qa-image artifact, since artifacts are scoped to a
  single workflow run. Both workflows share the `drydock` GHA cache
  scope, so whichever runs second hits a warm cache.
- ci-verify still owns the qa-image artifact upload because
  dast-zap-baseline, dast-nuclei, and load-test-ci consume it
  inside the same workflow run.
undici's fetch surfaces failures as a generic 'TypeError: fetch failed';
the actionable diagnostic (ENOTFOUND, ECONNREFUSED,
UNABLE_TO_VERIFY_LEAF_SIGNATURE, etc.) lives on error.cause, sometimes
nested. The previous sanitizer only logged the top-level message, so
issue #368 (Authentik SSO regression on rc.21) reached us with only
'Unable to initialize OIDC session (fetch failed)' — no way to tell
whether DNS, TLS, or routing was at fault.

- New getErrorChainMessage(error, fallback?) walks error.cause up to
  depth 5, joins parts with ' ← ', appends '[code]' when present, and
  handles cycles via WeakSet.
- sanitizeOidcErrorMessage now uses it, so all OIDC warn logs include
  the cause chain (still passed through the existing URL + token
  redaction).
- Tests cover plain Error, multi-level chains, cyclic cause,
  depth-5 truncation, missing message + custom fallback, and an
  end-to-end OIDC discovery rejection that asserts the cause's
  ENOTFOUND code reaches log.warn.

Forward-only diagnostic improvement — no runtime behavior changes for
healthy OIDC paths.
…k SSO regression

Fixes #368.

Node 24 ships built-in undici 7.21.0 (v1 dispatcher interface) while
the app's userland undici@8.2.0 (bumped on May 12 in commit e763e09,
shipped in rc.20) exposes an Agent with the v2 dispatcher interface.
The OIDC custom fetch was constructing the Agent from userland
undici@8 and passing it as `dispatcher` to Node's GLOBAL `fetch`,
which is bound to the built-in undici 7. The v2 Agent's handlers
don't satisfy the v1 contract, so the request fails with the opaque
`TypeError: fetch failed` — the same surface symptom @begunfx
reported after upgrading rc.19 → rc.21 with
`DD_AUTH_OIDC_AUTHENTIK_INSECURE=true` against self-signed Authentik.

undici PR nodejs/undici#4827 covers this exact cross-version mismatch
and adds a Dispatcher1Wrapper bridge — but only on Node 22. Node 24
has no such bridge, so the global-fetch + userland-undici-Agent
combination silently fails.

Fix: import `fetch` from `undici` and use it whenever a custom
dispatcher is required (cafile or insecure path). Both halves now
share the same dispatcher version. The non-insecure code path is
unchanged — openid-client still uses its default fetch when no
custom dispatcher is needed.

Tests updated to mock `undici`'s `fetch` instead of spying on
`globalThis.fetch`. All 8085+ app tests pass; coverage stays at
100%.
@vercel

vercel Bot commented May 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
drydock-demo Ready Ready Preview, Comment May 15, 2026 11:19pm
drydock-website Ready Ready Preview, Comment May 15, 2026 11:19pm

@codecov

codecov Bot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…nt types

The undici-fetch fix in 03ed0f4 passed `npm test` (vitest is lenient on
type-only mismatches) but failed the Docker app-build stage where strict
`tsc` runs:

  Oidc.ts(471): TS2322: Promise<undici.Response> not assignable to Promise<Response>
  Oidc.ts(472): TS2345: 'URL | RequestInfo' not assignable to undici's RequestInfo

undici's RequestInfo / RequestInit / Response are nominally distinct
from the lib.dom types openid-client's CustomFetch is typed against.
At runtime they're the same shape (Node 24's global fetch is undici
under the hood). Cast through `unknown` at the boundary using
`Parameters<typeof undiciFetch>` for the inputs and
`ReturnType<openidClientLibrary.CustomFetch>` for the return — the
latter sidesteps the fact that `Response` already resolves to Express's
response type from the top-of-file import.

No runtime behavior change. Build, lint, and full app suite (8084
tests, 100% coverage) all pass.
AgentClient.startSse() reset reconnectAttempts to 0 the instant the
axios response headers arrived, before the SSE stream proved it could
stay open. A stream that returned HTTP 200 then ended immediately —
crash-looping agent, reverse-proxy idle timeout — reset the backoff on
every cycle, collapsing exponential backoff into a flat 1s reconnect
loop that hammered the struggling agent. This is the symptom in the
#362 reporter's controller logs: "SSE stream ended. Reconnecting..."
every ~1.00s with no escalation.

The backoff now resets only after the stream stays open for
SSE_STABLE_CONNECTION_MS (30s). A stability timer is armed when the
response arrives and cancelled by scheduleReconnect() if the stream
ends or errors early, so transient connections keep their accumulated
attempt count and the delay escalates to the 60s cap as intended.
Retitle [Unreleased] to [1.5.0-rc.22] and document all seven commits in
the RC: the SSE reconnect-backoff fix (#362), the Authentik SSO
regression fix (#368) and its error.cause-chain logging follow-up, the
i18n parity pass across 16 locales, and the Playwright CI split.

@biggest-littlest biggest-littlest left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rc.22 release prep reviewed — SSE reconnect-backoff fix (#362), Authentik OIDC undici fix (#368), error.cause logging, 16-locale i18n parity, Playwright CI split. Approving for release cut.

@ALARGECOMPANY ALARGECOMPANY left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rc.22 release prep — second code-owner approval. Changes reviewed, app suite green at 100% coverage.

@scttbnsn scttbnsn merged commit 0ddf007 into main May 15, 2026
25 checks passed
@scttbnsn scttbnsn deleted the feature/v1.5-rc22 branch May 15, 2026 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants