docs: document gateway node policies

This commit is contained in:
Peter Steinberger
2026-06-04 17:14:38 -04:00
parent fba99cddc1
commit 2da49ef4ac
8 changed files with 26 additions and 0 deletions
+2
View File
@@ -1,3 +1,5 @@
// Gateway hook routing policy helpers.
// Normalizes configured agent allowlists for hook dispatch.
import { normalizeAgentId } from "../routing/session-key.js";
// Hook policy config narrows hooks to explicit agent ids. A wildcard means no
+2
View File
@@ -1,3 +1,5 @@
// Gateway hook payload type aliases.
// Keeps hook-facing channel ids on public plugin channel contracts.
import type { ChannelId } from "../channels/plugins/types.public.js";
// Gateway hooks use public channel ids so hook payloads stay aligned with plugin
+6
View File
@@ -1,3 +1,5 @@
// Gateway node command policy.
// Computes per-platform allowlists from built-in, plugin, runtime, and config inputs.
import { normalizeOptionalLowercaseString } from "@openclaw/normalization-core/string-coerce";
import { normalizeUniqueStringEntries } from "@openclaw/normalization-core/string-normalization";
import type { OpenClawConfig } from "../config/types.openclaw.js";
@@ -292,6 +294,8 @@ function filterApprovedRuntimeCommands(params: {
if (!isDesktopPlatformId(params.platformId)) {
return [];
}
// Desktop host commands are not default-enabled for normal node sessions.
// A live node can still expose approved commands from its runtime handshake.
return params.commands.filter((command) => DESKTOP_HOST_COMMANDS.has(command.trim()));
}
@@ -338,6 +342,8 @@ function resolveNodeCommandAllowlistInternal(
const extra = cfg.gateway?.nodes?.allowCommands ?? [];
const deny = new Set(cfg.gateway?.nodes?.denyCommands ?? []);
const dangerousPluginCommands = new Set(listDangerousPluginNodeCommands());
// Dangerous plugin commands are excluded from plugin defaults. Explicit
// gateway.nodes.allowCommands below can still opt them in for operators.
const allow = new Set(
[...base, ...talkCommands, ...pluginDefaults, ...approved, ...extra]
.map((cmd) => cmd.trim())
+4
View File
@@ -1,3 +1,5 @@
// Plugin-provided node.invoke policy adapter.
// Lets plugin policies gate dangerous node commands before transport dispatch.
import { randomUUID } from "node:crypto";
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import type { PluginApprovalRequestPayload } from "../infra/plugin-approvals.js";
@@ -86,6 +88,8 @@ function createApprovalRuntime(params: {
record,
excludeConnId: params.client?.connId,
});
// Approval requests are routed to eligible operator clients only. Falling
// back to broadcast is safe because the event payload carries no secret.
if (approvalClientConnIds) {
params.context.broadcastToConnIds(
"plugin.approval.requested",
+2
View File
@@ -1,3 +1,5 @@
// Node invocation forwarding sanitizer.
// Strips or validates gateway-only control fields before node transport.
import type { ExecApprovalManager } from "./exec-approval-manager.js";
import { sanitizeSystemRunParamsForForwarding } from "./node-invoke-system-run-approval.js";
import type { GatewayClient } from "./server-methods/types.js";
@@ -1,3 +1,5 @@
// system.run approval sanitizer.
// Verifies forwarded node exec approvals against stored operator decisions.
import { asNullableRecord } from "@openclaw/normalization-core/record-coerce";
import { normalizeNullableString } from "@openclaw/normalization-core/string-coerce";
import {
@@ -1,3 +1,5 @@
// SecretRef-aware Gateway config string resolver.
// Resolves configured secret inputs and fallback values without leaking values.
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resolveSecretInputRef } from "../config/types.secrets.js";
@@ -142,6 +144,8 @@ export async function resolveConfiguredSecretInputWithFallback(params: {
if (!resolved.refConfigured) {
const fallback = params.readFallback?.();
if (fallback) {
// Fallbacks are only returned after direct config is absent, preserving
// explicit config precedence while still allowing credential stores.
return {
value: fallback,
source: "fallback",
@@ -161,6 +165,8 @@ export async function resolveConfiguredSecretInputWithFallback(params: {
const fallback = params.readFallback?.();
if (fallback) {
// An unresolved SecretRef does not block fallback credentials. Callers get
// both the source and secretRefConfigured flag for warning policy.
return {
value: fallback,
source: "fallback",
+2
View File
@@ -1,3 +1,5 @@
// Gateway secret-input path helpers.
// Lists config locations that may contain plaintext values or SecretRefs.
import type { OpenClawConfig } from "../config/types.openclaw.js";
/** Canonical Gateway config paths whose values may be plaintext or secret refs. */