슈퍼어드민 디스코드 ID를 저장소에서 제거: 서버 deploy/.env의 SUPERADMIN_DISCORD_IDS에만 둔다

- config: 기본값 삭제(설정이 없으면 슈퍼어드민 없음)
- 테스트·E2E: 만든 ID(900000000000000001/2) 사용
- 문서·README·.env.example·관리자 화면 입력 예시에서 실제 ID 삭제

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-10-08 10:36:08 +09:00
parent 4e4c195c79
commit e499c79464
10 changed files with 19 additions and 18 deletions

View File

@@ -1,8 +1,8 @@
/** Admin site tests (docs/14-admin.md §9). */
import { afterEach, describe, expect, test } from 'bun:test';
import { Client, api, boot, guest, sleep } from './test-utils';
import { Client, TEST_SUPERADMINS, api, boot, guest, sleep } from './test-utils';
const SUPER = '293719842274541579';
const [SUPER, SUPER2] = TEST_SUPERADMINS;
type Booted = ReturnType<typeof boot>;
const running: Booted[] = [];
const clients: Client[] = [];
@@ -47,7 +47,7 @@ describe('roles', () => {
const me = await api(s.base, '/api/admin/me', { cookie: sup.cookie });
expect(me.body.role).toBe('superadmin');
expect((await api(s.base, '/api/me', { cookie: sup.cookie })).body.role).toBe('superadmin');
const sup2 = await discordLogin(s, '1352267557213573160');
const sup2 = await discordLogin(s, SUPER2);
expect((await api(s.base, '/api/admin/me', { cookie: sup2.cookie })).body.role).toBe('superadmin');
});
@@ -60,7 +60,7 @@ describe('roles', () => {
// Pre-register before the person ever logged in.
const add = await api(s.base, '/api/admin/admins', { method: 'POST', cookie: sup.cookie, body: JSON.stringify({ discordId: adminDiscord, note: '친구1' }) });
expect(add.res.status).toBe(200);
expect(add.body.admins.map((a: any) => a.discordId)).toEqual([SUPER, '1352267557213573160', adminDiscord]);
expect(add.body.admins.map((a: any) => a.discordId)).toEqual([SUPER, SUPER2, adminDiscord]);
const adm = await discordLogin(s, adminDiscord);
expect((await api(s.base, '/api/admin/me', { cookie: adm.cookie })).body.role).toBe('admin');
expect((await api(s.base, '/api/admin/users', { cookie: adm.cookie })).res.status).toBe(403);

View File

@@ -14,9 +14,6 @@ export interface Config {
loadTestNoHttpLimits: boolean;
}
/** Superadmin Discord IDs, comma-separated (docs/14-admin.md §2). */
export const DEFAULT_SUPERADMIN = '293719842274541579,1352267557213573160';
export function loadConfig(env: Record<string, string | undefined> = process.env): Config {
const publicOrigin = (env.PUBLIC_ORIGIN ?? 'http://localhost:5173').replace(/\/$/, '');
const extra = (env.ALLOWED_ORIGINS ?? '').split(',').map((s) => s.trim()).filter(Boolean);
@@ -36,6 +33,7 @@ export function loadConfig(env: Record<string, string | undefined> = process.env
secureCookies: publicOrigin.startsWith('https://'),
trustProxy: env.TRUST_PROXY === '1',
loadTestNoHttpLimits: env.LOADTEST_NO_HTTP_LIMITS === '1' && !publicOrigin.startsWith('https://'),
superadminDiscordIds: (env.SUPERADMIN_DISCORD_IDS ?? DEFAULT_SUPERADMIN).split(',').map((s) => s.trim()).filter(Boolean),
/** Superadmin Discord IDs, comma-separated (docs/14-admin.md §2). Only in deploy/.env, never in the repo. */
superadminDiscordIds: (env.SUPERADMIN_DISCORD_IDS ?? '').split(',').map((s) => s.trim()).filter(Boolean),
};
}

View File

@@ -7,6 +7,8 @@ import { loadConfig } from './config';
import { startServer, type StartOptions } from './server';
export const ORIGIN = 'http://localhost:5173';
/** Made-up superadmin Discord IDs for tests (the real ones live only in deploy/.env). */
export const TEST_SUPERADMINS = ['900000000000000001', '900000000000000002'] as const;
export function tempDbPath(): string {
const dir = mkdtempSync(join(process.env.TMPDIR ?? tmpdir(), 'bg-test-'));
@@ -14,7 +16,7 @@ export function tempDbPath(): string {
}
export function boot(dbPath = tempDbPath(), extra: Partial<StartOptions> = {}) {
const config = loadConfig({ PORT: '0', DB_PATH: dbPath, PUBLIC_ORIGIN: ORIGIN });
const config = loadConfig({ PORT: '0', DB_PATH: dbPath, PUBLIC_ORIGIN: ORIGIN, SUPERADMIN_DISCORD_IDS: TEST_SUPERADMINS.join(',') });
const app = startServer({ config, log: () => {}, staticDir: null, stopWaitMs: 50, ...extra });
const base = `http://localhost:${app.server.port}`;
return { ...app, base, dbPath, config };