Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
3.4 KiB
Phase 4 — Harden via harden-base.sh
Goal: run
_primitives/harden-base.shon the VM, over SSH, idempotently. Verify criterion: script exited 0;systemctl is-activereturnsactiveforssh,ufw,fail2ban,auditd.
4.a — Ship the script
The script lives on the workstation; copy to the VM and run with sudo:
scp _primitives/harden-base.sh "${ADMIN_USER}@${VM_IP}:/tmp/harden-base.sh"
ssh "${ADMIN_USER}@${VM_IP}" "sudo bash /tmp/harden-base.sh \
--admin-user ${ADMIN_USER} \
--ssh-port ${SSH_PORT} \
$(for p in ${APP_PORTS[@]}; do echo --allow-port $p; done)"
Why not curl … | bash? Because that depends on a hosted URL AND a
trusted TLS cert. scp the file you already audited locally. Lower
surface area, reproducible.
The script is idempotent — safe to re-run. Re-runs converge the VM to the declared state; missing directives get rewritten, extra ones are left alone.
4.b — Stream logs
harden-base.sh logs to stderr with timestamps. Capture to
<run-dir>/harden.log:
ssh "${ADMIN_USER}@${VM_IP}" "sudo bash /tmp/harden-base.sh …" 2> >(tee <run-dir>/harden.log >&2)
If the script exits non-zero: STOP. Do NOT proceed to Phase 5. Surface
the last 30 lines of <run-dir>/harden.log + ask the user to choose:
- (A) Fix locally + re-ship — edit the primitive (if bug is there) or
adjust flags. Commit the fix under
checkpoint:before retry. - (B) Patch the VM manually — user logs in, fixes, we re-run the script to ensure idempotency.
- (C) Destroy + reprovision — when remediation risk > cost of a fresh VM (2 min on Hetzner).
4.c — Post-hardening live-check
After exit 0, SSH back in and confirm:
ssh "${ADMIN_USER}@${VM_IP}" "
set -e
systemctl is-active ssh ufw fail2ban auditd unattended-upgrades.service 2>/dev/null || true
ufw status | head -20
sudo auditctl -l | head -10
"
All four services must be active. auditctl -l must show the baseline
rules (sshd_config, sudoers, identity, module, time). Record the output
in <run-dir>/post-harden.txt.
4.d — AskUserQuestion (ready to verify?)
One AskUserQuestion:
Hardening applied. Four services active; auditd rules loaded.
- Run verification gate (Phase 5).
- Apply one more pass (typo in
APP_PORTS, extra user, etc. — loops 4.a with a delta). - Pause (leave the VM in current state).
4.e — Verify criterion
harden-base.shexited 0.ssh / ufw / fail2ban / auditdallactive.<run-dir>/harden.log+<run-dir>/post-harden.txtcaptured.
Emit:
Phase 4 done: 4/4 services active. Log: <run-dir>/harden.log.
Proceed to Phase 5 (hard gate).
4.f — Non-obvious failure modes
systemctl reload sshfails becausesshd -trejects the drop-in. Usually a customSSH_PORTcollides with ufw still configured for 22. Fix: ensure ufw rule + sshd Port match BEFORE reload.harden-base.shwrites both in one pass, but if an out-of-band edit happened between runs, you get this.- fail2ban service flaps. Usually a systemd-journal backend mismatch
on very old Debian. Verify
backend = systemdin/etc/fail2ban/jail.local(script sets this). - auditd refuses
-e 2. Means an earlier rules load is still mastered;augenrules --loadforces reload. Already in the script.
None of these require a Level-2 escalation — all three have known fixes.