|
11 | 11 | */ |
12 | 12 |
|
13 | 13 | import { createDecipheriv, privateDecrypt, constants } from 'crypto'; |
| 14 | +import { FIELD_KEY_TO_ENV_VAR } from '@kilocode/kiloclaw-secret-catalog'; |
14 | 15 | import type { EncryptedEnvelope, EncryptedChannelTokens } from '../schemas/instance-config'; |
15 | 16 |
|
16 | 17 | export class EncryptionConfigurationError extends Error { |
@@ -145,32 +146,39 @@ export function mergeEnvVarsWithSecrets( |
145 | 146 | return result; |
146 | 147 | } |
147 | 148 |
|
148 | | -/** |
149 | | - * Channel token env var mapping. |
150 | | - * Maps channel config keys to the container env var names expected by start-openclaw.sh. |
151 | | - */ |
152 | | -const CHANNEL_ENV_MAP: Record<keyof EncryptedChannelTokens, string> = { |
153 | | - telegramBotToken: 'TELEGRAM_BOT_TOKEN', |
154 | | - discordBotToken: 'DISCORD_BOT_TOKEN', |
155 | | - slackBotToken: 'SLACK_BOT_TOKEN', |
156 | | - slackAppToken: 'SLACK_APP_TOKEN', |
157 | | -}; |
158 | | - |
159 | 149 | /** |
160 | 150 | * Decrypt encrypted channel tokens and map to container env var names. |
161 | 151 | * |
| 152 | + * Uses FIELD_KEY_TO_ENV_VAR from the secret catalog to map channel config keys |
| 153 | + * to the container env var names expected by start-openclaw.sh. |
| 154 | + * |
162 | 155 | * Example: channels.telegramBotToken -> TELEGRAM_BOT_TOKEN |
| 156 | + * |
| 157 | + * Unknown keys (e.g. stale DO state from a rolled-back schema change) are |
| 158 | + * skipped with a console.warn rather than throwing, so a single unrecognised |
| 159 | + * key does not prevent the machine from starting. |
163 | 160 | */ |
164 | 161 | export function decryptChannelTokens( |
165 | 162 | channels: EncryptedChannelTokens, |
166 | 163 | privateKeyPem: string |
167 | 164 | ): Record<string, string> { |
168 | 165 | const result: Record<string, string> = {}; |
169 | 166 |
|
170 | | - for (const channelKey of Object.keys(CHANNEL_ENV_MAP) as (keyof EncryptedChannelTokens)[]) { |
| 167 | + for (const channelKey of Object.keys(channels) as (keyof EncryptedChannelTokens)[]) { |
171 | 168 | const envelope = channels[channelKey]; |
172 | 169 | if (envelope) { |
173 | | - result[CHANNEL_ENV_MAP[channelKey]] = decryptWithPrivateKey(envelope, privateKeyPem); |
| 170 | + const envVarName = FIELD_KEY_TO_ENV_VAR.get(channelKey); |
| 171 | + if (!envVarName) { |
| 172 | + // Gracefully skip unknown keys rather than hard-failing. |
| 173 | + // This can happen if DO state contains a key that was removed from the |
| 174 | + // catalog (e.g. after a schema rollback) or added to EncryptedChannelTokens |
| 175 | + // before the catalog was updated. |
| 176 | + console.warn( |
| 177 | + `[decryptChannelTokens] Unknown channel key '${channelKey}' — not in secret catalog. Skipping.` |
| 178 | + ); |
| 179 | + continue; |
| 180 | + } |
| 181 | + result[envVarName] = decryptWithPrivateKey(envelope, privateKeyPem); |
174 | 182 | } |
175 | 183 | } |
176 | 184 |
|
|
0 commit comments