Keep quiet for the setuid search the engine now runs to completion (hq issue 361)
The node-engine's search has no bound any more: it runs at idle priority and judges from its last complete, fresh result. The controller's quiet while an agent account waits is the engine's rootsearch.Quiet, not the old fifteen-minute bound, and the node-engine is pinned at its pull request.
This commit is contained in:
@@ -119,9 +119,11 @@ func judgedConfined(agent string, h inventory.NodeHealth, had bool, now time.Tim
|
||||
}
|
||||
|
||||
// searchQuietFor is how long the controller lets an agent account's verdict wait for the node-engine's setuid
|
||||
// search before that is itself the urgent condition: the engine's bound on one search (link.RootSearchBound, the
|
||||
// engine's own value), counted from when this controller first saw it waiting, never from the engine's start.
|
||||
const searchQuietFor = link.RootSearchBound
|
||||
// search before that is itself the urgent condition: the longest a search is expected to take (link.RootSearchQuiet,
|
||||
// the engine's own value; novox/hq issue 361 — the search runs to completion, with no bound of its own), counted
|
||||
// from when this controller first saw it waiting, never from the engine's start. Quiet raises nothing; it never
|
||||
// makes the agent account confined, which only a healthy verdict from a complete, fresh search does.
|
||||
const searchQuietFor = link.RootSearchQuiet
|
||||
|
||||
// The kinds of an agent account's verdict, for the quiet a search earns.
|
||||
const (
|
||||
@@ -207,10 +209,10 @@ func probeAgentAccounts(ctx context.Context, d *doctor) ([]conditions.Observatio
|
||||
if confined {
|
||||
continue
|
||||
}
|
||||
// Not judged yet only because the first search since the node-engine started is still running: not the
|
||||
// Not judged yet only because the node-engine's search runs and no complete, fresh one judges: not the
|
||||
// urgent condition after every restart. The agent is still not confined — ADR 0259's router reads
|
||||
// agentConfined, not this — and `node show` still says not judged. Loud again once the search fails,
|
||||
// runs out its bound, or the statement goes stale.
|
||||
// waits past searchQuietFor, or the statement goes stale.
|
||||
if quiet {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -199,14 +199,20 @@ func TestTheNodeVerbOnlyShows(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// After every node-engine restart its search for setuid programs runs for up to its bound, and the agent account
|
||||
// is not judged until it ends. DA does not raise that as urgent while the search is within its bound, counted from
|
||||
// when this controller first saw it waiting — never from the engine's own "since", which a restart resets, so an
|
||||
// engine restarted in a loop does not keep it quiet. The account is still not confined, and `node show` still
|
||||
// says not judged; a search that failed, or a way to root found, is urgent at once.
|
||||
// Until a complete search for setuid programs judges — none since the node-engine's state was kept, or the last
|
||||
// older than the engine lets one judge — the agent account is not judged, and the search runs to its end with no
|
||||
// bound (novox/hq issue 361). DA does not raise that as urgent within searchQuietFor, counted from when this
|
||||
// controller first saw it waiting — never from the engine's own "since", which a restart resets, so an engine
|
||||
// restarted in a loop does not keep it quiet. The account is still not confined, and `node show` still says not
|
||||
// judged; a search that failed, or a way to root found, is urgent at once.
|
||||
func TestASearchStillRunningAfterARestartIsNotUrgent(t *testing.T) {
|
||||
if searchQuietFor != rootsearch.Bound {
|
||||
t.Fatalf("the quiet is %s and the node-engine's bound %s: they are one value", searchQuietFor, rootsearch.Bound)
|
||||
if searchQuietFor != rootsearch.Quiet {
|
||||
t.Fatalf("the quiet is %s and the node-engine's %s: they are one value", searchQuietFor, rootsearch.Quiet)
|
||||
}
|
||||
// A daily search that finishes within the quiet never leaves the account unjudged between two of them.
|
||||
if rootsearch.FreshFor < rootsearch.Every+rootsearch.Quiet {
|
||||
t.Fatalf("a complete search judges for %s, less than a day's search (%s) and the quiet (%s)",
|
||||
rootsearch.FreshFor, rootsearch.Every, rootsearch.Quiet)
|
||||
}
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
|
||||
@@ -25,7 +25,9 @@ import (
|
||||
// 1. the machine names an account agents run as (novox/hq ADR 0266), so no agent runs as the operator's
|
||||
// account, which may become root;
|
||||
// 2. its node-engine — running as root, which no agent controls — judged that account unable to become root
|
||||
// without a person, in a statement heard within the last 15 minutes (agentConfined, judgedConfined);
|
||||
// without a person, in a statement heard within the last 15 minutes (agentConfined, judgedConfined). The
|
||||
// engine gives that verdict only from a complete search for setuid programs younger than mesh-host's
|
||||
// rootsearch.FreshFor; before one, it says "not judged yet", which is no pass (novox/hq issue 361);
|
||||
// 3. the login shell's `execute` is not served there (novox/hq ADR 0268): its holder's setting withholds it
|
||||
// **and** the bus was asked and heard no `execute` answered there. `execute` runs commands as the machine's
|
||||
// runtime account, which the mesh's acting tools give passwordless sudo; that account is taken to become
|
||||
@@ -95,8 +97,8 @@ type rootFacts struct {
|
||||
// Execute is whether the login shell's execute is served there; ExecuteWhy why, in words.
|
||||
Execute bool
|
||||
ExecuteWhy string
|
||||
// SearchPending is the agent account unjudged only because the node-engine's first setuid search runs,
|
||||
// within its bound (ADR 0266's quiet window).
|
||||
// SearchPending is the agent account unjudged only because the node-engine's setuid search runs, within
|
||||
// the quiet the controller gives it (searchQuietFor; ADR 0266's quiet window, issue 361).
|
||||
SearchPending bool
|
||||
}
|
||||
|
||||
@@ -106,7 +108,7 @@ type rootVerdict struct {
|
||||
Free bool `json:"free"`
|
||||
Why string `json:"why"`
|
||||
Judged time.Time `json:"judged"`
|
||||
// Quiet is a machine not free only because its first setuid search still runs, within its bound: the
|
||||
// Quiet is a machine not free only because its setuid search still runs, within searchQuietFor: the
|
||||
// self-check raises nothing for it then (ADR 0266's quiet window). It is never free for it.
|
||||
Quiet bool `json:"quiet,omitempty"`
|
||||
}
|
||||
@@ -136,7 +138,7 @@ func judgeRoot(f rootFacts, now time.Time) rootVerdict {
|
||||
}
|
||||
if len(not) > 0 {
|
||||
v.Why = strings.Join(not, "; ")
|
||||
// The one failure is the agent account not judged yet, because its first search runs.
|
||||
// The one failure is the agent account not judged yet, because its search runs.
|
||||
v.Quiet = len(not) == 1 && f.SearchPending && f.AgentNamed && !f.Confined && len(f.Unread) == 0 && !f.Execute
|
||||
return v
|
||||
}
|
||||
@@ -154,8 +156,8 @@ type rootReader struct {
|
||||
asked error
|
||||
// confined is agentConfined; settings the login shell holder's settings on a machine. Replaceable in a test.
|
||||
confined func(ctx context.Context, node string, now time.Time) (named, confined bool, why string, err error)
|
||||
// quiet says the one thing keeping a machine's agent account unjudged is the node-engine's first setuid
|
||||
// search, within its bound (ADR 0266, searchStillRunning). Read by the self-check alone, to raise nothing
|
||||
// quiet says the one thing keeping a machine's agent account unjudged is the node-engine's setuid
|
||||
// search, within searchQuietFor (ADR 0266, searchStillRunning). Read by the self-check alone, to raise nothing
|
||||
// then; nil reads no quiet. It never makes a machine root-free.
|
||||
quiet func(ctx context.Context, node string, now time.Time) bool
|
||||
settings func(ctx context.Context, node, module string) ([]catalogue.Layer, error)
|
||||
@@ -304,8 +306,8 @@ func probeAgentRoot(ctx context.Context, d *doctor) ([]conditions.Observation, e
|
||||
if r.read != nil {
|
||||
return nil, r.read
|
||||
}
|
||||
// The self-check alone reads ADR 0266's quiet window: nothing raised while a machine's first setuid search
|
||||
// runs, within its bound. The root-free verb never reads it, so the machine still answers not free.
|
||||
// The self-check alone reads ADR 0266's quiet window: nothing raised while a machine's setuid search
|
||||
// runs, within searchQuietFor. The root-free verb never reads it, so the machine still answers not free.
|
||||
r.quiet = func(ctx context.Context, node string, now time.Time) bool {
|
||||
n, err := inv.NodeByName(ctx, node)
|
||||
if err != nil || n.AgentAccount == "" {
|
||||
|
||||
Reference in New Issue
Block a user