Files
gavindiazandClaude Code 3a005ddcc6
Docs / Validate documentation (push) Canceled after 0s
Docs / Deploy GitHub Pages (push) Canceled after 0s
CI Final Summary (AI) / AI Final Summary (push) Canceled after 0s
CI Final Summary (AI) / Push/PR event feed (push) Canceled after 0s
CI / CI Integrity and Change Classification (push) Canceled after 0s
CI / Code Quality & Tests (push) Canceled after 0s
Dependency Lock & Migration Safety / Dependency drift (lock vs pyproject) (push) Canceled after 0s
Dependency Lock & Migration Safety / Migration safety (fail-loud + version postconditions) (push) Canceled after 0s
JS Tests / Frontend JS Unit Tests (push) Canceled after 0s
Security / CodeQL Analysis (push) Canceled after 0s
Security / Trivy Vulnerability Scan (push) Canceled after 0s
Tests (OS Matrix) / Py Tests (macos-latest) (push) Canceled after 0s
Tests (OS Matrix) / Py Tests (windows-latest) (push) Canceled after 0s
CI / Extended Validation (Tier 2) (push) Canceled after 0s
CI / Heavy CI (database-provider) (push) Canceled after 0s
CI / Heavy CI (e2e) (push) Canceled after 0s
CI / Heavy CI (integration) (push) Canceled after 0s
CI / Heavy CI (model-validation) (push) Canceled after 0s
CI / Heavy CI (research-backtest) (push) Canceled after 0s
CI / Aggregate CI Results (push) Canceled after 0s
chore(repo): initial import of Nexus Trading Forex Bot into self-hosted hosting
Full project import for the self-hosted code hosting
(https://code.aifunny.ltd/gavindiaz/my-NexusTradingForexBot.git).

Includes the live-freshness + scaler-hash fixes for the permanent
STALE dashboard (tick_pipeline now_utc stamps; infer_probabilities
computes model_input_hash on the actual scaled 70D tensor), the
data-fetch default-path fix, the g29 web-auth test fixes, and a
Chinese user manual (使用手册.md) for the web dashboard.

Scratch diagnostic scripts (check*.py, contain a live web-auth token)
and the .kilo/ agent-worktree directory are gitignored, not committed.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 23:24:54 +08:00

337 lines
13 KiB
Python

"""DOWNLOAD/INSTALL INTEGRITY VERIFICATION suite (INSTALL-VERIFY hardening).
Proves the download->install integrity gate end-to-end with LOCAL fixtures
(localhost HTTP origin, real PowerShell) - zero external network:
H1 SHA256 match -> download verified, artifact lands at destination
H2 SHA256 mismatch -> BLOCKED (throw), no artifact at destination
H3 malformed digest -> BLOCKED before any network use of the value
H4 truncated payload + MinBytes floor -> BLOCKED as truncated
H5 empty payload -> BLOCKED (empty check retained)
H6 HTTP 404 payload -> retried then BLOCKED, no destination file
H7 unverified path still records telemetry with sha256 of the artifact
H8 .partial residue never left behind on failure
H9 state/install.json carries install_state + download_telemetry fields
Failure of any of these means the installer can mistake a corrupt download
for a successful one - the exact defect class this hardening closes.
"""
from __future__ import annotations
import hashlib
import json
import subprocess
import sys
import threading
import zipfile
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
import pytest
REPO_ROOT = Path(__file__).resolve().parents[2]
INSTALLER = REPO_ROOT / "installer" / "install.ps1"
pytestmark = pytest.mark.skipif(
not INSTALLER.exists() or sys.platform != "win32",
reason="installer integrity tests require Windows + installer/install.ps1",
)
def _ps() -> str:
import shutil
for candidate in ("pwsh.exe", "powershell.exe"):
p = shutil.which(candidate)
if p:
return p
pytest.skip("no PowerShell host")
return ""
PS = _ps()
# ---------------------------------------------------------------------------
# Local HTTP origin serving one deterministic payload
# ---------------------------------------------------------------------------
class _PayloadHandler(BaseHTTPRequestHandler):
payload = b""
status = 200
def do_GET(self):
self.send_response(self.status)
self.send_header("Content-Length", str(len(self.payload)))
self.end_headers()
self.wfile.write(self.payload)
def log_message(self, *a): # silence
pass
def _serve(payload: bytes, status: int = 200):
handler = type("H", (_PayloadHandler,), {"payload": payload, "status": status})
srv = ThreadingHTTPServer(("127.0.0.1", 0), handler)
t = threading.Thread(target=srv.serve_forever, daemon=True)
t.start()
return srv, f"http://127.0.0.1:{srv.server_address[1]}/artifact.bin"
def run_download(tmp_path: Path, url: str, dest: Path, *extra: str, max_attempts: int = 2):
"""Drive the REAL Invoke-NexusDownload through a dot-sourced installer."""
expr = (
'. "{inst}"; '
"try {{ "
" $f = Invoke-NexusDownload -Url '{url}' -Destination '{dest}' "
" -MaxAttempts {max_attempts} -TimeoutSec 60 {extra}; "
" 'DOWNLOADED=' + $f; "
" $t = $Script:DownloadTelemetry | Select-Object -Last 1; "
" 'TELEMETRY=' + ($t | ConvertTo-Json -Compress) "
"}} catch {{ "
" 'BLOCKED=' + $_.Exception.Message; "
" $t = $Script:DownloadTelemetry | Select-Object -Last 1; "
" if ($t) {{ 'TELEMETRY=' + ($t | ConvertTo-Json -Compress) }} "
"}}"
).format(
inst=str(INSTALLER).replace("\\", "/"),
url=url,
dest=str(dest).replace("\\", "/"),
max_attempts=max_attempts,
extra=" ".join(extra),
)
return subprocess.run(
[PS, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", expr],
capture_output=True,
text=True,
timeout=240,
encoding="utf-8",
errors="replace",
check=False,
)
class TestSha256Verification:
def test_matching_digest_downloads_and_verifies(self, tmp_path):
payload = b"NEXUS integrity fixture" * 100
digest = hashlib.sha256(payload).hexdigest()
srv, url = _serve(payload)
try:
dest = tmp_path / "ok.bin"
r = run_download(tmp_path, url, dest, "-ExpectedSha256", digest)
out = r.stdout
assert "DOWNLOADED=" in out, out + r.stderr[-400:]
assert dest.read_bytes() == payload
# Telemetry must record the verified outcome with the digest.
tel_line = next((ln for ln in out.splitlines() if ln.startswith("TELEMETRY=")), "")
assert tel_line, out
tel = json.loads(tel_line[len("TELEMETRY=") :])
assert tel["outcome"] == "ok"
assert tel["verification"] == "sha256"
assert tel["expected_sha"] == digest
assert tel["actual_sha"] == digest
finally:
srv.shutdown()
def test_mismatched_digest_is_blocked_with_no_artifact(self, tmp_path):
payload = b"NEXUS integrity fixture" * 100
wrong_digest = "0" * 64
srv, url = _serve(payload)
try:
dest = tmp_path / "tampered.bin"
r = run_download(tmp_path, url, dest, "-ExpectedSha256", wrong_digest, max_attempts=1)
out = r.stdout
assert "BLOCKED=" in out, out + r.stderr[-400:]
assert "MISMATCH" in out, out
assert not dest.exists(), (
"a digest-mismatched artifact must never land at the destination"
)
tel_line = next((ln for ln in out.splitlines() if ln.startswith("TELEMETRY=")), "")
if tel_line:
tel = json.loads(tel_line[len("TELEMETRY=") :])
assert tel["outcome"] == "blocked"
finally:
srv.shutdown()
def test_malformed_digest_is_blocked(self, tmp_path):
payload = b"data"
srv, url = _serve(payload)
try:
dest = tmp_path / "bad-digest.bin"
r = run_download(tmp_path, url, dest, "-ExpectedSha256", "deadbeef", max_attempts=1)
assert "BLOCKED=" in r.stdout, r.stdout + r.stderr[-400:]
assert "64-hex" in r.stdout
assert not dest.exists()
finally:
srv.shutdown()
def test_truncated_payload_blocked_by_min_bytes_floor(self, tmp_path):
payload = b"short"
srv, url = _serve(payload)
try:
dest = tmp_path / "truncated.bin"
r = run_download(tmp_path, url, dest, "-MinBytes", "10000", max_attempts=1)
out = r.stdout
assert "BLOCKED=" in out, out + r.stderr[-400:]
assert "minimum" in out or "truncated" in out
assert not dest.exists()
finally:
srv.shutdown()
def test_empty_payload_still_blocked(self, tmp_path):
srv, url = _serve(b"")
try:
dest = tmp_path / "empty.bin"
r = run_download(tmp_path, url, dest, max_attempts=1)
assert "BLOCKED=" in r.stdout, r.stdout + r.stderr[-400:]
assert not dest.exists()
finally:
srv.shutdown()
def test_http_error_status_blocked_and_retried(self, tmp_path):
srv, url = _serve(b"not found", status=404)
try:
dest = tmp_path / "http404.bin"
r = run_download(tmp_path, url, dest, max_attempts=2)
assert "BLOCKED=" in r.stdout, r.stdout + r.stderr[-400:]
assert not dest.exists()
# .partial residue must be cleaned on every failure path.
partials = list(tmp_path.glob("http404.bin.partial-*"))
assert not partials, f"partial residue left behind: {partials}"
finally:
srv.shutdown()
def test_unverified_download_records_telemetry_with_actual_sha(self, tmp_path):
payload = b"unverified-but-recorded" * 10
digest = hashlib.sha256(payload).hexdigest()
srv, url = _serve(payload)
try:
dest = tmp_path / "unverified.bin"
r = run_download(tmp_path, url, dest)
assert "DOWNLOADED=" in r.stdout, r.stdout + r.stderr[-400:]
tel_line = next((ln for ln in r.stdout.splitlines() if ln.startswith("TELEMETRY=")), "")
assert tel_line
tel = json.loads(tel_line[len("TELEMETRY=") :])
assert tel["outcome"] == "ok"
assert tel["verification"] in ("empty-check", "size")
assert tel["actual_sha"] == digest, (
"telemetry must record the artifact digest even when unpinned"
)
finally:
srv.shutdown()
class TestStateTelemetryFields:
def test_state_ledger_carries_install_state_and_telemetry_fields(self, tmp_path):
"""The state stage's install.json must carry the truth-table summary
field (install_state) and the download telemetry array (possibly
empty) - the machine-readable contract for AVAILABLE/DEGRADED/BLOCKED
reporting and per-download digests."""
home = tmp_path / "NexusHome"
engine = tmp_path / "engine-src"
expr = (
'. "{inst}"; '
"$NexusHome = '{home}'; "
"$InstallDir = '{engine}'; "
"Write-InstallState -LastStage 'state'; "
"'STATE-WRITTEN'"
).format(
inst=str(INSTALLER).replace("\\", "/"),
home=str(home).replace("\\", "/"),
engine=str(engine).replace("\\", "/"),
)
r = subprocess.run(
[PS, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", expr],
capture_output=True,
text=True,
timeout=180,
encoding="utf-8",
errors="replace",
check=False,
)
assert "STATE-WRITTEN" in r.stdout, r.stdout + r.stderr[-400:]
state = json.loads((home / "state" / "install.json").read_text(encoding="utf-8"))
# No stages ran in this session => honest UNKNOWN, never a fake AVAILABLE.
assert state.get("install_state") == "UNKNOWN"
assert hasattr(state, "get") and "download_telemetry" in state
assert isinstance(state["download_telemetry"], list)
class TestChecksumManifestProbe:
"""Manual checksum probe contract: the helper must agree with an
independent Python-side SHA256 of the same file (the 'manual probe' the
verification plan calls for)."""
def test_get_file_sha256_matches_python_hashlib(self, tmp_path):
payload = bytes(range(256)) * 512 # 128 KiB deterministic blob
target = tmp_path / "probe.bin"
target.write_bytes(payload)
expected = hashlib.sha256(payload).hexdigest()
expr = (". \"{inst}\"; $h = Get-FileSha256 -Path '{p}'; 'HASH=' + $h").format(
inst=str(INSTALLER).replace("\\", "/"), p=str(target).replace("\\", "/")
)
r = subprocess.run(
[PS, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", expr],
capture_output=True,
text=True,
timeout=120,
encoding="utf-8",
errors="replace",
check=False,
)
out = r.stdout.strip()
assert out.startswith("HASH="), r.stdout + r.stderr[-300:]
actual = out[len("HASH=") :].strip().lower()
assert actual == expected, f"installer hash {actual} != python hash {expected}"
def test_zip_artifact_with_pinned_digest_roundtrip(self, tmp_path):
"""A ZIP artifact verified against a pre-computed digest then
extracted: the full download->verify->extract chain in one flow."""
good = tmp_path / "src.zip"
with zipfile.ZipFile(good, "w") as zf:
zf.writestr("repo/pyproject.toml", "[project]\nname = 'nexus'\n")
payload = good.read_bytes()
digest = hashlib.sha256(payload).hexdigest()
srv, url = _serve(payload)
try:
dest = tmp_path / "roundtrip.zip"
extract = tmp_path / "roundtrip-extract"
expr = (
'. "{inst}"; '
"try {{ "
" $f = Invoke-NexusDownload -Url '{url}' -Destination '{dest}' "
" -MaxAttempts 1 -TimeoutSec 60 -ExpectedSha256 '{digest}'; "
" Expand-NexusZipSafe -ZipPath $f -Destination '{extract}'; "
" 'CHAIN-OK'"
"}} catch {{ 'CHAIN-BLOCKED=' + $_.Exception.Message }}"
).format(
inst=str(INSTALLER).replace("\\", "/"),
url=url,
dest=str(dest).replace("\\", "/"),
digest=digest,
extract=str(extract).replace("\\", "/"),
)
r = subprocess.run(
[
PS,
"-NoProfile",
"-NonInteractive",
"-ExecutionPolicy",
"Bypass",
"-Command",
expr,
],
capture_output=True,
text=True,
timeout=180,
encoding="utf-8",
errors="replace",
check=False,
)
assert "CHAIN-OK" in r.stdout, r.stdout + r.stderr[-400:]
assert (extract / "repo" / "pyproject.toml").exists()
finally:
srv.shutdown()