운영 보안을 보존하여 빌드 개선 배포본 통합

This commit is contained in:
2026-10-23 01:33:42 +09:00
97 changed files with 5522 additions and 740 deletions
+6 -1
View File
@@ -29,7 +29,12 @@ const main = async (): Promise<void> => {
baseEnv: config.baseEnv,
});
const migrationRunner = new PnpmBuildRunner();
const releaseBuildRunner = createReleaseBuildRunner(config.releaseBuilderUrl, migrationRunner);
const releaseBuildRunner = createReleaseBuildRunner(
config.releaseBuilderUrl,
migrationRunner,
fetch,
config.baseEnv.RELEASE_BUILDER_TOKEN_FILE
);
const processManager = new Pm2ProcessManager();
const controller = new GatewayReleaseController(
repository,
@@ -160,7 +160,12 @@ export class GatewayReleaseController {
private readonly now: () => Date = () => new Date(),
private readonly fetchImpl: typeof fetch = fetch
) {
this.releaseBuildRunner = createReleaseBuildRunner(config.releaseBuilderUrl, migrationRunner, fetchImpl);
this.releaseBuildRunner = createReleaseBuildRunner(
config.releaseBuilderUrl,
migrationRunner,
fetchImpl,
config.baseEnv.RELEASE_BUILDER_TOKEN_FILE
);
this.artifactManager = new FrontendArtifactManager(config.frontendArtifactRoot ?? '/srv/frontend-artifacts');
}
@@ -509,7 +514,11 @@ export class GatewayReleaseController {
}
private async waitForReadiness(operationId: string): Promise<void> {
await this.appendLog(operationId, 'readiness', 'Gateway API, 정적 frontend와 PM2 process readiness를 확인합니다.');
await this.appendLog(
operationId,
'readiness',
'Gateway API, 정적 frontend와 PM2 process readiness를 확인합니다.'
);
const deadline = performance.now() + this.config.readinessTimeoutMs;
const apiUrl = `http://127.0.0.1:${this.config.gatewayApiPort}/healthz`;
const frontendUrl =
@@ -524,10 +533,7 @@ export class GatewayReleaseController {
);
while (performance.now() < deadline) {
try {
const [api, frontend] = await Promise.all([
this.fetchImpl(apiUrl),
this.fetchImpl(frontendUrl),
]);
const [api, frontend] = await Promise.all([this.fetchImpl(apiUrl), this.fetchImpl(frontendUrl)]);
const processes = await this.processManager.list();
const expected = processes.filter((process) => expectedNames.includes(process.name));
const safe = expected.filter(
@@ -447,6 +447,8 @@ describe('GatewayReleaseController', () => {
it('runs release builds remotely while keeping Gateway migration on the runtime runner', async () => {
const workspace = await createReleaseWorkspace();
const tokenFile = path.join(workspace, 'builder-token.fixture');
await fs.writeFile(tokenFile, 't'.repeat(64), { mode: 0o600 });
const harness = createRepository();
const localCommandGroups: string[][] = [];
const remoteRequests: Array<{ commands: Array<{ args: string[] }> }> = [];
@@ -481,10 +483,15 @@ describe('GatewayReleaseController', () => {
running.delete(name);
},
},
{ ...config, releaseBuilderUrl: 'http://builder:15100' },
{
...config,
releaseBuilderUrl: 'http://builder:15100',
baseEnv: { ...config.baseEnv, RELEASE_BUILDER_TOKEN_FILE: tokenFile },
},
() => new Date('2026-08-01T00:00:00.000Z'),
async (input, init) => {
if (String(input) === 'http://builder:15100/v1/builds') {
expect(new Headers(init?.headers).get('x-release-builder-token')).toBe('t'.repeat(64));
remoteRequests.push(JSON.parse(String(init?.body)) as { commands: Array<{ args: string[] }> });
return new Response(`${JSON.stringify({ result: { ok: true, exitCode: 0, output: '' } })}\n`, {
status: 200,