[agent/codex] Full AX v0.8.0 compliance review. Read CODEX.md and .core/re... #13
11 changed files with 115 additions and 157 deletions
|
|
@ -40,7 +40,7 @@ logging/ — Structured levelled logger with component scoping (stdlib only)
|
|||
|
||||
### Data flow
|
||||
|
||||
1. **Identity** (`identity.go`) — Ed25519 keypair via Borg STMF. Shared secrets derived via X25519 ECDH + SHA-256.
|
||||
1. **Identity** (`identity.go`) — X25519 keypair via Borg STMF. Shared secrets derived via X25519 ECDH + SHA-256.
|
||||
2. **Transport** (`transport.go`) — WebSocket server/client (gorilla/websocket). Handshake exchanges `NodeIdentity` + HMAC-SHA256 challenge-response. Post-handshake messages are Borg SMSG-encrypted. Includes deduplication (5-min TTL), rate limiting (token bucket: 100 burst/50 per sec), and MaxConns enforcement.
|
||||
3. **Dispatcher** (`dispatcher.go`) — Routes verified UEPS packets to intent handlers. Threat circuit breaker drops packets with `ThreatScore > 50,000` before routing.
|
||||
4. **Controller** (`controller.go`) — Issues requests to remote peers using a pending-map pattern (`map[string]chan *Message`). Auto-connects to peers on demand.
|
||||
|
|
@ -75,7 +75,7 @@ type ProfileManager interface {
|
|||
|
||||
- UK English (colour, organisation, centre, behaviour, recognise)
|
||||
- All parameters and return types explicitly annotated
|
||||
- Tests use `testify` assert/require; table-driven subtests with `t.Run()`
|
||||
- Tests use `testify` assert/require; prefer table-driven subtests with `t.Run()` when multiple related cases share one shape
|
||||
- Test name suffixes: `_Good` (happy path), `_Bad` (expected errors), `_Ugly` (panic/edge cases)
|
||||
- Licence: EUPL-1.2 — new files need `// SPDX-License-Identifier: EUPL-1.2`
|
||||
- Security-first: do not weaken HMAC, challenge-response, Zip Slip defence, or rate limiting
|
||||
|
|
|
|||
11
CODEX.md
Normal file
11
CODEX.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||
|
||||
# CODEX.md
|
||||
|
||||
Codex-compatible entrypoint for this repository.
|
||||
|
||||
- Treat `CLAUDE.md` as the authoritative local conventions file for commands, architecture notes, coding standards, and commit format.
|
||||
- Current module path: `dappco.re/go/core/p2p`.
|
||||
- Verification baseline: `go build ./...`, `go vet ./...`, and `go test ./...`.
|
||||
- Use conventional commits with `Co-Authored-By: Virgil <virgil@lethean.io>`.
|
||||
- If `.core/reference/docs/RFC.md` is absent in the checkout, report that gap explicitly and use the local docs under `docs/` plus the code as the available reference set.
|
||||
50
README.md
50
README.md
|
|
@ -1,30 +1,52 @@
|
|||
[](https://pkg.go.dev/forge.lthn.ai/core/go-p2p)
|
||||
[](LICENSE.md)
|
||||
[](https://pkg.go.dev/dappco.re/go/core/p2p)
|
||||
[](CONTRIBUTING.md#license)
|
||||
[](go.mod)
|
||||
|
||||
# go-p2p
|
||||
|
||||
P2P mesh networking layer for the Lethean network. Provides Ed25519 node identity, an encrypted WebSocket transport with HMAC-SHA256 challenge-response handshake, KD-tree peer selection across four dimensions (latency, hops, geography, reliability score), UEPS wire protocol (RFC-021) TLV packet builder and reader, UEPS intent routing with a threat circuit breaker, and TIM deployment bundle encryption with Zip Slip and decompression-bomb defences.
|
||||
P2P mesh networking layer for the Lethean network. Provides X25519 node identity, an encrypted WebSocket transport with HMAC-SHA256 challenge-response handshake, KD-tree peer selection across four dimensions (latency, hops, geography, reliability score), UEPS wire protocol (RFC-021) TLV packet builder and reader, UEPS intent routing with a threat circuit breaker, and TIM deployment bundle encryption with Zip Slip and decompression-bomb defences.
|
||||
|
||||
**Module**: `forge.lthn.ai/core/go-p2p`
|
||||
**Module**: `dappco.re/go/core/p2p`
|
||||
**Licence**: EUPL-1.2
|
||||
**Language**: Go 1.25
|
||||
**Language**: Go 1.26
|
||||
|
||||
## Quick Start
|
||||
|
||||
```go
|
||||
import (
|
||||
"forge.lthn.ai/core/go-p2p/node"
|
||||
"forge.lthn.ai/core/go-p2p/ueps"
|
||||
"log"
|
||||
|
||||
"dappco.re/go/core/p2p/node"
|
||||
"dappco.re/go/core/p2p/ueps"
|
||||
)
|
||||
|
||||
// Start a P2P node
|
||||
identity, _ := node.LoadOrCreateIdentity()
|
||||
transport := node.NewTransport(identity, node.TransportConfig{ListenAddr: ":9091"})
|
||||
transport.Start(ctx)
|
||||
nm, err := node.NewNodeManager()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if !nm.HasIdentity() {
|
||||
if err := nm.GenerateIdentity("worker-1", node.RoleWorker); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Build a UEPS packet
|
||||
pkt, _ := ueps.NewBuilder(ueps.IntentCompute, payload).MarshalAndSign(sharedSecret)
|
||||
registry, err := node.NewPeerRegistry()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
transport := node.NewTransport(nm, registry, node.DefaultTransportConfig())
|
||||
if err := transport.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
payload := []byte(`{"job":"hashrate"}`)
|
||||
sharedSecret := make([]byte, 32)
|
||||
pkt, err := ueps.NewBuilder(node.IntentCompute, payload).MarshalAndSign(sharedSecret)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
_ = pkt
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
|
@ -44,4 +66,4 @@ go build ./...
|
|||
|
||||
## Licence
|
||||
|
||||
European Union Public Licence 1.2 — see [LICENCE](LICENCE) for details.
|
||||
European Union Public Licence 1.2 — see [CONTRIBUTING](CONTRIBUTING.md#license) for details.
|
||||
|
|
|
|||
148
SESSION-BRIEF.md
148
SESSION-BRIEF.md
|
|
@ -1,129 +1,57 @@
|
|||
# Session Brief: core/go-p2p
|
||||
|
||||
**Repo**: `forge.lthn.ai/core/go-p2p` (clone at `/tmp/core-go-p2p`)
|
||||
**Module**: `forge.lthn.ai/core/go-p2p`
|
||||
**Status**: 16 Go files, ~2,500 LOC, node tests PASS (42% coverage), ueps has NO TESTS
|
||||
**Wiki**: https://forge.lthn.ai/core/go-p2p/wiki (6 pages)
|
||||
**Repo**: `forge.lthn.ai/core/go-p2p`
|
||||
**Module**: `dappco.re/go/core/p2p`
|
||||
**Status**: `go build ./...`, `go vet ./...`, and `go test ./...` pass on 2026-03-27.
|
||||
**Primary references**: `CLAUDE.md`, `docs/architecture.md`, `docs/development.md`
|
||||
|
||||
## What This Is
|
||||
|
||||
P2P networking layer for the Lethean network. Three packages:
|
||||
P2P networking layer for the Lethean network. The repository currently consists of four Go packages:
|
||||
|
||||
### node/ — P2P Mesh (14 files)
|
||||
- **Identity**: Ed25519 keypair generation, PEM serialisation, challenge-response auth
|
||||
- **Transport**: Encrypted WebSocket connections via gorilla/websocket + Borg (encrypted blob storage)
|
||||
- **Peers**: Registry with scoring, persistence, auth modes (open/allowlist), name validation
|
||||
- **Messages**: Typed protocol messages (handshake, ping, stats, miner control, deploy, logs)
|
||||
- **Protocol**: Response handler with validation and typed parsing
|
||||
- **Worker**: Command handler (ping, stats, miner start/stop, deploy profiles, get logs)
|
||||
- **Dispatcher**: UEPS packet routing skeleton with threat circuit breaker
|
||||
- **Controller**: Remote node operations (connect, command, disconnect)
|
||||
- **Bundle**: Service factory for Core framework DI registration
|
||||
|
||||
### ueps/ — Wire Protocol (2 files, NO TESTS)
|
||||
- **PacketBuilder**: Constructs signed UEPS frames with TLV encoding
|
||||
- **ReadAndVerify**: Parses and verifies HMAC-SHA256 integrity
|
||||
- TLV tags: 0x01-0x05 (header fields), 0x06 (HMAC), 0xFF (payload marker)
|
||||
- Header: Version, CurrentLayer, TargetLayer, IntentID, ThreatScore
|
||||
|
||||
### logging/ — Structured Logger (1 file)
|
||||
- Simple levelled logger (INFO/WARN/ERROR/DEBUG) with key-value pairs
|
||||
- `node/` — P2P mesh: identity, transport, peer registry, messages, protocol helpers, worker/controller logic, dispatcher, and deployment bundles
|
||||
- `node/levin/` — standalone CryptoNote Levin binary protocol support
|
||||
- `ueps/` — UEPS TLV wire protocol with HMAC-SHA256 integrity verification
|
||||
- `logging/` — structured levelled logger with component scoping
|
||||
|
||||
## Current State
|
||||
|
||||
| Area | Status |
|
||||
|------|--------|
|
||||
| node/ tests | PASS — 42% statement coverage |
|
||||
| ueps/ tests | NONE — zero test files |
|
||||
| logging/ tests | NONE |
|
||||
| go vet | Clean |
|
||||
| TODOs/FIXMEs | None found |
|
||||
| Identity (Ed25519) | Well tested — keypair, challenge-response, deterministic sigs |
|
||||
| PeerRegistry | Well tested — add/remove, scoring, persistence, auth modes, name validation |
|
||||
| Messages | Well tested — all 15 message types, serialisation, error codes |
|
||||
| Worker | Well tested — ping, stats, miner, deploy, logs handlers |
|
||||
| Transport | NOT tested — WebSocket + Borg encryption |
|
||||
| Controller | NOT tested — remote node operations |
|
||||
| Dispatcher | NOT tested — UEPS routing skeleton |
|
||||
| Build | PASS |
|
||||
| Vet | PASS |
|
||||
| Tests | PASS |
|
||||
| `logging/` | Has direct unit coverage |
|
||||
| `ueps/` | Has round-trip, malformed packet, and coverage-path tests |
|
||||
| `node/transport` | Has real WebSocket handshake and integration tests |
|
||||
| `node/controller` | Has request/response, auto-connect, ping, and miner-control tests |
|
||||
| `node/dispatcher` | Has routing, threshold, and concurrency tests |
|
||||
| `node/levin` | Has protocol encode/decode coverage |
|
||||
|
||||
## Key Behaviours
|
||||
|
||||
- **Identity** — X25519 keypair generation via Borg STMF, persisted through XDG paths
|
||||
- **Transport** — WebSocket mesh with challenge-response authentication, SMSG encryption, deduplication, rate limiting, and keepalive handling
|
||||
- **Peer registry** — KD-tree selection across latency, hops, geography, and reliability score
|
||||
- **Controller/worker** — request/response messaging for stats, miner control, logs, and deployment
|
||||
- **Dispatcher** — UEPS intent routing with a threat circuit breaker at `ThreatScore > 50000`
|
||||
- **Bundles** — TIM-based profile and miner bundle handling with defensive tar extraction
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `github.com/Snider/Borg` v0.2.0 (encrypted blob storage)
|
||||
- `github.com/Snider/Enchantrix` v0.0.2 (secure environment)
|
||||
- `github.com/Snider/Poindexter` (secure pointer)
|
||||
- `github.com/gorilla/websocket` v1.5.3
|
||||
- `github.com/google/uuid` v1.6.0
|
||||
- `github.com/ProtonMail/go-crypto` v1.3.0
|
||||
- `dappco.re/go/core` v0.8.0-alpha.1
|
||||
- `forge.lthn.ai/Snider/Borg` v0.3.1
|
||||
- `forge.lthn.ai/Snider/Poindexter` v0.0.3
|
||||
- `github.com/adrg/xdg` v0.5.3
|
||||
- `github.com/google/uuid` v1.6.0
|
||||
- `github.com/gorilla/websocket` v1.5.3
|
||||
- `github.com/stretchr/testify` v1.11.1
|
||||
- `golang.org/x/crypto` v0.45.0
|
||||
|
||||
## Priority Work
|
||||
|
||||
### High (coverage gaps)
|
||||
1. **UEPS tests** — Zero tests for the wire protocol. This is the consent-gated TLV protocol from RFC-021. Need: builder round-trip, HMAC verification, malformed packet rejection, boundary conditions (max ThreatScore, empty payload, oversized payload).
|
||||
2. **Transport tests** — WebSocket connection, Borg encryption handshake, reconnection logic.
|
||||
3. **Controller tests** — Connect/command/disconnect flow.
|
||||
4. **Dispatcher tests** — UEPS routing, threat circuit breaker (ThreatScore > 50000 drops).
|
||||
|
||||
### Medium (hardening)
|
||||
5. **Increase node/ coverage** from 42% to 70%+ — focus on transport.go, controller.go, dispatcher.go
|
||||
6. **Benchmarks** — Peer scoring, UEPS marshal/unmarshal, identity key generation
|
||||
7. **Integration test** — Full node-to-node handshake over localhost WebSocket
|
||||
|
||||
### Low (completeness)
|
||||
8. **Logging tests** — Simple but should have coverage
|
||||
9. **Peer discovery** — Currently manual. Add mDNS or DHT discovery
|
||||
10. **Connection pooling** — Transport creates fresh connections; add pool for controller
|
||||
|
||||
## File Map
|
||||
|
||||
```
|
||||
/tmp/core-go-p2p/
|
||||
├── node/
|
||||
│ ├── bundle.go + bundle_test.go — Core DI factory
|
||||
│ ├── identity.go + identity_test.go — Ed25519 keypair, PEM, challenge-response
|
||||
│ ├── message.go + message_test.go — Protocol message types
|
||||
│ ├── peer.go + peer_test.go — Registry, scoring, auth
|
||||
│ ├── protocol.go + protocol_test.go — Response validation, typed parsing
|
||||
│ ├── worker.go + worker_test.go — Command handlers
|
||||
│ ├── transport.go (NO TEST) — WebSocket + Borg encryption
|
||||
│ ├── controller.go (NO TEST) — Remote node operations
|
||||
│ ├── dispatcher.go (NO TEST) — UEPS routing skeleton
|
||||
│ └── logging.go — Package-level logger setup
|
||||
├── ueps/
|
||||
│ ├── ueps.go (NO TEST) — PacketBuilder, ReadAndVerify, TLV
|
||||
│ └── types.go (NO TEST) — UEPSHeader, ParsedPacket, intent IDs
|
||||
├── logging/
|
||||
│ └── logger.go (NO TEST) — Levelled structured logger
|
||||
├── go.mod
|
||||
└── go.sum
|
||||
```
|
||||
|
||||
## Key Interfaces
|
||||
|
||||
```go
|
||||
// node/message.go — 15 message types
|
||||
const (
|
||||
MsgHandshake MsgHandshakeAck MsgPing MsgPong
|
||||
MsgDisconnect MsgGetStats MsgStats MsgStartMiner
|
||||
MsgStopMiner MsgMinerAck MsgDeploy MsgDeployAck
|
||||
MsgGetLogs MsgLogs MsgError
|
||||
)
|
||||
|
||||
// ueps/types.go — UEPS header
|
||||
type UEPSHeader struct {
|
||||
Version uint8 // 0x09
|
||||
CurrentLayer uint8
|
||||
TargetLayer uint8
|
||||
IntentID uint8 // 0x01=Handshake, 0x20=Compute, 0x30=Rehab, 0xFF=Extended
|
||||
ThreatScore uint16
|
||||
}
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
- UK English
|
||||
- Tests: testify assert/require
|
||||
- Licence: EUPL-1.2
|
||||
- Lethean codenames: Borg (Secure/Blob), Poindexter (Secure/Pointer), Enchantrix (Secure/Environment)
|
||||
- UK English in comments, logs, and docs
|
||||
- `core.E()` for library error wrapping and sentinel definitions
|
||||
- `core.Fs` adapters for library file I/O in `node/`
|
||||
- `testify` in tests; prefer `t.Run()` tables for related cases
|
||||
- EUPL-1.2 SPDX identifiers on new files
|
||||
- Conventional commits with `Co-Authored-By: Virgil <virgil@lethean.io>`
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Architecture — go-p2p
|
||||
|
||||
`go-p2p` is the P2P networking layer for the Lethean network. Module path: `forge.lthn.ai/core/go-p2p`.
|
||||
`go-p2p` is the P2P networking layer for the Lethean network. Module path: `dappco.re/go/core/p2p`.
|
||||
|
||||
## Package Structure
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ go-p2p/
|
|||
|
||||
### identity.go — Node Identity
|
||||
|
||||
Each node holds an Ed25519 keypair generated via Borg STMF (X25519 curve). The private key is stored at `~/.local/share/lethean-desktop/node/private.key` (mode 0600) and the public identity JSON at `~/.config/lethean-desktop/node.json`.
|
||||
Each node holds an X25519 keypair generated via Borg STMF. The private key is stored at `~/.local/share/lethean-desktop/node/private.key` (mode 0600) and the public identity JSON at `~/.config/lethean-desktop/node.json`.
|
||||
|
||||
`NodeIdentity` carries:
|
||||
- `ID` — 32-character hex string derived from SHA-256 of the public key (first 16 bytes)
|
||||
|
|
@ -83,7 +83,7 @@ The `Transport` manages a WebSocket server (gorilla/websocket) and outbound conn
|
|||
|
||||
`SelectOptimalPeer()` queries the tree for the point nearest to the origin (ideal: zero latency, zero hops, zero distance, maximum score). `SelectNearestPeers(n)` returns the n best.
|
||||
|
||||
**Persistence**: Writes are debounced with a 5-second coalesce window (`scheduleSave`). The actual write uses an atomic rename pattern (write to `.tmp`, then `os.Rename`) to prevent partial file corruption. `Close()` flushes any pending dirty state synchronously.
|
||||
**Persistence**: Writes are debounced with a 5-second coalesce window (`scheduleSave`). The actual write uses an atomic rename pattern (write to `.tmp`, then rename) to prevent partial file corruption. `Close()` flushes any pending dirty state synchronously.
|
||||
|
||||
**Auth modes**:
|
||||
- `PeerAuthOpen` — any connecting peer is accepted (default).
|
||||
|
|
@ -209,10 +209,10 @@ The Unified Encrypted Packet Structure defines a TLV-encoded binary frame authen
|
|||
[0x04][len][IntentID] Header: Semantic routing token
|
||||
[0x05][0x02][ThreatScore] Header: uint16, big-endian
|
||||
[0x06][0x20][HMAC-SHA256] Signature: 32 bytes, covers header TLVs + payload data
|
||||
[0xFF][...payload...] Data: no length prefix (relies on external framing)
|
||||
[0xFF][len][...payload...] Data: length-prefixed payload
|
||||
```
|
||||
|
||||
**HMAC coverage**: The signature is computed over the serialised header TLVs (tags 0x01–0x05) concatenated with the raw payload bytes. The HMAC TLV itself (tag 0x06) and the payload tag byte (0xFF) are excluded from the signed data.
|
||||
**HMAC coverage**: The signature is computed over the serialised header TLVs (tags 0x01–0x05) concatenated with the raw payload bytes. The HMAC TLV itself (tag 0x06) and the payload TLV header (tag `0xFF` plus the 2-byte length) are excluded from the signed data.
|
||||
|
||||
### PacketBuilder
|
||||
|
||||
|
|
@ -220,9 +220,7 @@ The Unified Encrypted Packet Structure defines a TLV-encoded binary frame authen
|
|||
|
||||
### ReadAndVerify
|
||||
|
||||
`ReadAndVerify(r *bufio.Reader, sharedSecret)` reads a stream, decodes the TLV fields in order, reconstructs the signed data buffer, and verifies the HMAC with `hmac.Equal`. Unknown TLV tags are accumulated into the signed data buffer (forward-compatible extension mechanism) but their semantics are ignored.
|
||||
|
||||
**Known limitation**: Tag 0xFF carries no length prefix. The reader calls `io.ReadAll` on the remaining stream, which requires external TCP framing (e.g. a 4-byte length prefix on the enclosing connection) to delimit the packet boundary. The packet is not self-delimiting.
|
||||
`ReadAndVerify(r *bufio.Reader, sharedSecret)` reads a stream, decodes the TLV fields in order, reconstructs the signed data buffer, and verifies the HMAC with `hmac.Equal`. Unknown TLV tags are accumulated into the signed data buffer (forward-compatible extension mechanism) but their semantics are ignored. The payload TLV is length-prefixed like every other field, so UEPS frames are self-delimiting.
|
||||
|
||||
## logging/ — Structured Logger
|
||||
|
||||
|
|
@ -255,8 +253,8 @@ The codebase is verified race-free under `go test -race`.
|
|||
```
|
||||
node/ ──► ueps/
|
||||
node/ ──► logging/
|
||||
node/ ──► github.com/Snider/Borg (STMF crypto, SMSG encryption, TIM)
|
||||
node/ ──► github.com/Snider/Poindexter (KD-tree peer selection)
|
||||
node/ ──► forge.lthn.ai/Snider/Borg (STMF crypto, SMSG encryption, TIM)
|
||||
node/ ──► forge.lthn.ai/Snider/Poindexter (KD-tree peer selection)
|
||||
node/ ──► github.com/gorilla/websocket
|
||||
node/ ──► github.com/google/uuid
|
||||
ueps/ ──► (stdlib only)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Prerequisites
|
||||
|
||||
- Go 1.25 or later (the module declares `go 1.25.5`)
|
||||
- Go 1.26 or later (the module declares `go 1.26.0`)
|
||||
- Network access to `forge.lthn.ai` for private dependencies (Borg, Poindexter, Enchantrix)
|
||||
- SSH key configured for `git@forge.lthn.ai:2223` (HTTPS auth is not supported on Forge)
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ go vet ./...
|
|||
|
||||
### Table-Driven Subtests
|
||||
|
||||
All tests use table-driven subtests with `t.Run()`. A test that does not follow this pattern should be refactored before merging.
|
||||
Prefer table-driven subtests with `t.Run()` when multiple related cases share the same structure. Use clear case names and keep setup and verification consistent across the table.
|
||||
|
||||
```go
|
||||
func TestFoo(t *testing.T) {
|
||||
|
|
@ -177,12 +177,12 @@ All parameters and return types must carry explicit type annotations. Avoid `int
|
|||
### Error Handling
|
||||
|
||||
- Never discard errors silently.
|
||||
- Wrap errors with context using `fmt.Errorf("context: %w", err)`.
|
||||
- Wrap library errors with context using `core.E("operation", "context", err)`.
|
||||
- Return typed sentinel errors for conditions callers need to inspect programmatically.
|
||||
|
||||
### Licence Header
|
||||
|
||||
Every new file must carry the EUPL-1.2 licence identifier. The module's `LICENSE` file governs the package. Do not include the full licence text in each file; a short SPDX identifier comment at the top is sufficient for new files:
|
||||
Every new file must carry the EUPL-1.2 licence identifier. The project is licensed under EUPL-1.2; do not include the full licence text in each file. A short SPDX identifier comment at the top is sufficient for new files:
|
||||
|
||||
```go
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ Peers are persisted to `~/.config/lethean-desktop/peers.json` as a JSON array.
|
|||
|
||||
### Debounced Writes
|
||||
|
||||
To avoid excessive disk I/O, saves are debounced with a 5-second coalesce interval. Multiple mutations within that window produce a single disk write. The write uses an atomic rename pattern (write to `.tmp`, then `os.Rename`) to prevent corruption on crash.
|
||||
To avoid excessive disk I/O, saves are debounced with a 5-second coalesce interval. Multiple mutations within that window produce a single disk write. The write uses an atomic rename pattern (write to `.tmp`, then rename) to prevent corruption on crash.
|
||||
|
||||
```go
|
||||
// Flush pending changes on shutdown
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ Implemented the complete test suite for the UEPS binary framing layer. Tests cov
|
|||
|
||||
- PacketBuilder round-trip: basic, binary payload, elevated threat score, large payload
|
||||
- HMAC verification: payload tampering detected, header tampering detected, wrong shared secret detected
|
||||
- Boundary conditions: nil payload, empty slice payload, `uint16` max ThreatScore (65,535), TLV value exceeding 255 bytes (`writeTLV` error path)
|
||||
- Boundary conditions: nil payload, empty slice payload, `uint16` max ThreatScore (65,535), TLV value exceeding 65,535 bytes (`writeTLV` error path)
|
||||
- Stream robustness: truncated packets detected at multiple cut points (EOF mid-tag, mid-length, mid-value), missing HMAC tag, unknown TLV tags skipped and included in signed data
|
||||
|
||||
The 11.5% gap from 100% coverage is the reader's `io.ReadAll` error path, which requires a contrived broken `io.Reader` to exercise.
|
||||
The remaining gap from 100% coverage at the time was the payload read-error path, which required a contrived broken reader to exercise.
|
||||
|
||||
### Phase 2 — Transport Tests
|
||||
|
||||
|
|
@ -86,11 +86,9 @@ Three integration tests (`TestIntegration_*`) exercise the full stack end-to-end
|
|||
|
||||
## Known Limitations
|
||||
|
||||
### UEPS 0xFF Payload Not Self-Delimiting
|
||||
### UEPS Payload Framing (Resolved)
|
||||
|
||||
The `TagPayload` (0xFF) field carries no length prefix. `ReadAndVerify` calls `io.ReadAll` on the remaining stream, which means the packet format relies on external TCP framing to delimit the packet boundary. The enclosing transport must provide a length-prefixed frame before calling `ReadAndVerify`. This is noted in comments in both `packet.go` and `reader.go` but no solution is implemented.
|
||||
|
||||
Consequence: UEPS packets cannot be chained in a raw stream without an outer framing protocol. The current WebSocket transport encapsulates each UEPS frame in a single WebSocket message, which provides the necessary boundary implicitly.
|
||||
The `TagPayload` (0xFF) field now uses the same 2-byte length prefix as the other TLVs. `ReadAndVerify` reads that explicit length, so UEPS packets are self-delimiting and can be chained in a stream without relying on an outer framing layer.
|
||||
|
||||
### No Resource Cleanup on Some Error Paths
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ description: P2P mesh networking layer for the Lethean network.
|
|||
|
||||
P2P networking layer for the Lethean network. Encrypted WebSocket mesh with UEPS wire protocol.
|
||||
|
||||
**Module:** `forge.lthn.ai/core/go-p2p`
|
||||
**Module:** `dappco.re/go/core/p2p`
|
||||
**Go:** 1.26
|
||||
**Licence:** EUPL-1.2
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ description: UEPS intent-based packet routing with threat circuit breaker.
|
|||
|
||||
# Intent Routing
|
||||
|
||||
The `Dispatcher` routes verified UEPS packets to registered intent handlers. Before routing, it enforces a threat circuit breaker that silently drops packets with elevated threat scores.
|
||||
The `Dispatcher` routes verified UEPS packets to registered intent handlers. Before routing, it enforces a threat circuit breaker that blocks packets with elevated threat scores and returns sentinel errors to the caller.
|
||||
|
||||
**File:** `node/dispatcher.go`
|
||||
|
||||
|
|
@ -74,8 +74,8 @@ Dropped packets are logged at WARN level with the threat score, threshold, inten
|
|||
|
||||
### Design Rationale
|
||||
|
||||
- **High-threat packets are dropped silently** (from the sender's perspective) rather than returning an error, consistent with the "don't even parse the payload" philosophy.
|
||||
- **Unknown intents are dropped**, not forwarded, to avoid back-pressure on the transport layer. They are logged at WARN level for debugging.
|
||||
- **High-threat packets are not dispatched**. The dispatcher logs them and returns `ErrThreatScoreExceeded` to the caller; the sender still receives no protocol-level response.
|
||||
- **Unknown intents are not forwarded**. The dispatcher logs them and returns `ErrUnknownIntent`, avoiding back-pressure on the transport layer.
|
||||
- **Handler errors propagate** to the caller, allowing upstream code to record failures.
|
||||
|
||||
## Intent Constants
|
||||
|
|
@ -100,12 +100,13 @@ const (
|
|||
|
||||
```go
|
||||
var (
|
||||
ErrThreatScoreExceeded = fmt.Errorf(
|
||||
"packet rejected: threat score exceeds safety threshold (%d)",
|
||||
ThreatScoreThreshold,
|
||||
ErrThreatScoreExceeded = core.E(
|
||||
"Dispatcher.Dispatch",
|
||||
core.Sprintf("packet rejected: threat score exceeds safety threshold (%d)", ThreatScoreThreshold),
|
||||
nil,
|
||||
)
|
||||
ErrUnknownIntent = errors.New("packet dropped: unknown intent")
|
||||
ErrNilPacket = errors.New("dispatch: nil packet")
|
||||
ErrUnknownIntent = core.E("Dispatcher.Dispatch", "packet dropped: unknown intent", nil)
|
||||
ErrNilPacket = core.E("Dispatcher.Dispatch", "nil packet", nil)
|
||||
)
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ description: TLV-encoded wire protocol with HMAC-SHA256 integrity verification (
|
|||
|
||||
The `ueps` package implements the Universal Encrypted Payload System -- a consent-gated TLV (Type-Length-Value) wire protocol with HMAC-SHA256 integrity verification. This is the low-level binary protocol that sits beneath the JSON-over-WebSocket mesh layer.
|
||||
|
||||
**Package:** `forge.lthn.ai/core/go-p2p/ueps`
|
||||
**Package:** `dappco.re/go/core/p2p/ueps`
|
||||
|
||||
## TLV Format
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue