diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f1ab76..ba7c851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Documentation: glossary, FAQ, implementation guide, security guides - Governance RFC workflow and RFC-0001 process - Compliance docs: threat model and DPIA-lite baseline +- Lab-only federation handshake schema + RFC-0002 ### Changed - Clarified LoopSignal voting weight calculations diff --git a/README.md b/README.md index 0fdeaa2..92003b2 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ the repository documentation. - Specification: `SPECIFICATION.md` - API reference: `openapi.json` - Security guide: `docs/security-guide.md` +- Federation handshake: `docs/federation-handshake.md` - Threat model: `docs/compliance/threat-model.md` - DPIA lite: `docs/compliance/dpia-lite.md` diff --git a/docs/federation-handshake.md b/docs/federation-handshake.md new file mode 100644 index 0000000..4f3e8c5 --- /dev/null +++ b/docs/federation-handshake.md @@ -0,0 +1,32 @@ +# Federation Handshake (Lab Only) + +This document defines a **lab-only** handshake payload used to introduce +two LOOP nodes in a controlled demo environment. It does **not** represent +production federation. + +## Goals +- Exchange minimal node metadata. +- Confirm protocol version compatibility. +- Establish a lab-only trust acknowledgement. + +## Handshake request +Schema: `schemas/handshake.schema.json` (`NodeHandshake`). + +Required fields: +- `node_id` (e.g., `munich.loop`) +- `endpoint` (lab API URL) +- `capabilities` (string array) +- `timestamp` (ISO 8601) + +## Handshake response +Schema: `schemas/handshake.schema.json` (`NodeHandshakeResponse`). + +Required fields: +- `status` (`accepted` or `rejected`) +- `peer_id` +- `received_at` +- `lab_only: true` + +## Security notes (lab stage) +- Request signatures are optional placeholders. +- Mutual TLS and request signing are planned for later TRL stages. diff --git a/examples/09-handshake-request.json b/examples/09-handshake-request.json new file mode 100644 index 0000000..5c11652 --- /dev/null +++ b/examples/09-handshake-request.json @@ -0,0 +1,11 @@ +{ + "@context": "https://loop-protocol.org/v0.1.1", + "@type": "NodeHandshake", + "schema_version": "0.1.1", + "node_id": "munich.loop", + "name": "DEMO Munich Node", + "endpoint": "https://demo-munich.loop/api", + "capabilities": ["material-registry", "lab-relay"], + "timestamp": "2025-12-20T10:00:00Z", + "public_key": "-----BEGIN PUBLIC KEY-----MIIB...END PUBLIC KEY-----" +} diff --git a/examples/10-handshake-response.json b/examples/10-handshake-response.json new file mode 100644 index 0000000..f6ac15f --- /dev/null +++ b/examples/10-handshake-response.json @@ -0,0 +1,11 @@ +{ + "@context": "https://loop-protocol.org/v0.1.1", + "@type": "NodeHandshakeResponse", + "schema_version": "0.1.1", + "status": "accepted", + "peer_id": "lab-hub.loop", + "capabilities": ["lab-relay"], + "received_at": "2025-12-20T10:00:05Z", + "lab_only": true, + "message": "Lab handshake accepted." +} diff --git a/rfcs/0002-federation-handshake.md b/rfcs/0002-federation-handshake.md new file mode 100644 index 0000000..5b2c758 --- /dev/null +++ b/rfcs/0002-federation-handshake.md @@ -0,0 +1,32 @@ +# RFC-0002: Federation Handshake (Lab Only) + +## Summary +Introduce a minimal federation handshake payload for lab environments to +exchange node metadata and confirm protocol compatibility. + +## Motivation +Multi-node demos require a clear, documented handshake to show how nodes +announce themselves without implying production readiness. + +## Proposal +Add a `NodeHandshake` request and `NodeHandshakeResponse` schema (v0.1.1) +with a strict `lab_only: true` marker in responses. + +## Security & Privacy +- Handshake signatures are optional placeholders. +- No PII is required. +- Production-grade mutual TLS and signing are deferred. + +## Backwards Compatibility +No breaking changes; this is a new schema for lab-only use. + +## Implementation Plan +1. Add handshake schema + examples. +2. Publish a lab-only handshake endpoint in the demo backend. +3. Document in the docs hub and governance index. + +## Alternatives Considered +- Reuse NodeInfo schema (rejected: lacks handshake semantics). + +## Open Questions +None for v0.1. diff --git a/rfcs/README.md b/rfcs/README.md index 2e4e680..c30d78a 100644 --- a/rfcs/README.md +++ b/rfcs/README.md @@ -4,6 +4,7 @@ This directory contains LOOP Protocol Request for Comments (RFCs). ## Active - RFC-0001: RFC process (v0.1) +- RFC-0002: Federation handshake (lab-only) ## How to submit Use `rfcs/template.md` to create a new RFC and open a PR. diff --git a/schemas/README.md b/schemas/README.md index cc94002..69c3f83 100644 --- a/schemas/README.md +++ b/schemas/README.md @@ -7,6 +7,7 @@ JSON Schema definitions for LOOP Protocol payloads. - `offer.schema.json` (v0.1.1 minimal interop) - `match.schema.json` (v0.1.1 minimal interop) - `transfer.schema.json` (v0.1.1 minimal interop) +- `handshake.schema.json` (v0.1.1 lab federation) - `loopcoin.schema.json` - `loopsignal.schema.json` - `transaction.schema.json` diff --git a/schemas/handshake.schema.json b/schemas/handshake.schema.json new file mode 100644 index 0000000..212eb47 --- /dev/null +++ b/schemas/handshake.schema.json @@ -0,0 +1,134 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://loop-protocol.org/schemas/v0.1.1/handshake.schema.json", + "title": "NodeHandshake", + "description": "Lab-only federation handshake payload for LOOP Protocol v0.1.1", + "oneOf": [ + { "$ref": "#/definitions/HandshakeRequest" }, + { "$ref": "#/definitions/HandshakeResponse" } + ], + "definitions": { + "HandshakeRequest": { + "type": "object", + "required": [ + "@context", + "@type", + "schema_version", + "node_id", + "name", + "endpoint", + "capabilities", + "timestamp" + ], + "properties": { + "@context": { + "type": "string", + "const": "https://loop-protocol.org/v0.1.1" + }, + "@type": { + "type": "string", + "const": "NodeHandshake" + }, + "schema_version": { + "type": "string", + "const": "0.1.1" + }, + "node_id": { + "type": "string", + "pattern": "^[a-z0-9\\-]+\\.loop$", + "examples": ["munich.loop"] + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 120, + "examples": ["DEMO Munich Node"] + }, + "endpoint": { + "type": "string", + "format": "uri", + "pattern": "^https?://", + "examples": ["https://demo-munich.loop/api"] + }, + "capabilities": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + }, + "examples": [["material-registry", "lab-relay"]] + }, + "public_key": { + "type": "string", + "description": "Optional public key for lab validation", + "examples": ["-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----"] + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "signature": { + "type": "string", + "description": "Optional lab-only signature placeholder" + } + }, + "additionalProperties": false + }, + "HandshakeResponse": { + "type": "object", + "required": [ + "@context", + "@type", + "schema_version", + "status", + "peer_id", + "capabilities", + "received_at", + "lab_only" + ], + "properties": { + "@context": { + "type": "string", + "const": "https://loop-protocol.org/v0.1.1" + }, + "@type": { + "type": "string", + "const": "NodeHandshakeResponse" + }, + "schema_version": { + "type": "string", + "const": "0.1.1" + }, + "status": { + "type": "string", + "enum": ["accepted", "rejected"] + }, + "peer_id": { + "type": "string", + "pattern": "^[a-z0-9\\-]+\\.loop$", + "examples": ["lab-hub.loop"] + }, + "capabilities": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + }, + "received_at": { + "type": "string", + "format": "date-time" + }, + "lab_only": { + "type": "boolean", + "const": true + }, + "message": { + "type": "string", + "maxLength": 280 + } + }, + "additionalProperties": false + } + } +}