Files
nekonest-cloud/README.md
T

7.5 KiB
Raw Blame History

NekoNest Cloud

NekoNest Cloud is the private commercial control plane and managed Relay for the open-source NekoNest data plane. Self-hosted NekoNest remains independent: it does not contact this repository, read subscriptions, or display Cloud concepts.

The managed architecture is deliberately not “one Docker Server per customer”:

Daemon / Cloud PWA
  -> stable Connect origin
  -> regional Cloud Relay
  -> TenantEngineRegistry
  -> one isolated relaycore.Engine per tenant
  -> per-tenant SQLite and attachment root

Cloud control plane
  -> account, entitlement, host slots, placement, authorization revisions
  -> short-lived signed authorization snapshots for Relay nodes

One account maps to one tenant/Nest. A host slot is consumed by one non-revoked host identity, whether it is online or not. A copied device credential remains the same identity and the managed Relay rejects a second simultaneous daemon; software cannot prove that a fully copied private key resides on a different physical machine.

Current commercial policy

  • Open-source self-hosting remains free.
  • Cloud is a closed, free test while operational and legal gates remain open.
  • No quote, order, payment, balance, automatic charge, or token resale path is enabled.
  • The existing entitlement/capacity source is authoritative for host slots. Registering the N+1 non-revoked identity returns device_capacity_exceeded; revoking a host releases its slot.
  • Lowering capacity below the active host count is rejected until the user explicitly revokes hosts. Cloud never chooses a device to evict.
  • Price, billing period, refund, subscription-expiry, and payment-provider policy remain outside this implementation.

See docs/commercial-contract.md and docs/launch-gates.md.

Implemented control-plane contracts

  • Account, beta entitlement, host-slot, pairing, claim, device credential, revocation, audit, feedback, retention, and account-exit domain state in D1.
  • Atomic host claiming: an identity retry is idempotent and does not consume a second slot; a different N+1 identity is refused.
  • Stable daemon registration. POST /api/devices/register returns the existing device fields plus connection_state: ready | provisioning and optional retry_after_seconds; it never returns a tenant Relay URL.
  • Regions, Relay nodes, tenant placement, placement generation, authorization revision, opaque route handles, and single-use handoff tickets.
  • Ed25519-signed canonical authorization snapshots with kid, issue/expiry, tenant state, home region, target node, generation, revision, and active credential digests.
  • Relay-node-only internal APIs for live authorization, revision/delta polling, route resolution, and heartbeat. Node calls use scoped identity; clients cannot submit a raw tenant ID.
  • A 60-second, origin-bound, single-use Dashboard-to-PWA handoff. D1 stores only the ticket digest. Exchange creates an independent revocable phone_id, phone_token, and non-authorizing opaque route handle. Completion first records a non-authorizing pending principal; only the first request proving possession of the exact token and route handle activates it and advances the tenant authorization revision. A lost exchange response therefore cannot leave an unused active phone identity.
  • Login or handoff never grants a phone access to a host. The phone must still complete NekoNests per-device E2E pairing and receive that devices key package.
  • Stable ingress resolves the current placement for every new connection and uses authenticated internal HTTPS/WSS forwarding when the home node is elsewhere; clients never receive a node URL or redirect.
  • Fenced backup/restore and migration primitives keep one writable generation. Application-layer tenant purge closes the Engine, deletes live data, attachments and all tenant backups, then clears active credentials only after node acknowledgement. Its completion audit is written only after all D1 postconditions hold, and the purge job's completed marker is the final fenced mutation.

The Cloud PWA is built from an exact NekoNest revision. It points at the stable Connect origin through NekoNest runtime endpoint configuration and refuses any managed endpoint that is not sealed.

The manual cloud-pwa.yml workflow accepts only a full 40-character NekoNest commit SHA, verifies the checkout, runs the PWA tests/type-check/build, writes the deploy-time Connect config, records the source SHA, and emits an immutable build artifact. It does not deploy by itself.

Removed legacy design

The unreleased activation poller, /api/devices/bootstrap, tenant relay_url handoff, managed-device manifest, per-tenant Server container, and single-VPS Node provisioner are intentionally removed. They are not a fallback or a compatibility mode. A daemon with that old managed configuration must re-register.

Local control-plane development

Requires Node.js 22.13 or newer:

npm ci
npm run dev

Production control-plane configuration includes:

  • D1 binding DB from .openai/hosting.json;
  • NEKONEST_CLOUD_ADMIN_EMAILS for the temporary closed-test admin boundary;
  • NEKONEST_CLOUD_CREDENTIAL_SECRET with at least 32 random characters for purpose-separated HMAC digests;
  • Relay snapshot signing keys and active kid;
  • independent Relay-node mTLS identities and an exact origin allowlist for the Cloud PWA;
  • the stable Connect and PWA origins used by registration and handoff.

Sites/ChatGPT identity and the development demo viewer are closed-test scaffolding, not the final public identity or account-recovery decision.

Daemon distribution

The download catalog is fail closed. It accepts only an exact stable NekoNest tag, exact platform assets, checksums.txt, and configured SHA-256 digests; it never follows latest. The compatible daemon must implement protocol 1.3, stable server_url, ready | provisioning, and structured service errors. Artifact hashes do not replace publisher/code signing.

See docs/daemon-distribution.md.

Relay deployment, internal forwarding, migration and purge configuration are documented in docs/relay-operations.md. The manual cloud-relay.yml workflow rejects local replace directives, verifies the requested relaycore/vX.Y.Z tag against go.mod, and runs tests, vet, race checks, and a provenance build with GOWORK=off.

Database

Drizzle schema is in db/schema.ts, with append-only migrations under drizzle/. Runtime migration tracking uses cloud_schema_migrations.

npm run db:generate

Never rewrite a migration already applied to a D1 environment. Because this repository has not yet served production users, a disposable environment may be recreated; any non-disposable D1 database must be exported before migration.

Verification

npm run type-check
npm run lint
npm test

cd relay
go test -count=1 ./...
go vet ./...

The Go Relay has its own tests, race checks, and resource-leak checks. A local green build is not public-service acceptance. Paid/public launch stays blocked until exact-build deployment proves stable ingress, cross-tenant isolation, sealed message and attachment paths, 15-second revocation, five-minute snapshot expiry, backup/restore, deletion/purge, regional migration and rollback, monitoring/on-call, retention, identity, domain/filing, and payment policy.