Harden platform security, reliability, and CI after full audit.

Close deployment IDOR and gate stub payment endpoints, add production
secret validation, health probes, Redis-backed build progress, GitHub
Actions CI, expanded tests, billing/k8s refactors, and ops runbooks.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
keyhan
2026-06-29 20:59:49 +03:30
parent a87bc49393
commit 837f0fa63f
83 changed files with 3953 additions and 1308 deletions
+5
View File
@@ -84,6 +84,11 @@ export default () => ({
port: parseInt(process.env.REDIS_PORT || '6379', 10),
},
cluster: {
/** AES-256-GCM key for encrypting stored kubeconfigs. Required in production. */
kubeconfigKey: process.env.CLUSTER_KUBECONFIG_KEY || '',
},
// OTP SMS. Provider selectable via SMS_PROVIDER ('mizbansms' | 'kavenegar').
sms: {
provider: (process.env.SMS_PROVIDER || 'mizbansms').trim().toLowerCase(),
@@ -0,0 +1,40 @@
import { validateProductionConfig } from './validate-production-config';
describe('validateProductionConfig', () => {
const env = process.env;
beforeEach(() => {
process.env = { ...env };
});
afterAll(() => {
process.env = env;
});
it('does nothing in development', () => {
process.env.NODE_ENV = 'development';
delete process.env.JWT_SECRET;
expect(() => validateProductionConfig()).not.toThrow();
});
it('throws in production when secrets are missing or default', () => {
process.env.NODE_ENV = 'production';
process.env.JWT_SECRET = 'default-jwt-secret';
process.env.JWT_REFRESH_SECRET = 'default-refresh-secret';
process.env.DB_PASSWORD = 'cloudhost_secret';
expect(() => validateProductionConfig()).toThrow(/Production configuration validation failed/);
expect(() => validateProductionConfig()).toThrow(/JWT_SECRET/);
expect(() => validateProductionConfig()).toThrow(/CLUSTER_KUBECONFIG_KEY/);
});
it('passes in production with strong secrets', () => {
process.env.NODE_ENV = 'production';
process.env.JWT_SECRET = 'a-very-long-random-production-secret';
process.env.JWT_REFRESH_SECRET = 'another-very-long-random-refresh-secret';
process.env.DB_PASSWORD = 'strong-db-password-here';
process.env.CLUSTER_KUBECONFIG_KEY = '0123456789abcdef0123456789abcdef';
expect(() => validateProductionConfig()).not.toThrow();
});
});
@@ -0,0 +1,34 @@
const DEFAULT_JWT_SECRET = 'default-jwt-secret';
const DEFAULT_REFRESH_SECRET = 'default-refresh-secret';
const DEFAULT_DB_PASSWORD = 'cloudhost_secret';
export function validateProductionConfig(): void {
if (process.env.NODE_ENV !== 'production') {
return;
}
const errors: string[] = [];
const jwtSecret = process.env.JWT_SECRET || DEFAULT_JWT_SECRET;
const refreshSecret = process.env.JWT_REFRESH_SECRET || DEFAULT_REFRESH_SECRET;
const dbPassword = process.env.DB_PASSWORD || DEFAULT_DB_PASSWORD;
if (!process.env.JWT_SECRET || jwtSecret === DEFAULT_JWT_SECRET) {
errors.push('JWT_SECRET must be set to a strong random value in production');
}
if (!process.env.JWT_REFRESH_SECRET || refreshSecret === DEFAULT_REFRESH_SECRET) {
errors.push('JWT_REFRESH_SECRET must be set to a strong random value in production');
}
if (!process.env.DB_PASSWORD || dbPassword === DEFAULT_DB_PASSWORD) {
errors.push('DB_PASSWORD must be changed from the default in production');
}
if (!process.env.CLUSTER_KUBECONFIG_KEY?.trim()) {
errors.push('CLUSTER_KUBECONFIG_KEY must be set in production to encrypt stored kubeconfigs');
}
if (errors.length > 0) {
throw new Error(
`Production configuration validation failed:\n${errors.map((e) => ` - ${e}`).join('\n')}`,
);
}
}