feat: Schlüssel und gemeinsamer Kern für Sprachnotizen (T7 L2 Tasks 5+6)
Task 5: Schlüsselbund-Zweck voice (VOICE_ENCRYPTION_KEY), AES-256-GCM- Hilfen für Text und Bytes mit AAD capture:<id>:<art>, voice-config (Modell, Tageslimit, Aufnahme, Whisper-Grösse) und anthropic-config (nie geloggt, nur worker/all), Startprüfung verlangt den Schlüssel in Produktion in jeder Rolle, rekey versiegelt offene Sprachnotizen neu (Audio einzeln gelesen, CAS mit Status), Secret-Vorlagen und ensure-secrets.sh ergänzt. Task 6: Text-Normalisierung und Bereinigung (Steuer- und Formatzeichen, Codepoint-Kürzung), Zitatprüfung mit Dezimalzahlen als ein Wort (Ruling 7), Felderliste passend zu CreateInspectionDto, versiegeltes Transkript mit Grenzen, Fachwörter und Skalen mit Paritätstests. Rollout: Ein Image mit diesem Stand startet in Produktion nur mit VOICE_ENCRYPTION_KEY in apicore-backend-secret (ARCHITECTURE Annahme 22). Gates: Backend tsc, eslint, 922 Unit-Tests, e2e 100 Suites / 1004 Tests. Refs #27 #28 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
2a4dc868d9
commit
9795f98006
27 files changed
+2212
-31
No files matched your search
@@ -0,0 +1,59 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import type { ApicoreRole } from '../runtime/role';
|
||||
|
||||
/** Key format issued by Anthropic: "sk-ant-" followed by URL-safe characters. */
|
||||
export const ANTHROPIC_KEY_PATTERN = /^sk-ant-[A-Za-z0-9_-]{20,}$/;
|
||||
|
||||
const PLACEHOLDER_PATTERN = /^change-me/i;
|
||||
const WORKER_ROLES: readonly ApicoreRole[] = ['worker', 'all'];
|
||||
|
||||
function trimmed(value: string | undefined): string | null {
|
||||
const text = value?.trim();
|
||||
return text ? text : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The API key for voice extraction, or null if it is unset, a placeholder or
|
||||
* malformed - extraction then stays off (code EXTRACT_DISABLED). Only the
|
||||
* worker holds the key (Secret apicore-anthropic, optional).
|
||||
*/
|
||||
export function anthropicApiKey(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): string | null {
|
||||
const key = trimmed(env.ANTHROPIC_API_KEY);
|
||||
return key !== null && ANTHROPIC_KEY_PATTERN.test(key) ? key : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Startup check, same rules as the Telegram token: optional, a bad value
|
||||
* never stops a pod. In the worker, a missing key is a warning and a
|
||||
* placeholder or malformed key an error, once, naming the variable and
|
||||
* never its value. API and job pods never hold the key and skip the check.
|
||||
*/
|
||||
export function assertAnthropicKey(
|
||||
role: ApicoreRole,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
logger: Pick<Logger, 'warn' | 'error'> = new Logger('AnthropicStartup'),
|
||||
): void {
|
||||
if (!WORKER_ROLES.includes(role)) {
|
||||
return;
|
||||
}
|
||||
const raw = trimmed(env.ANTHROPIC_API_KEY);
|
||||
if (raw === null) {
|
||||
logger.warn(
|
||||
'ANTHROPIC_API_KEY is not set: voice extraction stays off (EXTRACT_DISABLED).',
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (PLACEHOLDER_PATTERN.test(raw)) {
|
||||
logger.error(
|
||||
'ANTHROPIC_API_KEY is still set to an example placeholder: voice extraction stays off - set the real key or remove it.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!ANTHROPIC_KEY_PATTERN.test(raw)) {
|
||||
logger.error(
|
||||
'ANTHROPIC_API_KEY is malformed (expected "sk-ant-..."): voice extraction stays off.',
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user