mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 03:45:46 -06:00
fix(security): align agent roster default audit with runtime semantics (#124398)
A fresh openclaw onboard (and agents add) writes agents.entries without any default:true marker; runtime resolves the sole agent as default via tryResolveSoleAgentId, and read-time migration strips valid legacy markers before the audit ever sees the config. The audit still demanded exactly one default=true marker on non-explicit rosters, so every fresh install got a false config.agent_roster.invalid_default_count warning. Make the audit mirror runtime truth: a non-explicit roster is valid exactly when the canonical resolver (tryResolveLegacyCompatibilityAgentId) finds an owner - sole agent, one legacy marker, or the retained migration owner. Explicit fleets keep the strict no-marker rule. This also fixes the sibling false alarm for migrated legacy multi-agent configs whose marker was removed at load time with the owner retained in-process. Regression test: fresh-install-shaped sole-agent roster produces no roster finding (fails pre-fix).
This commit is contained in:
committed by
GitHub
parent
0c7b560b23
commit
345fde4e14
@@ -102,6 +102,26 @@ describe("security audit rosterless configs", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts a fresh-install sole-agent roster without a default marker", async () => {
|
||||
const { stateDir, workspaceDir } = makeAuditPaths("fresh-install-roster");
|
||||
|
||||
// `openclaw onboard` and `agents add` write markerless entries; runtime
|
||||
// resolves the sole agent as default, so the audit must not warn.
|
||||
const report = await runSecurityAuditCore({
|
||||
config: { agents: { entries: { main: {} } } } as never,
|
||||
stateDir,
|
||||
configPath: path.join(stateDir, "openclaw.json"),
|
||||
workspaceDir,
|
||||
env: {},
|
||||
includeFilesystem: true,
|
||||
includeChannelSecurity: false,
|
||||
});
|
||||
|
||||
expect(report.findings).not.toContainEqual(
|
||||
expect.objectContaining({ checkId: "config.agent_roster.invalid_default_count" }),
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
label: "an explicitly empty roster",
|
||||
|
||||
+16
-7
@@ -4,7 +4,11 @@ import { redactSensitiveUrlLikeString } from "@openclaw/net-policy/redact-sensit
|
||||
import { asNullableRecord } from "@openclaw/normalization-core/record-coerce";
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { normalizeStringEntries } from "@openclaw/normalization-core/string-normalization";
|
||||
import { hasAgentRosterProperty, listAgentEntries } from "../agents/agent-scope-config.js";
|
||||
import {
|
||||
hasAgentRosterProperty,
|
||||
listAgentEntries,
|
||||
tryResolveLegacyCompatibilityAgentId,
|
||||
} from "../agents/agent-scope-config.js";
|
||||
import { tryResolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||
import { resolveExecDefaults } from "../agents/exec-defaults.js";
|
||||
import { resolveSandboxConfigForAgent } from "../agents/sandbox/config.js";
|
||||
@@ -955,8 +959,14 @@ function collectAgentRosterFindings(cfg: OpenClawConfig): SecurityAuditFinding[]
|
||||
return [];
|
||||
}
|
||||
const defaultCount = agents.filter((agent) => agent?.default === true).length;
|
||||
const expectedDefaultCount = cfg.agents?.ownership === "explicit" ? 0 : 1;
|
||||
if (defaultCount === expectedDefaultCount) {
|
||||
const explicitOwnership = cfg.agents?.ownership === "explicit";
|
||||
// Mirror runtime default resolution: explicit fleets are ownerless by design,
|
||||
// otherwise the roster is valid exactly when the canonical resolver finds an
|
||||
// owner (sole agent, one legacy marker, or a retained migration owner).
|
||||
const resolvable = explicitOwnership
|
||||
? defaultCount === 0
|
||||
: tryResolveLegacyCompatibilityAgentId(cfg) !== undefined;
|
||||
if (resolvable) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
@@ -964,10 +974,9 @@ function collectAgentRosterFindings(cfg: OpenClawConfig): SecurityAuditFinding[]
|
||||
checkId: "config.agent_roster.invalid_default_count",
|
||||
severity: "warn",
|
||||
title: "Agent roster has an invalid default selection",
|
||||
detail:
|
||||
expectedDefaultCount === 0
|
||||
? `Expected no agents.entries default=true entries with agents.ownership=explicit, found ${defaultCount}.`
|
||||
: `Expected exactly one agents.entries default=true entry, found ${defaultCount}.`,
|
||||
detail: explicitOwnership
|
||||
? `Expected no agents.entries default=true entries with agents.ownership=explicit, found ${defaultCount}.`
|
||||
: `Expected a resolvable default agent (sole entry, one default=true marker, or agents.ownership=explicit); found ${defaultCount} default markers across ${agents.length} configured agents.`,
|
||||
remediation: "Run `openclaw doctor --fix` to repair the authored agent roster.",
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user