mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix: remove stale allowlist matcher cache
This commit is contained in:
@@ -82,6 +82,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Sessions/reset model recompute: clear stale runtime model, context-token, and system-prompt metadata before session resets recompute the replacement session, so resets pick up current defaults and explicit overrides instead of reusing old runtime model state. (#41173) thanks @PonyX-lab.
|
||||
- Browser/Browserbase 429 handling: surface stable no-retry rate-limit guidance without buffering discarded HTTP 429 response bodies from remote browser services. (#40491) thanks @mvanhorn.
|
||||
- Gateway/auth: allow one trusted device-token retry on shared-token mismatch with recovery hints to prevent reconnect churn during token drift. (#42507) Thanks @joshavant.
|
||||
- Channels/allowlists: remove stale matcher caching so same-array allowlist edits and wildcard replacements take effect immediately, with regression coverage for in-place mutation cases.
|
||||
|
||||
## 2026.3.8
|
||||
|
||||
|
||||
85
src/channels/allowlist-match.test.ts
Normal file
85
src/channels/allowlist-match.test.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
resolveAllowlistMatchByCandidates,
|
||||
resolveAllowlistMatchSimple,
|
||||
} from "./allowlist-match.js";
|
||||
|
||||
describe("channels/allowlist-match", () => {
|
||||
it("reflects in-place allowFrom edits even when array length stays the same", () => {
|
||||
const allowFrom = ["alice", "bob"];
|
||||
|
||||
expect(resolveAllowlistMatchSimple({ allowFrom, senderId: "bob" })).toEqual({
|
||||
allowed: true,
|
||||
matchKey: "bob",
|
||||
matchSource: "id",
|
||||
});
|
||||
|
||||
allowFrom[1] = "mallory";
|
||||
|
||||
expect(resolveAllowlistMatchSimple({ allowFrom, senderId: "bob" })).toEqual({
|
||||
allowed: false,
|
||||
});
|
||||
expect(resolveAllowlistMatchSimple({ allowFrom, senderId: "mallory" })).toEqual({
|
||||
allowed: true,
|
||||
matchKey: "mallory",
|
||||
matchSource: "id",
|
||||
});
|
||||
});
|
||||
|
||||
it("drops wildcard access after in-place wildcard replacement", () => {
|
||||
const allowFrom = ["*"];
|
||||
|
||||
expect(resolveAllowlistMatchSimple({ allowFrom, senderId: "eve" })).toEqual({
|
||||
allowed: true,
|
||||
matchKey: "*",
|
||||
matchSource: "wildcard",
|
||||
});
|
||||
|
||||
allowFrom[0] = "alice";
|
||||
|
||||
expect(resolveAllowlistMatchSimple({ allowFrom, senderId: "eve" })).toEqual({
|
||||
allowed: false,
|
||||
});
|
||||
expect(resolveAllowlistMatchSimple({ allowFrom, senderId: "alice" })).toEqual({
|
||||
allowed: true,
|
||||
matchKey: "alice",
|
||||
matchSource: "id",
|
||||
});
|
||||
});
|
||||
|
||||
it("recomputes candidate allowlist sets after in-place replacement", () => {
|
||||
const allowList = ["user:alice", "user:bob"];
|
||||
|
||||
expect(
|
||||
resolveAllowlistMatchByCandidates({
|
||||
allowList,
|
||||
candidates: [{ value: "user:bob", source: "prefixed-user" }],
|
||||
}),
|
||||
).toEqual({
|
||||
allowed: true,
|
||||
matchKey: "user:bob",
|
||||
matchSource: "prefixed-user",
|
||||
});
|
||||
|
||||
allowList[1] = "user:mallory";
|
||||
|
||||
expect(
|
||||
resolveAllowlistMatchByCandidates({
|
||||
allowList,
|
||||
candidates: [{ value: "user:bob", source: "prefixed-user" }],
|
||||
}),
|
||||
).toEqual({
|
||||
allowed: false,
|
||||
});
|
||||
expect(
|
||||
resolveAllowlistMatchByCandidates({
|
||||
allowList,
|
||||
candidates: [{ value: "user:mallory", source: "prefixed-user" }],
|
||||
}),
|
||||
).toEqual({
|
||||
allowed: true,
|
||||
matchKey: "user:mallory",
|
||||
matchSource: "prefixed-user",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -16,17 +16,6 @@ export type AllowlistMatch<TSource extends string = AllowlistMatchSource> = {
|
||||
matchSource?: TSource;
|
||||
};
|
||||
|
||||
type CachedAllowListSet = {
|
||||
size: number;
|
||||
set: Set<string>;
|
||||
};
|
||||
|
||||
const ALLOWLIST_SET_CACHE = new WeakMap<string[], CachedAllowListSet>();
|
||||
const SIMPLE_ALLOWLIST_CACHE = new WeakMap<
|
||||
Array<string | number>,
|
||||
{ normalized: string[]; size: number; wildcard: boolean; set: Set<string> }
|
||||
>();
|
||||
|
||||
export function formatAllowlistMatchMeta(
|
||||
match?: { matchKey?: string; matchSource?: string } | null,
|
||||
): string {
|
||||
@@ -82,13 +71,7 @@ export function resolveAllowlistMatchSimple(params: {
|
||||
}
|
||||
|
||||
function resolveAllowListSet(allowList: string[]): Set<string> {
|
||||
const cached = ALLOWLIST_SET_CACHE.get(allowList);
|
||||
if (cached && cached.size === allowList.length) {
|
||||
return cached.set;
|
||||
}
|
||||
const set = new Set(allowList);
|
||||
ALLOWLIST_SET_CACHE.set(allowList, { size: allowList.length, set });
|
||||
return set;
|
||||
return new Set(allowList);
|
||||
}
|
||||
|
||||
function resolveSimpleAllowFrom(allowFrom: Array<string | number>): {
|
||||
@@ -97,19 +80,12 @@ function resolveSimpleAllowFrom(allowFrom: Array<string | number>): {
|
||||
wildcard: boolean;
|
||||
set: Set<string>;
|
||||
} {
|
||||
const cached = SIMPLE_ALLOWLIST_CACHE.get(allowFrom);
|
||||
if (cached && cached.size === allowFrom.length) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const normalized = allowFrom.map((entry) => String(entry).trim().toLowerCase()).filter(Boolean);
|
||||
const set = new Set(normalized);
|
||||
const built = {
|
||||
return {
|
||||
normalized,
|
||||
size: allowFrom.length,
|
||||
wildcard: set.has("*"),
|
||||
set,
|
||||
};
|
||||
SIMPLE_ALLOWLIST_CACHE.set(allowFrom, built);
|
||||
return built;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user