Configuration
Location to config file
Docker
Note
This file needs to be edited before running the make commands.
<path to source root>/docker/engine.conf.inc
Manual
Note
Need to restart each scoring engine service once the config is modified.
/home/engine/scoring_engine/src/engine.conf
Configuration Keys
Note
Each of these config keys can be expressed via environment variables (and take precendence over the values defined in the file). IE: To define target_round_time, I’d set SCORINGENGINE_TARGET_ROUND_TIME=3.
Note
An environment variable that exists but is empty (or whitespace only) is treated as unset and does not override the config file. A leftover SCORINGENGINE_FOO= line in a copied .env therefore cannot silently blank out a value you configured in engine.conf. If you genuinely want an option to be empty, leave it empty in the config file instead (this is how redis_password ships).
Key Name |
Description |
|---|---|
checks_location |
Local path to directory of checks |
target_round_time |
Length of time (seconds) the engine should target per round |
agent_psk |
The pre-shared key used for encryption between BTA and the Scoring Engine |
agent_show_flag_early_mins |
The length of time in minutes before a flag becomes active that BTA can grab the flag details |
worker_refresh_time |
Amount of time (seconds) the engine will sleep for in-between polls of worker status |
max_consecutive_round_failures |
How many rounds may fail back to back before the engine gives up and exits non-zero. A failed round is rolled back and retried (transient database blips should not stop a competition), but an error that repeats every round is not transient, so the engine exits and lets the container restart make the problem visible. Default is 3. Set to 0 to retry forever (not recommended) |
worker_num_concurrent_tasks |
The number of concurrent tasks the worker will run. Set to -1 to default to number of processors. |
worker_queue |
The queue name for a worker to pull tasks from. This can be used to control which workers get which service checks. Default is ‘main’ |
blue_team_update_hostname |
A boolean indicating if blue teams should be allowed to update the hostnames associated for scored checks |
blue_team_update_port |
A boolean indicating if blue teams should be allowed to update the port associated for scored checks |
blue_team_update_account_usernames |
A boolean indicating if blue teams should be allowed to change usernames associated with scored checks |
blue_team_update_account_passwords |
A boolean indicating if blue teams should be allowed to change passwords of scored users |
blue_team_view_check_output |
A boolean indicating if blue teams should be allowed to view verbose output from checks |
timezone |
Local timezone of the competition |
debug |
Determines wether or not the engine should be run in debug mode (useful for development). The worker will also display output from all checks. |
secret_key |
The key Flask uses to sign session cookies. Must be a long random value and must be identical across restarts and across every web process/container. See Session Secret Key. |
db_uri |
Database connection URI |
cache_type |
The type of storage for the cache. Set to null to disable caching |
redis_host |
The hostname/ip of the redis server |
redis_port |
The port of the redis server |
redis_password |
The password used to connect to redis (if no password, leave empty) |
session_cookie_secure |
A boolean marking the session and remember-me cookies “Secure” so browsers only send them over HTTPS. The bundled docker compose stack terminates TLS at nginx and sets this to True. Leave it False for a plain-HTTP dev run, otherwise the browser drops the session cookie and logins silently fail. (default: False) |
sla_enabled |
A boolean to enable/disable SLA penalties for consecutive service failures |
sla_penalty_threshold |
Number of consecutive failures before penalties begin (default: 5) |
sla_penalty_percent |
Penalty percentage per failure after threshold (default: 10) |
sla_penalty_max_percent |
Maximum total penalty percentage cap (default: 50) |
sla_penalty_mode |
Penalty calculation mode: additive, flat, exponential, or next_check_reduction |
sla_allow_negative |
A boolean to allow scores to go negative from penalties |
dynamic_scoring_enabled |
A boolean to enable/disable time-based scoring multipliers |
dynamic_scoring_early_rounds |
Number of rounds in the early phase (default: 10) |
dynamic_scoring_early_multiplier |
Points multiplier for early phase (default: 2.0) |
dynamic_scoring_late_start_round |
Round number when late phase begins (default: 50) |
dynamic_scoring_late_multiplier |
Points multiplier for late phase (default: 0.5) |
inject_scores_visible |
A boolean to show inject scores on the public scoreboard (default: False, private grading) |
Session Secret Key
The web application signs session cookies with secret_key. It is the only
configuration key that is security critical and has no default, so it is worth
calling out separately.
Why it must be set
If the key changes, every existing session cookie becomes invalid and all users – including white team – are logged out. A key that is generated at startup therefore logs everyone out on every restart, redeploy, or crash loop.
If two web processes or containers hold different keys, a session issued by one is rejected by the other. That makes it impossible to run more than one web replica behind a load balancer, i.e. it blocks horizontal scaling entirely.
Why there is no default
No key is shipped in engine.conf.inc. A fixed default that operators forget
to change would let anyone who has read the source forge a session cookie for
any team, including white team. An unset key is a warning; a shared default key
would be a vulnerability.
Generating a key
Generate it yourself, on a machine you trust:
python -c "import secrets; print(secrets.token_hex(64))"
The engine never generates a key for you and prints it. Anything written to
stdout ends up in the container log stream, which is readable by anyone who can
run docker logs and is frequently shipped to a log aggregator – a signing
key that appears there should be considered compromised.
Setting it
Docker (recommended – docker/engine.conf.inc is baked into the image at
build time, so use the environment instead):
# in .env, next to the other credentials
SCORINGENGINE_SECRET_KEY=<paste the generated value>
The web, engine, and bootstrap services in docker-compose.yml
already pass this variable through. .env.example ships this line commented
out on purpose: an empty SCORINGENGINE_SECRET_KEY= is still an assignment,
and compose would forward it into the containers as an empty string. (Since an
empty environment variable is treated as unset, it no longer overrides the
config file – but a commented-out line makes the intent unambiguous.)
Manual install, in engine.conf:
secret_key = <paste the generated value>
If it is not set
The application still starts. It generates a random key for that process and
logs a warning explaining that sessions will not survive a restart and cannot
scale beyond one process. bin/setup performs the same check and warns with
the command to generate a key – it does not print a key. This is fine for local
development and never fine for a competition.
Warning
Treat the key like a password. Do not commit it, and rotate it if it leaks – rotating logs everyone out, which is the intended effect.