fix(security): a production server refuses to start until its keys, allowed origins and test login are right (REL-01, REL-03, SEC-04)
With NODE_ENV=production (always, in the Docker image) the API lists every problem at once and does not start while any of these holds: - OTP_MASTER_CODE is set: the fixed test login signs in any customer. A test server built from the production image must say so with TEST_SERVER_ALLOW_MASTER_CODE=yes. - JWT_CUSTOMER_SECRET is missing, equal to JWT_SECRET, or under 32 characters. - JWT_SECRET is missing, the published dev key, or under 32 characters. - CORS_ORIGINS is empty, `*`, or not full origins. It no longer falls back to allow-all. Checked live: a misconfigured start lists all four problems; a correct one starts, answers the allowed origin, and blocks any other. docs/SERVER-SETUP-CHECKLIST.md is the operator's list. DELIVERY.md, docker-compose.yml and .env.example are updated to match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d91dcf197b
commit
9d3b5388ba
@@ -0,0 +1,49 @@
|
||||
import { productionConfigProblems } from './production-checks';
|
||||
|
||||
describe('productionConfigProblems', () => {
|
||||
const A = 'a'.repeat(40);
|
||||
const C = 'c'.repeat(40);
|
||||
const good = {
|
||||
NODE_ENV: 'production',
|
||||
JWT_SECRET: A,
|
||||
JWT_CUSTOMER_SECRET: C,
|
||||
CORS_ORIGINS: 'https://adm.example.ir, https://app.example.ir/',
|
||||
};
|
||||
|
||||
it('a complete production config passes', () => {
|
||||
expect(productionConfigProblems(good)).toEqual([]);
|
||||
});
|
||||
|
||||
it('checks nothing outside production', () => {
|
||||
expect(productionConfigProblems({ NODE_ENV: 'development' })).toEqual([]);
|
||||
});
|
||||
|
||||
it('refuses the fixed test login code (REL-01)', () => {
|
||||
expect(productionConfigProblems({ ...good, OTP_MASTER_CODE: '1234' })).toHaveLength(1);
|
||||
// explicit opt-in for a test server built from the production image
|
||||
expect(
|
||||
productionConfigProblems({ ...good, OTP_MASTER_CODE: '1234', TEST_SERVER_ALLOW_MASTER_CODE: 'yes' }),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it('requires a separate customer token key (REL-03)', () => {
|
||||
expect(productionConfigProblems({ ...good, JWT_CUSTOMER_SECRET: '' })).toHaveLength(1);
|
||||
expect(productionConfigProblems({ ...good, JWT_CUSTOMER_SECRET: A })).toHaveLength(1);
|
||||
expect(productionConfigProblems({ ...good, JWT_CUSTOMER_SECRET: 'short' })).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('requires a strong admin key (SEC-04)', () => {
|
||||
expect(productionConfigProblems({ ...good, JWT_SECRET: undefined })).toHaveLength(1);
|
||||
expect(productionConfigProblems({ ...good, JWT_SECRET: 'dev-only-insecure-secret' })).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('requires an explicit list of allowed origins (SEC-04)', () => {
|
||||
expect(productionConfigProblems({ ...good, CORS_ORIGINS: '' })).toHaveLength(1);
|
||||
expect(productionConfigProblems({ ...good, CORS_ORIGINS: '*' })).toHaveLength(1);
|
||||
expect(productionConfigProblems({ ...good, CORS_ORIGINS: 'adm.example.ir' })).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('lists every problem at once', () => {
|
||||
expect(productionConfigProblems({ NODE_ENV: 'production', OTP_MASTER_CODE: '1234' })).toHaveLength(4);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user