Files
core2026/tools/legacy-db-migration/test/config.test.ts
T
Hide_D 0c5dee1af8 fix(migration): Ref 전용 아이콘을 업로드 API로 이관한다
전용 아이콘 바이트를 모두 검증한 뒤 sam-image 서명 API에 결정적 경로로 등록한다. API 반환 경로를 계정과 아이콘 소유 목록에 연결하고 Core에서 바뀐 현재 선택은 보존한다.
2026-08-24 08:33:19 +00:00

74 lines
3.1 KiB
TypeScript

import { chmod, mkdtemp, rm, writeFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import { loadMigrationPlan } from '../src/config.js';
const workDirectories: string[] = [];
afterEach(async () => {
delete process.env.TEST_GATEWAY_DATABASE_URL;
await Promise.all(workDirectories.splice(0).map((directory) => rm(directory, { recursive: true, force: true })));
});
const writeFixture = async (mode = 0o600): Promise<string> => {
const directory = await mkdtemp(path.join(os.tmpdir(), 'sammo-legacy-plan-'));
workDirectories.push(directory);
await writeFile(path.join(directory, 'mysql-password'), 'secret-value\n', { mode: 0o600 });
await writeFile(path.join(directory, 'image-upload-secret'), `${'u'.repeat(32)}\n`, { mode: 0o600 });
const iconDirectory = await mkdtemp(path.join(directory, 'icons-'));
const configPath = path.join(directory, 'migration-plan.json');
await writeFile(
configPath,
JSON.stringify({
version: 1,
sourceSet: 'fixture-cutover',
gateway: {
source: {
host: '127.0.0.1',
database: 'root_dump',
user: 'migration_reader',
passwordFile: './mysql-password',
},
userIcons: {
sourceDirectory: iconDirectory,
uploadBaseUrl: 'https://sam-image.hided.net',
publicBaseUrl: 'https://sam-image.hided.net/icons',
uploadSecretFile: './image-upload-secret',
},
targetUrlEnv: 'TEST_GATEWAY_DATABASE_URL',
},
}),
{ mode }
);
await chmod(configPath, mode);
return configPath;
};
describe('legacy migration plan config', () => {
it('resolves a mode-0600 structured source without placing its password in arguments', async () => {
process.env.TEST_GATEWAY_DATABASE_URL = 'postgresql://target@127.0.0.1/gateway';
const plan = await loadMigrationPlan(await writeFixture());
const source = new URL(plan.stages[0]!.sourceUrl);
expect(plan.sourceSet).toBe('fixture-cutover');
expect(plan.stages.map((stage) => stage.name)).toEqual(['gateway']);
expect(source.hostname).toBe('127.0.0.1');
expect(source.username).toBe('migration_reader');
expect(source.password).toBe('secret-value');
expect(plan.stages[0]!.sourceIdentity.key).toBe('fixture-cutover:gateway');
expect(plan.stages[0]!.userIcons).toMatchObject({
uploadBaseUrl: 'https://sam-image.hided.net',
publicBaseUrl: 'https://sam-image.hided.net/icons',
uploadSecret: 'u'.repeat(32),
});
});
it('rejects a config readable by group or other users', async () => {
process.env.TEST_GATEWAY_DATABASE_URL = 'postgresql://target@127.0.0.1/gateway';
await expect(loadMigrationPlan(await writeFixture(0o644))).rejects.toThrow('expected mode 0600');
});
});