Skip to content

feat(cli): control-parity subcommands + peer management (#426 #559)#45

Merged
MichaelTaylor3d merged 2 commits into
mainfrom
feat/cli-control-parity
Jul 17, 2026
Merged

feat(cli): control-parity subcommands + peer management (#426 #559)#45
MichaelTaylor3d merged 2 commits into
mainfrom
feat/cli-control-parity

Conversation

@MichaelTaylor3d

Copy link
Copy Markdown
Contributor

Closes #426 #559

TLDR

The dig-node/dign CLI now has a subcommand for every node control the DIG Chrome extension can drive (over the gated control.* WS surface), plus peers for viewing + managing peer connections — all with --json machine 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:

control.* method CLI verb status
control.status info added (distinct from status, the unauth /health liveness probe)
control.config.get / setUpstream config [get] / config set-upstream <url> added
control.cache.get / setCap / clear cache [get] / cache set-cap <bytes> / cache clear added
control.hostedStores.list / pin / unpin / status stores [list] / stores pin|unpin|status <store> added
control.sync.status / trigger sync [status] / sync trigger <store> added
control.updater.status / setChannel / pause / resume / checkNow updater status|set-channel|pause|resume|check-now added
control.subscribe / unsubscribe / listSubscriptions subscriptions add|remove|list added
control.pairing.list / approve / revoke pair list|approve|revoke already existed (#280)
control.peerStatus peers [list] added (#559)

A drift test (cli_covers_every_node_control_method) asserts every method in CONTROL_METHODS has 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's peersApi.ts surface.

Auth-gate handling

Every mutating CLI control goes through the identical gate as the WS surface: the shared control_client::call_control presents the node's MASTER control token (read WITHOUT minting, #501) as X-Dig-Control-Token over the loopback endpoint. Possession of the on-disk master token = local-machine control — no unauthenticated backdoor. pair.rs was refactored onto this shared client (dedupe).

--json coverage

Every 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 extended control.peerStatus (peers[]/bans[]/pool), but the node has not implemented them (documented gap in peersApi.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 extended control.peerStatus payload; 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-service green; cargo clippy -p dig-node-service --all-targets zero warnings; cargo fmt clean.
  • 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 --help shows all new subcommands.

gitnexus blast radius

Scoped to dig-node-service: new modules control_client/control_cli/peers; edits to entrypoint.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

MichaelTaylor3d and others added 2 commits July 16, 2026 17:05
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
MichaelTaylor3d merged commit ed0e10a into main Jul 17, 2026
13 checks passed
@MichaelTaylor3d
MichaelTaylor3d deleted the feat/cli-control-parity branch July 17, 2026 00:27
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>
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