Skip to content

Require verified peer inventory for service decisions - #43

Merged
JaredP94 merged 18 commits into
mainfrom
fix/verified-peer-inventory
Nov 3, 2026
Merged

JaredP94 merged 18 commits into
mainfrom
fix/verified-peer-inventory

Conversation

@JaredP94

@JaredP94 JaredP94 commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Design

  • Discovery announcements and public HTTP inventory are endpoint hints, never identity proofs.
  • A shared bounded reader proves the exact current peer certificate over pinned cluster mTLS and rechecks authorization after decoding.
  • Proof bindings include the local admission, local leaf and exact peer pin record.
  • Node-info publishes broker-owned service metadata alongside its public hardware preview.
  • Scanner candidates and verified peers have independent identities and lifetimes; removing a preview cannot remove a verified peer.
  • Only authenticated metadata supplies PAIR service ports, model/engine inventory and scheduler telemetry.
  • Broker relay delivery, scheduler snapshots and telemetry ingestion/replay recheck current provenance; worker retirement withdraws its sources.
  • Explicitly user-added bare engines remain a separately labelled manual routing bypass, without PAIR identity or peer telemetry.
  • Additive peerRecordId / identityVerification fields distinguish verified peers, previews and manual configurations.

Description

Adapt NVIDIA/Personal-AI-Router#179 to this fork's source-aware discovery, three inference proxies and scheduler. A peer claiming a pinned principal must prove possession of its key over cluster mTLS before its claims can establish trust or supply service decisions. Public hardware previews remain available.

The takeover audit also fixed an authorization gap for telemetryValid:false samples: unavailable readings now require the same proof as valid readings, including delivery and replay. Otherwise an unproven unavailable reading could erase authenticated GPU pressure. The scanner's engine-native replacement regression now exercises actual remote mTLS browse instead of passing through a local-self early return. Added retry-budget/lifetime and original-withdrawal-token coverage.

Version decisions, compared with v0.8.0:services/versions.json:

  • nvpair-node-info: 1.3.0 → 1.4.0; additive authenticated service metadata/provenance and security behavior.
  • nvpair-node-scanner: 1.2.0 → 1.3.0; additive proof-bound inventory/provenance and security behavior (main was 1.2.1).
  • nvpair-manual-nodes: 1.2.1 → 1.3.0; additive authenticated/manual provenance and security behavior (main was 1.2.2).
  • Broker remains at main's already-unreleased 2.5.0 (released 2.4.1), sufficient for the additive snapshot/security changes. TUI remains at main's unreleased 1.2.1 (released 1.2.0); its change consumes and labels provenance. Other existing unreleased component bumps and product/installer versions are unchanged.

The security-review follow-up is pushed as one signed-off commit per blocking finding:

  1. 7022b7c — inventory proofs require an active, non-retired admission; retained pins cannot authorize fresh, pooled or cached inventory after withdrawal.
  2. adde205 — local and peer certificate validity windows gate current proofs and response acceptance; expiry disqualifies cached routing inventory, telemetry ingestion and scheduler replay, including responses crossing expiry on pooled connections.
  3. 6957ee6 — serialize manual trust-refresh snapshot/replay with worker callbacks and retirement; reject retired-generation status snapshots.
  4. 658fc8f — atomically remove only the exact expired scanner record and order verified publication/enrichment updates with withdrawal/cache cleanup.

333f5a4 restores the original telemetry failover assertions through the authenticated fixture: the full refreshTelemetryOnce sweep, emitted identity/proof/utilization, and remembered answering address. Each finished commit was pushed immediately. 4fd864b additionally carries the existing fork-main cancellation-ownership fix (6b58e5d) with its tests, eliminating the baseline broker vet warning rather than disabling that analyzer.

Scope

Included: shared inventory/provenance, node-info, scanner, manual nodes, broker/relay/scheduler boundaries, TUI labels, generated service-contract documentation, component documentation and security/architecture guidance. The original six coherent signed-off commits replace the unpushed WIP; adapted work credits Kaylee Lubick. The security-review follow-up adds the four focused blocking fixes, restored failover coverage, and the existing fork-main vet cleanup listed above.

Follow-ups:

  1. Desktop handling of peerRecordId and identityVerification, where previews must never be keyed by a claimed hostUuid.
  2. Persist each manual entry's kind (PAIR peer vs bare engine) in manual-nodes.json, so a known PAIR peer never downgrades across worker restarts.

Validation

Rebase and Linux CI repair (current head 7bd921a)

Rebased the branch from a0c46f5 onto origin/main 12d00de (the merged mDNS socket-reuse work), without conflicts, in the isolated worktree /tmp/pair-work/verified-peer-ci-repair. No notice regeneration was needed. Ran all five complete module suites with go test -race ./... after rebasing and before the force-with-lease push: shared, nvpair-node-scanner, nvpair-manual-nodes, nvpair-node-info, nvpair-ui-broker — all passed.

The six Linux failures in run 41600617583 were introduced by this PR, not pre-existing failures:

  • (a) TestModelsHTTPEnrichment — its public HTTP/mDNS stub supplied no pinned-mTLS identity proof; withholding model inventory is intended.
  • (a) TestModelsPeriodicRefreshConvergesWithoutMDNSChange — the same unproven fixture cannot supply periodically refreshed model inventory.
  • (a) TestWorkloadManagerRehydratesActiveWorkloadOnRestart — its pinned workload listener lacked authenticated node-info/service metadata, and its advertised host UUID differed from the pinned principal, so discovery correctly withheld it from broadcast peers.
  • (a) TestWorkloadManagerRehydratesRecentTerminalOnRestart — the same fixture problem, not a removal of terminal rehydration.
  • (b) TestWorkloadFailedOnNodeLoss — active state was accepted against a preview, then preview removal explicitly bypassed the node-loss sweep. This is a product defect.
  • (a) TestWorkloadManagerOutboundBroadcast — the same unproven service-discovery fixture as the restart tests; refusing the target is intended.

Signed-off repair commits:

  • 212e9f7 fixes preview withdrawal and scanner-retirement cleanup for already tracked workloads, rejects active events naming known unproven participants, and preserves jobs when a proven claim survives. Terminal reconciliation and relayed participants not yet discovered locally remain supported. Broker stays at its existing unreleased 2.5.0 bump (released 2.4.1); no extra version bumps.
  • 7bd921a upgrades the end-to-end fixtures to admitted, exact-cross-pinned cluster mTLS peers with authenticated node-info identities and service maps. Model unions/per-engine attribution/loaded sets, periodic additions and final deletions, active and terminal rehydration after worker restart, outbound inference broadcasts, and verified peer-loss failure all retain their positive assertions. A plaintext lookalike remains an untrusted preview, contributes no models and receives no model read.

Local follow-up validation (macOS arm64):

  • go test -race -count=1 ./... in nvpair-ui-broker — full suite passed after the product fix and again after the sensitivity check.
  • New TestPreviewWithdrawalRetiresAlreadyTrackedWorkloads, TestScannerRetirementRetiresPreviewWorkloads, and TestActiveWorkloadsCannotUseUnverifiedPreview regressions failed without the fix. Temporarily removing the fix reproduced all intended failures; restoring it returned the complete broker race suite to green. A surviving verified claim is covered.
  • GOOS=darwin go vet ./..., GOOS=linux go vet ./..., GOOS=windows go vet ./... in both services/tests and nvpair-ui-broker — passed.
  • gofmt -l on every follow-up Go file — clean; git diff --check origin/main — passed.
  • SPDX checker — 1276 checked, 0 missing.
  • No cross-process suite was run locally. No desktop source or wire surface changed in this repair.

Final CI: run 41603781815, head 7bd921a5fa451a4f437e4df4494a2990644f9128, success, all six jobs passed: desktop gates (including service contracts and licenses), SPDX, Go modules on Linux/macOS, and cross-process suites on Linux/macOS.

Downloaded both diagnostic artifacts into the new empty directory /tmp/pair-review/art43-final-41603781815-EkHXtI and inspected the JSONL, without executing artifact contents. The Linux artifact records real pass events (not skips) for all six:

  • TestModelsHTTPEnrichment — 16.51 s.
  • TestModelsPeriodicRefreshConvergesWithoutMDNSChange — 31.51 s.
  • TestWorkloadManagerRehydratesActiveWorkloadOnRestart — 11.04 s.
  • TestWorkloadManagerRehydratesRecentTerminalOnRestart — 11.04 s.
  • TestWorkloadFailedOnNodeLoss — 60.03 s.
  • TestWorkloadManagerOutboundBroadcast — 5.03 s.

Linux reports 101 passing cases including subtests, zero failures, and one separate skip: TestScannerEvictsRecordSupersededAtItsAddress never discovered its record and is untested, not counted as passing. macOS skips these six multicast-dependent tests; Linux, not those skips, supplies their runtime evidence. Live deployment, Windows runtime, desktop launch and packaged artifacts remain unverified.

Same-address ghost-node coverage repair (head 8ff7c5e)

The Linux skip in run 41603781815 was a fixture/event-contract error, not unavailable multicast: onBrowse emits public peers as independently keyed preview:<sha> records via discovery:node-updated, while the old test awaited discovery:node-discovered under the claimed host UUID.

Signed-off follow-up commits:

  • 7ee1039 adds an in-module regression for a genuinely replaced key-bearing endpoint: the original peer proves its identity over pinned mTLS, survives multicast loss, then loses its listener to an unclustered fresh identity at the exact same address/port. A transient proof failure preserves the grace period; an aged failed proof withdraws the original verified record and token despite the live public responder.
  • 9a53ed6 restores TestScannerEvictsRecordSupersededAtItsAddress with the admitted, exact-cross-pinned fixture from 7bd921a, then wipes it to a fresh public identity at the same endpoint. Separate TestScannerEvictsPreviewSupersededAtItsAddress covers the public candidate's identity-mismatch liveness probe and independently keyed preview removal.
  • 8ff7c5e removes the other post-multicast prerequisite skips.

No scanner product bug or runtime change was needed for this repair. Verified-peer lifetime already belongs to failed pinned-mTLS refresh/expiry, not public HTTP identity claims or TCP reachability. Disabling that existing expiry made the new in-module test fail with “a new identity at the same live endpoint kept stale verified inventory alive”; restoring it passed. Public mismatch probes still evict previews and cannot withdraw a verified peer. No version bumps: all changes are test-only.

Skip audit (never discovered, inconclusive, and t.Skip after requireMulticast) converted four sites to failures:

  1. Ghost test's missing-discovery branch (both verified and preview cases now fail).
  2. TestWorkloadManagerRehydratesActiveWorkloadOnRestart port guard.
  3. TestWorkloadManagerRehydratesRecentTerminalOnRestart port guard.
  4. startBrokerProcInCluster's workload-manager port guard, also reachable from multicast-dependent node-loss/broadcast tests.
    No other discovery-time “never discovered”/“inconclusive” self-skips were found. The environment decision in requireMulticast, explicit -short, and unrelated platform/environment guards remain.

Local validation in isolated worktree /tmp/pair-work/ghost-identity, based on origin/fix/verified-peer-inventory at 7bd921a:

  • go test -race -count=1 ./... in nvpair-node-scanner — passed.
  • GOOS=darwin/linux/windows go vet ./... in both services/tests and nvpair-node-scanner — passed.
  • gofmt -l for both touched modules — clean; git diff --check — passed.
  • SPDX checker — 1276 checked, 0 missing.
  • No cross-process tests were run locally.

Latest-head CI at verification: run 41608227469, branch head 8ff7c5ec79148693fa4fc46ab25b053591764dd3, all six jobs passed (SPDX, desktop checks, Go modules on Linux/macOS, cross-process on Linux/macOS).

Downloaded the Linux diagnostic artifact into the new empty directory /tmp/pair-review/ghost43-linux-41608227469-HjJzB4 and parsed its JSONL with isolated python3 -I, without executing artifact contents:

  • 103 passing cases, zero failures, ZERO skips.
  • TestScannerEvictsRecordSupersededAtItsAddress — pass, 60.02 s.
  • TestScannerEvictsPreviewSupersededAtItsAddress — pass, 66.01 s.

The previously skipped regression is now exercised on Linux, not counted from an inconclusive run. Later commits on this shared branch require their own latest-head CI evidence.

Risk

After a manual-nodes worker restart, an address the user added for a PAIR peer can be routed to as an unauthenticated plaintext bare engine if no PAIR endpoint answers there (e.g. if someone else answers on that address). The worker's peerSeen downgrade suppression lasts only for the configuration's in-process lifetime. Persisting entry kind is the explicit follow-up above; this PR does not claim to solve restart-time intent loss.

Mixed-cluster compatibility: upgraded consumers keep older peers without the new authenticated broker metadata as unverified previews and do not route to them or accept their scheduling inventory until upgraded. No plaintext or operator-CA compatibility downgrade is added. Older consumers retain their existing policies; upgrading one node does not retrofit this guarantee into older binaries.

Public hardware previews still expose inventory/utilization to the LAN. The desktop has not yet adopted the new independent preview identity fields; service trust/routing/scheduling enforcement is in Go, not a claim that the existing desktop projection is fully migrated. Live deployment and artifact certification remain outstanding.

Checklist

  • I have read the Contributing Guidelines.
  • Every commit is signed off (git commit -s), certifying the Developer Certificate of Origin.
  • New or existing tests cover the change.
  • Relevant documentation is updated.
  • I checked the diff, changed filenames, and commit messages for credentials, private data, internal URLs, internal issue identifiers, and generated artifacts.
  • I recorded the validation commands and results above.
  • I bumped any affected component in services/versions.json, and described user-visible changes above so they reach the release notes.

@JaredP94
JaredP94 force-pushed the fix/verified-peer-inventory branch from 4fd864b to 8544067 Compare November 3, 2026 07:45
JaredP94 and others added 12 commits November 3, 2026 10:18
Public identity claims must not authorize service inventory. Add bounded pinned-mTLS inventory reads, authorization bindings covering admission and certificate pins, and separate preview and manual record namespaces. Recheck the exact peer certificate after each response.

Adapt the peer inventory separation from NVIDIA#179, with explicit provenance and proof lifetimes.

Co-authored-by: Kaylee Lubick <klubick@nvidia.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Serve pinned cluster inventory beside the public hardware preview. Accept service metadata only from the owning broker and only for the local identity, so remote consumers can authenticate service ports without trusting discovery announcements.

Adapt NVIDIA#179 to the shared inventory proof boundary.

Co-authored-by: Kaylee Lubick <klubick@nvidia.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Authenticate remote hardware and service metadata before granting trust, reading model inventory, or emitting scheduler telemetry. Keep public candidates independently keyed so their updates and removal cannot displace a proven peer. Expire failed proofs using their original tokens and retain independent telemetry retry budgets.

Adapt NVIDIA#179 with admission-bound proofs and real pinned-mTLS regression fixtures.

Co-authored-by: Kaylee Lubick <klubick@nvidia.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Read PAIR identity, models, engines and telemetry only over pinned cluster mTLS. Keep explicitly configured bare engines as a separately labelled manual bypass, and prevent a recognized PAIR configuration from downgrading during its lifetime in the worker. Preserve independent manual configuration identities.

Adapt NVIDIA#179; manual-entry kind persistence across worker restarts remains follow-up work.

Co-authored-by: Kaylee Lubick <klubick@nvidia.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Recheck proof bindings for relay delivery, scheduler snapshots and all telemetry, including unavailable samples and replay. Withdraw retired worker sources independently and prevent preview claims from replacing verified records. Publish owned service metadata to node-info and carry provenance into client snapshots and the terminal interface.

Adapt NVIDIA#179 to source-aware relay and manual-node ownership. Add regressions for unproven routes and invalid telemetry replacing authenticated pressure.

Co-authored-by: Kaylee Lubick <klubick@nvidia.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Describe authenticated inventory, independent previews and older-peer compatibility. Disclose the manual-worker restart downgrade risk and the desktop identity and durable manual-kind follow-ups. Bump node-info, scanner and manual-nodes for additive provenance and security behavior; retain already-unreleased broker and other component bumps relative to v0.8.0.

Document the adaptation of NVIDIA#179.

Co-authored-by: Kaylee Lubick <klubick@nvidia.com>
Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Retained peer pins can keep the transport clustered after admission is cleared. Require an active non-retired admission for proof bindings so fresh, pooled and cached inventory cannot survive withdrawal. Cover absent, cleared and retired admission records with retained pins.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Check local and pinned peer certificate validity whenever a proof binding is used, and recheck the response certificate at acceptance. This disqualifies cached routing inventory and telemetry when a certificate expires, including responses crossing expiry on pooled connections. Add invalid-window, in-flight expiry and broker cache/replay regressions.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Hold the worker callback mutex across trust-refresh snapshot and replay, and tag statuses with their worker generation. Reject retired-generation snapshots and advance launch generations under the same mutex. Controlled replay regressions cover retirement, removal and newer callbacks without resurrecting stale routing inventory.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Remove an expired directory snapshot only when the complete record is still current under the directory lock. Serialize verified publication and enrichment apply/notify with removal, cache cleanup and withdrawal. Controlled interleavings cover same-second refreshes and a publication racing a paused withdrawal, preserving fresh inventory and notification order.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Exercise refreshTelemetryOnce against the mutually pinned TLS fixture with an unreachable first address. Assert emitted peer identity, proof and GPU utilization, and retain the shared remembered-address selection assertion. The regression fails when telemetry is restricted to its first address.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
The manual bridge fixtures answered public PAIR node-info, which now intentionally denies the unauthenticated bare-engine bypass. Hold the node-info port but return 404 for bare Ollama and LM Studio, and expect the namespaced manual routing key and manual inventory label.

Replace the unproven learned-UUID routing expectation with preview regressions for absent and claimed UUIDs. Check independent peerRecordId and identityVerification, no peer trust or models, and exclusion from both proxies across a re-probe interval. Verified UUID keying remains covered by TestManualToEnrichedHostUUID and TestManualNodeBridgesToRelayDir in the broker module. No runtime behavior or versions change.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
@JaredP94
JaredP94 force-pushed the fix/verified-peer-inventory branch from a0c46f5 to cb118dd Compare November 3, 2026 08:20
Do not exempt preview withdrawal or scanner retirement from cleaning up already tracked workloads. Preserve jobs when a proven claim survives for the same participant, and reject new active events against known preview-only inventory without blocking terminal reconciliation or participants not yet discovered locally.

Add in-module regressions for preview-only loss, surviving verified claims, scanner retirement and preview workload admission. All new failing cases were observed on the unfixed broker. Keep the existing unreleased broker 2.5.0 bump relative to released 2.4.1.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Upgrade the model enrichment, periodic refresh, workload restart, node-loss and outbound fixtures to real admitted cross-pinned peers. Serve authenticated node-info metadata with the exact certificate principal and service ports before model reads or broadcasts become eligible. Preserve all enrichment, deletion, running/terminal rehydration and node-loss assertions.

Keep a plaintext lookalike preview alongside the proven model peer and assert that it never contributes model inventory or receives a model read. Cross-process execution is intentionally left to Linux CI; local validation is three-platform go vet and formatting only.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Replace a proven peer's key-bearing listener with a fresh public identity at the identical endpoint. Keep the verified record through a transient proof failure, then require its original-token withdrawal after the grace period despite a live TCP port. A multicast miss alone must preserve a peer that still proves its identity.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
The plaintext ghost fixture now produces an independently keyed preview through node-updated, so waiting for node-discovered silently skipped working Linux discovery. Exercise the verified record with the admitted, cross-pinned mTLS fixture, then replace its listener with a wiped public identity at the exact same address. Retain a separate preview test for the public identity-confirming liveness probe, and fail missing discovery after the multicast prerequisite succeeds.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Remove the remaining post-requireMulticast self-skips in active and terminal workload rehydration and the shared workload-manager startup helper. A required port collision must fail those tests rather than silently erase their runtime coverage.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Peer certificate renewal changes the pin before discovery publishes the renewed proof. The preview-only workload guard treated that inventory gap as an unverified remote claim and discarded authoritative lifecycle reports from our own proxies.

Track workload provenance from the supervised worker path, exempt local proxy reports from preview admission, and retain stable participant IDs and existing loss and withdrawal sweeps. Remote claims remain guarded even when their payload names the local origin. Cover all three proxies, client and scheduler delivery, and cleanup after renewal, withdrawal and scanner retirement. Keep the broker at its already-unreleased 2.5.0 version; no wire payload changes.

Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
@JaredP94
JaredP94 merged commit ad5edd7 into main Nov 3, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant