A hive key becomes a certificate subject and a directory name, but only the reserved-name and fragment guards looked at it, so `a/b` or `../x` evaluated and misbehaved later. Assert at eval time that every key is 1-63 characters of [a-z0-9-], the rule `Ident` applies in hive-types, and name the offending keys in the message.
89 lines
2.4 KiB
Nix
89 lines
2.4 KiB
Nix
# Assertions about names an operator chooses, so a module states WHAT is
|
|
# forbidden and not how to phrase the refusal.
|
|
{ lib }:
|
|
let
|
|
# One shape for both guards. Reports EVERY offender, not the first: fixing
|
|
# one per rebuild is the slowest possible way to learn a rule.
|
|
#
|
|
# Offenders come after their label rather than before it, so one name and
|
|
# five read the same — no English verb agrees with both.
|
|
guard =
|
|
{
|
|
option,
|
|
names,
|
|
forbidden,
|
|
hit,
|
|
problem,
|
|
forbiddenLabel,
|
|
why,
|
|
}:
|
|
let
|
|
offenders = lib.filter (n: lib.any (f: hit f n) forbidden) names;
|
|
quote = xs: lib.concatMapStringsSep ", " (x: "'${x}'") xs;
|
|
in
|
|
{
|
|
assertion = offenders == [ ];
|
|
message = ''
|
|
${option} ${problem}: ${quote offenders}
|
|
${forbiddenLabel}: ${quote forbidden}
|
|
|
|
${why}
|
|
'';
|
|
};
|
|
in
|
|
{
|
|
# No name may BE one of `reserved`.
|
|
mustNotEqual =
|
|
{
|
|
option,
|
|
names,
|
|
reserved,
|
|
why,
|
|
}:
|
|
guard {
|
|
inherit option names why;
|
|
forbidden = reserved;
|
|
hit = f: n: f == n;
|
|
problem = "has reserved name(s)";
|
|
forbiddenLabel = "Reserved";
|
|
};
|
|
|
|
# No name may CONTAIN one of `fragments`.
|
|
mustNotContain =
|
|
{
|
|
option,
|
|
names,
|
|
fragments,
|
|
why,
|
|
}:
|
|
guard {
|
|
inherit option names why;
|
|
forbidden = fragments;
|
|
hit = lib.hasInfix;
|
|
problem = "has name(s) containing a reserved word";
|
|
forbiddenLabel = "Forbidden as substrings";
|
|
};
|
|
|
|
# Every name must be a valid hive `Ident` (hive-types/src/lib.rs): 1-63
|
|
# characters of `[a-z0-9-]`, with no leading-character rule. A hive name is
|
|
# spliced into certificate subjects and filesystem paths, where `/` and `..`
|
|
# change meaning.
|
|
mustBeIdent =
|
|
{ option, names }:
|
|
let
|
|
offenders = lib.filter (n: builtins.match "[a-z0-9-]+" n == null || lib.stringLength n > 63) names;
|
|
in
|
|
{
|
|
assertion = offenders == [ ];
|
|
message = ''
|
|
${option} has name(s) that are not valid identifiers: ${
|
|
lib.concatMapStringsSep ", " (x: "'${x}'") offenders
|
|
}
|
|
Required: 1-63 characters, each one of [a-z0-9-]
|
|
|
|
A hive name becomes a certificate subject and a directory name, so a
|
|
`/` or `..` in it names something else. `Ident` in
|
|
hive-types/src/lib.rs applies the same rule. Rename the hive.
|
|
'';
|
|
};
|
|
}
|