mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 04:47:03 -06:00
fix(config): cap missing-provider group-policy warning cache with shared dedupe helper (#108806)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Covers runtime group-policy resolution from config and context.
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
GROUP_POLICY_BLOCKED_LABEL,
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
@@ -63,4 +63,41 @@ describe("warnMissingProviderGroupPolicyFallbackOnce", () => {
|
||||
expect(lines[0]).toContain("channels.runtime-policy-test is missing");
|
||||
expect(lines[0]).toContain("room messages blocked");
|
||||
});
|
||||
|
||||
describe("warning dedupe cache bounds", () => {
|
||||
let warnOnceFn: typeof warnMissingProviderGroupPolicyFallbackOnce;
|
||||
|
||||
// Fresh module instance so the module-level cache starts empty for this block.
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
const mod = await import("./runtime-group-policy.js");
|
||||
warnOnceFn = mod.warnMissingProviderGroupPolicyFallbackOnce;
|
||||
});
|
||||
|
||||
it("refreshes recent keys and re-warns evicted keys once the cap overflows", () => {
|
||||
const lines: string[] = [];
|
||||
const warnForAccount = (accountId: string) =>
|
||||
warnOnceFn({
|
||||
providerMissingFallbackApplied: true,
|
||||
providerKey: "runtime-policy-evict-test",
|
||||
accountId,
|
||||
log: (message) => lines.push(message),
|
||||
});
|
||||
|
||||
for (let i = 0; i < 4096; i++) {
|
||||
warnForAccount(`account-${i}`);
|
||||
}
|
||||
expect(lines).toHaveLength(4096);
|
||||
|
||||
// Recent duplicate stays deduped and refreshes its recency.
|
||||
expect(warnForAccount("account-0")).toBe(false);
|
||||
expect(lines).toHaveLength(4096);
|
||||
|
||||
// Overflow evicts the oldest untouched key (account-1), not the refreshed one.
|
||||
expect(warnForAccount("account-overflow")).toBe(true);
|
||||
expect(warnForAccount("account-0")).toBe(false);
|
||||
expect(warnForAccount("account-1")).toBe(true);
|
||||
expect(lines).toHaveLength(4098);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Resolves runtime group-policy settings for channels and sessions.
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { createDedupeCache } from "../infra/dedupe.js";
|
||||
import type { GroupPolicy } from "./types.base.js";
|
||||
|
||||
type RuntimeGroupPolicyResolution = {
|
||||
@@ -90,7 +91,13 @@ export function resolveAllowlistProviderRuntimeGroupPolicy(
|
||||
});
|
||||
}
|
||||
|
||||
const warnedMissingProviderGroupPolicy = new Set<string>();
|
||||
const MAX_WARNED_MISSING_PROVIDER_GROUP_POLICY_KEYS = 4096;
|
||||
// Warn-once keys accumulate per provider/account for the process lifetime;
|
||||
// bounding them means evicted keys can re-warn instead of growing without limit.
|
||||
const warnedMissingProviderGroupPolicy = createDedupeCache({
|
||||
ttlMs: 0,
|
||||
maxSize: MAX_WARNED_MISSING_PROVIDER_GROUP_POLICY_KEYS,
|
||||
});
|
||||
|
||||
/**
|
||||
* Log the missing-provider fail-closed fallback once per provider/account.
|
||||
@@ -107,10 +114,9 @@ export function warnMissingProviderGroupPolicyFallbackOnce(params: {
|
||||
return false;
|
||||
}
|
||||
const key = `${params.providerKey}:${params.accountId ?? "*"}`;
|
||||
if (warnedMissingProviderGroupPolicy.has(key)) {
|
||||
if (warnedMissingProviderGroupPolicy.check(key)) {
|
||||
return false;
|
||||
}
|
||||
warnedMissingProviderGroupPolicy.add(key);
|
||||
const blockedLabel = normalizeOptionalString(params.blockedLabel) || "group messages";
|
||||
params.log(
|
||||
`${params.providerKey}: channels.${params.providerKey} is missing; defaulting groupPolicy to "allowlist" (${blockedLabel} blocked until explicitly configured).`,
|
||||
|
||||
Reference in New Issue
Block a user