DPL operations snapshot

Source commit: d331f45b0e
This commit is contained in:
hellcat 2026-10-20 16:27:34 +08:00
parent 2547ea25b4
commit 64c3b08740

View File

@ -14,6 +14,7 @@ import os
from pathlib import Path from pathlib import Path
import shutil import shutil
import socket import socket
import ssl
import subprocess import subprocess
import tempfile import tempfile
import time import time
@ -53,6 +54,7 @@ def validate(config, expectations, exact=True):
except ValueError as exc: except ValueError as exc:
raise VerificationError('Invalid expected exit IP') from exc raise VerificationError('Invalid expected exit IP') from exc
require(len(spec['expected_country']) == 2 and spec['expected_country'].isalpha() and spec['expected_country'].isupper(), 'Expected country must be two uppercase letters') require(len(spec['expected_country']) == 2 and spec['expected_country'].isalpha() and spec['expected_country'].isupper(), 'Expected country must be two uppercase letters')
require(spec.get('verification', 'full') in ('full', 'tls'), 'Unsupported verification mode')
tag = spec['tag'] tag = spec['tag']
require(tag in nodes and tag not in selected, 'Missing/duplicate selected node') require(tag in nodes and tag not in selected, 'Missing/duplicate selected node')
node = nodes[tag] node = nodes[tag]
@ -151,6 +153,23 @@ def run_node(config, spec, binary, port, diagnostic_dir):
stop(proc) stop(proc)
def run_tls(spec):
"""Reach the relay and validate the node certificate; no exit/traffic claim."""
context = ssl.create_default_context()
with socket.create_connection((spec['host'], spec['port']), timeout=10) as stream:
with context.wrap_socket(stream, server_hostname=spec['sni']) as secure:
protocol = secure.version()
require(protocol in ('TLSv1.2', 'TLSv1.3'), 'Unexpected TLS protocol')
return {'tag': spec['tag'], 'strict_tls': True, 'live': True,
'relay': spec['host'], 'relay_port': spec['port'], 'sni': spec['sni'],
'verification': 'tls', 'node_tls': protocol}
def run_specs(config, specs, binary, port, folder):
return [run_tls(spec) if spec.get('verification', 'full') == 'tls'
else run_node(config, spec, binary, port, folder) for spec in specs]
def write_report(path, report): def write_report(path, report):
destination = Path(path) destination = Path(path)
require(destination.parent.is_dir() and destination.parent.stat().st_mode & 0o077 == 0, require(destination.parent.is_dir() and destination.parent.stat().st_mode & 0o077 == 0,
@ -212,6 +231,7 @@ def main():
specs = [{'tag': candidates[0]['tag'], 'host': qa.get('host'), 'port': qa.get('port'), specs = [{'tag': candidates[0]['tag'], 'host': qa.get('host'), 'port': qa.get('port'),
'sni': qa.get('sni'), 'uuid': qa.get('uuid'), 'expected_exit': args.expected_exit, 'sni': qa.get('sni'), 'uuid': qa.get('uuid'), 'expected_exit': args.expected_exit,
'expected_country': args.expected_country}] 'expected_country': args.expected_country}]
require(bool(args.expectations) or all(s.get('verification', 'full') == 'full' for s in specs), 'Isolated QA requires full verification')
tags = validate(config, specs, exact=bool(args.expectations)) tags = validate(config, specs, exact=bool(args.expectations))
results = [] results = []
if args.run: if args.run:
@ -219,8 +239,7 @@ def main():
binary = str(Path(args.binary).resolve()) binary = str(Path(args.binary).resolve())
folder = Path(source).resolve().parent folder = Path(source).resolve().parent
require(folder.stat().st_mode & 0o077 == 0, 'Live diagnostics directory must be private') require(folder.stat().st_mode & 0o077 == 0, 'Live diagnostics directory must be private')
for spec in specs: results = run_specs(config, specs, binary, args.port, str(folder))
results.append(run_node(config, spec, binary, args.port, str(folder)))
report = {'state': 'live_verified' if args.run else 'structure_validated', report = {'state': 'live_verified' if args.run else 'structure_validated',
'verified_at': int(time.time()) if args.run else None, 'verified_at': int(time.time()) if args.run else None,
'qa_user_id': qa_user_id, 'selected_nodes': tags, 'results': results, 'qa_user_id': qa_user_id, 'selected_nodes': tags, 'results': results,