Skip to content

realtime: IRC EventBus bridge with per-user (hybrid) identity#13

Open
LESdylan wants to merge 15 commits into
audit/web-quality-hardeningfrom
feat/realtime-irc-bridge
Open

realtime: IRC EventBus bridge with per-user (hybrid) identity#13
LESdylan wants to merge 15 commits into
audit/web-quality-hardeningfrom
feat/realtime-irc-bridge

Conversation

@LESdylan

@LESdylan LESdylan commented Jun 9, 2026

Copy link
Copy Markdown
Member

Adds an IRC-backed EventBus so the realtime gateway can bridge to an external RFC 2812 IRC server (e.g. ircserv), with hybrid per-user identity.

What's in it

  • crates/realtime-bus-irc (new): implements EventBus/Publisher/Subscriber. Dependency-free async IRC client; topic↔channel mapping (chat/<room>#<room>); WS PUBLISHPRIVMSG, inbound PRIVMSGEVENT.
  • Hybrid identity: events carrying a user EventSource (kind = Api) are posted through that user's own IRC session (derived nick, real presence — they JOIN the channels they speak in); platform events with no user go out on a shared service nick. The service connection is the sole inbound source (no duplicate events); per-user sessions open lazily and are idle-reaped. Nick derivation is collision-resistant within the server's 9-char limit, with 433 retry.
  • Config wiring: EventBusConfig::Irc { host, port, password, nick, channels, namespace, ... } selectable via build_event_bus; realtime-server depends on the new crate.
  • Gateway: handle_publish stamps EventEnvelope.source (id = claims.sub, handle from claims metadata) so the bus can attribute events to the right user.

Verification

Built under rust:1.89 (matching the Dockerfile): cargo clippy -p realtime-bus-irc -p realtime-server --all-targets is clean (zero warnings; workspace denies unwrap/expect/panic), and cargo test -p realtime-bus-irc passes (10/10).

⚠️ Note on scope

This branch forked from audit/web-quality-hardening and also carries two of your own desktop commits that were committed here between iterations and are not yet on the base:

  • c65e460 feat(desktop): native account migration
  • 1a90935 feat(desktop): native edition bundles gotrue

They're included because they live only on this branch. If you want a realtime-only merge, cherry-pick the four feat(realtime): … commits onto a fresh branch off the base instead — I left the branch history untouched rather than rewrite commits you authored.

LESdylan and others added 15 commits June 9, 2026 18:34
…Docker)

Real accounts are gotrue-managed (password in auth.users, not public.users), and the auth-gateway
delegates to gotrue via the SDK -> /auth/v1. So the native edition needs gotrue:
- build-native.sh: extract the gotrue static Go binary + its 69 migrations from the gotrue image
- supervisor.mjs: start gotrue after firstRun (shares the JWT secret), health-gate on /health
- restProxy.mjs: route /rest/v1->postgrest AND /auth/v1->gotrue (Kong's job, Kong-less)
- main.js: gotrue bin + migrations paths
Verified via --test: register + login round-trip through bridge->gateway->gotrue both return 200.
…ount + data (no Docker)

- native-migrate.sh: dump auth.users/identities + public.users + osionos_* from the Docker stack
  -> ~/.config/osionos/native/import.sql (data-only INSERTs)
- firstrun.importDump: load it after gotrue (which owns auth.users), FK triggers relaxed; strip
  pg_dump 16.4 psql meta-commands (\restrict); normalize imported users aud/role to 'authenticated'
  (older gotrue rows had empty aud -> login 401); mark file done (one-time)
- firstrun MIGRATIONS: match production order (user->gdpr->auth-security->osionos-bridge->folder->
  rls-hardening); gdpr added so users has deletion_requested_at/deleted_at the dump needs
- supervisor: run importDump after gotrue health gate
Verified end-to-end: dump -> import -> login as dylan@gmail.com returns 200 + session; data present.
- Menu.setApplicationMenu(null): kills the LIBDBUSMENU-GLIB-WARNING spam (custom titlebar already)
- will-navigate guard: the main window never leaves app://osionos (Mail/Calendar do location.href
  to an external URL, which stranded you on a blank page with no titlebar) -> external URLs open in
  the system browser instead, osionos stays put with its controls
- crash recovery: render-process-gone reloads to app home; unresponsive reloads; F5 / Ctrl+R reload,
  Ctrl+Shift+H home; global Ctrl/Cmd+Shift+R works even on a fully black screen
- docker-compose.yml: explicit mem_limit for every long-running service
  (nginx static apps 128m, node bridges 512m, vite dev apps 1g, infra
  services per observed usage) so no container can balloon against the host
- mini-baas trino: mem_limit 2g — its JVM sizes heap as 80% of visible RAM
  and was reserving against the whole 31GB host (~900MB RSS idle)
- osionos app.Dockerfile: strip source maps from the runtime image (27.8MB
  of the 43MB html root) and precompress assets for nginx gzip_static

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… three planes

Data plane (Rust): new schema.rs (table/column introspection) and
schema_ddl.rs (DDL statement planning) in data-plane-core, wired through
capability gating, ports, and the postgres/mysql/mongo pools; the server
exposes the new schema routes.

Query router (TS): GET :dbId/schema and POST :dbId/schema/ddl
(schema.controller + schema.service + DTO, with unit specs), plus a
realtime-publisher service that emits change events for live views;
proxy/module/service wiring for the Rust data plane.

SDK: new schema domain (SchemaClient), typed routes/types, rebuilt dist,
node:test suite + type tests and an npm test script.

Verification: scripts/verify/m22-live-database.sh with shared
lib-live-tenant.sh helpers gate the milestone.
…ot tips

- apps/calendar eee3131: /health answers instantly with cached BaaS status
  (container was stuck unhealthy behind a 5s downstream probe)
- apps/osionos/app 7dd6e14: pane-resize perf + React #185 crash fix,
  SettingsCenter chunk split (711->126KB), warm-path code-split restore,
  gzip_static + map-free prod image, live-database client work
- apps/opposite-osiris c81dac57: moved onto the canonical rewritten
  prismatica history (auth-gateway hardening); the old unrelated
  pre-rewrite local history tracked all of node_modules and is obsolete
- vendor/born2root c909d0b: records the sh42 (hellish) checkout
…red 2-10x faster rebuilds

- osionos app.Dockerfile: copy manifests before pnpm install so the install
  layer survives source edits (was re-installing on every build: 44.8s -> 34.0s
  per source change), and parallelize the asset precompression (gzip via
  xargs -P nproc)
- data-plane-router: BuildKit cache mounts for the cargo registry/git/target;
  a Cargo.toml change now rebuilds in 19.5s instead of re-downloading the
  registry and recompiling every dependency (minutes)
- realtime-agnostic: same cargo cache mounts + apt cache; also FIXES the build,
  which was broken — the stub stage was missing the realtime-bus-irc manifest
  so the workspace graph could not resolve (verified: image boots, /v1/health
  200); binary now copied out of the target cache mount
- go/control-plane: GOMODCACHE + GOCACHE cache mounts shared across APP
  variants (second binary builds in 4.0s, was a full cold compile each), and
  drop the build-time 'go mod tidy' which rewrote go.mod inside the image
- apps/baas/.dockerignore (new): the kong image needs two config files but its
  context was the whole 3.2GB directory — allowlist brings it to 390 bytes
- osionos submodule 9056826: recursive **/node_modules + **/.git dockerignore
  patterns (bare names only match at the context root) and the same parallel
  gzip in Dockerfile.prod
…ins, redact JWT secret

- realtime: the running container was on a 2-month-old image — rebuilt from
  the current workspace (IRC bus, per-user sessions) via the Makefile
  orchestrator and recreated; verified healthy with PG CDC + Mongo change
  streams configured
- security: AuthConfig derived Debug printed the JWT secret in plain text in
  the startup log — manual Debug impl redacts it (verified '<redacted>' in
  the live container log)
- realtime-gateway: fix the fanout unit test that no longer compiled after
  the per-user-session channel became (sub_id, event) — 28/28 tests pass
- Docker-first toolchains (no rustc/cargo/go/node on the host): the
  mini-baas Makefile's rust/go/nestjs targets now run inside containers with
  named-volume caches (cargo registry/git + per-workspace target, GOMODCACHE/
  GOCACHE, npm cache + node_modules); new rust-realtime-check/test/build
  targets; same conversion for the realtime-agnostic inner Makefile, whose
  'check' recipe also exited 1 on SUCCESS (grep -v with no residual output) —
  replaced with cargo --quiet
- docker/services/realtime/Dockerfile (wrapper): was pinned to the stale
  2-month-old registry digest with a curl/wget healthcheck that cannot run on
  distroless (no shell) — now tracks the locally built tag and probes through
  the binary
- includes seed-live-demo Makefile target + script (live-database demo
  seeding) so the tree stays coherent
…ngo guards, seed/demo hardening

Data plane (live-probed bug classes, all pinned by the new m23 gate):
- mongo: `_id` survives filters (by-pk update/delete touched EVERY owned
  doc before), ObjectId-hex dual matching, top-level operator guard (400
  instead of driver 502), require_row_filter parity (empty-filter update
  mass-wrote 39 docs live), validator/dup-key → 409
- postgres: enum-slot binding (every enum filter was a 502), hand-rolled
  `numeric` binary encoder (money columns could neither filter nor
  update), class-22 + client-side bind failures → 409, DDL shape errors
  → 400/409
- mysql: truncation/out-of-range → 409 on both paths, DDL shape errors
  classified

Gates & demo:
- scripts/verify/m23-live-edge-battery.sh: dialects, mass-write guards,
  error envelopes, per-engine lifecycles, latency budgets (cached schema
  4ms, 500-row list 16ms, 25k-row aggregate 17ms); 429-retry safe
- m22 resolves ports before compose up (root-stack 5432 clash recreated
  postgres mid-gate); seed-live-demo: sibling-container mongosh (exec
  inside mongod's cgroup OOM-killed it), `_id` validators accept
  ObjectId, VITE_BAAS_TENANT_ID for the dynamic mount catalog
- kong: X-Baas-Tenant-Id in CORS allow-list (browser mount catalog)
- app image: VITE_BAAS_* build args wired through compose; osionos-app
  rebuilt via make osionos-app-live
- repo health: docker-bake.hcl restored (emptied by 45ea260 — make all's
  compose-build was broken), apps/opposite-osiris .gitmodules entry
  restored (make pulls), newsletter healthcheck step guarded
- agency tenant/people generated env state gitignored (live API key)
… workspace

The shared 26-page agency wiki (seed_agency_wiki.py) was invisible to
dylan@gmail.com because he was never a member of the org workspace — the
seeder now grants editor membership idempotently. (The empty mysql-ops /
mongo-activity tables were the OTHER half of the report: rows were
owner-stamped with a previous API key and MySQL/Mongo reads are
owner-scoped; fixed operationally with RESEED=1 which re-stamps owners
with the current app key — no code change needed for that.)
Three shared pages (visibility='shared', uuid5-stable upserts) in dylan's
workspace embedding the new wikiSeed databases: Milestones <-> Files two-way
relation, rollups (file count / total KB), live formulas (health, days left,
age, weight), button properties, and ten views — timeline roadmap, status
board, gallery collection, source board, activity calendar, pinned list, and
the relation-filtered 'Notes — <milestone>' tables (Source=Note AND Milestone
contains <id>). Apply: python3 tools/seeds/seed_delivery_wiki.py <ws> <owner>
| psql (root postgres).
LESdylan added a commit that referenced this pull request Jun 15, 2026
CMEK envelope encryption + crypto-shred is now gate-green (892edf1, m123): mark the
enterprise-procurable scorecard target 7→7.5/10 (last enterprise CODE gap closed —
remainder is purely human/legal: live IdP, SOC2 audit, lawyer), add the CMEK row to
the proven enterprise lane, and rewrite HUMAN-ATOM #13 from "no CMEK code exists" to
"envelope+crypto-shred done via Vault Transit; a cloud-KMS backend (AWS/GCP) is the
optional remaining atom". No co-author.
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.

1 participant