- Add docker-compose.yml following trading web pattern - Update web Dockerfile to use multi-stage build with metadata - Add build metadata (commit SHA, branch, timestamp, author, message) - Rewrite deploy.sh to use docker compose with build metadata - Add hotcopy deployment script for quick updates - Add comprehensive backend API with deployment orchestration - Add health checks, service management, and monitoring endpoints - Add CI/CD workflow configuration - Add deployment documentation and guides Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
120 lines
3.3 KiB
TypeScript
120 lines
3.3 KiB
TypeScript
import { SecretClient } from '@azure/keyvault-secrets';
|
|
import { DefaultAzureCredential, ClientSecretCredential } from '@azure/identity';
|
|
import { config } from './config.js';
|
|
import { getAzureConfig as getStoredAzureConfig } from '../modules/azure-config/repository.js';
|
|
|
|
let keyVaultClient: SecretClient | null = null;
|
|
|
|
export async function getKeyVaultClient(): Promise<SecretClient | null> {
|
|
if (keyVaultClient) {
|
|
return keyVaultClient;
|
|
}
|
|
|
|
try {
|
|
let credential;
|
|
let keyVaultUrl = config.AZURE_KEY_VAULT_URL;
|
|
|
|
// Try to get configuration from database first
|
|
const storedConfig = await getStoredAzureConfig();
|
|
if (storedConfig && storedConfig.isActive) {
|
|
keyVaultUrl = storedConfig.keyVaultUrl;
|
|
if (storedConfig.tenantId && storedConfig.clientId && storedConfig.clientSecret) {
|
|
credential = new ClientSecretCredential(
|
|
storedConfig.tenantId,
|
|
storedConfig.clientId,
|
|
storedConfig.clientSecret
|
|
);
|
|
}
|
|
}
|
|
|
|
// Fall back to environment variables if no stored config
|
|
if (!credential && config.AZURE_TENANT_ID && config.AZURE_CLIENT_ID && config.AZURE_CLIENT_SECRET) {
|
|
credential = new ClientSecretCredential(
|
|
config.AZURE_TENANT_ID,
|
|
config.AZURE_CLIENT_ID,
|
|
config.AZURE_CLIENT_SECRET
|
|
);
|
|
}
|
|
|
|
// Use DefaultAzureCredential as last resort
|
|
if (!credential) {
|
|
credential = new DefaultAzureCredential();
|
|
}
|
|
|
|
if (!keyVaultUrl) {
|
|
return null;
|
|
}
|
|
|
|
keyVaultClient = new SecretClient(keyVaultUrl, credential);
|
|
return keyVaultClient;
|
|
} catch (error) {
|
|
console.error('Failed to initialize Azure Key Vault client:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function getAzureSecret(secretName: string): Promise<string | null> {
|
|
const client = await getKeyVaultClient();
|
|
if (!client) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const secret = await client.getSecret(secretName);
|
|
return secret.value || null;
|
|
} catch (error) {
|
|
console.error(`Failed to get secret ${secretName} from Azure Key Vault:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function setAzureSecret(secretName: string, secretValue: string): Promise<boolean> {
|
|
const client = await getKeyVaultClient();
|
|
if (!client) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
await client.setSecret(secretName, secretValue);
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Failed to set secret ${secretName} in Azure Key Vault:`, error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function deleteAzureSecret(secretName: string): Promise<boolean> {
|
|
const client = await getKeyVaultClient();
|
|
if (!client) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
await client.beginDeleteSecret(secretName);
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Failed to delete secret ${secretName} from Azure Key Vault:`, error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function listAzureSecrets(): Promise<string[]> {
|
|
const client = await getKeyVaultClient();
|
|
if (!client) {
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
const secrets: string[] = [];
|
|
for await (const secretProperties of client.listPropertiesOfSecrets()) {
|
|
if (secretProperties.name) {
|
|
secrets.push(secretProperties.name);
|
|
}
|
|
}
|
|
return secrets;
|
|
} catch (error) {
|
|
console.error('Failed to list secrets from Azure Key Vault:', error);
|
|
return [];
|
|
}
|
|
}
|