mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix: resolve ClickClack token secret refs
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
// ClickClack API module exposes the plugin secret contract.
|
||||
export {
|
||||
channelSecrets,
|
||||
collectRuntimeConfigAssignments,
|
||||
secretTargetRegistryEntries,
|
||||
} from "./src/secret-contract.js";
|
||||
@@ -7,4 +7,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./setup-plugin-api.js",
|
||||
exportName: "clickClackSetupPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./secret-contract-api.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
createComputedAccountStatusAdapter,
|
||||
createDefaultChannelRuntimeState,
|
||||
} from "openclaw/plugin-sdk/status-helpers";
|
||||
import { resolveClickClackAccount } from "./accounts.js";
|
||||
import {
|
||||
CLICKCLACK_CHANNEL_ID,
|
||||
clickClackConfigAdapter,
|
||||
@@ -30,6 +29,7 @@ import {
|
||||
sendClickClackMedia,
|
||||
sendClickClackText,
|
||||
} from "./outbound.js";
|
||||
import { collectRuntimeConfigAssignments, secretTargetRegistryEntries } from "./secret-contract.js";
|
||||
import { clickClackSetupAdapter } from "./setup-core.js";
|
||||
import { clickClackSetupWizard } from "./setup-surface.js";
|
||||
import {
|
||||
@@ -129,6 +129,10 @@ export const clickClackPlugin: ChannelPlugin<ResolvedClickClackAccount> = create
|
||||
config: clickClackConfigAdapter,
|
||||
setup: clickClackSetupAdapter,
|
||||
setupWizard: clickClackSetupWizard,
|
||||
secrets: {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
},
|
||||
messaging: {
|
||||
targetPrefixes: ["clickclack", "cc"],
|
||||
normalizeTarget: normalizeClickClackTarget,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// ClickClack tests cover token secret contract behavior.
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { createResolverContext } from "openclaw/plugin-sdk/secret-ref-runtime";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { collectRuntimeConfigAssignments, secretTargetRegistryEntries } from "./secret-contract.js";
|
||||
|
||||
describe("ClickClack secret contract", () => {
|
||||
it("publishes ClickClack token targets", () => {
|
||||
expect(secretTargetRegistryEntries.map((entry) => entry.id)).toEqual([
|
||||
"channels.clickclack.accounts.*.token",
|
||||
"channels.clickclack.token",
|
||||
]);
|
||||
});
|
||||
|
||||
it("collects an account file SecretRef even when the default uses tokenFile", () => {
|
||||
const sourceConfig = {
|
||||
channels: {
|
||||
clickclack: {
|
||||
enabled: true,
|
||||
baseUrl: "https://clickclack.example",
|
||||
workspace: "default",
|
||||
tokenFile: "/run/secrets/default-clickclack-token",
|
||||
accounts: {
|
||||
work: {
|
||||
token: { source: "file", provider: "vault", id: "/clickclack/work" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
const context = createResolverContext({ sourceConfig, env: {} });
|
||||
|
||||
collectRuntimeConfigAssignments({
|
||||
config: structuredClone(sourceConfig),
|
||||
defaults: undefined,
|
||||
context,
|
||||
});
|
||||
|
||||
expect(context.assignments).toHaveLength(1);
|
||||
expect(context.assignments[0]).toMatchObject({
|
||||
path: "channels.clickclack.accounts.work.token",
|
||||
ref: { source: "file", provider: "vault", id: "/clickclack/work" },
|
||||
});
|
||||
expect(context.warnings).toStrictEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
// ClickClack plugin module implements token secret contract behavior.
|
||||
import {
|
||||
collectConditionalChannelFieldAssignments,
|
||||
createChannelSecretTargetRegistryEntries,
|
||||
getChannelSurface,
|
||||
hasConfiguredSecretInputValue,
|
||||
type ResolverContext,
|
||||
type SecretDefaults,
|
||||
} from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
|
||||
export const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
|
||||
channelKey: "clickclack",
|
||||
account: ["token"],
|
||||
channel: ["token"],
|
||||
});
|
||||
|
||||
export function collectRuntimeConfigAssignments(params: {
|
||||
config: { channels?: Record<string, unknown> };
|
||||
defaults?: SecretDefaults;
|
||||
context: ResolverContext;
|
||||
}): void {
|
||||
const resolved = getChannelSurface(params.config, "clickclack");
|
||||
if (!resolved) {
|
||||
return;
|
||||
}
|
||||
const { channel: clickclack, surface } = resolved;
|
||||
const baseTokenFile = normalizeOptionalString(clickclack.tokenFile) ?? "";
|
||||
const accountTokenFile = (account: Record<string, unknown>) =>
|
||||
normalizeOptionalString(account.tokenFile) ?? "";
|
||||
const hasImplicitDefault =
|
||||
Boolean(normalizeOptionalString(clickclack.baseUrl)) &&
|
||||
Boolean(normalizeOptionalString(clickclack.workspace));
|
||||
|
||||
collectConditionalChannelFieldAssignments({
|
||||
channelKey: "clickclack",
|
||||
field: "token",
|
||||
channel: clickclack,
|
||||
surface,
|
||||
defaults: params.defaults,
|
||||
context: params.context,
|
||||
topLevelActiveWithoutAccounts: baseTokenFile.length === 0,
|
||||
topLevelInheritedAccountActive: ({ account, enabled }) =>
|
||||
(hasImplicitDefault && baseTokenFile.length === 0) ||
|
||||
(enabled &&
|
||||
baseTokenFile.length === 0 &&
|
||||
accountTokenFile(account).length === 0 &&
|
||||
!hasConfiguredSecretInputValue(account.token, params.defaults)),
|
||||
accountActive: ({ account, enabled }) => enabled && accountTokenFile(account).length === 0,
|
||||
topInactiveReason:
|
||||
"no enabled ClickClack account inherits this top-level token (tokenFile is configured).",
|
||||
accountInactiveReason: "ClickClack account is disabled or tokenFile is configured.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
Reference in New Issue
Block a user