Przejdź do treści

Configuration files and precedence

Ta treść nie jest jeszcze dostępna w twoim języku.

This reference reflects Onetime Secret v0.26.19 (e98a88c9).

Four subjects have their own configuration file. Each one is resolved separately, and each one has a shipped defaults file beside it.

Subject Shipped defaults Deployment file Loader
Main application etc/defaults/config.defaults.yaml etc/config.yaml lib/onetime/config.rb
Authentication etc/defaults/auth.defaults.yaml etc/auth.yaml lib/onetime/auth_config.rb
Logging etc/defaults/logging.defaults.yaml etc/logging.yaml lib/onetime/initializers/setup_loggers.rb
Billing none shipped etc/billing.yaml lib/onetime/billing_config.rb

The shipped defaults files are part of the application. Edit the deployment file next to them instead, and leave etc/defaults/ untouched, so an upgrade can replace the defaults without discarding your settings.

Billing ships an example rather than a defaults file. If etc/billing.yaml does not exist, the billing configuration is empty and billing is off.

For each subject, path resolution runs in this order:

  1. When RACK_ENV=test, spec/<subject>.test.yaml, then apps/**/spec/<subject>.test.yaml.
  2. etc/<subject>.yaml.

The shipped defaults file is resolved separately and only at etc/defaults/<subject>.defaults.yaml.

If no main configuration file is found at all, the search falls back to fixed directories: /etc/onetime, ./etc and ./etc/defaults when the application runs as a service, and ~/.onetime first when it runs as a command-line utility.

There is no environment variable that selects the configuration file path at this release. A search for ONETIME_CONFIG across the application returns no matches, so the paths above are the whole mechanism.

Passing an explicit path to the main loader is the one way to bypass the defaults layer. When a path is given, the shipped defaults file is not read and the single file is used as it stands.

Three layers resolve a key, in this order:

  1. The shipped defaults file is the base.
  2. The deployment file is deep-merged on top, so a value you set wins over the shipped one. Nils are not preserved at this step: an explicit nil in the deployment file means nil, and does not fall back to the shipped value.
  3. In-code defaults are then merged underneath, with nils preserved. A key that resolved to nil through the first two steps takes the in-code default.

Deep merge means per-key, at every depth. Setting one key inside a section leaves its siblings at their shipped values; it does not replace the section.

Two consequences of step 3 are worth stating outright:

  • An empty string is a value. In Ruby "" is truthy, so a key set to an empty string replaces the in-code default rather than falling through to it.
  • A key you want to clear back to the in-code default has to be nil, not empty.

The authentication and logging files layer the same way through the same merge. The authentication file is stricter about YAML types: its loader permits no extra classes, so an unquoted date that the main file would accept raises an error there. A failure to load the authentication file stops the boot.

Environment variables are not a configuration layer. They take effect only through ERB inside the YAML files: the loader renders each file with ERB and then parses the result. A key whose value in the shipped defaults file is a literal cannot be set from the environment at all.

That is why the key records say which variables reach each key, and why some keys list none. The three shapes you will see in the shipped files are a plain read (<%= ENV['HOST'] %>), a read with a literal fallback (<%= ENV['HOST'] || 'localhost:3000' %>) and a boolean comparison (<%= ENV['SSL'] == 'true' %>). A few values are computed from several reads and are reported as determined at run time, with the expression shown.

Because the environment is read during ERB rendering, an environment value behaves as though it were written in the file it appears in. The layering above then applies to the rendered result.

When the application finds a removed or relocated configuration key, or its environment variable, at boot, compatibility.deprecated_config_mode decides what happens:

Value Behaviour
strict Raise a configuration error and refuse to start. This is the default.
warn Log a migration message and continue.
silent Ignore it.

An unrecognized value is treated as strict. Entries the application marks as warn-severity log under both strict and warn rather than stopping the boot.

So the default posture is that a configuration file left over from an older release stops the boot with an error naming the key, instead of starting with the setting quietly ignored.

Every key in the shipped defaults files has one owning reference page.

Page Keys it owns
Site and interface site.* except secret options and sign-in switches, internationalization.*, diagnostics.*
Features and branding features.*, brand.*, site.secret_options.*, site.authentication.*
Datastore and queues redis.*, jobs.*
Email and delivery emailer.*, email_providers.*, mail.*
Auth, logging and billing files every key in the authentication, logging and billing files
This page development.*, compatibility.*, experimental

These keys configure the configuration layer itself and the development-mode behaviour that depends on it. The values are read from etc/defaults/config.defaults.yaml at the release named above.

Key Value Environment variables Since Source
development.enabled determined at run time: true when RACK_ENV is development or dev RACK_ENV not annotated etc/defaults/config.defaults.yaml:2014
development.debug determined at run time: true when ONETIME_DEBUG is true, 1 or yes ONETIME_DEBUG not annotated etc/defaults/config.defaults.yaml:2015
development.frontend_host http://localhost:5173 FRONTEND_HOST not annotated etc/defaults/config.defaults.yaml:2019
development.allow_nil_global_secret false ALLOW_NIL_GLOBAL_SECRET v0.24.0 etc/defaults/config.defaults.yaml:2051
development.devbasicauth false when unset DEV_BASIC_AUTH v0.24.6 etc/defaults/config.defaults.yaml:2066
development.devsessionauth false when unset DEV_SESSION_AUTH v0.24.6 etc/defaults/config.defaults.yaml:2080
compatibility.deprecated_config_mode strict DEPRECATED_CONFIG_MODE v0.25.5 etc/defaults/config.defaults.yaml:2090
experimental empty mapping none v0.26.0 etc/defaults/config.defaults.yaml:2102

development.allow_nil_global_secret takes effect only while development.enabled is true; the normalization step forces it to false otherwise. development.devbasicauth and development.devsessionauth register development-only authentication strategies and are refused in production. experimental is an empty extension point in the shipped defaults.