























1+import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
2+import {
3+applyResolvedAssignments,
4+createResolverContext,
5+resolveSecretRefValues,
6+} from "openclaw/plugin-sdk/secret-ref-runtime";
7+import { describe, expect, it } from "vitest";
8+import { collectRuntimeConfigAssignments, secretTargetRegistryEntries } from "./secret-contract.js";
9+10+async function resolveSmsSecretAssignments(
11+sourceConfig: OpenClawConfig,
12+env: NodeJS.ProcessEnv,
13+): Promise<{
14+config: OpenClawConfig;
15+warnings: ReturnType<typeof createResolverContext>["warnings"];
16+}> {
17+const resolvedConfig: OpenClawConfig = structuredClone(sourceConfig);
18+const context = createResolverContext({ sourceConfig, env });
19+20+collectRuntimeConfigAssignments({
21+config: resolvedConfig,
22+defaults: sourceConfig.secrets?.defaults,
23+ context,
24+});
25+26+const resolved = await resolveSecretRefValues(
27+context.assignments.map((assignment) => assignment.ref),
28+{
29+config: sourceConfig,
30+env: context.env,
31+cache: context.cache,
32+},
33+);
34+applyResolvedAssignments({ assignments: context.assignments, resolved });
35+36+return { config: resolvedConfig, warnings: context.warnings };
37+}
38+39+describe("sms secret contract", () => {
40+it("publishes SMS auth token targets", () => {
41+expect(secretTargetRegistryEntries.map((entry) => entry.id)).toEqual([
42+"channels.sms.accounts.*.authToken",
43+"channels.sms.authToken",
44+]);
45+});
46+47+it("resolves top-level authToken SecretRefs for SMS accounts", async () => {
48+const resolved = await resolveSmsSecretAssignments(
49+{
50+channels: {
51+sms: {
52+enabled: true,
53+accountSid: "AC123",
54+authToken: { source: "env", provider: "default", id: "TWILIO_AUTH_TOKEN" },
55+fromNumber: "+15557654321",
56+},
57+},
58+} as OpenClawConfig,
59+{ TWILIO_AUTH_TOKEN: "resolved-token" },
60+);
61+62+expect(resolved.config.channels?.sms?.authToken).toBe("resolved-token");
63+expect(resolved.warnings).toStrictEqual([]);
64+});
65+66+it("keeps top-level authToken active for an implicit default sender plus named accounts", async () => {
67+const resolved = await resolveSmsSecretAssignments(
68+{
69+channels: {
70+sms: {
71+enabled: true,
72+accountSid: "AC123",
73+authToken: { source: "env", provider: "default", id: "TWILIO_DEFAULT_TOKEN" },
74+fromNumber: "+15557654321",
75+accounts: {
76+support: {
77+enabled: true,
78+accountSid: "AC456",
79+authToken: { source: "env", provider: "default", id: "TWILIO_SUPPORT_TOKEN" },
80+fromNumber: "+15558675309",
81+},
82+},
83+},
84+},
85+} as OpenClawConfig,
86+{
87+TWILIO_DEFAULT_TOKEN: "resolved-default-token",
88+TWILIO_SUPPORT_TOKEN: "resolved-support-token",
89+},
90+);
91+92+expect(resolved.config.channels?.sms?.authToken).toBe("resolved-default-token");
93+expect(resolved.config.channels?.sms?.accounts?.support?.authToken).toBe(
94+"resolved-support-token",
95+);
96+expect(resolved.warnings).toStrictEqual([]);
97+});
98+99+it("keeps top-level authToken active for env-backed default senders plus named accounts", async () => {
100+const resolved = await resolveSmsSecretAssignments(
101+{
102+channels: {
103+sms: {
104+enabled: true,
105+authToken: { source: "env", provider: "default", id: "TWILIO_DEFAULT_TOKEN" },
106+accounts: {
107+support: {
108+enabled: true,
109+accountSid: "AC456",
110+authToken: { source: "env", provider: "default", id: "TWILIO_SUPPORT_TOKEN" },
111+fromNumber: "+15558675309",
112+},
113+},
114+},
115+},
116+} as OpenClawConfig,
117+{
118+TWILIO_ACCOUNT_SID: "AC-env",
119+TWILIO_PHONE_NUMBER: "+15550001111",
120+TWILIO_DEFAULT_TOKEN: "resolved-default-token",
121+TWILIO_SUPPORT_TOKEN: "resolved-support-token",
122+},
123+);
124+125+expect(resolved.config.channels?.sms?.authToken).toBe("resolved-default-token");
126+expect(resolved.config.channels?.sms?.accounts?.support?.authToken).toBe(
127+"resolved-support-token",
128+);
129+expect(resolved.warnings).toStrictEqual([]);
130+});
131+132+it("treats top-level authToken refs as inactive when all enabled accounts override them", async () => {
133+const resolved = await resolveSmsSecretAssignments(
134+{
135+channels: {
136+sms: {
137+authToken: { source: "env", provider: "default", id: "UNUSED_TWILIO_TOKEN" },
138+accounts: {
139+support: {
140+enabled: true,
141+accountSid: "AC456",
142+authToken: { source: "env", provider: "default", id: "TWILIO_SUPPORT_TOKEN" },
143+fromNumber: "+15558675309",
144+},
145+},
146+},
147+},
148+} as OpenClawConfig,
149+{ TWILIO_SUPPORT_TOKEN: "resolved-support-token" },
150+);
151+152+expect(resolved.config.channels?.sms?.authToken).toEqual({
153+source: "env",
154+provider: "default",
155+id: "UNUSED_TWILIO_TOKEN",
156+});
157+expect(resolved.config.channels?.sms?.accounts?.support?.authToken).toBe(
158+"resolved-support-token",
159+);
160+expect(resolved.warnings.map((warning) => warning.path)).toContain("channels.sms.authToken");
161+});
162+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。