Compare commits
4 changed files with 26 additions and 118 deletions
|
|
@ -1,66 +0,0 @@
|
||||||
# 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";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -72,13 +72,6 @@ let
|
||||||
# would be an eval error rather than a silently missing guard.
|
# would be an eval error rather than a silently missing guard.
|
||||||
reservedOwners = import ../reserved-names.nix;
|
reservedOwners = import ../reserved-names.nix;
|
||||||
|
|
||||||
# Words no hive name may CONTAIN, because identifiers are composed from a
|
|
||||||
# hive name. That file explains why it is not merged into the list above.
|
|
||||||
reservedFragments = import ../reserved-hive-fragments.nix;
|
|
||||||
|
|
||||||
nameGuards = import ./lib/name-guards.nix { inherit lib; };
|
|
||||||
hiveNames = lib.attrNames hyperhiveCfg.swarm.hives;
|
|
||||||
|
|
||||||
# A published target is declared as ONE url, because that url is also the
|
# A published target is declared as ONE url, because that url is also the
|
||||||
# audience its token is minted for — but prometheus wants the same fact in
|
# audience its token is minted for — but prometheus wants the same fact in
|
||||||
# three fields. Split it here rather than asking a service to state it
|
# three fields. Split it here rather than asking a service to state it
|
||||||
|
|
@ -665,30 +658,33 @@ in
|
||||||
Put it back, or give this module a different swarmTierName.
|
Put it back, or give this module a different swarmTierName.
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
(nameGuards.mustNotEqual {
|
{
|
||||||
option = "services.hyperhive.swarm.hives";
|
# A hive whose name is one this module claims for itself collides in
|
||||||
names = hiveNames;
|
# the collector's component namespace, and `//` resolves it silently:
|
||||||
reserved = reservedOwners;
|
# the swarm tier's parts win, that hive's `metrics/<name>` pipeline
|
||||||
why = ''
|
# disappears, and its `resource/<name>` stamp goes with it — so the
|
||||||
The collector names components `<kind>/<owner>` with the hive name
|
# hive still connects and pushes into nothing, unlabelled.
|
||||||
as owner, and `//` resolves the clash silently: the swarm tier's
|
#
|
||||||
parts win, that hive's pipeline and `hive=` stamp disappear, and it
|
# Checked rather than documented for the same reason the port range
|
||||||
keeps pushing into a route that goes nowhere. Rename the hive.
|
# is: the names are all known at evaluation time, and the runtime
|
||||||
|
# symptom is a hive that looks healthy and reports no metrics, with
|
||||||
|
# nothing in any log naming the cause.
|
||||||
|
assertion = !lib.any (h: lib.elem h reservedOwners) (lib.attrNames hyperhiveCfg.swarm.hives);
|
||||||
|
message = ''
|
||||||
|
services.hyperhive.swarm.hives contains ${
|
||||||
|
lib.concatMapStringsSep ", " (h: "'${h}'") (
|
||||||
|
lib.filter (h: lib.elem h reservedOwners) (lib.attrNames hyperhiveCfg.swarm.hives)
|
||||||
|
)
|
||||||
|
}, which the swarm collector reserves for its own pipelines.
|
||||||
|
|
||||||
|
The collector names components `<kind>/<owner>` and uses the hive
|
||||||
|
name as the owner, so such a hive would silently replace the
|
||||||
|
swarm tier's parts and lose its own — it would keep accepting
|
||||||
|
pushes into a pipeline that routes nowhere.
|
||||||
|
|
||||||
|
Rename the hive. Reserved: ${lib.concatMapStringsSep ", " (n: "'${n}'") reservedOwners}.
|
||||||
'';
|
'';
|
||||||
})
|
}
|
||||||
(nameGuards.mustNotContain {
|
|
||||||
option = "services.hyperhive.swarm.hives";
|
|
||||||
names = hiveNames;
|
|
||||||
fragments = reservedFragments;
|
|
||||||
why = ''
|
|
||||||
Hive-scoped identifiers are composed from a hive name —
|
|
||||||
`hive-<name>`, `hive-<name>-agent` — so a name containing one of
|
|
||||||
these produces an identifier that is also somebody else's. The
|
|
||||||
failure is a wrong grant rather than an error: the client
|
|
||||||
authenticates and receives another principal's permissions, and a
|
|
||||||
NATS denial arrives as a timeout. Rename the hive.
|
|
||||||
'';
|
|
||||||
})
|
|
||||||
{
|
{
|
||||||
# A published target that is not an `https://host/path` url. Without
|
# A published target that is not an `https://host/path` url. Without
|
||||||
# this the split returns null and the failure surfaces as
|
# this the split returns null and the failure surfaces as
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
# Words no HIVE name may CONTAIN. The substring half of `./reserved-names.nix`.
|
|
||||||
#
|
|
||||||
# Separate because the two differ in every dimension: subject (hive names only
|
|
||||||
# vs hive AND agent), matcher (substring vs equality), and admission rule (a
|
|
||||||
# fixed segment of a COMPOSED identifier vs a value some component emits).
|
|
||||||
# Folding them would widen the other one — containment over `forge` refuses
|
|
||||||
# `forgeworks`, which names no failure.
|
|
||||||
[
|
|
||||||
# `hive-<name>` — every hive's OIDC client id, and the string the queue's
|
|
||||||
# auth-callout responder strips to decide which hive a connection is.
|
|
||||||
"hive"
|
|
||||||
# `hive-<name>-agent` — the client its agent containers present. A hive named
|
|
||||||
# `foo-agent` mints exactly the id hive `foo`'s agents do.
|
|
||||||
"agent"
|
|
||||||
# Also an exact-match entry next door, for the collector's `<kind>/<owner>`
|
|
||||||
# components. Here because it is the word this swarm composes identifiers
|
|
||||||
# from everywhere.
|
|
||||||
"swarm"
|
|
||||||
]
|
|
||||||
|
|
@ -25,9 +25,6 @@
|
||||||
# `from`/`to`, or a component name the collector builds pipelines from — not a
|
# `from`/`to`, or a component name the collector builds pipelines from — not a
|
||||||
# word that merely looked risky. A name in here that nothing emits is a refusal
|
# word that merely looked risky. A name in here that nothing emits is a refusal
|
||||||
# with no failure behind it.
|
# with no failure behind it.
|
||||||
#
|
|
||||||
# ⚠️ Matched by EQUALITY. Words forbidden *inside* a hive name live in
|
|
||||||
# `./reserved-hive-fragments.nix` — read its header before merging the two.
|
|
||||||
[
|
[
|
||||||
# ---- message-layer senders -------------------------------------------
|
# ---- message-layer senders -------------------------------------------
|
||||||
# The human at the dashboard: a broker recipient (the T4LK box sends
|
# The human at the dashboard: a broker recipient (the T4LK box sends
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue