Files
truf-server/app/child_bootstrap.py
2026-09-30 20:30:56 +03:00

487 lines
22 KiB
Python

"""Stdlib-only authentication boundary for supervised application children."""
import sys
sys.dont_write_bytecode = True
if not sys.dont_write_bytecode:
raise RuntimeError('supervised child bootstrap could not disable bytecode writes')
import hashlib
import hmac
import json
import os
import runpy
import socket
import stat
MAX_METADATA_BYTES = 256 * 1024
MAX_HANDSHAKE_BYTES = 1024 * 1024
MAX_PYVENV_BYTES = 64 * 1024
MANIFEST_SCHEMA = 5
APPLICATION_IMPORT_SUFFIXES = ('.py', '.pyw', '.pyc', '.pyd')
CONTROL_SCHEMA = 1
REQUIRED_DEPENDENCIES = {
'supervisor': ('psycopg', 'yaml'),
'postgres-runtime': ('psycopg', 'yaml'),
'migrate-runtime-safety': ('psycopg', 'yaml'),
'scanner': ('psycopg', 'requests', 'urllib3', 'yaml', 'zstandard'),
'discovery-producer': ('psycopg', 'requests', 'urllib3', 'yaml', 'zstandard'),
'docker-shadow': ('psycopg', 'requests', 'urllib3', 'yaml', 'zstandard'),
'keycheck': ('psycopg', 'requests', 'yaml'),
'dashboard': ('pandas', 'plotly', 'psycopg', 'streamlit', 'yaml'),
'keycheck-provider': ('boto3', 'botocore', 'psycopg', 'requests', 'yaml'),
'janitor': ('yaml',),
'result-ingester': ('psycopg', 'yaml'),
'jsonl-projector': ('psycopg', 'yaml'),
'worker-api': ('psycopg', 'requests', 'starlette', 'urllib3', 'uvicorn', 'yaml', 'zstandard'),
}
class ChildRuntimeError(RuntimeError):
pass
ENV = {
'instance_file': 'TRUF_SUPERVISOR_INSTANCE_FILE',
'instance_id': 'TRUF_SUPERVISOR_INSTANCE_ID',
'token': 'TRUF_SUPERVISOR_TOKEN',
'config_sha256': 'TRUF_SUPERVISOR_CONFIG_SHA256',
'supervisor_sha256': 'TRUF_SUPERVISOR_SHA256',
'code_manifest_sha256': 'TRUF_SUPERVISOR_CODE_MANIFEST_SHA256',
'dsn_sha256': 'TRUF_SUPERVISOR_DSN_SHA256',
'kind': 'TRUF_SUPERVISOR_CHILD_KIND',
}
def _canonical(path):
return os.path.normcase(os.path.realpath(os.path.abspath(os.fspath(path))))
def _is_reparse_point(path):
details = os.lstat(path)
if stat.S_ISLNK(details.st_mode):
return True
attributes = getattr(details, 'st_file_attributes', 0)
reparse_attribute = getattr(stat, 'FILE_ATTRIBUTE_REPARSE_POINT', 0)
return bool(attributes & reparse_attribute) or getattr(os.path, 'isjunction', lambda _path: False)(path)
def _contained(path, roots):
for root in roots:
try:
if path != root and os.path.commonpath((root, path)) == root:
return True
except ValueError:
continue
return False
def _validated_site_directory(path, roots):
if not path or not os.path.isdir(path):
return ''
candidate = _canonical(path)
trusted_roots = tuple(_canonical(root) for root in roots if root)
if os.path.basename(candidate).lower() not in ('site-packages', 'dist-packages'):
raise RuntimeError(f'interpreter dependency path is not a site-packages directory: {candidate}')
if not _contained(candidate, trusted_roots):
raise RuntimeError(f'interpreter dependency path escapes its trusted root: {candidate}')
return candidate
def _append_site_directories(paths, roots):
existing = {_canonical(path) for path in sys.path if path}
for path in paths:
candidate = _validated_site_directory(path, roots)
if candidate and candidate not in existing:
# Direct insertion intentionally does not evaluate .pth hook lines.
sys.path.append(candidate)
existing.add(candidate)
def _venv_configuration():
# Preserve a venv's bin/python symlink location while locating pyvenv.cfg.
executable_dir = os.path.dirname(os.path.normcase(os.path.abspath(sys.executable)))
roots = [executable_dir]
if os.path.basename(executable_dir).lower() in ('bin', 'scripts'):
roots.insert(0, os.path.dirname(executable_dir))
for root in roots:
config_path = os.path.join(root, 'pyvenv.cfg')
if not os.path.isfile(config_path):
continue
details = os.stat(config_path, follow_symlinks=False)
if not stat.S_ISREG(details.st_mode) or details.st_size > MAX_PYVENV_BYTES:
raise RuntimeError('interpreter pyvenv.cfg is not a bounded regular file')
with open(config_path, 'rb') as handle:
payload = handle.read(MAX_PYVENV_BYTES + 1)
if len(payload) > MAX_PYVENV_BYTES:
raise RuntimeError('interpreter pyvenv.cfg exceeds its byte bound')
include_system = False
for raw_line in payload.decode('utf-8', errors='strict').splitlines():
key, separator, value = raw_line.partition('=')
if separator and key.strip().lower() == 'include-system-site-packages':
include_system = value.strip().lower() in ('1', 'true', 'yes')
return _canonical(root), include_system
return '', True
def _venv_site_directories(root):
if os.name == 'nt':
return [os.path.join(root, 'Lib', 'site-packages')]
version = f'python{sys.version_info.major}.{sys.version_info.minor}'
return [
os.path.join(root, library, version, name)
for library in ('lib', 'lib64')
for name in ('site-packages', 'dist-packages')
]
def _system_site_directories():
import sysconfig
roots = tuple(dict.fromkeys((_canonical(sys.base_prefix), _canonical(sys.base_exec_prefix))))
paths = sysconfig.get_paths(vars={
'base': sys.base_prefix,
'platbase': sys.base_exec_prefix,
})
return [paths.get('purelib'), paths.get('platlib')], roots
def _user_site_directories():
if os.name == 'nt':
try:
import ctypes
appdata = ctypes.create_unicode_buffer(32768)
if ctypes.windll.shell32.SHGetFolderPathW(None, 0x001A, None, 0, appdata) != 0:
return [], ()
root = _canonical(os.path.join(appdata.value, 'Python'))
version = f'Python{sys.version_info.major}{sys.version_info.minor}'
return [os.path.join(root, version, 'site-packages')], (root,)
except (AttributeError, OSError, ValueError):
return [], ()
try:
import pwd
home = _canonical(pwd.getpwuid(os.getuid()).pw_dir)
except (ImportError, KeyError, OSError):
return [], ()
version = f'python{sys.version_info.major}.{sys.version_info.minor}'
if sys.platform == 'darwin':
root = _canonical(os.path.join(home, 'Library', 'Python', f'{sys.version_info.major}.{sys.version_info.minor}'))
return [os.path.join(root, 'lib', 'python', 'site-packages')], (root,)
root = _canonical(os.path.join(home, '.local'))
return [
os.path.join(root, 'lib', version, 'site-packages'),
os.path.join(root, 'lib', version, 'dist-packages'),
], (root,)
def _missing_dependencies(kind):
import importlib.util
return [name for name in REQUIRED_DEPENDENCIES[kind] if importlib.util.find_spec(name) is None]
def _enable_dependency_paths(kind):
venv_root, include_system = _venv_configuration()
if venv_root:
_append_site_directories(_venv_site_directories(venv_root), (venv_root,))
if include_system:
system_paths, system_roots = _system_site_directories()
_append_site_directories(system_paths, system_roots)
if _missing_dependencies(kind):
user_paths, user_roots = _user_site_directories()
_append_site_directories(user_paths, user_roots)
missing = _missing_dependencies(kind)
if missing:
raise RuntimeError('required authenticated child dependencies are unavailable: ' + ', '.join(missing))
def _sha256_file(path):
digest = hashlib.sha256()
with open(path, 'rb') as handle:
while True:
block = handle.read(1024 * 1024)
if not block:
return digest.hexdigest()
digest.update(block)
def _read_object(path):
details = os.stat(path, follow_symlinks=False)
if not stat.S_ISREG(details.st_mode) or details.st_size <= 0 or details.st_size > MAX_METADATA_BYTES:
raise RuntimeError('supervisor metadata is not a bounded regular file')
with open(path, 'rb') as handle:
payload = handle.read(MAX_METADATA_BYTES + 1)
if len(payload) > MAX_METADATA_BYTES:
raise RuntimeError('supervisor metadata exceeds its byte bound')
value = json.loads(payload.decode('utf-8'))
if not isinstance(value, dict):
raise RuntimeError('supervisor metadata root is invalid')
return value
def _manifest_digest(manifest):
payload = json.dumps(manifest, ensure_ascii=True, sort_keys=True, separators=(',', ':')).encode('utf-8')
return hashlib.sha256(payload).hexdigest()
def _application_code_files(root):
names = set()
def raise_walk_error(exc):
raise RuntimeError(f'unable to inspect the application root: {exc}') from exc
for current, directories, files in os.walk(root, followlinks=False, onerror=raise_walk_error):
for name in directories:
candidate = os.path.join(current, name)
if _is_reparse_point(candidate):
relative = os.path.relpath(candidate, root).replace(os.sep, '/')
raise RuntimeError(f'application directory reparse point is forbidden: {relative}')
relative_current = os.path.relpath(current, root)
in_cache = any(part.lower() == '__pycache__' for part in relative_current.split(os.sep))
suffixes = ('.pyc',) if in_cache else APPLICATION_IMPORT_SUFFIXES
for name in files:
source_path = os.path.abspath(os.path.join(current, name))
if _is_reparse_point(source_path):
relative = os.path.relpath(source_path, root).replace(os.sep, '/')
raise RuntimeError(f'application file reparse point is forbidden: {relative}')
if not name.lower().endswith(suffixes):
continue
path = _canonical(source_path)
try:
contained = os.path.commonpath((root, path)) == root
except ValueError:
contained = False
if not contained:
raise RuntimeError('application Python authority escapes its root')
names.add(os.path.relpath(source_path, root).replace(os.sep, '/'))
return names
def _reject_cached_bytecode(root):
def raise_walk_error(exc):
raise RuntimeError(f'unable to inspect the application root: {exc}') from exc
try:
root_details = os.lstat(root)
except OSError as exc:
raise RuntimeError(f'application root is unavailable: {root}') from exc
if _is_reparse_point(root):
raise RuntimeError(f'application root reparse point is forbidden: {root}')
if not stat.S_ISDIR(root_details.st_mode):
raise RuntimeError(f'application root is not a directory: {root}')
for current, directories, files in os.walk(root, followlinks=False, onerror=raise_walk_error):
for name in directories:
candidate = os.path.join(current, name)
if _is_reparse_point(candidate):
relative = os.path.relpath(candidate, root).replace(os.sep, '/')
if name.lower() == '__pycache__':
raise RuntimeError(f'application __pycache__ link is forbidden: {relative}')
raise RuntimeError(f'application directory reparse point is forbidden: {relative}')
relative_current = os.path.relpath(current, root)
in_cache = any(part.lower() == '__pycache__' for part in relative_current.split(os.sep))
for name in files:
candidate = os.path.join(current, name)
relative = os.path.relpath(candidate, root).replace(os.sep, '/')
if _is_reparse_point(candidate):
raise RuntimeError(f'application file reparse point is forbidden: {relative}')
if in_cache and name.lower().endswith('.pyc'):
raise RuntimeError(f'application __pycache__ bytecode is forbidden: {relative}')
def _verify_manifest(metadata, inherited):
manifest = metadata.get('code_manifest')
if not isinstance(manifest, dict) or manifest.get('schema') != MANIFEST_SCHEMA:
raise RuntimeError('unsupported child code manifest')
expected_digest = str(metadata.get('code_manifest_sha256') or '')
if not hmac.compare_digest(_manifest_digest(manifest), expected_digest):
raise RuntimeError('child code manifest digest mismatch')
if not hmac.compare_digest(expected_digest, inherited['code_manifest_sha256']):
raise RuntimeError('inherited child code manifest mismatch')
root_value = manifest.get('root') or ''
files = manifest.get('files')
executables = manifest.get('executables')
assets = manifest.get('assets')
if not root_value or not isinstance(files, dict) or not isinstance(executables, dict) or not isinstance(assets, dict):
raise RuntimeError('child code manifest is incomplete')
raw_root = os.path.abspath(os.fspath(root_value))
_reject_cached_bytecode(raw_root)
root = _canonical(raw_root)
manifested_code = set()
for name, value in files.items():
if not isinstance(value, dict):
raise RuntimeError('child code manifest file entry is invalid')
expected_path = _canonical(os.path.join(root, *str(name).split('/')))
path = _canonical(value.get('path') or '')
if path != expected_path or not hmac.compare_digest(_sha256_file(path), str(value.get('sha256') or '')):
raise RuntimeError(f'child code authority drifted: {name}')
try:
contained = os.path.commonpath((root, path)) == root
except ValueError:
contained = False
if contained and str(name).lower().endswith(APPLICATION_IMPORT_SUFFIXES):
manifested_code.add(str(name).replace('\\', '/'))
current_code = _application_code_files(root)
if current_code != manifested_code:
added = sorted(current_code - manifested_code)
removed = sorted(manifested_code - current_code)
detail = added[0] if added else removed[0] if removed else 'unknown'
raise RuntimeError(f'application code authority file set drifted: {detail}')
for group_name, values in (('executable', executables), ('asset', assets)):
for name, value in values.items():
if not isinstance(value, dict):
raise RuntimeError(f'child {group_name} authority entry is invalid')
path = _canonical(value.get('path') or '')
if not os.path.isabs(path) or not hmac.compare_digest(_sha256_file(path), str(value.get('sha256') or '')):
raise RuntimeError(f'child {group_name} authority drifted: {name}')
return root
def _handshake(metadata):
control = metadata.get('control') or {}
request = {
'schema': CONTROL_SCHEMA,
'instance_id': metadata['instance_id'],
'token': metadata['token'],
'action': 'handshake',
}
encoded = json.dumps(request, ensure_ascii=True, separators=(',', ':')).encode('utf-8') + b'\n'
chunks = []
total = 0
with socket.create_connection((control.get('host'), int(control.get('port') or 0)), timeout=3) as client:
client.settimeout(3)
client.sendall(encoded)
client.shutdown(socket.SHUT_WR)
while True:
chunk = client.recv(65536)
if not chunk:
break
total += len(chunk)
if total > MAX_HANDSHAKE_BYTES:
raise RuntimeError('supervisor handshake exceeds its byte bound')
chunks.append(chunk)
response = json.loads(b''.join(chunks).decode('utf-8'))
if (
not isinstance(response, dict)
or response.get('schema') != CONTROL_SCHEMA
or response.get('instance_id') != metadata['instance_id']
or response.get('ok') is not True
or not isinstance(response.get('result'), dict)
):
raise RuntimeError('authenticated supervisor handshake failed')
return response['result']
def _authenticate(kind):
inherited = {name: str(os.getenv(variable) or '') for name, variable in ENV.items()}
if not all(inherited.values()):
raise RuntimeError('direct mutation is retired; use an authenticated active supervisor command')
if inherited['kind'] != kind:
raise RuntimeError('supervised child kind does not match the bootstrap entrypoint')
instance_file = _canonical(inherited['instance_file'])
metadata = _read_object(instance_file)
if metadata.get('schema') != 2 or _canonical(metadata.get('instance_file') or '') != instance_file:
raise RuntimeError('supervisor child instance metadata is invalid')
for key in ('instance_id', 'token', 'config_sha256', 'supervisor_sha256', 'code_manifest_sha256'):
if not hmac.compare_digest(str(metadata.get(key) or ''), inherited[key]):
raise RuntimeError(f'supervisor child {key} authority mismatch')
if str(metadata.get('activation_state') or '').upper() != 'ACTIVE':
raise RuntimeError('supervisor is not ACTIVE; child launch is refused')
if not hmac.compare_digest(_sha256_file(metadata['config_path']), inherited['config_sha256']):
raise RuntimeError('supervisor config authority drifted')
if not hmac.compare_digest(_sha256_file(metadata['supervisor_path']), inherited['supervisor_sha256']):
raise RuntimeError('supervisor script authority drifted')
root = _verify_manifest(metadata, inherited)
dsn = str(os.getenv('TRUF_MANAGED_POSTGRES_DSN') or '')
if kind == 'janitor':
if dsn or os.getenv('SCANNER_DB_URL') or os.getenv('DATABASE_URL'):
raise RuntimeError('janitor child must not receive database mutation capability')
else:
dsn_digest = hashlib.sha256(dsn.encode('utf-8')).hexdigest() if dsn else ''
if not dsn or not hmac.compare_digest(dsn_digest, inherited['dsn_sha256']):
raise RuntimeError('managed PostgreSQL DSN authority mismatch')
for variable in ('SCANNER_DB_URL', 'DATABASE_URL'):
if not hmac.compare_digest(str(os.getenv(variable) or ''), dsn):
raise RuntimeError(f'{variable} does not match managed PostgreSQL authority')
handshake = _handshake(metadata)
if handshake.get('activation_state') != 'ACTIVE' or handshake.get('instance_id') != metadata['instance_id']:
raise RuntimeError('supervisor handshake did not confirm ACTIVE authority')
for key in ('config_sha256', 'supervisor_sha256', 'code_manifest_sha256'):
if not hmac.compare_digest(str(handshake.get(key) or ''), inherited[key]):
raise RuntimeError(f'supervisor handshake {key} mismatch')
if not hmac.compare_digest(str(handshake.get('canonical_dsn_sha256') or ''), inherited['dsn_sha256']):
raise RuntimeError('supervisor handshake PostgreSQL authority mismatch')
return root, metadata
def main():
if not sys.flags.isolated or not sys.flags.no_site or not sys.flags.dont_write_bytecode:
raise RuntimeError('supervised child bootstrap requires isolated no-site bytecode-free startup (-I -S -B)')
if len(sys.argv) < 2:
raise SystemExit('supervised child bootstrap kind is required')
kind = str(sys.argv[1]).strip().lower()
root, metadata = _authenticate(kind)
_enable_dependency_paths(kind)
arguments = list(sys.argv[2:])
if kind != 'keycheck-provider' and arguments[:1] == ['--']:
arguments.pop(0)
if kind in ('scanner', 'discovery-producer'):
entrypoint = os.path.join(root, 'console_runner.py')
elif kind == 'docker-shadow':
entrypoint = os.path.join(root, 'docker_shadow.py')
elif kind == 'keycheck':
entrypoint = os.path.join(root, 'keycheck_runner.py')
elif kind == 'dashboard':
entrypoint = os.path.join(root, 'dashboard.py')
elif kind == 'janitor':
entrypoint = os.path.join(root, 'janitor.py')
elif kind == 'result-ingester':
entrypoint = os.path.join(root, 'result_ingester.py')
elif kind == 'jsonl-projector':
entrypoint = os.path.join(root, 'jsonl_projector.py')
elif kind == 'worker-api':
entrypoint = os.path.join(root, 'worker_api.py')
elif kind == 'keycheck-provider':
if not arguments:
raise RuntimeError('keycheck provider bootstrap entrypoint is required')
relative = arguments.pop(0).replace('\\', '/')
if not arguments or arguments.pop(0) != '--':
raise RuntimeError('keycheck provider bootstrap separator is required')
if '--' in arguments:
raise RuntimeError('duplicate keycheck provider bootstrap separator')
entrypoint = _canonical(os.path.join(root, *relative.split('/')))
provider_root = _canonical(os.path.join(root, 'keycheckers'))
try:
allowed = os.path.commonpath((provider_root, entrypoint)) == provider_root
except ValueError:
allowed = False
if not allowed or not relative.lower().endswith('.py'):
raise RuntimeError('keycheck provider bootstrap entrypoint is outside authority')
else:
raise RuntimeError('unsupported supervised child bootstrap kind')
entrypoint = _canonical(entrypoint)
files = (metadata.get('code_manifest') or {}).get('files') or {}
if not any(_canonical(value.get('path') or '') == entrypoint for value in files.values() if isinstance(value, dict)):
raise RuntimeError('child entrypoint is absent from immutable authority')
sys.path.insert(0, root)
try:
if kind == 'dashboard':
sys.argv = ['streamlit', 'run', entrypoint, *arguments]
runpy.run_module('streamlit', run_name='__main__', alter_sys=True)
else:
sys.argv = [entrypoint, *arguments]
runpy.run_path(entrypoint, run_name='__main__')
except Exception as exc:
raise ChildRuntimeError(str(exc)) from exc
if __name__ == '__main__':
try:
main()
except ChildRuntimeError as exc:
raise SystemExit(f'supervised child runtime failed: {exc}') from exc
except Exception as exc:
raise SystemExit(f'supervised child bootstrap rejected launch: {exc}') from exc