feat(fleetnode): route miner commands to fleet-node-paired devices#390
Draft
ankitgoswami wants to merge 1 commit into
Draft
feat(fleetnode): route miner commands to fleet-node-paired devices#390ankitgoswami wants to merge 1 commit into
ankitgoswami wants to merge 1 commit into
Conversation
Build the command path on the Phase-1 ControlStream foundation: operator commands for a device paired to a fleet node now dispatch over the node's ControlStream and execute against the LAN miner, reusing the existing command pipeline unchanged (RFC 0001's remote-node Miner adapter). - proto: add pairing.v1.MinerCommand (oneof over reboot/start/stop/blink/curtail/ uncurtail/set-cooling-mode/set-power-target) plus a connection descriptor and an opaque credential field, wired as AgentCommand.miner_command. Add ACK_CODE_UNAUTHENTICATED / ACK_CODE_UNIMPLEMENTED. - server: a remote-node interfaces.Miner adapter marshals each command, calls registry.SendCommand, and maps the ControlAck to the method's error contract. MinerService resolves a device's active fleet node first (new GetActiveFleetNodeForDevice query) and returns the adapter; cloud-dialed devices fall through to the direct PluginMiner. Wired in fleetd via WithCommandSender. - node: handleMinerCommand reconstructs the target miner from the descriptor via the plugin driver and runs the action, behind a credential-provider seam (no-secret drivers work now; authed-driver credential delivery is a pairing concern). End-to-end for the no-secret virtual driver; authed drivers route correctly and light up once pairing provisions the node's per-org key. Heavy commands (firmware, logs, password, unpair) and read/telemetry methods return Unimplemented for now. Also fixes a test-only data race the Phase-1 worker pool can trigger: the stub discoverer now hands out cloned reports. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🔐 Codex Security Review
Review SummaryOverall Risk: HIGH Findings[HIGH] Fleet-node commands route authenticated miners without credentials
[HIGH] Concurrent commands can overwrite and close each other’s plugin handles
[MEDIUM] Transient offline/busy states are converted into permanent queue failures
NotesNo hardcoded wallet, pool, stratum, or worker-credential rewrite logic appeared in the scoped diff. The protobuf/sqlc generated outputs appear consistent with the source proto/query changes. Generated by Codex Security Review | |
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.
Summary
Builds the actual capability: operator commands now reach miners paired via fleet nodes. Stacked on #389 (the ControlStream foundation) — review/merge that first.
A command issued through the existing RPCs/UI against a fleet-node-paired device now routes down that node's
ControlStream, the node reconstructs the LAN miner and executes the action, and the result comes back as aControlAck. The entire command service / queue / status / permissions / curtailment pipeline is unchanged — this is RFC 0001's remote-nodeMineradapter slotted in at miner resolution.What changed
pairing.v1.MinerCommand— aoneofover reboot / start / stop / blink-LED / curtail / uncurtail / set-cooling-mode / set-power-target, plus aMinerConnectionDescriptor(the cloud supplies connection coords; the node has no device DB) and an opaquecredentialfield. Wired asAgentCommand.miner_command. AddedACK_CODE_UNAUTHENTICATED/ACK_CODE_UNIMPLEMENTED.internal/domain/miner/remotenode): aninterfaces.Minerwhose methods marshal aMinerCommand, callregistry.SendCommand, and map theControlAckto the method's error contract (auth → evict + Unauthenticated; unsupported → Unimplemented; offline → FailedPrecondition).internal/domain/miner): newGetActiveFleetNodeForDevicequery;GetMinerFromDeviceIdentifierchecks fleet-node ownership first and returns the adapter, else falls through to the directPluginMiner. Wired infleetdviaWithCommandSender.cmd/fleetnode):handleMinerCommandbuilds a control device from the descriptor via the plugin driver and runs the action, behind a credential-provider seam.Scope / boundary
virtualdriver (thejust devfake miners).proto,antminer) need the node's per-org key to decrypt credentials — that provisioning is the separate pairing effort. Until then those commands reach the miner and fail auth gracefully (UNAUTHENTICATED).Unimplementedfor these.Test plan
go test -race ./cmd/fleetnode/... ./internal/domain/miner/...— green. Adapter: action encoding for all 8 commands + ack→error mapping + offline + unsupported. Node executor (gomock driver/device): execute+ack, enum conversion, error classification, unknown-driver. Resolution (real DB): a fleet-node-paired device resolves to the remote-node miner and a command reaches the sender.serverbuild,golangci-lint, pre-pushtsc— clean.Manual end-to-end (virtual driver)
just dev; enroll/confirm a fleet node; discover avirtualdevice on it; seeddevice+device_pairing=PAIRED+fleet_node_device(until the pairing flow lands); issue Reboot/Curtail/StartMining and confirm it routes over the ControlStream (node logscontrol command received, kind=miner_command), executes against the fake miner, and the batch reports SUCCESS. Verify an offline node fails fast and a command during a discovery on the same node still succeeds.🤖 Generated with Claude Code