feat(release): add reversible production cutover gates

This commit is contained in:
chick
2026-07-18 17:24:51 +08:00
parent 3718c91706
commit 4a7e29cf06
18 changed files with 1468 additions and 8 deletions
+22 -2
View File
@@ -28,6 +28,7 @@ describe('production runtime foundation', () => {
MULTI_SIMADMIN_DATA_ROOT: root,
MULTI_SIMADMIN_DATABASE_PATH: join(root, 'db.sqlite'),
MULTI_SIMADMIN_GATEWAY_TOKEN: token,
MULTI_SIMADMIN_WEB_DIST: root,
API_HOST: '127.0.0.1',
API_PORT: '8790',
});
@@ -36,6 +37,7 @@ describe('production runtime foundation', () => {
dataRoot: root,
databasePath: join(root, 'db.sqlite'),
gatewayToken: token,
webDist: root,
});
expect(Object.isFrozen(config)).toBe(true);
expect(Object.isFrozen(config.api)).toBe(true);
@@ -44,6 +46,7 @@ describe('production runtime foundation', () => {
MULTI_SIMADMIN_DATA_ROOT: root,
MULTI_SIMADMIN_DATABASE_PATH: '/tmp/escape.sqlite',
MULTI_SIMADMIN_GATEWAY_TOKEN: token,
MULTI_SIMADMIN_WEB_DIST: root,
}),
).toThrow(/data root/i);
expect(() =>
@@ -70,6 +73,7 @@ describe('production runtime foundation', () => {
MULTI_SIMADMIN_DATA_ROOT: root,
MULTI_SIMADMIN_DATABASE_PATH: databasePath,
MULTI_SIMADMIN_GATEWAY_TOKEN: token,
MULTI_SIMADMIN_WEB_DIST: root,
}),
).toThrow(/data root|symlink/i);
await expect(lstat(join(outside, 'db.sqlite'))).rejects.toMatchObject({ code: 'ENOENT' });
@@ -150,10 +154,26 @@ describe('production runtime foundation', () => {
const db = openDatabase(join(directory, 'db.sqlite'));
migrateDatabase(db);
const keychainMetadataCheck = vi.fn(async () => true);
const readiness = createProductionReadiness({ db, gatewayToken: token, keychainMetadataCheck });
const readiness = createProductionReadiness({
db,
gatewayToken: token,
keychainMetadataCheck,
assetsCheck: async () => true,
recoveryMarkersCheck: async () => 0,
upstreamGatewayCheck: async () => true,
});
expect(await readiness()).toEqual({
ready: true,
checks: { database: 'ready', migrations: 'ready', gatewayAuth: 'ready', keychain: 'ready' },
checks: {
database: 'ready',
migrations: 'ready',
gatewayAuth: 'ready',
keychain: 'ready',
pendingCredentials: 'ready',
assets: 'ready',
recoveryMarkers: 'ready',
upstreamGateway: 'ready',
},
});
expect(keychainMetadataCheck).toHaveBeenCalledOnce();
db.close();