fix: clarify unstored exec approval defaults (#114417)

This commit is contained in:
Dallin Romney
2026-07-27 16:07:11 +08:00
committed by GitHub
parent 669db2968f
commit ec391edea7
4 changed files with 46 additions and 9 deletions

View File

@@ -169,6 +169,7 @@ function scopeByLabel(label: string, output: Record<string, unknown> = writtenJs
}
function resetLocalSnapshot() {
localSnapshot.exists = true;
localSnapshot.hash = "hash-local";
localSnapshot.file = { version: 1, agents: {} };
}
@@ -309,6 +310,17 @@ describe("exec approvals CLI", () => {
expect(runtimeErrors).toHaveLength(0);
});
it("renders an unstored fresh-install policy as defaults instead of absent", async () => {
localSnapshot.exists = false;
await runApprovalsCommand(["approvals", "get"]);
const output = defaultRuntime.log.mock.calls.map(([line]) => String(line ?? "")).join("\n");
expect(output).toContain("State");
expect(output).toContain("defaults (no stored overrides)");
expect(output).not.toContain("Exists");
});
it("adds effective policy to json output", async () => {
localSnapshot.file = {
version: 1,
@@ -329,7 +341,7 @@ describe("exec approvals CLI", () => {
expect(defaultRuntime.writeJson).toHaveBeenCalledWith(writtenJson(), 0);
const policy = effectivePolicy();
expect(String(policy.note)).toContain(
"Effective exec policy is the host approvals file intersected with requested tools.exec policy.",
"Effective exec policy is the host approvals policy intersected with requested tools.exec policy.",
);
expect(String(policy.note)).toContain(SESSION_EXEC_OVERRIDES_NOTE);
const scope = scopeByLabel("tools.exec");
@@ -430,7 +442,7 @@ describe("exec approvals CLI", () => {
expect(defaultRuntime.writeJson).toHaveBeenCalledWith(writtenJson(), 0);
const policy = effectivePolicy();
expect(String(policy.note)).toContain(
"Effective exec policy is the node host approvals file intersected with gateway tools.exec policy.",
"Effective exec policy is the node host approvals policy intersected with gateway tools.exec policy.",
);
expect(String(policy.note)).toContain(SESSION_EXEC_OVERRIDES_NOTE);
const scope = scopeByLabel("tools.exec");

View File

@@ -757,7 +757,7 @@ function buildEffectivePolicyReport(params: {
scopes: [],
note: params.nativePolicy
? "This node enforces a host-native exec policy; OpenClaw approvals-file policy math does not apply."
: "Approvals file unavailable.",
: "Host approvals policy unavailable.",
};
}
if (params.source === "node") {
@@ -784,7 +784,7 @@ function buildEffectivePolicyReport(params: {
hostDefaultSource: "node-reported resolved defaults",
}),
note:
"Effective exec policy is the node host approvals file intersected with gateway tools.exec policy. " +
"Effective exec policy is the node host approvals policy intersected with gateway tools.exec policy. " +
SESSION_EXEC_OVERRIDES_NOTE,
};
}
@@ -801,7 +801,7 @@ function buildEffectivePolicyReport(params: {
hostPath: params.hostPath,
}),
note:
"Effective exec policy is the host approvals file intersected with requested tools.exec policy. " +
"Effective exec policy is the host approvals policy intersected with requested tools.exec policy. " +
SESSION_EXEC_OVERRIDES_NOTE,
};
}
@@ -887,7 +887,10 @@ function renderApprovalsSnapshot(snapshot: ExecApprovalsSnapshot, targetLabel: s
const summaryRows = [
{ Field: "Target", Value: targetLabel },
{ Field: "Path", Value: snapshot.path },
{ Field: "Exists", Value: snapshot.exists ? "yes" : "no" },
{
Field: "State",
Value: snapshot.exists ? "stored" : "defaults (no stored overrides)",
},
{ Field: "Hash", Value: snapshot.hash },
{ Field: "Version", Value: String(file.version ?? 1) },
{ Field: "Socket", Value: file.socket?.path ?? "default" },

View File

@@ -326,6 +326,26 @@ describe("exec-policy CLI", () => {
});
});
it("renders an unstored fresh-install policy as defaults instead of missing", async () => {
mocks.readExecApprovalsSnapshot.mockImplementationOnce(() => ({
path: "~/.openclaw/state/openclaw.sqlite#exec_approvals_config",
exists: false,
raw: null,
hash: "missing-hash",
file: { version: 1, agents: {} },
}));
await runExecPolicyCommand(["exec-policy", "show"]);
const output = stripAnsi(
mocks.defaultRuntime.log.mock.calls.map((call) => String(call[0] ?? "")).join("\n"),
);
expect(output).toContain("Approvals State");
expect(output).toContain("defaults (no stored overrides)");
expect(output).not.toContain("Approvals File");
expect(output).not.toContain("missing");
});
it("marks host=node scopes as node-managed in show output", async () => {
mocks.setConfig({
tools: {

View File

@@ -287,7 +287,7 @@ async function buildLocalExecPolicyShowPayload(): Promise<ExecPolicyShowPayload>
);
const baseNote = hasNodeRuntimeScope
? "Scopes requesting host=node are node-managed at runtime. Local approvals are shown only for local/gateway scopes."
: "Effective exec policy is the host approvals file intersected with requested tools.exec policy.";
: "Effective exec policy is the host approvals policy intersected with requested tools.exec policy.";
return {
configPath: configSnapshot.path,
approvalsPath: approvalsSnapshot.path,
@@ -349,8 +349,10 @@ function renderExecPolicyShow(payload: ExecPolicyShowPayload): void {
{ Field: "Config", Value: sanitizeExecPolicyTableCell(payload.configPath) },
{ Field: "Approvals", Value: sanitizeExecPolicyTableCell(payload.approvalsPath) },
{
Field: "Approvals File",
Value: sanitizeExecPolicyTableCell(payload.approvalsExists ? "present" : "missing"),
Field: "Approvals State",
Value: sanitizeExecPolicyTableCell(
payload.approvalsExists ? "stored" : "defaults (no stored overrides)",
),
},
],
}).trimEnd(),