KISA 제보 3건(KVE-2026-2010/2011/2018)과 그 동일 계열 형제 결함을 전수 조치하고, 그 과정에서 드러난 두 결함군을 함께 닫는다. - 검증 시점과 연결 시점이 host 를 다르게 읽던 SSRF 통로를 정규화 SSoT 한 곳으로 모았다 - 세션을 여는 지점(2FA 완료·토큰 재발급)이 잠금 검사를 거치지 않아 계정 잠금이 우회됐다 - 인증도 서명도 없는 브라우저 리턴 콜백이 주문 상태를 바꾸던 통로를 4 PG 전부에서 닫고, 소유권을 대조하는 close-report 를 토스에도 신설했다. 그 결과 정리 주체를 잃는 결제창 미완료 주문은 만료 자동취소가 거둔다 - 저장소 A(_local)에만 쓰는 경로가 B 의 값을 조용히 덮던 회귀를 정본 writer 로 닫았다 (engine-v1.63.5). 한 방향만 보던 정적 검사에 반대 방향 축과 양방향 계약 테스트를 더했다 - 레이아웃 JSON 의 같은 객체 중복 키가 앞선 선언을 오류 없이 삼키던 결함군을 닫았다
103 lines
4.9 KiB
TypeScript
103 lines
4.9 KiB
TypeScript
/**
|
|
* KG이니시스 플러그인 Playwright E2E 설정.
|
|
*
|
|
* 코어 `playwright.config.ts` 와 동일한 base URL 해석 우선순위를 따른다 — 플러그인도 활성 호스트가
|
|
* 가변(개발자/CI/운영 환경별로 다른 도메인)이므로 하드코딩 회피.
|
|
*
|
|
* Base URL 해석:
|
|
* 1. PLAYWRIGHT_BASE_URL 환경변수 (CI/명시적 오버라이드)
|
|
* 2. .env (코어 루트) 의 APP_URL — 단 localhost 류는 fallback 부적합
|
|
* 3. 그 외 — 명시 에러
|
|
*
|
|
* 실행 예시:
|
|
* PowerShell — $env:PLAYWRIGHT_BASE_URL='https://g7.dev'; npm run test:e2e
|
|
* Bash — PLAYWRIGHT_BASE_URL=https://g7.dev npm run test:e2e
|
|
*
|
|
* 플러그인은 코어 fixture 의 `issueToken` / `authenticatePage` 헬퍼를 재사용 — 권한 식별자는
|
|
* `sirsoft-pay_kginicis.*` 등 임의 string.
|
|
*/
|
|
import { defineConfig, devices } from '@playwright/test';
|
|
import { readFileSync, existsSync } from 'node:fs';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
// ESM 환경(package.json "type": "module")에서는 __dirname 이 정의되지 않으므로
|
|
// import.meta.url 로 재구성한다.
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
|
/**
|
|
* 코어 루트 (artisan / .env / Playwright 산출물의 기준 경로).
|
|
*
|
|
* 확장 config 는 확장 디렉토리에서 실행되지만, 산출물을 그 안에 쓰면 Windows 에서
|
|
* `plugin:update` 의 디렉토리 이동이 열린 핸들에 걸려 실패한다.
|
|
* 산출물은 코어 루트 아래로 모아 update 경로와 분리한다 (.gitignore 가 이미 덮는 위치).
|
|
*/
|
|
const CORE_ROOT = process.env.G7_ROOT || resolve(__dirname, '../../../../../');
|
|
|
|
/** 확장별 산출물 격리 — 확장끼리 리포트를 덮어쓰지 않도록 slug 로 네임스페이스. */
|
|
const ARTIFACT_SLUG = 'plugins/sirsoft-pay_kginicis';
|
|
|
|
function readEnvFile(filePath: string, key: string): string | null {
|
|
if (!existsSync(filePath)) return null;
|
|
const content = readFileSync(filePath, { encoding: 'utf-8' });
|
|
const pattern = new RegExp(`^${key}=(.*)$`, 'm');
|
|
const match = content.match(pattern);
|
|
if (!match) return null;
|
|
let value = match[1].trim();
|
|
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
value = value.slice(1, -1);
|
|
}
|
|
return value || null;
|
|
}
|
|
|
|
function resolveBaseUrl(): string {
|
|
if (process.env.PLAYWRIGHT_BASE_URL) {
|
|
return process.env.PLAYWRIGHT_BASE_URL;
|
|
}
|
|
const appUrl = readEnvFile(resolve(CORE_ROOT, '.env'), 'APP_URL');
|
|
if (appUrl && !/^https?:\/\/localhost(:\d+)?\/?$/i.test(appUrl)) {
|
|
return appUrl;
|
|
}
|
|
throw new Error(
|
|
'KG이니시스 플러그인 E2E base URL 미설정. PLAYWRIGHT_BASE_URL 환경변수를 지정하거나 코어 .env 의 APP_URL 을 활성 호스트로 설정하세요.'
|
|
);
|
|
}
|
|
|
|
export default defineConfig({
|
|
testDir: './specs',
|
|
outputDir: resolve(CORE_ROOT, 'test-results', ARTIFACT_SLUG),
|
|
fullyParallel: true,
|
|
forbidOnly: !!process.env.CI,
|
|
retries: process.env.CI ? 2 : 0,
|
|
workers: process.env.CI ? 1 : undefined,
|
|
reporter: [
|
|
['html', { outputFolder: resolve(CORE_ROOT, 'playwright-report', ARTIFACT_SLUG), open: 'never' }],
|
|
['list'],
|
|
],
|
|
use: {
|
|
// 실제 브라우저 UA 를 지정한다.
|
|
//
|
|
// Playwright 기본 UA 에는 `HeadlessChrome` 이 들어 있어 `SeoMiddleware` 의 봇 판정에
|
|
// 걸린다. 그러면 공개 사용자 경로 요청이 SPA 가 아니라 **검색엔진용 정적 HTML** 을
|
|
// 받는다 — `window.G7Core` 도 엔진 스크립트도 없는 화면이다. 그 상태에서도 서버가
|
|
// 심은 글꼴·아이콘은 정상이라 "페이지가 잘 뜬다" 로 보이고, 정작 재려던 SPA 동작
|
|
// (테마 적용·핸들러·확장 번들 로드)은 한 번도 실행되지 않은 채 통과한다.
|
|
//
|
|
// 봇 경로를 의도적으로 재는 spec 은 UA 가 아니라 `?_escaped_fragment_=` 로 유발하므로
|
|
// 여기서 실제 UA 를 고정해도 그 검증은 그대로 동작한다.
|
|
userAgent:
|
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
|
|
baseURL: resolveBaseUrl(),
|
|
// spec 이 한국어 화면 문구를 단언하므로 로케일을 고정한다.
|
|
// 로케일 우선순위는 localStorage g7_locale → 서버 응답값 → 'ko' 이고, 서버값은 미인증
|
|
// 요청에서 Accept-Language 로 결정된다(SetLocale 미들웨어). Playwright 의 locale 옵션이
|
|
// 그 헤더를 만들므로, 지정하지 않으면 첫 페이지 로드가 en-US 로 나가 화면이 영어로 렌더되고
|
|
// 엔진이 그 값을 localStorage 에 저장해 이후 인증해도 세션 전체가 영어로 고정된다.
|
|
locale: 'ko-KR',
|
|
trace: 'retain-on-failure',
|
|
screenshot: 'only-on-failure',
|
|
ignoreHTTPSErrors: true,
|
|
},
|
|
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
|
|
});
|