Repository navigation
Releases: Ragnar-Security/Ragnar-Lab-Playground
Release list
v1.0.0
The first public release. Earlier builds were never versioned; their
/auth/health did not report a version.
Added
- Apache-2.0 license,
NOTICE,SECURITY.md, and a secret-scanning
configuration. Site-specific values (domains, hosts, staff, the lab
catalog, branding) live only in untracked operator files, created from the
committed examples (.env.example,templates.example.yaml,
scripts/site.env.example,config/headscale-acl.example.json). - Admin-issued, single-use password reset links, with one live link per
student.SEED_ADMIN_ACCOUNTmakes the generic admin account optional. - Database-backed coordination tables for node-memory and VMID reservations,
the VMID high-water mark and the password-reset limiter
(app/coordination.py). - An
alert_outboxtable: deletion-failure and orphan-reaped alerts are
queued in the same commit as the state they report and delivered by the
expiry loop, with retries and backoff. - Failed-deploy guests that cannot be recorded during a database outage are
written to a fallback file underdata/and imported once the database is
back, so the expiry loop still removes them. - The expiry loop retires the record of a guest deleted by hand in Proxmox
once fresh inventory has confirmed it missing. - Jumpbox tooling that rebuilds the lab router:
jumpbox_provision.sh,
jumpbox_configure.sh(VLAN gateways, DHCP, optional Tailscale, SSH-key-only
login, monitoring, and an optional staff-only SSH filter) and
jumpbox_accounts.sh; seedocs/JUMPBOX.md. - Headscale pre-auth key rotation (
scripts/rotate_headscale_keys.sh) and the
term changeover procedure (scripts/term_changeover.sh). /auth/healthreportsversionand, for release images,revision.- Versioned release images on GHCR with build provenance and SBOM
attestations, and a deploy bundle on each GitHub Release
(docs/RELEASING.md).
Changed
- Images install exactly the packages pinned in
uv.lock, with hash
checking; gunicorn is 23.0.0. - The orphan reaper runs after the expiry pass and stops starting guests past
a per-sweep time and guest budget, so it cannot hold up expiry. Alert
delivery has its own per-pass budget. /extendand/destroyact on one deployment, chosen by
deployment_scope, instead of every deployment sharing a name.
Fixed
- An extension that committed while the expiry worker was processing the
same VM could be destroyed anyway. - The orphan reaper reported failures for guests that had already gone,
because Proxmox answers a missing guest with HTTP 500, not 404.
Security
- Logout revokes every copy of a session (
users.session_version). - Production refuses an admin password shorter than 16 characters while the
admin account is seeded. - MySQL is published on the loopback interface only.
Upgrade notes
For operators upgrading a deployment that runs a pre-release build. A host
that runs a checkout of the older repository this one replaced follows
"Migrating an existing checkout to this repository" in
docs/PRODUCTION_DEPLOYMENT.md first.
-
Back up the database first (
scripts/backup-database.sh) and record the
running commit or image as the rollback target. -
Run all six migrations before the new code starts. Each is idempotent
and only adds columns, an index or tables, so the old code keeps working
while they run. Skipping one is not safe:db.create_all()never adds
columns to an existing table, and the new code reads them on every request.for migration in migrate_koth_claim_mode.py migrate_add_session_version.py \ migrate_vm_deletion_retry.py migrate_add_password_reset_tokens.py \ migrate_add_coordination_tables.py migrate_add_alert_outbox.py; do docker compose -f docker-compose.prod.yml exec -T -w /app vm-automation \ python scripts/$migration done
If the running image does not contain a migration yet, copy it in for the
run; "Redeploy an Existing Production Host" in
docs/PRODUCTION_DEPLOYMENT.mdshows how. -
New optional environment variables. All have defaults; set them in
.envonly to change the default.ORPHAN_REAPER_MAX_PASS_SECONDS(default 120) and
ORPHAN_REAPER_MAX_PASS_GUESTS(default 10): per-sweep budget of the
orphan reaper.DISTRIBUTED_VM_LOCKS(default false): VM lifecycle locks through MySQL
GET_LOCK. Keep it false while running one gunicorn worker.UNTRACKED_SURVIVORS_FILE(defaultdata/untracked-survivors.jsonl):
where failed-deploy guests are recorded during a database outage. It must
stay on the persistentdata/mount.ALERT_DISPATCH_MAX_PASS_SECONDS(default 20) and
ALERT_DISPATCH_MAX_PASS_ALERTS(default 50): per-pass budget of alert
delivery.
-
Breaking:
POST /destroyandPOST /extendrequire
deployment_scope=individualordeployment_scope=group; a request
without it is refused. The bundled pages send it. A student whose browser
still has the old JavaScript gets an error from the Extend and Destroy
buttons until a hard refresh (Ctrl+Shift+R, or Cmd+Shift+R on macOS).
Scripts that call these endpoints must add the field. -
Still one gunicorn worker. Do not raise
workersingunicorn.conf.py:
the scheduler, the live scoreboard event bus, the reaper schedule and alert
delivery are still per-process. -
Rollback: the old code ignores the added columns and tables, so going
back to the previous build needs no database restore. The old code does not
deliver alerts still pending inalert_outbox, and does not read the
failed-deploy survivor files; see the rollback step in
docs/PRODUCTION_DEPLOYMENT.md.
Image: ghcr.io/ragnar-security/lab-playground:1.0.0 (sha256:c0484fae7c97d928c7a8498016cac1d3ce599fc8b7705dddf0729422c502d758), commit 0b394a1009444c3fa669f1e38fffcd826292c7f1
Run it with docker-compose.release.yml and LAB_PLAYGROUND_VERSION=1.0.0; see DEPLOY-FROM-RELEASE.md in the bundle.
Verify that this workflow built both from this tag and commit:
gh attestation verify oci://ghcr.io/ragnar-security/lab-playground:1.0.0 -R Ragnar-Security/Ragnar-Lab-Playground --signer-workflow Ragnar-Security/Ragnar-Lab-Playground/.github/workflows/release.yml --source-ref refs/tags/v1.0.0 --source-digest 0b394a1009444c3fa669f1e38fffcd826292c7f1
sha256sum -c SHA256SUMS
gh attestation verify lab-playground-1.0.0-deploy.tar.gz -R Ragnar-Security/Ragnar-Lab-Playground --signer-workflow Ragnar-Security/Ragnar-Lab-Playground/.github/workflows/release.yml --source-ref refs/tags/v1.0.0 --source-digest 0b394a1009444c3fa669f1e38fffcd826292c7f1