feat(engine): de-slop commons, harden security, add targeted compose and env bridge
- Purge misplaced RFCs, scratch tokens, and node-proprietary assets - Decouple remote provisioning to ci/scripts/init-node.py - Add targeted composition orchestration in actions/compose.py - Add host-side Xray stale socket cleanup in /dev/shm - Add actions/env.py for shell exports and .env synchronization - Harden UFW, backup retention, host tempfiles, and notify dispatcher - Add pyproject.toml and Makefile with 78 passing unit tests
This commit is contained in:
66 files changed
+686
-1657
No files matched your search
@@ -0,0 +1,121 @@
|
||||
"""Pinned, non-destructive checkout enrollment as the node administrator."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import pwd
|
||||
import subprocess
|
||||
|
||||
from engine.identity import read_env
|
||||
from . import ENROLLMENT_INTERFACE
|
||||
from .state import ProvisionError, safe_path
|
||||
|
||||
|
||||
def as_adam(args, cwd=None):
|
||||
environment = dict(os.environ, GIT_TERMINAL_PROMPT='0',
|
||||
GIT_SSH_COMMAND='ssh -o BatchMode=yes -o StrictHostKeyChecking=yes',
|
||||
LC_ALL='C')
|
||||
result = subprocess.run(['runuser', '-u', 'adam', '--', *args], cwd=cwd,
|
||||
env=environment, text=True, capture_output=True, timeout=300)
|
||||
if result.returncode:
|
||||
# Git/hook stderr may contain credential files or remote URL credentials.
|
||||
raise ProvisionError('repository operation failed; check administrator Git access and the pinned checkout')
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
def verify_checkout_setup(destination, account):
|
||||
if as_adam(['git', 'config', '--get', 'core.hooksPath'], destination) != 'commons/githooks':
|
||||
raise ProvisionError('checkout hook configuration is missing or incompatible')
|
||||
home = safe_path(account.pw_dir)
|
||||
bashrc = safe_path(home / '.bashrc')
|
||||
entry = 'export PATH="' + str(destination / 'commons') + ':$PATH"'
|
||||
if not bashrc.is_file() or bashrc.read_text().splitlines().count(entry) != 1:
|
||||
raise ProvisionError('checkout PATH setup is missing or duplicated; reconcile init.sh before retrying')
|
||||
vim = home / '.vimrc'
|
||||
if not vim.is_symlink() or vim.resolve() != (destination / 'commons/etc/.vimrc').resolve():
|
||||
raise ProvisionError('checkout editor link is missing or incompatible')
|
||||
|
||||
|
||||
def reconcile_repository(spec, state, save, srv=Path('/srv')):
|
||||
repository = spec.repository
|
||||
destination = safe_path(Path(srv) / repository.name)
|
||||
staging = safe_path(Path(srv) / ('.apex-clone-' + repository.name))
|
||||
expected = {'name': repository.name, 'url': repository.url, 'ref': repository.ref}
|
||||
account = pwd.getpwnam('adam')
|
||||
record = state.setdefault('repository', {})
|
||||
if record and record.get('request') != expected:
|
||||
raise ProvisionError('repository enrollment conflicts with its recorded request')
|
||||
if not record:
|
||||
if destination.exists() or staging.exists():
|
||||
raise ProvisionError('unrecorded repository path exists; explicit adoption is required')
|
||||
record.update(request=expected, clone_intent=True)
|
||||
save()
|
||||
if not destination.exists():
|
||||
if staging.exists():
|
||||
# An interrupted clone may be incomplete: never erase or guess its state.
|
||||
raise ProvisionError('an interrupted clone remains; inspect the staging checkout before retrying')
|
||||
staging.mkdir(mode=0o755)
|
||||
os.chown(staging, account.pw_uid, account.pw_gid)
|
||||
as_adam(['git', 'clone', '--no-checkout', '--', repository.url, str(staging)])
|
||||
os.rename(staging, destination)
|
||||
safe_path(destination / '.git')
|
||||
origin = as_adam(['git', 'remote', 'get-url', 'origin'], destination)
|
||||
if origin != repository.url:
|
||||
raise ProvisionError('existing checkout has a different origin; it was preserved')
|
||||
if 'commit' not in record:
|
||||
reference = repository.ref or 'HEAD'
|
||||
if repository.ref:
|
||||
as_adam(['git', 'fetch', '--no-tags', 'origin', reference], destination)
|
||||
reference = 'FETCH_HEAD'
|
||||
commit = as_adam(['git', 'rev-parse', '--verify', reference + '^{commit}'], destination)
|
||||
record['commit'] = commit
|
||||
record['checkout_intent'] = True
|
||||
save()
|
||||
commit = record['commit']
|
||||
if record.get('checkout_intent'):
|
||||
# --no-checkout index intentionally looks dirty before the first checkout.
|
||||
if any(p.name != '.git' for p in destination.iterdir()):
|
||||
head = as_adam(['git', 'rev-parse', 'HEAD'], destination)
|
||||
dirty = as_adam(['git', 'status', '--porcelain'], destination)
|
||||
if head != commit or dirty:
|
||||
raise ProvisionError('interrupted checkout has unexpected contents; it was preserved')
|
||||
else:
|
||||
as_adam(['git', 'checkout', '--detach', commit], destination)
|
||||
record.pop('checkout_intent')
|
||||
save()
|
||||
if as_adam(['git', 'rev-parse', 'HEAD'], destination) != commit:
|
||||
raise ProvisionError('checkout revision changed; initialization will not reset it')
|
||||
if as_adam(['git', 'status', '--porcelain'], destination):
|
||||
raise ProvisionError('checkout contains local changes; initialization will not reset it')
|
||||
node_env = safe_path(destination / 'node.env')
|
||||
node_identity = read_env(str(node_env))
|
||||
if node_identity.get('APEX_NODE_FQDN') != spec.hostname:
|
||||
raise ProvisionError('repository node.env does not declare the requested hostname')
|
||||
if node_identity.get('APEX_ENROLLMENT_INTERFACE') != str(ENROLLMENT_INTERFACE):
|
||||
raise ProvisionError('node checkout enrollment interface is missing or unsupported; update its init.sh and node.env together')
|
||||
as_adam(['git', 'submodule', 'update', '--init', '--recursive'], destination)
|
||||
commons = safe_path(destination / 'commons')
|
||||
if not commons.is_dir():
|
||||
raise ProvisionError('node checkout does not contain its pinned commons submodule')
|
||||
commons_commit = as_adam(['git', 'rev-parse', 'HEAD'], commons)
|
||||
gitlink = as_adam(['git', 'ls-tree', 'HEAD', '--', 'commons'], destination).split()
|
||||
if gitlink != ['160000', 'commit', commons_commit, 'commons']:
|
||||
raise ProvisionError('commons is not the exact pinned Git submodule')
|
||||
if Path(as_adam(['git', 'rev-parse', '--show-toplevel'], commons)).resolve() != commons.resolve():
|
||||
raise ProvisionError('commons does not have its own Git worktree')
|
||||
if record.get('commons_commit', commons_commit) != commons_commit:
|
||||
raise ProvisionError('pinned commons revision changed unexpectedly')
|
||||
hook = safe_path(destination / 'init.sh')
|
||||
if not hook.is_file():
|
||||
raise ProvisionError('node repository is missing its checkout initializer')
|
||||
if not record.get('hook_complete'):
|
||||
as_adam(['bash', './init.sh'], destination)
|
||||
verify_checkout_setup(destination, account)
|
||||
record['hook_complete'] = True
|
||||
else:
|
||||
verify_checkout_setup(destination, account)
|
||||
if as_adam(['git', 'status', '--porcelain'], destination):
|
||||
raise ProvisionError('checkout initializer changed tracked files; inspect before resuming')
|
||||
record['commons_commit'] = commons_commit
|
||||
save()
|
||||
return {'path': str(destination), 'commit': commit, 'commons_commit': commons_commit}
|
||||
Reference in new issue
Block a user