Skip to content

Releases: CyLabAcademy/cmgr

Release v3.1.0

Choose a tag to compare

@github-actions github-actions released this 20 Aug 04:23
dc20743

Changes

New Features

  • New seccomp.profile challenge option names a JSON profile sitting beside
    problem.md, replacing cmgr's embedded policy for that challenge's runtime
    containers. Build, artifact, and solver containers keep the embedded policy.
    Profiles are validated at load time and contribute to the challenge's source
    checksum, so editing one triggers a rebuild. A per-host overrides block does
    not inherit a top-level profile. Adds a containerOptions.seccomp column,
    migrated automatically on open; challenges selecting no profile are unaffected.

    • New examples/seccomp/: the embedded policy as a copyable default.json
      baseline, execstack.json and no-ptrace.json, a profile-diff.py tool that
      reports only a profile's semantic delta from the baseline, and a README on
      what the default policy already permits. examples/execstack/ is a worked
      challenge for the READ_IMPLIES_EXEC case.
  • Artifact archives from build containers are now validated on ingest instead of
    repacked verbatim: path traversal, absolute paths, symlinks, hardlinks, device
    nodes and duplicate entries are rejected, ownership and xattrs are stripped,
    and entry count, per-file and total decompressed size are bounded (including
    tar metadata records). Archives stage to a temp file and rename into place, so
    a failed build can no longer replace a good archive with a partial one. Limits
    are tunable via CMGR_MAX_ARTIFACT_FILES, CMGR_MAX_ARTIFACT_BYTES, and
    CMGR_MAX_ARTIFACT_FILE_BYTES. Ported from ArmyCyberInstitute/cmgr bdbf839.

Updates

Dependencies: dropped github.com/docker/cli in favor of an in-tree NanoCPU
parser, migrated gopkg.in/yaml.v2 to go.yaml.in/yaml/v3, and bumped
go-sqlite3, goldmark, and moby/moby/client.

Release v3.0.0

Choose a tag to compare

@github-actions github-actions released this 27 Jul 18:08
4a4a0eb

Changes

Breaking

  • Challenges that are not services no longer get instances. cmgr now derives a
    delivery_type for every challenge (service, artifact_only, or flag_only) from
    whether it publishes ports and which challenge type it uses. Only service challenges
    run instances: builds of artifact-only and flag-only challenges always report an empty
    instances list, and POST /builds/<id> (start instance) fails for them. Previously
    every build launched a placeholder container.

    • API consumers must branch on delivery_type. An empty instance list is only a
      deployment problem when delivery_type is service and instance_count is
      positive; on-demand builds (instance_count of -1) legitimately have zero
      instances between user sessions.
    • Placeholder instances left over from older versions are torn down on the next schema
      update or challenge rebuild.
    • cmgr test and cmgr playtest skip the start/stop steps for non-service challenges
      and run the solver directly against the build.
  • Docker image tags are now content-addressed. Tags changed from
    <challenge>:<build_id>-<host> to <challenge>:s<seed>-<checksum>-<host>, where the
    checksum covers the challenge source and flag format. Build IDs are local database
    handles and no longer appear in tags, so rebuilt content gets a new tag instead of
    mutating one in place (making challenge images safe to push to a registry). Anything
    that reconstructs image tags from build IDs must be updated. Existing images are
    retagged automatically by a one-time, resumable migration on first start.

  • Built-in challenge types now build on ubuntu:24.04 (was ubuntu:20.04). This
    affects remote-make, static-make, and the solver image. Existing challenges may
    need updating for OpenSSL 3.x, PEP 668 (pip now runs with
    --break-system-packages), and renamed distro packages.

New features

  • flag-only challenge type for challenges that are nothing but a submission prompt
    — no service, no downloads (knowledge checks, second flags exported by a sibling
    challenge). The build's only product is metadata.json; a Makefile is optional, and
    the SEED build argument allows per-build shuffling of option lists. Exempt from
    cmgr test --require-solve, since the flag is the answer. See
    examples/flag-only/.
  • POST /builds/<id>/check runs the automated solver against a non-service build
    without an instance, mirroring the existing instance check. Service builds are
    rejected. cmgr test --require-solve uses the same path.
  • cmgr update --prune-old untags the image generation each rebuild displaces from
    its rollback slot. Off by default, since another cmgr database on the same Docker
    daemon may reference those tags. Removal is refcount-guarded; the current and previous
    generations are always retained.
  • cmgr test --keep-images retains build images until the whole run finishes so
    challenges can share base layers — a large speedup when testing a directory of
    challenges. Used by CI.
  • Builds now report checksum and prev_checksum (the retained rollback generation)
    through the API, and images carry cmgr.managed / cmgr.challenge labels.
  • cmgr update prints a delivery-type summary, so a challenge that is unexpectedly
    artifact-only (a forgotten # PUBLISH) is visible before deployment. A challenge that
    publishes neither ports nor artifacts logs a warning.

Fixes

  • Docker build failures are no longer swallowed. Modern daemons emit an error key
    before errorDetail; the old anchored pattern missed it and surfaced every build,
    push, and pull failure as a misleading "No such image".
  • cmgr update now warns when a challenge's on-disk source has drifted but its builds
    are already complete, closing the gap where updating a schema left stale images in
    place.
  • Artifact extraction works against images with no CMD, no need to tail /dev/null anymore.
  • Solvers for artifact-only challenges run on Docker's default bridge, preserving
    outbound network access.
  • Line endings are normalized to LF via .gitattributes.

Examples and CI

  • Example challenges standardized on ubuntu:24.04 and hardened; the multi reference
    was deduplicated and the static-make lockbox builds against OpenSSL 3.0.
  • The disks examples share a slimmed libguestfs base image, cutting build time
    substantially.
  • CI checks out before setup-go so the Go module cache actually hits, and runs the
    integration tests with --keep-images.

Dependencies

  • Bumped docker/cli, moby/moby (api + client), mattn/go-sqlite3, yuin/goldmark,
    JohannesKaufmann/html-to-markdown, golang.org/x/net, and golang.org/x/sys to
    their latest releases.

Release v2.1.3

Choose a tag to compare

@github-actions github-actions released this 07 Jun 23:54
v2.1.3
1caef5c

hotfix for on-demand instance pruning query

Release v2.1.2

Choose a tag to compare

@github-actions github-actions released this 03 Jun 02:04
v2.1.2
7dff7cc

Since v2.1.1 (2026-06-02)

Fixes older db migrations

Release v2.1.1

Choose a tag to compare

@github-actions github-actions released this 02 Jun 18:57
v2.1.1
4bd479a

Since v2.1.0 (2026-05-27)

A small performance and build-targets release.

Performance

  • Skip port read-back on explicit ports (#67) — when a challenge launches with explicit CMGR_PORTS, the host ports are already reserved and bound before ContainerCreate, so the post-start ContainerInspect/backoff loop could only re-read values cmgr already knows. That loop is now gated on portLow == 0 and skipped on the explicit-port path, removing the inspect round-trips and backoff sleeps from the hot launch path while networking settles. Docker-assigned ephemeral ports still read back as before, and the rebuild flow (which clears instance.Ports before restarting) is correctly detected as "not yet known" so it continues to read the bound port back.
  • Cache Docker OSType once at init (#67) — the daemon's OSType (used only to decide whether to apply the Linux seccomp profile) is immutable for the daemon's lifetime. It's now fetched once in initDocker instead of via a heavy Info call on every build, launch, and solve.

Hardening

  • Container ports with no reverse-port-map entry are now logged and skipped during read-back instead of being written under an empty key, which previously could drop the real mapping or clobber other unmapped ports (#67).

Build & CI

  • Dropped the Intel Mac (darwin_amd64) release target (99fc129) — published binaries now cover linux_amd64 and darwin_arm64 (Apple Silicon). Intel Mac and Linux ARM builds are no longer published; build from source for those platforms.

Testing

  • Added unit coverage for the explicit-port skip logic and the unmapped-port edge case (cmgr/database_operations_test.go, +158 lines).

Documentation

  • README install note updated to reflect the published platform targets and source-build guidance for unsupported ones.

Release v2.1.0

Choose a tag to compare

@github-actions github-actions released this 27 May 20:06
b2d33b0

Since v2.0.0 (2024-05-06)

Features

  • Markdown challenge text (#62, #63, #64) — challenge description, hint, and details now flow through as Markdown end-to-end. HTML islands are detected with net/html and converted via html-to-markdown v2; LaTeX passes through cleanly. Templated metadata ({{ ... }}) uses custom delimiters so it survives the Markdown round-trip.
  • Concurrent instance launches (#44) — replaced the port-assignment mutex with a semaphore, allowing two instances to launch in parallel and pipelining work against the Docker daemon.
  • Atomic SQLite port reservations (part of #20) — port allocation now happens inside a single SQL transaction, eliminating races under concurrent launches.
  • Autoprune for lingering instances (#19) — instance rows orphaned by external container reaping are now pruned on each launch (configurable via PRUNE_AGE), preventing port-exhaustion spirals.
  • User-supplied env vars on container launch (#14) — cmgrd now accepts a required user_id and an optional env-var map, propagated equally to every container in a multi-container challenge.
  • LINUX_IMMUTABLE capability (#6) — opt-in via challenge metadata.

Performance

Bundled in #20 (numbers below are pre-launch pre-compute time):

DB size Before #19 With #19 With #20
20 0.31 ms 0.32 ms 0.33 ms
200 0.44 ms 0.42 ms 0.29 ms
20 000 24.91 ms 26.27 ms 12.43 ms
50 000 60.51 ms 64.76 ms 31.43 ms
  • SQLite WAL mode enabled by default, with _synchronous=NORMAL and _busy_timeout=50ms DSN tuning.
  • Replaced the in-memory port map with a compact bitset in getFreePort.
  • Added indexes for cascade deletes and portAssignments(port).
  • Fixed an N+1 query pattern in lookupBuildInstances (batched via JOIN, wrapped in a read-only transaction).

Fixes

  • On-demand challenge rebuilds (#17) — rebuilds previously restarted on-demand instances with nil env vars, silently dropping injected values like CMGR_USER_ID. They are now torn down on rebuild and must be Start()ed again with proper env.
  • InstanceMetadata.CreatedAt is now *time.Time so JSON output is RFC3339.
  • Migration ALTER TABLE guarded by PRAGMA table_info (idempotent migration on re-run).
  • Periodic prune log demoted from info to debug.
  • Errors in the migration block are no longer swallowed.

Build & CI

  • Docker module v25 → v29 (#12, #42) — adapted to breaking v29 API changes (network.ParsePort with error handling, netip.ParseAddr error checks, pushResp close fix).
  • Go 1.26 in CI; go build runs only on master push.
  • macOS-latest runners used for arm64 builds.
  • GitHub Actions pinned to commit SHAs with a cooldown window for security.
  • Dependabot enabled (weekly).

Testing

  • Comprehensive unit test suite added (#16) — covers autoprune (Prune/checkPrune), lookupBuildInstances, usedPortBitset/getFreePort, cache isolation for lookupBuildMetadata / lookupChallengeMetadata, concurrent port reservations, HTML-island boundaries, and LaTeX passthrough.

Documentation

  • README and Swagger updated for the env-var launch feature; new examples/runtime_env_vars challenge.
  • Documented that env vars broadcast equally to all containers in a multi-container challenge.
  • CLI usage info for PRUNE_AGE.

Dependencies

Routine bumps via Dependabot: docker/cli, moby/moby/client, mattn/go-sqlite3, yuin/goldmark, jmoiron/sqlx, containerd/containerd, go.opentelemetry.io/otel, golang.org/x/net.

Release v2.0.0

Choose a tag to compare

@github-actions github-actions released this 06 May 14:53
v2.0.0
d2753f1

Changes

  • Challenge types other than remote-make and static-make are no longer supported.
    • Existing challenges of other types can be converted to custom by exporting their Dockerfile (cmgr dockerfile <type>).
  • JSON challenge specifications (problem.json) are no longer supported. Any existing challenges using this format must be converted to use problem.md instead.

Release v1.2.1

Choose a tag to compare

@github-actions github-actions released this 12 Feb 18:07
v1.2.1
a1f38d7

Changes

  • Fixed an issue preventing ARM64 builds in GitHub release artifacts from working correctly.
  • Linux ARM64 builds are no longer available.

Release v1.2.0

Choose a tag to compare

@github-actions github-actions released this 30 Jan 02:16

Changes

  • The cmgr update-schema command and POST /schemas/{schema_name} cmgrd endpoint now function as upserts: if the specified schema does not yet exist, a warning is logged and it is created. This allows clients to easily apply updates to schemas without needing to consider whether they already exist (ca62a57)

Release v1.1.1

Choose a tag to compare

@github-actions github-actions released this 29 Jan 18:00
v1.1.1
50de11d

Changes

  • Fixes bugs related to the use of {{url}} and {{lookup}} templates in the Description field, as introduced in v1.1.0 (50de11d)