github cloudfoundry/stratos v5.0.0
Stratos v5.0.0

3 hours ago

Stratos v5.0.0

Breaking Changes

  • Jetstream now sends a Content-Security-Policy header with the console page by default (#5688). The built-in policy permits only the origins the console itself needs, so a deployment that reaches somewhere else — a metrics or auth endpoint on another host, say — has to set CONSOLE_CSP to a policy of its own, or CONSOLE_CSP=off to send no header. The page is served uncached so each response can carry its own nonce. Settings are described in src/jetstream/config.example.
  • Jetstream now sends X-Content-Type-Options: nosniff on every response, so a browser will not second-guess the content type a response declares. A deployment that serves console assets through a proxy which mislabels them will find those assets rejected rather than silently corrected, so check the content types your proxy emits before upgrading.
  • The Content-Security-Policy nonce is now placed on the console's script tags as well as its style tags, and the default policy's script-src carries 'strict-dynamic' in place of 'self'. Origin no longer confers trust: a script the console did not nonce is refused even when it is served from the console's own address, which is the point of the directive. The console's own module scripts are appended by the frontend build and nonced as the page is served, so a stock deployment is unaffected — but a deployment that injects its own <script> tag into index.html, or serves the page through something that rewrites those tags, will find that script refused unless it carries the nonce. CONSOLE_CSP supplies a policy of your own if you need one.
  • Custom extensions and themes built against 4.x will not work unchanged. Deploying the console as shipped is unaffected, but anything under src/frontend/packages that carries your own code has to be revisited: Angular went from 14 to 22 and TypeScript to 6.0, @ngrx was removed entirely in favour of signal-native services (so an extension that read from the store, used the list framework, or dispatched actions has no equivalent to port to), strict null checks and strictTemplates are now on across the frontend packages, styling moved from SCSS to Tailwind v4, and theme colors are now semantic tokens expressed in OKLCH rather than Material palettes. There is no automated migration for this release — the v4-migration tooling covers 3.x to 4.x only.

Features

  • The frontend no longer uses @ngrx. Every page, list and wizard now reads its data through signal-native services, and the legacy ngrx list framework, router-store, auth/session/dashboard/endpoint/create-app/deploy slices and the schema-only entity catalog are gone. This ran as a long series of waves (#5308 through #5428) covering CF, Kubernetes, Helm, autoscaler, git and core, and the store package is now a fraction of its former size.
  • Every dialog is movable by default (#5645), and setup wizards consistently offer Cancel (#5522). The Add Route stepper was redesigned (#5312).
  • An endpoint whose token has expired is now a first-class state with one-click recovery, rather than presenting as a generic connection failure (#5636). Connect and disconnect show transient states, endpoint dialogs are modeless, and CF section navigation was fixed alongside them (#5642).
  • Sorting uses a tokenized natural comparison with a match-case toggle, so cf1 sorts before cf2 before cf10 (#5368).
  • Bulk operations returned across CF. Lists and cards support selection (#5382, #5665), routes can be deleted or unmapped in bulk and roles managed for several users at once (#5444), and the full set of CF bulk operations is restored with guard tests behind it (#5664). A bulk delete now reports the real settled outcome of each item with live progress rather than an optimistic summary (#5680).
  • All CF entity deletes route through one chokepoint (#5406), which made a blocked-delete state with classified reasons possible (#5407).
  • Work has begun on the Stratos Theme Builder (tools/stb), a build-time theming tool that harvests the running console's styling into a typed facet model and edits it with a live preview and export (#5396, #5503, #5508 through #5546). It is a work in progress and is not ready to be used. It is a developer tool rather than part of the shipped console, and is listed here to record the work, not to invite use.
  • Starred endpoints show on Home regardless of connection state — a starred endpoint that is down renders as a Disconnected card instead of disappearing (#5601).
  • The application detail page merged Instances into Summary, reworked the scaling controls and added live instance telemetry (#5427).
  • Service keys and route service bindings are supported end to end (#4301, #4302) — native Jetstream handlers (#5460) plus the Service Keys (#5461) and Route Services (#5462) pages, with busy states, a per-instance key-count column and count cells anchored to the list they came from (#5470, #5472, #5473).
  • Service instance parameter editing works against the full OSBAPI schema again (#5495), plan parameters can be previewed from the marketplace Plans tab (#5497), and the service instance detail page gained parameters, credentials and uniform linking (#5500). Bind-existing options now render from v3 rows (#5617) and the service instance dashboard link is back (#5491).
  • The CF Users surface was rebuilt on the CF v3 role APIs. There is a selection-driven action bar for Manage Roles and Remove across the CF, organization and space pages (#5475), an Add User dialog that either associates an existing user or sends an invite (#5478), a multi-organization role-assignment widget with space_supporter support and a role registry (#5479), and faster role loading with a view toggle, mixed-role summaries and links from role cells (#5480).
  • Colors are normalized onto semantic theme tokens (#5494, #5496) expressed in OKLCH (#5649), and the remaining light-only placeholder and chart colors now adapt to the dark theme (#5498). The default font is IBM Plex Sans with stylistic alternates enabled for a dotted zero and simple a/g (#5641, #5654).
  • The login page takes its branding from company-config, covering the error strip, inputs, notice and show/hide toggles (#5504).
  • Content-Security-Policy violations are now reported to Jetstream and logged as a security warning, so a resource the policy blocks no longer fails silently. Grep the log for SECURITY:, or filter on security_event if you run with LOG_TO_JSON=true. Set CONSOLE_CSP_REPORT_COLLECTOR to forward a fuller copy of each report to your own collector as well, and CONSOLE_CSP_REPORT_ONLY to trial a stricter policy against real traffic without enforcing it.
  • The built-in Content-Security-Policy now sets object-src 'none', refusing plugin content outright. Previously the directive was absent and inherited default-src 'self', which still permitted <object> and <embed> from the console's own origin. Nothing in the console embeds plugin content.
  • Jetstream now warns at startup if the index.html it is serving carries script tags it cannot nonce. Those tags are appended by the frontend build rather than written by hand, so a change to the form they are emitted in would otherwise surface only as a blank console under a strict policy.

Bug Fixes

  • List paging state is now scope-aware everywhere: navigating to a different data set (another org's spaces, a space tab after wall browsing, another app's tabs) resets to page 1, returning to the same one keeps your place, page position is no longer restored across sessions, and every pager clamps to its last page so stale state can never render an empty page over a non-empty list.
  • Space-scoped tab headers now report the scope's own count: the space Applications tab showed the endpoint-wide total (82 on a 1-app space), and the space Services / User Services headers tracked the filter box instead of the space.
  • Entering a name filter jumps to page 1 of the results and erasing it returns to the page you were on; the space summary page's Applications and Routes tiles now show the space's real counts (they were 0 for every space).
  • A stepper's onEnter is delivered after the activating render rather than before it (#5604), and the variable-editor dialog no longer closes when the editor is resized (#5487).
  • Registering an endpoint surfaces the new GUID so the connect step can use it (#5355), first connect falls back to the last-used username (#5384), a native CF endpoint error is classified as unreachable or auth in the banner (#5385), and the reconnect action in the snackbar opens the connect dialog (#5631).
  • The "All" page size works again in signal-list (#5576), and every app-table consumer now runs on signal-list rather than the retired legacy list framework (#5402, #5405).
  • Deploying an application from GitHub or GitLab works again: Source Config is applied, private repositories authenticate, and an expired token is re-validated rather than silently failing (#5707). File-upload deploy was restored during the signal migration (#5379, #5380), route host/domain/path overrides take effect (#5425), the source/commit picker UX was reworked (#5424), and a failed source fetch now surfaces as a deploy failure instead of an empty wizard (#5623).
  • Favorite and recent entries refresh their display names again after the signal migration, and null metadata no longer breaks the card (#5426, #5430).
  • Switching application tabs no longer remounts the page and refetches environment variables every time (#5519, #5526), and starting an unstaged application reports the real CF error instead of a generic failure (#5520, #5525).
  • Fixed a login redirect loop, and app deletion no longer leaves orphaned routes and bindings behind (#5697). The SSO message banner strips URL lures before rendering (#5681), SSO nosplash is honored for unauthenticated visitors (#5678), and the login background is sized correctly (#5582).
  • When more than one registered endpoint shares a URL, a banner now says so — on CF, Kubernetes and Helm endpoints and in both pickers (#5534, #5698, #5699).
  • Fixed an app-wide denial of Stratos-level permissions caused by the permission checker contract (#5574), so administrative affordances appear for the users entitled to them.
  • CF errors are classified correctly and transient list failures retry instead of surfacing as a hard error (#5580), and the user profile is fetched on first subscription (#5575).
  • The home page's header controls now line up: the Favorites/Connected/All pill sat 3px high at the top and 7px low at the bottom against the card layout chooser, and the divider between them is a rule rather than a "|" character whose size followed the header font. Screen reader users get three fixes in the same row — the sort toggle is no longer announced as one of the "which endpoints to show" choices, the card layout button has a name instead of being an unlabelled icon and now reports whether its menu is open, and the layout options no longer all announce as selected.
  • Deploying an application from a private or self-hosted GitLab now works: the access token entered in the deploy wizard is applied to every GitLab API call (previously only GitHub tokens were sent, so private/self-hosted GitLab lookups were unauthenticated and returned "Repository not found"), and the GitLab base URL is normalized to its /api/v4 REST root so users can enter just the host (e.g. https://gitlab.example.com) instead of the full API URL.
  • GitLab projects in nested subgroups (e.g. group/subgroup/project) can now be deployed: the repository lookup accepts paths with more than two segments and URL-encodes the full path, the repository-suggestions search queries the group namespace (including subgroups) instead of the /users endpoint (which returned "404 User Not Found" for a group path), and the project-name validator no longer rejects nested paths.
  • The deploy wizard no longer reports "Repository not found" while a self-hosted GitLab or GitHub Enterprise base URL is still being typed — the repository check now waits until the entered URL is well-formed instead of querying a half-typed host.
  • Repository suggestions in the deploy wizard now handle project names containing &, # or spaces, which previously truncated the search and returned no matches.
  • The CF capability probe no longer reports v2 support on foundations where the CAPI v2 API is disabled. Such foundations still answer /v2/info with 200 and a blank api_version, which the probe previously read as v2-enabled — leaving V2Info.APIVersion empty and breaking cf push through the deploy wizard. The probe now requires a populated api_version, while still keeping the served /v2/info body for the SSH fields the root document does not carry, so application SSH keeps working (#5727).
  • Session cleanup no longer fails on PostgreSQL, and session validation no longer fails on MySQL and SQLite. The Gorilla session table is called http_sessions on PostgreSQL and sessions on MySQL and SQLite — the session store libraries pick the name, and only two of the three accept one from Stratos — but the statements joining against it are shared by every provider and each hardcoded one of the two spellings. One query was therefore broken on PostgreSQL (expiring session data errored on every cleanup tick, leaving orphaned session_data rows to accumulate indefinitely) and the other on MySQL and SQLite (session validation, reached through the Kubernetes terminal cleanup). The name is now resolved per provider alongside the other dialect differences, and the table Stratos asks the session store to create comes from that same source.
  • The Events tabs no longer drain a foundation's entire audit-event history into browser memory. The frontend loader fetches a bounded newest-first window — 50 pages of 500, the same 25k ceiling the pre-rewrite backend handler enforced — and the comments that still described the departed backend cap now describe the real mechanism (#5536).

Chores

  • Release notes now accumulate as per-PR fragments in changelog.d/, are assembled into the annotated release tag body at make stamp tag and published from the tag by make publish. Fragments are not cleared by a prerelease — they accumulate until the official release, so each prerelease's notes stand on their own rather than sending the reader back through the intermediate ones. make sweep clears them when the official release ships.
  • Added a modern Concourse pipeline (ci/) — gate, nightly audit, and tag-triggered release jobs as thin make callers — plus a shared CI tools image (ghcr.io/cloudfoundry/stratos-ci) consumed by both Concourse and GitHub Actions.
  • go-cfenv updated to v1.19.0, removing the archived mitchellh/mapstructure and joefitzgerald/rainbow-reporter from Jetstream's dependency graph. go-cfenv was the only path to archived mapstructure in the build, and its old go 1.11 directive was also leaking test-only dependencies into Jetstream's module graph.
  • Upgraded to Angular 22 and TypeScript 6.0, having first landed the Angular 21 upgrade (#5304, #5445). Strict null checks (#5448) and strictTemplates (#5622) are now on across the frontend packages, and the ESLint warning backlog that the upgrades exposed was cleared (#5455).
  • The frontend moved to Tailwind CSS v4 (#5354), and the component stylesheet count fell from 280 to 128 as SCSS gave way to utilities (#5357, and the batched :host migrations that followed). There is a Tailwind v4 usage guide in the docs (#5541).
  • Routine dependency updates across the frontend, Jetstream modules and the website throughout the cycle, including the Go toolchain moving to 1.26 (#5465), the test toolchain to Node 26 and Bun 1.3.14 (#5393), and Dependabot switching to the bun ecosystem (#5646).
  • Jetstream tracks the upstream fivetwenty-io/capi/v3 client and no longer carries a fork replace (#5451, #5502). Along the way it picked up typed includes, quota contract fixes, isolation segments, quota-delete jobs and an empty-202 recovery path for managed service instance updates (#5432, #5442, #5443, #5449, #5482).
  • Name-uniqueness checks migrated off the CF v2 API (#5591), and a v3-only CF now sources its auth endpoints from the root links when /v2/info is absent (#5464).
  • Required status checks now report on every pull request, including ones that touch only tools/stb or only docs, which previously left PRs waiting forever on a check that never ran (#5527, #5529, #5564, #5566, #5567). Bun caching and lockfile handling in CI were fixed (#5543), and the CF vitest async leaks behind an intermittent gate hang were tracked down (#5671).
  • End-to-end tests run in tiers with impact-based selection and make dispatch (#5653). Playwright selectors were modernized for the Tailwind frontend (#5615), the data-test contract is complete and guarded by a ratchet (#5648, #5650), and the harness reliability fixes were driven by measured failure classes rather than guesses (#5655, #5568).
  • The documentation website is now Docusaurus 3.10 with Tailwind (#5551), website/docs and docs/ were merged into one tree (#5547), and the site publishes to GitHub Pages (#5586). Docs are linted against a GFM subset (#5548), and there are offline booklets with mermaid diagrams and GFM alerts (#5583).
  • The release lifecycle is owned by make: tag, publish, unpublish and untag (#5684), a CF-pushable zip is published (#5659), and the all-in-one image is thin with a CGO-free pure-Go sqlite driver (#5662). Backend plugins are generated before every build (#5587), make must be run from the repository root (#5563), and version.mk was split into a vendorable core (#5656). Korifi build and release targets exist but are not usable until Korifi auth lands (#5584).
  • Monaco editor is lazy-loaded and bundled through the Angular build as ESM, and assets were right-sized, with load diagnostics added to measure it (#5560, #5651). Per-space enrichment is skipped on the prewarm drain when nothing consumes it (#5614), and endpoint catalogs the endpoint has already loaded are no longer refetched (#5700).
  • Adopted zizmor, osv-scanner, gitleaks and CodeQL as standing scanners (#5616), added a golangci-lint gate and expanded the audit tooling (#5633), and added a dependency-archival audit target (#5683).
  • Bumped the website dependency group: @radix-ui/react-avatar 1.2.6 (restoring React Server Components compatibility), @radix-ui/react-slot 1.3.3, lucide-react 1.27.0, baseline-browser-mapping 2.11.6 and postcss 8.5.24 (#5716), then @easyops-cn/docusaurus-search-local 0.55.3 (#5718).
  • Dependency bumps now reach the release notes on their own: release-notes.sh check reports how many have landed since the last tag and release-notes.sh deps drafts the fragment from them, both reading the chore(deps) commit prefix now pinned in the Dependabot config. make stamp tag runs the check before freezing the tag body, and pull requests that add no fragment get a non-blocking warning on the Files tab.
  • Release notes are now ordered by when each fragment landed on develop rather than by the number in its filename, so entries read in merge order without anyone renumbering them by hand. The number is only there to keep filenames distinct, and two concurrent pull requests picking the same one no longer matters.
  • The Monaco editor wrapper no longer hands consumers the raw Monaco editor instance: its init event emits the typed wrapper component, text changes and language switches go through a typed valueChange output and setLanguage() method, JSON schema diagnostics are configured through the shared Monaco loader, and no component outside the loader touches the window.monaco global anymore. This makes the wrapper's public API the complete editor contract, so any future change of the underlying editor (see #5705) fails at compile time instead of at runtime.
  • Release verbs resolve their default tag from their intent: stamp tag still derives it from the version being released, publish now targets the nearest existing tag (deriving from package.json pointed one release ahead once the post-release bump landed, and --verify-tag aborted having published nothing), and the deletion verbs unpublish and stamp untag no longer guess — they require an explicit TAG=.
  • GitHub allows several releases on one tag, and drafts are invisible to tag-based gh release lookups — the July release run hit both, ending with duplicate releases that could only be deleted by numeric id. publish now refuses a tag that already has a release (draft or published), and unpublish resolves the tag to release ids through the API so drafts and duplicates are previewed and deleted reliably.
  • The release pipeline supports concurrent version lines (5.0.X maintenance beside 5.1.Y development): make stamp line cuts a release/X.Y.x maintenance branch at the line's newest final tag, every nearest-tag derivation is scoped to the checkout's own line, and the Latest pointer — the GitHub release and the docker latest tag alike — no longer moves backwards onto a maintenance patch (#5724, #5723).
  • Content-hashed build artifacts (the Angular bundles and hashed media files) are now served with cache-control: public, max-age=31536000, immutable, eliminating the per-asset revalidation round-trips (and Firefox's full re-downloads) that dominated warm page loads. The allowlist is filename-shaped and default-deny: index.html, assets/, plugin trees, and anything unversioned keep the conservative no-cache policy that guards against cached-data bleed (#5562).
  • Cleared the outstanding frontend advisories — three critical and twenty-seven high, all in the build chain rather than the shipped bundle — mostly as floor raises through overrides (#5754). The website is a separate workspace with its own lockfile and had no overrides block, so none of the root pinning reached it; seven pins cleared the ten high advisories there (#5754).
  • The devkit undici override moved to 7.29.0. The pin at 7.28.0 had itself been a security fix, but that version had since become the vulnerable range for five further advisories, and the pin was what blocked the upgrade (#5754).
  • @babel/core was collapsed onto the already-patched copy. istanbul-lib-instrument resolved 7.28.3, inside the sourceMappingURL arbitrary-file-read advisory, while every other consumer already pinned 7.29.7 — so the tree carried two copies and only one was patched (#5754).
  • Angular moved from 22.0.1 to 22.0.8 (#5747), fast-uri was bumped in the devkit package (#5748), and the website group took baseline-browser-mapping, lucide-react and postcss (#5749), then baseline-browser-mapping 2.11.10 (#5757).
  • Release notes now carry their section headings. The assembler emitted the [Section] authoring syntax verbatim, which is not markdown, so a published release body arrived as one undifferentiated list with bracketed labels sitting in it as plain text. Headings are now emitted as markdown, and BugFixes is displayed as "Bug Fixes".
  • The release tag now has a title. Its message opened straight into the first section header, and since git ends a subject at the first blank line, the header and the whole first bullet became a single run-on subject — which is what git tag -n and the tag list on GitHub display. The subject is now the release name, and the notes follow as the body.

Security Updates

  • Jetstream gained SSRF and path-traversal guards, and its build-chain dependencies were patched (#5624). The remaining high and medium CodeQL alerts were resolved (#5629) and the outstanding Dependabot alerts cleared (#5630).
  • The unmaintained mholt/archiver/v3 was replaced with mholt/archives (#5620).
  • Three fixable CVEs were patched across the Jetstream modules in the shipped backend tree: golang.org/x/text 0.37.0 to 0.39.0 (CVE-2026-56852), golang.org/x/net 0.55.0 to 0.56.0 (CVE-2026-46600) and oras.land/oras-go 2.6.1 to 2.6.2 (CVE-2026-50163) (#5754).

Don't miss a new stratos release

NewReleases is sending notifications on new releases.