Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,31 @@ Versioning follows [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [0.4.3] — 2026-07-31

### Fixed

- The Workspace UI load balancer now owns an HTTP-only default site, so its
internal nodes no longer expose a fallback TLS listener without a configured
certificate. The site-specific public TLS layer continues to forward traffic
to the Workspace load balancer on port 80.
- Message-route links render their anchor before surrounding context finishes
loading, preventing valid deep links from appearing unavailable temporarily.
- URL-shaped URNs in message content are rendered as links.

### Requirements and compatibility

- Requirements are unchanged from `0.4.2`: Exordos Core `0.2.3` or newer and
Workspace backend `0.1.18` or newer.
- No Workspace API, persisted-data format, or client data migration changes are
introduced by this release.

### Migration notes

- Update `workspace_ui` to `0.4.3`.

No client or server data migration is required.

## [0.4.2] — 2026-07-29

### Fixed
Expand Down
5 changes: 5 additions & 0 deletions docs/exordos-element.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,8 @@ the Workspace origin to port 80 of the load balancer reported by the deployed
load balancer. The element sets the backend `Host` and `X-Forwarded-Proto`
headers from `forwarded_host` and `forwarded_proto` so realm URLs remain
canonical behind an external TLS or port-forwarding layer.

The element also replaces the load-balancer image's packaged default site with
an HTTP-only port 80 catch-all. This keeps TLS certificates and the public 443
listener at the site-specific edge instead of exposing an unconfigured fallback
TLS listener on the internal Workspace load balancer.
25 changes: 25 additions & 0 deletions exordos/manifests/workspace_ui.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,31 @@ resources:
disk_size: 10
nodes_number: 1

$core.config.configs:
workspace_ui_lb_default_site:
project_id: "12345678-c625-4fee-81d5-f691897b8142"
path: /etc/nginx/sites-enabled/default
mode: "0644"
owner: root
target:
kind: node_set
node_set: $core.network.lb.$workspace_ui_lb:uuid
on_change:
kind: shell
command: nginx -t && systemctl reload nginx
body:
kind: text
content: |
server {
listen 80 default_server reuseport;
listen [::]:80 default_server;
server_name _;

location / {
return 444;
}
}

$core.network.lb.$workspace_ui_lb.backend_pools:
workspace_backend_http:
name: workspace-backend-http
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "0.4.2",
"version": "0.4.3",
"npmClient": "npm",
"packages": [".", "packages/*"],
"command": {
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "workspace",
"private": true,
"version": "0.4.2",
"version": "0.4.3",
"description": "Exordos Workspace - smart corporate messenger built with React/Electron",
"workspaces": [
".",
Expand Down
2 changes: 1 addition & 1 deletion packages/electron/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "exordos-workspace",
"version": "0.4.2",
"version": "0.4.3",
"private": true,
"description": "Exordos Workspace desktop app",
"author": "Exordos <info@genesis-corporation.ru>",
Expand Down
2 changes: 1 addition & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "web",
"version": "0.4.2",
"version": "0.4.3",
"private": true,
"type": "module",
"author": "Exordos <info@genesis-corporation.ru>",
Expand Down
25 changes: 25 additions & 0 deletions scripts/validate-exordos-element.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@ for (const [name, route] of Object.entries(routes)) {
}
}

const defaultSite = manifest.resources["$core.config.configs"]?.workspace_ui_lb_default_site;
if (!defaultSite) {
throw new Error("Workspace UI manifest must own the load-balancer default site");
}
if (
defaultSite.target?.kind !== "node_set" ||
defaultSite.target.node_set !== "$core.network.lb.$workspace_ui_lb:uuid"
) {
throw new Error("Workspace UI load-balancer default site must target its node set");
}
if (defaultSite.path !== "/etc/nginx/sites-enabled/default") {
throw new Error("Workspace UI load-balancer default site must replace the packaged site");
}
if (defaultSite.on_change?.command !== "nginx -t && systemctl reload nginx") {
throw new Error("Workspace UI load-balancer default site must validate and reload nginx");
}

const defaultSiteContent = defaultSite.body?.content ?? "";
if (!defaultSiteContent.includes("listen 80 default_server")) {
throw new Error("Workspace UI load-balancer default site must keep the port 80 catch-all");
}
if (/listen\s+(?:\[::\]:)?443\b|ssl_certificate/.test(defaultSiteContent)) {
throw new Error("Workspace UI load-balancer default site must not configure TLS");
}

const webAction = routes.workspace_web?.condition?.actions?.[0];
if (webAction?.kind !== "local_dir_download" || !webAction.url.endsWith("/workspace-ui.tar.zst")) {
throw new Error("workspace_web must download the workspace-ui.tar.zst artifact");
Expand Down
Loading