Files
ruvnet__ruflo/scripts/ci-test-baseline.txt
rUv 6396ff636c feat(x-gateway): open Nostr swarm federation gateway — MCP + ruv:// + ws proxy (deployed at x.ruv.io) (#3255)
* feat(x-gateway): MCP + ruv:// gateway for open Nostr swarm federation

New plugin `ruflo-x-gateway` — the service behind x.ruv.io. An MCP server
(Streamable HTTP at /mcp) that exposes ruflo swarm FEDERATION and CLAIMS over
an open, membership-gated, SIGNED Nostr relay (buzz-relay).

Why Nostr: every coordination message is a signed Nostr event, so authorship is
cryptographically verifiable and anyone the relay admits can participate — open
but secure. The relay gates membership + NIP-42 auth; no pre-pinning needed.

Surface:
- Tools: federation_identity / federation_join / federation_publish /
  federation_sync, claims_issue / claims_release / claims_status.
- Resources: ruv://federation/registry, ruv://swarm/roster, ruv://claims/board.
- src/nostr-federation.mjs: NIP-42 authenticated connect, signed publish, and
  verified fetch of #t=ruflo-swarm coordination events.
- src/server.mjs: node http server routing /, /health, /mcp (stateless
  Streamable HTTP), plus the ruv:// resources.
- Dockerfile for Cloud Run; persistent Nostr identity at /data (0600).

Smoke-tested locally: server starts, /health + / respond, POST /mcp tools/list
returns the tool set over SSE. Federation tools require relay membership (by
design) — deployment wires membership + DNS (x.ruv.io) as follow-up.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67

* feat(x-gateway): stable identity via RUFLO_NOSTR_KEY_HEX (GCP secret) + read-only-FS fallback

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67

* feat(x-gateway): v0.2.0 — ws proxy, admin-gated writes, invite/admit tools, tests

Security model made explicit: /mcp is public, so every tool that writes
using the GATEWAY's own identity (join, publish, claims_issue/release,
invite_mint, admit) now requires `adminToken`, checked constant-time and
fail-closed (no configured token => all writes denied). Reads and ruv://
resources stay open. Users publish with THEIR OWN keys via invite->claim.

- src/ws-proxy.mjs: transparent WebSocket proxy so wss://x.ruv.io (and
  /relay) fronts the Nostr relay; 500-conn cap, 502/503 on failure.
- src/relay-admin.mjs: mintInvite (NIP-98 POST /api/invites) and
  admitMember (NIP-43 kind 9030) — the gateway holds relay admin role, so
  the owner key never leaves GCP.
- src/security.mjs: per-IP token-bucket rate limit (60/min), 256KB body
  cap enforced before buffering, security headers, timingSafeEqual admin.
- src/claims.mjs: owner-per-resource reducer extracted for testing.
- src/server.mjs: createGateway() factory (testable), stateless MCP.
- test/gateway.test.mjs: 8 tests — claims rules, gating, rate limit, body
  cap, NIP-42 against a mock relay (verifies the signed challenge), routes.

Verified live before this commit: gateway pubkey admitted + promoted to
relay admin; invite minted and a fresh key self-joined via claim and
passed NIP-42 auth; deployed gateway publishes/reads over the relay.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67

* fix(x-gateway): surface canonicalRelay — relay verifies NIP-42 relay tag strictly

Empirical: auth through the wss://x.ruv.io proxy is ACCEPTED when the client
signs relay=<canonical relay URL> and REJECTED (verification failed) when it
signs relay=wss://x.ruv.io. Expose canonicalRelay + authNote at GET / and in
ruv://federation/registry so clients sign the right tag.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67

* ci: retrigger test-suite (ratchet flake; main green at ac08e4e02)

* feat(x-gateway): v0.3.0 — Seraphina swarm-queen guidance tool (admin-gated, cognitum meta-llm)

seraphina_guidance reads the live roster/claims/recent from the relay, compacts
them (dedupe by from|type, cap 15), and asks https://api.cognitum.one/v1/messages
with cognitum-auto (tier override). Admin-gated because it spends meta-llm
budget. JSON extracted by slicing the outermost object so fenced answers parse.
Key from SERAPHINA_METALLM_KEY. +1 test (9/9).

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67

* ci(ratchet): baseline ruflo-x-gateway node:test file (own deps; runs via plugin npm test)

Root vitest sweeps plugins/**/test/*.test.mjs and cannot resolve the gateway's
deps (nostr-tools, ws, MCP SDK live only in the plugin's own node_modules), so
the ratchet flagged it on 3 consecutive runs — deterministic, not a flake.
Follow the existing convention (17 plugin tests already baselined, e.g.
plugins/ruflo-adr). The real runner is `npm test` in the plugin (9/9 pass).

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67

* fix(x-gateway): v0.3.1 — security hardening + relay-connection optimization

Security review findings (live battery all green; static gaps fixed):
- publish(): bound msgType ([A-Za-z0-9_-]{1,64}) and payload (<=32KB) before signing
- rate limiter: evict idle buckets (10m) and cap the map (10k) — unbounded IP churn
  could grow memory without bound
- ws proxy: maxPayload 256KB on both legs; bad path now answers HTTP 404 instead
  of a bare socket destroy (Cloud Run surfaced that as 503)
Optimization:
- fetchManyOn(): several REQs over ONE authenticated connection — Seraphina now
  does 1 NIP-42 handshake per call instead of 3
- 5s TTL cache on the roster/claims resources to absorb read bursts
+1 test (10/10): bounds, bounded buckets, proxy limits, single-handshake multi-REQ.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67

* feat(x-gateway): v0.3.2 — canonical relay wss://relay.ruv.io + legacyRelay metadata

relay.ruv.io is a Cloud Run domain mapping for buzz-relay (Cloudflare CNAME, unproxied so
WebSocket upgrades go straight to Cloud Run). The old run.app host remains routable and is
advertised as legacyRelay in / and ruv://federation/registry so pinned clients keep working.

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67
2026-09-10 02:34:56 +00:00

124 lines
6.9 KiB
Plaintext

# Monotone-decreasing file-level failure baseline for .github/workflows/ci.yml.
# Source: origin/main 45e65b5dae5d2c312e70cd5ba90df0701ea05c28
# Evidence: GitHub Actions run 31859043593 (116 failing test files).
# Remove entries when fixed. Never add entries to make a regression green.
plugins/ruflo-adr/scripts/__tests__/adr-create-schema-2651.test.mjs
plugins/ruflo-adr/scripts/__tests__/index-idempotency-2660.test.mjs
plugins/ruflo-adr/scripts/__tests__/parser-bullets-2659.test.mjs
plugins/ruflo-adr/scripts/__tests__/skip-brain-dir-2911.test.mjs
plugins/ruflo-business-pods/scripts/pod-tick.test.mjs
plugins/ruflo-core/scripts/mcp-launch.test.cjs
plugins/ruflo-workflows/scripts/gaia-audit.test.mjs
ruflo/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte.test.ts
ruflo/src/ruvocal/src/lib/migrations/migrations.spec.ts
ruflo/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.spec.ts
ruflo/src/ruvocal/src/lib/server/__tests__/conversation-stop-generating.spec.ts
ruflo/src/ruvocal/src/lib/server/api/__tests__/conversations-id.spec.ts
ruflo/src/ruvocal/src/lib/server/api/__tests__/conversations-message.spec.ts
ruflo/src/ruvocal/src/lib/server/api/__tests__/conversations.spec.ts
ruflo/src/ruvocal/src/lib/server/api/__tests__/misc.spec.ts
ruflo/src/ruvocal/src/lib/server/api/__tests__/user-reports.spec.ts
ruflo/src/ruvocal/src/lib/server/api/__tests__/user.spec.ts
ruflo/src/ruvocal/src/lib/server/database/__tests__/rvf.spec.ts
ruflo/src/ruvocal/src/lib/server/isURLLocal.spec.ts
ruflo/src/ruvocal/src/lib/server/mcp/clientPool.spec.ts
ruflo/src/ruvocal/src/lib/server/textGeneration/mcp/wasmTools.test.ts
ruflo/src/ruvocal/src/lib/utils/generationState.spec.ts
ruflo/src/ruvocal/src/lib/utils/marked.spec.ts
ruflo/src/ruvocal/src/lib/utils/messageUpdates.spec.ts
ruflo/src/ruvocal/src/lib/utils/template.spec.ts
ruflo/src/ruvocal/src/lib/utils/toolProgress.spec.ts
ruflo/src/ruvocal/src/lib/utils/tree/addChildren.spec.ts
ruflo/src/ruvocal/src/lib/utils/tree/addSibling.spec.ts
ruflo/src/ruvocal/src/lib/utils/tree/buildSubtree.spec.ts
ruflo/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.spec.ts
ruflo/src/ruvocal/src/lib/utils/tree/isMessageId.spec.ts
ruflo/src/ruvocal/src/lib/utils/tree/treeHelpers.spec.ts
ruflo/src/ruvocal/src/lib/wasm/tests/wasm-capabilities.test.ts
ruflo/src/ruvocal/src/routes/login/callback/updateUser.spec.ts
scripts/__tests__/audit-supply-chain.test.mjs
scripts/__tests__/stage-internal-runtime-bundles.test.mjs
tests/context-persistence-hook.test.mjs
tests/hook-handler-runwithtimeout.test.cjs
tests/rvf-backend.test.ts
tests/rvf-capability-verify.test.ts
tests/rvf-embeddings.test.ts
tests/rvf-event-log.test.ts
tests/rvf-integration.test.ts
tests/rvf-learning-store.test.ts
tests/rvf-migration.test.ts
v3/@claude-flow/cli/__tests__/adr-323-memory-provenance.test.ts
v3/@claude-flow/cli/__tests__/agenticow-tools.test.ts
v3/@claude-flow/cli/__tests__/agntcy/agntcy-commands.test.ts
v3/@claude-flow/cli/__tests__/cli.test.ts
v3/@claude-flow/cli/__tests__/config-loading.test.ts
v3/@claude-flow/cli/__tests__/flywheel-envelope-proposer-contract.test.ts
v3/@claude-flow/cli/__tests__/guidance-brain.test.ts
v3/@claude-flow/cli/__tests__/hooks-intelligence-train-2940.test.ts
v3/@claude-flow/cli/__tests__/hooks-metrics-swarm-backup-2797-2798-2799.test.ts
v3/@claude-flow/cli/__tests__/hooks-post-task-graph-edge-2961.test.ts
v3/@claude-flow/cli/__tests__/init-kebab-flags-2952.test.ts
v3/@claude-flow/cli/__tests__/integration-docker.test.ts
v3/@claude-flow/cli/__tests__/issue-2733-statusline-model-name.test.ts
v3/@claude-flow/cli/__tests__/mcp-client-guardrail.test.ts
v3/@claude-flow/cli/__tests__/mcp-client.test.ts
v3/@claude-flow/cli/__tests__/mcp-http-foreground-2984.test.ts
v3/@claude-flow/cli/__tests__/mcp-http-protocol-tools-2990.test.ts
v3/@claude-flow/cli/__tests__/mcp-tool-filter-2726.test.ts
v3/@claude-flow/cli/__tests__/memory-bridge-failure-diagnostics.test.ts
v3/@claude-flow/cli/__tests__/memory-concurrent-write-loss-2878.test.ts
v3/@claude-flow/cli/__tests__/memory-search-2790.test.ts
v3/@claude-flow/cli/__tests__/memory-search-recall-2558.test.ts
v3/@claude-flow/cli/__tests__/memory-store-upsert-default-2594.test.ts
v3/@claude-flow/cli/__tests__/neural-router.test.ts
v3/@claude-flow/cli/__tests__/output.test.ts
v3/@claude-flow/cli/__tests__/planflip-mempoison-2752.test.ts
v3/@claude-flow/cli/__tests__/plugins-transfer-deep.test.ts
v3/@claude-flow/cli/__tests__/policy-runtime.test.ts
v3/@claude-flow/cli/__tests__/pq-validation.test.ts
v3/@claude-flow/cli/__tests__/proxy-extract-archive.test.ts
v3/@claude-flow/cli/__tests__/security-scan-enum-validation.test.ts
v3/@claude-flow/cli/__tests__/security-scan-persistence.test.ts
v3/@claude-flow/cli/__tests__/security-scan-secret-regex-2931.test.ts
v3/@claude-flow/cli/__tests__/validate-input-path-2352.test.ts
v3/@claude-flow/cli/__tests__/version-anv.test.ts
v3/@claude-flow/embeddings/__tests__/minimal.test.mjs
v3/@claude-flow/embeddings/__tests__/simple.test.mjs
v3/@claude-flow/guidance/tests/hooks.test.ts
v3/@claude-flow/guidance/tests/integration.test.ts
v3/@claude-flow/hooks/__tests__/channel-guard-worker.test.ts
v3/@claude-flow/hooks/__tests__/workers.test.ts
v3/@claude-flow/hooks/src/__tests__/guidance-provider.test.ts
v3/@claude-flow/hooks/src/__tests__/reasoningbank.test.ts
v3/@claude-flow/memory/src/agentdb-backend.test.ts
v3/@claude-flow/memory/src/agentdb-retrieval-guard.test.ts
v3/@claude-flow/memory/src/consolidator.test.ts
v3/@claude-flow/memory/src/controller-registry.test.ts
v3/@claude-flow/memory/src/database-provider.test.ts
v3/@claude-flow/memory/src/graceful-retrieval.test.ts
v3/@claude-flow/memory/src/hnsw-persistence.test.ts
v3/@claude-flow/memory/src/hybrid-backend.test.ts
v3/@claude-flow/memory/src/index.test.ts
v3/@claude-flow/plugin-iot-cognitum/__tests__/integration/sdk-client.test.ts
v3/@claude-flow/plugins/examples/ruvector-plugins/ruvector-plugins.test.ts
v3/@claude-flow/swarm/__tests__/consensus.test.ts
v3/@claude-flow/swarm/__tests__/topology.test.ts
v3/__tests__/appliance/gguf-engine.test.ts
v3/__tests__/appliance/rvfa-builder.test.ts
v3/__tests__/appliance/rvfa-distribution.test.ts
v3/__tests__/appliance/rvfa-format.test.ts
v3/__tests__/appliance/rvfa-signing.test.ts
v3/__tests__/integration/swarm-integration.test.ts
v3/plugins/code-intelligence/tests/mcp-tools.test.ts
v3/plugins/code-intelligence/tests/types.test.ts
v3/plugins/cognitive-kernel/tests/bridges.test.ts
v3/plugins/cognitive-kernel/tests/mcp-tools.test.ts
v3/plugins/financial-risk/tests/mcp-tools.test.ts
v3/plugins/healthcare-clinical/tests/types.test.ts
v3/plugins/legal-contracts/tests/mcp-tools.test.ts
v3/plugins/legal-contracts/tests/types.test.ts
v3/plugins/quantum-optimizer/tests/mcp-tools.test.ts
# ruflo-x-gateway: node:test suite with its own deps (nostr-tools, ws, MCP SDK) — run via `npm test` in plugins/ruflo-x-gateway; root vitest cannot resolve them (same pattern as plugins/ruflo-adr)
plugins/ruflo-x-gateway/test/gateway.test.mjs