Skip to content

fix: 콜백 주소 기본값을 없애고 필수 설정 누락을 기동 시 막음(N-6) - #100

Merged
kimwuju merged 3 commits into
mainfrom
fix/callback-url-config
Oct 15, 2026
Merged

kimwuju merged 3 commits into
mainfrom
fix/callback-url-config

Conversation

@kimwuju

@kimwuju kimwuju commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

개요

A-1 N-6 "콜백 주소 기본값 제거 및 운영 기동 검증"입니다. main(bd6663e) 기준입니다. 스키마 변경은 없습니다.

  • 문제
    • app.callback-base-url의 기본값이 개발자 ngrok 주소(https://wildcat-startle-rope.ngrok-free.dev)였습니다.
    • 그래서 운영에서 CALLBACK_BASE_URL을 빠뜨려도 서버가 떴고, 분석·채팅 서버의 결과가 그 주소로 갔습니다.
    • 접수는 202로 정상처럼 보이고, 실패는 몇 분 뒤 시간 초과로만 드러났습니다.
  • 해결: 기본값을 없애고, 빠졌거나 잘못된 설정은 기동 단계에서 막습니다(RequiredSettingsCheck). 블루/그린 배포라 새 서버가 뜨지 않으면 이전 서버가 그대로 남습니다.

변경

1. 콜백 주소 (app.callback-base-url = CALLBACK_BASE_URL)

  • 기본값을 없앴습니다(${CALLBACK_BASE_URL:}).
  • 항상 확인하는 것: 비어 있지 않음, http/https, 호스트가 있음, 사용자 정보·쿼리·조각·끝 슬래시가 없음.
    • 끝 슬래시를 막는 이유: 뒤에 붙는 콜백 경로와 합쳐져 //api/...가 되고, 시큐리티 방화벽이 콜백을 모두 400으로 막습니다.
  • prod 프로필에서만 확인하는 것: https만 받고, 포트는 생략하거나 443이어야 합니다(분석 서버와 CallbackUrls.require()가 다른 포트를 거부합니다). ngrok·localhost·*.localhost·127.x·[::1]·0.0.0.0도 받지 않습니다.
  • 구문만 봅니다. 외부 서버가 잠깐 멈췄다고 기동을 막지 않도록 네트워크 연결 검사는 하지 않습니다.

2. 내부 인증 필수 (app.internal-auth.required = INTERNAL_AUTH_REQUIRED, 신규, 기본 false)

  • true인데 INTERNAL_AUTH_TOKEN이 비어 있으면 기동이 실패합니다. 비어 있는 채로 "인증 없이 받기"로 조용히 돌아가는 것을 막습니다.
  • 기존 내부 인증 동작(InternalCallbackAuthInterceptor)은 그대로입니다. 오류 메시지에 인증값을 싣지 않습니다.
  • 기본값을 true로 바꾸지 않았습니다. 운영 활성화는 배포 절차로 분리합니다(아래).

3. 테스트 설정 (src/test/resources/config/application.yaml, 신규)

  • 콜백 주소를 https://api.repit.test로 명시합니다.
  • classpath:/config/ 파일이라 기본 application.yaml 위에 겹쳐 읽히고, 로컬 .env 값보다 우선합니다(확인함). 그래서 CI(test.yml)는 바꾸지 않았습니다.

설정 변경 목록

변수 이전 이후 예시
CALLBACK_BASE_URL 선택(기본 ngrok 주소) 필수. 비었거나 형식이 틀리면 기동 실패 https://api.repit.example (끝 슬래시 없음)
INTERNAL_AUTH_REQUIRED 없음 신규, 기본 false true (토큰 필수)
SPRING_PROFILES_ACTIVE 쓰지 않음 prod면 운영 주소 검사(https, 포트 생략·443, 개발용 주소 금지) prod

명세는 INTERNAL_AUTH_REQUIRED와 운영 프로필이 이미 있다고 가정했습니다. 레포에는 둘 다 없었습니다(Dockerfile은 java -jar만 실행). 그래서 위처럼 새로 정했습니다.

배포 (N-6 활성화 절차)

  1. 이 PR을 배포하기 전에 운영 env에 CALLBACK_BASE_URL이 들어 있는지 확인합니다. 없으면 새 서버가 뜨지 않습니다.
  2. 운영 주소 검사를 쓰려면 운영 env에 SPRING_PROFILES_ACTIVE=prod를 넣습니다. 넣지 않으면 필수·형식 검사만 합니다.
  3. INTERNAL_AUTH_REQUIRED=true는 마지막에 켭니다. Chat·Analysis가 X-Internal-Token 헤더를 실제로 보내도록 배포를 마치고, INTERNAL_AUTH_TOKEN을 채운 뒤입니다.
  4. 로컬 개발은 .env의 CALLBACK_BASE_URL(ngrok 등)을 그대로 씁니다. 프로필이 prod가 아니면 개발용 주소를 받습니다.

테스트

  • ./gradlew test 전체 640개가 통과했습니다.
  • RequiredSettingsCheckTest(신규, ApplicationContextRunner로 실제 기동 판정)
    • 콜백 주소가 없거나 비면 기동 실패하고, 메시지로 CALLBACK_BASE_URL을 짚습니다.
    • 형식이 틀린 주소 8가지(스킴 없음, ftp, 호스트 없음, 사용자 정보, 쿼리, 조각, 끝 슬래시, 공백)를 막습니다.
    • 운영이 아니면 ngrok·localhost를 받습니다.
    • 운영(prod)에서는 ngrok·loopback·http·기본이 아닌 포트(:8443)를 막고, 정상 https 주소(포트 생략, :443)면 기동합니다.
    • 내부 인증 필수인데 인증값이 없으면 기동 실패합니다. 필수가 아니면 인증값 없이도 기동합니다.

🤖 Generated with Claude Code

app.callback-base-url의 기본값이 개발자 ngrok 주소라, 운영에서 CALLBACK_BASE_URL을 빠뜨려도 서버가 떠서
분석·채팅 서버의 결과가 그 주소로 갔다. 접수는 202로 정상처럼 보이고 실패는 시간 초과로만 드러났다.

- callback-base-url 기본값 제거. 비었거나 형식이 틀리면(http/https 아님, 호스트 없음, 사용자 정보·쿼리·조각·끝 슬래시)
  기동 실패. 끝 슬래시는 "//api/..."가 되어 콜백이 모두 400으로 막힌다
- prod 프로필이면 https만 받고 ngrok·localhost·loopback 주소를 받지 않는다. 네트워크 연결 검사는 하지 않는다
- INTERNAL_AUTH_REQUIRED(app.internal-auth.required, 기본 false) 추가. true인데 INTERNAL_AUTH_TOKEN이 비면 기동 실패.
  기존 내부 인증 동작은 그대로이고, 오류 메시지에 인증값을 싣지 않는다
- 테스트는 src/test/resources/config/application.yaml에서 콜백 주소를 명시적으로 채운다

운영 env에 CALLBACK_BASE_URL이 반드시 있어야 한다. prod 검사를 쓰려면 SPRING_PROFILES_ACTIVE=prod를 넣는다.
INTERNAL_AUTH_REQUIRED=true는 Chat·Analysis가 헤더를 보내는 배포를 마친 뒤 마지막에 켠다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@danjee2009 danjee2009 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

검토 범위: 기동 시 콜백 URL과 내부 인증 설정 검증, 관련 설정 테스트를 확인했습니다. GitHub 테스트 체크는 통과했습니다.

Comment thread src/main/java/repit/repit_api_server/global/config/RequiredSettingsCheck.java Outdated
사용자 정보·쿼리가 붙은 주소를 막는 검사인데 오류 메시지에 원문을 넣어, 그 안의 자격 증명이 기동 실패 로그에
그대로 남을 수 있었다(PR #100 리뷰). 검증 항목과 호스트만 싣는다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@2-dayeon

Copy link
Copy Markdown
Contributor

[P2] 기동 시 콜백 포트도 실제 요청 코드와 동일하게 검증해야 합니다. — RequiredSettingsCheck.java:60
현재 https://api.example.com:8443은 운영 기동 검증을 통과합니다. 하지만 음성·영상 분석이 사용하는 CallbackUrls.require()는 포트 생략 또는 443만 허용하므로, 실제 분석 요청은 422로 실패합니다.
잘못된 설정을 배포 때 차단하려는 목적에 맞게 기동 검증에도 같은 포트 제한을 적용하고, :443 통과·:8443 거부 테스트를 추가하면 됩니다.

음성·영상 분석 요청의 CallbackUrls.require()는 포트를 생략했거나 443인 주소만 받는데, 기동 검사는
https://api.example.com:8443을 통과시켜 실제 분석 요청이 422로 실패할 수 있었다(PR #100 리뷰).
prod 프로필 검사에 같은 포트 제한을 넣는다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kimwuju
kimwuju merged commit 5c73279 into main Oct 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants