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.
|
||||
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
|
||||
# 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
|
||||
|
|
@ -665,30 +658,33 @@ in
|
|||
Put it back, or give this module a different swarmTierName.
|
||||
'';
|
||||
}
|
||||
(nameGuards.mustNotEqual {
|
||||
option = "services.hyperhive.swarm.hives";
|
||||
names = hiveNames;
|
||||
reserved = reservedOwners;
|
||||
why = ''
|
||||
The collector names components `<kind>/<owner>` with the hive name
|
||||
as owner, and `//` resolves the clash silently: the swarm tier's
|
||||
parts win, that hive's pipeline and `hive=` stamp disappear, and it
|
||||
keeps pushing into a route that goes nowhere. Rename the hive.
|
||||
{
|
||||
# A hive whose name is one this module claims for itself collides in
|
||||
# the collector's component namespace, and `//` resolves it silently:
|
||||
# the swarm tier's parts win, that hive's `metrics/<name>` pipeline
|
||||
# disappears, and its `resource/<name>` stamp goes with it — so the
|
||||
# hive still connects and pushes into nothing, unlabelled.
|
||||
#
|
||||
# Checked rather than documented for the same reason the port range
|
||||
# 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
|
||||
# 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
|
||||
# word that merely looked risky. A name in here that nothing emits is a refusal
|
||||
# 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 -------------------------------------------
|
||||
# The human at the dashboard: a broker recipient (the T4LK box sends
|
||||
|
|
|
|||
Loading…
Reference in a new issue