Files

65 lines
2.7 KiB
Python

"""Synthetic, network-none checks against the actual pinned Core and nginx."""
import hashlib
from pathlib import Path
import stat
import urllib.error
import urllib.request
KEY = "11" * 32
def request(port, path, expected, method="GET", key=None):
headers = {} if key is None else {"X-API-KEY": key}
req = urllib.request.Request(f"http://127.0.0.1:{port}{path}", method=method, headers=headers)
try:
with urllib.request.urlopen(req, timeout=8) as response:
code, body = response.status, response.read()
except urllib.error.HTTPError as error:
code, body = error.code, error.read()
assert code == expected, (method, path, code, expected, body[:200])
assert KEY.encode() not in body, "managed key leaked in HTTP response"
print(f"PASS {method} {port}{path}: {code}")
return body
children = set()
for proc in Path('/proc').iterdir():
if not proc.name.isdigit():
continue
try:
command = (proc / 'cmdline').read_bytes().split(b'\x00')[0]
if command.endswith(b'java') or command.startswith(b'nginx:'):
assert b'QORTAL_API_KEY=' not in (proc / 'environ').read_bytes()
children.add('java' if command.endswith(b'java') else 'nginx')
except FileNotFoundError:
pass # An unrelated short-lived fixture process exited.
assert children == {'java', 'nginx'}
print('PASS managed environment secret absent from actual Core/nginx children')
key_path = Path("/qortal/apikey.txt")
assert key_path.read_text() == KEY
info = key_path.stat()
assert stat.S_ISREG(info.st_mode) and stat.S_IMODE(info.st_mode) == 0o600
assert (info.st_uid, info.st_gid) == (1000, 100)
assert Path("/qortal/operator-sentinel").read_bytes() == b"preserve operator data\n"
settings_digest = hashlib.sha256(Path("/qortal/settings.json").read_bytes()).hexdigest()
settings_receipt = Path("/qortal/fixture-settings-sha256")
if settings_receipt.exists():
assert settings_receipt.read_text() == settings_digest, "operator settings changed"
else:
settings_receipt.write_text(settings_digest)
receipt = Path("/qortal/fixture-key-inode")
if receipt.exists():
assert int(receipt.read_text()) == info.st_ino, "key unexpectedly replaced"
else:
receipt.write_text(str(info.st_ino))
request(12391, "/admin/info", 200)
request(12390, "/", 200)
request(12390, "/core/admin/info", 200)
request(12390, "/core/admin/stop", 404, "GET", KEY)
request(12390, "/core/admin/info", 403, "POST", KEY)
request(12391, "/admin/stop", 403, "GET")
request(12391, "/admin/stop", 403, "GET", "22" * 32)
request(12391, "/admin/info", 200)
print("PASS managed key/private mode/inode and operator bytes preserved")
# Explicit stop of this disposable node only, after unauthorized calls failed.
request(12391, "/admin/stop", 200, "GET", KEY)