Skip to content

v0.3.0 — community readiness: operator surface, data-root, parity, fixes

Choose a tag to compare

@gl0bal01 gl0bal01 released this 15 May 10:36
· 7 commits to master since this release

Full community-readiness release. All Phases 2–6 of the readiness plan land together per the v0.3.0 ADR (atomic Phase 2 + 2.5 constraint; Phases 3–6 within the same release).

Upgrading from v0.2.x? See docs/migration.md. Existing operators on systemd must mv repos to /var/lib/ctfd-warboard/repos/ (or accept the auto-WARN with mv instructions) and re-run make service-install.

Operator surface (Phase 2)

  • Makefile at repo root with 17 targets — single entrypoint for install / check / bot / service-* / migrate-data-root.
  • .env.example + scripts/ctfd-bot.env.example documenting all bot env vars (no real secrets).
  • docs/deployment.md — full VPS setup: dedicated user, FHS layout, env file, systemd install, journald, SSH key, backups, log rotation, secret rotation, mixed bot+CLI access.

Data root + hardened systemd (Phase 2.5, atomic)

  • packages/core/src/paths.ts — shared resolver: dataRoot(), repoPathFor(), lockPathFor(), assertDataRootWritable(). Honors CTFD_WARBOARD_HOME; absolute-path validation; mkdir -p mode 0700; path-traversal rejection via allowlist regex; boot-time writability check (FATAL + exit 1 before Discord connect).
  • Bot + CLI share data root via CTFD_WARBOARD_HOME. Bot CONFIG_DIR derived from dataRoot(). Bot ctf-start.ts and ctf-join.ts use repoPathFor(ctfName) instead of cwd-based resolve(ctfName).
  • ConfigManager lazy-once meta.repoPath migration — rewrites persisted CTFMeta entries whose repoPath falls outside dataRoot(); WARN log with old→new + mv instruction (emitted only after rename succeeds); idempotent.
  • make migrate-data-root — triggers migration without starting the bot.
  • Hardened systemd unit (scripts/ctfd-bot.service) — User=ctfd-warboard, EnvironmentFile=, Environment=CTFD_WARBOARD_HOME=/var/lib/ctfd-warboard, ProtectSystem=strict, ReadWritePaths=/var/lib/ctfd-warboard, NoNewPrivileges=true, PrivateTmp=true, ProtectHome=true. No inline secrets.
  • make service-install code-level gate — refuses to install the strict unit if packages/core/src/paths.ts is absent (filesystem stat).
  • Cross-process lock unification — bot and CLI both resolve lock paths through lockPathFor(); concurrent ops on shared CTFD_WARBOARD_HOME serialize correctly.

Bot ↔ CLI parity (Phase 3)

  • downloadChallengeFilesForCTF in @ctfd-warboard/core — shared download orchestration helper.
  • Bot /ctf start now downloads CTFd challenge files (identical layout to ctfd init), with Discord interaction editReply progress edits every 10 challenges. Downloads run inside the per-ctfName FileLock, before the git transaction.
  • CLI init.ts now also uses the shared helper — single source of truth.

Functional fixes (Phase 4)

  • CLI ctfd claim uses resolveChallenge for category/challenge resolution (web/sql-injection now resolves correctly to category web).
  • CLI --version reads dynamically from packages/cli/package.json.
  • resolveAuthAndClient(meta, opts?) in @ctfd-warboard/core — shared auth helper. Priority: meta.tokenmeta.sessionCookie (verified; 401 falls through) → username + password. Bot /ctf start, bot helpers.ts, CLI solve, CLI init all migrated. loginWithCredentials direct callsites in packages/bot and packages/cli removed.
  • CLI ctfd solve now supports all auth types (was token-only).
  • helpers.ts error rewrap narrowed — only emits "No credentials found" when no auth method exists; otherwise re-throws original error with cause (DNS/TLS/SSRF surface correctly).

CI + release docs (Phase 5)

  • CI Bun version pinned to 1.3.13 in .github/workflows/ci.yml; .tool-versions added for local reproducibility.
  • CI runs make check (single entrypoint matches local).
  • docs/release.md — release checklist with concrete shell commands.

README (Phase 6)

  • New sections: "5-minute local bot smoke test", "Production install on Ubuntu with systemd", "How secrets are stored", "Known limitations", "Troubleshooting". Cross-links to docs/deployment.md, docs/migration.md, docs/release.md.

Verification

  • 239 tests pass / 0 fail across 28 files.
  • bun run lint, bun run typecheck, bun audit --audit-level=high → exit 0.
  • systemd-analyze verify scripts/ctfd-bot.service → exit 0.
  • Acceptance greps: resolve(ctfName)\|resolve(repoName) in packages/bot/src → empty; loginWithCredentials in packages/bot packages/cli → empty.

Known limitations

  • VM smoke test under the strict systemd unit is deferred — operators are encouraged to exercise the hardened unit before mass adoption and append any required additional ReadWritePaths= entries.
  • Several NIT/MEDIUM follow-ups from the v0.3.0 code review (memoize mkdirSync, narrow auth-resolver re-login to also cover 403, ctf-start scaffold-before-lock, etc.) are filed as future work.

Full Changelog: v0.2.1...v0.3.0