PSA/server/knexfile.cjs
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

181 lines
5.0 KiB
JavaScript

/* eslint-disable no-undef */
require('dotenv').config();
const fs = require('fs');
const path = require('path');
// Calculate secrets directory path once at module load
const DOCKER_SECRETS_PATH = '/run/secrets';
const LOCAL_SECRETS_PATH = '../secrets';
const SECRETS_PATH = fs.existsSync(DOCKER_SECRETS_PATH) ? DOCKER_SECRETS_PATH : LOCAL_SECRETS_PATH;
/**
* Gets a secret value from either a Docker secret file or environment variable
* @param secretName - Name of the secret (e.g. 'postgres_password')
* @param envVar - Name of the fallback environment variable
* @param defaultValue - Optional default value if neither source exists
* @returns The secret value as a string
*/
function getSecret(secretName, envVar, defaultValue = '') {
const secretPath = path.join(SECRETS_PATH, secretName);
try {
return fs.readFileSync(secretPath, 'utf8').trim();
} catch (error) {
if (process.env[envVar]) {
console.warn(`Using ${envVar} environment variable instead of Docker secret`);
const envVal = process.env[envVar] || defaultValue;
console.log(`Using ${envVar} environment variable: ${envVal}`);
return envVal;
}
console.warn(`Neither secret file ${secretPath} nor ${envVar} environment variable found, using default value`);
return defaultValue;
}
}
const DatabaseType = {
postgres: 'postgres'
};
const externals = {
[DatabaseType.postgres]: 'pg'
// Add more alternatives as needed
};
const isValidDbType = (type) => {
return type !== undefined && Object.keys(externals).includes(type);
};
const getClient = () => {
const dbType = process.env.DB_TYPE;
if (isValidDbType(dbType)) {
return externals[dbType];
}
console.warn(`Invalid or missing DB_TYPE: ${dbType}. Defaulting to postgres.`);
return externals[DatabaseType.postgres];
};
const { validate: uuidValidate } = require('uuid');
const seedsDirectory = process.env.SEEDS_DIR || './seeds/dev';
function isValidTenantId(tenantId) {
if (!tenantId) return true;
if (tenantId === 'default') return true;
return uuidValidate(tenantId);
}
const createConnectionWithTenant = (config, tenant) => {
if (!isValidTenantId(tenant)) {
throw new Error('Invalid tenant ID format');
}
return {
...config,
asyncStackTraces: true,
pool: {
...config.pool,
afterCreate: (conn, done) => {
// With CitusDB, tenant isolation is handled automatically at the shard level
// No need to set app.current_tenant session variable
console.log(`Connection created for tenant: ${tenant} (CitusDB handles isolation automatically)`);
done(null, conn);
},
},
};
};
// Base configuration for migrations (uses postgres user)
const migrationConfig = {
client: 'pg',
connection: {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER_ADMIN || 'postgres',
password: getSecret('postgres_password', 'DB_PASSWORD_ADMIN'),
database: process.env.DB_NAME_SERVER,
},
pool: {
min: 0,
max: 20,
},
migrations: {
directory: process.env.MIGRATIONS_DIR || "./migrations",
loadExtensions: ['.cjs', '.js']
},
seeds: {
directory: seedsDirectory,
loadExtensions: ['.cjs', '.js']
}
};
// Base configuration for application (uses app_user)
const appConfig = {
client: 'pg',
connection: {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER_SERVER || 'app_user',
password: getSecret('db_password_server', 'DB_PASSWORD_SERVER'),
database: process.env.DB_NAME_SERVER,
},
pool: {
min: 2,
max: 20,
}
};
const knexfile = {
development: {
// Development uses app_user for normal operations
...appConfig,
// But keeps postgres user connection for migrations
migrations: migrationConfig.migrations,
seeds: {
directory: seedsDirectory,
loadExtensions: ['.cjs', '.js']
}
},
test: {
client: 'pg',
connection: {
host: process.env.DB_HOST || 'localhost',
port: process.env.DB_PORT || '5432',
user: process.env.DB_USER_ADMIN || 'postgres',
password: getSecret('db_password_server', 'DB_PASSWORD_SERVER', 'test_password'),
database: process.env.DB_NAME_SERVER || 'sebastian_test',
},
pool: {
min: 2,
max: 20,
},
migrations: migrationConfig.migrations,
},
production: {
// Production uses app_user for normal operations
...appConfig,
// But keeps postgres user connection for migrations
migrations: migrationConfig.migrations,
},
local: {
client: 'postgresql',
connection: {
host: 'localhost',
port: '5432',
user: process.env.DB_USER_SERVER || 'postgres',
password: getSecret('db_password_server', 'DB_PASSWORD_SERVER', 'abcd1234!'),
database: process.env.DB_NAME_SERVER || 'server',
},
migrations: migrationConfig.migrations,
},
// Special config just for running migrations (uses postgres user)
migration: migrationConfig
};
// console.log('/server knexfile', knexfile);
module.exports = {
...knexfile,
createConnectionWithTenant,
};