clawdie-ai/setup/secrets.ts
Operator & Codex aabc403648 Align subnet defaults and public jail docs
---
Build: pass | Tests: pass — 71 passed (3 files)

---
Build: pass | Tests: pass — 2163 passed (630 files)
2026-05-05 22:23:42 +02:00

232 lines
7 KiB
TypeScript

import { randomBytes } from 'crypto';
import fs from 'fs';
import {
brainDb,
brainDbUser,
forgejoDb,
forgejoDbUser,
opsDb,
opsDbUser,
sharedGitDb,
sharedGitDbUser,
sharedBrainDb,
sharedBrainDbUser,
sharedOpsDb,
sharedOpsDbUser,
sharedSkillsDb,
sharedSkillsDbUser,
skillsDb,
skillsDbUser,
} from '../src/db-identifiers.js';
import { normalizeTenantId } from '../src/platform-layout.js';
import { ensureEnvFile, extractEnvValue, writeEnvLine } from './profile.js';
export interface SplitBrainSecrets {
envFile: string;
tenantId: string;
subnetBase: string;
dbHost: string;
skillsDbUser: string;
skillsDbName: string;
memoryDbUser: string;
memoryDbName: string;
forgejoDbUser: string;
forgejoDbName: string;
opsDbUser: string;
opsDbName: string;
postgresAdminPassword: string;
skillsDbPassword: string;
memoryDbPassword: string;
forgejoDbPassword: string;
opsDbPassword: string;
strapiDbPassword: string;
strapiAppKeys: string;
strapiApiTokenSalt: string;
strapiAdminJwtSecret: string;
strapiTransferTokenSalt: string;
strapiJwtSecret: string;
skillsDbUrl: string;
memoryDbUrl: string;
forgejoDbUrl: string;
opsDbUrl: string;
}
function generateSecret(bytes = 24): string {
return randomBytes(bytes).toString('base64url');
}
function generateStrapiAppKeys(): string {
return Array.from({ length: 4 }, () => generateSecret(24)).join(',');
}
function currentEnvValue(content: string, key: string): string | null {
const value = extractEnvValue(content, key);
return value && value.trim() ? value.trim() : null;
}
function buildPostgresUrl(
user: string,
password: string,
host: string,
database: string,
): string {
return `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}:5432/${encodeURIComponent(database)}`;
}
function writeIfMissing(envFile: string, key: string, value: string): void {
const content = fs.readFileSync(envFile, 'utf-8');
if (!currentEnvValue(content, key)) {
writeEnvLine(envFile, key, value);
}
}
export function ensureSplitBrainSecrets(
projectRoot: string,
): SplitBrainSecrets {
const envFile = ensureEnvFile(projectRoot);
let content = fs.readFileSync(envFile, 'utf-8');
const rawTenantId = currentEnvValue(content, 'TENANT_ID');
const tenantId = rawTenantId ? normalizeTenantId(rawTenantId) : '';
const subnetBase =
currentEnvValue(content, 'AGENT_SUBNET_BASE') ||
currentEnvValue(content, 'WARDEN_SUBNET_BASE') ||
'10.0.1';
const dbRuntime = (
process.env.DB_RUNTIME ||
currentEnvValue(content, 'DB_RUNTIME') ||
'jail'
)
.trim()
.toLowerCase();
const dbHost =
process.env.DB_HOST ||
currentEnvValue(content, 'DB_HOST') ||
(dbRuntime === 'host'
? `${subnetBase}.1`
: currentEnvValue(content, 'WARDEN_DB_IP') || `${subnetBase}.5`);
const skillsUser =
currentEnvValue(content, 'SKILLS_DB_USER') ||
(tenantId ? skillsDbUser(tenantId) : sharedSkillsDbUser());
const skillsName =
currentEnvValue(content, 'SKILLS_DB_NAME') ||
(tenantId ? skillsDb(tenantId) : sharedSkillsDb());
const memoryUser =
currentEnvValue(content, 'MEMORY_DB_USER') ||
(tenantId ? brainDbUser(tenantId) : sharedBrainDbUser());
const memoryName =
currentEnvValue(content, 'MEMORY_DB_NAME') ||
(tenantId ? brainDb(tenantId) : sharedBrainDb());
const forgejoUser =
currentEnvValue(content, 'FORGEJO_DB_USER') ||
(tenantId ? forgejoDbUser(tenantId) : sharedGitDbUser());
const forgejoName =
currentEnvValue(content, 'FORGEJO_DB_NAME') ||
(tenantId ? forgejoDb(tenantId) : sharedGitDb());
const opsUser =
currentEnvValue(content, 'OPS_DB_USER') ||
(tenantId ? opsDbUser(tenantId) : sharedOpsDbUser());
const opsName =
currentEnvValue(content, 'OPS_DB_NAME') ||
(tenantId ? opsDb(tenantId) : sharedOpsDb());
writeIfMissing(envFile, 'POSTGRES_ADMIN_PASSWORD', generateSecret(24));
writeIfMissing(envFile, 'SKILLS_DB_PASSWORD', generateSecret(24));
writeIfMissing(envFile, 'MEMORY_DB_PASSWORD', generateSecret(24));
writeIfMissing(envFile, 'FORGEJO_DB_PASSWORD', generateSecret(24));
writeIfMissing(envFile, 'OPS_DB_PASSWORD', generateSecret(24));
writeIfMissing(envFile, 'STRAPI_DB_PASSWORD', generateSecret(24));
writeIfMissing(envFile, 'STRAPI_APP_KEYS', generateStrapiAppKeys());
writeIfMissing(envFile, 'STRAPI_API_TOKEN_SALT', generateSecret(24));
writeIfMissing(envFile, 'STRAPI_ADMIN_JWT_SECRET', generateSecret(24));
writeIfMissing(envFile, 'STRAPI_TRANSFER_TOKEN_SALT', generateSecret(24));
writeIfMissing(envFile, 'STRAPI_JWT_SECRET', generateSecret(24));
content = fs.readFileSync(envFile, 'utf-8');
const postgresAdminPassword =
currentEnvValue(content, 'POSTGRES_ADMIN_PASSWORD') || generateSecret(24);
const skillsDbPassword =
currentEnvValue(content, 'SKILLS_DB_PASSWORD') || generateSecret(24);
const memoryDbPassword =
currentEnvValue(content, 'MEMORY_DB_PASSWORD') || generateSecret(24);
const forgejoDbPassword =
currentEnvValue(content, 'FORGEJO_DB_PASSWORD') || generateSecret(24);
const opsDbPassword =
currentEnvValue(content, 'OPS_DB_PASSWORD') || generateSecret(24);
const strapiDbPassword =
currentEnvValue(content, 'STRAPI_DB_PASSWORD') || generateSecret(24);
const strapiAppKeys =
currentEnvValue(content, 'STRAPI_APP_KEYS') || generateStrapiAppKeys();
const strapiApiTokenSalt =
currentEnvValue(content, 'STRAPI_API_TOKEN_SALT') || generateSecret(24);
const strapiAdminJwtSecret =
currentEnvValue(content, 'STRAPI_ADMIN_JWT_SECRET') || generateSecret(24);
const strapiTransferTokenSalt =
currentEnvValue(content, 'STRAPI_TRANSFER_TOKEN_SALT') ||
generateSecret(24);
const strapiJwtSecret =
currentEnvValue(content, 'STRAPI_JWT_SECRET') || generateSecret(24);
const skillsDbUrl = buildPostgresUrl(
skillsUser,
skillsDbPassword,
dbHost,
skillsName,
);
const memoryDbUrl = buildPostgresUrl(
memoryUser,
memoryDbPassword,
dbHost,
memoryName,
);
const forgejoDbUrl = buildPostgresUrl(
forgejoUser,
forgejoDbPassword,
dbHost,
forgejoName,
);
const opsDbUrl = buildPostgresUrl(
opsUser,
opsDbPassword,
dbHost,
opsName,
);
writeEnvLine(envFile, 'SKILLS_DB_URL', skillsDbUrl);
writeEnvLine(envFile, 'MEMORY_DB_URL', memoryDbUrl);
writeEnvLine(envFile, 'FORGEJO_DB_URL', forgejoDbUrl);
writeEnvLine(envFile, 'OPS_DB_URL', opsDbUrl);
return {
envFile,
tenantId,
subnetBase,
dbHost,
skillsDbUser: skillsUser,
skillsDbName: skillsName,
memoryDbUser: memoryUser,
memoryDbName: memoryName,
forgejoDbUser: forgejoUser,
forgejoDbName: forgejoName,
opsDbUser: opsUser,
opsDbName: opsName,
postgresAdminPassword,
skillsDbPassword,
memoryDbPassword,
forgejoDbPassword,
opsDbPassword,
strapiDbPassword,
strapiAppKeys,
strapiApiTokenSalt,
strapiAdminJwtSecret,
strapiTransferTokenSalt,
strapiJwtSecret,
skillsDbUrl,
memoryDbUrl,
forgejoDbUrl,
opsDbUrl,
};
}