[PATCH v5 13/13] Validate configuration parameters

Demi Marie Obenour
2025-11-26T19:42:22Z

Wrong values for the version or update URL will cause very confusing
build-time or runtime errors. Provide a better user experience by
validating them up-front.

The update URL validator is loose. It rejects only URLs that cannot
possibly work: either appending /SHA256SUMS to them doesn't append to
the path, or they will definitely be rejected by curl due to being
malformed.

The version validator is in lib/config.nix, as the version number is
used in many places. It checks that the version only uses characters
that are permitted by systemd's version number specification [1] and
that will not break code that uses them in shell or sed commands.

[1]: https://uapi-group.org/specifications/specs/version_format_specification

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
Changes since v4:
- Drop compression level.
- Centralize validation.
- Use camelCase for Nix identifiers.
- Clean up formatting.

Changes since v3:
- Validate compression level.

Changes since v2:
- Use loose URL validation: allow anything that might work.
- Only reject versions that violate the specification.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
lib/config.nix | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/lib/config.nix b/lib/config.nix
index e437cdbe9aa22dd0f9c8d7052ac331c8fccf6ce6..e641642de07c1549e69fc12e91c4e80e2f82d035 100644
--- a/lib/config.nix
+++ b/lib/config.nix
@@ -17,6 +17,31 @@ let
callConfig = config: if builtins.typeOf config == "lambda" then config {
inherit default;
} else config;
+ finalConfig = default // callConfig config;
+ # Use builtins.fromJSON because it supports \uXXXX escapes.
+ # This is the same regex used by check-url.awk in the update VM.
+ # The update code is careful to escape any metacharacters, but some
+ # simply cannot be made to work. Concatenating the URL with /SHA256SUMS
+ # must append to the path portion of the URL, and the URL must be one
+ # that libcurl will accept.
+ urlRegex = builtins.fromJSON "\"^[^\\u0001- #?\\u007F]+$\"";
in

-default // callConfig config
+# Version is used in many files, so validate it here.
+# See https://uapi-group.org/specifications/specs/version_format_specification
+# for allowed version strings.
+if builtins.match "[[:alnum:]_.~^-]+" finalConfig.version == null then
+ builtins.abort ''
+ Version ${builtins.toJSON finalConfig.version} has forbidden characters.
+ Only ASCII alphanumerics, ".", "_", "~", "^", "+", and "-" are allowed.
+ See <https://uapi-group.org/specifications/specs/version_format_specification>.
+ ''
+else
+if builtins.match urlRegex finalConfig.updateUrl == null then
+ builtins.abort ''
+ Update URL ${builtins.toJSON finalConfig.updateUrl} has forbidden characters.
+ Query strings, and fragment specifiers are not supported.
+ ASCII control characters and whitespace must be %-encoded.
+ ''
+else
+finalConfig

--
2.52.0