S05: NATS endpoint catalog, passthrough and error-bundle docs

This commit is contained in:
George Lambert 2026-09-15 22:17:17 -04:00
commit 0cf87863d4
15 changed files with 1315 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
build/
__pycache__/

7
LICENSE Normal file
View file

@ -0,0 +1,7 @@
Copyright 2026 Verae / George Lambert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files to use, copy, modify,
merge, publish, and distribute, subject to including this notice.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.

11
Makefile Normal file
View file

@ -0,0 +1,11 @@
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build
.PHONY: html latexpdf all
html:
$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)/html"
latexpdf:
$(SPHINXBUILD) -b latex "$(SOURCEDIR)" "$(BUILDDIR)/latex"
cd "$(BUILDDIR)/latex" && pdflatex -interaction=nonstopmode nats-service-endpoints.tex && pdflatex -interaction=nonstopmode nats-service-endpoints.tex
all: html latexpdf

15
README.md Normal file
View file

@ -0,0 +1,15 @@
# nats-service-endpoints
Canonical list of NATS subjects for Verae / PFC / secure-messaging.
* `catalog/endpoints.json` — secure-messaging + admin-config endpoints (full records)
* `catalog/pfc-derived.json` — imported from peergos-for-compliance `subjects.json`
* `catalog/schema.json` — JSON Schema for an endpoint row
* Docs: `source/` (Sphinx HTML + LaTeX PDF)
Hub: https://git.georgelambert.org/marchon/system-git-sync
Passthrough: the **destination** (and NATS subject) may be in the clear; the
**body** is ciphertext. The broker is untrusted.
Not a HIPAA/SOC 2/ISO certificate.

93
catalog/endpoints.json Normal file
View file

@ -0,0 +1,93 @@
{
"version": "1.0.0",
"broker": "untrusted",
"git": "https://git.georgelambert.org/marchon/nats-service-endpoints",
"related": [
"https://git.georgelambert.org/marchon/secure-messaging",
"https://git.georgelambert.org/marchon/peergos-for-compliance",
"https://git.georgelambert.org/marchon/system-git-sync"
],
"encryption_modes": {
"npe": "HPKE X25519-HKKE-SHA256-ChaCha20-Poly1305; dest inbox npe.inbox.<id_fp>",
"lab-xor": "pfc-lab-xor PSK; lab only",
"plain-lab": "JSON body; lab tests only",
"passthrough": "destination and NATS subject in the clear; payload ciphertext"
},
"endpoints": [
{
"name": "verae.sm.send",
"pattern": "core",
"for": "Deliver a passthrough secure message to a mailbox identity",
"from": ["console", "go-leaf", "access-api"],
"to": ["sm-leaf", "npe sidecar"],
"in": {
"header": ["to", "from_lookup_id", "alg", "error_token"],
"body": "ciphertext (not readable by broker or sender after send)"
},
"out": {"ack": {"lookup_id": "string", "accepted": true}},
"encryption": "passthrough-full-body",
"reject": ["missing to", "unsigned config", "alg not in signed config", "empty ciphertext when mode!=plain-lab"],
"dead": "verae.sm.dead"
},
{
"name": "verae.sm.dead",
"pattern": "core",
"for": "Dead-letter failed service requests",
"from": ["sm-leaf"],
"to": ["error-handler"],
"in": {"header": ["error_code", "lookup_id", "to"], "body": "Network Error Bundle"},
"out": "none",
"encryption": "system-key bundle plus sender-only status",
"reject": ["bundle missing ct_system"],
"dead": "none"
},
{
"name": "verae.sm.error",
"pattern": "core",
"for": "Build and emit a Network Error Bundle",
"from": ["sm-leaf", "pfc-admin"],
"to": ["sender (ct_sender)", "system logger (ct_system)"],
"in": {"error_code": "string", "lookup_id": "string", "dest_class": "mailbox|service"},
"out": {"ct_sender": "box to sender", "ct_system": "box to system public key"},
"encryption": "no recipient payload; bounce metadata only",
"reject": ["unknown error_code"],
"dead": "verae.sm.log.summary"
},
{
"name": "verae.sm.log.summary",
"pattern": "core",
"for": "Central log summaries of system failures (no message bodies)",
"from": ["sm-leaf", "pfc-admin"],
"to": ["central-log"],
"in": {"code": "string", "lookup_id": "string", "dest_class": "string"},
"out": "ack",
"encryption": "summary plaintext allowed; never ciphertext of mail",
"reject": ["body-like fields present"],
"dead": "none"
},
{
"name": "verae.admin.config.sign",
"pattern": "core",
"for": "Sign a new configuration payload; reject unsigned files at load",
"from": ["pfc-console", "pfc-config TUI"],
"to": ["admin-history cube"],
"in": {"payload": "object", "prev_signed": "object|null"},
"out": "signed wrapper",
"encryption": "Ed25519 signature; payload may be lab-clear",
"reject": ["bad key_id", "canonical JSON mismatch"],
"dead": "verae.sm.dead"
},
{
"name": "verae.admin.history.append",
"pattern": "core",
"for": "Append prev file, new file, and unified diff to DataCube admin-history",
"from": ["verae.admin.config.sign"],
"to": ["pfc CubeStore kind=admin-history"],
"in": {"prev": "string", "new": "string", "diff": "string", "actor": "string"},
"out": "chain row",
"encryption": "chain hashes; not NPE (admin audit)",
"reject": ["empty actor"],
"dead": "none"
}
]
}

1001
catalog/pfc-derived.json Normal file

File diff suppressed because it is too large Load diff

28
catalog/schema.json Normal file
View file

@ -0,0 +1,28 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "NATS-Service-Endpoints catalog",
"type": "object",
"required": ["version", "endpoints"],
"properties": {
"version": {"type": "string"},
"endpoints": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "for", "from", "to", "in", "out", "encryption", "reject"],
"properties": {
"name": {"type": "string"},
"pattern": {"type": "string"},
"for": {"type": "string"},
"from": {"type": "array", "items": {"type": "string"}},
"to": {"oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}]},
"in": {},
"out": {},
"encryption": {"type": "string"},
"reject": {"type": "array", "items": {"type": "string"}},
"dead": {"type": "string"}
}
}
}
}
}

View file

@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""Merge peergos-for-compliance subjects.json into catalog/pfc-derived.json."""
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PFC = Path("/Users/marchon/research/peergos-for-compliance/schemas/subjects.json")
OUT = ROOT / "catalog" / "pfc-derived.json"
def main() -> None:
src = json.loads(PFC.read_text())
rows = []
for s in src.get("subjects") or []:
rows.append(
{
"name": s["name"],
"pattern": s.get("pattern"),
"for": "PFC/Verae subject (see peergos-for-compliance/docs/nats-addresses.md)",
"from": ["pfc services", "connectors"],
"to": [s.get("owner") or "unknown"],
"in": {"fields": s.get("payload") or []},
"out": "service-specific",
"encryption": "NATS envelope pfc-lab-xor or NPE sidecar; Pattern A apps never publish",
"reject": ["unknown subject", "missing required fields"],
"dead": "none",
"git": "https://git.georgelambert.org/marchon/peergos-for-compliance",
}
)
OUT.write_text(json.dumps({"version": src.get("version"), "endpoints": rows}, indent=2) + "\n")
print("wrote", OUT, "n=", len(rows))
if __name__ == "__main__":
main()

10
source/conf.py Normal file
View file

@ -0,0 +1,10 @@
project = "NATS Service Endpoints"
copyright = "2026, Verae"
author = "Verae / George Lambert"
extensions = []
html_theme = "alabaster"
latex_engine = "pdflatex"
latex_documents = [
("index", "nats-service-endpoints.tex", "NATS Service Endpoints", "Verae", "manual"),
]
latex_elements = {"papersize": "letterpaper", "pointsize": "11pt"}

18
source/config.rst Normal file
View file

@ -0,0 +1,18 @@
Signed configuration
====================
A config file is unusable unless it is an Ed25519 wrapper::
{ "payload": { ... }, "sig": { "alg": "ed25519", "key_id": "...", "signature": "hex" } }
Select algorithms inside **payload** (the signed object):
* ``crypto.mode``: ``npe`` | ``lab-xor`` | ``plain-lab``
* ``routing.mode``: ``passthrough``
* ``admin.history_cube``: cube id for admin-history
* ``crypto.system_key_id``: system public key id
* ``logging.mode``: ``summary``
After an admin console change: sign again, then append previous file, new
file, and unified diff to the admin-history DataCube
(``verae.admin.history.append``).

17
source/endpoints.rst Normal file
View file

@ -0,0 +1,17 @@
Endpoint records
================
Full JSON: ``catalog/endpoints.json``. PFC import:
``catalog/pfc-derived.json`` from
https://git.georgelambert.org/marchon/peergos-for-compliance/src/branch/main/schemas/subjects.json
Secure-messaging subjects
-------------------------
* ``verae.sm.send`` -- passthrough deliver; from console/leaf; reject unsigned
config and empty ciphertext (unless ``plain-lab``).
* ``verae.sm.dead`` -- dead letter; Network Error Bundle in body.
* ``verae.sm.error`` -- emit bundle: ``ct_sender`` + ``ct_system``.
* ``verae.sm.log.summary`` -- central summaries (codes, lookup_id, dest_class).
* ``verae.admin.config.sign`` -- Ed25519 wrap; unsigned files rejected.
* ``verae.admin.history.append`` -- prev, new, unified diff on DataCube chain.

13
source/errors.rst Normal file
View file

@ -0,0 +1,13 @@
Errors and Network Error Bundle
================================
Never put the intended recipient payload in an error object.
* **ct_sender** -- failure status encrypted so **only the sender** can read it.
* **ct_system** -- bounce report encrypted to the **system public key** for
logging/recovery (lookup_id, error_code, dest_class, respond flag).
* **Dead letter** -- ``verae.sm.dead`` with the same bundle.
* **Central log** -- ``verae.sm.log.summary``: codes only.
The sender identifies the original message with ``lookup_id``, not by
decrypting what they sent.

29
source/index.rst Normal file
View file

@ -0,0 +1,29 @@
NATS Service Endpoints
======================
Canonical catalog for Verae / PFC / secure-messaging on
https://git.georgelambert.org/marchon/nats-service-endpoints
The NATS broker is **untrusted**. Production E2E is NPE (HPKE). Lab may use
``pfc-lab-xor``. This is **not** a HIPAA/SOC 2/ISO certificate.
Related: `system-git-sync <https://git.georgelambert.org/marchon/system-git-sync>`_,
`secure-messaging <https://git.georgelambert.org/marchon/secure-messaging>`_,
`peergos-for-compliance <https://git.georgelambert.org/marchon/peergos-for-compliance>`_.
.. toctree::
:maxdepth: 2
passthrough
endpoints
errors
config
tracing
Passthrough
-----------
Destination mailbox id and the NATS subject may be in the clear so routers
can work. The **body** is ciphertext. After send, the sender cannot open
that ciphertext; they keep a ``lookup_id`` only. The same rule applies to
the responder.

15
source/passthrough.rst Normal file
View file

@ -0,0 +1,15 @@
Passthrough routing
===================
::
sender --(ct, to, lookup_id)--> NATS subject
| |
| v
| sm-leaf / NPE
| |
+---- lookup_id only ---- v
recipient mailbox
Header (clear): ``to``, ``from_lookup_id``, ``alg``, ``error_token``.
Body: ciphertext. Broker must not log ``ct``.

18
source/tracing.rst Normal file
View file

@ -0,0 +1,18 @@
Message tracing
===============
Happy path::
1. Load signed config (reject if unsigned).
2. seal(body) -> envelope with to + ct + lookup_id.
3. Publish verae.sm.send.
4. Leaf acks {accepted:true, lookup_id}.
5. Recipient opens ct with NPE (prod) or lab-xor (lab).
Failure path::
1. Leaf cannot deliver.
2. Build Network Error Bundle (no mail body).
3. Publish verae.sm.dead and verae.sm.error.
4. Sender opens ct_sender; ops opens ct_system.
5. Summary to verae.sm.log.summary.