openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
4,677 lines • 214 kB
JavaScript
import { l as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty, t as hasNonEmptyString } from "./string-coerce-1VuiLaaR.mjs";
import { t as asBoolean } from "./boolean-CFfzB3ix.mjs";
import { c as isRecord, t as asNonArrayRecord } from "./record-coerce-TIsquoVR.mjs";
import { d as normalizeStringEntries, f as normalizeStringEntriesLower, y as uniqueStrings } from "./string-normalization-D6DKCpwE.mjs";
import { a as coerceSecretRef } from "./types.secrets-DD-Q2SS_.mjs";
import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs";
import { n as normalizeAccountId } from "./account-id-ifCOO7_9.mjs";
import { r as normalizeProviderId } from "./provider-id-D1VImdKk.mjs";
import { l as resolveExecModePolicy } from "./exec-approvals-core-s7tTQC_a.mjs";
import { a as splitSandboxBindSpec } from "./host-paths-C5NtLpi_.mjs";
import { p as resolveExecApprovalsDisplayPath } from "./exec-approvals-migration-gate-BHpUkl4x.mjs";
import { c as readExecApprovalsSnapshot } from "./exec-approvals-store-B-TRUVtg.mjs";
import "./string-coerce-runtime-BbIJhy7G.mjs";
import { o as resolveAgentRoute } from "./resolve-route-DeZAxBYa.mjs";
import { i as hasConfiguredAccountValue } from "./account-helpers-ATUS5rKM.mjs";
import "./routing-DvCc0aVb.mjs";
import "./secret-input-B0WNzmEZ.mjs";
import "./provider-model-shared-CFGX5pNa.mjs";
import "./exec-approvals-runtime-DDl-BZcB.mjs";
import { m as toolPolicy } from "./agent-harness-runtime-C1yVhaNg.mjs";
import "./account-helpers-B8_pbmvH.mjs";
import { basename, isAbsolute, resolve } from "node:path";
import { createHash } from "node:crypto";
import JSON5 from "json5";
//#region extensions/policy/src/doctor/check-ids.ts
const CHECK_IDS = {
policyMissingFile: "policy/policy-jsonc-missing",
policyInvalidFile: "policy/policy-jsonc-invalid",
policyUnmigratedToolsFile: "policy/tools-md-migration-required",
policyHashMismatch: "policy/policy-hash-mismatch",
policyAttestationMismatch: "policy/attestation-hash-mismatch",
policyDeniedChannelProvider: "policy/channels-denied-provider",
policyDeniedMcpServer: "policy/mcp-denied-server",
policyUnapprovedMcpServer: "policy/mcp-unapproved-server",
policyDeniedModelProvider: "policy/models-denied-provider",
policyUnapprovedModelProvider: "policy/models-unapproved-provider",
policyPrivateNetworkAccess: "policy/network-private-access-enabled",
policyRoutingBindingsRequired: "policy/routing-bindings-required",
policyRoutingBindingChannelUnconfigured: "policy/routing-binding-channel-unconfigured",
policyRoutingAgentMismatch: "policy/routing-agent-mismatch",
policyRoutingMatchKindMismatch: "policy/routing-match-kind-mismatch",
policyIngressDmPolicyUnapproved: "policy/ingress-dm-policy-unapproved",
policyIngressDmScopeUnapproved: "policy/ingress-dm-scope-unapproved",
policyIngressOpenGroupsDenied: "policy/ingress-open-groups-denied",
policyIngressGroupMentionRequired: "policy/ingress-group-mention-required",
policyGatewayNonLoopbackBind: "policy/gateway-non-loopback-bind",
policyGatewayAuthDisabled: "policy/gateway-auth-disabled",
policyGatewayRateLimitMissing: "policy/gateway-rate-limit-missing",
policyGatewayControlUiInsecure: "policy/gateway-control-ui-insecure",
policyGatewayTailscaleFunnel: "policy/gateway-tailscale-funnel",
policyGatewayRemoteEnabled: "policy/gateway-remote-enabled",
policyGatewayHttpEndpointEnabled: "policy/gateway-http-endpoint-enabled",
policyGatewayHttpUrlFetchUnrestricted: "policy/gateway-http-url-fetch-unrestricted",
policyGatewayNodeCommandDenied: "policy/gateway-node-command-denied",
policyAgentsWorkspaceAccessDenied: "policy/agents-workspace-access-denied",
policyAgentsToolNotDenied: "policy/agents-tool-not-denied",
policyToolsProfileUnapproved: "policy/tools-profile-unapproved",
policyToolsFsWorkspaceOnlyRequired: "policy/tools-fs-workspace-only-required",
policyToolsExecSecurityUnapproved: "policy/tools-exec-security-unapproved",
policyToolsExecAskUnapproved: "policy/tools-exec-ask-unapproved",
policyToolsExecHostUnapproved: "policy/tools-exec-host-unapproved",
policyToolsElevatedEnabled: "policy/tools-elevated-enabled",
policyToolsAlsoAllowMissing: "policy/tools-also-allow-missing",
policyToolsAlsoAllowUnexpected: "policy/tools-also-allow-unexpected",
policyToolsRequiredDenyMissing: "policy/tools-required-deny-missing",
policySandboxModeUnapproved: "policy/sandbox-mode-unapproved",
policySandboxBackendUnapproved: "policy/sandbox-backend-unapproved",
policySandboxContainerPostureUnobservable: "policy/sandbox-container-posture-unobservable",
policySandboxContainerHostNetworkDenied: "policy/sandbox-container-host-network-denied",
policySandboxContainerNamespaceJoinDenied: "policy/sandbox-container-namespace-join-denied",
policySandboxContainerMountModeRequired: "policy/sandbox-container-mount-mode-required",
policySandboxContainerRuntimeSocketMount: "policy/sandbox-container-runtime-socket-mount",
policySandboxContainerUnconfinedProfile: "policy/sandbox-container-unconfined-profile",
policySandboxBrowserCdpSourceRangeMissing: "policy/sandbox-browser-cdp-source-range-missing",
policyDataHandlingTelemetryContentCapture: "policy/data-handling-telemetry-content-capture",
policyDataHandlingSessionRetentionNotEnforced: "policy/data-handling-session-retention-not-enforced",
policyDataHandlingSessionTranscriptMemory: "policy/data-handling-session-transcript-memory-enabled",
policySecretsUnmanagedProvider: "policy/secrets-unmanaged-provider",
policySecretsDeniedProviderSource: "policy/secrets-denied-provider-source",
policySecretsInsecureProvider: "policy/secrets-insecure-provider",
policyAuthProfileInvalidMetadata: "policy/auth-profile-invalid-metadata",
policyAuthProfileUnapprovedMode: "policy/auth-profile-unapproved-mode",
policyExecApprovalsMissing: "policy/exec-approvals-missing",
policyExecApprovalsInvalid: "policy/exec-approvals-invalid",
policyExecApprovalsDefaultSecurityUnapproved: "policy/exec-approvals-default-security-unapproved",
policyExecApprovalsAgentSecurityUnapproved: "policy/exec-approvals-agent-security-unapproved",
policyExecApprovalsAutoAllowSkillsEnabled: "policy/exec-approvals-auto-allow-skills-enabled",
policyExecApprovalsAllowlistMissing: "policy/exec-approvals-allowlist-missing",
policyExecApprovalsAllowlistUnexpected: "policy/exec-approvals-allowlist-unexpected",
policyMissingToolRisk: "policy/tools-missing-risk-level",
policyUnknownToolRisk: "policy/tools-unknown-risk-level",
policyMissingToolSensitivity: "policy/tools-missing-sensitivity-token",
policyMissingToolOwner: "policy/tools-missing-owner",
policyUnknownToolSensitivity: "policy/tools-unknown-sensitivity-token"
};
const POLICY_CHECK_IDS = Object.values(CHECK_IDS);
//#endregion
//#region extensions/policy/src/exec-approvals-uri.ts
const EXEC_APPROVALS_POLICY_URI = "oc://exec-approvals.json";
const EXEC_APPROVALS_POLICY_DOCUMENT_NAME = EXEC_APPROVALS_POLICY_URI.slice(5);
function execApprovalsPolicyUri(relativePath) {
return relativePath ? `${EXEC_APPROVALS_POLICY_URI}/${relativePath}` : EXEC_APPROVALS_POLICY_URI;
}
//#endregion
//#region extensions/policy/src/doctor/metadata.ts
function booleanRule(path, checkId, required, options = {}) {
return {
policyPath: path.split("."),
strictness: required ? "requires-true" : "requires-false",
valueType: "boolean",
checkIds: [checkId],
...options
};
}
function allowlistRule(path, checkId, options = {}) {
return {
policyPath: path.split("."),
strictness: "allowlist-subset",
valueType: "string-list",
checkIds: [checkId],
emptyList: "disabled",
...options
};
}
function denylistRule(path, checkId, options = {}) {
return {
policyPath: path.split("."),
strictness: "denylist-superset",
valueType: "string-list",
checkIds: [checkId],
...options
};
}
const SANDBOX_CONTAINER_POLICY_RULES = [
{
key: "denyHostNetwork",
label: "host network posture",
checkIds: [CHECK_IDS.policySandboxContainerHostNetworkDenied]
},
{
key: "denyContainerNamespaceJoin",
label: "container namespace posture",
checkIds: [CHECK_IDS.policySandboxContainerNamespaceJoinDenied]
},
{
key: "requireReadOnlyMounts",
label: "container mount mode posture",
checkIds: [CHECK_IDS.policySandboxContainerMountModeRequired]
},
{
key: "denyContainerRuntimeSocketMounts",
label: "container runtime socket mount posture",
checkIds: [CHECK_IDS.policySandboxContainerRuntimeSocketMount]
},
{
key: "denyUnconfinedProfiles",
label: "container security profile posture",
checkIds: [CHECK_IDS.policySandboxContainerUnconfinedProfile]
}
];
const SANDBOX_POLICY_RULE_METADATA = [
allowlistRule("sandbox.requireMode", CHECK_IDS.policySandboxModeUnapproved, {
allowedValues: [
"off",
"non-main",
"all"
],
scopeSelectors: ["agentIds"]
}),
allowlistRule("sandbox.allowBackends", CHECK_IDS.policySandboxBackendUnapproved, { scopeSelectors: ["agentIds"] }),
...SANDBOX_CONTAINER_POLICY_RULES.map((rule) => ({
policyPath: [
"sandbox",
"containers",
rule.key
],
strictness: "requires-true",
valueType: "boolean",
checkIds: rule.checkIds,
scopeSelectors: ["agentIds"]
})),
booleanRule("sandbox.browser.requireCdpSourceRange", CHECK_IDS.policySandboxBrowserCdpSourceRangeMissing, true, { scopeSelectors: ["agentIds"] })
];
const POLICY_RULE_METADATA = [
{
policyPath: ["channels", "denyRules"],
strictness: "denylist-superset",
valueType: "channel-provider-deny-rules",
checkIds: [CHECK_IDS.policyDeniedChannelProvider],
emptyList: "meaningful",
caseSensitive: true
},
allowlistRule("mcp.servers.allow", CHECK_IDS.policyUnapprovedMcpServer, { caseSensitive: true }),
denylistRule("mcp.servers.deny", CHECK_IDS.policyDeniedMcpServer, { caseSensitive: true }),
allowlistRule("models.providers.allow", CHECK_IDS.policyUnapprovedModelProvider, { normalizeValues: "model-provider" }),
denylistRule("models.providers.deny", CHECK_IDS.policyDeniedModelProvider, { normalizeValues: "model-provider" }),
booleanRule("network.privateNetwork.allow", CHECK_IDS.policyPrivateNetworkAccess, false),
booleanRule("routing.requireBindings", CHECK_IDS.policyRoutingBindingsRequired, true),
booleanRule("routing.requireConfiguredChannels", CHECK_IDS.policyRoutingBindingChannelUnconfigured, true),
{
policyPath: ["routing", "probes"],
strictness: "routing-probes",
valueType: "routing-probes",
checkIds: [CHECK_IDS.policyRoutingAgentMismatch, CHECK_IDS.policyRoutingMatchKindMismatch]
},
{
policyPath: [
"ingress",
"session",
"requireDmScope"
],
strictness: "ordered-string",
valueType: "string",
orderedValues: [
"main",
"per-peer",
"per-channel-peer",
"per-account-channel-peer"
],
checkIds: [CHECK_IDS.policyIngressDmScopeUnapproved]
},
booleanRule("gateway.exposure.allowNonLoopbackBind", CHECK_IDS.policyGatewayNonLoopbackBind, false),
booleanRule("gateway.exposure.allowTailscaleFunnel", CHECK_IDS.policyGatewayTailscaleFunnel, false),
booleanRule("gateway.auth.requireAuth", CHECK_IDS.policyGatewayAuthDisabled, true),
booleanRule("gateway.auth.requireExplicitRateLimit", CHECK_IDS.policyGatewayRateLimitMissing, true),
booleanRule("gateway.controlUi.allowInsecure", CHECK_IDS.policyGatewayControlUiInsecure, false),
booleanRule("gateway.remote.allow", CHECK_IDS.policyGatewayRemoteEnabled, false),
denylistRule("gateway.http.denyEndpoints", CHECK_IDS.policyGatewayHttpEndpointEnabled, {
allowedValues: ["chatCompletions", "responses"],
caseSensitive: true
}),
booleanRule("gateway.http.requireUrlAllowlists", CHECK_IDS.policyGatewayHttpUrlFetchUnrestricted, true),
denylistRule("gateway.nodes.denyCommands", CHECK_IDS.policyGatewayNodeCommandDenied, { caseSensitive: true }),
allowlistRule("agents.workspace.allowedAccess", CHECK_IDS.policyAgentsWorkspaceAccessDenied, {
allowedValues: [
"none",
"ro",
"rw"
],
scopeSelectors: ["agentIds"]
}),
denylistRule("agents.workspace.denyTools", CHECK_IDS.policyAgentsToolNotDenied, {
allowedValues: [
"exec",
"process",
"write",
"edit",
"apply_patch"
],
scopeSelectors: ["agentIds"]
}),
allowlistRule("tools.profiles.allow", CHECK_IDS.policyToolsProfileUnapproved, {
allowedValues: [
"minimal",
"coding",
"messaging",
"full"
],
scopeSelectors: ["agentIds"]
}),
booleanRule("tools.fs.requireWorkspaceOnly", CHECK_IDS.policyToolsFsWorkspaceOnlyRequired, true, { scopeSelectors: ["agentIds"] }),
allowlistRule("tools.exec.allowSecurity", CHECK_IDS.policyToolsExecSecurityUnapproved, {
allowedValues: [
"deny",
"allowlist",
"full"
],
scopeSelectors: ["agentIds"]
}),
allowlistRule("tools.exec.requireAsk", CHECK_IDS.policyToolsExecAskUnapproved, {
allowedValues: [
"off",
"on-miss",
"always"
],
scopeSelectors: ["agentIds"]
}),
allowlistRule("tools.exec.allowHosts", CHECK_IDS.policyToolsExecHostUnapproved, {
allowedValues: [
"auto",
"sandbox",
"gateway",
"node"
],
scopeSelectors: ["agentIds"]
}),
booleanRule("tools.elevated.allow", CHECK_IDS.policyToolsElevatedEnabled, false, { scopeSelectors: ["agentIds"] }),
{
policyPath: [
"tools",
"alsoAllow",
"expected"
],
strictness: "exact-list",
valueType: "string-list",
checkIds: [CHECK_IDS.policyToolsAlsoAllowMissing, CHECK_IDS.policyToolsAlsoAllowUnexpected],
emptyList: "meaningful",
scopeSelectors: ["agentIds"]
},
denylistRule("tools.denyTools", CHECK_IDS.policyToolsRequiredDenyMissing, { scopeSelectors: ["agentIds"] }),
{
policyPath: ["tools", "requireMetadata"],
strictness: "denylist-superset",
valueType: "string-list",
checkIds: [
CHECK_IDS.policyUnmigratedToolsFile,
CHECK_IDS.policyMissingToolRisk,
CHECK_IDS.policyMissingToolSensitivity,
CHECK_IDS.policyMissingToolOwner
],
allowedValues: [
"risk",
"sensitivity",
"owner"
]
},
...SANDBOX_POLICY_RULE_METADATA,
allowlistRule("ingress.channels.allowDmPolicies", CHECK_IDS.policyIngressDmPolicyUnapproved, {
allowedValues: [
"pairing",
"allowlist",
"open",
"disabled"
],
scopeSelectors: ["channelIds"]
}),
booleanRule("ingress.channels.denyOpenGroups", CHECK_IDS.policyIngressOpenGroupsDenied, true, { scopeSelectors: ["channelIds"] }),
booleanRule("ingress.channels.requireMentionInGroups", CHECK_IDS.policyIngressGroupMentionRequired, true, { scopeSelectors: ["channelIds"] }),
{
policyPath: [
"dataHandling",
"sensitiveLogging",
"requireRedaction"
],
strictness: "requires-true",
valueType: "boolean",
checkIds: [],
satisfiedByInvariant: "oc://openclaw.invariant/logging/redaction"
},
booleanRule("dataHandling.telemetry.denyContentCapture", CHECK_IDS.policyDataHandlingTelemetryContentCapture, true),
booleanRule("dataHandling.retention.requireSessionMaintenance", CHECK_IDS.policyDataHandlingSessionRetentionNotEnforced, true),
booleanRule("dataHandling.memory.denySessionTranscriptIndexing", CHECK_IDS.policyDataHandlingSessionTranscriptMemory, true, { scopeSelectors: ["agentIds"] }),
booleanRule("secrets.requireManagedProviders", CHECK_IDS.policySecretsUnmanagedProvider, true),
denylistRule("secrets.denySources", CHECK_IDS.policySecretsDeniedProviderSource),
booleanRule("secrets.allowInsecureProviders", CHECK_IDS.policySecretsInsecureProvider, false),
booleanRule("execApprovals.requireFile", CHECK_IDS.policyExecApprovalsMissing, true),
allowlistRule("execApprovals.defaults.allowSecurity", CHECK_IDS.policyExecApprovalsDefaultSecurityUnapproved, { allowedValues: [
"deny",
"allowlist",
"full"
] }),
allowlistRule("execApprovals.agents.allowSecurity", CHECK_IDS.policyExecApprovalsAgentSecurityUnapproved, {
allowedValues: [
"deny",
"allowlist",
"full"
],
scopeSelectors: ["agentIds"]
}),
booleanRule("execApprovals.agents.allowAutoAllowSkills", CHECK_IDS.policyExecApprovalsAutoAllowSkillsEnabled, false, { scopeSelectors: ["agentIds"] }),
{
policyPath: [
"execApprovals",
"agents",
"allowlist",
"expected"
],
strictness: "exact-list",
valueType: "string-list",
checkIds: [CHECK_IDS.policyExecApprovalsAllowlistMissing, CHECK_IDS.policyExecApprovalsAllowlistUnexpected],
emptyList: "meaningful",
caseSensitive: true,
scopeSelectors: ["agentIds"]
},
denylistRule("auth.profiles.requireMetadata", CHECK_IDS.policyAuthProfileInvalidMetadata, { allowedValues: ["provider", "mode"] }),
allowlistRule("auth.profiles.allowModes", CHECK_IDS.policyAuthProfileUnapprovedMode, { allowedValues: [
"api_key",
"aws-sdk",
"oauth",
"token"
] })
];
//#endregion
//#region extensions/policy/src/doctor/fix-metadata.ts
const defineCheck = (checkId, description, fixClass, summary, configTargets, policyPath = POLICY_RULE_METADATA.find((rule) => rule.checkIds.includes(checkId))?.policyPath) => {
return {
description,
fix: {
checkId,
fixClass,
summary,
...policyPath === void 0 ? {} : { policyPath },
...configTargets === void 0 ? {} : { configTargets }
}
};
};
const POLICY_CHECK_METADATA = [
defineCheck(CHECK_IDS.policyMissingFile, "The enabled Policy plugin has a policy file to verify.", "manual", "Restore or author the approved policy artifact."),
defineCheck(CHECK_IDS.policyInvalidFile, "The enabled policy file parses before policy checks run.", "manual", "Repair the policy JSONC syntax or schema."),
defineCheck(CHECK_IDS.policyHashMismatch, "The policy file matches the configured expected hash.", "manual", "Restore the approved artifact or update the expected hash after review.", ["plugins.entries.policy.config.expectedHash"]),
defineCheck(CHECK_IDS.policyAttestationMismatch, "The current policy check matches the accepted attestation.", "manual", "Review the current attestation and update accepted hashes after approval.", ["plugins.entries.policy.config.expectedAttestationHash"]),
defineCheck(CHECK_IDS.policyDeniedChannelProvider, "Configured channels satisfy policy deny rules.", "automatic", "Disable product-managed channels matching the denied provider.", ["channels"]),
defineCheck(CHECK_IDS.policyDeniedMcpServer, "Configured MCP servers do not match policy deny rules.", "reviewRequired", "Remove or disable the denied MCP server.", ["mcp.servers"]),
defineCheck(CHECK_IDS.policyUnapprovedMcpServer, "Configured MCP servers do not match policy allow rules.", "reviewRequired", "Remove the unapproved MCP server or select an approved replacement.", ["mcp.servers"]),
defineCheck(CHECK_IDS.policyDeniedModelProvider, "Configured model providers do not match policy deny rules.", "reviewRequired", "Remove the model provider or switch references to an approved provider.", ["models"]),
defineCheck(CHECK_IDS.policyUnapprovedModelProvider, "Configured model providers do not match policy allow rules.", "reviewRequired", "Select an approved model provider.", ["models"]),
defineCheck(CHECK_IDS.policyPrivateNetworkAccess, "Network SSRF policy settings match private-network requirements.", "reviewRequired", "Disable the concrete private-network access opt-in.", ["network"]),
defineCheck(CHECK_IDS.policyIngressDmPolicyUnapproved, "Channel direct-message access policy matches ingress requirements.", "reviewRequired", "Set channel DM policy to an allowed value.", ["channels"]),
defineCheck(CHECK_IDS.policyIngressDmScopeUnapproved, "Direct-message sessions use the policy-required isolation scope.", "reviewRequired", "Move session DM scope to the required or stricter ordered value.", ["ingress"]),
defineCheck(CHECK_IDS.policyIngressOpenGroupsDenied, "Channel group access does not use open group policy when denied.", "automatic", "Disable product-managed open group ingress.", ["channels"]),
defineCheck(CHECK_IDS.policyIngressGroupMentionRequired, "Channel group access keeps mention gates enabled when required.", "automatic", "Require mention in product-managed group channels.", ["channels"]),
defineCheck(CHECK_IDS.policyRoutingBindingsRequired, "Routing policy has at least one channel route binding when required.", "reviewRequired", "Add an intentional channel route binding or revise the policy after review.", ["bindings"]),
defineCheck(CHECK_IDS.policyRoutingBindingChannelUnconfigured, "Route bindings name channels present in configuration.", "reviewRequired", "Correct the binding channel or configure the intended channel after review.", ["bindings", "channels"]),
defineCheck(CHECK_IDS.policyRoutingAgentMismatch, "Authored routing checks resolve to their expected agents.", "reviewRequired", "Review binding precedence and the expected agent before changing message delivery.", ["bindings"]),
defineCheck(CHECK_IDS.policyRoutingMatchKindMismatch, "Authored routing checks match at their expected specificity.", "reviewRequired", "Restore the intended binding specificity or approve the new match kind.", ["bindings"]),
defineCheck(CHECK_IDS.policyGatewayNonLoopbackBind, "Gateway bind posture matches policy exposure requirements.", "reviewRequired", "Set gateway bind address to loopback when remote exposure is not intended.", ["gateway.bind"]),
defineCheck(CHECK_IDS.policyGatewayAuthDisabled, "Gateway authentication remains enabled when required by policy.", "manual", "Configure token, password, or trusted-proxy auth.", ["gateway.auth"]),
defineCheck(CHECK_IDS.policyGatewayRateLimitMissing, "Gateway authentication rate-limit posture is explicit when required by policy.", "reviewRequired", "Add explicit gateway auth rate limits from product defaults.", ["gateway.auth.rateLimit"]),
defineCheck(CHECK_IDS.policyGatewayControlUiInsecure, "Gateway Control UI insecure exposure toggles remain disabled by policy.", "automatic", "Disable the insecure Control UI toggle.", ["gateway.controlUi"]),
defineCheck(CHECK_IDS.policyGatewayTailscaleFunnel, "Gateway Tailscale Funnel exposure matches policy.", "reviewRequired", "Disable Tailscale funnel or serve exposure.", ["tailscale"]),
defineCheck(CHECK_IDS.policyGatewayRemoteEnabled, "Remote gateway mode matches policy.", "automatic", "Disable product-managed remote gateway mode.", ["gateway.remote"]),
defineCheck(CHECK_IDS.policyGatewayHttpEndpointEnabled, "Gateway HTTP API endpoints match policy.", "automatic", "Disable denied Gateway HTTP endpoints.", ["gateway.http"]),
defineCheck(CHECK_IDS.policyGatewayHttpUrlFetchUnrestricted, "Gateway HTTP URL-fetch inputs have allowlists when required by policy.", "manual", "Add URL allowlists for each URL-fetch input.", ["gateway.http"]),
defineCheck(CHECK_IDS.policyGatewayNodeCommandDenied, "Gateway node command allowlists match policy.", "reviewRequired", "Add the command to gateway node denyCommands or update policy after review.", ["gateway.nodes.commands.deny"]),
defineCheck(CHECK_IDS.policyAgentsWorkspaceAccessDenied, "Agent sandbox workspace access matches policy.", "reviewRequired", "Set agent workspace access to an allowed mode.", ["agents"]),
defineCheck(CHECK_IDS.policyAgentsToolNotDenied, "Agent workspace mutation/runtime tools are denied when policy requires it.", "automatic", "Merge required built-in workspace tool denies.", ["agents"]),
defineCheck(CHECK_IDS.policyToolsProfileUnapproved, "Configured tool profiles match policy allow rules.", "reviewRequired", "Set the tool profile to an allowed profile.", ["tools.profile"]),
defineCheck(CHECK_IDS.policyToolsFsWorkspaceOnlyRequired, "Filesystem tools use workspace-only posture when policy requires it.", "reviewRequired", "Set workspace-only filesystem posture when required assets remain readable.", ["tools.fs.workspaceOnly"]),
defineCheck(CHECK_IDS.policyToolsExecSecurityUnapproved, "Exec tool security mode matches policy allow rules.", "reviewRequired", "Set exec security to an allowed value.", ["tools.exec.security"]),
defineCheck(CHECK_IDS.policyToolsExecAskUnapproved, "Exec tool ask mode matches policy allow rules.", "reviewRequired", "Set exec ask mode to an allowed value.", ["tools.exec.ask"]),
defineCheck(CHECK_IDS.policyToolsExecHostUnapproved, "Exec tool host routing matches policy allow rules.", "reviewRequired", "Move exec host to an allowed host mode.", ["tools.exec.host"]),
defineCheck(CHECK_IDS.policyToolsElevatedEnabled, "Elevated tool mode remains disabled when policy requires it.", "automatic", "Set tools elevated mode to disabled.", ["tools.elevated.enabled"]),
defineCheck(CHECK_IDS.policyToolsAlsoAllowMissing, "Configured tools.alsoAllow entries include policy expected lists.", "reviewRequired", "Add expected alsoAllow entries only when policy intentionally grants them.", ["tools.alsoAllow"]),
defineCheck(CHECK_IDS.policyToolsAlsoAllowUnexpected, "Configured tools.alsoAllow entries match policy expected lists.", "reviewRequired", "Remove unexpected alsoAllow entries.", ["tools.alsoAllow"]),
defineCheck(CHECK_IDS.policyToolsRequiredDenyMissing, "Configured tool deny lists include tools required by policy.", "automatic", "Merge required built-in deny tool classes.", ["tools.deny", "agents.entries.<id>.tools.deny"]),
defineCheck(CHECK_IDS.policySandboxModeUnapproved, "Sandbox mode config satisfies policy requirements.", "reviewRequired", "Set sandbox mode to an allowed value.", ["sandbox.mode"]),
defineCheck(CHECK_IDS.policySandboxBackendUnapproved, "Sandbox backend config satisfies policy requirements.", "reviewRequired", "Choose an approved sandbox backend that is installed.", ["sandbox.backend"]),
defineCheck(CHECK_IDS.policySandboxContainerPostureUnobservable, "Sandbox container posture policy only targets observable container backends.", "unsupported", "Add observable container posture evidence before patching."),
defineCheck(CHECK_IDS.policySandboxContainerHostNetworkDenied, "Sandbox container config avoids host network mode.", "reviewRequired", "Disable container host networking.", ["sandbox.containers"]),
defineCheck(CHECK_IDS.policySandboxContainerNamespaceJoinDenied, "Sandbox container config avoids joining another container network namespace.", "reviewRequired", "Disable joining container namespaces.", ["sandbox.containers"]),
defineCheck(CHECK_IDS.policySandboxContainerMountModeRequired, "Sandbox container mounts are read-only when policy requires it.", "reviewRequired", "Change required mounts to read-only.", ["sandbox.containers"]),
defineCheck(CHECK_IDS.policySandboxContainerRuntimeSocketMount, "Sandbox container mounts avoid host container runtime sockets.", "reviewRequired", "Remove container runtime socket binds.", ["sandbox.containers"]),
defineCheck(CHECK_IDS.policySandboxContainerUnconfinedProfile, "Sandbox container profile config avoids unconfined profiles.", "reviewRequired", "Remove unconfined container profiles.", ["sandbox.containers"]),
defineCheck(CHECK_IDS.policySandboxBrowserCdpSourceRangeMissing, "Sandbox browser CDP config includes a source range when policy requires it.", "manual", "Add an explicit browser CDP source range.", ["agents.sandbox.browser"]),
defineCheck(CHECK_IDS.policyDataHandlingTelemetryContentCapture, "Telemetry content capture remains disabled when policy denies it.", "automatic", "Disable telemetry content capture.", ["diagnostics.otel.captureContent"]),
defineCheck(CHECK_IDS.policyDataHandlingSessionRetentionNotEnforced, "Session retention maintenance is enforced when policy requires it.", "reviewRequired", "Set session maintenance to enforced mode.", ["session.maintenance.mode"]),
defineCheck(CHECK_IDS.policyDataHandlingSessionTranscriptMemory, "Session transcript memory indexing remains disabled when policy denies it.", "reviewRequired", "Disable transcript indexing for the affected agent scope.", ["memory"]),
defineCheck(CHECK_IDS.policySecretsUnmanagedProvider, "OpenClaw config SecretRefs use configured secret providers when policy requires managed providers.", "manual", "Migrate the secret to a managed provider.", ["secrets"]),
defineCheck(CHECK_IDS.policySecretsDeniedProviderSource, "OpenClaw config secret providers and SecretRefs do not use sources denied by policy.", "reviewRequired", "Move the secret out of the denied source.", ["secrets"]),
defineCheck(CHECK_IDS.policySecretsInsecureProvider, "Configured secret providers do not opt into insecure posture unless policy allows it.", "reviewRequired", "Remove insecure provider overrides.", ["secrets"]),
defineCheck(CHECK_IDS.policyAuthProfileInvalidMetadata, "OpenClaw config auth profiles declare required provider and mode metadata.", "manual", "Add required provider and mode metadata to auth profiles.", ["auth.profiles"]),
defineCheck(CHECK_IDS.policyAuthProfileUnapprovedMode, "OpenClaw config auth profile modes stay within the policy allowlist.", "manual", "Change auth mode and credentials through the auth owner flow.", ["auth.profiles"]),
defineCheck(CHECK_IDS.policyExecApprovalsMissing, "Required exec approvals artifact is present for policy conformance.", "manual", "Restore an attributable exec-approvals evidence file.", [EXEC_APPROVALS_POLICY_DOCUMENT_NAME]),
defineCheck(CHECK_IDS.policyExecApprovalsInvalid, "Exec approvals artifact parses before policy checks run.", "manual", "Repair the exec approvals evidence artifact."),
defineCheck(CHECK_IDS.policyExecApprovalsDefaultSecurityUnapproved, "Exec approval defaults use a policy-approved security mode.", "manual", "Update reviewed default approval evidence or policy.", [EXEC_APPROVALS_POLICY_DOCUMENT_NAME]),
defineCheck(CHECK_IDS.policyExecApprovalsAgentSecurityUnapproved, "Per-agent exec approval settings use policy-approved security modes.", "manual", "Update reviewed agent approval evidence or policy.", [EXEC_APPROVALS_POLICY_DOCUMENT_NAME]),
defineCheck(CHECK_IDS.policyExecApprovalsAutoAllowSkillsEnabled, "Exec approval agents do not implicitly auto-allow skill CLIs unless policy allows it.", "reviewRequired", "Disable auto-allow skills in the approval owner surface.", [EXEC_APPROVALS_POLICY_DOCUMENT_NAME]),
defineCheck(CHECK_IDS.policyExecApprovalsAllowlistMissing, "Exec approval allowlists include every pattern required by policy.", "manual", "Add expected approval patterns through approval review.", [EXEC_APPROVALS_POLICY_DOCUMENT_NAME]),
defineCheck(CHECK_IDS.policyExecApprovalsAllowlistUnexpected, "Exec approval allowlists do not contain patterns outside policy.", "manual", "Remove unexpected approval patterns through approval review.", [EXEC_APPROVALS_POLICY_DOCUMENT_NAME]),
defineCheck(CHECK_IDS.policyUnmigratedToolsFile, "Governed tool declarations have been migrated from TOOLS.md into AGENTS.md.", "manual", "Run openclaw doctor --fix to migrate governed tool declarations into AGENTS.md."),
defineCheck(CHECK_IDS.policyMissingToolRisk, "AGENTS.md tool policy entries declare explicit risk levels.", "manual", "Add tool risk metadata in the owning tool declaration.", ["tools"]),
defineCheck(CHECK_IDS.policyUnknownToolRisk, "AGENTS.md tool policy entries use known risk levels.", "manual", "Use a supported tool risk level.", ["tools"], ["tools", "requireMetadata"]),
defineCheck(CHECK_IDS.policyMissingToolSensitivity, "AGENTS.md tool policy entries declare default artifact sensitivity.", "manual", "Add tool sensitivity metadata in the owning tool declaration.", ["tools"]),
defineCheck(CHECK_IDS.policyMissingToolOwner, "AGENTS.md tool policy entries declare an accountable owner.", "manual", "Add owner metadata in the owning tool declaration.", ["tools"]),
defineCheck(CHECK_IDS.policyUnknownToolSensitivity, "AGENTS.md tool policy entries use known sensitivity levels.", "manual", "Use a supported tool sensitivity token.", ["tools"], ["tools", "requireMetadata"])
];
const POLICY_FIX_METADATA_BY_CHECK_ID = new Map(POLICY_CHECK_METADATA.toSorted((left, right) => POLICY_CHECK_IDS.indexOf(left.fix.checkId) - POLICY_CHECK_IDS.indexOf(right.fix.checkId)).map(({ fix }) => [fix.checkId, fix]));
//#endregion
//#region extensions/policy/src/doctor/policy-constants.ts
const KNOWN_RISK_LEVELS = [
"low",
"medium",
"high",
"critical"
];
const KNOWN_SENSITIVITY_LEVELS = [
"public",
"internal",
"confidential",
"restricted"
];
const SUPPORTED_TOOL_METADATA = [
"risk",
"sensitivity",
"owner"
];
const SUPPORTED_AUTH_PROFILE_METADATA = ["provider", "mode"];
const SUPPORTED_AUTH_PROFILE_MODES = [
"api_key",
"aws-sdk",
"oauth",
"token"
];
const SUPPORTED_POLICY_SECTIONS = [
"auth",
"agents",
"channels",
"dataHandling",
"execApprovals",
"gateway",
"ingress",
"mcp",
"models",
"network",
"routing",
"sandbox",
"scopes",
"secrets",
"tools"
];
const SUPPORTED_DM_POLICIES = [
"pairing",
"allowlist",
"open",
"disabled"
];
const SUPPORTED_DM_SCOPES = [
"main",
"per-peer",
"per-channel-peer",
"per-account-channel-peer"
];
const SUPPORTED_EXEC_APPROVAL_SECURITY = [
"deny",
"allowlist",
"full"
];
//#endregion
//#region extensions/policy/src/doctor/shape-helpers.ts
function unsupportedPolicyKey(value, allowedKeys) {
const allowed = new Set(allowedKeys);
return Object.keys(value).find((key) => !allowed.has(key));
}
function isChannelDenyRule(value) {
return isRecord(value) && (value.id === void 0 || typeof value.id === "string") && (value.reason === void 0 || typeof value.reason === "string") && isRecord(value.when) && typeof value.when.provider === "string";
}
function policyShapeFinding(policyPath, target, message, fixHint) {
return {
checkId: CHECK_IDS.policyInvalidFile,
severity: "error",
message,
source: "policy",
path: policyPath,
target,
fixHint
};
}
//#endregion
//#region extensions/policy/src/policy-value.ts
function getPolicyPath(value, path) {
let current = value;
for (const part of path) {
if (!isRecord(current)) return;
current = current[part];
}
return current;
}
//#endregion
//#region extensions/policy/src/policy-state-helpers.ts
function ocPathSegment$1(value) {
if (/^(?:[A-Za-z0-9_-]+|#\d+)$/.test(value)) return value;
if (value.includes("\"") || value.includes("\\")) return value;
return `"${value}"`;
}
function readBooleanPath(value, path) {
const current = getPolicyPath(value, path);
return typeof current === "boolean" ? current : void 0;
}
function collectPolicyConfiguredAgents(agents) {
const entries = agents.entries;
if (Object.hasOwn(agents, "entries") && entries !== void 0) return isRecord(entries) ? Object.entries(entries).toSorted(([a], [b]) => a.localeCompare(b)).map(([agentId, value]) => ({
agentId,
sourceBase: `oc://openclaw.config/agents/entries/${ocPathSegment$1(agentId)}`,
value
})) : [];
return Array.isArray(agents.list) ? agents.list.map((value, index) => ({
agentId: isRecord(value) && typeof value.id === "string" && value.id.trim() !== "" ? value.id.trim() : `agent-${index}`,
sourceBase: `oc://openclaw.config/agents/list/#${index}`,
value
})) : [];
}
function resolvePolicyValue(local, inherited, fallback) {
return {
value: local ?? inherited ?? fallback,
explicit: local !== void 0 || inherited !== void 0,
inherited: local === void 0 && inherited !== void 0
};
}
//#endregion
//#region extensions/policy/src/doctor/utils.ts
function readPolicyStringArray(policy, path, options = {}) {
const current = getPolicyPath(policy, path);
if (!Array.isArray(current) || !current.every((entry) => typeof entry === "string")) return;
return options.lowercase === false ? normalizeStringEntries(current) : normalizeStringEntriesLower(current);
}
function readStringList(policy, path, options) {
return readPolicyStringArray(policy, path, options) ?? [];
}
function readPolicyPathString(policy, path) {
const current = getPolicyPath(policy, path);
return typeof current === "string" ? current.trim().toLowerCase() : void 0;
}
function ocPathSegment(value) {
if (/^(?:[A-Za-z0-9_-]+|#\d+)$/.test(value)) return value;
return JSON.stringify(value);
}
//#endregion
//#region extensions/policy/src/doctor/policy-runtime.ts
async function readPolicyFile(ctx) {
const displayName = policyDisplayName(ctx);
const file = await readWorkspaceFile(ctx, policyPathSetting(ctx));
return file === null ? null : {
...file,
displayName,
ocDocName: basename(displayName)
};
}
async function readExecApprovalsFile() {
const snapshot = readExecApprovalsSnapshot();
if (!snapshot.exists || snapshot.raw === null) return null;
return {
raw: snapshot.raw,
path: snapshot.path,
displayName: snapshot.path,
ocDocName: EXEC_APPROVALS_POLICY_DOCUMENT_NAME
};
}
async function readWorkspaceFile(ctx, fileName) {
const path = resolveWorkspacePath(ctx, fileName);
try {
return {
raw: await (await import("node:fs/promises")).readFile(path, "utf-8"),
path
};
} catch (err) {
if (isNotFoundPathError(err)) return null;
throw err;
}
}
function resolveWorkspacePath(ctx, fileName) {
if (isAbsolute(fileName)) return fileName;
return resolve(ctx.cwd ?? process.cwd(), fileName);
}
function isNotFoundPathError(err) {
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
}
function parsePolicyFile(raw) {
try {
return {
ok: true,
value: JSON5.parse(raw)
};
} catch (err) {
return {
ok: false,
message: err instanceof Error ? err.message : String(err)
};
}
}
function workspaceRepairsEnabled(ctx) {
return policySettings(ctx).workspaceRepairs === true;
}
function readChannelDenyRules(policy, policyDocName) {
if (!isRecord(policy) || !isRecord(policy.channels) || !Array.isArray(policy.channels.denyRules)) return [];
return policy.channels.denyRules.flatMap((rule, index) => isChannelDenyRule(rule) ? [{
when: rule.when,
requirement: `oc://${policyDocName}/channels/denyRules/#${index}`,
...rule.id === void 0 ? {} : { id: rule.id },
...rule.reason === void 0 ? {} : { reason: rule.reason }
}] : []);
}
function channelIdsFromFindings(findings) {
return [...new Set(findings.filter((finding) => finding.checkId === CHECK_IDS.policyDeniedChannelProvider).map((finding) => finding.ocPath?.match(/^oc:\/\/openclaw\.config\/channels\/(.+)$/)?.[1]).filter((id) => id !== void 0 && id !== ""))];
}
function disableChannels(cfg, channelIds) {
if (!isRecord(cfg.channels)) return {
config: cfg,
changed: []
};
const channels = { ...cfg.channels };
const changed = [];
for (const id of channelIds) {
const current = channels[id];
if (!isRecord(current) || current.enabled === false) continue;
channels[id] = {
...current,
enabled: false
};
changed.push(id);
}
if (changed.length === 0) return {
config: cfg,
changed
};
return {
config: {
...cfg,
channels
},
changed
};
}
function policySettings(ctx) {
const pluginConfig = ctx.cfg.plugins?.entries?.["policy"]?.config;
if (!isRecord(pluginConfig)) return {};
return pluginConfig;
}
function policyChecksEnabled(ctx, settings) {
const entry = ctx.cfg.plugins?.entries?.["policy"];
if (!isRecord(entry) || entry.enabled === false) return false;
return settings.enabled !== false;
}
function requiredToolMetadata(policy) {
return new Set(readPolicyStringArray(policy, ["tools", "requireMetadata"]) ?? []);
}
function requiredAuthProfileMetadata(policy) {
const entries = readPolicyStringArray(policy, [
"auth",
"profiles",
"requireMetadata"
]) ?? [];
return new Set(entries.filter((entry) => SUPPORTED_AUTH_PROFILE_METADATA.some((metadata) => metadata === entry)));
}
function authProfileHasMetadata(profile, metadata) {
if (metadata === "provider") return profile.provider !== void 0 && profile.provider.trim() !== "";
return SUPPORTED_AUTH_PROFILE_MODES.some((mode) => mode === profile.mode);
}
function policyPathSetting(ctx) {
const configured = policySettings(ctx).path;
return typeof configured === "string" && configured.trim() !== "" ? configured.trim() : "policy.jsonc";
}
function policyDisplayName(ctx) {
const configured = policyPathSetting(ctx);
return isAbsolute(configured) ? basename(configured) : configured;
}
//#endregion
//#region extensions/policy/src/policy-routing.ts
const ROUTING_MATCH_KINDS = [
"binding.peer",
"binding.peer.parent",
"binding.peer.wildcard",
"binding.guild+roles",
"binding.guild",
"binding.team",
"binding.account",
"binding.channel",
"default"
];
function validPolicyRoutingMatchKinds(value) {
return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "string" && ROUTING_MATCH_KINDS.some((kind) => kind === entry)) && new Set(value).size === value.length;
}
function policyRoutingRules(policy) {
if (!isRecord(policy) || !isRecord(policy.routing)) return;
return policy.routing;
}
function scanPolicyRouting(cfg, rules) {
return {
bindings: listPolicyRouteBindings(cfg),
probes: (rules.probes ?? []).map((probe, index) => {
const result = resolveAgentRoute({
cfg,
channel: probe.route.channel,
accountId: probe.route.accountId,
peer: probe.route.peer,
parentPeer: probe.route.parentPeer,
guildId: probe.route.guildId,
teamId: probe.route.teamId,
memberRoleIds: probe.route.memberRoleIds === void 0 ? void 0 : [...probe.route.memberRoleIds]
});
return {
id: probe.id,
source: `oc://policy/routing/probes/#${index}`,
agentId: result.agentId,
matchedBy: result.matchedBy
};
})
};
}
function listPolicyRouteBindings(cfg) {
if (!Array.isArray(cfg.bindings)) return [];
const bindings = [];
for (const [index, value] of cfg.bindings.entries()) {
if (!isRecord(value) || value.type === "acp" || !isRecord(value.match)) continue;
if (typeof value.agentId !== "string" || typeof value.match.channel !== "string") continue;
bindings.push({
index,
source: `oc://openclaw.config/bindings/#${index}`,
channel: value.match.channel
});
}
return bindings;
}
//#endregion
//#region extensions/policy/src/policy-state-types.ts
const RESERVED_CHANNEL_CONFIG_KEYS = /* @__PURE__ */ new Set(["defaults", "modelByChannel"]);
//#endregion
//#region extensions/policy/src/policy-state-core.ts
function scanPolicyChannels(cfg) {
return Object.entries(asNonArrayRecord(cfg.channels)).filter(([id]) => !RESERVED_CHANNEL_CONFIG_KEYS.has(id)).toSorted(([a], [b]) => a.localeCompare(b)).map(([id, value]) => {
const entry = {
id,
provider: id,
source: `oc://openclaw.config/channels/${id}`
};
if (isRecord(value) && typeof value.enabled === "boolean") entry.enabled = value.enabled;
return entry;
});
}
function scanPolicyMcpServers(cfg) {
return Object.entries(asNonArrayRecord(asNonArrayRecord(cfg.mcp).servers)).toSorted(([a], [b]) => a.localeCompare(b)).map(([id, value]) => {
const entry = {
id,
transport: mcpServerTransport(value),
source: `oc://openclaw.config/mcp/servers/${ocPathSegment$1(id)}`
};
if (isRecord(value)) {
if (typeof value.command === "string") entry.command = value.command;
if (typeof value.url === "string") entry.url = redactMcpUrlForEvidence(value.url);
}
return entry;
});
}
function scanPolicyModelProviders(cfg) {
return Object.keys(asNonArrayRecord(asNonArrayRecord(cfg.models).providers)).toSorted((a, b) => a.localeCompare(b)).map((id) => ({
id: normalizeProviderId(id),
source: `oc://openclaw.config/models/providers/${id}`
}));
}
function scanPolicyModelRefs(cfg) {
const refs = [];
if (isRecord(cfg.agents)) {
collectModelRefsFromRecord(refs, cfg.agents, "oc://openclaw.config/agents");
collectModelRefsFromAgentAllowlist(refs, cfg.agents);
}
return refs.toSorted((a, b) => a.provider.localeCompare(b.provider) || a.model.localeCompare(b.model));
}
function scanPolicyNetwork(cfg) {
return [
["browser-private-network", "browser/ssrfPolicy/dangerouslyAllowPrivateNetwork"],
["browser-private-network-legacy", "browser/ssrfPolicy/allowPrivateNetwork"],
["web-fetch-private-network", "tools/web/fetch/ssrfPolicy/dangerouslyAllowPrivateNetwork"],
["web-fetch-private-network-legacy", "tools/web/fetch/ssrfPolicy/allowPrivateNetwork"],
["web-fetch-rfc2544-benchmark-range", "tools/web/fetch/ssrfPolicy/allowRfc2544BenchmarkRange"],
["web-fetch-ipv6-unique-local-range", "tools/web/fetch/ssrfPolicy/allowIpv6UniqueLocalRange"]
].flatMap(([id, path]) => {
const value = readBooleanPath(cfg, path.split("/"));
return value === void 0 ? [] : [{
id,
source: `oc://openclaw.config/${path}`,
value
}];
});
}
function mcpServerTransport(value) {
if (!isRecord(value)) return "unknown";
if (typeof value.command === "string") return "stdio";
if (value.transport === "sse" || value.transport === "streamable-http") return value.transport;
if (typeof value.url === "string") return "streamable-http";
return "unknown";
}
function redactMcpUrlForEvidence(raw) {
try {
const url = new URL(raw);
return `${url.protocol}//${url.host}`;
} catch {
return "[redacted-url]";
}
}
function collectModelRefsFromValue(refs, value, source) {
if (typeof value === "string") {
pushModelRef(refs, value, source);
return;
}
if (!isRecord(value)) return;
if (typeof value.primary === "string") pushModelRef(refs, value.primary, `${source}/primary`);
if (Array.isArray(value.fallbacks)) {
for (const [index, fallback] of value.fallbacks.entries()) if (typeof fallback === "string") pushModelRef(refs, fallback, `${source}/fallbacks/#${index}`);
}
}
function collectModelRefsFromRecord(refs, value, source) {
for (const [key, child] of Object.entries(value)) {
const childPath = `${source}/${key}`;
if (isModelSettingKey(key)) {
collectModelRefsFromValue(refs, child, childPath);
continue;
}
if (Array.isArray(child)) {
for (const [index, item] of child.entries()) if (isRecord(item)) collectModelRefsFromRecord(refs, item, `${childPath}/#${index}`);
continue;
}
if (isRecord(child)) collectModelRefsFromRecord(refs, child, childPath);
}
}
function collectModelRefsFromAgentAllowlist(refs, agents) {
const defaults = agents.defaults;
if (isRecord(defaults) && isRecord(defaults.models)) collectModelRefsFromModelMap(refs, defaults.models, "oc://openclaw.config/agents/defaults/models");
for (const configured of collectPolicyConfiguredAgents(agents)) {
const agent = configured.value;
if (!isRecord(agent) || !isRecord(agent.models)) continue;
collectModelRefsFromModelMap(refs, agent.models, `${configured.sourceBase}/models`);
}
}
function collectModelRefsFromModelMap(refs, models, source) {
for (const ref of Object.keys(models)) pushModelRef(refs, ref, `${source}/${ocPathSegment$1(ref)}`);
}
function isModelSettingKey(key) {
return key === "model" || key.endsWith("Model");
}
function pushModelRef(refs, ref, source) {
const trimmed = ref.trim();
const slash = trimmed.indexOf("/");
if (slash <= 0 || slash >= trimmed.length - 1) return;
refs.push({
ref,
provider: normalizeProviderId(trimmed.slice(0, slash)),
model: trimmed.slice(slash + 1),
source
});
}
//#endregion
//#region extensions/policy/src/policy-state-data.ts
function scanPolicySecrets(cfg) {
const entries = [...scanPolicySecretProviders(cfg)];
collectSecretInputs(entries, cfg, [], secretRefDefaults(asNonArrayRecord(cfg.secrets).defaults));
return entries.toSorted((a, b) => a.source.localeCompare(b.source));
}
function scanPolicyAuthProfiles(cfg) {
const auth = asNonArrayRecord(cfg.auth);
const profiles = asNonArrayRecord(auth.profiles);
return Object.entries(profiles).toSorted(([a], [b]) => a.localeCompare(b)).map(([id, value]) => {
const entry = {
id,
source: `oc://openclaw.config/auth/profiles/${ocPathSegment$1(id)}`,
validMetadata: isValidAuthProfileMetadata(value)
};
if (isRecord(value)) {
if (typeof value.provider === "string") entry.provider = value.provider;
if (typeof value.mode === "string") entry.mode = value.mode;
}
return entry;
});
}
function scanPolicyDataHandling(cfg) {
const entries = [];
entries.push({
id: "logging-redaction",
kind: "sensitiveLoggingRedaction",
source: "oc://openclaw.invariant/logging/redaction",
scope: "global",
value: true,
explicit: true
});
const diagnostics = asNonArrayRecord(cfg.diagnostics);
const otel = asNonArrayRecord(diagnostics.otel);
const otelEnabled = diagnostics.enabled !== false && otel.enabled === true;
const tracesEnabled = otelEnabled && otel.traces !== false;
const logsEnabled = otelEnabled && otel.logs === true;
const captureContent = otelEnabled && telemetryContentCaptureEnabled(otel.captureContent, {
tracesEnabled,
logsEnabled
});
entries.push({
id: "diagnostics-otel-content-capture",
kind: "telemetryContentCapture",
source: "oc://openclaw.config/diagnostics/otel/captureContent",
scope: "global",
value: captureContent,
explicit: otel.captureContent !== void 0
});
const session = asNonArrayRecord(cfg.session);
const maintenance = asNonArrayRecord(session.maintenance);
const retentionMode = typeof maintenance.mode === "string" ? maintenance.mode : "enforce";
entries.push({
id: "session-maintenance-mode",
kind: "sessionRetentionMode",
source: "oc://openclaw.config/session/maintenance/mode",
scope: "global",
value: retentionMode,
explicit: maintenance.mode !== void 0
});
pushMemorySessionTranscriptIndexing(entries, cfg);
return entries.toSorted((a, b) => a.source.localeCompare(b.source));
}
function telemetryContentCaptureEnabled(value, signals) {
if (value === true) return signals.tracesEnabled || signals.logsEnabled;
if (!isRecord(value) || !signals.tracesEnabled || value.enabled !== true) return false;
return value.inputMessages === true || value.outputMessages === true || value.toolInputs === true || value.toolOutputs === true || value.systemPrompt === true || value.toolDefinitions === true;
}
function pushMemorySessionTranscriptIndexing(entries, cfg) {
const defaults = readMemorySessionSettings(asNonArrayRecord(cfg.memory).search);
const defaultSessionMemory = memorySearchSessionTranscriptIndexing(defaults);
if (defaultSessionMemory !== void 0) entries.push({
id: "agents-defaults-memory-session-transcripts",
kind: "memorySessionTranscriptIndexing",
source: `oc://openclaw.config/memory/search/${defaults.sourceKey}`,
scope: "global",
value: defaultSessionMemory,
explicit: true
});
collectPolicyConfiguredAgents(asNonArrayRecord(cfg.agents)).forEach((configured) => {
const { agentId, value: rawAgent } = configured;
if (!isRecord(rawAgent)) return;
const memorySearch = asNonArrayRecord(rawAgent.memory).search;
const local = readMemorySessionSettings(memorySearch);
const agentSessionMemory = isRecord(memorySearch) ? memorySearchSessionTranscriptIndexing(local, defaults) : defaultSessionMemory;
if (agentSessionMemory === void 0) return;
entries.push({
id: `${agentId}-memory-session-transcripts`,
kind: "memorySessionTranscriptIndexing",
source: local.explicit ? `${configured.sourceBase}/memory/search/${local.sourceKey}` : "oc://openclaw.config/memory/search/rememberAcrossConversations",
scope: "agent",
agentId: normalizeAgentId(agentId),
value: agentSessionMemory,
explicit: local.explicit
});
});
}
function memorySearchSessionTranscriptIndexing(local, inherited = local) {
const rememberAcrossConversations = local.remember ?? inherited.remember;
if (rememberAcrossConversations === void 0 && !local.explicit) return;
return (local.enabled ?? inherited.enabled ?? true) && rememberAcrossConversations === true && (local.sessions ?? inherited.sessions ?? false);
}
function readMemorySessionSettings(value) {
const search = asNonArrayRecord(value);
const enabled = asBoolean(search.enabled);
const current = asBoolean(search.rememberAcrossConversations);
const legacy = current === void 0 ? asBoolean(asNonArrayRecord(search.experimental).sessionMemory) : void 0;
const remember = current ?? legacy;
const sessions = search.sources === void 0 ? void 0 : Array.isArray(search.sources) && search.sources.includes("sessions");
return {
enabled,
remember,
sessions,
explicit: enabled !== void 0 || remember !== void 0 || sessions !== void 0,
sourceKey: legacy === void 0 ? "rememberAcrossConversations" : "experimental/sessionMemory"
};
}
function scanPolicySecretProviders(cfg) {
const secrets = asNonArrayRecord(cfg.secrets);
const providers = asNonArrayRecord(secrets.providers);
return Object.entries(providers).map(([id, value]) => {
const entry = {
id,
kind: "provider",
source: `oc://openclaw.config/secrets/providers/${ocPathSegment$1(id)}`
};
if (isRecord(value) && typeof value.source === "string") entry.providerSource = value.source;
return entry;
});
}
function collectSecretInputs(entries, value, path, defaults) {
if (Array.isArray(value)) {
value.forEach((item, index) => collectSecretInputs(entries, item, [...path, `#${index}`], defaults));
return;
}
if (!isRecord(value)) return;
for (const [key, child] of Object.entries(value)) {
const childPath = [...path, key];
const source = `oc://openclaw.config/${childPath.map(ocPathSegment$1).join("/")}`;
const ref = isSecretInputPath(childPath) ? coerceSecretRef(child, defaults) : null;
if (ref !== null) {
entries.push({
id: source,
kind: "input",
source,
provenance: "secretRef",
refSource: ref.source,
refProvider: ref.provider
});
continue;
}
collectSecretInputs(entries, child, childPath, defaults);
}
}
function isSecretInputPath(path) {
const key = path.at(-1);
if (key === void 0) return false;
if (matchesConfigPath(path, [
"plugins",
"entries",
"acpx",
"config",
"mcpServers",
"*",
"env",
"*"
])) return true;
if (path.at(-2) === "env") return false;
if (isSecretInputKey(key)) return true;
return [
[
"models",
"providers",
"*",
"headers",
"*"
],
[
"memory",
"search",
"remote",
"headers",
"*"
],
[
"agents",
"entries",
"*",
"memory",
"search",
"remote",
"headers",
"*"
],
[
"agents",
"list",
"#",
"memory",
"search",
"remote",
"headers",
"*"
],
[
"diagnostics",
"otel",
"headers",
"*"
]
].some((pattern) => matchesConfigPath(path, pattern)) || [
[
"models",
"providers",
"*"
],
[
"tools",
"media",
"models",
"#"
],
[
"tools",
"media",
"audio"
],
[
"tools",
"media",
"image"
],
[
"tools",
"media",
"video"
]
].some((prefix) => isConfiguredProviderRequestSecretPath(path, prefix));
}
function isConfiguredProviderRequestSecretPath(path, prefix) {
if (!matchesConfigPathPrefix(path, prefix) || path[prefix.length] !== "request") return false;
const suffix = path.slice(prefix.length + 1);
if (suffix.length === 2) return suffix[0] === "headers" || suffix[0] === "auth" && (suffix[1] === "token" || suffix[1] === "value") || suffix[0] === "tls" && isConfiguredProviderTlsSecretKey(suffix[1]);
return suffix.length === 3 && suffix[0] === "proxy" && suffix[1] === "tls" && isConfiguredProviderTlsSecretKey(suffix[2]);
}
function matchesConfigPathPrefix(path, prefix) {
if (path.length < prefix.length) return false;
return prefix.every((segment, index) => {
const value = path[index];
if (segment === "*") return value !== void 0 && value !== "";
if (segment === "#") return value?.startsWith("#") ?? false;
return value === segment;
});
}
function matchesConfigPath(path, pattern) {
return path.length === pattern.length && matchesConfigPathPrefix(path, pattern);
}
function isConfiguredProviderTlsSecretKey(key) {
return key === "ca" || key === "cert" || key === "key" || key === "passphrase";
}
function isSecretInputKey(key) {
const normalized = key.toLowerCase();
return normalized === "keyref" || normalized === "tokenref" || normalized === "encryptkey" || normalized === "serviceaccount" || normalized === "serviceaccountref" || normalized === "privatekey" || normalized === "certificate" || normalized === "certificatedata" || normalized === "identitydata" || normalized === "knownhosts" || normalized === "knownhostsdata" || normalized.endsWith("apikey") || normalized.endsWith("token") || normalized.endsWith("secret") || normalized.endsWith("password");
}
function secretRefDefaults(value) {
if (!isRecord(value)) return;
const defaults = {};
for (const source of [
"env",
"file",
"exec",
"store"
]) if (typeof value[source] === "string") defaults[source] = value[source];
return defaults;
}
function isValidAuthProfileMetadata(value) {
if (!isRecord(value)) return false;
return typeof value.provider === "string" && value.provider.trim() !== "" && isAuthProfileMode(value.mode);
}
function isAuthProfileMode(value) {
return value === "api_key" || value === "aws-sdk" || value === "oauth" || value === "token";
}
//#endregion
//#region extensions/policy/src/policy-state-exec-approvals.ts
function scanPolicyExecApprovals(raw) {
const parsed = parseExecApprovalsFile(raw);
if (!parsed.ok) return [];
const evidence = [];
const defaults = asNonArrayRecord(parsed.value.defaults);
evidence.push(execApprovalPostureEvidence("defaults", "defaults", defaults, execApprovalsPolicyUri("defaults")));
for (const [agentId, value] of Object.entries(asNonArrayRecord(parsed.value.agents)).toSorted(([a], [b]) => a.localeCompare(b))) {
if (!isRecord(value)) continue;
const agentSource = execApprovalsPolicyUri(`agents/${ocPathSegment$1(agentId)}`);
evidence.push(execApprovalPostureEvidence(`agent:${agentId}`, "agent", value, agentSource, agentId));
if (!Array.isArray(value.allowlist)) continue;
let allowlistIndex = 0;
for (const [index, entry] of value.allowlist.entries()) {
if (!isRecord(entry)) continue;
const pattern = normalizeOptionalString(entry.pattern);
if (pattern === void 0) continue;
const argPattern = normalizeOptionalString(entry.argPattern);
const entrySource = normalizeOptionalString(entry.source) === "allow-always" ? "allow-always" : void 0;
evidence.push({
id: `agent:${agentId}:allowlist:${allowlistIndex++}`,
kind: "allowlist",
source: `${agentSource}/allowlist/#${index}`,
agentId,
pattern,
...argPattern === void 0 ? {} : { argPattern },
...entrySource === void 0 ? {} : { entrySource }
});
}
}
return evidence;
}
function parseExecApprovalsFile(raw) {
try {
const value = JSON.parse(raw);
if (!isRecord(value) || value.version !== 1) return {
ok: false,
message: "unsupported exec approvals version"
};
return {
ok: true,
value
};
} catch (err) {
return {
ok: false,
message: err instanceof Error ? err.message : String(err)
};
}
}
function execApprovalPostureEvidence(id, kind, value, source, agentId) {
const security = readExecApprovalSecurity(value.security);
const ask = readExecApprovalAsk(value.ask);
const askFallback = readExecApprovalSecurity(value.askFallback);
const autoAllowSkills = asBoolean(value.autoAllowSkills);
return {
id,
kind,
source,
...agentId === void 0 ? {} : { agentId },
...value.security == null ? {} : { securityConfigured: true },
...security === void 0 ? {} : { security },
...ask === void 0 ? {} : { ask },
...askFallback === void 0 ? {} : { askFallback },
...autoAllowSkills === void 0 ? {} : { autoAllowSkills }
};
}
function readExecApprovalSecurity(value) {
const normalized = normalizeOptionalString(value);
return normalized === "deny" || normalized === "allowlist" || normalized === "full" ? normalized : void 0;
}
function readExecApprovalAsk(value) {
const normalized = normalizeOptionalString(value);
return normalized === "off" || normalized === "on-miss" || normalized === "always" ? normalized : void 0;
}
//#endregion
//#region extensions/policy/src/policy-state-gateway.ts
function scanPolicyGatewayExposure(cfg) {
const gateway = asNonArrayRecord(cfg.gateway);
const entries = [];
const bind = typeof gateway.bind === "string" ? gateway.bind : void 0;
const customBindHost = typeof gateway.customBindHost === "string" ? gateway.customBindHost : void 0;
const hasCustomBindHost = customBindHost !== void 0 && customBindHost.trim() !== "";
const tailscale = asNonArrayRecord(gateway.tailscale);
const tailscaleForcesLoopback = tailscale.mode === "serve" || tailscale.mode === "funnel";
entries.push({
id: bind === void 0 ? "gateway-bind-default" : "gateway-bind",
kind: "bind",
source: "oc://openclaw.config/gateway/bind",
value: bind ?? (tailscaleForcesLoopback ? "loopback" : "runtime-default"),
nonLoopback: bind === void 0 ? !tailscaleForcesLoopback : bind === "custom" ? false : isGatewayNonLoopbackBind(bind),
explicit: bind !== void 0
});
if (bind === "custom" && hasCustomBindHost) entries.push({
id: "gateway-custom-bind-host",
kind: "bind",
source: "oc://openclaw.config/gateway/customBindHost",
value: customBindHost,
nonLoopback: isRuntimeNonLoopbackCustomBindHost(customBindHost)
});
const auth = asNonArrayRecord(gateway.auth);
entries.push({
id: "gateway-auth-mode",
kind: "auth",
source: "oc://openclaw.config/gateway/auth/mode",
value: typeof auth.mode === "string" ? auth.mode : "token",
explicit: typeof auth.mode === "string"
});
entries.push({
id: "gateway-auth-rate-limit",
kind: "authRateLimit",
source: "oc://openclaw.config/gateway/auth/rateLimit",
value: isRecord(auth.rateLimit),
explicit: isRecord(auth.rateLimit)
});
const controlUi = asNonArrayRecord(gateway.controlUi);
for (const [suffix, value, source] of [
[
"enabled",
controlUi.enabled,
"oc://openclaw.config/gateway/controlUi/enabled"
],
[
"insecure-auth",
false,
"oc://openclaw.invariant/gateway/controlUi/deviceIdentity"
],
[
"device-auth-disabled",
false,
"oc://openclaw.invariant/gateway/controlUi/deviceIdentity"
],
[
"host-origin-fallback",
controlUi.dangerouslyAllowHostHeaderOriginFallback,
"oc://openclaw.config/gateway/controlUi/dangerouslyAllowHostHeaderOriginFallback"
]
]) if (typeof value === "boolean") entries.push({
id: `gateway-control-ui-${suffix}`,
kind: "controlUi",
source,
value
});
if (typeof tailscale.mode === "string") entries.push({
id: "gateway-tailscale-mode",
kind: "tailscale",
source: "oc://openclaw.config/gateway/tailscale/mode",
value: tailscale.mode
});
if (tailscale.mode === "serve" && tailscale.preserveFunnel === true) entries.push({
id: "gateway-tailscale-preserve-funnel",
kind: "tailscale",
source: "oc://openclaw.config/gateway/tailscale/preserveFunnel",
value: "funnel"
});
const remote = asNonArrayRecord(gateway.remote);
if (gateway.mode === "remote") {
entries.push({
id: "gateway-mode-remote",
kind: "remote",
source: "oc://openclaw.config/gateway/mode",
value: "remote"
});
if (typeof remote.url === "string" && remote.url.trim() !== "") entries.push({
id: "gateway-remote-url",
kind: "remote",
source: "oc://openclaw.config/gateway/remote/url",
value: true
});
}
const http = asNonArrayRecord(gateway.http);
const endpoints = asNonArrayRecord(http.endpoints);
pushGatewayHttpEndpointEvidence(entries, endpoints, "chatCompletions");
pushGatewayHttpEndpointEvidence(entries, endpoints, "responses");
pushGatewayNodeCommandEvidence(entries, asNonArrayRecord(gateway.nodes));
return entries.toSorted((a, b) => a.source.localeCompare(b.source));
}
function pushGatewayHttpEndpointEvidence(entries, endpoints, endpoint) {
const config = endpoints[endpoint];
if (!isRecord(config) || config.enabled !== true) return;
const source = `oc://openclaw.config/gateway/http/endpoints/${endpoint}`;
entries.push({
id: `gateway-http-${endpoint}`,
kind: "httpEndpoint",
source: `${source}/enabled`,
value: true,
endpoint
});
for (const input of endpoint === "chatCompletions" ? ["images"] : ["files", "images"]) pushGatewayHttpUrlFetchEvidence(entries, source, endpoint, input, config[input]);
}
function pushGatewayHttpUrlFetchEvidence(entries, endpointSource, endpoint, input, value) {
const allowUrl = isRecord(value) ? value.allowUrl : void 0;
if (allowUrl === false || allowUrl !== true && endpoint !== "responses") return;
const allowlist = isRecord(value) ? value.urlAllowlist : void 0;
const hasEffectiveAllowlist = Array.isArray(allowlist) && allowlist.some((entry) => isEffectiveGatewayUrlAllowlistEntry(entry));
entries.push({
id: `gateway-http-${endpoint}-${input}-url-fetch`,
kind: "httpUrlFetch",
source: `${endpointSource}/${ocPathSegment$1(input)}/allowUrl`,
value: true,
endpoint,
explicit: allowUrl === true,
hasAllowlist: hasEffectiveAllowlist
});
}
function pushGatewayNodeCommandEvidence(entries, nodes) {
const commands = isRecord(nodes.commands) ? nodes.commands : null;
const deniedCommands = /* @__PURE__ */ new Set();
for (const [list, kind, idPrefix] of [[
"deny",
"nodeDenyCommand",
"gateway-node-deny-command"
], [
"allow",
"nodeCommand",
"gateway-node-command"
]]) {
const values = commands?.[list];
if (!Array.isArray(values)) continue;
values.forEach((command, index) => {
if (typeof command !== "string") return;
const normalized = command.trim();
if (normalized === "" || list === "allow" && deniedCommands.has(normalized)) return;
if (list === "deny") deniedCommands.add(normalized);
entries.push({
id: `${idPrefix}-${normalized}`,
kind,
source: `oc://openclaw.config/gateway/nodes/commands/${list}/#${index}`,
value: normalized,
command: normalized
});
});
}
}
function isEffectiveGatewayUrlAllowlistEntry(value) {
if (typeof value !== "string") return false;
const normalized = value.trim().toLowerCase();
return normalized !== "" && normalized !== "*" && normalized !== "*.";
}
function isGatewayNonLoopbackBind(value) {
return value === "auto" || value === "lan" || value === "custom" || value === "tailnet";
}
function isRuntimeNonLoopbackCustomBindHost(value) {
const normalized = value.trim().toLowerCase();
return isCanonicalDottedDecimalIPv4(normalized) && !normalized.startsWith("127.");
}
function isCanonicalDottedDecimalIPv4(value) {
return /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/.test(value);
}
//#endregion
//#region extensions/policy/src/policy-state-tool-posture.ts
function scanPolicyToolPosture(cfg) {
const globalTools = asNonArrayRecord(cfg.tools);
const agents = asNonArrayRecord(cfg.agents);
const defaults = asNonArrayRecord(agents.defaults);
const defaultSandbox = asNonArrayRecord(defaults.sandbox);
const entries = [];
pushToolPostureEvidence(entries, {
id: "tools",
scope: "global",
tools: globalTools,
inheritedTools: {},
sandbox: defaultSandbox,
inheritedSandbox: {},
sourceBase: "oc://openclaw.config/tools"
});
collectPolicyConfiguredAgents(agents).forEach((configured) => {
const agent = configured.value;
if (!isRecord(agent)) return;
pushToolPostureEvidence(entries, {
id: configured.agentId,
scope: "agent",
agentId: configured.agentId,
tools: asNonArrayRecord(agent.tools),
inheritedTools: globalTools,
sandbox: asNonArrayRecord(agent.sandbox),
inheritedSandbox: defaultSandbox,
sourceBase: `${configured.sourceBase}/tools`
});
});
return entries.toSorted((a, b) => a.source.localeCompare(b.source) || a.id.localeCompare(b.id));
}
function pushToolPostureEvidence(entries, params) {
pushToolPostureValue(entries, params, {
suffix: "profile",
kind: "profile",
...resolvePolicyValue(normalizeOptionalString(params.tools.profile), normalizeOptionalString(params.inheritedTools.profile), "full")
});
for (const key of [
"allow",
"alsoAllow",
"deny"
]) pushToolPostureList(entries, params, key);
pushToolFsPosture(entries, params);
pushToolExecPosture(entries, params);
pushToolElevatedPosture(entries, params);
}
function pushToolFsPosture(entries, params) {
const localFs = asNonArrayRecord(params.tools.fs);
const inheritedFs = asNonArrayRecord(params.inheritedTools.fs);
pushToolPostureValue(entries, params, {
suffix: "fs/workspaceOnly",
kind: "fsWorkspaceOnly",
...resolvePolicyValue(asBoolean(localFs.workspaceOnly), asBoolean(inheritedFs.workspaceOnly), false)
});
}
function pushToolExecPosture(entries, params) {
const localExec = asNonArrayRecord(params.tools.exec);
const inheritedExec = asNonArrayRecord(params.inheritedTools.exec);
const hostPosture = resolvePolicyValue(normalizeOptionalString(localExec.host), normalizeOptionalString(inheritedExec.host), "auto");
const host = hostPosture.value;
pushToolPostureValue(entries, params, {
suffix: "exec/host",
kind: "execHost",
...hostPosture
});
const localSecurity = normalizeOptionalString(localExec.security);
const inheritedSecurity = normalizeOptionalString(inheritedExec.security);
const localAsk = normalizeOptionalString(localExec.ask);
const inheritedAsk = normalizeOptionalString(inheritedExec.ask);
const localMode = readExecMode(localExec.mode);
const inheritedMode = readExecMode(inheritedExec.mode);
const sandboxCanApply = (normalizeOptionalString(params.sandbox.mode) ?? normalizeOptionalString(params.inheritedSandbox.mode)) === "all";
const defaultSecurity = host === "sandbox" || host === "auto" && sandboxCanApply ? "deny" : "full";
const selectedMode = localMode === void 0 ? inheritedMode === void 0 ? void 0 : {
value: inheritedMode,
inherited: true
} : {
value: localMode,
inherited: false
};
const modePosture = selectedMode === void 0 ? void 0 : {
...selectedMode,
...resolveExecModePolicy({
mode: selectedMode.value,
security: "full",
ask: "off"
})
};
for (const [field, kind, local, inherited, fallback] of [[
"security",
"execSecurity",
localSecurity,
inheritedSecurity,
defaultSecurity
], [
"ask",
"execAsk",
localAsk,
inheritedAsk,
"off"
]]) {
const usesMode = modePosture?.inherited === false || local === void 0 && modePosture?.inherited === true;
pushToolPostureValue(entries, params, {
suffix: `exec/${field}`,
sourceSuffix: usesMode ? "exec/mode" : void 0,
kind,
value: modePosture?.inherited === false ? modePosture[field] : local ?? modePosture?.[field] ?? inherited ?? fallback,
explicit: modePosture !== void 0 || local !== void 0 || inherited !== void 0,
inherited: modePosture?.inherited === true ? local === void 0 : local === void 0 && inherited !== void 0
});
}
}
function pushToolElevatedPosture(entries, params) {
const localElevated = asNonArrayRecord(params.tools.elevated);
const inheritedElevated = asNonArrayRecord(params.inheritedTools.elevated);
const localEnabled = asBoolean(localElevated.enabled);
const inheritedEnabled = asBoolean(inheritedElevated.enabled);
pushToolPostureValue(entries, params, {
suffix: "elevated/enabled",
kind: "elevatedEnabled",
value: inheritedEnabled === false ? false : localEnabled ?? inheritedEnabled ?? true,
explicit: localEnabled !== void 0 || inheritedEnabled !== void 0,
inherited: inheritedEnabled === false && localEnabled !== false || localEnabled === void 0 && inheritedEnabled !== void 0
});
const localAllowFrom = asNonArrayRecord(localElevated.allowFrom);
const inheritedAllowFrom = asNonArrayRecord(inheritedElevated.allowFrom);
const providers = [.../* @__PURE__ */ new Set([...Object.keys(inheritedAllowFrom), ...Object.keys(localAllowFrom)])].toSorted((a, b) => a.localeCompare(b));
for (const provider of providers) {
const localEntries = readStringOrNumberArray(localAllowFrom[provider]);
const inheritedEntries = readStringOrNumberArray(inheritedAllowFrom[provider]);
const inherited = localEntries.length === 0 && inheritedEntries.length > 0;
entries.push({
id: `${params.id}-elevated-allow-from-${ocPathSegment$1(provider)}`,
kind: "elevatedAllowFrom",
source: `${inherited ? "oc://openclaw.config/tools" : params.sourceBase}/elevated/allowFrom/${ocPathSegment$1(provider)}`,
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
entries: localEntries.length > 0 ? localEntries : inheritedEntries,
explicit: localEntries.length > 0 || inheritedEntries.length > 0
});
}
}
function pushToolPostureValue(entries, params, entry) {
entries.push({
id: `${params.id}-${entry.suffix.replaceAll("/", "-")}`,
kind: entry.kind,
source: `${entry.inherited ? "oc://openclaw.config/tools" : params.sourceBase}/${entry.sourceSuffix ?? entry.suffix}`,
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
...entry.value === void 0 ? {} : { value: entry.value },
explicit: entry.explicit
});
}
function readExecMode(value) {
const mode = normalizeOptionalString(value)?.toLowerCase();
switch (mode) {
case "deny":
case "allowlist":
case "ask":
case "auto":
case "full": return mode;
default: return;
}
}
function pushToolPostureList(entries, params, key) {
const localValue = params.tools[key];
const inheritedValue = params.inheritedTools[key];
const localEntries = readStringArray(localValue);
const inheritedEntries = readStringArray(inheritedValue);
const replace = key === "alsoAllow";
const localConfigured = replace ? Array.isArray(localValue) : localEntries.length > 0;
const inheritedConfigured = replace ? Array.isArray(inheritedValue) : inheritedEntries.length > 0;
const inherited = !localConfigured && inheritedConfigured;
entries.push({
id: `${params.id}-${key}`,
kind: key,
source: `${inherited ? "oc://openclaw.config/tools" : params.sourceBase}/${key}`,
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
entries: replace ? inherited ? inheritedEntries : localEntries : [...inheritedEntries, ...localEntries],
explicit: localConfigured || inheritedConfigured
});
}
const AGENT_WORKSPACE_POLICY_TOOLS = [
"exec",
"process",
"write",
"edit",
"apply_patch"
];
const IMPLICIT_DEFAULT_ACCOUNT_FIELDS = {
discord: ["token"],
googlechat: ["serviceAccount", "serviceAccountFile"],
imessage: ["cliPath", "dbPath"],
"qa-channel": ["baseUrl"],
qqbot: [
"appId",
"clientSecret",
"clientSecretFile"
],
signal: ["account"],
slack: [
"appToken",
"botToken",
"signingSecret"
],
"synology-chat": ["token"],
telegram: ["botToken", "tokenFile"],
tlon: ["ship"],
twitch: ["username"],
whatsapp: ["authDir"],
zalo: ["botToken", "tokenFile"],
zalouser: ["profile"]
};
function readStringArray(value) {
if (!Array.isArray(value)) return [];
return value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
}
function readStringOrNumberArray(value) {
if (!Array.isArray(value)) return [];
const entries = [];
for (const entry of value) if (typeof entry === "string" && entry.trim() !== "") entries.push(entry.trim());
else if (typeof entry === "number" && Number.isFinite(entry)) entries.push(String(entry));
return entries;
}
//#endregion
//#region extensions/policy/src/policy-state-ingress.ts
const ALLOWLIST_DEFAULT_INGRESS_GROUP_POLICY_CHANNELS = /* @__PURE__ */ new Set([
"googlechat",
"irc",
"line",
"mattermost",
"matrix",
"msteams",
"nextcloud-talk",
"signal"
]);
const OPEN_GROUPS_DEFAULT_TO_NO_MENTION_CHANNELS = /* @__PURE__ */ new Set(["feishu", "qa-channel"]);
function scanPolicyIngress(cfg) {
const channels = asNonArrayRecord(cfg.channels);
const channelDefaults = asNonArrayRecord(channels.defaults);
const inheritedChannelDefaults = channelDefaults.groupPolicy === void 0 ? {} : { groupPolicy: channelDefaults.groupPolicy };
const channelDefaultsSource = "oc://openclaw.config/channels/defaults";
const entries = [];
const session = asNonArrayRecord(cfg.session);
const dmScope = normalizeOptionalString(session.dmScope)?.toLowerCase();
entries.push({
id: "session-dm-scope",
kind: "sessionDmScope",
source: "oc://openclaw.config/session/dmScope",
value: dmScope ?? "main",
explicit: dmScope !== void 0
});
for (const [channel, value] of Object.entries(channels)) {
if (RESERVED_CHANNEL_CONFIG_KEYS.has(channel) || !isRecord(value) || value.enabled === false) continue;
const channelSource = `oc://openclaw.config/channels/${ocPathSegment$1(channel)}`;
const accounts = asNonArrayRecord(value.accounts);
const configuredAccounts = Object.entries(accounts).filter((entry) => isRecord(entry[1]));
const activeAccounts = configuredAccounts.filter(([, account]) => account.enabled !== false);
if (configuredAccounts.length === 0 || hasImplicitDefaultAccountConfig(channel, value)) pushChannelIngress(entries, {
channel,
config: value,
inheritedConfig: inheritedChannelDefaults,
sourceBase: channelSource,
inheritedSourceBase: channelDefaultsSource,
fallbackSourceBase: channelSource
});
for (const [accountId, account] of activeAccounts) pushChannelIngress(entries, {
channel,
accountId,
config: account,
inheritedConfig: value,
inheritNestedContainers: true,
inheritEmptyNestedContainers: channel === "telegram" && configuredAccounts.length <= 1,
sourceBase: `${channelSource}/accounts/${ocPathSegment$1(accountId)}`,
inheritedSourceBase: channelSource,
fallbackConfig: inheritedChannelDefaults,
fallbackSourceBase: channelDefaultsSource
});
}
return entries.toSorted((a, b) => a.source.localeCompare(b.source) || a.id.localeCompare(b.id));
}
function hasImplicitDefaultAccountConfig(channel, config) {
return (IMPLICIT_ACCOUNT_REQUIREMENTS[channel] ?? (IMPLICIT_DEFAULT_ACCOUNT_FIELDS[channel] ?? []).map((field) => [field])).some((fields) => fields.every((field) => hasConfiguredAccountValue(config[field])));
}
const IMPLICIT_ACCOUNT_REQUIREMENTS = {
clickclack: [[
"baseUrl",
"workspace",
"token"
]],
feishu: [["appId", "appSecret"]],
irc: [["host", "nick"]],
line: [["channelAccessToken"], ["tokenFile"]],
matrix: [["homeserver", "accessToken"], [
"homeserver",
"userId",
"password"
]],
mattermost: [["baseUrl", "botToken"]],
"nextcloud-talk": [["baseUrl", "botSecret"], ["baseUrl", "botSecretFile"]]
};
function pushChannelIngress(entries, params) {
const dmPolicy = channelDmPolicy(params.config, params.sourceBase) ?? channelDmPolicy(params.inheritedConfig, params.inheritedSourceBase) ?? channelDmPolicy(params.fallbackConfig ?? {}, params.fallbackSourceBase);
entries.push({
id: channelIngressId(params, "dm-policy"),
kind: "channelDmPolicy",
source: dmPolicy?.source ?? `${params.fallbackSourceBase}/dmPolicy`,
channel: params.channel,
...params.accountId === void 0 ? {} : { accountId: params.accountId },
value: dmPolicy?.value ?? "pairing",
explicit: dmPolicy !== void 0
});
const groupPolicy = channelIngressValue(params, "groupPolicy", normalizeOptionalString);
const implicitGroupPolicy = channelImplicitGroupPolicy(params);
const effectiveGroupPolicy = groupPolicy ?? implicitGroupPolicy;
entries.push({
id: channelIngressId(params, "group-policy"),
kind: "channelGroupPolicy",
source: effectiveGroupPolicy.source,
channel: params.channel,
...params.accountId === void 0 ? {} : { accountId: params.accountId },
value: effectiveGroupPolicy.value,
explicit: groupPolicy !== void 0
});
pushChannelRequireMentionIngress(entries, params, effectiveGroupPolicy.value);
}
function channelIngressValue(params, field, read) {
for (const [config, sourceBase] of [
[params.config, params.sourceBase],
[params.inheritedConfig, params.inheritedSourceBase],
[params.fallbackConfig, params.fallbackSourceBase]
]) {
const value = read(config?.[field]);
if (value !== void 0) return {
value,
source: `${sourceBase}/${field}`
};
}
}
function channelImplicitGroupPolicy(params) {
const groups = effectiveNestedIngressContainer(params, "groups");
if (groups !== void 0) return {
source: `${groups.sourceBase}/groups`,
value: "allowlist"
};
const fallbackGroups = isRecord(params.fallbackConfig?.groups) ? params.fallbackConfig.groups : void 0;
if (fallbackGroups !== void 0 && Object.keys(fallbackGroups).length > 0) return {
source: `${params.fallbackSourceBase}/groups`,
value: "allowlist"
};
return {
source: `${params.sourceBase}/groupPolicy`,
value: ALLOWLIST_DEFAULT_INGRESS_GROUP_POLICY_CHANNELS.has(params.channel) ? "allowlist" : "open"
};
}
function pushChannelRequireMentionIngress(entries, params, groupPolicy) {
const requireMention = channelWildcardRequireMention(params) ?? channelIngressValue(params, "requireMention", asBoolean);
const defaultRequireMention = !(groupPolicy === "open" && OPEN_GROUPS_DEFAULT_TO_NO_MENTION_CHANNELS.has(params.channel));
entries.push({
id: channelIngressId(params, "require-mention"),
kind: "channelRequireMention",
source: requireMention?.source ?? `${params.sourceBase}/requireMention`,
channel: params.channel,
...params.accountId === void 0 ? {} : { accountId: params.accountId },
value: requireMention?.value ?? defaultRequireMention,
explicit: requireMention !== void 0
});
for (const containerKey of [
"groups",
"guilds",
"channels",
"rooms",
"teams"
]) {
const effective = effectiveNestedIngressContainer(params, containerKey);
if (effective === void 0) continue;
const { container, sourceBase } = effective;
for (const [groupId, groupConfig] of Object.entries(container)) {
if (!isRecord(groupConfig)) continue;
pushNestedRequireMentionIngress(entries, params, containerKey, groupId, groupConfig, sourceBase);
}
}
}
function channelWildcardRequireMention(params) {
for (const key of [
"groups",
"guilds",
"channels",
"rooms",
"teams"
]) {
const effective = effectiveNestedIngressContainer(params, key);
const fallback = {
container: asNonArrayRecord(params.fallbackConfig?.[key]),
sourceBase: params.fallbackSourceBase
};
for (const candidate of [effective, fallback]) {
const wildcard = candidate?.container["*"];
if (!isRecord(wildcard) || wildcard.enabled === false) continue;
const requireMention = asBoolean(wildcard.requireMention);
if (requireMention !== void 0 && candidate !== void 0) return {
source: `${candidate.sourceBase}/${key}/${ocPathSegment$1("*")}/requireMention`,
value: requireMention
};
}
}
}
function effectiveNestedIngressContainer(params, key) {
const local = isRecord(params.config[key]) ? params.config[key] : void 0;
const inherited = isRecord(params.inheritedConfig[key]) ? params.inheritedConfig[key] : void 0;
if (local !== void 0 && Object.keys(local).length > 0) return {
container: local,
sourceBase: params.sourceBase
};
const inheritsEmpty = local !== void 0 && params.inheritEmptyNestedContainers === true;
const inheritsMissing = local === void 0 && params.inheritNestedContainers === true;
if ((inheritsEmpty || inheritsMissing) && inherited !== void 0) return {
container: inherited,
sourceBase: params.inheritedSourceBase
};
}
function pushNestedRequireMentionIngress(entries, params, containerKey, groupId, config, parentSourceBase) {
if (config.enabled === false) return;
const sourceBase = `${parentSourceBase}/${containerKey}/${ocPathSegment$1(groupId)}`;
const requireMention = asBoolean(config.requireMention);
if (requireMention !== void 0) entries.push({
id: `${channelIngressId(params, `${containerKey}-${ocPathSegment$1(groupId)}`)}-require-mention`,
kind: "channelRequireMention",
source: `${sourceBase}/requireMention`,
channel: params.channel,
...params.accountId === void 0 ? {} : { accountId: params.accountId },
groupId,
value: requireMention,
explicit: true
});
for (const nestedKey of ["channels", "topics"]) {
const nested = config[nestedKey];
if (!isRecord(nested)) continue;
for (const [nestedId, nestedConfig] of Object.entries(nested)) if (isRecord(nestedConfig)) pushNestedRequireMentionIngress(entries, params, `${containerKey}/${ocPathSegment$1(groupId)}/${nestedKey}`, nestedId, nestedConfig, parentSourceBase);
}
}
function channelDmPolicy(config, sourceBase) {
const dm = asNonArrayRecord(config.dm);
if (dm.enabled === false) return {
value: "disabled",
source: `${sourceBase}/dm/enabled`
};
const direct = normalizeOptionalString(config.dmPolicy);
if (direct !== void 0) return {
value: direct,
source: `${sourceBase}/dmPolicy`
};
const legacy = normalizeOptionalString(dm.policy);
return legacy === void 0 ? void 0 : {
value: legacy,
source: `${sourceBase}/dm/policy`
};
}
function channelIngressId(params, suffix) {
return params.accountId === void 0 ? `${params.channel}-${suffix}` : `${params.channel}-${params.accountId}-${suffix}`;
}
//#endregion
//#region extensions/policy/src/policy-state-sandbox.ts
const DEFAULT_POLICY_SANDBOX_BROWSER_NETWORK = "openclaw-sandbox-browser";
function scanPolicySandboxPosture(cfg) {
const agents = asNonArrayRecord(cfg.agents);
const defaults = asNonArrayRecord(agents.defaults);
const defaultSandbox = asNonArrayRecord(defaults.sandbox);
const entries = [];
pushSandboxPostureEvidence(entries, {
id: "agents-defaults",
scope: "defaults",
sandbox: defaultSandbox,
inheritedSandbox: {},
sourceBase: "oc://openclaw.config/agents/defaults/sandbox"
});
collectPolicyConfiguredAgents(agents).forEach((configured) => {
const agent = configured.value;
if (!isRecord(agent)) return;
const sandbox = asNonArrayRecord(agent.sandbox);
pushSandboxPostureEvidence(entries, {
id: configured.agentId,
scope: "agent",
agentId: configured.agentId,
sandbox,
inheritedSandbox: defaultSandbox,
sharedSandboxScope: sandboxScopeIsShared(sandbox, defaultSandbox),
sourceBase: `${configured.sourceBase}/sandbox`
});
});
return entries.toSorted((a, b) => a.source.localeCompare(b.source) || a.id.localeCompare(b.id));
}
function pushSandboxPostureEvidence(entries, params) {
pushSandboxPostureValue(entries, params, {
suffix: "mode",
kind: "mode",
...resolvePolicyValue(normalizeOptionalString(params.sandbox.mode), normalizeOptionalString(params.inheritedSandbox.mode), "off")
});
const backend = resolvePolicyValue(normalizeOptionalString(params.sandbox.backend), normalizeOptionalString(params.inheritedSandbox.backend), "docker");
const effectiveBackend = backend.value.toLowerCase();
const effectiveParams = {
...params,
effectiveBackend
};
pushSandboxPostureValue(entries, params, {
suffix: "backend",
kind: "backend",
...backend,
value: effectiveBackend
});
if (effectiveBackend === "docker" || effectiveBackend === "podman") pushSandboxDockerPosture(entries, effectiveParams);
pushSandboxBrowserPosture(entries, effectiveParams);
}
function pushSandboxDockerPosture(entries, params) {
const localDocker = !params.sharedSandboxScope ? asNonArrayRecord(params.sandbox.docker) : {};
const inheritedDocker = asNonArrayRecord(params.inheritedSandbox.docker);
pushSandboxPostureValue(entries, params, {
suffix: "docker/network",
kind: "containerNetwork",
...resolvePolicyValue(normalizeOptionalString(localDocker.network), normalizeOptionalString(inheritedDocker.network), "none"),
networkSurface: "docker"
});
for (const profile of ["seccomp", "apparmor"]) {
const key = `${profile}Profile`;
const localValue = normalizeOptionalString(localDocker[key]);
const inheritedValue = normalizeOptionalString(inheritedDocker[key]);
const inherited = localValue === void 0 && inheritedValue !== void 0;
const value = localValue ?? inheritedValue;
entries.push({
id: `${params.id}-docker-${profile}-profile`,
kind: "containerSecurityProfile",
source: `${inherited ? "oc://openclaw.config/agents/defaults/sandbox" : params.sourceBase}/docker/${key}`,
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
profile,
...value === void 0 ? {} : { value },
explicit: value !== void 0
});
}
pushSandboxBindPosture(entries, params, "docker");
}
function pushSandboxBindPosture(entries, params, surface, configSurface = surface) {
const local = !params.sharedSandboxScope ? asNonArrayRecord(params.sandbox[configSurface]) : {};
const inheritedBinds = readStringArray(asNonArrayRecord(params.inheritedSandbox[configSurface]).binds);
const localBinds = readStringArray(local.binds);
for (const [index, bind] of [...inheritedBinds, ...localBinds].entries()) {
const inherited = index < inheritedBinds.length;
const parsed = splitSandboxBindSpec(bind, { allowWindowsContainerPath: true });
const bindMode = parsed?.options.split(",").some((option) => option.trim().toLowerCase() === "ro") ? "ro" : "rw";
entries.push({
id: `${params.id}-${surface}-bind-${index}`,
kind: "containerMount",
source: `${inherited ? "oc://openclaw.config/agents/defaults/sandbox" : params.sourceBase}/${configSurface}/binds/#${inherited ? index : index - inheritedBinds.length}`,
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
bind,
bindHost: parsed?.host,
bindMode,
bindSurface: surface,
explicit: true
});
}
}
function pushSandboxBrowserPosture(entries, params) {
const localBrowser = !params.sharedSandboxScope ? asNonArrayRecord(params.sandbox.browser) : {};
const inheritedBrowser = asNonArrayRecord(params.inheritedSandbox.browser);
const localEnabled = asBoolean(localBrowser.enabled);
const inheritedEnabled = asBoolean(inheritedBrowser.enabled);
const enabled = localEnabled ?? inheritedEnabled ?? false;
if (!enabled && localEnabled === void 0 && inheritedEnabled === void 0) return;
const hasLocalRange = Object.hasOwn(localBrowser, "cdpSourceRange");
const localRange = normalizeOptionalString(localBrowser.cdpSourceRange);
const inheritedRange = normalizeOptionalString(inheritedBrowser.cdpSourceRange);
const inherited = enabled ? !hasLocalRange && inheritedRange !== void 0 : localEnabled === void 0 && inheritedEnabled !== void 0;
const value = enabled ? hasLocalRange ? localRange : inheritedRange : false;
entries.push({
id: `${params.id}-browser-cdp-source-range`,
kind: "browserCdpSourceRange",
source: `${inherited ? "oc://openclaw.config/agents/defaults/sandbox" : params.sourceBase}/browser/${enabled ? "cdpSourceRange" : "enabled"}`,
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
...value === void 0 ? {} : { value },
explicit: value !== void 0
});
if (!enabled) return;
pushSandboxPostureValue(entries, params, {
suffix: "browser/network",
kind: "containerNetwork",
...resolvePolicyValue(normalizeOptionalString(localBrowser.network), normalizeOptionalString(inheritedBrowser.network), DEFAULT_POLICY_SANDBOX_BROWSER_NETWORK),
networkSurface: "browser"
});
if (inheritedBrowser.binds !== void 0 || localBrowser.binds !== void 0) pushSandboxBindPosture(entries, params, "browser");
else if (params.effectiveBackend !== "docker" && params.effectiveBackend !== "podman") pushSandboxBindPosture(entries, params, "browser", "docker");
}
function sandboxScopeIsShared(sandbox, inheritedSandbox) {
const localScope = normalizeOptionalString(sandbox.scope);
const inheritedScope = normalizeOptionalString(inheritedSandbox.scope);
return (localScope ?? inheritedScope) === "shared";
}
function pushSandboxPostureValue(entries, params, entry) {
entries.push({
id: `${params.id}-${entry.suffix.replaceAll("/", "-")}`,
kind: entry.kind,
source: `${entry.inherited ? "oc://openclaw.config/agents/defaults/sandbox" : params.sourceBase}/${entry.suffix}`,
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
...entry.value === void 0 ? {} : { value: entry.value },
...entry.networkSurface === void 0 ? {} : { networkSurface: entry.networkSurface },
explicit: entry.explicit
});
}
//#endregion
//#region extensions/policy/src/policy-state-tools.ts
function scanPolicyTools(raw) {
const section = markdownSectionLines(raw);
if (section.length === 0) return [];
const tools = [];
let localNotesMode;
for (let index = 0; index < section.length; index += 1) {
const sectionLine = section[index];
const line = sectionLine?.text ?? "";
const sectionHeading = /^(#{1,6})\s+(.+?)\s*#*\s*$/u.exec(line);
const isChildHeading = sectionHeading?.[1]?.length === (sectionLine?.sectionDepth ?? 0) + 1;
if (line.includes("Skills provide your tools.") && line.includes("Keep local notes") && line.includes("TOOLS.md")) {
localNotesMode = "plain";
continue;
}
if (isChildHeading && /^Local notes\s*$/iu.test(sectionHeading?.[2] ?? "")) {
localNotesMode = "plain";
continue;
}
if (isChildHeading && /^Local notes \(migrated from TOOLS\.md\)\s*$/iu.test(sectionHeading?.[2] ?? "")) {
localNotesMode = "migrated";
continue;
}
if (localNotesMode && sectionHeading && sectionHeading[1].length <= (section[index]?.sectionDepth ?? 0) && slugify(sectionHeading[2] ?? "") === "tools") {
localNotesMode = void 0;
continue;
}
if (localNotesMode === "plain" && isChildHeading) localNotesMode = void 0;
if (localNotesMode) continue;
const heading = isChildHeading ? /^([^\s#]+)(.*)$/u.exec(sectionHeading?.[2] ?? "") : null;
const bullet = /^[-*+]\s+([^:\s][^:]*?)\s*:(.*)$/.exec(line);
const match = heading ?? bullet;
const toolName = match?.[1];
if (!toolName) continue;
const id = slugify(toolName);
if (!id) continue;
const metaLines = [match[2] ?? ""];
for (let metaIndex = index + 1; metaIndex < section.length; metaIndex += 1) {
const metaSectionLine = section[metaIndex];
const metaLine = metaSectionLine?.text ?? "";
const metaHeading = /^(#{1,6})\s+(.+?)\s*#*\s*$/u.exec(metaLine.trim());
if (metaHeading !== null && (metaHeading[1]?.length ?? 0) <= (metaSectionLine?.sectionDepth ?? 0) + 1 || /^[-*+]\s+[^:\s][^:]*?\s*:/.test(metaLine)) break;
metaLines.push(metaLine);
}
const meta = metaLines.join("\n");
const risk = riskFromMeta(meta);
const sensitivity = /\bsensitivity\s*:\s*([a-z0-9_-]+)\b/i.exec(meta)?.[1]?.toLowerCase();
const owner = /\bowner\s*:\s*([^\s#]+)\b/i.exec(meta)?.[1];
const capabilities = capabilityTokensFromMetaLines(metaLines);
tools.push({
id,
source: `oc://AGENTS.md/tools/${id}`,
line: section[index]?.line ?? index + 1,
...risk === void 0 ? {} : { risk },
...sensitivity === void 0 ? {} : { sensitivity },
...owner === void 0 ? {} : { owner },
...capabilities.length === 0 ? {} : { capabilities }
});
}
return tools;
}
function markdownSectionLines(raw) {
const lines = raw.split(/\r?\n/);
let sectionDepth;
let foundSection = false;
let fence;
const section = [];
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index] ?? "";
const fenceRun = /^\s*(`{3,}|~{3,})/.exec(line)?.[1];
const closingFenceRun = /^\s*(`{3,}|~{3,})\s*$/.exec(line)?.[1];
const marker = fenceRun?.[0];
if (marker && !fence) {
fence = {
marker,
length: fenceRun.length
};
continue;
}
if (closingFenceRun && fence && closingFenceRun[0] === fence.marker && closingFenceRun.length >= fence.length) {
fence = void 0;
continue;
}
if (fence) continue;
const heading = /^(#{1,6})\s+(.+?)\s*#*\s*$/.exec(line);
if (heading !== null) {
const depth = heading[1]?.length ?? 0;
const slug = slugify(heading[2] ?? "");
if (sectionDepth !== void 0 && depth <= sectionDepth) sectionDepth = void 0;
if (sectionDepth !== void 0) {
section.push({
line: index + 1,
text: line,
sectionDepth
});
continue;
}
if (depth <= 2 && slug === "tools") {
if (foundSection) section.push({
line: index + 1,
text: line,
sectionDepth: depth
});
foundSection = true;
sectionDepth = depth;
}
continue;
}
if (sectionDepth !== void 0) section.push({
line: index + 1,
text: line,
sectionDepth
});
}
return section;
}
function slugify(text) {
return text.toLowerCase().replace(/_/g, "-").replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
}
function riskFromMeta(meta) {
const namedRisk = /\brisk\s*:\s*([a-z0-9_-]+)\b/i.exec(meta)?.[1];
if (namedRisk !== void 0) return namedRisk.toLowerCase();
const alias = /\bR([0-5])\b/.exec(meta)?.[1];
return alias === void 0 ? void 0 : [
"low",
"low",
"medium",
"medium",
"high",
"critical"
][Number(alias)];
}
function capabilityTokensFromMetaLines(lines) {
return lines.flatMap((line, index) => {
const trimmed = line.trim();
if (trimmed.length === 0) return [];
const tokens = trimmed.match(/\b[A-Z][A-Z0-9_]{2,}\b/g) ?? [];
if (index === 0 || /\bcapabilities\s*:/i.test(trimmed)) return tokens;
const withoutTokens = tokens.reduce((remaining, token) => {
return remaining.replace(token, "");
}, trimmed);
return /^[\s,;:[\](){}#*_-]*$/.test(withoutTokens) ? tokens : [];
});
}
//#endregion
//#region extensions/policy/src/tool-policy-conformance.ts
function toolListCoversTool(list, tool) {
return !toolPolicy.createToolPolicyMatcher({ deny: [...list] })(tool);
}
function expandPolicyToolRequirement(value) {
return toolPolicy.expandToolGroups([value]);
}
//#endregion
//#region extensions/policy/src/policy-state-workspace.ts
function scanPolicyAgentWorkspace(cfg) {
const agents = asNonArrayRecord(cfg.agents);
const defaults = asNonArrayRecord(agents.defaults);
const defaultSandbox = asNonArrayRecord(defaults.sandbox);
const defaultTools = asNonArrayRecord(cfg.tools);
const entries = [];
pushAgentWorkspaceEvidence(entries, {
id: "agents-defaults",
scope: "defaults",
sandbox: defaultSandbox,
inheritedSandbox: {},
tools: defaultTools,
inheritedTools: {},
workspaceSourceBase: "oc://openclaw.config/agents/defaults",
toolsSourceBase: "oc://openclaw.config/tools"
});
collectPolicyConfiguredAgents(agents).forEach((configured) => {
const agent = configured.value;
if (!isRecord(agent)) return;
const sandbox = asNonArrayRecord(agent.sandbox);
const tools = asNonArrayRecord(agent.tools);
pushAgentWorkspaceEvidence(entries, {
id: configured.agentId,
scope: "agent",
agentId: configured.agentId,
sandbox,
inheritedSandbox: defaultSandbox,
tools,
inheritedTools: defaultTools,
workspaceSourceBase: configured.sourceBase,
toolsSourceBase: `${configured.sourceBase}/tools`
});
});
return entries.toSorted((a, b) => a.source.localeCompare(b.source) || a.id.localeCompare(b.id));
}
function pushAgentWorkspaceEvidence(entries, params) {
const explicitSandboxMode = normalizeOptionalString(params.sandbox.mode);
const inheritedSandboxMode = normalizeOptionalString(params.inheritedSandbox.mode);
const sandboxMode = explicitSandboxMode ?? inheritedSandboxMode ?? "off";
const sandboxModeCoversAgentMain = sandboxMode === "all";
const sandboxModeSource = explicitSandboxMode !== void 0 ? `${params.workspaceSourceBase}/sandbox/mode` : "oc://openclaw.config/agents/defaults/sandbox/mode";
const explicitWorkspaceAccess = normalizeOptionalString(params.sandbox.workspaceAccess);
const inheritedWorkspaceAccess = normalizeOptionalString(params.inheritedSandbox.workspaceAccess);
entries.push({
id: `${params.id}-workspace-access`,
kind: "workspaceAccess",
source: explicitWorkspaceAccess !== void 0 ? `${params.workspaceSourceBase}/sandbox/workspaceAccess` : "oc://openclaw.config/agents/defaults/sandbox/workspaceAccess",
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
value: explicitWorkspaceAccess ?? inheritedWorkspaceAccess ?? "none",
sandboxMode,
sandboxModeSource,
sandboxEnabled: sandboxModeCoversAgentMain,
explicit: explicitWorkspaceAccess !== void 0
});
const denySources = agentWorkspaceToolDenySources(params, sandboxModeCoversAgentMain);
for (const tool of AGENT_WORKSPACE_POLICY_TOOLS) {
const match = denySources.find((entry) => toolListCoversTool(entry.entries, tool));
entries.push({
id: `${params.id}-tool-${tool}`,
kind: "toolDeny",
source: match?.source ?? `${params.toolsSourceBase}/deny`,
scope: params.scope,
...params.agentId === void 0 ? {} : { agentId: params.agentId },
tool,
denied: match !== void 0,
explicit: match !== void 0
});
}
}
function agentWorkspaceToolDenySources(params, sandboxModeCoversAgentMain) {
const localSandboxToolDeny = configuredSandboxToolDenyEntries(params.tools);
const inheritedSandboxToolDeny = configuredSandboxToolDenyEntries(params.inheritedTools);
return [
{
entries: readStringArray(params.tools.deny),
source: `${params.toolsSourceBase}/deny`
},
{
entries: readStringArray(params.inheritedTools.deny),
source: "oc://openclaw.config/tools/deny"
},
...sandboxModeCoversAgentMain ? [localSandboxToolDeny !== void 0 ? {
entries: localSandboxToolDeny,
source: `${params.toolsSourceBase}/sandbox/tools/deny`
} : {
entries: inheritedSandboxToolDeny ?? [],
source: "oc://openclaw.config/tools/sandbox/tools/deny"
}] : []
];
}
function configuredSandboxToolDenyEntries(tools) {
const sandbox = asNonArrayRecord(tools.sandbox);
const sandboxTools = asNonArrayRecord(sandbox.tools);
return Array.isArray(sandboxTools.deny) ? readStringArray(sandboxTools.deny) : void 0;
}
//#endregion
//#region extensions/policy/src/policy-state-attestation.ts
function policyDocumentHash(policy) {
return `sha256:${createHash("sha256").update(stableJson(policy)).digest("hex")}`;
}
function createPolicyAttestation(input) {
const workspaceHash = policyDocumentHash(input.evidence);
const findingsHash = policyDocumentHash(input.findings);
return {
checkedAt: input.checkedAt,
...input.policyHash === void 0 ? {} : { policy: {
path: input.policyPath,
hash: input.policyHash
} },
workspace: {
scope: "policy",
hash: workspaceHash
},
findingsHash,
attestationHash: policyDocumentHash({
ok: input.ok,
policyHash: input.policyHash,
workspaceHash,
findingsHash
})
};
}
function stableJson(value) {
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
if (isRecord(value)) return `{${Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, child]) => `${JSON.stringify(key)}:${stableJson(child)}`).join(",")}}`;
return JSON.stringify(value);
}
//#endregion
//#region extensions/policy/src/policy-state.ts
function collectPolicyEvidence(cfg, options = {}) {
return {
channels: scanPolicyChannels(cfg),
mcpServers: scanPolicyMcpServers(cfg),
modelProviders: scanPolicyModelProviders(cfg),
modelRefs: scanPolicyModelRefs(cfg),
network: scanPolicyNetwork(cfg),
...options.includeIngress === false ? {} : { ingress: scanPolicyIngress(cfg) },
...options.includeGatewayExposure === false ? {} : { gatewayExposure: scanPolicyGatewayExposure(cfg) },
...options.includeAgentWorkspace === false ? {} : { agentWorkspace: scanPolicyAgentWorkspace(cfg) },
...options.includeDataHandling === false ? {} : { dataHandling: scanPolicyDataHandling(cfg) },
...options.includeToolPosture === false ? {} : { toolPosture: scanPolicyToolPosture(cfg) },
...options.includeSandboxPosture === false ? {} : { sandboxPosture: scanPolicySandboxPosture(cfg) },
...options.includeSecrets === false ? {} : { secrets: scanPolicySecrets(cfg) },
...options.includeAuthProfiles === false ? {} : { authProfiles: scanPolicyAuthProfiles(cfg) },
...options.includeExecApprovals === false || options.execApprovalsRaw === void 0 ? {} : { execApprovals: options.execApprovalsRaw === null ? [] : scanPolicyExecApprovals(options.execApprovalsRaw) },
...options.routing === void 0 ? {} : { routing: scanPolicyRouting(cfg, options.routing) },
...options.toolsRaw === void 0 ? {} : { tools: scanPolicyTools(options.toolsRaw) }
};
}
//#endregion
//#region extensions/policy/src/doctor/exec-approval-rules.ts
function execApprovalAllowlistExpectedShapeFinding(value, params) {
if (value === void 0) return;
if (!Array.isArray(value)) return policyShapeFinding(params.policyPath, `oc://${params.policyDocName}/${params.target}`, `${params.policyPath} ${params.property} must be an array.`, `Fix ${params.policyPath} so ${params.property} is an array of exec approval allowlist entries.`);
const invalidIndex = value.findIndex((entry) => execApprovalAllowlistRequirement(entry) === void 0);
if (invalidIndex < 0) return;
return policyShapeFinding(params.policyPath, `oc://${params.policyDocName}/${params.target}/#${invalidIndex}`, `${params.policyPath} ${params.property}[${invalidIndex}] must be a non-empty string or an object with pattern and optional argPattern strings.`, `Use entries such as "deploy" or { "pattern": "deploy", "argPattern": "^--prod$" }.`);
}
function readExecApprovalAllowlistRequirements(policy, path) {
const current = getPolicyPath(policy, path);
if (!Array.isArray(current)) return;
const entries = current.map(execApprovalAllowlistRequirement);
return entries.every((entry) => entry !== void 0) ? entries : void 0;
}
function execApprovalAllowlistRequirement(value) {
if (typeof value === "string") {
const pattern = value.trim();
return pattern === "" ? void 0 : execApprovalAllowlistRequirementFromParts(pattern);
}
if (!isRecord(value)) return;
if (unsupportedPolicyKey(value, ["argPattern", "pattern"]) !== void 0) return;
const pattern = typeof value.pattern === "string" ? value.pattern.trim() : "";
if (pattern === "") return;
const argPattern = typeof value.argPattern === "string" ? value.argPattern.trim() : void 0;
if (value.argPattern !== void 0 && argPattern === void 0) return;
return execApprovalAllowlistRequirementFromParts(pattern, argPattern === "" ? void 0 : argPattern);
}
function execApprovalAllowlistRequirementFromParts(pattern, argPattern) {
return {
key: execApprovalAllowlistRequirementKey(pattern, argPattern),
pattern,
...argPattern === void 0 ? {} : { argPattern }
};
}
function execApprovalAllowlistRequirementKey(pattern, argPattern) {
return `${pattern}\0${argPattern ?? ""}`;
}
function execApprovalAllowlistMissingTarget(agentId) {
return agentId === void 0 ? EXEC_APPROVALS_POLICY_URI : execApprovalsPolicyUri(`agents/${ocPathSegment(agentId)}/allowlist`);
}
function formatExecApprovalAllowlistEntry(entry) {
const pattern = entry?.pattern ?? "";
return entry?.argPattern === void 0 ? pattern : `${pattern} argPattern=${entry.argPattern}`;
}
function execApprovalAgentEntries(entries, defaults, field, agentId) {
const agents = entries.filter((entry) => entry.kind === "agent");
const wildcard = agents.find((entry) => entry.agentId === "*");
const hasValue = (entry) => entry[field] !== void 0 || field === "security" && entry.securityConfigured === true;
if (agentId === void 0) {
const explicit = agents.filter((entry) => hasValue(entry) || field === "security" && entry.agentId === "*");
return (field === "security" ? wildcard === void 0 : wildcard?.autoAllowSkills === void 0) ? [...explicit, defaults ?? syntheticExecApprovalAgentEntry("*")] : explicit;
}
const exact = agents.find((entry) => entry.agentId !== void 0 && normalizeAgentId(entry.agentId) === normalizeAgentId(agentId));
if (exact !== void 0 && hasValue(exact)) return [exact];
if (wildcard?.[field] !== void 0) return [wildcard];
return [(field === "security" ? exact ?? wildcard : void 0) ?? defaults ?? syntheticExecApprovalAgentEntry(agentId)];
}
function syntheticExecApprovalAgentEntry(agentId) {
return {
id: `agent:${agentId}:runtime-defaults`,
kind: "agent",
source: EXEC_APPROVALS_POLICY_URI,
agentId
};
}
//#endregion
//#region extensions/policy/src/doctor/ordered-shape.ts
function policyRuleValueIsValid(metadata, value) {
switch (metadata.valueType) {
case "boolean": return typeof value === "boolean";
case "channel-provider-deny-rules": return Array.isArray(value) && value.every((entry) => isRecord(entry) && isRecord(entry.when) && typeof entry.when.provider === "string" && entry.when.provider.trim() !== "");
case "routing-probes": return Array.isArray(value);
case "string-list":
case "string": {
if (metadata.valueType === "string-list" && metadata.policyPath.join(".") === "execApprovals.agents.allowlist.expected") return readExecApprovalAllowlistRequirements(value, []) !== void 0;
const allowed = metadata.allowedValues ?? metadata.orderedValues;
return stringListIssue(metadata.valueType === "string" ? [value] : value, metadata.caseSensitive === true ? allowed : allowed?.map((entry) => entry.toLowerCase()), metadata.caseSensitive === true ? "trim" : "lower", false) === void 0;
}
}
return false;
}
function firstPolicyShapeFinding(findings) {
for (const finding of findings) if (finding !== void 0) return finding;
}
function collectPolicyShapeFindings(findings) {
return Array.from(findings).filter((finding) => finding !== void 0);
}
function stringListIssue(value, allowed, normalize = "trim", visitHoles = true) {
if (!Array.isArray(value)) return { kind: "array" };
const index = value.findIndex((entry, entryIndex) => {
if (!visitHoles && !(entryIndex in value)) return false;
if (typeof entry !== "string") return true;
const normalized = normalize === "raw" ? entry : normalize === "lower" ? entry.trim().toLowerCase() : entry.trim();
return normalized === "" || allowed !== void 0 && !allowed.includes(normalized);
});
return index < 0 ? void 0 : {
kind: "entry",
index
};
}
/** Executes primitive checks; callers retain their explicit first/all diagnostic schedule. */
function createOrderedPolicyShape(value, context) {
const paths = (path) => {
const parts = path === "" ? [] : path.split(".");
return {
value: getPolicyPath(value, parts),
property: [context.propertyPrefix, ...parts].filter((part) => part !== void 0).join("."),
target: [context.targetPrefix, ...parts.map(ocPathSegment)].filter((part) => part !== void 0).join("/"),
hasTarget: context.targetPrefix !== void 0 || parts.length > 0
};
};
const diagnostic = (path, text, detail = {}) => {
const location = paths(path);
const property = location.property;
const fields = {
policy: context.policyPath,
property,
key: detail.key ?? "",
index: String(detail.index ?? ""),
unsupported: property + "." + (detail.key ?? ""),
valueName: detail.valueName ?? "",
allowed: detail.allowed?.join(", ") ?? ""
};
const render = (template) => template.replace(/\{(policy|property|key|index|unsupported|valueName|allowed)\}/g, (_, key) => fields[key]);
const suffix = detail.key !== void 0 ? "/" + ocPathSegment(detail.key) : detail.index !== void 0 ? "/#" + detail.index : "";
return policyShapeFinding(context.policyPath, "oc://" + context.policyDocName + (location.hasTarget ? "/" + location.target : "") + suffix, render(text.message), render(text.hint));
};
return {
value: (path) => paths(path).value,
finding: diagnostic,
object(path, hint = "Fix {policy} so {property} is an object.", required = false) {
const current = paths(path).value;
return current === void 0 && !required || isRecord(current) ? void 0 : diagnostic(path, {
message: "{policy} {property} must be an object.",
hint
});
},
keys(path, allowed, section, hint, message = "{policy} {unsupported} is not supported in " + section + " policy.") {
const current = paths(path).value;
if (!isRecord(current)) return;
const key = Object.keys(current).find((entry) => !allowed.includes(entry));
return key === void 0 ? void 0 : diagnostic(path, {
message,
hint
}, { key });
},
boolean(path, hint = "Set {property} to true or false.") {
const current = paths(path).value;
return current === void 0 || typeof current === "boolean" ? void 0 : diagnostic(path, {
message: "{policy} {property} must be a boolean.",
hint
});
},
string(path, hint, required = false) {
const current = paths(path).value;
return current === void 0 && !required || typeof current === "string" && current.trim() !== "" ? void 0 : diagnostic(path, {
message: "{policy} {property} must be a non-empty string.",
hint
});
},
enum(path, allowed, text) {
const current = paths(path).value;
return current === void 0 || typeof current === "string" && allowed.includes(current) ? void 0 : diagnostic(path, text, { allowed });
},
list(path, options = {}) {
const current = paths(path).value;
if (current === void 0) return;
const issue = stringListIssue(current, options.allowed, options.normalize);
if (issue === void 0) return;
const text = issue.kind === "array" ? options.array ?? {
message: "{policy} {property} must be an array.",
hint: "Fix {policy} so {property} is an array of {valueName}s."
} : options.entry ?? {
message: "{policy} {property}[{index}] must be a supported {valueName}.",
hint: "Use non-empty {valueName} entries." + (options.allowed === void 0 ? "" : " Supported values: {allowed}.")
};
return diagnostic(path, text, {
...issue.kind === "entry" ? { index: issue.index } : {},
valueName: options.valueName,
allowed: options.allowed
});
}
};
}
//#endregion
//#region extensions/policy/src/doctor/access-findings.ts
function metadataRequirementShapeFindings(policy, policyPath, policyDocName, path) {
const finding = createOrderedPolicyShape(policy, {
policyPath,
policyDocName
}).list(path, {
allowed: path === "tools.requireMetadata" ? SUPPORTED_TOOL_METADATA : SUPPORTED_AUTH_PROFILE_METADATA,
normalize: "lower",
array: {
message: "{policy} {property} must be an array of metadata keys.",
hint: "Use supported metadata keys: {allowed}."
},
entry: {
message: "{policy} {property}[{index}] must be a supported metadata key.",
hint: "Use supported metadata keys: {allowed}."
}
});
return finding === void 0 ? [] : [finding];
}
function invalidChannelDenyRuleFindings(policy, policyPath, policyDocName) {
const shape = createOrderedPolicyShape(policy, {
policyPath,
policyDocName
});
const rules = shape.value("channels.denyRules");
if (rules === void 0) return [];
if (!Array.isArray(rules)) return [shape.finding("channels.denyRules", {
message: "{policy} {property} must be an array.",
hint: "Fix {policy} so channel deny rules are an array."
})];
for (const [index, rule] of rules.entries()) {
if (!isRecord(rule)) continue;
const entry = createOrderedPolicyShape(rule, {
policyPath,
policyDocName,
propertyPrefix: "channels.denyRules[" + index + "]",
targetPrefix: "channels/denyRules/#" + index
});
const finding = entry.keys("", [
"id",
"reason",
"when"
], "", "Remove {unsupported} or use id, when.provider, and reason.", "{policy} {unsupported} is not supported in channel deny rules.") ?? entry.keys("when", ["provider"], "", "Remove {unsupported} or use when.provider.", "{policy} {unsupported} is not supported in channel deny rules.");
if (finding !== void 0) return [finding];
}
const index = rules.findIndex((rule) => !isChannelDenyRule(rule));
return index < 0 ? [] : [shape.finding("channels.denyRules", {
message: "{policy} {property}[{index}] must define when.provider as a string.",
hint: "Fix {policy} so each channel deny rule has a provider match."
}, { index })];
}
//#endregion
//#region extensions/policy/src/doctor/policy-evidence-finding.ts
function policyEvidenceFinding(entry, params, location = { path: "openclaw config" }) {
return {
checkId: params.checkId,
severity: "error",
message: params.message,
source: "policy",
...location,
ocPath: entry.source,
target: entry.source,
requirement: params.requirement,
fixHint: params.fixHint
};
}
function policyEvidenceRuleFindings(entries, rules, policyDocName, requirementBase) {
return rules.flatMap((rule) => entries.filter((entry) => (rule.kind === void 0 || entry.kind === rule.kind) && rule.violates(entry)).map((entry) => policyEvidenceFinding(entry, {
checkId: rule.checkId,
message: rule.message(entry),
requirement: `oc://${policyDocName}/${requirementBase}/${rule.path.join("/")}`,
fixHint: rule.fixHint
})));
}
//#endregion
//#region extensions/policy/src/doctor/strictness.ts
function isPolicyValueAtLeastAsStrict(metadata, candidate, baseline) {
switch (metadata.strictness) {
case "allowlist-subset":
case "denylist-superset":
case "exact-list": return comparePolicyStringLists(metadata, candidate, baseline);
case "ordered-string": return isPolicyOrderedStringAtLeastAsStrict(metadata, candidate, baseline);
case "requires-true": return baseline !== true || candidate === true;
case "requires-false": return baseline !== false || candidate === false;
case "routing-probes": return routingProbesAtLeastAsStrict(candidate, baseline);
}
return false;
}
function routingProbesAtLeastAsStrict(candidate, baseline) {
if (!Array.isArray(candidate) || !Array.isArray(baseline)) return false;
const candidateById = /* @__PURE__ */ new Map();
for (const entry of candidate) {
if (!isRecord(entry) || !hasNonEmptyString(entry.id) || candidateById.has(entry.id)) return false;
candidateById.set(entry.id, entry);
}
return baseline.every((baselineEntry) => {
if (!isRecord(baselineEntry) || !hasNonEmptyString(baselineEntry.id)) return false;
const candidateEntry = candidateById.get(baselineEntry.id);
if (!isRecord(candidateEntry)) return false;
const candidateRoute = canonicalRoutingRoute(candidateEntry.route);
const baselineRoute = canonicalRoutingRoute(baselineEntry.route);
if (candidateRoute === void 0 || baselineRoute === void 0 || candidateRoute !== baselineRoute || !isRecord(candidateEntry.expect) || !isRecord(baselineEntry.expect) || !hasNonEmptyString(candidateEntry.expect.agentId) || !hasNonEmptyString(baselineEntry.expect.agentId) || normalizeAgentId(candidateEntry.expect.agentId) !== normalizeAgentId(baselineEntry.expect.agentId)) return false;
return routingMatchKindsAtLeastAsStrict(candidateEntry.expect.matchedBy, baselineEntry.expect.matchedBy);
});
}
function routingMatchKindsAtLeastAsStrict(candidate, baseline) {
if (baseline === void 0) return candidate === void 0 || validPolicyRoutingMatchKinds(candidate);
if (!validPolicyRoutingMatchKinds(candidate) || !validPolicyRoutingMatchKinds(baseline)) return false;
const baselineKinds = new Set(baseline);
return candidate.every((entry) => baselineKinds.has(entry));
}
function canonicalRoutingRoute(value) {
if (!isRecord(value) || Object.keys(value).some((key) => ![
"accountId",
"channel",
"guildId",
"memberRoleIds",
"parentPeer",
"peer",
"teamId"
].includes(key)) || !hasNonEmptyString(value.channel) || [
value.accountId,
value.guildId,
value.teamId
].some((entry) => entry !== void 0 && !hasNonEmptyString(entry))) return;
const peer = canonicalRoutingPeer(value.peer);
const parentPeer = canonicalRoutingPeer(value.parentPeer);
if (peer === null || parentPeer === null) return;
const memberRoleIds = value.memberRoleIds;
if (memberRoleIds !== void 0 && (!Array.isArray(memberRoleIds) || memberRoleIds.length === 0 || memberRoleIds.some((entry) => !hasNonEmptyString(entry)) || new Set(memberRoleIds).size !== memberRoleIds.length)) return;
return JSON.stringify({
channel: normalizeLowercaseStringOrEmpty(value.channel),
accountId: normalizeAccountId(value.accountId),
peer,
parentPeer,
guildId: normalizeRoutingId(value.guildId),
teamId: normalizeRoutingId(value.teamId),
memberRoleIds: memberRoleIds?.toSorted()
});
}
function canonicalRoutingPeer(value) {
if (value === void 0) return;
if (!isRecord(value) || Object.keys(value).some((key) => key !== "id" && key !== "kind") || ![
"channel",
"direct",
"group"
].some((kind) => kind === value.kind) || !hasNonEmptyString(value.id)) return null;
return {
kind: value.kind,
id: value.id.trim()
};
}
function normalizeRoutingId(value) {
return typeof value === "string" ? value.trim() : void 0;
}
function isPolicyOrderedStringAtLeastAsStrict(metadata, candidate, baseline) {
const candidateValue = policyString(candidate, metadata);
const baselineValue = policyString(baseline, metadata);
if (candidateValue === void 0 || baselineValue === void 0 || metadata.orderedValues === void 0) return false;
const orderedValues = metadata.orderedValues.map((entry) => metadata.caseSensitive === true ? entry : entry.toLowerCase());
const candidateIndex = orderedValues.indexOf(candidateValue);
const baselineIndex = orderedValues.indexOf(baselineValue);
return candidateIndex >= 0 && baselineIndex >= 0 && candidateIndex >= baselineIndex;
}
function comparePolicyStringLists(metadata, candidate, baseline) {
const candidateList = policyStringList(candidate, metadata);
const baselineList = policyStringList(baseline, metadata);
if (candidateList === void 0 || baselineList === void 0) return false;
if (metadata.strictness === "allowlist-subset") {
if (metadata.emptyList === "disabled") {
if (baselineList.length === 0) return true;
if (candidateList.length === 0) return false;
}
const allowed = new Set(baselineList);
return candidateList.every((entry) => allowed.has(entry));
}
if (metadata.strictness === "denylist-superset") {
if (metadata.policyPath.join(".") === "tools.denyTools") return baselineList.flatMap(expandPolicyToolRequirement).every((tool) => toolListCoversTool(candidateList, tool));
const denied = new Set(candidateList);
return baselineList.every((entry) => denied.has(entry));
}
const candidateSorted = candidateList.toSorted();
const baselineSorted = baselineList.toSorted();
return candidateSorted.length === baselineSorted.length && candidateSorted.every((entry, index) => entry === baselineSorted[index]);
}
function policyStringList(value, metadata) {
if (metadata.valueType === "channel-provider-deny-rules") return channelProviderDenyRuleList(value, metadata);
if (!Array.isArray(value)) return;
if (metadata.policyPath.join(".") === "execApprovals.agents.allowlist.expected") return readExecApprovalAllowlistRequirements(value, [])?.map((entry) => entry.key);
if (!value.every((entry) => typeof entry === "string")) return;
return value.map((entry) => entry.trim()).filter(Boolean).map((entry) => normalizePolicyStringListEntry(entry, metadata));
}
function normalizePolicyStringListEntry(entry, metadata) {
if (metadata.normalizeValues === "model-provider") return normalizeProviderId(entry);
return metadata.caseSensitive === true ? entry : entry.toLowerCase();
}
function channelProviderDenyRuleList(value, metadata) {
if (!Array.isArray(value)) return;
const providers = [];
for (const entry of value) {
if (!isChannelDenyRule(entry)) return;
const provider = entry.when.provider.trim();
if (provider !== "") providers.push(metadata.caseSensitive === true ? provider : provider.toLowerCase());
}
return providers;
}
function policyString(value, metadata) {
if (typeof value !== "string" || value.trim() === "") return;
const trimmed = value.trim();
return metadata.caseSensitive === true ? trimmed : trimmed.toLowerCase();
}
//#endregion
//#region extensions/policy/src/doctor/policy-scope.ts
function scopedAgentEvidenceMatches(entry, policyAgentId, entries, inheritedEntry) {
return scopedAgentIdMatches(entry.agentId, policyAgentId) || inheritedEntry && !entries.some((candidate) => candidate.scope === "agent" && candidate.kind === entry.kind && scopedAgentIdMatches(candidate.agentId, policyAgentId));
}
function scopedAgentIdMatches(evidenceAgentId, policyAgentId) {
return evidenceAgentId !== void 0 && normalizeAgentId(evidenceAgentId) === normalizeAgentId(policyAgentId);
}
function policyHasRules(policy, section) {
if (!isRecord(policy)) return false;
const hasRules = (document) => {
if (section === "execApprovals") {
const value = document.execApprovals;
return isRecord(value) && (value.requireFile !== void 0 || isRecord(value.defaults) || isRecord(value.agents));
}
return POLICY_RULE_METADATA.some((rule) => rule.policyPath[0] === section && (section !== "tools" || rule.policyPath[1] !== "requireMetadata") && getPolicyPath(document, rule.policyPath) !== void 0);
};
return hasRules(policy) || section !== "auth" && section !== "gateway" && section !== "secrets" && scopedPolicyOverlays(policy).some(([, overlay]) => hasRules(overlay));
}
function scopedPolicyOverlays(policy) {
if (!isRecord(policy) || !isRecord(policy.scopes)) return [];
return Object.entries(policy.scopes).filter((entry) => isRecord(entry[1]));
}
function agentScopedPolicyTargets(policy) {
return scopedPolicyOverlays(policy).flatMap(([scopeName, overlay]) => normalizePolicySelectorValues(overlay.agentIds, "agentIds").map((agentId) => ({
scopeName,
agentId,
overlay
})));
}
function channelScopedPolicyTargets(policy) {
return scopedPolicyOverlays(policy).flatMap(([scopeName, overlay]) => normalizePolicySelectorValues(overlay.channelIds, "channelIds").map((channelId) => ({
scopeName,
channelId,
overlay
})));
}
function normalizePolicySelectorValues(value, selector) {
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim() !== "").map(selector === "agentIds" ? normalizeAgentId : normalizeLowercaseStringOrEmpty) : [];
}
function duplicateScopedPolicyFieldFinding(scopes, params) {
return duplicateScopedFieldFinding(scopes, {
...params,
selector: "agentIds",
selectorLabel: "agent"
}) ?? duplicateScopedFieldFinding(scopes, {
...params,
selector: "channelIds",
selectorLabel: "channel"
});
}
function duplicateScopedFieldFinding(scopes, params) {
const seen = /* @__PURE__ */ new Map();
for (const [scopeName, overlay] of Object.entries(scopes)) {
if (!isRecord(overlay)) continue;
const fields = scopedPolicyFields(scopeName, overlay, params.selector);
for (const selectorValue of normalizePolicySelectorValues(overlay[params.selector], params.selector)) for (const field of fields) {
const topLevelValue = getPolicyPath(params.policy, field.metadata.policyPath);
if (topLevelValue !== void 0 && !isPolicyValueAtLeastAsStrict(field.metadata, field.value, topLevelValue)) return policyShapeFinding(params.policyPath, `oc://${params.policyDocName}/${field.targetPath}`, `${params.policyPath} scopes.${scopeName}.${field.propertyPath} is weaker than the top-level ${field.propertyPath} policy.`, `Use an equally or more restrictive scoped value, or remove the scoped override.`);
const key = `${selectorValue}\0${field.propertyPath}`;
const previous = seen.get(key);
if (previous !== void 0 && !isPolicyValueAtLeastAsStrict(field.metadata, field.value, previous.field.value)) return policyShapeFinding(params.policyPath, `oc://${params.policyDocName}/${field.targetPath}`, `${params.policyPath} scopes.${scopeName}.${field.propertyPath} is not an equally or more restrictive override of ${previous.propertyPath} for ${params.selectorLabel} '${selectorValue}'.`, `Use one effective scoped value per ${params.selectorLabel}, or make later scoped values stricter according to policy metadata.`);
seen.set(key, {
propertyPath: `scopes.${scopeName}.${field.propertyPath}`,
field
});
}
}
}
function scopedPolicyFields(scopeName, overlay, selector) {
const prefix = `scopes/${ocPathSegment(scopeName)}`;
return POLICY_RULE_METADATA.filter((rule) => rule.scopeSelectors?.includes(selector) === true).map((rule) => ({
rule,
value: getPolicyPath(overlay, rule.policyPath)
})).filter((entry) => entry.value !== void 0).map(({ rule, value }) => ({
propertyPath: rule.policyPath.join("."),
targetPath: `${prefix}/${rule.policyPath.map(ocPathSegment).join("/")}`,
metadata: rule,
value
}));
}
//#endregion
//#region extensions/policy/src/doctor/posture-shapes.ts
function object(path) {
return {
kind: "object",
path: path.split(".")
};
}
function keys(path, section, hint, scoped = false) {
const prefix = path.split(".");
const allowed = /* @__PURE__ */ new Set();
for (const entry of POLICY_RULE_METADATA) if (prefix.every((part, index) => entry.policyPath[index] === part) && (!scoped || entry.scopeSelectors?.includes("agentIds"))) {
const key = entry.policyPath[prefix.length];
if (key !== void 0) allowed.add(key);
}
return {
kind: "keys",
path: prefix,
allowed: [...allowed],
section,
hint,
scoped
};
}
function rule(path, valueName = "", style) {
const metadata = POLICY_RULE_METADATA.find((entry) => entry.policyPath.join(".") === path);
if (metadata === void 0 || metadata.valueType !== "boolean" && metadata.valueType !== "string-list") throw new Error(`Unsupported posture shape rule: ${path}`);
let listStyle;
if (style === "node-commands") listStyle = { kind: style };
else if (style !== void 0) {
if (metadata.allowedValues === void 0) throw new Error(`Missing posture shape enum values: ${path}`);
listStyle = {
kind: style,
allowed: metadata.allowedValues
};
}
return {
kind: "rule",
path: metadata.policyPath,
metadata,
valueName,
style: listStyle
};
}
const workspace = [
object("agents.workspace"),
keys("agents.workspace", "agent workspace", "a supported agent workspace policy rule"),
rule("agents.workspace.allowedAccess", "", "workspace-access"),
rule("agents.workspace.denyTools", "", "workspace-tools")
];
const tools = [
keys("tools", "tools", "a supported tools policy rule"),
...[
"profiles",
"fs",
"exec",
"elevated",
"alsoAllow"
].map((key) => object(`tools.${key}`)),
keys("tools.profiles", "tools", { key: "allow" }),
rule("tools.profiles.allow", "tool profile id"),
keys("tools.fs", "tools", { key: "requireWorkspaceOnly" }),
rule("tools.fs.requireWorkspaceOnly"),
keys("tools.exec", "tools", "a supported tools exec policy rule"),
rule("tools.exec.allowSecurity", "exec security mode"),
rule("tools.exec.requireAsk", "exec ask mode"),
rule("tools.exec.allowHosts", "exec host"),
keys("tools.elevated", "tools", { key: "allow" }),
rule("tools.elevated.allow"),
keys("tools.alsoAllow", "tools", { key: "expected" }),
rule("tools.alsoAllow.expected", "tool id"),
rule("tools.denyTools", "tool id or group")
];
const gatewaySections = [
"exposure",
"auth",
"controlUi",
"remote",
"http",
"nodes"
];
const shapes = {
agents: [
object("agents"),
keys("agents", "agents", { key: "workspace" }),
...workspace
],
workspace,
tools,
"scoped-tools": [
keys("tools", "agent-scoped tools", "", true),
...[
"profiles",
"fs",
"exec",
"elevated",
"alsoAllow"
].map((key) => keys(`tools.${key}`, "agent-scoped tools", "", true)),
...tools
],
sandbox: [
object("sandbox"),
keys("sandbox", "sandbox", "a supported sandbox posture rule"),
rule("sandbox.requireMode", "sandbox mode"),
rule("sandbox.allowBackends", "sandbox backend id"),
object("sandbox.containers"),
object("sandbox.browser"),
keys("sandbox.containers", "sandbox", "a supported sandbox container posture rule"),
...POLICY_RULE_METADATA.filter((entry) => entry.policyPath[0] === "sandbox" && entry.policyPath[1] === "containers").map((entry) => rule(entry.policyPath.join("."))),
keys("sandbox.browser", "sandbox", "a supported sandbox browser posture rule"),
rule("sandbox.browser.requireCdpSourceRange")
],
gateway: [
object("gateway"),
...gatewaySections.map((key) => object(`gateway.${key}`)),
keys("gateway", "Gateway", "a supported Gateway policy section"),
...gatewaySections.map((key) => keys(`gateway.${key}`, "Gateway", "a supported Gateway policy rule")),
rule("gateway.exposure.allowNonLoopbackBind"),
rule("gateway.exposure.allowTailscaleFunnel"),
rule("gateway.auth.requireAuth"),
rule("gateway.auth.requireExplicitRateLimit"),
rule("gateway.controlUi.allowInsecure"),
rule("gateway.remote.allow"),
rule("gateway.http.requireUrlAllowlists"),
rule("gateway.http.denyEndpoints", "", "http-endpoints"),
rule("gateway.nodes.denyCommands", "", "node-commands")
]
};
function posturePolicyShapeFinding(shape, value, params) {
if (value === void 0) return;
const root = shape === "workspace" ? "agents.workspace" : shape === "scoped-tools" ? "tools" : shape;
const rootDepth = root.split(".").length;
const validator = createOrderedPolicyShape(value, {
...params,
propertyPrefix: params.propertyPrefix ?? root,
targetPrefix: params.targetPrefix ?? root.replaceAll(".", "/")
});
function* findings() {
for (const step of shapes[shape]) {
const path = step.path.slice(rootDepth).join(".");
if (step.kind === "object") yield validator.object(path);
else if (step.kind === "keys") {
const hint = typeof step.hint === "string" ? step.hint : "{property}." + step.hint.key;
yield validator.keys(path, step.allowed, step.section, step.scoped ? "Move {unsupported} to top-level tools or use a supported scoped tools posture rule." : "Remove {unsupported} or use " + hint + ".");
} else if (step.metadata.valueType === "boolean") yield validator.boolean(path, shape === "gateway" ? "Fix {policy} so {property} is true or false." : void 0);
else if (step.style === void 0) yield validator.list(path, {
allowed: step.metadata.allowedValues,
valueName: step.valueName
});
else yield customListShapeFinding(validator, path, step.style);
}
}
return firstPolicyShapeFinding(findings());
}
function customListShapeFinding(validator, path, style) {
let arrayHint;
let entryHint;
let entryMessage;
switch (style.kind) {
case "workspace-access":
arrayHint = "Use workspace access values such as [\"none\", \"ro\"].";
entryHint = arrayHint;
entryMessage = "must be none, ro, or rw.";
break;
case "workspace-tools":
arrayHint = "Use tool ids such as [\"exec\", \"process\", \"write\", \"edit\", \"apply_patch\"].";
entryHint = "Use supported tool ids: {allowed}.";
entryMessage = "must be a supported agent workspace tool id.";
break;
case "http-endpoints":
arrayHint = "Use an array of endpoint ids such as [\"responses\"] or remove gateway.http.denyEndpoints.";
entryHint = "Use supported endpoint ids: {allowed}.";
entryMessage = "must be a supported endpoint id.";
break;
case "node-commands":
arrayHint = "Use an array of node command ids such as [\"system.run\"] or remove gateway.nodes.denyCommands.";
entryHint = "Use non-empty node command ids.";
entryMessage = "must be a non-empty node command id.";
}
return validator.list(path, {
allowed: style.kind === "node-commands" ? void 0 : style.allowed,
normalize: style.kind === "workspace-access" ? "raw" : "trim",
array: {
message: "{policy} {property} must be an array.",
hint: arrayHint
},
entry: {
message: "{policy} {property}[{index}] " + entryMessage,
hint: entryHint
}
});
}
//#endregion
//#region extensions/policy/src/doctor/access-shapes.ts
function ingressPolicyShapeFinding(value, params) {
if (value === void 0) return;
const shape = createOrderedPolicyShape(value, {
...params,
propertyPrefix: params.propertyPrefix ?? "ingress",
targetPrefix: params.targetPrefix ?? "ingress"
});
function* findings() {
yield shape.object("");
if (params.allowSession === false && shape.value("session") !== void 0) yield shape.finding("session", {
message: "{policy} {property} is not supported by the channelIds selector.",
hint: "Move session ingress rules to top-level ingress; scoped ingress currently supports ingress.channels.*."
});
yield shape.keys("", ["channels", "session"], "ingress", "Remove {unsupported} or use ingress.session or ingress.channels.");
yield shape.object("session");
yield shape.object("channels");
yield shape.keys("session", ["requireDmScope"], "ingress", "Remove {unsupported} or use {property}.requireDmScope.");
yield shape.enum("session.requireDmScope", SUPPORTED_DM_SCOPES, {
message: "{policy} {property} must be a supported DM scope.",
hint: "Use supported DM scopes: {allowed}."
});
yield shape.keys("channels", [
"allowDmPolicies",
"denyOpenGroups",
"requireMentionInGroups"
], "ingress", "Remove {unsupported} or use a supported ingress channel policy rule.");
yield shape.list("channels.allowDmPolicies", {
allowed: SUPPORTED_DM_POLICIES,
valueName: "DM policy"
});
yield shape.boolean("channels.denyOpenGroups");
yield shape.boolean("channels.requireMentionInGroups");
}
return firstPolicyShapeFinding(findings());
}
function execApprovalsPolicyShapeFinding(value, params) {
if (value === void 0) return;
const context = {
...params,
propertyPrefix: params.propertyPrefix ?? "execApprovals",
targetPrefix: params.targetPrefix ?? "execApprovals"
};
const shape = createOrderedPolicyShape(value, context);
const allowDefaults = params.allowDefaults ?? true;
function* findings() {
yield shape.object("");
yield shape.keys("", allowDefaults ? [
"agents",
"defaults",
"requireFile"
] : ["agents"], "exec approvals", "Remove {unsupported} or use a supported execApprovals rule.");
yield shape.boolean("requireFile", "Set execApprovals.requireFile to true or false.");
for (const section of allowDefaults ? ["defaults", "agents"] : ["agents"]) yield shape.object(section);
if (allowDefaults) {
yield shape.keys("defaults", ["allowSecurity"], "exec approvals", "Use execApprovals.defaults.allowSecurity or remove the unsupported rule.");
yield shape.list("defaults.allowSecurity", {
allowed: SUPPORTED_EXEC_APPROVAL_SECURITY,
valueName: "exec approval security mode"
});
}
yield shape.keys("agents", [
"allowAutoAllowSkills",
"allowSecurity",
"allowlist"
], "exec approvals", "Use execApprovals.agents.allowSecurity, execApprovals.agents.allowAutoAllowSkills, or execApprovals.agents.allowlist.expected.");
yield shape.list("agents.allowSecurity", {
allowed: SUPPORTED_EXEC_APPROVAL_SECURITY,
valueName: "exec approval security mode"
});
yield shape.boolean("agents.allowAutoAllowSkills", "Set execApprovals.agents.allowAutoAllowSkills to true or false.");
yield shape.object("agents.allowlist");
yield shape.keys("agents.allowlist", ["expected"], "exec approvals", "Use execApprovals.agents.allowlist.expected or remove the unsupported rule.");
yield execApprovalAllowlistExpectedShapeFinding(shape.value("agents.allowlist.expected"), {
policyDocName: params.policyDocName,
policyPath: params.policyPath,
property: context.propertyPrefix + ".agents.allowlist.expected",
target: context.targetPrefix + "/agents/allowlist/expected"
});
}
return firstPolicyShapeFinding(findings());
}
function scopedDataHandlingPolicyShapeFinding(dataHandling, params) {
const shape = createOrderedPolicyShape(dataHandling, {
...params,
propertyPrefix: "scopes." + params.scopeName + ".dataHandling",
targetPrefix: params.targetPrefix + "/dataHandling"
});
function* findings() {
yield shape.keys("", ["memory"], "", "Move global data-handling rules to top-level dataHandling, or use dataHandling.memory with agentIds.", "{policy} {unsupported} is not a supported scoped policy section.");
yield shape.object("memory", "Fix {policy} so the scoped dataHandling.memory policy section is an object.");
yield shape.keys("memory", ["denySessionTranscriptIndexing"], "", "Use dataHandling.memory.denySessionTranscriptIndexing or remove the unsupported rule.", "{policy} {unsupported} is not a supported scoped policy rule.");
yield shape.boolean("memory.denySessionTranscriptIndexing", "Set dataHandling.memory.denySessionTranscriptIndexing to true or false.");
}
return firstPolicyShapeFinding(findings());
}
//#endregion
//#region extensions/policy/src/doctor/scoped-policy-shape.ts
function scopedPolicyShapeFinding(value, params) {
if (value === void 0) return;
const root = createOrderedPolicyShape(value, {
...params,
propertyPrefix: "scopes",
targetPrefix: "scopes"
});
if (!isRecord(value)) return root.object("", "Fix {policy} so scopes maps scope names to policy overlays with selectors such as agentIds.");
const scopes = value;
function* findings() {
for (const [scopeName, overlay] of Object.entries(scopes)) {
const targetPrefix = "scopes/" + ocPathSegment(scopeName);
const propertyPrefix = "scopes." + scopeName;
const shape = createOrderedPolicyShape(overlay, {
...params,
propertyPrefix,
targetPrefix
});
yield shape.object("", "Fix {policy} so the named policy scope is an object.", true);
const hasAgentIds = shape.value("agentIds") !== void 0;
const hasChannelIds = shape.value("channelIds") !== void 0;
if (!hasAgentIds && !hasChannelIds) yield shape.finding("", {
message: "{policy} {property} must define at least one selector.",
hint: "List agentIds for agent-scoped policy or channelIds for channel-scoped ingress policy."
});
yield scopedSelectorShapeFinding(shape, "agentIds", "agent");
yield scopedSelectorShapeFinding(shape, "channelIds", "channel");
if (shape.value("ingress") !== void 0 && !hasChannelIds) yield shape.finding("ingress", {
message: "{policy} {property} requires the channelIds selector.",
hint: "Move global ingress rules to top-level ingress, or list channelIds for channel-scoped ingress policy."
});
if ([
"agents",
"dataHandling",
"execApprovals",
"tools",
"sandbox"
].some((section) => shape.value(section) !== void 0) && !hasAgentIds) yield shape.finding("", {
message: "{policy} {property} uses agent-scoped sections without agentIds.",
hint: "List agentIds for agents.workspace, dataHandling.memory, tools, or sandbox policy sections."
});
yield shape.keys("", [
"agentIds",
"channelIds",
"agents",
"dataHandling",
"execApprovals",
"tools",
"sandbox",
"ingress"
], "", "Use agentIds with agents.workspace, dataHandling.memory, execApprovals, tools, or sandbox, and channelIds with ingress.channels.", "{policy} {unsupported} is not a supported scoped policy section.");
yield shape.object("dataHandling", "Fix {policy} so the scoped dataHandling policy section is an object.");
const dataHandling = shape.value("dataHandling");
if (isRecord(dataHandling)) yield scopedDataHandlingPolicyShapeFinding(dataHandling, {
...params,
targetPrefix,
scopeName
});
yield shape.object("agents", "Fix {policy} so the scoped agents policy section is an object.");
yield shape.keys("agents", ["workspace"], "", "Move the rule under agents.workspace or a supported scoped top-level section.", "{policy} {unsupported} is not supported by the agentIds selector.");
const sectionParams = (section) => ({
...params,
targetPrefix: targetPrefix + "/" + section.replaceAll(".", "/"),
propertyPrefix: propertyPrefix + "." + section
});
yield posturePolicyShapeFinding("workspace", shape.value("agents.workspace"), sectionParams("agents.workspace"));
yield execApprovalsPolicyShapeFinding(shape.value("execApprovals"), {
...sectionParams("execApprovals"),
allowDefaults: false
});
yield shape.object("tools", "Fix {policy} so the scoped tools policy overlay is an object.");
yield posturePolicyShapeFinding("scoped-tools", shape.value("tools"), sectionParams("tools"));
yield posturePolicyShapeFinding("sandbox", shape.value("sandbox"), sectionParams("sandbox"));
yield ingressPolicyShapeFinding(shape.value("ingress"), {
...sectionParams("ingress"),
allowSession: false
});
}
yield duplicateScopedPolicyFieldFinding(scopes, params);
}
return firstPolicyShapeFinding(findings());
}
function scopedSelectorShapeFinding(shape, path, kind) {
const valueName = kind + " id";
const finding = shape.list(path, { valueName });
if (finding !== void 0) return finding;
const value = shape.value(path);
if (!Array.isArray(value)) return;
if (value.length === 0) return shape.finding(path, {
message: "{policy} {property} must include at least one {valueName}.",
hint: "Add one or more {valueName}s to {policy} {property}."
}, { valueName });
const seen = /* @__PURE__ */ new Map();
for (const [index, rawValue] of value.entries()) {
if (typeof rawValue !== "string") continue;
const normalized = kind === "agent" ? normalizeAgentId(rawValue) : normalizeLowercaseStringOrEmpty(rawValue);
const previous = seen.get(normalized);
if (previous !== void 0) return shape.finding(path, {
message: "{policy} {property}[{index}] duplicates {property}[" + previous + "] after normalization.",
hint: "List each {valueName} only once per named policy scope."
}, {
index,
valueName
});
seen.set(normalized, index);
}
}
function hasValidScopedPolicy(policy, policyPath, policyDocName) {
return isRecord(policy) && scopedPolicyShapeFinding(policy.scopes, {
policyDocName,
policyPath,
policy
}) === void 0;
}
//#endregion
//#region extensions/policy/src/doctor/agent-workspace-findings.ts
function agentWorkspaceFindings(policy, policyPath, policyDocName, evidence) {
if (posturePolicyShapeFinding("agents", isRecord(policy) ? policy.agents : void 0, {
policyDocName,
policyPath
}) !== void 0) return [];
const entries = evidence.agentWorkspace ?? [];
const findings = workspaceFindings(getPolicyPath(policy, ["agents", "workspace"]), policyDocName, "agents/workspace", entries);
if (hasValidScopedPolicy(policy, policyPath, policyDocName)) for (const target of agentScopedPolicyTargets(policy)) findings.push(...workspaceFindings(getPolicyPath(target.overlay, ["agents", "workspace"]), policyDocName, `scopes/${ocPathSegment(target.scopeName)}/agents/workspace`, entries.filter((entry) => scopedAgentEvidenceMatches(entry, target.agentId, entries, entry.scope === "defaults"))));
return findings;
}
function workspaceFindings(workspace, policyDocName, requirementBase, entries) {
const allowed = new Set(readStringList(workspace, ["allowedAccess"]));
const requiredDeniedTools = new Set(readStringList(workspace, ["denyTools"]));
return [...entries.filter((entry) => allowed.size > 0 && entry.kind === "workspaceAccess" && entry.value !== void 0 && (entry.sandboxEnabled !== true || !allowed.has(entry.value))).map((entry) => {
const sandboxDisabled = entry.sandboxEnabled !== true;
const observed = sandboxDisabled ? `sandbox mode '${entry.sandboxMode ?? "off"}'` : `sandbox workspaceAccess '${entry.value ?? ""}'`;
return policyEvidenceFinding({ source: sandboxDisabled ? entry.sandboxModeSource ?? entry.source : entry.source }, {
checkId: CHECK_IDS.policyAgentsWorkspaceAccessDenied,
message: `${workspaceLabel(entry)} ${observed} is not allowed by policy.`,
requirement: `oc://${policyDocName}/${requirementBase}/allowedAccess`,
fixHint: "Enable sandbox mode with workspaceAccess none/ro or update policy after review."
});
}), ...entries.filter((entry) => entry.kind === "toolDeny" && entry.tool !== void 0 && requiredDeniedTools.has(entry.tool) && entry.denied !== true).map((entry) => policyEvidenceFinding(entry, {
checkId: CHECK_IDS.policyAgentsToolNotDenied,
message: `${workspaceLabel(entry)} does not deny required tool '${entry.tool ?? ""}'.`,
requirement: `oc://${policyDocName}/${requirementBase}/denyTools`,
fixHint: "Add the tool to tools.deny or agents.entries.<id>.tools.deny, or update policy after review."
}))];
}
function workspaceLabel(entry) {
return entry.agentId === void 0 ? "agents.defaults" : `agent '${entry.agentId}'`;
}
//#endregion
//#region extensions/policy/src/doctor/data-auth-shapes.ts
function dataHandlingPolicyShapeFindings(policy, policyPath, policyDocName) {
if (!isRecord(policy) || !isRecord(policy.dataHandling)) return [];
const shape = createOrderedPolicyShape(policy, {
policyPath,
policyDocName
});
const sections = [
["sensitiveLogging", "requireRedaction"],
["telemetry", "denyContentCapture"],
["retention", "requireSessionMaintenance"],
["memory", "denySessionTranscriptIndexing"]
];
function* sectionRules(section, rule) {
yield shape.keys("dataHandling." + section, [rule], "data-handling", "Remove {unsupported} or use {property}." + rule + ".");
yield shape.boolean("dataHandling." + section + "." + rule);
}
function* findings() {
yield shape.keys("dataHandling", [
"memory",
"retention",
"sensitiveLogging",
"telemetry"
], "data-handling", "Remove {unsupported} or use a supported data-handling policy rule.");
for (const [section] of sections) yield shape.object("dataHandling." + section, "Fix {property} so it contains boolean policy rules.");
for (const [section, rule] of sections) yield firstPolicyShapeFinding(sectionRules(section, rule));
}
return collectPolicyShapeFindings(findings());
}
function dataHandlingLabel(entry) {
return entry.agentId === void 0 ? "Global data handling config" : "agent '" + entry.agentId + "'";
}
function secretPolicyShapeFindings(policy, policyPath, policyDocName) {
if (!isRecord(policy) || !isRecord(policy.secrets)) return [];
const shape = createOrderedPolicyShape(policy, {
policyPath,
policyDocName
});
function* findings() {
yield shape.boolean("secrets.requireManagedProviders");
yield shape.boolean("secrets.allowInsecureProviders");
yield shape.list("secrets.denySources", {
array: {
message: "{policy} {property} must be an array of source names.",
hint: "Use an array such as [\"exec\"] or remove secrets.denySources."
},
entry: {
message: "{policy} {property}[{index}] must be a non-empty source name.",
hint: "Use non-empty source names such as env, file, exec, or openclaw."
}
});
}
return collectPolicyShapeFindings(findings());
}
function authProfileAllowModesShapeFindings(policy, policyPath, policyDocName) {
const finding = createOrderedPolicyShape(policy, {
policyPath,
policyDocName
}).list("auth.profiles.allowModes", {
allowed: SUPPORTED_AUTH_PROFILE_MODES,
normalize: "lower",
array: {
message: "{policy} {property} must be an array of auth modes.",
hint: "Use supported auth modes: {allowed}."
},
entry: {
message: "{policy} {property}[{index}] must be a supported auth mode.",
hint: "Use supported auth modes: {allowed}."
}
});
return finding === void 0 ? [] : [finding];
}
//#endregion
//#region extensions/policy/src/doctor/data-auth-findings.ts
function secretAuthProvenanceFindings(policy, policyPath, policyDocName, evidence) {
const secretShapeFindings = secretPolicyShapeFindings(policy, policyPath, policyDocName);
const authShapeFindings = authProfileAllowModesShapeFindings(policy, policyPath, policyDocName);
return [...secretShapeFindings.length > 0 ? secretShapeFindings : [...secretManagedProviderFindings(policy, policyDocName, evidence), ...secretDeniedSourceFindings(policy, policyDocName, evidence)], ...authShapeFindings.length > 0 ? authShapeFindings : [...authProfileMetadataFindings(policy, policyDocName, evidence), ...authProfileModeFindings(policy, policyDocName, evidence)]];
}
function dataHandlingFindings(policy, policyPath, policyDocName, evidence) {
const shapeFindings = dataHandlingPolicyShapeFindings(policy, policyPath, policyDocName);
if (shapeFindings.length > 0) return shapeFindings;
const findings = [];
findings.push(...dataHandlingFindingsForRule(policy, policyDocName, "dataHandling", evidence, () => true));
for (const target of agentScopedPolicyTargets(policy)) {
if (!policyHasRules(target.overlay, "dataHandling")) continue;
findings.push(...dataHandlingFindingsForRule(target.overlay, policyDocName, `scopes/${ocPathSegment(target.scopeName)}/dataHandling`, evidence, (entry) => entry.kind !== "memorySessionTranscriptIndexing" || scopedAgentEvidenceMatches(entry, target.agentId, evidence.dataHandling ?? [], entry.id === "agents-defaults-memory-session-transcripts")));
}
return findings;
}
function dataHandlingFindingsForRule(policy, policyDocName, requirementBase, evidence, evidenceFilter) {
const dataHandling = isRecord(policy) ? policy.dataHandling : void 0;
if (!isRecord(dataHandling)) return [];
const rules = [
{
path: ["telemetry", "denyContentCapture"],
kind: "telemetryContentCapture",
violates: (entry) => entry.value === true,
checkId: CHECK_IDS.policyDataHandlingTelemetryContentCapture,
message: () => "Telemetry content capture is enabled.",
fixHint: "Disable diagnostics.otel.captureContent or update policy after review."
},
{
path: ["retention", "requireSessionMaintenance"],
kind: "sessionRetentionMode",
violates: (entry) => entry.value !== "enforce",
checkId: CHECK_IDS.policyDataHandlingSessionRetentionNotEnforced,
message: (entry) => `Session retention maintenance mode is '${entry.value ?? "unknown"}'.`,
fixHint: "Set session.maintenance.mode to enforce or update policy after review."
},
{
path: ["memory", "denySessionTranscriptIndexing"],
kind: "memorySessionTranscriptIndexing",
violates: (entry) => entry.value === true,
checkId: CHECK_IDS.policyDataHandlingSessionTranscriptMemory,
message: (entry) => `${dataHandlingLabel(entry)} enables session transcript memory indexing.`,
fixHint: "Disable session transcript memory indexing for the matching config surface or update policy after review."
}
];
return policyEvidenceRuleFindings((evidence.dataHandling ?? []).filter(evidenceFilter), rules.filter((rule) => readBooleanPath(dataHandling, rule.path) === true), policyDocName, requirementBase);
}
function secretManagedProviderFindings(policy, policyDocName, evidence) {
if (readBooleanPath(policy, ["secrets", "requireManagedProviders"]) !== true) return [];
const secrets = evidence.secrets ?? [];
const providerKeys = new Set(secrets.filter((secret) => secret.kind === "provider" && secret.providerSource !== void 0).map((secret) => `${secret.providerSource}:${secret.id}`));
return secrets.filter((secret) => secret.kind === "input" && secret.provenance === "secretRef" && (secret.refProvider === void 0 || secret.refSource === void 0 || !providerKeys.has(`${secret.refSource}:${secret.refProvider}`))).map((secret) => {
return policyEvidenceFinding(secret, {
checkId: CHECK_IDS.policySecretsUnmanagedProvider,
message: `SecretRef uses unmanaged provider '${secret.refProvider ?? "default"}'.`,
requirement: `oc://${policyDocName}/secrets/requireManagedProviders`,
fixHint: "Declare the referenced provider under secrets.providers or update policy after review."
});
});
}
function secretDeniedSourceFindings(policy, policyDocName, evidence) {
const deniedSources = new Set(readStringList(policy, ["secrets", "denySources"]));
if (deniedSources.size === 0) return [];
return (evidence.secrets ?? []).filter((secret) => {
const source = secret.kind === "provider" ? secret.providerSource : secret.refSource;
return source !== void 0 && deniedSources.has(source);
}).map((secret) => {
const source = secret.kind === "provider" ? secret.providerSource : secret.refSource;
return policyEvidenceFinding(secret, {
checkId: CHECK_IDS.policySecretsDeniedProviderSource,
message: `Secret ${secret.kind} '${secret.id}' uses denied source '${source}'.`,
requirement: `oc://${policyDocName}/secrets/denySources`,
fixHint: "Move this secret to an approved source or update policy after review."
});
});
}
function authProfileMetadataFindings(policy, policyDocName, evidence) {
const requiredMetadata = requiredAuthProfileMetadata(policy);
if (requiredMetadata.size === 0) return [];
return (evidence.authProfiles ?? []).flatMap((profile) => {
const missing = [...requiredMetadata].filter((metadata) => !authProfileHasMetadata(profile, metadata));
if (missing.length === 0) return [];
return [policyEvidenceFinding(profile, {
checkId: CHECK_IDS.policyAuthProfileInvalidMetadata,
message: `Auth profile '${profile.id}' is missing required metadata: ${missing.join(", ")}.`,
requirement: `oc://${policyDocName}/auth/profiles/requireMetadata`,
fixHint: "Set auth.profiles.<id>.provider and a supported auth profile mode."
})];
});
}
function authProfileModeFindings(policy, policyDocName, evidence) {
const allowedModes = new Set(readStringList(policy, [
"auth",
"profiles",
"allowModes"
]));
if (allowedModes.size === 0) return [];
return (evidence.authProfiles ?? []).filter((profile) => profile.mode !== void 0 && !allowedModes.has(profile.mode)).map((profile) => {
return policyEvidenceFinding(profile, {
checkId: CHECK_IDS.policyAuthProfileUnapprovedMode,
message: `Auth profile '${profile.id}' uses mode '${profile.mode}' outside the policy allowlist.`,
requirement: `oc://${policyDocName}/auth/profiles/allowModes`,
fixHint: "Change the auth profile mode or update policy after review."
});
});
}
//#endregion
//#region extensions/policy/src/doctor/exec-approval-findings.ts
function execApprovalsFindings(policy, policyPath, policyDocName, evidence, file, displayName) {
if (!isRecord(policy)) return [];
const findings = [];
const entries = evidence.execApprovals ?? [];
const defaults = entries.find((entry) => entry.kind === "defaults");
const defaultSecurity = defaults?.security ?? "full";
if (isRecord(policy.execApprovals)) {
const shapeFinding = execApprovalsPolicyShapeFinding(policy.execApprovals, {
policyDocName,
policyPath
});
if (shapeFinding !== void 0) return [shapeFinding];
const fileFindings = execApprovalsFileFindings(policy.execApprovals, {
policyDocName,
file,
displayName,
requirementBase: "execApprovals"
});
findings.push(...fileFindings);
if (fileFindings.length > 0) return findings;
findings.push(...execApprovalsRuleFindings(policy.execApprovals, {
entries,
defaultSecurity,
defaults,
displayName,
fileDisplayName: file?.displayName,
policyDocName,
requirementBase: "execApprovals"
}));
}
if (!hasValidScopedPolicy(policy, policyPath, policyDocName)) return findings;
const scopedFileFindingScopes = /* @__PURE__ */ new Set();
for (const target of agentScopedPolicyTargets(policy)) {
if (!isRecord(target.overlay.execApprovals)) continue;
const requirementBase = `scopes/${ocPathSegment(target.scopeName)}/execApprovals`;
const fileFindings = execApprovalsFileFindings(target.overlay.execApprovals, {
policyDocName,
file,
displayName,
requirementBase
});
if (fileFindings.length > 0) {
if (!scopedFileFindingScopes.has(target.scopeName)) {
findings.push(...fileFindings);
scopedFileFindingScopes.add(target.scopeName);
}
continue;
}
findings.push(...execApprovalsRuleFindings(target.overlay.execApprovals, {
entries,
defaultSecurity,
defaults,
displayName,
fileDisplayName: file?.displayName,
policyDocName,
requirementBase,
targetAgentId: target.agentId
}));
}
return findings;
}
function execApprovalsFileFindings(execApprovalsPolicy, params) {
const requireFile = readBooleanPath(execApprovalsPolicy, ["requireFile"]) === true;
const needsArtifactEvidence = requireFile || execApprovalsPolicyNeedsArtifactEvidence(execApprovalsPolicy);
if (needsArtifactEvidence && params.file === null) return [{
checkId: CHECK_IDS.policyExecApprovalsMissing,
severity: "error",
message: `${EXEC_APPROVALS_POLICY_DOCUMENT_NAME} evidence is required by policy but was not found.`,
source: "policy",
path: params.displayName,
target: EXEC_APPROVALS_POLICY_URI,
requirement: `oc://${params.policyDocName}/${requireFile ? `${params.requirementBase}/requireFile` : params.requirementBase}`,
fixHint: "Restore the approved exec approvals artifact or update policy after review."
}];
if (params.file === null || params.file === void 0) return [];
const parsed = parseExecApprovalsFile(params.file.raw);
if (parsed.ok || !needsArtifactEvidence) return [];
return [{
checkId: CHECK_IDS.policyExecApprovalsInvalid,
severity: "error",
message: `${params.file.displayName} could not be parsed: ${parsed.message}`,
source: "policy",
path: params.file.displayName,
target: `oc://${params.file.ocDocName}`,
requirement: `oc://${params.policyDocName}/${params.requirementBase}`,
fixHint: `Fix ${EXEC_APPROVALS_POLICY_DOCUMENT_NAME} so it is valid JSON.`
}];
}
function execApprovalsPolicyNeedsArtifactEvidence(execApprovalsPolicy) {
return isRecord(execApprovalsPolicy.defaults) || isRecord(execApprovalsPolicy.agents);
}
function execApprovalsRuleFindings(execApprovalsPolicy, params) {
const findings = [];
const allowedDefaults = new Set(readStringList(execApprovalsPolicy, ["defaults", "allowSecurity"]));
if (params.targetAgentId === void 0 && allowedDefaults.size > 0 && !allowedDefaults.has(params.defaultSecurity.toLowerCase())) findings.push(execApprovalFinding(params.defaults, {
checkId: CHECK_IDS.policyExecApprovalsDefaultSecurityUnapproved,
message: `exec approvals defaults use unapproved security mode '${params.defaultSecurity}'.`,
requirement: `oc://${params.policyDocName}/${params.requirementBase}/defaults/allowSecurity`,
fixHint: "Set defaults.security to an approved mode or update policy after review."
}));
const allowedAgents = new Set(readStringList(execApprovalsPolicy, ["agents", "allowSecurity"]));
if (allowedAgents.size > 0) {
const agentEntries = execApprovalAgentEntries(params.entries, params.defaults, "security", params.targetAgentId);
for (const entry of agentEntries) {
const security = entry.security ?? params.defaultSecurity;
if (allowedAgents.has(security.toLowerCase())) continue;
findings.push(execApprovalFinding(entry, {
checkId: CHECK_IDS.policyExecApprovalsAgentSecurityUnapproved,
message: `exec approvals agent '${entry.agentId ?? params.targetAgentId ?? "inherited defaults"}' uses unapproved security mode '${security}'.`,
requirement: `oc://${params.policyDocName}/${params.requirementBase}/agents/allowSecurity`,
fixHint: "Set the agent approval security mode to an approved value or update policy after review."
}));
}
}
if (readBooleanPath(execApprovalsPolicy, ["agents", "allowAutoAllowSkills"]) === false) {
const autoAllowEntries = execApprovalAgentEntries(params.entries, params.defaults, "autoAllowSkills", params.targetAgentId);
for (const entry of autoAllowEntries) {
if (entry.autoAllowSkills !== true) continue;
findings.push(execApprovalFinding(entry, {
checkId: CHECK_IDS.policyExecApprovalsAutoAllowSkillsEnabled,
message: `exec approvals agent '${entry.agentId ?? params.targetAgentId ?? "inherited defaults"}' enables autoAllowSkills outside policy.`,
requirement: `oc://${params.policyDocName}/${params.requirementBase}/agents/allowAutoAllowSkills`,
fixHint: "Set autoAllowSkills to false or update policy after reviewing implicit skill CLI trust."
}));
}
}
const expected = readExecApprovalAllowlistRequirements(execApprovalsPolicy, [
"agents",
"allowlist",
"expected"
]);
if (expected !== void 0) {
const expectedSet = new Set(expected.map((entry) => entry.key));
const actual = /* @__PURE__ */ new Map();
for (const entry of execApprovalAllowlistEntries(params.entries, params.targetAgentId)) {
if (entry.pattern === void 0) continue;
const key = execApprovalAllowlistRequirementKey(entry.pattern, entry.argPattern);
if (!actual.has(key)) actual.set(key, entry);
}
for (const entry of expected.toSorted((a, b) => a.key.localeCompare(b.key))) if (!actual.has(entry.key)) {
const requirement = `oc://${params.policyDocName}/${params.requirementBase}/agents/allowlist/expected`;
const target = execApprovalAllowlistMissingTarget(params.targetAgentId);
findings.push({
checkId: CHECK_IDS.policyExecApprovalsAllowlistMissing,
severity: "error",
message: `exec approvals allowlist is missing expected pattern '${formatExecApprovalAllowlistEntry(entry)}'.`,
source: "policy",
path: params.fileDisplayName ?? params.displayName,
target,
requirement,
fixHint: "Add the expected approval pattern or update policy after review."
});
}
for (const key of [...actual.keys()].toSorted()) {
if (expectedSet.has(key)) continue;
const entry = actual.get(key);
findings.push(execApprovalFinding(entry, {
checkId: CHECK_IDS.policyExecApprovalsAllowlistUnexpected,
message: `exec approvals allowlist has unexpected pattern '${formatExecApprovalAllowlistEntry(entry)}'.`,
requirement: `oc://${params.policyDocName}/${params.requirementBase}/agents/allowlist/expected`,
fixHint: "Remove the unexpected approval pattern or update policy after review."
}));
}
}
return findings;
}
function execApprovalAllowlistEntries(entries, agentId) {
return entries.filter((entry) => entry.kind === "allowlist" && (agentId === void 0 || entry.agentId !== void 0 && (normalizeAgentId(entry.agentId) === normalizeAgentId(agentId) || entry.agentId === "*")));
}
function execApprovalFinding(entry, params) {
return policyEvidenceFinding({ source: entry?.source ?? "oc://exec-approvals.json" }, params, { path: EXEC_APPROVALS_POLICY_DOCUMENT_NAME });
}
//#endregion
//#region extensions/policy/src/doctor/ingress-findings.ts
function ingressFindings(policy, policyPath, policyDocName, evidence) {
if (!isRecord(policy)) return [];
const findings = [];
const ingressPolicy = policy.ingress;
if (ingressPolicyShapeFinding(ingressPolicy, {
policyDocName,
policyPath
}) === void 0 && isRecord(ingressPolicy)) findings.push(...ingressFindingsForRule(ingressPolicy, policyDocName, "ingress", evidence, () => true));
if (hasValidScopedPolicy(policy, policyPath, policyDocName)) for (const target of channelScopedPolicyTargets(policy)) {
if (!isRecord(target.overlay.ingress)) continue;
findings.push(...ingressFindingsForRule(target.overlay.ingress, policyDocName, `scopes/${ocPathSegment(target.scopeName)}/ingress`, evidence, (entry) => scopedIngressChannelMatches(entry, target.channelId)));
}
return findings;
}
function ingressFindingsForRule(ingressPolicy, policyDocName, requirementBase, evidence, evidenceFilter) {
const requiredDmScope = readPolicyPathString(ingressPolicy, ["session", "requireDmScope"]);
const allowedDmPolicies = new Set(readStringList(ingressPolicy, ["channels", "allowDmPolicies"]));
const entries = (evidence.ingress ?? []).filter(evidenceFilter);
const groupPolicies = entries.filter((entry) => entry.kind === "channelGroupPolicy");
return policyEvidenceRuleFindings(entries, [
{
kind: "sessionDmScope",
enabled: requiredDmScope !== void 0,
violates: (entry) => entry.value !== requiredDmScope,
checkId: CHECK_IDS.policyIngressDmScopeUnapproved,
message: (entry) => `session.dmScope '${entry.value ?? ""}' does not match policy.`,
path: ["session", "requireDmScope"],
fixHint: "Set session.dmScope to the required isolation scope or update policy after review."
},
{
kind: "channelDmPolicy",
enabled: allowedDmPolicies.size > 0,
violates: (entry) => typeof entry.value === "string" && !allowedDmPolicies.has(entry.value.toLowerCase()),
checkId: CHECK_IDS.policyIngressDmPolicyUnapproved,
message: (entry) => `${ingressLabel(entry)} uses unapproved DM policy '${entry.value ?? ""}'.`,
path: ["channels", "allowDmPolicies"],
fixHint: "Set the channel DM policy to an allowed value or update policy after review."
},
{
kind: "channelGroupPolicy",
enabled: readBooleanPath(ingressPolicy, ["channels", "denyOpenGroups"]) === true,
violates: (entry) => entry.value !== "allowlist" && entry.value !== "disabled",
checkId: CHECK_IDS.policyIngressOpenGroupsDenied,
message: (entry) => `${ingressLabel(entry)} allows open group ingress.`,
path: ["channels", "denyOpenGroups"],
fixHint: "Set groupPolicy to allowlist or disabled, or update policy after review."
},
{
kind: "channelRequireMention",
enabled: readBooleanPath(ingressPolicy, ["channels", "requireMentionInGroups"]) === true,
violates: (entry) => !isGroupIngressDisabled(entry, groupPolicies) && entry.value !== true,
checkId: CHECK_IDS.policyIngressGroupMentionRequired,
message: (entry) => `${ingressLabel(entry)} does not require group mentions.`,
path: ["channels", "requireMentionInGroups"],
fixHint: "Set requireMention=true for the channel/group entry or update policy after review."
}
].filter((rule) => rule.enabled), policyDocName, requirementBase);
}
function isGroupIngressDisabled(entry, groupPolicies) {
const entryParent = ocPathParent(entry.source);
const channelDefaultsParent = "oc://openclaw.config/channels/defaults";
return groupPolicies.filter((candidate) => {
const candidateParent = ocPathParent(candidate.source);
return candidate.channel === entry.channel && (candidate.accountId ?? "") === (entry.accountId ?? "") && (candidateParent === channelDefaultsParent || entryParent === candidateParent || entryParent.startsWith(`${candidateParent}/`));
}).toSorted((left, right) => ocPathParent(right.source).length - ocPathParent(left.source).length)[0]?.value === "disabled";
}
function ocPathParent(source) {
return source.slice(0, Math.max(0, source.lastIndexOf("/")));
}
function scopedIngressChannelMatches(entry, policyChannelId) {
return normalizeLowercaseStringOrEmpty(entry.channel ?? "") === policyChannelId;
}
function ingressLabel(entry) {
const account = entry.accountId === void 0 ? "" : ` account '${entry.accountId}'`;
const group = entry.groupId === void 0 ? "" : ` group '${entry.groupId}'`;
return `channel '${entry.channel ?? "unknown"}'${account}${group}`;
}
//#endregion
//#region extensions/policy/src/doctor/routing-shapes.ts
const ROUTING_HINT = "Fix {policy} so routing uses the documented policy syntax.";
function routingPolicyShapeFinding(value, ctx) {
if (value === void 0) return;
const shape = createOrderedPolicyShape(value, {
...ctx,
propertyPrefix: "routing",
targetPrefix: "routing"
});
function* findings() {
yield shape.object("", ROUTING_HINT, true);
yield routingKeys(shape, "", [
"probes",
"requireBindings",
"requireConfiguredChannels"
]);
for (const key of ["requireBindings", "requireConfiguredChannels"]) yield shape.boolean(key, ROUTING_HINT);
const probes = shape.value("probes");
if (probes === void 0) return;
if (!Array.isArray(probes)) {
yield routingFinding(shape, "probes", "must be an array.");
return;
}
const ids = /* @__PURE__ */ new Set();
for (const [index, probe] of probes.entries()) {
const target = `routing/probes/#${index}`;
const entry = createOrderedPolicyShape(probe, {
...ctx,
propertyPrefix: `routing.probes[${index}]`,
targetPrefix: target
});
yield entry.object("", ROUTING_HINT, true);
yield routingKeys(entry, "", [
"expect",
"id",
"route"
]);
yield entry.string("id", ROUTING_HINT, true);
const id = entry.value("id");
if (typeof id === "string") {
if (ids.has(id.trim())) yield policyShapeFinding(ctx.policyPath, `oc://${ctx.policyDocName}/${target}/id`, `${ctx.policyPath} routing check id ${id.trim()} must be unique.`, `Fix ${ctx.policyPath} so routing uses the documented policy syntax.`);
ids.add(id.trim());
}
yield* routeShapeFindings(entry);
yield* expectShapeFindings(entry);
}
}
return firstPolicyShapeFinding(findings());
}
function* routeShapeFindings(shape) {
yield shape.object("route", ROUTING_HINT, true);
yield routingKeys(shape, "route", [
"accountId",
"channel",
"guildId",
"memberRoleIds",
"parentPeer",
"peer",
"teamId"
]);
yield shape.string("route.channel", ROUTING_HINT, true);
for (const key of [
"accountId",
"guildId",
"teamId"
]) yield shape.string(`route.${key}`, ROUTING_HINT);
for (const key of ["peer", "parentPeer"]) {
const path = `route.${key}`;
if (shape.value(path) === void 0) continue;
yield shape.object(path, ROUTING_HINT, true);
yield routingKeys(shape, path, ["id", "kind"]);
const kind = shape.value(`${path}.kind`);
if (typeof kind !== "string" || ![
"channel",
"direct",
"group"
].includes(kind)) yield routingFinding(shape, `${path}.kind`, "must be direct, group, or channel.");
yield shape.string(`${path}.id`, ROUTING_HINT, true);
}
const memberRoleIds = shape.value("route.memberRoleIds");
if (memberRoleIds !== void 0 && (!Array.isArray(memberRoleIds) || memberRoleIds.length === 0 || memberRoleIds.some((entry) => !hasNonEmptyString(entry)) || new Set(memberRoleIds.map((entry) => String(entry).trim())).size !== memberRoleIds.length)) yield routingFinding(shape, "route.memberRoleIds", "must contain unique non-empty strings.");
}
function* expectShapeFindings(shape) {
yield shape.object("expect", ROUTING_HINT, true);
yield routingKeys(shape, "expect", ["agentId", "matchedBy"]);
yield shape.string("expect.agentId", ROUTING_HINT, true);
const matchedBy = shape.value("expect.matchedBy");
if (matchedBy !== void 0 && !validPolicyRoutingMatchKinds(matchedBy)) yield routingFinding(shape, "expect.matchedBy", "must contain unique supported match kinds.");
}
function routingKeys(shape, path, allowed) {
return shape.keys(path, allowed, "", ROUTING_HINT, "{policy} {unsupported} is not supported.");
}
function routingFinding(shape, path, message) {
return shape.finding(path, {
message: "{policy} {property} " + message,
hint: ROUTING_HINT
});
}
//#endregion
//#region extensions/policy/src/doctor/policy-shape.ts
function policyContainerShapeFindings(policy, policyPath, policyDocName) {
if (!isRecord(policy)) return [policyShapeFinding(policyPath, "oc://" + policyDocName, policyPath + " must contain a policy object.", "Fix " + policyPath + " so the top-level policy is an object.")];
const document = policy;
const params = {
policyPath,
policyDocName
};
const shape = createOrderedPolicyShape(document, params);
function* allowDeny(path, valueName) {
yield shape.object(path);
yield shape.keys(path, ["allow", "deny"], "", "Remove {unsupported} or use {property}.allow or {property}.deny.", "{policy} {unsupported} is not supported in policy.");
for (const key of ["allow", "deny"]) yield shape.list(path + "." + key, {
valueName,
entry: {
message: "{policy} {property}[{index}] must be a non-empty string.",
hint: "Fix {policy} so each {property} entry is a {valueName}."
}
});
}
function* findings() {
yield shape.keys("", SUPPORTED_POLICY_SECTIONS, "", "Remove {key} or use a supported policy section.", "{policy} {key} is not a supported policy section.");
yield shape.object("tools");
yield posturePolicyShapeFinding("tools", document.tools, params);
yield shape.object("channels");
yield shape.keys("channels", ["denyRules"], "channel", "Remove {unsupported} or use channels.denyRules.");
yield shape.object("mcp");
yield shape.keys("mcp", ["servers"], "MCP", "Remove {unsupported} or use mcp.servers.");
yield shape.object("dataHandling");
yield* allowDeny("mcp.servers", "MCP server id");
yield shape.object("models");
yield shape.keys("models", ["providers"], "model", "Remove {unsupported} or use models.providers.");
yield* allowDeny("models.providers", "model provider id");
yield shape.object("network");
yield shape.keys("network", ["privateNetwork"], "network", "Remove {unsupported} or use network.privateNetwork.");
yield shape.object("network.privateNetwork");
yield shape.keys("network.privateNetwork", ["allow"], "network", "Remove {unsupported} or use network.privateNetwork.allow.");
yield shape.boolean("network.privateNetwork.allow", "Fix {policy} so {property} is true or false.");
yield shape.object("secrets");
yield shape.keys("secrets", [
"allowInsecureProviders",
"denySources",
"requireManagedProviders"
], "secrets", "Remove {unsupported} or use a supported secrets policy rule.");
yield shape.object("auth");
yield shape.keys("auth", ["profiles"], "auth", "Remove {unsupported} or use auth.profiles.");
yield shape.object("auth.profiles");
yield shape.keys("auth.profiles", ["allowModes", "requireMetadata"], "auth profile", "Remove {unsupported} or use a supported auth profile policy rule.");
yield execApprovalsPolicyShapeFinding(document.execApprovals, params);
yield posturePolicyShapeFinding("sandbox", document.sandbox, params);
yield ingressPolicyShapeFinding(document.ingress, params);
yield posturePolicyShapeFinding("gateway", document.gateway, params);
yield routingPolicyShapeFinding(document.routing, params);
yield posturePolicyShapeFinding("agents", document.agents, params);
yield scopedPolicyShapeFinding(document.scopes, {
...params,
policy: document
});
}
const finding = firstPolicyShapeFinding(findings());
return finding === void 0 ? [] : [finding];
}
//#endregion
//#region extensions/policy/src/doctor/routing-findings.ts
function routingFindings(policy, policyPath, policyDocName, evidence) {
const rules = policyRoutingRules(policy);
if (rules === void 0 || evidence.routing === void 0 || routingPolicyShapeFinding(rules, {
policyPath,
policyDocName
}) !== void 0) return [];
const findings = [];
if (rules.requireBindings === true && evidence.routing.bindings.length === 0) findings.push({
checkId: CHECK_IDS.policyRoutingBindingsRequired,
severity: "error",
message: "Routing policy requires at least one channel route binding, but none are configured.",
source: "policy",
path: policyPath,
target: "oc://openclaw.config/bindings",
requirement: `oc://${policyDocName}/routing/requireBindings`,
fixHint: "Add an intentional route binding or update the policy after review."
});
if (rules.requireConfiguredChannels === true) {
const configured = new Set(evidence.channels.map((channel) => channel.id.toLowerCase()));
for (const binding of evidence.routing.bindings) {
if (configured.has(binding.channel.toLowerCase())) continue;
findings.push({
checkId: CHECK_IDS.policyRoutingBindingChannelUnconfigured,
severity: "error",
message: `Route binding ${binding.index} names unconfigured channel ${binding.channel}.`,
source: "policy",
path: policyPath,
target: `oc://openclaw.config/bindings/#${binding.index}`,
requirement: `oc://${policyDocName}/routing/requireConfiguredChannels`,
fixHint: `Configure channels.${binding.channel}, correct the binding channel, or update the policy after review.`
});
}
}
for (const probe of rules.probes ?? []) {
const result = evidence.routing.probes.find((entry) => entry.id === probe.id);
if (result === void 0) continue;
const resultTarget = `oc://policy/routing/probes/${ocPathSegment(probe.id)}/result`;
const requirement = `oc://${policyDocName}/routing/probes/${ocPathSegment(probe.id)}/expect`;
if (normalizeAgentId(result.agentId) !== normalizeAgentId(probe.expect.agentId)) findings.push({
checkId: CHECK_IDS.policyRoutingAgentMismatch,
severity: "error",
message: `Routing check ${probe.id} resolved to agent ${result.agentId}, not ${probe.expect.agentId}.`,
source: "policy",
path: policyPath,
target: resultTarget,
requirement,
fixHint: "Review the route bindings and expected destination before changing either one."
});
if (probe.expect.matchedBy !== void 0 && !probe.expect.matchedBy.includes(result.matchedBy)) findings.push({
checkId: CHECK_IDS.policyRoutingMatchKindMismatch,
severity: "error",
message: `Routing check ${probe.id} matched by ${result.matchedBy}, which is not an expected match kind.`,
source: "policy",
path: policyPath,
target: resultTarget,
requirement,
fixHint: "Restore the intended binding specificity or update the accepted match kinds after review."
});
}
return findings;
}
//#endregion
//#region extensions/policy/src/doctor/sandbox-findings.ts
function sandboxPostureFindings(policy, policyPath, policyDocName, evidence) {
if (!isRecord(policy)) return [];
const findings = [];
const entries = evidence.sandboxPosture ?? [];
const sandboxPolicy = policy.sandbox;
if (isRecord(sandboxPolicy) && posturePolicyShapeFinding("sandbox", sandboxPolicy, {
policyDocName,
policyPath
}) === void 0) findings.push(...sandboxPostureFindingsForRule(sandboxPolicy, policyDocName, "sandbox", entries));
if (!hasValidScopedPolicy(policy, policyPath, policyDocName)) return findings;
for (const target of agentScopedPolicyTargets(policy)) {
const scopedSandboxPolicy = target.overlay.sandbox;
if (!isRecord(scopedSandboxPolicy)) continue;
findings.push(...sandboxPostureFindingsForRule(scopedSandboxPolicy, policyDocName, `scopes/${ocPathSegment(target.scopeName)}/sandbox`, entries.filter((entry) => scopedSandboxAgentMatches(entry, target.agentId, entries))));
}
return findings;
}
function sandboxPostureFindingsForRule(sandboxPolicy, policyDocName, requirementBase, entries) {
const findings = [{
kind: "mode",
key: "requireMode",
checkId: CHECK_IDS.policySandboxModeUnapproved,
fixHint: "Set agents.defaults.sandbox.mode or agents.entries.<id>.sandbox.mode to an approved value."
}, {
kind: "backend",
key: "allowBackends",
checkId: CHECK_IDS.policySandboxBackendUnapproved,
fixHint: "Use an approved sandbox backend or update policy after review."
}].flatMap((rule) => {
const allowed = new Set(readStringList(sandboxPolicy, [rule.key]));
if (allowed.size === 0) return [];
return entries.filter((entry) => entry.kind === rule.kind).filter((entry) => typeof entry.value === "string" && !allowed.has(entry.value.toLowerCase())).map((entry) => policyEvidenceFinding(entry, {
checkId: rule.checkId,
message: `${sandboxPostureLabel(entry)} uses unapproved sandbox ${rule.kind} '${entry.value ?? ""}'.`,
requirement: `oc://${policyDocName}/${requirementBase}/${rule.key}`,
fixHint: rule.fixHint
}));
});
const enabledRules = SANDBOX_CONTAINER_POLICY_RULES.filter((rule) => readBooleanPath(sandboxPolicy, ["containers", rule.key]) === true);
findings.push(...entries.filter((entry) => entry.kind === "backend").filter((entry) => typeof entry.value === "string" && !isObservableContainerSandboxBackend(entry.value)).flatMap((entry) => enabledRules.map((rule) => policyEvidenceFinding(entry, {
checkId: CHECK_IDS.policySandboxContainerPostureUnobservable,
message: `${sandboxPostureLabel(entry)} uses sandbox backend '${entry.value ?? ""}', which cannot observe ${rule.label}.`,
requirement: `oc://${policyDocName}/${requirementBase}/containers/${rule.key}`,
fixHint: "Use an observable container backend for this sandbox or remove the container posture rule."
}))));
const rules = [
{
path: ["containers", "denyHostNetwork"],
kind: "containerNetwork",
violates: (entry) => typeof entry.value === "string" && entry.value.toLowerCase() === "host",
checkId: CHECK_IDS.policySandboxContainerHostNetworkDenied,
message: (entry) => `${sandboxPostureLabel(entry)} uses host container network mode.`,
fixHint: "Change the container network mode or update policy after review."
},
{
path: ["containers", "denyContainerNamespaceJoin"],
kind: "containerNetwork",
violates: (entry) => typeof entry.value === "string" && entry.value.toLowerCase().startsWith("container:"),
checkId: CHECK_IDS.policySandboxContainerNamespaceJoinDenied,
message: (entry) => `${sandboxPostureLabel(entry)} joins another container network namespace '${entry.value ?? ""}'.`,
fixHint: "Change the container network mode or update policy after review."
},
{
path: ["containers", "requireReadOnlyMounts"],
kind: "containerMount",
violates: (entry) => entry.bindMode !== "ro",
checkId: CHECK_IDS.policySandboxContainerMountModeRequired,
message: (entry) => `${sandboxPostureLabel(entry)} has container mount '${entry.bind ?? ""}' with mode '${entry.bindMode ?? "unknown"}'.`,
fixHint: "Set the mount mode to read-only or update policy after review."
},
{
path: ["containers", "denyContainerRuntimeSocketMounts"],
kind: "containerMount",
violates: (entry) => bindHostLooksLikeContainerRuntimeSocket(entry.bindHost),
checkId: CHECK_IDS.policySandboxContainerRuntimeSocketMount,
message: (entry) => `${sandboxPostureLabel(entry)} binds host container runtime socket '${entry.bindHost ?? ""}'.`,
fixHint: "Remove the container runtime socket bind or update policy after review."
},
{
path: ["containers", "denyUnconfinedProfiles"],
kind: "containerSecurityProfile",
violates: (entry) => typeof entry.value === "string" && entry.value.toLowerCase() === "unconfined",
checkId: CHECK_IDS.policySandboxContainerUnconfinedProfile,
message: (entry) => `${sandboxPostureLabel(entry)} sets container ${entry.profile ?? "security"} profile to unconfined.`,
fixHint: "Remove the unconfined container profile or update policy after review."
},
{
path: ["browser", "requireCdpSourceRange"],
kind: "browserCdpSourceRange",
violates: (entry) => entry.value === void 0,
checkId: CHECK_IDS.policySandboxBrowserCdpSourceRangeMissing,
message: (entry) => `${sandboxPostureLabel(entry)} enables sandbox browser without cdpSourceRange.`,
fixHint: "Set agents.*.sandbox.browser.cdpSourceRange or update policy after review."
}
];
findings.push(...policyEvidenceRuleFindings(entries, rules.filter((rule) => readBooleanPath(sandboxPolicy, rule.path) === true), policyDocName, requirementBase));
return findings;
}
function scopedSandboxAgentMatches(entry, policyAgentId, entries) {
if (scopedAgentIdMatches(entry.agentId, policyAgentId)) return true;
return entry.scope === "defaults" && !scopedSandboxDefaultDisabledForAgent(entry, policyAgentId, entries) && !entries.some((candidate) => candidate.scope === "agent" && sandboxPostureEntriesDescribeSameField(candidate, entry) && scopedAgentIdMatches(candidate.agentId, policyAgentId));
}
function scopedSandboxDefaultDisabledForAgent(entry, policyAgentId, entries) {
if (sandboxEntryRequiresContainerBackend(entry)) {
const backend = entries.find((candidate) => candidate.scope === "agent" && candidate.kind === "backend" && scopedAgentIdMatches(candidate.agentId, policyAgentId));
if (typeof backend?.value === "string" && !isObservableContainerSandboxBackend(backend.value)) return true;
}
if (sandboxEntryRequiresBrowser(entry)) {
if (entries.find((candidate) => candidate.scope === "agent" && candidate.kind === "browserCdpSourceRange" && scopedAgentIdMatches(candidate.agentId, policyAgentId))?.value === false) return true;
}
return false;
}
function sandboxEntryRequiresContainerBackend(entry) {
return entry.kind === "containerNetwork" && entry.networkSurface === "docker" || entry.kind === "containerSecurityProfile" || entry.kind === "containerMount" && entry.bindSurface === "docker";
}
function sandboxEntryRequiresBrowser(entry) {
return entry.kind === "browserCdpSourceRange" || entry.kind === "containerNetwork" && entry.networkSurface === "browser" || entry.kind === "containerMount" && entry.bindSurface === "browser";
}
function sandboxPostureEntriesDescribeSameField(candidate, baseline) {
return candidate.kind === baseline.kind && candidate.bindSurface === baseline.bindSurface && candidate.networkSurface === baseline.networkSurface && candidate.profile === baseline.profile;
}
function isObservableContainerSandboxBackend(value) {
return value.toLowerCase() === "docker" || value.toLowerCase() === "podman";
}
function sandboxPostureLabel(entry) {
return entry.agentId === void 0 ? "default sandbox config" : `agent '${entry.agentId}'`;
}
const CONTAINER_RUNTIME_SOCKET_BASENAMES = /* @__PURE__ */ new Set([
"containerd.sock",
"docker.sock",
"podman.sock"
]);
function bindHostLooksLikeContainerRuntimeSocket(value) {
if (value === void 0) return false;
const basenameLocal = value.replaceAll("\\", "/").toLowerCase().split("/").at(-1) ?? "";
return CONTAINER_RUNTIME_SOCKET_BASENAMES.has(basenameLocal);
}
//#endregion
//#region extensions/policy/src/doctor/scopes/gateway.ts
function gatewayExposureFindings(policy, policyDocName, evidence) {
const rules = [
{
path: ["exposure", "allowNonLoopbackBind"],
enabled: false,
violates: (entry) => entry.kind === "bind" && entry.nonLoopback === true,
checkId: CHECK_IDS.policyGatewayNonLoopbackBind,
message: (entry) => entry.explicit === false ? "Gateway bind is omitted while the runtime default can permit non-loopback exposure." : `Gateway bind setting '${entry.id}' permits non-loopback exposure.`,
fixHint: "Use gateway.bind=loopback or update policy after review."
},
{
path: ["auth", "requireAuth"],
enabled: true,
violates: (entry) => entry.kind === "auth" && entry.value === "none",
checkId: CHECK_IDS.policyGatewayAuthDisabled,
message: () => "Gateway authentication is disabled.",
fixHint: "Set gateway.auth.mode to token, password, or trusted-proxy."
},
{
path: ["auth", "requireExplicitRateLimit"],
enabled: true,
violates: (entry) => entry.kind === "authRateLimit" && entry.explicit !== true,
checkId: CHECK_IDS.policyGatewayRateLimitMissing,
message: () => "Gateway authentication rate-limit posture is not explicit.",
fixHint: "Configure gateway.auth.rateLimit or update policy after review."
},
{
path: ["controlUi", "allowInsecure"],
enabled: false,
violates: (entry) => entry.kind === "controlUi" && entry.value === true && (entry.id === "gateway-control-ui-insecure-auth" || entry.id === "gateway-control-ui-device-auth-disabled" || entry.id === "gateway-control-ui-host-origin-fallback"),
checkId: CHECK_IDS.policyGatewayControlUiInsecure,
message: (entry) => `Gateway Control UI insecure toggle '${entry.id}' is enabled.`,
fixHint: "Disable the insecure Control UI toggle or update policy after review."
},
{
path: ["exposure", "allowTailscaleFunnel"],
enabled: false,
violates: (entry) => entry.kind === "tailscale" && entry.value === "funnel",
checkId: CHECK_IDS.policyGatewayTailscaleFunnel,
message: () => "Gateway Tailscale Funnel exposure is enabled.",
fixHint: "Use tailscale serve/off or update policy after review."
},
{
path: ["remote", "allow"],
enabled: false,
violates: (entry) => entry.kind === "remote",
checkId: CHECK_IDS.policyGatewayRemoteEnabled,
message: (entry) => `Gateway remote posture '${entry.id}' is enabled.`,
fixHint: "Disable remote gateway mode/config or update policy after review."
}
];
return [
...policyEvidenceRuleFindings(evidence.gatewayExposure ?? [], rules.filter((rule) => readBooleanPath(policy, ["gateway", ...rule.path]) === rule.enabled), policyDocName, "gateway"),
...gatewayHttpEndpointFindings(policy, policyDocName, evidence),
...gatewayHttpUrlFetchFindings(policy, policyDocName, evidence),
...gatewayNodeCommandFindings(policy, policyDocName, evidence)
];
}
function gatewayHttpEndpointFindings(policy, policyDocName, evidence) {
const denied = new Set(readStringList(policy, [
"gateway",
"http",
"denyEndpoints"
]));
if (denied.size === 0) return [];
return (evidence.gatewayExposure ?? []).filter((entry) => entry.kind === "httpEndpoint" && entry.endpoint !== void 0 && denied.has(entry.endpoint.toLowerCase())).map((entry) => {
return policyEvidenceFinding(entry, {
checkId: CHECK_IDS.policyGatewayHttpEndpointEnabled,
message: `Gateway HTTP endpoint '${entry.endpoint ?? entry.id}' is denied by policy.`,
requirement: `oc://${policyDocName}/gateway/http/denyEndpoints`,
fixHint: "Disable the HTTP endpoint or update policy after review."
});
});
}
function gatewayHttpUrlFetchFindings(policy, policyDocName, evidence) {
if (readBooleanPath(policy, [
"gateway",
"http",
"requireUrlAllowlists"
]) !== true) return [];
return (evidence.gatewayExposure ?? []).filter((entry) => entry.kind === "httpUrlFetch" && entry.hasAllowlist !== true).map((entry) => {
return policyEvidenceFinding(entry, {
checkId: CHECK_IDS.policyGatewayHttpUrlFetchUnrestricted,
message: `Gateway HTTP URL-fetch input '${entry.id}' has no URL allowlist.`,
requirement: `oc://${policyDocName}/gateway/http/requireUrlAllowlists`,
fixHint: "Add a urlAllowlist for this URL-fetch input or update policy after review."
});
});
}
function gatewayNodeCommandFindings(policy, policyDocName, evidence) {
if (!hasValidOptionalStringList(policy, [
"gateway",
"nodes",
"denyCommands"
])) return [];
const policyDenied = readStringList(policy, [
"gateway",
"nodes",
"denyCommands"
], { lowercase: false });
if (policyDenied.length === 0) return [];
const configDenied = new Set((evidence.gatewayExposure ?? []).filter((entry) => entry.kind === "nodeDenyCommand" && entry.command !== void 0).map((entry) => entry.command));
return policyDenied.filter((command) => !configDenied.has(command)).map((command) => {
return policyEvidenceFinding({ source: "oc://openclaw.config/gateway/nodes/commands/deny" }, {
checkId: CHECK_IDS.policyGatewayNodeCommandDenied,
message: `Gateway node command '${command}' is denied by policy but not denied by OpenClaw config.`,
requirement: `oc://${policyDocName}/gateway/nodes/denyCommands`,
fixHint: `Add '${command}' to gateway.nodes.commands.deny or update policy after review.`
});
});
}
function hasValidOptionalStringList(policy, path) {
const current = getPolicyPath(policy, path);
return current === void 0 || Array.isArray(current) && current.every((entry) => typeof entry === "string" && entry.trim() !== "");
}
//#endregion
//#region extensions/policy/src/doctor/scopes/model-network.ts
function mcpServerFindings(policy, policyDocName, evidence) {
const denied = new Set(readStringList(policy, [
"mcp",
"servers",
"deny"
], { lowercase: false }));
const allowed = new Set(readStringList(policy, [
"mcp",
"servers",
"allow"
], { lowercase: false }));
return evidence.mcpServers.flatMap((server) => {
const isDenied = denied.has(server.id);
if (!isDenied && (allowed.size === 0 || allowed.has(server.id))) return [];
return [policyEvidenceFinding(server, {
checkId: isDenied ? CHECK_IDS.policyDeniedMcpServer : CHECK_IDS.policyUnapprovedMcpServer,
message: isDenied ? `MCP server '${server.id}' is denied by policy.` : `MCP server '${server.id}' is not in the policy allowlist.`,
requirement: `oc://${policyDocName}/mcp/servers/${isDenied ? "deny" : "allow"}`,
fixHint: isDenied ? "Remove this configured MCP server or update the policy after review." : "Use an approved MCP server or update the policy after review."
})];
});
}
function modelProviderFindings(policy, policyDocName, evidence) {
const denied = new Set(readModelProviderPolicyList(policy, [
"models",
"providers",
"deny"
]));
const allowed = new Set(readModelProviderPolicyList(policy, [
"models",
"providers",
"allow"
]));
return [...evidence.modelProviders, ...evidence.modelRefs].flatMap((entry) => {
const isModelRef = "ref" in entry;
const provider = isModelRef ? entry.provider : entry.id;
const isDenied = denied.has(provider);
if (!isDenied && (allowed.size === 0 || allowed.has(provider))) return [];
const message = isModelRef ? `Model ref '${entry.ref}' uses ${isDenied ? "denied" : "unapproved"} provider '${provider}'.` : `Model provider '${provider}' is ${isDenied ? "denied by policy" : "not in the policy allowlist"}.`;
return [policyEvidenceFinding(entry, {
checkId: isDenied ? CHECK_IDS.policyDeniedModelProvider : CHECK_IDS.policyUnapprovedModelProvider,
message,
requirement: `oc://${policyDocName}/models/providers/${isDenied ? "deny" : "allow"}`,
fixHint: isModelRef ? "Select an approved model provider or update the policy after review." : isDenied ? "Remove this configured provider or update the policy after review." : "Use an approved model provider or update the policy after review."
})];
});
}
function readModelProviderPolicyList(policy, path) {
return readStringList(policy, path).map((provider) => normalizeProviderId(provider));
}
function networkFindings(policy, policyDocName, evidence) {
if (readBooleanPath(policy, [
"network",
"privateNetwork",
"allow"
]) !== false) return [];
return evidence.network.filter((setting) => setting.value).map((setting) => {
return policyEvidenceFinding(setting, {
checkId: CHECK_IDS.policyPrivateNetworkAccess,
message: `Network setting '${setting.id}' allows private-network access.`,
requirement: `oc://${policyDocName}/network/privateNetwork/allow`,
fixHint: "Disable this private-network access setting or update policy after review."
});
});
}
//#endregion
//#region extensions/policy/src/doctor/tool-findings.ts
function toolPostureFindings(policy, policyPath, policyDocName, evidence) {
const findings = [];
const entries = evidence.toolPosture ?? [];
if (isRecord(policy) && isRecord(policy.tools) && posturePolicyShapeFinding("tools", policy.tools, {
policyDocName,
policyPath
}) === void 0) findings.push(...toolPostureFindingsForRule(policy.tools, policyDocName, "tools", entries));
if (!hasValidScopedPolicy(policy, policyPath, policyDocName)) return findings;
for (const target of agentScopedPolicyTargets(policy)) {
if (!isRecord(target.overlay.tools)) continue;
const requirementBase = `scopes/${ocPathSegment(target.scopeName)}/tools`;
findings.push(...toolPostureFindingsForRule(target.overlay.tools, policyDocName, requirementBase, entries.filter((entry) => scopedAgentEvidenceMatches(entry, target.agentId, entries, entry.scope === "global"))));
}
return findings;
}
function toolPostureFindingsForRule(toolsPolicy, policyDocName, requirementBase, entries) {
return [
...toolValuePostureFindings(toolsPolicy, policyDocName, requirementBase, entries),
...toolAlsoAllowExpectedFindings(toolsPolicy, policyDocName, requirementBase, entries),
...toolRequiredDenyFindings(toolsPolicy, policyDocName, requirementBase, entries)
];
}
function toolValuePostureFindings(toolsPolicy, policyDocName, requirementBase, entries) {
return [
{
path: ["profiles", "allow"],
kind: "profile",
checkId: CHECK_IDS.policyToolsProfileUnapproved,
message: (entry) => `${toolPostureLabel(entry)} uses unapproved tool profile '${entry.value ?? ""}'.`,
fixHint: "Use an approved tools.profile value or update policy after review."
},
{
path: ["fs", "requireWorkspaceOnly"],
kind: "fsWorkspaceOnly",
required: true,
checkId: CHECK_IDS.policyToolsFsWorkspaceOnlyRequired,
message: (entry) => `${toolPostureLabel(entry)} does not require workspace-only filesystem tools.`,
fixHint: "Set tools.fs.workspaceOnly=true or update policy after review."
},
...[
[
"allowSecurity",
"execSecurity",
"exec security",
CHECK_IDS.policyToolsExecSecurityUnapproved
],
[
"requireAsk",
"execAsk",
"exec ask",
CHECK_IDS.policyToolsExecAskUnapproved
],
[
"allowHosts",
"execHost",
"exec host",
CHECK_IDS.policyToolsExecHostUnapproved
]
].map(([key, kind, label, checkId]) => ({
path: ["exec", key],
kind,
checkId,
message: (entry) => `${toolPostureLabel(entry)} uses unapproved ${label} '${entry.value ?? ""}'.`,
fixHint: "Adjust the configured tool posture or update policy after review."
})),
{
path: ["elevated", "allow"],
kind: "elevatedEnabled",
required: false,
checkId: CHECK_IDS.policyToolsElevatedEnabled,
message: (entry) => `${toolPostureLabel(entry)} permits elevated tool mode.`,
fixHint: "Set tools.elevated.enabled=false or update policy after review."
}
].flatMap((rule) => {
const allowed = new Set(readStringList(toolsPolicy, rule.path));
if (rule.required === void 0 ? allowed.size === 0 : readBooleanPath(toolsPolicy, rule.path) !== rule.required) return [];
return policyEvidenceRuleFindings(entries, [{
...rule,
violates: (entry) => rule.required === void 0 ? typeof entry.value === "string" && !allowed.has(entry.value.toLowerCase()) : entry.value !== rule.required
}], policyDocName, requirementBase);
});
}
function toolAlsoAllowExpectedFindings(toolsPolicy, policyDocName, requirementBase, entries) {
if ((isRecord(toolsPolicy.alsoAllow) ? toolsPolicy.alsoAllow : {}).expected === void 0) return [];
const expected = new Set(readStringList(toolsPolicy, ["alsoAllow", "expected"]).toSorted());
const findings = [];
for (const entry of entries.filter((candidate) => candidate.kind === "alsoAllow")) {
const actual = new Set(normalizeStringEntriesLower(entry.entries).toSorted());
for (const expectedTool of expected) {
if (actual.has(expectedTool)) continue;
findings.push(policyEvidenceFinding(entry, {
checkId: CHECK_IDS.policyToolsAlsoAllowMissing,
message: `${toolPostureLabel(entry)} is missing expected tools.alsoAllow entry '${expectedTool}'.`,
requirement: `oc://${policyDocName}/${requirementBase}/alsoAllow/expected`,
fixHint: "Add the expected tools.alsoAllow entry or update policy after review."
}));
}
for (const actualTool of actual) {
if (expected.has(actualTool)) continue;
findings.push(policyEvidenceFinding(entry, {
checkId: CHECK_IDS.policyToolsAlsoAllowUnexpected,
message: `${toolPostureLabel(entry)} has unexpected tools.alsoAllow entry '${actualTool}'.`,
requirement: `oc://${policyDocName}/${requirementBase}/alsoAllow/expected`,
fixHint: "Remove the unexpected tools.alsoAllow entry or update policy after review."
}));
}
}
return findings;
}
function toolRequiredDenyFindings(toolsPolicy, policyDocName, requirementBase, entries) {
const required = readStringList(toolsPolicy, ["denyTools"]);
if (required.length === 0) return [];
const requiredTools = uniqueStrings(required.flatMap(expandPolicyToolRequirement));
const findings = [];
for (const entry of entries.filter((candidate) => candidate.kind === "deny")) for (const tool of requiredTools) {
if (toolListCoversTool(entry.entries ?? [], tool)) continue;
findings.push(policyEvidenceFinding(entry, {
checkId: CHECK_IDS.policyToolsRequiredDenyMissing,
message: `${toolPostureLabel(entry)} does not deny required tool '${tool}'.`,
requirement: `oc://${policyDocName}/${requirementBase}/denyTools`,
fixHint: "Add the tool or group to tools.deny/agents.entries.<id>.tools.deny, or update policy after review."
}));
}
return findings;
}
function toolPostureLabel(entry) {
return entry.agentId === void 0 ? "global tools config" : `agent '${entry.agentId}'`;
}
function toolMetadataFinding(tool, policyDocName, checkId, message, fixHint) {
return policyEvidenceFinding(tool, {
checkId,
message,
requirement: `oc://${policyDocName}/tools/requireMetadata`,
fixHint
}, {
path: "AGENTS.md",
line: tool.line
});
}
const TOOL_METADATA_CHECKS = [
{
metadata: "risk",
issue: (tool) => tool.risk === void 0 ? [
CHECK_IDS.policyMissingToolRisk,
`AGENTS.md tool '${tool.id}' has no explicit risk classification.`,
"Declare risk:low, risk:medium, risk:high, risk:critical, or an R0-R5 review alias."
] : void 0
},
{
metadata: "risk",
issue: (tool) => tool.risk !== void 0 && !KNOWN_RISK_LEVELS.some((risk) => risk === tool.risk) ? [
CHECK_IDS.policyUnknownToolRisk,
`AGENTS.md tool '${tool.id}' declares unknown risk '${tool.risk}'.`,
`Use one of: ${KNOWN_RISK_LEVELS.join(", ")}.`
] : void 0
},
{
metadata: "sensitivity",
issue: (tool) => {
if (tool.sensitivity === void 0) return [
CHECK_IDS.policyMissingToolSensitivity,
`AGENTS.md tool '${tool.id}' has no declared artifact sensitivity.`,
`Declare sensitivity as one of: ${KNOWN_SENSITIVITY_LEVELS.join(", ")}.`
];
return KNOWN_SENSITIVITY_LEVELS.some((level) => level === tool.sensitivity) ? void 0 : [
CHECK_IDS.policyUnknownToolSensitivity,
`AGENTS.md tool '${tool.id}' declares unknown sensitivity '${tool.sensitivity}'.`,
`Use one of: ${KNOWN_SENSITIVITY_LEVELS.join(", ")}.`
];
}
},
{
metadata: "owner",
issue: (tool) => tool.owner === void 0 ? [
CHECK_IDS.policyMissingToolOwner,
`AGENTS.md tool '${tool.id}' has no declared owner.`,
"Declare owner:<team-or-person> for this tool."
] : void 0
}
];
function toolMetadataFindings(policyDocName, evidence, required) {
return TOOL_METADATA_CHECKS.filter((check) => required.has(check.metadata)).flatMap((check) => (evidence.tools ?? []).flatMap((tool) => {
const issue = check.issue(tool);
return issue === void 0 ? [] : [toolMetadataFinding(tool, policyDocName, ...issue)];
}));
}
//#endregion
//#region extensions/policy/src/doctor/evaluation.ts
const policyEvaluationCache = /* @__PURE__ */ new WeakMap();
function evaluatePolicy(ctx) {
const cached = policyEvaluationCache.get(ctx);
if (cached !== void 0) return cached;
const next = evaluatePolicyUncached(ctx);
policyEvaluationCache.set(ctx, next);
return next;
}
async function evaluatePolicyUncached(ctx) {
const settings = policySettings(ctx);
const policyPath = policyDisplayName(ctx);
let evidence = collectPolicyEvidence(ctx.cfg, {
includeIngress: false,
includeGatewayExposure: false,
includeAgentWorkspace: false,
includeToolPosture: false,
includeSandboxPosture: false,
includeSecrets: false,
includeAuthProfiles: false,
includeExecApprovals: false
});
const findings = [];
const initialEvaluation = {
policyPath,
evidence,
expectedAttestationHash: settings.expectedAttestationHash,
findings,
attestedFindings: findings
};
if (!policyChecksEnabled(ctx, settings)) return initialEvaluation;
const policyFile = await readPolicyFile(ctx);
if (policyFile === null) {
findings.push({
checkId: CHECK_IDS.policyMissingFile,
severity: "warning",
message: `${policyPath} is missing for the enabled Policy plugin.`,
source: "policy",
path: policyPath,
fixHint: `Restore ${policyPath} or add the policy artifact for this workspace.`
});
return initialEvaluation;
}
const parsedPolicy = parsePolicyFile(policyFile.raw);
if (!parsedPolicy.ok) {
findings.push(policyParseFinding(policyFile.displayName, policyFile.ocDocName, parsedPolicy));
return initialEvaluation;
}
const policy = parsedPolicy.value;
const policyHash = policyDocumentHash(policy);
const expectedHash = settings.expectedHash;
if (typeof expectedHash === "string" && expectedHash.trim() !== "" && policyHash !== expectedHash.trim()) {
findings.push({
checkId: CHECK_IDS.policyHashMismatch,
severity: "error",
message: `${policyFile.displayName} does not match the configured policy hash.`,
source: "policy",
path: policyFile.displayName,
target: `oc://${policyFile.ocDocName}`,
requirement: "oc://openclaw.config/plugins/entries/policy/config/expectedHash",
fixHint: `Restore the approved policy artifact or update plugins.entries.policy.config.expectedHash after review.`
});
return {
...initialEvaluation,
policy: {
value: policy,
hash: policyHash
}
};
}
const metadataRequirementFindings = metadataRequirementShapeFindings(policy, policyFile.displayName, policyFile.ocDocName, "tools.requireMetadata");
const authMetadataRequirementFindings = metadataRequirementShapeFindings(policy, policyFile.displayName, policyFile.ocDocName, "auth.profiles.requireMetadata");
const requiredMetadata = metadataRequirementFindings.length === 0 ? requiredToolMetadata(policy) : /* @__PURE__ */ new Set();
const includeExecApprovals = policyHasRules(policy, "execApprovals");
const routing = isRecord(policy) && isRecord(policy.routing) && routingPolicyShapeFinding(policy.routing, {
policyDocName: policyFile.ocDocName,
policyPath: policyFile.displayName
}) === void 0 ? policyRoutingRules(policy) : void 0;
const execApprovalsFile = includeExecApprovals ? await readExecApprovalsFile() : void 0;
const evidenceOptions = {
includeIngress: policyHasRules(policy, "ingress"),
includeGatewayExposure: policyHasRules(policy, "gateway"),
includeAgentWorkspace: policyHasRules(policy, "agents"),
includeDataHandling: policyHasRules(policy, "dataHandling"),
includeToolPosture: policyHasRules(policy, "tools"),
includeSandboxPosture: policyHasRules(policy, "sandbox"),
includeSecrets: policyHasRules(policy, "secrets"),
includeAuthProfiles: policyHasRules(policy, "auth"),
includeExecApprovals,
execApprovalsRaw: includeExecApprovals ? execApprovalsFile?.raw ?? null : void 0,
routing
};
let unmigratedToolsFinding;
if (requiredMetadata.size > 0) {
const [toolsFile, legacyToolsFile] = await Promise.all([readWorkspaceFile(ctx, "AGENTS.md"), readWorkspaceFile(ctx, "TOOLS.md")]);
if (legacyToolsFile !== null) unmigratedToolsFinding = {
checkId: CHECK_IDS.policyUnmigratedToolsFile,
severity: "error",
message: "TOOLS.md contains unmigrated governed tool declarations; run `openclaw doctor --fix` to migrate them into the AGENTS.md `## Tools` section before policy evaluation can pass.",
source: "policy",
path: "TOOLS.md",
target: "oc://TOOLS.md/tools",
requirement: `oc://${policyFile.ocDocName}/tools/requireMetadata`,
fixHint: "Run `openclaw doctor --fix` to migrate TOOLS.md into the AGENTS.md `## Tools` section."
};
evidence = collectPolicyEvidence(ctx.cfg, {
toolsRaw: toolsFile?.raw ?? "",
...evidenceOptions
});
} else evidence = collectPolicyEvidence(ctx.cfg, evidenceOptions);
const policyFindings = [
...policyContainerShapeFindings(policy, policyFile.displayName, policyFile.ocDocName),
...channelFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence),
...mcpServerFindings(policy, policyFile.ocDocName, evidence),
...modelProviderFindings(policy, policyFile.ocDocName, evidence),
...networkFindings(policy, policyFile.ocDocName, evidence),
...routingFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence),
...ingressFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence),
...gatewayExposureFindings(policy, policyFile.ocDocName, evidence),
...agentWorkspaceFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence),
...toolPostureFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence),
...sandboxPostureFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence),
...dataHandlingFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence),
...secretAuthProvenanceFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence),
...execApprovalsFindings(policy, policyFile.displayName, policyFile.ocDocName, evidence, execApprovalsFile, resolveExecApprovalsDisplayPath()),
...authMetadataRequirementFindings,
...metadataRequirementFindings,
...unmigratedToolsFinding === void 0 ? [] : [unmigratedToolsFinding]
];
policyFindings.push(...toolMetadataFindings(policyFile.ocDocName, evidence, requiredMetadata));
const attestationFindings = policyAttestationFindings(policyFile.displayName, policyHash, evidence, policyFindings, settings);
if (hasPolicyValidationFinding(policyFindings)) findings.push(...policyFindings);
else if (attestationFindings.length > 0) findings.push(...attestationFindings);
else findings.push(...policyFindings);
return {
policyPath,
policy: {
value: policy,
hash: policyHash
},
evidence,
expectedAttestationHash: settings.expectedAttestationHash,
findings,
attestedFindings: policyFindings
};
}
function policyParseFinding(policyPath, policyDocName, parseError) {
return {
checkId: CHECK_IDS.policyInvalidFile,
severity: "error",
message: `${policyPath} could not be parsed: ${parseError.message}`,
source: "policy",
path: policyPath,
target: `oc://${policyDocName}`,
fixHint: `Fix ${policyPath} so policy conformance checks can run.`
};
}
function hasPolicyValidationFinding(findings) {
return findings.some((finding) => finding.checkId === CHECK_IDS.policyInvalidFile || finding.checkId === CHECK_IDS.policyUnmigratedToolsFile);
}
function channelFindings(policy, policyPath, policyDocName, evidence) {
const invalidRules = invalidChannelDenyRuleFindings(policy, policyPath, policyDocName);
if (invalidRules.length > 0) return invalidRules;
const denyRules = readChannelDenyRules(policy, policyDocName);
if (denyRules.length === 0) return [];
return evidence.channels.flatMap((channel) => {
if (channel.enabled === false) return [];
const rule = denyRules.find((candidate) => candidate.when.provider === channel.provider);
if (rule === void 0) return [];
return [policyEvidenceFinding(channel, {
checkId: CHECK_IDS.policyDeniedChannelProvider,
message: `Channel '${channel.id}' uses denied provider '${channel.provider}'.`,
requirement: rule.requirement,
fixHint: rule.reason ?? "Disable this channel, remove it from config, or update the policy deny rule."
})];
});
}
function policyAttestationFindings(policyPath, policyHash, evidence, findings, settings) {
const expected = settings.expectedAttestationHash?.trim();
if (!expected) return [];
const current = createPolicyAttestation({
ok: findings.length === 0,
checkedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
policyPath,
policyHash,
evidence,
findings: findings.map(toAttestedFinding)
});
if (current.attestationHash === expected) return [];
return [{
checkId: CHECK_IDS.policyAttestationMismatch,
severity: "error",
message: "The current policy check no longer matches the accepted policy attestation.",
source: "policy",
path: "policy attestation",
target: "oc://policy/attestation/current",
requirement: "oc://openclaw.config/plugins/entries/policy/config/expectedAttestationHash",
fixHint: `Run policy check, review attestation ${current.attestationHash}, then update plugins.entries.policy.config.expectedAttestationHash and the supervisor/gateway accepted attestation.`
}];
}
function toAttestedFinding(finding) {
return {
checkId: finding.checkId,
severity: finding.severity,
message: finding.message,
...finding.source !== void 0 ? { source: finding.source } : {},
...finding.path !== void 0 ? { path: finding.path } : {},
...finding.line !== void 0 ? { line: finding.line } : {},
...finding.column !== void 0 ? { column: finding.column } : {},
...finding.ocPath !== void 0 ? { ocPath: finding.ocPath } : {},
...finding.target !== void 0 ? { target: finding.target } : {},
...finding.requirement !== void 0 ? { requirement: finding.requirement } : {},
...finding.fixHint !== void 0 ? { fixHint: finding.fixHint } : {}
};
}
//#endregion
export { POLICY_RULE_METADATA as _, scopedPolicyFields as a, policyRuleValueIsValid as c, disableChannels as d, workspaceRepairsEnabled as f, POLICY_FIX_METADATA_BY_CHECK_ID as g, POLICY_CHECK_METADATA as h, normalizePolicySelectorValues as i, createPolicyAttestation as l, getPolicyPath as m, toAttestedFinding as n, scopedPolicyOverlays as o, ocPathSegment as p, policyContainerShapeFindings as r, isPolicyValueAtLeastAsStrict as s, evaluatePolicy as t, channelIdsFromFindings as u, CHECK_IDS as v, POLICY_CHECK_IDS as y };