fix: harden gossip, HLC restarts, watcher races, MCP args, pagination
- gossip: validate push batches (4 MiB / 1000-row caps); reject rows claiming the local node id (vector-poisoning), empty ids, negative HCLs - gossip: reconcile derived state after pulls (pulls only append to the observation log, so entry-count comparison could never trigger it) - hlc: seek clock from persisted MAX(hcl) at Open so a restart with a regressed wall clock cannot reissue values (locator/cursor safety) - db: serialize writers via BEGIN IMMEDIATE DSN, single conn per pool, and a per-KnoxDB mutex around RecordObservation's dedup - watch: atomic ticker guards (was a cross-goroutine data race), trailing-edge per-path debounce, recursive directory watches, rename re-ingest, remove cancels pending ingests - mcp: strict argument validation (no silent clamping), thread existence checks before writes, nil-safe golden-thread tool - cli: --page 0 no longer panics; query/recent pagination actually pages - tests: hlc SeekTo monotonicity, concurrent dedup race, push validation, batch caps, idempotency on observation counts
This commit is contained in:
@@ -3,6 +3,7 @@ package db
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// GossipObservation is the serializable wire form of an observation exchanged
|
||||
@@ -40,6 +41,19 @@ func (k *KnoxDB) PushObservations(rows []GossipObservation) (int, error) {
|
||||
|
||||
inserted := 0
|
||||
for _, o := range rows {
|
||||
// Reject malformed or forged rows. Nodes only ever push their own
|
||||
// observations, so a row claiming this node's id cannot be legitimate:
|
||||
// accepting it would let a peer poison our knowledge vector (a forged
|
||||
// max-HCL makes peers believe they have our whole history and stop
|
||||
// pulling). Empty node ids and negative HCLs are likewise never produced
|
||||
// by a real node.
|
||||
if o.NodeID == "" || o.HCL < 0 {
|
||||
continue
|
||||
}
|
||||
if o.NodeID == k.nodeID {
|
||||
log.Printf("[gossip] dropped pushed row claiming local node_id (spoof?)")
|
||||
continue
|
||||
}
|
||||
res, err := tx.Exec(
|
||||
`INSERT OR IGNORE INTO observations
|
||||
(fingerprint, source_id, source_path, project, content_type, title, summary,
|
||||
|
||||
Reference in New Issue
Block a user