76 lines
9.2 KiB
Markdown
76 lines
9.2 KiB
Markdown
# 2026-09-22 출시 준비 상태 검증
|
||
|
||
**판정: 현재 산출물 그대로 라이브 출시 보류(NO-GO).** 기본 동작과 빌드는 통과했으나 운영 설정 패키징 결함이 재현됐고, 신규 DB 초기화·운영 환경 검증이 남아 있다. 검증 대상은 `feat/v2`의 `184839434c94d500cdf6e74ae77b4b4c658dcc4c`이다. 코드 수정·운영 배포·원격 push는 수행하지 않았다.
|
||
|
||
**후속 최신 취약점 확인:** [최신 의존성 권고 대조](./2026-09-22-current-dependency-advisories.md)에서 배포 구성요소 6종의 영향 버전 포함을 확인했다. 아래 캐시 기반 0건은 당시 실행 기록이며 현재 출시 승인 근거로 사용할 수 없다.
|
||
|
||
ATP Tier B 순차 self-check로 수행했다. 독립 advisor 검토 또는 전체 보안 감사 결과가 아니다. [세션과 증거](../../.atp/work-session/20260922-114058/report.md).
|
||
|
||
## 실행 결과
|
||
|
||
| 검증 | 결과 | 실제 검증 범위 |
|
||
| --- | --- | --- |
|
||
| 전체 테스트 + 실행형 live WAR | PASS | JDK 21 컨테이너의 독립 HEAD 복사본에서 `mvn -o -B -P live test package spring-boot:repackage`; 362 tests, failure/error/skip 0 |
|
||
| live WAR 기동 | PASS | 독립 PostgreSQL 16 + `db/schema.sql`, live 프로필, DB search_path는 테스트용 dev; 운영 DB 검증 아님 |
|
||
| 공개 화면 브라우저 | PASS | 개발 인스턴스의 `/`, `/posts`, `/recruit`, `/jams`, `/login`, `/signup`, `/terms`, `/operation-policy` × 폭 1440/390 = 16회. 응답 200, JS 예외·실패 리소스·가로 넘침 0 |
|
||
| HTTP 기능 흐름 | PASS | 독립 live WAR에서 회원가입/로그인/로그아웃, 세션 ID 교체, 프로필, 모집글 생성·상세의 저장한 제목 출력 |
|
||
| 인증·CSRF 일부 계약 | PASS | 회원가입/로그인/모집글의 토큰 없는 POST 403, 토큰 있는 정상 요청 200, 일반 계정 `/posts/new` 403, 로그아웃 후 프로필 접근 리다이렉트 |
|
||
| DB 확인 | 부분 PASS | 기존 dev의 좋아요 UNIQUE 제약·카테고리 5종 확인. 신규 DB 카테고리는 아래 실패 |
|
||
| 의존성 스캔 | 제한적 PASS | `mvn -B dependency-check:check`: 50개(40 unique), 탐지 취약점 0. 캐시 갱신 꺼짐, 최신성 미검증, OSS Index 인증 없어 제외, provided scope 제외 |
|
||
| 실제 운영 배포 게이트 | 미수행 | 운영 URL·접근 환경·배포 절차·실제 Unity 빌드가 지정되지 않음 |
|
||
|
||
호스트 Java 미설치로 `./mvnw -o test`는 실행하지 못해 기존 Maven/JDK 컨테이너의 별도 디렉터리에서 실행했다. 개발 인스턴스의 컴파일 디렉터리는 변경하지 않았다. 의존성 플러그인은 Maven offline 모드를 거부하여 일반 실행으로 재검증했다. 위 테스트는 실 DB 매퍼 전체·전체 권한 조합·부하·장애복구를 보장하지 않는다.
|
||
|
||
## 수정 또는 배포 전 해소가 필요한 항목
|
||
|
||
### R1 — P1: live 설정 파일이 WAR에서 제외됨
|
||
|
||
- 근거: `pom.xml:278`에서 `application-*.properties`를 제외한다. dev에도 `pom.xml:241`의 같은 제외 규칙이 있다.
|
||
- `src/main/resources/application-live.properties:3`의 `server.servlet.session.cookie.secure=true`가 산출물에 포함되지 않는다.
|
||
- 실제 live WAR에는 `WEB-INF/classes/application.properties`만 있고 `application-live.properties`가 없다. 기본 파일의 active profile은 `live`임을 확인했다.
|
||
- 독립 WAR 런타임에서 익명 세션과 로그인 후 모두 `JSESSIONID; Path=/; HttpOnly; SameSite=Lax`이며 `Secure`가 없었다. HTTP 시험이므로 운영 TLS/프록시의 쿠키 정책을 추정하지 않는다. 확인된 결함은 명시한 Secure 강제 설정이 패키징에서 사라진다는 점이다.
|
||
- 조치: 프로필 설정 리소스를 포함하도록 빌드를 수정하고, 실제 배포 산출물과 운영 HTTPS 응답의 쿠키 속성을 함께 검증한다. WAR 엔트리/실행 프로필/쿠키 속성 회귀 검증이 필요하다.
|
||
|
||
### R2 — P1: 배포 이미지 경로가 dev 프로필로 고정됨
|
||
|
||
- 근거: `Dockerfile:30`은 `mvn -B -P dev ...`로 빌드한다. `docker-compose.yml`에는 live 프로필 강제 설정이 없다.
|
||
- 문서는 base compose를 배포 이미지 경로로 안내하지만, 현재 그 경로는 기본적으로 dev 프로필 산출물이다. 개발용 compose 자체는 결함이 아니며, 이를 그대로 라이브 배포 경로로 쓰는 것이 문제다.
|
||
- 조치: 운영 빌드/실행 프로필과 DB search_path를 명시한 별도 배포 구성을 확정하고, 그 실제 이미지로 재검증한다. 이번 live WAR 직접 실행은 Dockerfile 이미지 검증을 대체하지 않는다.
|
||
|
||
### R3 — P1: 새 DB 초기화에 기본 포스트 카테고리 시드가 빠짐
|
||
|
||
- 근거: `docker-compose.yml:22`는 `db/schema.sql`만 초기 적용한다. `db/apply-local-ddl.sh:46`의 기본 대상은 `docs/*-ddl.sql`이므로 `db/migrations/20260724-post-categories-seed.sql`이 포함되지 않는다.
|
||
- 실측: 기존 dev 카테고리는 `notice/devlog/showcase/resources/industry` 5종, 새 PostgreSQL에 schema.sql만 적용하면 0종이다. 새 환경에서는 카테고리 탭이 기존 결과물과 다르게 나온다.
|
||
- 조치: 신규 설치와 기존 DB 업그레이드 양쪽의 migration 목록·실행 순서·적용 확인 절차에 이 시드를 포함한다. 좋아요 UNIQUE도 운영 DB에서 별도 확인한다. 로컬 적용 사실을 운영 적용 증거로 사용하지 않는다.
|
||
|
||
### R4 — P2: 잘못된 입력/없는 정적 리소스를 500으로 처리함
|
||
|
||
- 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/ApiExceptionControllerAdvice.java:38`의 전역 `Exception` 핸들러가 기본 예외를 500으로 변환한다.
|
||
- 독립 live WAR 재현: `/posts?categoryId=abc`, `/posts?categoryId=9223372036854775808`, `/css/readiness-missing.css`가 모두 500. 앞의 두 요청은 입력 오류, 마지막 요청은 리소스 부재다.
|
||
- 조치: 입력 변환 오류는 400, 없는 리소스는 404로 보존하도록 구체적인 예외 처리를 적용하고 회귀 테스트를 추가한다. 정상 브라우저 16회에서 실제 참조 리소스 실패는 없었다.
|
||
|
||
### R5 — P2: 모집글 작성의 CSRF 폴백 미완료
|
||
|
||
- 근거: `src/main/webapp/WEB-INF/views/recruit-form.jsp:403` 이후 JS helper 미존재 분기는 CSRF 헤더 없이 전송하며 hidden `_csrf`도 없다.
|
||
- 서버는 `RecruitController.java:65` 이후 검증으로 토큰 없는 요청을 403 처리한다. **CSRF 우회가 아니라 helper/JS 장애 시 정상 작성도 거부되는 폴백 가용성 문제**다. 정상 helper 경로의 모집글 저장·조회는 이번에 통과했다.
|
||
- 조치: hidden 토큰과 fetch 폴백을 보완하고 정상/폴백/토큰 누락의 동작을 각각 확인한다.
|
||
|
||
## 라이브 승인에 필요한 추가 증거
|
||
|
||
1. R1~R3 해소 후 **실제 배포 이미지**를 staging에서 실행해 프로필·운영 HTTPS 쿠키·DB migrations를 확인한다.
|
||
2. 실제 Unity WebGL 빌드 업로드 → 실행 → 교체 → 소유권 거부, 좋아요·리뷰·배지, 잼 참가·심사·투표·시상, 운영자 포스팅의 전체 시나리오를 검증한다. 이번 HTTP 검증은 이 흐름들을 포함하지 않는다.
|
||
3. [배포 후 체크리스트](../maintenance/post-deploy-verification-checklist.md)의 실 HTTPS 외부 fetch·피드 폴링·자산 경로·DNS TTL을 실제 환경에서 완료한다.
|
||
4. 의존성 DB를 갱신한 스캔 결과와 제외된 런타임 의존성 범위를 확인한다. 이번 0건 결과를 최신 CVE 안전 판정으로 쓰지 않는다.
|
||
5. DB/업로드 백업의 복구, 배포 rollback, 오류·디스크·업로드 제한 모니터링, 예상 트래픽의 부하 검증 결과를 확보한다. 저장소만으로 운영 준비 완료를 판정할 수 없다.
|
||
|
||
R4/R5는 함께 보완하는 것이 좋다. 우선순위는 운영 프로필과 설정 패키징 → DB 초기화/업그레이드 재현 → 핵심 사용자 E2E 및 운영 증거다. 현재는 staging 검증을 진행할 수 있는 상태이며 라이브 출시 승인 상태는 아니다.
|
||
|
||
## 증거와 한계
|
||
|
||
- [빌드 로그](../../.atp/work-session/20260922-114058/artifacts/build.log): 컴파일 WARNING 200줄(중복 포함, 주로 MockBean deprecation), ERROR 0. 테스트 실패 없음.
|
||
- [브라우저 결과](../../.atp/work-session/20260922-114058/artifacts/browser.json), [모바일 홈](../../.atp/work-session/20260922-114058/artifacts/home-390.png), [포스트 화면](../../.atp/work-session/20260922-114058/artifacts/posts-1440.png).
|
||
- [live WAR HTTP](../../.atp/work-session/20260922-114058/artifacts/live-http.json), [인증·작성 흐름](../../.atp/work-session/20260922-114058/artifacts/flow.json), [경계 입력](../../.atp/work-session/20260922-114058/artifacts/edge.json).
|
||
- `edge.json`의 없는 post/recruit/jam 항목 200은 목록 리다이렉트를 따라간 최종 응답이다. 해당 컨트롤러의 의도한 리다이렉트이며 새 결함으로 판정하지 않았다.
|
||
- [의존성 스캔 로그](../../.atp/work-session/20260922-114058/artifacts/dependencies.log), [검증 WAR 해시](../../.atp/work-session/20260922-114058/artifacts/war.sha256).
|
||
- 기존 graph는 7월 소스 기준이며 JSP가 누락되는 한계가 있다. 탐색 보조로만 사용하고 모든 발견은 현재 소스와 실행 결과로 대조했다.
|