refactor: dedupe extension lowercase helpers

This commit is contained in:
Peter Steinberger
2026-04-07 14:56:14 +01:00
parent 948d139399
commit 9314bb7180
28 changed files with 72 additions and 48 deletions

View File

@@ -1,6 +1,7 @@
import type { StreamFn } from "@mariozechner/pi-agent-core";
import { streamSimple } from "@mariozechner/pi-ai";
import type { ThinkLevel } from "../../auto-reply/thinking.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
import { streamWithPayloadPatch } from "./stream-payload-utils.js";
function isGemini31Model(modelId: string): boolean {
@@ -9,7 +10,7 @@ function isGemini31Model(modelId: string): boolean {
}
function isGemma4Model(modelId: string): boolean {
return modelId.trim().toLowerCase().startsWith("gemma-4");
return normalizeLowercaseStringOrEmpty(modelId).startsWith("gemma-4");
}
function mapThinkLevelToGoogleThinkingLevel(
@@ -106,9 +107,7 @@ export function sanitizeGoogleThinkingPayload(params: {
}
const mappedLevel =
explicitMappedLevel ??
normalizedThinkingLevel ??
(hadThinkingBudget ? "MINIMAL" : undefined);
explicitMappedLevel ?? normalizedThinkingLevel ?? (hadThinkingBudget ? "MINIMAL" : undefined);
if (mappedLevel) {
thinkingConfigObj.thinkingLevel = mappedLevel;

View File

@@ -77,7 +77,7 @@ function parseExecDirectiveArgs(raw: string): Omit<
if (idx === -1) {
return null;
}
const key = token.slice(0, idx).trim().toLowerCase();
const key = normalizeOptionalLowercaseString(token.slice(0, idx));
const value = token.slice(idx + 1).trim();
if (!key) {
return null;

View File

@@ -10,6 +10,7 @@ import {
isTrustedSafeBinPath,
normalizeTrustedSafeBinDirs,
} from "../../../infra/exec-safe-bin-trust.js";
import { normalizeOptionalLowercaseString } from "../../../shared/string-coerce.js";
import { sanitizeForLog } from "../../../terminal/ansi.js";
import { asObjectRecord } from "./object.js";
@@ -42,7 +43,7 @@ function normalizeConfiguredSafeBins(entries: unknown): string[] {
return Array.from(
new Set(
entries
.map((entry) => (typeof entry === "string" ? entry.trim().toLowerCase() : ""))
.map((entry) => normalizeOptionalLowercaseString(entry) ?? "")
.filter((entry) => entry.length > 0),
),
).toSorted();

View File

@@ -1,9 +1,10 @@
import { vi } from "vitest";
import * as ssrf from "../../../infra/net/ssrf.js";
import { normalizeLowercaseStringOrEmpty } from "../../../shared/string-coerce.js";
export function mockPublicPinnedHostname() {
return vi.spyOn(ssrf, "resolvePinnedHostnameWithPolicy").mockImplementation(async (hostname) => {
const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
const normalized = normalizeLowercaseStringOrEmpty(hostname).replace(/\.$/, "");
const addresses = ["93.184.216.34"];
return {
hostname: normalized,

View File

@@ -20,6 +20,10 @@ import { hasNonEmptyString } from "../infra/outbound/channel-target.js";
import { getActivePluginRegistry } from "../plugins/runtime.js";
import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
import { asNullableRecord } from "../shared/record-coerce.js";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
} from "../shared/string-coerce.js";
import { collectDeepCodeSafetyFindings } from "./audit-deep-code-safety.js";
import { collectDeepProbeFindings } from "./audit-deep-probe-findings.js";
import {
@@ -395,9 +399,7 @@ export function collectGatewayConfigFindings(
? cfg.gateway?.tools?.allow
: [];
const gatewayToolsAllow = new Set(
gatewayToolsAllowRaw
.map((v) => (typeof v === "string" ? v.trim().toLowerCase() : ""))
.filter(Boolean),
gatewayToolsAllowRaw.map((v) => normalizeOptionalLowercaseString(v) ?? "").filter(Boolean),
);
const reenabledOverHttp = DEFAULT_GATEWAY_HTTP_TOOL_DENY.filter((name) =>
gatewayToolsAllow.has(name),
@@ -689,7 +691,7 @@ function isStrictLoopbackTrustedProxyEntry(entry: string): boolean {
return rawIp.trim() === "127.0.0.1" && prefix === 32;
}
if (ipVersion === 6) {
return prefix === 128 && rawIp.trim().toLowerCase() === "::1";
return prefix === 128 && normalizeLowercaseStringOrEmpty(rawIp) === "::1";
}
return false;
}
@@ -959,7 +961,7 @@ export function collectExecRuntimeFindings(cfg: OpenClawConfig): SecurityAuditFi
return Array.from(
new Set(
entries
.map((entry) => (typeof entry === "string" ? entry.trim().toLowerCase() : ""))
.map((entry) => normalizeOptionalLowercaseString(entry) ?? "")
.filter((entry) => entry.length > 0),
),
).toSorted();

View File

@@ -1,9 +1,10 @@
import { vi } from "vitest";
import * as ssrf from "../infra/net/ssrf.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
export function mockPinnedHostnameResolution(addresses: string[] = ["93.184.216.34"]) {
return vi.spyOn(ssrf, "resolvePinnedHostname").mockImplementation(async (hostname) => {
const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
const normalized = normalizeLowercaseStringOrEmpty(hostname).replace(/\.$/, "");
const pinnedAddresses = [...addresses];
return {
hostname: normalized,