mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-09-14 14:01:28 +08:00
8485302f10
* feat(x-gateway): 0.6.1 — Seraphina bounded by budget, not by an admin token Squashes what is actually running on x.ruv.io so git and production agree. Seraphina was gated alongside the write tools, but it is not like them: it reads the roster, the claims board and recent messages, asks a model, and returns advice. It writes nothing and carries no authority. The gate answered the wrong question — the exposure is model spend, and spend is bounded with a budget, not a password. The practical cost was worse than a wrong abstraction. A browser cannot hold a bearer secret, so a published UI was either locked out or tempted to ship RUFLO_ADMIN_TOKEN to the client — the same token that mints invites and publishes as the gateway identity. The safe-looking option was the catastrophic one. Seraphina now answers with no token, bounded by a shared daily cap and a per-client hourly cap, and anonymous callers cannot select the high or ultra tiers. An admin token lifts both. Every write tool keeps its gate; verified live that claims_issue, federation_invite_mint, federation_publish, federation_admit and channel_publish all still refuse an anonymous caller. Not included, deliberately: a tool to relay member-signed events through the gateway. It was built, tested against the live relay, and removed. buzz-relay refuses any EVENT whose pubkey differs from the NIP-42 authenticated connection, so a gateway cannot publish on another identity's behalf — and it does not need to. Members already publish as themselves through the wss://x.ruv.io proxy, verified end to end. Shipping a tool that always fails would be worse than none. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67 * feat(x-gateway): serve onboarding guidance, and deliberately not key generation The registry said "generate a Nostr keypair" and stopped, and it never named the two identities in play. That gap was not theoretical: a capable agent inspected the surface, found only gateway-signed publishing, and concluded ordinary members could not publish from a dashboard at all. They can. It just was not written anywhere they could reach. federation_onboarding and ruv://federation/onboarding now answer it, open, no token. The guide leads with the distinction that causes the confusion — your key signs for you, the gateway's key signs for the service, and the gated tools are gated precisely because they speak as the service. It carries the five steps, the four things never to do, and the three traps this service has actually taught us: sign the NIP-42 relay tag with the canonical URL even when proxied, the relay binds publishing to the authenticated connection, and the channel tag is `c` not `h`. It does NOT generate keys, and that is the point rather than an omission. A service that mints your keypair and returns the secret has seen your secret, and becomes custodian of every identity it "helped" — the same custody mistake as putting an admin token in a browser, inverted. The guide ships the code so the caller runs it locally and the key never crosses the wire. One test note worth keeping: the first version of the safety assertion regex- matched for "send your secret" and failed on the guide's own "Never send your secret key" line. It is now structural — no field may be named for secret material — because a string search cannot tell an instruction from its negation. Verified live on 0.7.0 (ruflo-x-gateway-00015-qj7) with an anonymous call. 20/20. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67 * fix(ci): register the gateway's credential and budget knobs, and skip test/ like tests/ The ADR-125 precedence audit failed the gateway PR, and it was right to look — but for two reasons that are both about the audit, not the code. RUFLO_ADMIN_TOKEN was not registered as an escape hatch even though its sibling RUFLO_X_ADMIN_TOKEN is, with the same reasoning: a secret must never be a CLI flag, where it lands in shell history and process listings. The gateway is a long-running service with no typed command surface at all, so there is no invocation to attach a flag to. Same for the two Seraphina budget knobs added in #3275. The other half was a naming gap. SKIP_DIRS already excludes `tests` and `__tests__` because the audit is about production precedence, not test setup — but the flagged lines were in `plugins/ruflo-x-gateway/test/`, singular, which was not in the set. Two `process.env.X = 'test-admin-token'` assignments inside a test fixture were reported as undeclared production reads. Verified: the audit now exits clean on this branch. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67