From 926dbd7a97a737ef99e54b932a502d5deba18cc7 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 9 Oct 2026 11:02:44 +0200 Subject: [PATCH] Fill machine facts in a user's home, so an agent account named with a home is made there node agent-account [home] stored a home that nothing used: the account was created at /home/ while its files went to the named home (hq ADR 0266). The engine reads a user's home only when it creates the account, so an existing one is never moved. --- internal/catalogue/agent_account_test.go | 10 ++++++++-- internal/catalogue/machine_into_files.go | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/internal/catalogue/agent_account_test.go b/internal/catalogue/agent_account_test.go index 70b18b26..90efb041 100644 --- a/internal/catalogue/agent_account_test.go +++ b/internal/catalogue/agent_account_test.go @@ -36,7 +36,8 @@ func TestTheAgentAccountFactFallsBackToTheOperatorAndIsNeverRootOnlyWhenItsOwn(t // The agent's module, in the shape the catalogue's declares it: the account, never root where it is its // own; its directory under that home, owned by it. const agentModule = `{"module": "agent", "version": "1", "resources": [ - {"id": "account", "type": "user", "name": "${machine:agent-account}", "root": "${machine:agent-root}"}, + {"id": "account", "type": "user", "name": "${machine:agent-account}", "home": "${machine:agent-home}", + "root": "${machine:agent-root}"}, {"id": "home", "type": "directory", "path": "${machine:agent-home}/.agent", "mode": "0700", "owner": "${machine:agent-account}"} ]}` @@ -57,13 +58,18 @@ func TestTheAgentAccountIsDeclaredNeverRootOnlyToAnEngineThatJudgesIt(t *testing } user, home := compose(Resolution{Account: "ops", AgentAccount: "agent"}, Rendering{JudgesRoot: true}) - if user["name"] != "agent" || user[RootField] != RootNever { + if user["name"] != "agent" || user[RootField] != RootNever || user["home"] != "/home/agent" { t.Errorf("an engine that judges root is sent the agent account never to become root: %v", user) } if home["path"] != "/home/agent/.agent" || home["owner"] != "agent" { t.Errorf("the agent's directory is under its own home, its own: %v", home) } + user, _ = compose(Resolution{Account: "ops", AgentAccount: "agent", AgentAccountHome: "/srv/agent"}, Rendering{JudgesRoot: true}) + if user["home"] != "/srv/agent" { + t.Errorf("an agent account named with a home of its own is made there: %v", user) + } + user, _ = compose(Resolution{Account: "ops", AgentAccount: "agent"}, Rendering{}) if _, sent := user[RootField]; sent || user["name"] != "agent" { t.Errorf("an older engine, which parses strictly, is sent root: %v", user) diff --git a/internal/catalogue/machine_into_files.go b/internal/catalogue/machine_into_files.go index 928bf8de..f0e38de6 100644 --- a/internal/catalogue/machine_into_files.go +++ b/internal/catalogue/machine_into_files.go @@ -145,8 +145,10 @@ func machineInto(resource map[string]any, facts map[string]string, module string // the shell module makes the operator's account its holder's login shell, and the desktop's // watchers run as that account (novox/hq ADR 0176, ADR 0177) — neither can name the person. And a // user's `root`: the agent's module declares the account agents run as with ${machine:agent-root}, - // "never" only where that account is the agents' own (novox/hq ADR 0266). - for _, field := range []string{"path", "owner", "content", "name", "user", "root"} { + // "never" only where that account is the agents' own (novox/hq ADR 0266), and its `home`, so an account + // the operator named with a home of its own is made there (${machine:agent-home}); the node-engine reads a + // user's home only when it creates the account, so an existing one is never moved. + for _, field := range []string{"path", "owner", "content", "name", "user", "root", "home"} { s, ok := resource[field].(string) if !ok { continue