refactor: harden plugin install flow and main DM route pinning

This commit is contained in:
Peter Steinberger
2026-03-02 21:22:32 +00:00
parent af637deed1
commit b782ecb7eb
22 changed files with 737 additions and 269 deletions

View File

@@ -7,6 +7,7 @@ import {
resolveDmGroupAccessDecision,
resolveDmGroupAccessWithLists,
resolveEffectiveAllowFromLists,
resolvePinnedMainDmOwnerFromAllowlist,
} from "./dm-policy-shared.js";
describe("security/dm-policy-shared", () => {
@@ -106,6 +107,43 @@ describe("security/dm-policy-shared", () => {
expect(lists.effectiveGroupAllowFrom).toEqual([]);
});
it("infers pinned main DM owner from a single configured allowlist entry", () => {
const pinnedOwner = resolvePinnedMainDmOwnerFromAllowlist({
dmScope: "main",
allowFrom: [" line:user:U123 "],
normalizeEntry: (entry) =>
entry
.trim()
.toLowerCase()
.replace(/^line:(?:user:)?/, ""),
});
expect(pinnedOwner).toBe("u123");
});
it("does not infer pinned owner for wildcard/multi-owner/non-main scope", () => {
expect(
resolvePinnedMainDmOwnerFromAllowlist({
dmScope: "main",
allowFrom: ["*"],
normalizeEntry: (entry) => entry.trim(),
}),
).toBeNull();
expect(
resolvePinnedMainDmOwnerFromAllowlist({
dmScope: "main",
allowFrom: ["u123", "u456"],
normalizeEntry: (entry) => entry.trim(),
}),
).toBeNull();
expect(
resolvePinnedMainDmOwnerFromAllowlist({
dmScope: "per-channel-peer",
allowFrom: ["u123"],
normalizeEntry: (entry) => entry.trim(),
}),
).toBeNull();
});
it("excludes storeAllowFrom when dmPolicy is allowlist", () => {
const lists = resolveEffectiveAllowFromLists({
allowFrom: ["+1111"],

View File

@@ -4,6 +4,28 @@ import type { ChannelId } from "../channels/plugins/types.js";
import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
import { normalizeStringEntries } from "../shared/string-normalization.js";
export function resolvePinnedMainDmOwnerFromAllowlist(params: {
dmScope?: string | null;
allowFrom?: Array<string | number> | null;
normalizeEntry: (entry: string) => string | undefined;
}): string | null {
if ((params.dmScope ?? "main") !== "main") {
return null;
}
const rawAllowFrom = Array.isArray(params.allowFrom) ? params.allowFrom : [];
if (rawAllowFrom.some((entry) => String(entry).trim() === "*")) {
return null;
}
const normalizedOwners = Array.from(
new Set(
rawAllowFrom
.map((entry) => params.normalizeEntry(String(entry)))
.filter((entry): entry is string => Boolean(entry)),
),
);
return normalizedOwners.length === 1 ? normalizedOwners[0] : null;
}
export function resolveEffectiveAllowFromLists(params: {
allowFrom?: Array<string | number> | null;
groupAllowFrom?: Array<string | number> | null;