feat(cli): control-parity subcommands + peer management (#426 #559)#45
Merged
Conversation
Add a `dig-node`/`dign` CLI verb for every gated `control.*` method the DIG Chrome extension drives, plus `peers` for viewing + managing peer connections — each with `--json` machine output (§6.2) and thin-dispatched over the ONE loopback control plane (no forked logic). - New shared `control_client::call_control` — reads the master control token read-only (#501) and POSTs a `control.*` method to loopback; the single transport `pair`, `control_cli`, and `peers` all use. `pair.rs` refactored onto it (dedupe). - `control_cli` — info/config/cache/stores/sync/updater/subscriptions actions, each mapping to the SAME control method the extension calls. Mutations go through the identical master-token gate as the WS surface (no backdoor). - `peers` (#559) — list (control.peerStatus) with IPv6-first address display (§5.2) + connect/disconnect/ban/pool-config verbs matching the extension. - Parity enforced mechanically: `control::CONTROL_METHODS` is the canonical set and a drift test asserts every method has a CLI verb. - SPEC §8.6/§8.7, CHANGELOG; version 0.36.0 → 0.37.0 (minor: additive CLI). Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d
added a commit
that referenced
this pull request
Jul 17, 2026
…the control method table (#711) Two control-plane hardening follow-ups from the #45 CLI-parity gates: 1. no_proxy pin: the operator loopback control client now builds its reqwest client with `.no_proxy()`, so a hostile `HTTP_PROXY`/`HTTPS_PROXY` in the environment can no longer route the token-bearing `control.*` POST through an attacker-controlled proxy. reqwest's default proxy behaviour has no automatic loopback bypass; the control plane is loopback-only + token-gated, so the transport is now pinned DIRECT to 127.0.0.1/::1. 2. CONTROL_METHODS <-> dispatch_control lockstep: dispatch_control now routes owned methods via the new OWNED_CONTROL_METHODS routing const (delegating the rest to the node), and a lockstep test asserts CONTROL_METHODS equals OWNED_CONTROL_METHODS + DELEGATED_CONTROL_METHODS exactly (disjoint union). This closes the shell-owned-method drift gap the cli_covers_* test leaves open. The owned match's `_` arm is unreachable by construction. TDD: both tests verified RED first (proxy test dialed the dead proxy; partition test caught an injected drift entry). fmt + clippy -D + full lib suite (213) green. Version bumped 0.38.1 -> 0.38.2 (patch: defense-in-depth hardening, no public-API or behaviour change to the shipped surface). SPEC §7.3 updated. Refs #426 #501 Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d
added a commit
that referenced
this pull request
Jul 17, 2026
…/dispatch lockstep guard (#711) (#49) * chore: wip control-client no_proxy + lockstep guard (#711) Co-Authored-By: Claude <noreply@anthropic.com> * fix(control): pin control-client to direct loopback + lockstep-guard the control method table (#711) Two control-plane hardening follow-ups from the #45 CLI-parity gates: 1. no_proxy pin: the operator loopback control client now builds its reqwest client with `.no_proxy()`, so a hostile `HTTP_PROXY`/`HTTPS_PROXY` in the environment can no longer route the token-bearing `control.*` POST through an attacker-controlled proxy. reqwest's default proxy behaviour has no automatic loopback bypass; the control plane is loopback-only + token-gated, so the transport is now pinned DIRECT to 127.0.0.1/::1. 2. CONTROL_METHODS <-> dispatch_control lockstep: dispatch_control now routes owned methods via the new OWNED_CONTROL_METHODS routing const (delegating the rest to the node), and a lockstep test asserts CONTROL_METHODS equals OWNED_CONTROL_METHODS + DELEGATED_CONTROL_METHODS exactly (disjoint union). This closes the shell-owned-method drift gap the cli_covers_* test leaves open. The owned match's `_` arm is unreachable by construction. TDD: both tests verified RED first (proxy test dialed the dead proxy; partition test caught an injected drift entry). fmt + clippy -D + full lib suite (213) green. Version bumped 0.38.1 -> 0.38.2 (patch: defense-in-depth hardening, no public-API or behaviour change to the shipped surface). SPEC §7.3 updated. Refs #426 #501 Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #426 #559
TLDR
The
dig-node/dignCLI now has a subcommand for every node control the DIG Chrome extension can drive (over the gatedcontrol.*WS surface), pluspeersfor viewing + managing peer connections — all with--jsonmachine output. Each subcommand is a THIN dispatch over the SAME control method the extension calls, through one shared loopback client; no logic is forked from the control plane.Control-surface parity audit (#426)
Canonical set =
control::CONTROL_METHODS(the union of shell-owned + node-delegated control methods). Coverage:infostatus, the unauth/healthliveness probe)config [get]/config set-upstream <url>cache [get]/cache set-cap <bytes>/cache clearstores [list]/stores pin|unpin|status <store>sync [status]/sync trigger <store>updater status|set-channel|pause|resume|check-nowsubscriptions add|remove|listpair list|approve|revokepeers [list]A drift test (
cli_covers_every_node_control_method) asserts every method inCONTROL_METHODShas a CLI verb — so a new node control method cannot ship without a CLI subcommand.Peer commands (#559)
peers [list]→control.peerStatus— running flag, connected count, relay reservation, and (when a newer node fills it) the per-peer list. Addresses displayed IPv6-first per §5.2.peers connect\|disconnect <peer>,peers ban <peer> --state <ban\|blacklist\|none>,peers pool-config --max-connections <n>— match the extension'speersApi.tssurface.Auth-gate handling
Every mutating CLI control goes through the identical gate as the WS surface: the shared
control_client::call_controlpresents the node's MASTER control token (read WITHOUT minting, #501) asX-Dig-Control-Tokenover the loopback endpoint. Possession of the on-disk master token = local-machine control — no unauthenticated backdoor.pair.rswas refactored onto this shared client (dedupe).--jsoncoverageEvery new subcommand shows in
--help, emits the standard{ok,action,service,version,...result}success /{ok:false,error:{code,exit_code,...}}error envelope under--json, and uses the existing differentiated exit-code table.Cross-repo drift flagged (follow-up, NOT fixed here)
The extension defines
control.peers.connect/disconnect/setBan/setPoolConfig+ an extendedcontrol.peerStatus(peers[]/bans[]/pool), but the node has not implemented them (documented gap inpeersApi.ts). This CLI adds the matching verbs so the surface is at parity, but they currently return the node's METHOD_NOT_FOUND until the node ships the peer-management RPCs (dig-nat/dig-gossip AddressManager wiring). Recommend a dig-node follow-up ticket to implement the node-side peer-management control methods + the extendedcontrol.peerStatuspayload; the CLI + extension light up with no client change once it lands.SemVer
minor (0.36.0 → 0.37.0) — additive, backwards-compatible new CLI capability.
Verification
cargo build -p dig-node-servicegreen;cargo clippy -p dig-node-service --all-targetszero warnings;cargo fmtclean.cargo test -p dig-node-service --lib→ 201 passed, 0 failed (incl. the parity drift test, params/summary tests, and the IPv6-first peer-display tests).dig-node --helpshows all new subcommands.gitnexus blast radius
Scoped to
dig-node-service: new modulescontrol_client/control_cli/peers; edits toentrypoint.rs(subcommand tree),control.rs(+CONTROL_METHODS),pair.rs(refactor onto shared client),lib.rs(module registration). No change to the node engine (dig-node-core) or the control-plane dispatch behaviour — the CLI only reaches existing methods over the existing loopback endpoint.Co-Authored-By: Claude noreply@anthropic.com