Skip to content

Conversation

@coli-geonwoo
Copy link
Collaborator

@coli-geonwoo coli-geonwoo commented Sep 14, 2025

🚩 연관 이슈

closd #92

🔂 변경 내역

Summary by CodeRabbit

  • 신규 기능
    • 깃허브 403(권한 없음) 응답을 명시적으로 처리하여 권한 부족 시 사용자 친화적 오류 메시지를 제공합니다.
  • 버그 수정
    • 저장/웹훅 생성 과정에서 발생하는 403/404 응답을 일관되게 처리해 오류 안내 신뢰성을 높였습니다.
  • 테스트
    • 403(권한 없음), 404(리소스 없음) 시나리오에 대한 단위 테스트를 추가하여 오류 처리 동작을 검증했습니다.

@coderabbitai
Copy link

coderabbitai bot commented Sep 14, 2025

Walkthrough

GitHub 403 Forbidden을 전파·처리하기 위해 예외 GithubForbiddenException을 추가하고, GitHub 클라이언트 필터와 RepositoryFacadeService.save에서 403을 404와 동일하게 매핑하도록 예외 처리 분기와 테스트를 확장했습니다.

Changes

Cohort / File(s) Summary
New exception type
gss-client/gss-github-client/src/main/java/com/devoops/exception/GithubForbiddenException.java
새 런타임 예외 GithubForbiddenException 추가(문자열 메시지 생성자).
GitHub client error mapping
gss-client/gss-github-client/src/main/java/com/devoops/client/GithubExchangeFilterFunction.java
HTTP 403 응답 시 GithubForbiddenException을 명시적으로 throw. 기존 404→GithubNotFoundException, 기타→GssException 매핑은 유지.
Facade save error handling
gss-api-app/src/main/java/com/devoops/service/facade/RepositoryFacadeService.java
save에서 GithubNotFoundException 단일 catch를 404/403 동시 처리(multi-catch)로 확장하여 둘 다 REGISTRY_GITHUB_REPOSITORY_NOT_FOUND로 매핑.
Tests for 403/404
gss-api-app/src/test/java/com/devoops/service/facade/RepositoryFacadeServiceTest.java
404/403 시나리오 테스트 추가 및 헬퍼 메서드 개선(예외 주입형). 403은 GithubForbiddenException 사용.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant S as RepositoryFacadeService
  participant G as GithubClient/Webhook API
  participant E as Exception Mapper

  S->>G: createWebhook(repo)
  alt Success (2xx)
    G-->>S: Webhook created
    S-->>S: 저장 및 이벤트 발행
  else 404 Not Found
    G-->>S: throw GithubNotFoundException
    S->>E: map to GssException(REGISTRY_GITHUB_REPOSITORY_NOT_FOUND)
    E-->>S: GssException
  else 403 Forbidden
    G-->>S: throw GithubForbiddenException
    S->>E: map to GssException(REGISTRY_GITHUB_REPOSITORY_NOT_FOUND)
    E-->>S: GssException
  else Other errors
    G-->>S: throw GssException(GITHUB_CLIENT_ERROR)
  end
Loading
sequenceDiagram
  autonumber
  participant C as GithubExchangeFilterFunction
  participant GH as GitHub API

  C->>GH: HTTP request
  GH-->>C: HTTP response
  alt 404
    C-->>C: throw GithubNotFoundException
  else 403
    C-->>C: throw GithubForbiddenException
  else Other error (4xx/5xx)
    C-->>C: throw GssException(GITHUB_CLIENT_ERROR)
  else 2xx
    C-->>C: proceed
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning PR 설명은 템플릿의 섹션 제목을 포함하나 내용이 불완전합니다; "closd #92"의 오타로 이슈 참조가 명확하지 않고 '# 🔂 변경 내역'이 비어 있어 변경 사항의 세부 내용과 영향(예: 403 처리 추가, GithubForbiddenException 클래스 추가, 테스트 변경 등)이 누락되어 리뷰어가 변경 범위를 파악하기 어렵습니다. 'closd #92'를 'closes #92' 또는 적절한 이슈 참조로 수정하고 '# 🔂 변경 내역' 섹션에 변경된 파일과 핵심 변경 요약(403 처리 추가, 예외 매핑 변경, 테스트 추가 등), 테스트 결과 및 배포/런타임 영향(마이그레이션·설정 변경 여부)을 간단히 기재하여 설명을 보완해 주세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed 제목은 PR의 핵심 변경사항인 "레포 등록 시 깃허브 웹훅 등록 과정에서 403 에러를 애플리케이션 에러로 전환"을 정확히 요약하고 있어 변경 내용과 일치합니다. 다만 접두사 '[REFACOTR]'에 오타(REFACOTR → REFACTOR)가 있어 가독성 및 일관성 측면에서 수정이 권장됩니다.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/#92-github-403-error

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

Test Results

0 tests   0 ✅  0s ⏱️
0 suites  0 💤
0 files    0 ❌

Results for commit 296d29f.

@github-actions
Copy link

📝 Test Coverage Report

Overall Project NaN% NaN% 🍏

There is no coverage information present for the Files changed

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (7)
gss-client/gss-github-client/src/main/java/com/devoops/exception/GithubForbiddenException.java (1)

3-8: 예외 생성자/직렬화 ID 보강 제안

원인 추적과 직렬화 안전성을 위해 cause 생성자와 serialVersionUID 추가를 권장합니다.

 public class GithubForbiddenException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
 
     public GithubForbiddenException(String message) {
         super(message);
     }
+
+    public GithubForbiddenException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }
gss-client/gss-github-client/src/main/java/com/devoops/client/GithubExchangeFilterFunction.java (2)

34-36: 403 분기: HttpStatus 사용 및 문구/마침표 통일

가독성/일관성을 위해 HttpStatus.FORBIDDEN을 사용하고, 안내 문구를 자연스러운 표현으로 마침표까지 통일해주세요.

-                            if(response.statusCode().isSameCodeAs(HttpStatusCode.valueOf(403))) {
-                                return Mono.error(new GithubForbiddenException("깃허브 자원의 접근 권한이 없습니다"));
+                            if (response.statusCode().isSameCodeAs(HttpStatus.FORBIDDEN)) {
+                                return Mono.error(new GithubForbiddenException("깃허브 자원에 대한 접근 권한이 없습니다."));
                             }

추가(파일 상단 import):

import org.springframework.http.HttpStatus;

25-31: 오류 본문/URL 전체 로깅은 민감정보 및 과다 로그 위험

에러 시 응답 본문 전체와 URL 전체를 그대로 남기면 토큰/개인정보 노출 및 로그 폭증 위험이 있습니다. 경로만 로그하고 본문은 길이 제한/마스킹을 권장합니다.

예시:

-                            log.error("GitHub API Error: {}", Map.of(
-                                    "method", request.method(),
-                                    "url", request.url(),
-                                    "status", response.statusCode(),
-                                    "response", body
-                            ));
+                            String responseSnippet = body.length() > 1024 ? body.substring(0, 1024) + "..." : body;
+                            log.error("GitHub API Error: {}", Map.of(
+                                    "method", request.method(),
+                                    "urlPath", request.url().getPath(),
+                                    "status", response.statusCode().value(),
+                                    "responseSnippet", responseSnippet
+                            ));
gss-api-app/src/main/java/com/devoops/service/facade/RepositoryFacadeService.java (1)

46-48: 403→NOT_FOUND 매핑 정책 확인 및 원인 로깅 추가 제안

403을 404와 동일한 애플리케이션 에러로 매핑하는 요구사항이 맞는지 확인 부탁드립니다. 또한 디버깅을 위해 원인 로그를 남기는 편이 좋습니다.

@@
-        } catch (GithubNotFoundException | GithubForbiddenException githubException) {
-            throw new GssException(ErrorCode.REGISTRY_GITHUB_REPOSITORY_NOT_FOUND);
+        } catch (GithubNotFoundException | GithubForbiddenException githubException) {
+            log.warn("GitHub webhook 등록 실패로 등록 롤백: {}", githubException.getMessage(), githubException);
+            throw new GssException(ErrorCode.REGISTRY_GITHUB_REPOSITORY_NOT_FOUND);
         }

추가(파일 상단):

+import lombok.extern.slf4j.Slf4j;
@@
-@Service
+@Service
+@Slf4j
 @RequiredArgsConstructor
 public class RepositoryFacadeService {

가능하다면 GssException이 cause를 받는 생성자를 제공/사용해 원인 체인을 보존해주세요.

gss-api-app/src/test/java/com/devoops/service/facade/RepositoryFacadeServiceTest.java (3)

63-71: 상호작용 검증 추가로 테스트 안정성 강화

예외 매핑만 검증 중입니다. 클라이언트 호출이 의도대로 1회 시도됐는지도 함께 검증하면 회귀를 잡는 데 유익합니다.

         assertThatThrownBy(() -> repositoryFacadeService.save(request, user))
                 .isInstanceOf(GssException.class)
                 .hasMessage(ErrorCode.REGISTRY_GITHUB_REPOSITORY_NOT_FOUND.getMessage());
+
+        Mockito.verify(gitHubClient, times(1)).getRepositoryInfo(any(), any(), any());
+        Mockito.verify(gitHubClient, times(1)).createWebhook(any(), any(), any(), any());

73-82: 403 시나리오도 동일하게 상호작용 검증

403 케이스에도 동일한 호출 수 검증을 추가해 주세요.

         assertThatThrownBy(() -> repositoryFacadeService.save(request, user))
                 .isInstanceOf(GssException.class)
                 .hasMessage(ErrorCode.REGISTRY_GITHUB_REPOSITORY_NOT_FOUND.getMessage());
+
+        Mockito.verify(gitHubClient, times(1)).getRepositoryInfo(any(), any(), any());
+        Mockito.verify(gitHubClient, times(1)).createWebhook(any(), any(), any(), any());

136-144: 불필요한 지역 변수 제거

mockWebHookCreateResponse가 사용되지 않습니다. 제거해 테스트 노이즈를 줄여주세요.

-            WebHookCreateResponse mockWebHookCreateResponse = new WebHookCreateResponse(123);
             Mockito.when(gitHubClient.getRepositoryInfo(anyString(), anyString(), anyString()))
                     .thenReturn(mockResponse);
             Mockito.when(gitHubClient.createWebhook(any(), any(), any(), any()))
                     .thenThrow(exception);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f4614c and 296d29f.

📒 Files selected for processing (4)
  • gss-api-app/src/main/java/com/devoops/service/facade/RepositoryFacadeService.java (2 hunks)
  • gss-api-app/src/test/java/com/devoops/service/facade/RepositoryFacadeServiceTest.java (3 hunks)
  • gss-client/gss-github-client/src/main/java/com/devoops/client/GithubExchangeFilterFunction.java (2 hunks)
  • gss-client/gss-github-client/src/main/java/com/devoops/exception/GithubForbiddenException.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
gss-client/gss-github-client/src/main/java/com/devoops/client/GithubExchangeFilterFunction.java (1)
gss-client/gss-github-client/src/main/java/com/devoops/exception/GithubForbiddenException.java (1)
  • GithubForbiddenException (3-8)
gss-api-app/src/main/java/com/devoops/service/facade/RepositoryFacadeService.java (1)
gss-client/gss-github-client/src/main/java/com/devoops/exception/GithubForbiddenException.java (1)
  • GithubForbiddenException (3-8)
gss-api-app/src/test/java/com/devoops/service/facade/RepositoryFacadeServiceTest.java (1)
gss-client/gss-github-client/src/main/java/com/devoops/exception/GithubForbiddenException.java (1)
  • GithubForbiddenException (3-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push

@coli-geonwoo coli-geonwoo merged commit 0b0b0bd into develop Sep 17, 2025
5 checks passed
@coli-geonwoo coli-geonwoo deleted the chore/#92-github-403-error branch September 17, 2025 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CHORE] 조직 레포 추가 시 Github 403 에러 발생 → 리다이렉트 추가 처리

2 participants