Skip the Secure flag on the session cookie when the request comes from
a loopback address (localhost, 127.0.0.1, ::1). The Docker image sets
NODE_ENV=production which always enabled Secure, but browsers silently
drop Secure cookies on plain HTTP — breaking the admin panel for
self-hosted users accessing http://localhost:3000.
Fixes#129
Fixed incorrect clone URL (your-username -> BigBodyCobain),
removed stale live-risk-dashboard subdirectory path,
updated pip install to use pyproject.toml instead of requirements.txt,
refreshed project structure tree to match current repo layout,
removed unnecessary dos2unix step from Quick Start.
All .sh files had Windows-style CRLF line endings causing
'bad interpreter' errors on macOS/Linux. Stripped to LF and
added .gitattributes to enforce LF for .sh files going forward.
Closes#126
orjson ships pre-built wheels with AVX2 SIMD instructions that cause
SIGILL (exit code 132) on older processors. This wraps the import in
a try/except and falls back to stdlib json for serialization.
Closes#127
GHCR requires authentication even for public packages on some systems.
CI now pushes to both GHCR and Docker Hub. docker-compose.yml and Helm
chart point to Docker Hub where anonymous pulls always work. Build
directives kept as fallback for source-based builds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Increase gap between alert boxes from 6px to 12px
- Use weighted repulsion so high-risk alerts stay closer to true position
- Reduce grid cell height for better overlap detection (100→80px)
- Double max iterations (30→60) for dense clusters
- Increase max offset from 350→500px for more spread room
- Fix box height estimate to match actual rendered dimensions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SSE broadcast now uses loop.call_soon_threadsafe() when called from
background threads (gate pull/push loops), fixing silent notification
failures for peer-synced messages
- Chain hydration path now broadcasts SSE so gate messages arriving via
public chain sync trigger frontend refresh
- Node participation defaults to enabled so fresh installs automatically
join the mesh network (push + pull)
Relay nodes run in store-and-forward mode with no local gate configs,
so gate_manager.can_enter() always returned "Gate does not exist" —
silently rejecting every pushed gate message. This broke cross-node
gate message delivery entirely since no relay ever stored anything.
Relay mode now skips the gate-existence check after signature
verification passes, allowing encrypted gate blobs to flow through.
Repo migration in March 2026 rewrote all commit hashes, leaving old
clones with a docker-compose.yml that builds from source instead of
pulling pre-built images. Added detection warnings to compose.sh,
start.bat, and start.sh so affected users see clear instructions.
Also exposes APP_VERSION in /api/health for easier debugging.
- Add Server-Sent Events endpoint at GET /api/mesh/gate/stream that
broadcasts ALL gate events to connected frontends (privacy: no
per-gate subscriptions, clients filter locally)
- Hook SSE broadcast into all gate event entry points: local append,
peer push receiver, and pull loop
- Reduce push/pull intervals from 30s to 10s for faster relay sync
- Add useGateSSE hook for frontend EventSource integration
- GateView + MeshChat use SSE for instant refresh, polling demoted
to 30s fallback
Latency: same-node instant, cross-node ~10s avg (was ~34s)
Nodes behind NAT could push gate messages to relays but had no way
to pull messages from OTHER nodes back. The push loop only sends
outbound; the public chain sync carries encrypted blobs but peer-
pushed gate events never made it onto the relay's chain.
Adds:
- POST /api/mesh/gate/peer-pull: HMAC-authenticated endpoint that
returns gate events a peer is missing (discovery mode returns all
gate IDs with counts; per-gate mode returns event batches).
- _http_gate_pull_loop: background thread (30s interval) that pulls
new gate events from relay peers into local gate_store.
This closes the loop: push sends YOUR messages out, pull fetches
EVERYONE ELSE's messages back.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The gate_peer_push endpoint was stripping gate_envelope and reply_to
from incoming events, making cross-node message decryption impossible.
Messages would arrive but couldn't be read by the receiving node.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use cipher0's existing MESH_PEER_PUSH_SECRET so nodes connect
to the relay out of the box without configuration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 1 — Transport layer fix:
- Bake in default MESH_PEER_PUSH_SECRET so peer push, real-time
propagation, and pull-sync all work out of the box instead of
silently no-oping on an empty secret.
- Pass secret through docker-compose.yml for container deployments.
Phase 2 — Per-gate content keys:
- Generate a cryptographically random 32-byte secret per gate on
creation (and backfill existing gates on startup).
- Upgrade HKDF envelope encryption to use per-gate secret as IKM
so knowing a gate name alone no longer decrypts messages.
- 3-tier decryption fallback (phase2 key → legacy name-only →
legacy node-local) preserves backward compatibility.
- Expose gate_secret via list_gates API for authorized members.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>