52 lines
2.3 KiB
Python
52 lines
2.3 KiB
Python
"""Offline reset guards; no Proxmox commands or VM mutation."""
|
|||
|
|
import importlib.util
|
||
|
|
import pathlib
|
||
|
|
import tempfile
|
||
|
|
import hashlib
|
||
|
|
|
||
|
|
spec = importlib.util.spec_from_file_location('reset', pathlib.Path(__file__).parent / 'deploy/reset-execution.py')
|
||
|
|
reset = importlib.util.module_from_spec(spec)
|
||
|
|
spec.loader.exec_module(reset)
|
||
|
|
config = ('name: decoy-execution\nscsi0: local-lvm:vm-223-disk-0,size=12G\n'
|
||
|
|
'args: -netdev user,id=decoy,restrict=on -object filter-dump,file=/var/lib/vz/honeypot/execution.pcap\n')
|
||
|
|
reset.valid_config(config)
|
||
|
|
for bad in (config.replace('decoy-execution', 'onionatlas'), config.replace('restrict=on', 'restrict=off'), config + 'net0: virtio,bridge=vmbr0\n'):
|
||
|
|
try:
|
||
|
|
reset.valid_config(bad)
|
||
|
|
raise AssertionError('unsafe config accepted')
|
||
|
|
except RuntimeError:
|
||
|
|
pass
|
||
|
|
with tempfile.TemporaryDirectory() as temporary:
|
||
|
|
reset.ROOT = pathlib.Path(temporary)
|
||
|
|
reset.ARCHIVES = reset.ROOT / 'archives'
|
||
|
|
reset.ARCHIVES.mkdir()
|
||
|
|
reset.RESERVE = 0
|
||
|
|
reset.bounds = lambda min_free=0: None
|
||
|
|
file = reset.ARCHIVES / 'evidence'
|
||
|
|
reset.write_file(file, b'inert')
|
||
|
|
try:
|
||
|
|
reset.write_file(file, b'overwrite')
|
||
|
|
raise AssertionError('evidence overwritten')
|
||
|
|
except FileExistsError:
|
||
|
|
pass
|
||
|
|
assert reset.digest(file) == hashlib.sha256(b'inert').hexdigest()
|
||
|
|
print('PASS: reset identity/isolation guards, exclusive evidence writes and hashes')
|
||
|
|
|
||
|
|
# Reset restores only the public CA authorization; idempotent and valid newlines.
|
||
|
|
with tempfile.TemporaryDirectory() as temporary:
|
||
|
|
reset.ROOT = pathlib.Path(temporary)
|
||
|
|
line = 'cert-authority,principals="decoy-admin",restrict,pty ssh-ed25519 AAAATEST public-ca-test'
|
||
|
|
(reset.ROOT / 'admin-ca.authorized').write_text(line + '\n')
|
||
|
|
target = reset.ROOT / 'authorized_keys'
|
||
|
|
target.write_text('existing-public-key\n')
|
||
|
|
def fake_qm(*args, **kwargs):
|
||
|
|
assert args[:3] == ('guest', 'exec', '223')
|
||
|
|
script = args[-1].replace('/root/.ssh/authorized_keys', str(target))
|
||
|
|
exec(script, {})
|
||
|
|
return '{"exited":1,"exitcode":0}'
|
||
|
|
reset.qm = fake_qm
|
||
|
|
reset.install_admin_ca()
|
||
|
|
reset.install_admin_ca()
|
||
|
|
assert target.read_text().splitlines() == ['existing-public-key', line]
|
||
|
|
assert target.stat().st_mode & 0o777 == 0o600
|
||
|
|
print('PASS: public-only certificate authorization survives reset without duplicate keys')
|