Files
OwnCord/CHANGELOG.md
T
J3vbandClaude Fable 5 b4c34d2bc6 chore(repo): P0 hygiene for the alpha reset
- gitignore .serena/ and Client/tauri-client/.env; untrack the .env
  (the KLIPY key it held is treated as burned; rotation + server-side
  proxy tracked for P3)
- CI: verify generated sqlc output (make sqlc-verify) on the ubuntu leg
- CHANGELOG: honest reset narrative (v1.1.0-alpha series), remove
  references to deleted roadmap files
- delete stale docs/phase-a-status.md; fix dangling ref in
  docs/plans/slash-commands.md
- add root SECURITY.md (GitHub-surfaced policy; reporting works while
  the source repo is private)
- docs/audit-2026-04-07.md: add maintained finding-closure table

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:17:29 +02:00

5.6 KiB

Changelog

All notable changes to OwnCord are listed here. The repository's release tooling (npm run changelog) auto-generates entries from commit messages on each release; this file is the curated counterpart that calls out behavioural changes operators must know about.

Unreleased — v1.1.0-alpha series (Phase B + C)

Project reset note: OwnCord has re-entered alpha. The v1.0.0 release is superseded; versioning continues forward as v1.1.0-alpha.N so deployed servers and clients keep receiving updates. Releases are published to the public OwnCord-releases repository, including a full source snapshot with every release.

Phase B — Acceleration

  • Event persistence layer (Step 7). A new events table backs the WebSocket reconnect path. When a client's last_seq is too old for the in-memory ring buffer (~1000 events), the server now falls back to a SQLite query before forcing a full re-sync. The hub seeds its monotonic sequence counter from MAX(events.seq) at startup so row seqs and wrapped-payload seqs stay aligned across restarts. Configurable via the new event_persistence block; enabled by default (see "Behavioural changes" below).
  • Tiered reconnect telemetry. auth_ok now includes a replay_source field ("none" | "buffer" | "db") so clients can attribute reconnection behaviour. The same tier label is exported as the ws_reconnect_tier_total{tier} counter.
  • OpenTelemetry skeleton (Step 8). Public API + no-op default provider in Server/telemetry/. Chi router middleware mounted unconditionally. Service-layer spans on MessageService.SendMessage, PermissionService.HasChannelPerm, ChannelService.ListVisibleChannels, DMService.CreateDM, VoiceService.JoinChannel, InviteService.CreateInvite, ModerationService.BanUser, BlockService.BlockUser, UserService.UpdateProfile. The real OTel SDK is gated behind -tags otel and is currently a placeholder; completing it is deferred until after the beta reset.
  • Solid.js proof of concept (Step 6). Two leaf components migrated (Badge, ChannelListItem), Vite + JSX configured, store→signal adapter landed. The remaining vanilla components remain in place; migration is mechanical and tracked in the local TODO.

Phase C — Differentiation

  • Plugin runtime skeleton (Step 9). New Server/plugin/ package with manifest parser, on-disk loader, registry, and host capability surfaces (commands, events, storage, http, ui). Manifest format is JSON (plugin.json); the design's TOML format is gated behind the -tags wazero build and tracked locally.
  • Plugin admin REST surface. Lifecycle endpoints under /api/v1/admin/plugins: list, enable, disable, uninstall, and the new install path that accepts a multipart zip upload, validates it zip-slip safe with size + symlink rejection, and atomically installs it. Mounted under both AdminIPRestrict and the admin.RequireAdminAuth session/permission middleware.
  • Plugin admin client bridge. pluginBridge.ts mounts plugin UI tabs in sandboxed iframes with origin-validated postMessage routing.

Security

  • SSRF defense for http capability. Plugin outbound HTTP requests are now validated through net/url.Parse, suffix-matched with a dot boundary (so evil-api.example.com does not match api.example.com), and rejected for empty allowlist entries. A custom Transport.DialContext re-resolves DNS on every dial and refuses any resolved address in loopback / RFC1918 / RFC4193 / RFC6598 (CGN) / link-local / multicast / unspecified ranges. Closes the DNS-rebinding TOCTOU window. Response body is capped at 5 MiB.
  • Plugin manifest hardening. Manifest.Name must match ^[a-z0-9][a-z0-9_-]{0,63}$. Entrypoint and UI tab asset paths are rejected if absolute, non-canonical, contain .., or contain NUL bytes / backslashes.
  • Plugin asset handler. Defends against symlink escapes (rejected at install time via filepath.Walk + Lstat) and prefix-without- separator path traversal (via filepath.Rel check after join).
  • Plugin postMessage routing. The host bridge looks up the trusted pluginId via e.source -> contentWindow instead of trusting the pluginId field in the message body. Spoofed messages from any non-iframe source are dropped.

Behavioural changes operators must know about

  • event_persistence.enabled defaults to true. Every broadcast WebSocket event is written to the events table, retained for 24 hours by default, and pruned by a background goroutine every hour. This is a new on-disk write path that did not exist before. Disable it by adding to config.yaml:
    event_persistence:
      enabled: false
    
  • DM events are persisted under the same retention. Operators with GDPR or compliance requirements should review the retention window and consider setting event_persistence.enabled: false until a per-channel-type opt-out lands.
  • Plugin admin endpoints require admin session auth in addition to the existing IP restriction. A previous prerelease shipped with only the IP gate; that has been corrected.

Deferred work

The project is under a feature freeze until the beta reset completes. Explicitly deferred (not abandoned unless noted): real OpenTelemetry SDK wiring, the Postgres backend (scaffolding removed pending real demand), the slash-command dispatcher (docs/plans/slash-commands.md), and the Solid.js migration (abandoned — the experiment is being removed in favor of the established vanilla component pattern).