Skip to content

Commit 3ac09cb

Browse files
author
Alex Godoroja
committed
fix: final review
1 parent 5993a68 commit 3ac09cb

13 files changed

Lines changed: 294 additions & 319 deletions

File tree

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,9 +470,25 @@ with Driver() as d:
470470
"other-agent"
471471
)
472472

473-
# Send a message
474-
with d.dial("other-agent:1000") as conn:
475-
conn.write(b"hello")
473+
# Send a file
474+
d.send_file("other-agent",
475+
"./data.json")
476+
477+
# Send typed message
478+
d.send_message("other-agent",
479+
b'{"status":"ready"}',
480+
msg_type="json")
481+
482+
# Subscribe to events
483+
for topic, data in d.subscribe_event(
484+
"other-agent", "status",
485+
timeout=30
486+
):
487+
print(f"{topic}: {data}")
488+
489+
# Publish an event
490+
d.publish_event("other-agent",
491+
"status", b"online")
476492

477493
# Handshake & trust
478494
d.handshake(peer_id, "hello")

cmd/pilotctl/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ func cmdDaemonStart(args []string) {
10281028
encrypt := !flagBool(flags, "no-encrypt")
10291029
identityPath := flagString(flags, "identity", "")
10301030
if identityPath == "" {
1031-
identityPath = configDir() + "/identity.key"
1031+
identityPath = configDir() + "/identity.json"
10321032
}
10331033
owner := flagString(flags, "owner", "")
10341034
configFile := flagString(flags, "config", "")

configs/daemon.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"listen": ":4000",
55
"socket": "/tmp/pilot.sock",
66
"encrypt": true,
7-
"identity": "/var/lib/pilot/identity.key",
7+
"identity": "/var/lib/pilot/identity.json",
88
"owner": "",
99
"log-level": "info",
1010
"log-format": "text"

examples/go/config/daemon.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"socket": "/tmp/pilot.sock",
66
"encrypt": true,
77
"registry-tls": false,
8-
"identity": "/var/lib/pilot/identity.key",
8+
"identity": "/var/lib/pilot/identity.json",
99
"owner": "",
1010
"keepalive": "30s",
1111
"idle-timeout": "120s",

pkg/registry/dashboard.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,17 @@ func (s *Server) ServeDashboard(addr string) error {
121121

122122
// Snapshot trigger endpoint (POST only, localhost only)
123123
mux.HandleFunc("/api/snapshot", func(w http.ResponseWriter, r *http.Request) {
124-
// Check localhost
125-
clientIP := r.Header.Get("X-Real-IP")
126-
if clientIP == "" {
127-
clientIP, _, _ = net.SplitHostPort(r.RemoteAddr)
124+
// Check localhost - only trust X-Real-IP if request is from a trusted proxy
125+
remoteIP, _, _ := net.SplitHostPort(r.RemoteAddr)
126+
clientIP := remoteIP
127+
128+
// Only trust X-Real-IP header if the request is already from localhost (trusted proxy)
129+
if remoteIP == "127.0.0.1" || remoteIP == "::1" || remoteIP == "localhost" {
130+
if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
131+
clientIP = realIP
132+
}
128133
}
134+
129135
if clientIP != "127.0.0.1" && clientIP != "::1" && clientIP != "localhost" {
130136
http.Error(w, "Forbidden", http.StatusForbidden)
131137
return
@@ -146,14 +152,20 @@ func (s *Server) ServeDashboard(addr string) error {
146152
})
147153

148154
// localhostOnly rejects requests not originating from loopback.
149-
// Checks X-Real-IP / X-Forwarded-For (set by nginx) to detect proxied public requests.
155+
// Only trusts X-Real-IP header when the request is from a trusted proxy (localhost).
150156
localhostOnly := func(next http.HandlerFunc) http.HandlerFunc {
151157
return func(w http.ResponseWriter, r *http.Request) {
152-
// If behind a reverse proxy, the real client IP is in X-Real-IP
153-
clientIP := r.Header.Get("X-Real-IP")
154-
if clientIP == "" {
155-
clientIP, _, _ = net.SplitHostPort(r.RemoteAddr)
158+
// Get the actual remote address
159+
remoteIP, _, _ := net.SplitHostPort(r.RemoteAddr)
160+
clientIP := remoteIP
161+
162+
// Only trust X-Real-IP header if the request is already from localhost (trusted proxy)
163+
if remoteIP == "127.0.0.1" || remoteIP == "::1" || remoteIP == "localhost" {
164+
if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
165+
clientIP = realIP
166+
}
156167
}
168+
157169
if clientIP != "127.0.0.1" && clientIP != "::1" && clientIP != "localhost" {
158170
http.Error(w, "Forbidden", http.StatusForbidden)
159171
return

pkg/registry/server.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,8 +2086,7 @@ func (s *Server) TriggerSnapshot() error {
20862086
if s.storePath == "" {
20872087
return nil // no persistence configured
20882088
}
2089-
s.flushSave()
2090-
return nil
2089+
return s.flushSave()
20912090
}
20922091

20932092
// snapshot is the JSON-serializable registry state.
@@ -2157,7 +2156,9 @@ func (s *Server) saveLoop() {
21572156
dirty = true
21582157
case <-ticker.C:
21592158
if dirty {
2160-
s.flushSave()
2159+
if err := s.flushSave(); err != nil {
2160+
slog.Error("periodic save failed", "err", err)
2161+
}
21612162
dirty = false
21622163
}
21632164
case <-s.done:
@@ -2168,15 +2169,17 @@ func (s *Server) saveLoop() {
21682169
default:
21692170
}
21702171
if dirty {
2171-
s.flushSave()
2172+
if err := s.flushSave(); err != nil {
2173+
slog.Error("final save failed", "err", err)
2174+
}
21722175
}
21732176
return
21742177
}
21752178
}
21762179
}
21772180

21782181
// flushSave serializes the full registry state and writes it to disk.
2179-
func (s *Server) flushSave() {
2182+
func (s *Server) flushSave() error {
21802183
s.mu.RLock()
21812184
snap := snapshot{
21822185
NextNode: s.nextNode,
@@ -2272,20 +2275,22 @@ func (s *Server) flushSave() {
22722275
data, err := json.Marshal(snap)
22732276
if err != nil {
22742277
slog.Error("registry save marshal error", "err", err)
2275-
return
2278+
return fmt.Errorf("marshal snapshot: %w", err)
22762279
}
22772280

22782281
// Persist to disk atomically
22792282
if s.storePath != "" {
22802283
if err := fsutil.AtomicWrite(s.storePath, data); err != nil {
22812284
slog.Error("registry save error", "err", err)
2285+
return fmt.Errorf("write snapshot: %w", err)
22822286
}
22832287
}
22842288

22852289
// Push to replication subscribers
22862290
s.replMgr.push(data)
22872291

22882292
slog.Debug("registry state saved", "nodes", nodeCount, "networks", netCount)
2293+
return nil
22892294
}
22902295

22912296
// load reads the registry state from disk.

sdk/cgo/bindings.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
// Keeps Go heap objects alive while C/Python holds a uint64 token.
2121

2222
var handles struct {
23-
sync.Mutex
23+
sync.RWMutex
2424
m map[uint64]interface{}
2525
next uint64
2626
}
@@ -40,9 +40,9 @@ func storeHandle(v interface{}) uint64 {
4040
}
4141

4242
func loadHandle(id uint64) (interface{}, bool) {
43-
handles.Lock()
43+
handles.RLock()
4444
v, ok := handles.m[id]
45-
handles.Unlock()
45+
handles.RUnlock()
4646
return v, ok
4747
}
4848

sdk/python/README.md

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,48 @@ dg = d.recv_from()
192192
# Returns: {"src_addr": "...", "src_port": 8080, "dst_port": 9090, "data": ...}
193193
```
194194

195+
### Data Exchange Service (Port 1001)
196+
197+
```python
198+
# Send a message (text, JSON, or binary)
199+
result = d.send_message("other-agent", b"hello", msg_type="text")
200+
# Returns: {"sent": 5, "type": "text", "target": "0:0001.0000.0002", "ack": "..."}
201+
202+
# Send a file
203+
result = d.send_file("other-agent", "/path/to/file.txt")
204+
# Returns: {"sent": 1234, "filename": "file.txt", "target": "0:0001.0000.0002", "ack": "..."}
205+
```
206+
207+
### Event Stream Service (Port 1002)
208+
209+
```python
210+
# Publish an event
211+
result = d.publish_event("other-agent", "sensor/temperature", b'{"temp": 25.5}')
212+
# Returns: {"status": "published", "topic": "sensor/temperature", "bytes": 15}
213+
214+
# Subscribe to events (generator)
215+
for topic, data in d.subscribe_event("other-agent", "sensor/*", timeout=30):
216+
print(f"{topic}: {data}")
217+
218+
# Subscribe with callback
219+
def handle_event(topic, data):
220+
print(f"Event: {topic} -> {data}")
221+
222+
d.subscribe_event("other-agent", "*", callback=handle_event, timeout=30)
223+
```
224+
225+
### Task Submit Service (Port 1003)
226+
227+
```python
228+
# Submit a task for execution
229+
task = {
230+
"task_description": "process data",
231+
"parameters": {"input": "data.csv"}
232+
}
233+
result = d.submit_task("other-agent", task)
234+
# Returns: {"status": 200, "task_id": "...", "message": "Task accepted"}
235+
```
236+
195237
### Configuration
196238

197239
```python
@@ -242,20 +284,7 @@ cd sdk/python
242284
python -m pytest tests/ -v
243285
```
244286

245-
47 tests cover all wrapper methods, error handling, and library discovery.
246-
247-
## Development
248-
249-
```bash
250-
# Build shared library
251-
make sdk-lib
252-
253-
# Install SDK in development mode
254-
cd sdk/python && pip install -e .
255-
256-
# Run tests
257-
pytest tests/ -v
258-
```
287+
61 tests cover all wrapper methods, error handling, and library discovery.
259288

260289
## Development
261290

sdk/python/scripts/generate-coverage-badge.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ if [ ! -f coverage.json ]; then
1313
fi
1414

1515
# Extract coverage percentage
16-
coverage=$(/Users/alexgodo/web4/pilotprotocol/.venv/bin/python -c "import json; data=json.load(open('coverage.json')); print(int(data['totals']['percent_covered']))")
16+
coverage=$(python3 -c "import json; data=json.load(open('coverage.json')); print(int(data['totals']['percent_covered']))")
1717

1818
echo "Coverage: ${coverage}%"
1919

tests/integration/test_cli.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ LOG_LEVEL="${PILOT_LOG_LEVEL:-info}"
7272

7373
pilot-daemon \
7474
--hostname "$TEST_HOSTNAME" \
75-
--identity /root/.pilot/identity.key \
75+
--identity /root/.pilot/identity.json \
7676
--log-level "$LOG_LEVEL" > "$DAEMON_LOG" 2>&1 &
7777
DAEMON_PID=$!
7878

0 commit comments

Comments
 (0)