Implements the unattended episode loop described in docs/deploy.md but not yet built. run_campaign.py boots a fresh VM per episode, drives the full phase schedule via the existing EpisodeRunner/VMLoadController stack, writes campaign.json atomically after each episode, and signals completion with campaign_done.marker. shipper.py watches data/episodes/ for done.marker files, tar+zstd-compresses each, and PUTs them to the receiver with exponential backoff on failure. Both support SIGTERM gracefully, finishing the current episode/scan before exiting. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
36 lines
909 B
Desktop File
36 lines
909 B
Desktop File
[Unit]
|
|
Description=CIS490 episode shipper
|
|
Documentation=https://maxgit.wg/spectral/CIS490
|
|
After=network-online.target cis490-orchestrator.service
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=cis490
|
|
Group=cis490
|
|
WorkingDirectory=/opt/cis490
|
|
ExecStart=/opt/cis490/.venv/bin/python tools/shipper.py \
|
|
--data-root /var/lib/cis490/data \
|
|
--receiver-url https://collector.wg \
|
|
--host-id lab-host-1 \
|
|
--ca-bundle /etc/cis490/certs/wg-ca.pem \
|
|
--client-cert /etc/cis490/certs/lab-host-1.pem \
|
|
--client-key /etc/cis490/certs/lab-host-1.key
|
|
Restart=on-failure
|
|
RestartSec=10
|
|
|
|
# Hardening
|
|
NoNewPrivileges=true
|
|
PrivateTmp=true
|
|
ProtectSystem=strict
|
|
ProtectHome=true
|
|
ReadWritePaths=/var/lib/cis490
|
|
ProtectKernelTunables=true
|
|
ProtectKernelModules=true
|
|
ProtectControlGroups=true
|
|
LockPersonality=true
|
|
RestrictRealtime=true
|
|
SystemCallArchitectures=native
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|