swarm-controller re-issues an agent's store leaf at half its validity, but the running container kept presenting the copy its hive delivered at start, so a re-issued leaf reached the agent only on its next restart. hive-agent-bao-identity now seeds a live copy of the pair in its own runtime directory from the delivered credentials, and re-runs every 10 minutes: it logs in with the live leaf, reads its own swarm/agents/<agent>/bao-mtls (a read render_agent already grants), and when the leaf changed, logs in with the new pair and swaps it in only if the store accepts it. Every unit in the container that logs in to the store presents the live pair: hive-agent (queue-identity.nix), hive-matrix-daemon, hive-subagent-daemon, hive-agent-forge-token, hive-agent-forge-accounts and hive-agent-github-token. They keep loading the server CA as a credential. The long-running daemons are ordered after the refresher so the live pair exists when they start. It renews only while the held leaf is still valid: the login that reads the new leaf is made with the current one. Refs #5017
112 lines
3.7 KiB
Nix
112 lines
3.7 KiB
Nix
# `checks.module-eval-agent-github-bao` — see ./lib.nix for the shared
|
|
# rationale (why this suite exists, naming convention, "evaluates
|
|
# not executes").
|
|
#
|
|
# The agent side of the swarm-stored GitHub token: ../agent-modules/github-token.nix
|
|
# fetches it into the file ../agent-modules/github.nix's readers use.
|
|
{
|
|
pkgs,
|
|
lib,
|
|
self,
|
|
nixosSystem,
|
|
}:
|
|
let
|
|
inherit
|
|
(import ./lib.nix {
|
|
inherit
|
|
pkgs
|
|
lib
|
|
self
|
|
nixosSystem
|
|
;
|
|
})
|
|
agentWith
|
|
runGroup
|
|
;
|
|
|
|
baoAddr = "https://bao.t.local:8200";
|
|
|
|
# A store, and the integration on by default.
|
|
agentGithubBao = agentWith {
|
|
services.hyperhive.agent.bao.addr = baoAddr;
|
|
};
|
|
|
|
# No store: the absence arm, and what makes the cases above able to fail.
|
|
agentGithubNoBao = agentWith { };
|
|
|
|
# A store, and the integration switched off.
|
|
agentGithubOff = agentWith {
|
|
services.hyperhive.agent.bao.addr = baoAddr;
|
|
services.hyperhive.agent.github.enable = false;
|
|
};
|
|
|
|
fetchUnit = machine: machine.systemd.services.hive-agent-github-token;
|
|
has = machine: machine.systemd.services ? hive-agent-github-token;
|
|
hasTimer = machine: machine.systemd.timers ? hive-agent-github-token;
|
|
in
|
|
let
|
|
cases = [
|
|
{
|
|
name = "an agent with a store address and the integration on fetches its github token";
|
|
ok = has agentGithubBao && hasTimer agentGithubBao;
|
|
}
|
|
{
|
|
name = "an agent with no store address, or with the integration off, fetches none";
|
|
ok =
|
|
!(has agentGithubNoBao)
|
|
&& !(hasTimer agentGithubNoBao)
|
|
&& !(has agentGithubOff)
|
|
&& !(hasTimer agentGithubOff);
|
|
}
|
|
{
|
|
# The nix half of `swarm_secret_client::github::account_path`, and the
|
|
# file ./github.nix's `gh` wrapper, credential helper and poller read.
|
|
name = "the fetch reads the agent's own github-token path into its state-dir file";
|
|
ok =
|
|
let
|
|
name = agentGithubBao.services.hyperhive.agent.user.name;
|
|
s = (fetchUnit agentGithubBao).script;
|
|
in
|
|
lib.hasInfix "bao kv get -format=json secret/swarm/agents/${name}/github-token >" s
|
|
&& lib.hasInfix "token=/agents/${name}/state/github-token" s
|
|
&& lib.hasInfix ".data.data.value | strings" s;
|
|
}
|
|
{
|
|
# The agent user owns its state dir (./user.nix), and the file keeps
|
|
# its `0600` mode.
|
|
name = "the fetch runs as the agent, with its own store identity";
|
|
ok =
|
|
let
|
|
u = fetchUnit agentGithubBao;
|
|
name = agentGithubBao.services.hyperhive.agent.user.name;
|
|
in
|
|
u.serviceConfig.User == name
|
|
&& u.serviceConfig.UMask == "0077"
|
|
&& u.environment.BAO_ADDR == baoAddr
|
|
&& u.environment.BAO_CLIENT_CERT == "/run/hive-agent-bao-identity/cert"
|
|
&& u.environment.BAO_CLIENT_KEY == "/run/hive-agent-bao-identity/key";
|
|
}
|
|
{
|
|
# A file a hive wrote keeps working until the operator links a token in
|
|
# the swarm UI.
|
|
name = "the fetch never deletes the state-dir token, and swaps it in only on a change";
|
|
ok =
|
|
let
|
|
s = (fetchUnit agentGithubBao).script;
|
|
in
|
|
!(lib.hasInfix "rm -f \"$token\"" s)
|
|
&& lib.hasInfix "cmp -s \"$staged\" \"$token\"" s
|
|
&& lib.hasInfix "mv -f \"$staged\" \"$token\"" s;
|
|
}
|
|
{
|
|
# The poller reads the token once at start.
|
|
name = "the fetch runs before the github poller starts";
|
|
ok = builtins.elem "hive-github-notify.service" (fetchUnit agentGithubBao).before;
|
|
}
|
|
{
|
|
name = "the fetch re-runs every two minutes";
|
|
ok = agentGithubBao.systemd.timers.hive-agent-github-token.timerConfig.OnUnitInactiveSec == "2min";
|
|
}
|
|
];
|
|
in
|
|
runGroup "agent-github-bao" cases
|