Skip to content

Latest commit

 

History

History
212 lines (168 loc) · 10.3 KB

specification.md

File metadata and controls

212 lines (168 loc) · 10.3 KB

Challenge Specification

  • Namespace: cmgr/examples
  • Type: custom
  • Category: example
  • Points: 1

Description

This portion of the challenge description is displayed to users regardless of whether an instance of the challenge is currently running. It may include static text, as well as the following templates:

  • {{url_for("file", "display text")}} (link to an artifact file published in a build)
  • {{lookup("key")}} ("key" must have been published in metadata.json when creating a build)

Details

This portion of the challenge description is displayed to users when an instance of a challenge is running. It may include any content permitted in the "Description" section, as well as the following instance-specific templates:

  • {{http_base("port_name")}} (URL prefix for HTTP requests to the named port)
  • {{server("port_name")}} (hostname which hosts for connecting to the associated port for the challenge)
  • {{port("port_name")}} (The specific port number competitors will see which may not be the same number as exposed by Docker if the front-end is proxying connections.)
  • {{link("port_name", "/url/in/challenge")}} (convenience wrapper for generating an HTML link)
  • {{link_as("port_name", "/url/in/challenge", "display text")}} (convenience wrapper for generating an HTML link with text different from the URL)

Note: As a convenience, port_name can be omitted any time the challenge only publishes a single port to competitors. For templates that only take port_name as an argument, the parentheses should be omitted when using this convenience. The template strings exposed to front-ends will always be normalized to include port_name and have replaced link and linkAs with an HTML href tag that uses http_base.

Hints

  • A list of hints for the end user.
  • The hints are all templatable.
  • Whether there is a cost for displaying them is up to the front-end system

Tags

  • example
  • markdown

Attributes

  • Organization: ACI
  • Created: 2020-06-24

Challenge Options

This optional section can be used to apply additional restrictions to instances of this challenge via a ```yaml fenced code block. The available options are listed below, along with an example.

For multi-container challenges, by default any specified options apply to all containers. However, it is possible to specify separate options for each host (build stage) via an overrides: key, as seen in this example. Note that when an override is specified, it serves as a fully distinct set of challenge options for that container and will not be merged with any specified top-level options.

Container options are never applied to the "builder" stage or to solver containers.

  • The init option runs an init process as PID 1 inside the container. This can be useful if your challenge process forks, and will ensure that zombie processes are reaped. This is equivalent to passing the --init flag to docker run. Specify a boolean value, as shown in the example below. Defaults to false.

  • The cpus option specifies a maximum number of CPU cores that a container can utilize at full capacity. This may be useful in order to prevent computationally-heavy challenge instances from dominating the host. This is equivalent to passing the --cpus option to docker run. Specify a floating-point value, as shown in the example below. Unset by default.

  • The memory option specifies the maximum amount of memory available to a container. Attempting to exceed this limit at runtime may cause the container to restart, depending on how the challenge process handles allocation failures. This is useful in order to put an upper bound on the memory available to each challenge instance, preventing memory leaks from crashing the Docker host. This is equivalent to passing the --memory option to docker run. Specify an integer value with unit, as shown in the example below. Unset by default.

  • The ulimits option can be used to specify various resource limits inside the container. Note that the nproc ulimit is not supported, for reasons described here (use the pidslimit option instead). This is equivalent to passing --ulimit options to docker run. Specify a list of limit names and limits, as shown in the example below. Unset by default.

  • The pidslimit option specifies the maximum number of simultaneous processes inside the container. This is useful in order to prevent forkbombs from crashing the Docker host. This is equivalent to passing the --pids-limit option to docker run. Specify an integer value, as shown in the example below. Unset by default.

  • The readonlyrootfs option can be used to mount the container's root filesystem as read-only. If your challenge does not need to write to disk outside of /dev/shm, this is an easy way to improve the security of your challenge containers. This is equivalent to passing the --read-only flag to docker run. Specify a boolean value, as shown in the example below. Defaults to false.

  • The droppedcaps option can be used to drop additional Linux capabilities inside the container beyond Docker's defaults. This is equivalent to passing --cap-drop options to docker run. Specify a list of uppercase capability names, as shown in the example below. Unset by default.

  • The nonewprivileges option can be used to prevent processes inside the container from gaining additional privileges via execve() calls (by exploiting setuid binaries, etc). This is equivalent to passing the --security-opt="no-new-privileges:true" option to docker run. Specify a boolean value, as shown in the example below. Defaults to false.

  • The diskquota option can be used to limit the maximum size of the container's writable layer. This is equivalent to passing the --storage-opt size option to docker run.

    Note that this option is only supported when using the overlay2 Docker storage driver and pquota-enabled XFS backing storage (see this Docker Engine PR for more details.) If these requirements are not met, container creation will fail at runtime.

    To help prevent this issue, the diskquota option only takes effect if the CMGR_ENABLE_DISK_QUOTAS environment variable is set.

    Specify an integer value with unit, as shown in the example below. Unset by default.

  • The cgroupparent option can be used to manually specify the cgroup that a container will run in. This is equivalent to passing the --cgroup-parent flag to docker run.

    Note that it is also possible to set a default parent cgroup for all containers at the daemon level.

    Specify a cgroup name, as shown in the example below. Unset by default.

# sample challenge options:
init: true
cpus: 0.5
memory: 512m
ulimits:
    - nofile=512:1024
    - stack=4096
    - fsize=2048
pidslimit: 5
readonlyrootfs: true
droppedcaps:
    - CHOWN
    - SETPCAP
    - SETUID
nonewprivileges: true
diskquota: 256m
cgroupparent: customcgroup.slice

# only relevant for multi-container challenges:
overrides:
    work:
        pidslimit: 10
    randomDnsName:
        cpus: 0.25

Extra Sections

Any h2 sections (i.e. lines starting with ##) that don't match one of the headers above (not including "Extra Sections") will be parsed and added as additional attributes where the header text is the key and the value is raw text (i.e. no Markdown conversions) up to but not including the next h2 header. Whitespace at the start and end of this block of text is stripped, but all other whitespace is preserved exactly as written.

Mandatory Sections

There are only a few mandatory parts of this structure: the title line which is interpreted as the challenge name, the "type" entry (must be a list bullet in the block immediately following the title), and at least one templated reference to each artifact file and port exposed to the competitor (most likely in the "details" section). Although not required, the "namespace" entry is highly encouraged as it minimizes the likelihood of naming conflicts if challenges are released and/or merged with other sources.

Renaming Challenges

Challenge IDs are usually determined by sanitizing the user-facing challenge name and prepending the provided namespace (if any).

However, this means that changing a challenge's name and running cmgr update will be interpreted as removing the formerly-named challenge and adding a new one. This can be problematic when challenges have existing references to their former IDs in schemas or front-end software.

To avoid this issue, it is possible to specify an ID separately from the user-facing name by adding an "ID" list bullet to the block immediately following the title. When specified, the value of this ID field, rather than the challenge's name, is sanitized and prepended with the namespace to determine the challenge ID.

This makes it possible to update the user-facing name of a deployed challenge without affecting existing schema or front-end references by explicitly specifying the challenge's former name as its ID when changing its name.