Skip to content

[USER] 유저 정보 API 개선 및 에러 페이지 추가, 권한 정책 반영#65

Merged
usn757 merged 3 commits intoPETTY-HUB:mainfrom
taehyun32:feat/auth
Jun 7, 2025
Merged

[USER] 유저 정보 API 개선 및 에러 페이지 추가, 권한 정책 반영#65
usn757 merged 3 commits intoPETTY-HUB:mainfrom
taehyun32:feat/auth

Conversation

@taehyun32
Copy link
Member

@taehyun32 taehyun32 commented Jun 7, 2025

📜 PR 내용 요약

  • /users/me API에서 사용자 displayName을 반환하도록 개선했습니다.
  • 다양한 엔드포인트에 대한 권한 정책을 세분화하여 보안을 강화하고, API 요청에 대한 인증 오류 응답을 표준화했습니다.
  • 404 에러 페이지를 추가하여 사용자 경험을 개선했습니다.

⚒️ 작업 및 변경 내용(상세하게)

1. /users/me API 개선

  • UsersApiControllergetUserInfo() 메서드에서 /users/me 엔드포인트 요청 시, 기존에 username으로 반환되던 값을 사용자의 displayName으로 변경하여 반환하도록 수정했습니다.
  • 이는 프론트엔드에서 username 키를 displayName으로 사용하는 현재 상황을 반영하기 위함입니다.
  • 이 변경을 위해 UsersApiController의 생성자에 UsersRepository를 주입받아 사용자의 displayName을 조회하도록 로직을 개선했습니다.

2. 권한 정책 강화 및 인증 오류 응답 개선

  • src/main/java/io/github/petty/config/SecurityConfig.java 파일에서 다양한 API 및 웹 페이지에 대한 접근 권한을 세분화했습니다.
  • 관리자(ADMIN) 역할이 필요한 경로를 명확히 정의했습니다:
    • /admin/**
    • /api/posts/update-counts
    • /manual-sync/**, /embedding-batch/**
  • 인증된 사용자(authenticated)만 접근 가능한 경로를 추가 및 수정했습니다:
    • /profile/**
    • /posts/detail, /posts/*/new, /posts/*/edit
    • POST 요청 시 /api/posts
    • PUT 요청 시 /api/posts/**
    • DELETE 요청 시 /api/posts/**
    • POST 요청 시 /api/posts/{id}/comments
    • PUT 요청 시 /api/comments/**
    • DELETE 요청 시 /api/comments/**
    • POST 요청 시 /api/posts/{id}/like
    • /api/images/**
    • /api/users/me, /api/check-displayname
    • /flow/**
  • 인증 예외 처리(authenticationEntryPoint)를 개선했습니다:
    • /api/로 시작하는 API 요청에 대해 인증이 필요할 경우, 401 Unauthorized 상태 코드와 함께 JSON 형식의 오류 메시지 ({"error": "로그인이 필요합니다"})를 반환하도록 수정했습니다.
    • 그 외 웹 페이지 요청에 대해서는 /login 페이지로 리다이렉트하도록 처리했습니다.

3. 404 에러 페이지 추가

  • src/main/resources/templates/error/404.html 경로에 새로운 404 에러 페이지를 추가했습니다.
  • 해당 페이지는 "페이지를 찾을 수 없습니다"라는 메시지와 함께 사용자에게 친근한 안내를 제공합니다.

📚 기타 참고 사항

  • 궁금한 점이 있으시면 언제든지 물어봐 주세요.

@PETTY-HUB PETTY-HUB deleted a comment from coderabbitai bot Jun 7, 2025
@PETTY-HUB PETTY-HUB deleted a comment from coderabbitai bot Jun 7, 2025
@taehyun32
Copy link
Member Author

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented Jun 7, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 1

🧹 Nitpick comments (4)
src/main/resources/templates/error/404.html (2)

20-24: 그라디언트 텍스트의 브라우저 호환성을 확인하세요.

background-clip: text-webkit-text-fill-color는 모든 브라우저에서 지원되지 않을 수 있습니다. 폴백 스타일을 추가하는 것을 고려해보세요.

 .error-code {
     font-size: 8rem;
     font-weight: bold;
     margin: 0;
+    color: var(--accent-color); /* 폴백 색상 */
     background: linear-gradient(45deg, var(--accent-color), var(--point-color));
     -webkit-background-clip: text;
     -webkit-text-fill-color: transparent;
     background-clip: text;
     text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
 }

79-81: 하드코딩된 색상값을 CSS 변수로 대체하세요.

일관성을 위해 하드코딩된 색상값 #8fa97a를 CSS 변수로 대체하는 것이 좋습니다.

 .btn-secondary:hover {
-    background-color: #8fa97a;
+    background-color: var(--button-secondary-hover-color, #8fa97a);
     transform: translateY(-2px);
 }
src/main/java/io/github/petty/config/SecurityConfig.java (1)

25-25: 사용되지 않는 import를 제거하세요.

LocalDateTime import가 코드에서 사용되지 않고 있습니다.

-import java.time.LocalDateTime;
src/main/java/io/github/petty/users/controller/UsersApiController.java (1)

56-57: TODO 코멘트에 따라 API 응답 구조 개선이 필요합니다.

프론트엔드와의 일관성을 위해 응답 키 이름을 정리하는 것이 좋습니다.

프론트엔드와 협의하여 displayName 키를 사용하도록 API 응답 구조를 개선하는 작업을 도와드릴까요? 이를 위한 이슈를 생성할 수 있습니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 248bab3 and 7505ee1.

📒 Files selected for processing (3)
  • src/main/java/io/github/petty/config/SecurityConfig.java (4 hunks)
  • src/main/java/io/github/petty/users/controller/UsersApiController.java (3 hunks)
  • src/main/resources/templates/error/404.html (1 hunks)
🔇 Additional comments (5)
src/main/resources/templates/error/404.html (2)

1-7: HTML 구조 및 Thymeleaf 통합이 올바르게 구현되었습니다.

404 에러 페이지의 기본 구조가 적절하게 설정되었고, Thymeleaf 레이아웃 시스템과의 통합도 잘 되어 있습니다.

Also applies to: 169-184, 202-204


185-201: JavaScript 애니메이션이 적절하게 구현되었습니다.

DOM 요소 확인과 애니메이션 타이밍이 잘 처리되어 있습니다.

src/main/java/io/github/petty/config/SecurityConfig.java (2)

73-96: 보안 규칙이 적절하게 세분화되었습니다.

역할 기반 접근 제어와 HTTP 메소드별 인증 요구사항이 명확하게 정의되어 있습니다. API 보안이 강화되었습니다.


97-112: API와 웹 요청에 대한 인증 실패 처리가 잘 구현되었습니다.

RESTful API 패턴에 맞게 JSON 응답과 리다이렉트를 구분하여 처리하는 것이 적절합니다.

src/main/java/io/github/petty/users/controller/UsersApiController.java (1)

34-43: 의존성 주입이 올바르게 구현되었습니다.

UsersRepository가 생성자를 통해 적절히 주입되고 있습니다.

Comment on lines +53 to +57
Users user = usersRepository.findByUsername(auth.getName());

Map<String, String> userInfo = new HashMap<>();
userInfo.put("username", auth.getName());
// TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
userInfo.put("username", user.getDisplayName());
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

사용자 조회 시 null 체크가 필요합니다.

usersRepository.findByUsername()이 null을 반환할 수 있으므로 적절한 처리가 필요합니다.

 Users user = usersRepository.findByUsername(auth.getName());
+if (user == null) {
+    return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
+}
 
 Map<String, String> userInfo = new HashMap<>();
 // TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
 userInfo.put("username", user.getDisplayName());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Users user = usersRepository.findByUsername(auth.getName());
Map<String, String> userInfo = new HashMap<>();
userInfo.put("username", auth.getName());
// TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
userInfo.put("username", user.getDisplayName());
Users user = usersRepository.findByUsername(auth.getName());
if (user == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
Map<String, String> userInfo = new HashMap<>();
// TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
userInfo.put("username", user.getDisplayName());
🤖 Prompt for AI Agents
In src/main/java/io/github/petty/users/controller/UsersApiController.java around
lines 53 to 57, the result of usersRepository.findByUsername(auth.getName()) can
be null, which is not currently checked. Add a null check after fetching the
user; if the user is null, handle it appropriately by returning an error
response or throwing an exception to avoid NullPointerException later in the
code.

@coderabbitai
Copy link

coderabbitai bot commented Jun 7, 2025

Summary by CodeRabbit

  • 신규 기능

    • 404 오류 발생 시 표시되는 새로운 404 에러 페이지가 추가되었습니다. 시각적으로 강조된 디자인과 귀여운 일러스트, 친절한 안내 메시지가 포함되어 있습니다.
  • 버그 수정

    • 인증되지 않은 사용자가 API 경로에 접근할 때 JSON 형식의 오류 메시지("로그인이 필요합니다")와 함께 401 상태 코드가 반환됩니다. 웹 경로 접근 시에는 로그인 페이지로 리디렉션됩니다.
  • 기능 개선

    • 게시글, 프로필 등 다양한 경로에 대해 인증 및 권한 기반 접근 제어가 더욱 세분화되었습니다.
    • 사용자 정보 조회 시, "username" 필드가 실제 사용자 이름이 아닌 표시 이름(displayName)으로 반환됩니다.

Walkthrough

이 변경사항은 보안 설정의 경로별 접근 제어를 세분화하고, API 요청에 대해 맞춤형 인증 진입점을 도입했습니다. 사용자 정보 API는 사용자명 대신 displayName을 반환하도록 수정되었으며, 404 에러 페이지에 대한 새로운 HTML 템플릿이 추가되었습니다.

Changes

파일/경로 변경 요약
src/main/java/io/github/petty/config/SecurityConfig.java 경로별 세분화된 권한 부여 규칙 추가 및 API 요청에 대한 맞춤형 인증 진입점 도입
src/main/java/io/github/petty/users/controller/UsersApiController.java UsersRepository 의존성 추가, getUserInfo()에서 displayName 반환으로 변경
src/main/resources/templates/error/404.html 새로운 404 에러 페이지용 Thymeleaf HTML 템플릿 추가

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant SecurityConfig
    participant AuthEntryPoint
    participant UsersApiController
    participant UsersRepository

    Client->>SecurityConfig: 요청 전송 (예: /api/posts/update-counts)
    SecurityConfig->>AuthEntryPoint: 인증 필요 여부 확인
    alt 인증 실패 (API 경로)
        AuthEntryPoint->>Client: 401 + JSON 에러 메시지 반환
    else 인증 실패 (웹 경로)
        AuthEntryPoint->>Client: /login 페이지로 리다이렉트
    end

    Client->>UsersApiController: GET /api/user/info 요청
    UsersApiController->>UsersRepository: 사용자명으로 Users 엔티티 조회
    UsersRepository-->>UsersApiController: Users 엔티티 반환
    UsersApiController-->>Client: displayName 포함 JSON 반환
Loading

Possibly related PRs

Poem

🐰
새로운 경로마다 권한이 달라졌지,
API엔 JSON, 웹엔 리다이렉트까지!
사용자 이름 대신 멋진 displayName,
길 잃은 이들에겐 귀여운 404의 위로.
깡총깡총, 더 안전하고 친절한 서비스로!

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 2

♻️ Duplicate comments (1)
src/main/java/io/github/petty/users/controller/UsersApiController.java (1)

53-57: ⚠️ Potential issue

사용자 조회 시 null 체크가 여전히 누락되었습니다.

usersRepository.findByUsername()이 null을 반환할 수 있으므로 적절한 처리가 필요합니다. 이는 이전 리뷰에서도 지적된 문제입니다.

 Users user = usersRepository.findByUsername(auth.getName());
+if (user == null) {
+    return ResponseEntity.status(HttpStatus.NOT_FOUND)
+            .body(Map.of("error", "사용자 정보를 찾을 수 없습니다."));
+}
 
 Map<String, String> userInfo = new HashMap<>();
 // TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
 userInfo.put("username", user.getDisplayName());
🧹 Nitpick comments (1)
src/main/resources/templates/error/404.html (1)

186-201: 애니메이션 스크립트의 안정성을 개선하세요.

스크립트가 기본적으로 잘 작동하지만, 더 안정적인 구현을 위해 개선할 수 있습니다.

         document.addEventListener('DOMContentLoaded', function() {
             const illustration = document.querySelector('.cute-illustration');
-            if (illustration) {
+            if (illustration && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
                 illustration.style.opacity = '0';
                 illustration.style.transform = 'scale(0.8)';
 
                 setTimeout(() => {
                     illustration.style.transition = 'all 0.5s ease';
                     illustration.style.opacity = '0.8';
                     illustration.style.transform = 'scale(1)';
                 }, 200);
+            } else if (illustration) {
+                // 애니메이션을 선호하지 않는 사용자를 위한 기본 상태
+                illustration.style.opacity = '0.8';
             }
         });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 248bab3 and 7505ee1.

📒 Files selected for processing (3)
  • src/main/java/io/github/petty/config/SecurityConfig.java (4 hunks)
  • src/main/java/io/github/petty/users/controller/UsersApiController.java (3 hunks)
  • src/main/resources/templates/error/404.html (1 hunks)
🔇 Additional comments (5)
src/main/resources/templates/error/404.html (1)

1-6: HTML 구조와 Thymeleaf 설정이 적절합니다.

DOCTYPE, 언어 설정, Thymeleaf 네임스페이스 및 레이아웃 설정이 올바르게 구성되어 있습니다.

src/main/java/io/github/petty/config/SecurityConfig.java (3)

3-3: 필요한 imports가 적절히 추가되었습니다.

새로운 기능 구현을 위한 ObjectMapper, HttpServletResponse, HttpMethod, LocalDateTime, Map imports가 올바르게 추가되었습니다.

Also applies to: 12-12, 15-15, 25-26


74-93: 경로별 권한 설정이 잘 구조화되었습니다.

관리자 전용, 인증 필요, HTTP 메서드별 API 엔드포인트 권한이 논리적으로 잘 분리되어 있습니다. 보안 정책이 명확하고 포괄적입니다.


97-112: 커스텀 인증 진입점이 우수하게 구현되었습니다.

API 요청과 웹 요청을 구분하여 처리하는 로직이 훌륭합니다. API 요청에는 JSON 응답을, 일반 웹 요청에는 리다이렉트를 제공하는 것이 RESTful API 설계 원칙에 부합합니다.

src/main/java/io/github/petty/users/controller/UsersApiController.java (1)

6-8: 새로운 의존성 주입이 적절히 구현되었습니다.

UsersRepository 의존성이 올바르게 추가되고 생성자를 통해 주입되었습니다.

Also applies to: 34-34, 36-36, 42-42

Comment on lines +173 to +180
<div class="error-container">
<div class="error-code">404</div>
<h1 class="error-title">페이지를 찾을 수 없습니다</h1>
<div class="cute-illustration">🐕‍🦺 🔍</div>
<p class="error-message">
앗! 우리 반려동물이 길을 잃었나봐요.<br>
요청하신 페이지를 찾을 수 없습니다.
</p>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

사용자 경험을 개선하기 위한 네비게이션 요소가 누락되었습니다.

에러 메시지는 친근하고 적절하지만, 사용자가 메인 페이지나 이전 페이지로 돌아갈 수 있는 버튼이나 링크가 없습니다. CSS에는 .error-actions와 버튼 스타일이 정의되어 있지만 실제 HTML 요소가 누락되었습니다.

다음과 같이 네비게이션 요소를 추가하는 것을 권장합니다:

             <p class="error-message">
                 앗! 우리 반려동물이 길을 잃었나봐요.<br>
                 요청하신 페이지를 찾을 수 없습니다.
             </p>
+            
+            <div class="error-actions">
+                <a href="/" class="btn btn-primary">홈으로 돌아가기</a>
+                <button onclick="history.back()" class="btn btn-secondary">이전 페이지</button>
+            </div>
         </div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div class="error-container">
<div class="error-code">404</div>
<h1 class="error-title">페이지를 찾을 수 없습니다</h1>
<div class="cute-illustration">🐕‍🦺 🔍</div>
<p class="error-message">
앗! 우리 반려동물이 길을 잃었나봐요.<br>
요청하신 페이지를 찾을 수 없습니다.
</p>
<div class="error-container">
<div class="error-code">404</div>
<h1 class="error-title">페이지를 찾을 수 없습니다</h1>
<div class="cute-illustration">🐕‍🦺 🔍</div>
<p class="error-message">
앗! 우리 반려동물이 길을 잃었나봐요.<br>
요청하신 페이지를 찾을 수 없습니다.
</p>
<div class="error-actions">
<a href="/" class="btn btn-primary">홈으로 돌아가기</a>
<button onclick="history.back()" class="btn btn-secondary">이전 페이지</button>
</div>
</div>
🤖 Prompt for AI Agents
In src/main/resources/templates/error/404.html around lines 173 to 180, the
error page lacks navigation elements for users to return to the main or previous
page. Add a div with class "error-actions" containing buttons or links for
navigation, such as a "Go to Home" button linking to the main page and a "Go
Back" button using JavaScript history.back(). This will improve user experience
by providing clear options to recover from the error.

Comment on lines +56 to +57
// TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
userInfo.put("username", user.getDisplayName());
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

API 응답 구조의 일관성을 개선하세요.

TODO 코멘트에서 언급된 대로 키 이름의 불일치가 있습니다. 프론트엔드와의 계약을 명확히 하고 일관된 네이밍을 사용하는 것이 좋습니다.

다음과 같이 명확한 키 이름을 사용하는 것을 권장합니다:

 Map<String, String> userInfo = new HashMap<>();
-// TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
-userInfo.put("username", user.getDisplayName());
+userInfo.put("displayName", user.getDisplayName());
+userInfo.put("username", user.getUsername()); // 실제 사용자명이 필요한 경우

또는 프론트엔드와 협의하여 API 계약을 명확히 정의하세요.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
userInfo.put("username", user.getDisplayName());
Map<String, String> userInfo = new HashMap<>();
- // TODO: 프론트엔드에서 username 키로 displayName을 사용 중(키 이름 정리 필요)
- userInfo.put("username", user.getDisplayName());
+ userInfo.put("displayName", user.getDisplayName());
+ userInfo.put("username", user.getUsername()); // 실제 사용자명이 필요한 경우
🤖 Prompt for AI Agents
In src/main/java/io/github/petty/users/controller/UsersApiController.java at
lines 56-57, the key "username" is used to store the displayName, causing
inconsistency with the frontend. To fix this, rename the key to "displayName" to
match the actual data or coordinate with the frontend team to agree on a
consistent key name for this field, ensuring the API response structure is clear
and consistent.

@usn757 usn757 merged commit 8c1295a into PETTY-HUB:main Jun 7, 2025
2 checks 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.

2 participants