Files
lussierj 8b0d32cd6b security(discovery): enforce Zone isolation and retire unsafe legacy writers
Bind Agent observations, review, enrichment and telemetry to current Zone
and inventory authority. Preserve immutable MAC ownership and historical
snapshots with stale-result rejection and transactional security audits.

Retire unbound direct/range/scheduled discovery and one/bulk legacy summary
writes in both modes. Require reconciled exact inventory identity or
explicit Zone-scoped IP selection for CSV metadata imports.

Independent Blocker #1 application-security re-audit: PASS on tree
cf863aadc9. Evidence: 141 focused PostgreSQL/HTTP
tests passed; Chromium and PowerShell checks passed. Two documented baseline
source assertions remain unchanged. Production deployment is not approved.
2026-10-17 00:45:04 +00:00
..
2026-08-26 15:48:59 +00:00

MinerOps Windows Agent

Stage A physical-control containment

Physical miner control is disabled in this version, including suspend, resume, performance-mode changes, reboot, M30 tests, and miner-side password changes. No environment flag, configured API3 credential, or Agent capability report can enable it. This is containment, not completion of Blocker #3 identity binding.

The Hub returns HTTP 410 for retired legacy command, scheduling, and unrestricted diagnostic endpoints (after authorization where applicable). Typed control POSTs require miners.control and return HTTP 409 physical_control_disabled_stage_a. The unrestricted whatsminer-read-test endpoint is not a supported read-only tool.

Authenticated queue polling cancels pending/claimed physical and unknown command types, records an atomic agent.command.rejected audit entry, and only delivers fixed telemetry/discovery command types. Results cannot promote retired entries. Original payloads, prior results/errors, timestamps, and terminal history remain. Cancellation of an already claimed command does not prove it was never sent; the audit explicitly records its previous execution outcome as unknown.

The Windows executor rejects all current physical-control schemas without any device connection and advertises physical control as unavailable. Existing Agents must be stopped/drained and upgraded before claiming fleet-wide containment: server cancellation cannot recall payloads cached by older running Agents. Do not enable control or deploy this work before separate security review. The ordered, fail-closed procedure is in the Stage A old-Agent cutover runbook. Native Windows PowerShell 5.1/SYSTEM validation and verified fleet network fencing remain production gates; server cancellation alone cannot contain an old executor.

Retained legacy/API3 enrichment helpers validate exact read commands and fixed parameters before opening a socket. Unknown operations and extra keys fail closed. Schedule cancel/delete require miners.control and retire matching live unsupported commands for the stored Agent with atomic actor-attributed rejection audits. Deletion retains schedule history; retries do not duplicate audits. Previously claimed execution remains unknown. Manual cutover retirement does not claim read work and must sweep offline/queue-only Agent IDs until the global live count is zero.

The Windows Agent runs at a mining site and performs local discovery, polling, API3 enrichment, and pool polling. Physical miner control is disabled in Stage A. MinerOps does not send API3 credentials through the hub command queue; those credentials remain in the Agent's local agent-config.json.

Recovered Baseline

The seven runtime and support scripts in this directory were recovered from the live C:\MinerOpsAgent installation. BASELINE_SHA256SUMS records their exact pre-change hashes. Historical backups, live configuration, state, logs, and probe output are intentionally excluded.

Local Files

Create agent-config.json from config.example.json on the Agent host. Never commit that file. site_id is the durable MinerOps site UUID. agent_zone_id is the optional durable network-reachability Zone UUID; older configurations may omit it only when the Hub can preserve an established assignment or resolve exactly one enabled Zone at the Site. site_name is retained only for transitional display compatibility.

The Agent writes runtime state to agent-state.json and logs under logs/. Installation and upgrades preserve all three paths.

Security

API3 account and password values are local secrets. Missing credentials make miner control unavailable. Passwords, API tokens, salts, and the Agent secret must not be written to normal logs or returned to MinerOps command history.

New Agent identities use per-Agent credentials created through secure one-time enrollment. The permanent Agent secret is returned only to the enrolling Agent and is stored locally in agent-config.json; MinerOps stores only its hash. The legacy deployment shared secret remains only for explicitly retained compatibility behavior and must not authenticate a newly enrolled per-Agent identity.

Legacy Compatibility

The older direct Hub API3, /agent-control, password-change, bulk-control, and scheduling paths remain available for compatibility and are deprecated for the Internal Alpha. The new Miner Detail controls use only the typed control API and Agent queue; the modular control backend does not connect directly to miners.

Deployment

New Agent enrollment

For a new Agent, use Agent Management in MinerOps:

  1. Choose the Site and an enabled, unassigned Agent Zone.

  2. Enter a descriptive Agent name.

  3. Create a Windows enrollment.

  4. Download MinerOpsAgent-Windows.zip before the enrollment expires.

  5. Copy the ZIP to the intended Windows machine and extract it.

  6. Open Windows PowerShell as Administrator in the extracted MinerOpsAgent-Windows directory.

  7. Run:

    .\Enroll-MinerOpsAgent.ps1
    
  8. Enter the local WhatsMiner API3 account/password when prompted, or leave the account blank if API3 functionality is not being configured yet.

  9. The bootstrapper exchanges the short-lived token with POST /api/agent/enroll, saves the resulting permanent Agent identity locally, and hands off to the safe runtime installer.

  10. Verify the Agent appears in Agent Management and checks in successfully.

  11. Delete the downloaded ZIP and extracted setup directory.

Do not place enrollment.json, enrollment tokens, Agent secrets, or API3 credentials in screenshots, chat, tickets, logs, or source control.

Existing Agent upgrade

An existing legacy Agent must receive a per-Agent credential before the global shared-secret compatibility path can be retired for its identity. In Agent Management, use Upgrade credential on that Agent. Download the resulting Windows package, transfer it only to that Agent computer, and run:

   .\Upgrade-MinerOpsAgentCredential.ps1

The authorization is bound server-side to the existing Agent ID and its current Site and Agent Zone. The script validates the local Agent ID, upgrades the canonical runtime, stops the main Agent task, generates the permanent secret locally, and recoverably replaces only the credential and durable routing fields in agent-config.json using protected same-directory pending and prior names. Existing API3 credentials, polling settings, network ranges, state, logs, and backups are preserved. Before any secret is written, the script creates and verifies a protected recovery file containing the original Scheduled Task state, exact transition token, and exact locally generated credential. The Hub accepts an ambiguous retry only for that same token and credential.

The Agent directory is a filesystem security boundary. The transition rejects junctions/reparse points, verifies trusted ancestors, denies standard users create/delete/rename rights, and revalidates the boundary before each rename. If an existing Agent directory is discovered insecure, the script first writes C:\MinerOpsAgent.minerops-filesystem-trust.blocked-<random>.state under the trusted parent, then hardens the directory only to contain the incident. The blocker is outside the contaminated namespace because changing a DACL does not revoke file or directory handles opened before repair. The same process never redeems a token, creates or activates a permanent credential, runs the installer, or removes that blocker. Ordinary second, third, and later invocations remain blocked even when every current ACL looks correct.

Recovery, pending, replacement remnants, and late-arriving artifacts are non-authoritative while the external blocker exists. Known transition state is quarantined without parsing. A correct filename, syntax, or ACL cannot promote it on a later run. Invalidate any possibly exposed authorization and retain or remove evidence only under the approved incident procedure.

Filesystem trust-epoch recovery

Use this procedure only after confirming the blocker was created by the containment event and preserving required evidence:

  1. Do not delete or edit the external blocker. Do not run an ordinary retry.

  2. Use Restart to perform a full Windows kernel boot. Shutdown with Fast Startup is not sufficient: Microsoft documents Fast Startup as hibernating and restoring kernel session 0. The script identifies the kernel epoch by the Event Log record anchor of the newest Microsoft-Windows-Kernel-Boot event 27 whose BootType is exactly 0. Provider, event ID, record ID, and supported event version come from typed EventRecord properties; namespace-aware XML selection reads only the BootType payload. The new full-boot record ID must be strictly greater than the stored record ID. Equality, an older/restored record, log clearing or numbering reset, missing history, duplication, malformed XML, and an unsupported provider schema all fail closed and require safe operator intervention. There is no timestamp fallback. The anchor is unchanged by clock or timezone changes, sleep, hibernation, and Fast Startup. See Microsoft's system power-state documentation and Fast Startup support guidance.

  3. For a credential transition, use a fresh transition package if any recovery, pending, remnant, quarantine, or internal blocker existed. Remove those artifacts only under the approved incident procedure after invalidating the old authorization.

  4. From the reviewed package, run:

    .\Upgrade-MinerOpsAgentCredential.ps1 `
        -ApproveFilesystemTrustResetAfterReboot
    

    The script verifies that Windows boot identity changed, rescans the protected namespace, positively verifies and stops the expected Scheduled Task, and asks the installer to replace managed runtime without backing up or restoring any pre-reset runtime. The installer leaves both the Agent task and external blocker untouched after publication; it has no blocker-deletion path. Before its first fallible stop/install step, the parent durably records the strictly validated original task intent as reset-authorized; after installer success it advances the blocker to runtime-published. It then verifies the config against the package/server identity, commits the credential, and restores the recorded task intent. Only the parent removes the blocker, after active config and final task state have both been positively verified and non-recovery transition cleanup has succeeded. Protected recovery stays until after blocker deletion so an interrupted final cleanup remains safe.

  5. For a genuinely new enrollment, preserve evidence and use the approved protected-recreation incident procedure to remove the contaminated namespace and its external blocker, then let Enroll-MinerOpsAgent.ps1 stage a new protected directory. Enrollment has no in-script blocker-deletion path; its explicit compatibility switch cannot override a retained blocker.

The explicit switch without a strictly newer canonical full-kernel-boot anchor fails. Any suspicious transition artifact, failed runtime publication, failed credential convergence, invalid final task, or interrupted cleanup retains the blocker. Runtime publication alone never authorizes deletion. Protected directory recreation is the alternative when the retained namespace cannot be verified.

If the script is interrupted after the Hub commits, rerun the same extracted package without deleting or editing agent-credential-transition.recovery.json or agent-config.json.pending. A protected, matching pending config is resumed; an insecure, malformed, or mismatched artifact fails closed. The original task intent is durable: an Agent which was running before the first attempt ends running, while an intentionally stopped Agent remains stopped. Success is not reported and transition artifacts are not removed until both the active config and expected final task state are verified. The verifier requires exactly one enabled root MinerOpsAgent task, the SYSTEM service-account/highest principal, the installed Windows PowerShell action and service-script arguments, and an exact final state of Running for running intent or Ready for stopped intent. Missing, query failure, access denied, malformed, multiple, disabled, queued, unknown, wrong-action, and wrong-principal results all fail closed and retain recovery.

After a successful transition, the existing Agent ID, Site, and Zone are unchanged. Explicit Agent ID plus the new per-Agent secret is required, and the legacy shared secret is permanently disabled for that identity.

For later code-only upgrades of an Agent that already has a per-Agent credential, copy the new canonical Agent files to a temporary directory and run install.ps1 from an elevated Windows PowerShell session.

The installer copies only managed runtime code to C:\MinerOpsAgent and preserves agent-config.json, agent-state.json, logs, backups, probe output, and other runtime data. Existing Scheduled Task definitions are authoritative and are not rewritten. Missing tasks are created for a fresh or incomplete installation without hard-coded user names.

The per-user MinerOpsAgentTray task is optional UI and is not credential or core Agent authority. During an explicit filesystem trust reset, runtime publication may run noninteractively as NT AUTHORITY\SYSTEM, where no safe interactive user principal can be inferred. The installer still publishes MinerOpsAgentTray.ps1, but deliberately defers creation of a missing tray task until a later interactive maintenance install. It never creates the tray task as SYSTEM or invents a username. An existing tray task remains authoritative and is preserved unchanged rather than silently repaired under SYSTEM; inspect and remediate a suspected malformed definition separately. The core MinerOpsAgent task remains mandatory and strictly verified by credential recovery. MinerOpsApi3Enrichment and MinerOpsPoolPoller are non-interactive background tasks with explicit SYSTEM principals, so missing instances continue to be created during trust-reset publication.

If MinerOpsAgent was running before an upgrade, the installer stops only that Scheduled Task, waits for it to stop, replaces the managed files, and starts it again. A previously stopped Agent remains stopped. Before replacing runtime files, the installer copies them to a timestamped backup under C:\MinerOpsAgent\backups.

Runtime sources, installed destinations, active config, and rollback copies are rejected when they are reparse points or have more than one hard link. A normal trusted upgrade creates a fresh random backup directory and never adopts an existing backup destination. During an explicit post-reboot trust reset, old runtime is never copied into backup or restored; fresh package content replaces it while the external blocker remains, and the Agent task stays stopped for credential verification.

A failed deployment restores managed files, removes tasks created by that failed attempt, and restores the main Agent's prior running state.

uninstall.ps1 unregisters the four MinerOps Scheduled Tasks and removes runtime code while preserving local configuration, state, logs, and backups.