Claude 59ae4d8ad2 test+feat(phase-bc): pass 4 — test coverage, install endpoint, CHANGELOG
Final in-sandbox completeness pass. Five focused pieces; the remaining
items in PHASE_BC_LOCAL_TODO.md after this commit are all genuinely
local-only (toolchain, network, native deps).

Test coverage (the biggest gap from prior reviews)
- Server/plugin/manifest_test.go — pluginNameRegexp accept/reject table,
  validateRelativePath table, oversized version, unknown permission.
- Server/plugin/host_http_test.go — hostAllowed dot-boundary suffix,
  empty-entry rejection, case insensitivity, FQDN trailing dot. ipAllowed
  table over loopback, RFC1918, RFC4193 (ULA), RFC6598 (CGN), link-local,
  multicast, unspecified — both v4 and v6 — plus public-IP accept cases.
- Server/plugin/loader_test.go — rejectSymlinksUnder catches direct and
  nested symlinks; scanPluginDirectory rejects a plugin whose entrypoint
  is a symlink. Skipped on Windows where symlink creation needs elevation.
- Server/plugin/host_ui_test.go — AssetHandler serves declared files,
  rejects undeclared files (404), rejects path traversal, supports nested
  asset paths.
- Server/ws/hub_seedseq_test.go — SeedSeq monotonic, never-backwards,
  concurrent CAS safety, integration with nextSeq.
- Server/ws/extract_event_type_test.go — table covering happy paths,
  control char rejection, escaped quote rejection, length cap (64),
  empty/missing/non-JSON inputs.

Plugin install endpoint (closes a real feature gap)
- Server/plugin/registry.go — InstallFromZip extracts a plugin .zip into
  a staging directory under cfg.Directory, validates it zip-slip safe
  (cleaned-path Rel check), refuses non-regular entries, refuses
  symlinks, caps compressed at 16 MiB and uncompressed total at 64 MiB
  (each file gated by io.CopyN against the remaining budget). Manifest
  is parsed at the staged root, then atomically renamed into the
  canonical plugin directory and registered via the existing
  installFromDisk path.
- Server/api/plugins_handler.go — POST /install accepts multipart with
  one "plugin" file part, http.MaxBytesReader caps the request body,
  io.LimitReader caps the in-memory buffer, calls Registry.InstallFromZip,
  returns 201 with the new plugin name. The endpoint inherits the Pass 2
  admin auth + IP gate (mounted under r.Use(admin.RequireAdminAuth)).

Protocol surface
- Server/ws/serve.go — buildAuthOK now takes replaySource and includes
  it in the auth_ok payload as "replay_source": "none" | "buffer" | "db".
  Two call sites updated: reconnect path passes the existing local,
  fresh-connect path passes "none". Test export updated to pass "none".

CI build-tag matrix
- .github/workflows/ci.yml — three new steps inside server-build-test
  build the server with -tags otel, -tags wazero, and -tags otel,wazero.
  All three are continue-on-error: true until the upstream OTel and
  wazero modules land in go.mod (tracked in PHASE_BC_LOCAL_TODO.md).
  Once they do, dropping continue-on-error converts the steps into
  hard CI gates against tag-boundary drift.

Documentation
- CHANGELOG.md — new root-level file with curated entries for Phase B,
  Phase C, security, and behavioural changes operators must know about
  (notably event_persistence.enabled = true by default).
- PHASE_BC_LOCAL_TODO.md — ticks off the install endpoint, the
  replay_source field, and the existing event_persistence defaultYAML
  entry. The remaining items are toolchain-bound.

After this pass, the in-sandbox completeness ceiling is reached.
Everything still pending requires Go 1.25 toolchain, npm install,
real OTel SDK + wazero modules, sqlc, postgres backend impl, or
tinygo.

https://claude.ai/code/session_01UsBsQW2YiA2usk9pnJjAWk
2026-04-06 10:30:18 +00:00

stability-experimental

Go TypeScript NPM

OwnCord

The gaming chat platform you actually own.

Early Alpha / Work in Progress OwnCord is in active development and is not production-ready. Expect rough edges, rapid changes, and occasional breaking behavior.

Do not use it for sensitive communications yet.

Development Model

OwnCord is built with an AI-first development workflow. Most implementation is generated through autonomous AI tooling, with quality validated primarily through automated checks (CI, tests, linting) and real-world feedback during alpha.

This approach enables fast iteration, but it also means behavior may change quickly between releases.

OwnCord is a self-hosted chat stack with a Go server and a Tauri desktop client. It includes real-time messaging, voice/video via LiveKit, file sharing, and a web admin panel.

OwnCord Client

Login Page Admin Panel

Current Project Status

Area Status
Core chat flow Working in alpha
Voice/video Working in alpha
Admin panel Working in alpha
Security hardening In progress

Platform Support (Current Releases)

Component Windows x64 Linux x64 Linux ARM64
Server binary Yes Not published yet N/A
Desktop client Yes Not published yet Not published yet
Docker server N/A Not published yet N/A

Start Here

Quick Start

Option A: Prebuilt binaries

  1. Download assets from GitHub Releases.
  2. Run the server binary:
    • Windows: chatserver.exe
    • Linux: ./chatserver
  3. Open https://localhost:8443/admin and create your Owner account.
  4. Generate invite codes in the admin panel and share them with friends.

Option B: Docker (Linux server)

cd Server
cp .env.example .env
cp livekit.yaml.example livekit.yaml
# Edit both files before starting
docker compose up -d

See the full setup guide in docs/deployment.md.

The client uses TOFU (Trust On First Use) for self-signed certificates: it prompts once, then pins the certificate for future connections.

What OwnCord Already Has

  • Real-time channels and direct messages over WebSocket
  • Voice/video channels via LiveKit
  • Invite-only registration and role-based permissions
  • Web admin panel with logs, backups, and update tooling
  • File uploads and inline media rendering
  • TOTP 2FA support and API rate limiting
  • Desktop client auto-update with signature verification

See deeper feature and architecture docs in docs/client-architecture.md and docs/protocol.md.

Architecture

Two main components:

  • Go server (REST API, WebSocket hub, SQLite, admin panel)
  • Tauri v2 desktop client (Rust backend + TypeScript frontend)
+---------------------+         +---------------------+
|   OwnCord Client    |         |   OwnCord Server    |
|   (Tauri v2)        |         |       (Go)          |
|                     |         |                     |
|  +---------------+  |  WSS    |  +---------------+  |
|  |  Chat UI      |--+------->|  |  WebSocket Hub|  |
|  +---------------+  |         |  +---------------+  |
|  +---------------+  |  HTTPS  |  +---------------+  |
|  |  REST Client  |--+------->|  |  REST API     |  |
|  +---------------+  |         |  +---------------+  |
|  +---------------+  | LiveKit |  +---------------+  |
|  |  Voice/Video  |--+------->|  |  LiveKit SFU  |  |
|  +---------------+  |         |  +---------------+  |
+---------------------+         |  +---------------+  |
                                |  |  SQLite DB    |  |
                                |  +---------------+  |
                                +---------------------+

Build and Test

Prerequisites

  • Go 1.25+
  • Node.js 20+
  • Rust stable (client builds)

Build from source

# Server (Windows)
cd Server
go build -o chatserver.exe -ldflags "-s -w -X main.version=1.0.0" .

# Server (Linux)
cd Server
CGO_ENABLED=0 go build -o chatserver -ldflags "-s -w -X main.version=1.0.0" .

# Client
cd Client/tauri-client
npm install
npm run tauri build

Core verification commands

# Server
cd Server
go test ./...

# Client
cd Client/tauri-client
npm run typecheck
npm run lint
npm test

For the full command set, use docs/contributing.md.

Configuration

On first run, the server generates config.yaml and a local data/ directory:

data/
├── chatserver.db
├── certs/
├── uploads/
└── backups/

Key options include TLS mode, upload limits, LiveKit settings, and admin CIDR restrictions. See docs/server-configuration.md.

Security and Vulnerability Reporting

  • For vulnerabilities, use GitHub Security Advisories (private disclosure flow).
  • Do not open public issues for security bugs.
  • Read full policy and hardening notes in docs/security.md.

Update Signing Notes (Maintainers)

Client and server update signing keys are intentionally separate.

Required Actions secrets for release signing:

  • TAURI_SIGNING_PRIVATE_KEY
  • TAURI_SIGNING_PRIVATE_KEY_PASSWORD
  • SERVER_UPDATE_SIGNING_PRIVATE_KEY
  • SERVER_UPDATE_SIGNING_PRIVATE_KEY_PASSWORD

When rotating the server updater key, update Server/updater/server_update_public_key.txt and use staged rollover for live fleets.

Docs Index

Contributing

  1. Create a branch from dev.
  2. Keep changes focused and tested.
  3. Open a PR targeting dev.

See docs/contributing.md for the full process.

License

AGPL-3.0

S
Description
OwnCord is a self-hosted, open-source chat platform with text channels, voice/video chat, direct messages, and a desktop client — built for communities that want full control over their data.
Readme AGPL-3.0
111 MiB
Languages
TypeScript 48.7%
Go 44%
JavaScript 2.2%
Rust 2.1%
CSS 1.4%
Other 1.5%