Skip to content

chore: main 브랜치 변경사항 develop에 동기화#55

Merged
seoyeoki merged 15 commits intodevelopfrom
chore/sync-main-to-develop
Mar 24, 2026
Merged

chore: main 브랜치 변경사항 develop에 동기화#55
seoyeoki merged 15 commits intodevelopfrom
chore/sync-main-to-develop

Conversation

@seoyeoki
Copy link
Copy Markdown
Contributor

@seoyeoki seoyeoki commented Mar 23, 2026

Summary

변경 파일

  • SecurityConfig.java: .anyRequest().authenticated().anyRequest().permitAll() (인증 필요 API는 @PreAuthorize로 개별 관리)
  • README.md: 업데이트
  • docs/convention.md: 신규 추가
  • docs/erd.md: 신규 추가

Test plan

  • 로그인 없이 공개 API 호출 시 200 OK 확인
  • @PreAuthorize 적용된 API는 토큰 없이 401 반환 확인

🤖 Generated with Claude Code

Summary by CodeRabbit

릴리스 노트

  • Chores
    • 애플리케이션 보안 설정을 업데이트했습니다. 인증 처리 메커니즘을 개선하여 보다 유연한 접근 제어가 가능하도록 구성했습니다.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 23, 2026

📝 Walkthrough

개요

Spring Security 인증 규칙이 수정되어, 모든 요청(anyRequest)에 대한 기본 정책이 인증 요구(authenticated)에서 모든 요청 허용(permitAll)으로 변경되었습니다. JWT 필터, CSRF 비활성화, 오류 처리 진입점 등 다른 보안 설정은 유지됩니다.

변경 사항

공통 범주 / 파일 요약
Spring Security 설정
src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.java
anyRequest() 규칙이 authenticated()에서 permitAll()로 변경되었습니다. 보호된 메서드에 대한 접근 제어는 @PreAuthorize를 통해 처리되도록 조정되었으며, 관련 주석이 업데이트되었습니다. JWT 필터 및 다른 보안 설정은 변경되지 않았습니다.

코드 리뷰 예상 소요 시간

🎯 2 (단순) | ⏱️ ~8분

🐰 보안 규칙을 재배열하니,
모두가 드나들 수 있게 문을 열었네.
이제 @PreAuthorize가 경비를 서고,
토끼 굴의 비밀은 더욱 안전해졌어! 🛡️✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning PR 제목은 main 브랜치의 변경사항을 develop에 동기화한다는 내용으로, 실제 변경사항(SecurityConfig 보안 설정 변경, 문서 추가/업데이트)의 핵심을 명확하게 반영하지 못하고 있습니다. 더 구체적인 제목으로 변경하기를 권장합니다. 예: 'chore: SecurityConfig 보안 규칙 변경 및 문서 동기화' 또는 'chore: 기본 인증 정책 변경 및 문서 업데이트'
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/sync-main-to-develop

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.

@seoyeoki seoyeoki self-assigned this Mar 23, 2026
@seoyeoki seoyeoki requested review from Uzrt and seohyun27 March 23, 2026 08:03
Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.java`:
- Around line 55-57: The current SecurityConfig uses anyRequest().permitAll(),
which is a fail-open default that risks accidental exposure; change the policy
to a fail-closed default by replacing anyRequest().permitAll() with
anyRequest().authenticated() (or denyAll() if stricter) and explicitly add
permitAll() matchers for public endpoints such as the existing /health route and
any other intended public APIs; update the configuration in SecurityConfig
(where anyRequest().permitAll() is declared) and ensure JwtFilter and
`@PreAuthorize-protected` endpoints remain functional under the new default.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ef4dd422-9639-4da4-9636-76b723741ca5

📥 Commits

Reviewing files that changed from the base of the PR and between 1d6002c and e3174fc.

⛔ Files ignored due to path filters (3)
  • README.md is excluded by !**/*.md
  • docs/convention.md is excluded by !**/*.md
  • docs/erd.md is excluded by !**/*.md
📒 Files selected for processing (1)
  • src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.java

Comment on lines +55 to +57
// 나머지는 다 인증 불필요
// 인증이 필요한 메소드 위 @PreAuthorize을 붙일 것
.anyRequest().permitAll()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 목적: 컨트롤러 엔드포인트 중 보호 어노테이션 누락 항목 식별 (read-only)
# 해석:
# - 출력된 엔드포인트는 "의도된 공개 API"인지 명시 확인 필요
# - 비공개 의도면 `@PreAuthorize/`@Secured/@RolesAllowed 등 보안 어노테이션 추가 필요

python - <<'PY'
import re
from pathlib import Path

root = Path("src/main/java")
mapping_re = re.compile(r'^\s*@(?:Get|Post|Put|Delete|Patch|Request)Mapping\b')
method_re = re.compile(r'^\s*(public|protected|private)\s+[\w<>\[\], ?]+\s+(\w+)\s*\(')
guard_re = re.compile(r'@PreAuthorize\b|@Secured\b|@RolesAllowed\b|@PermitAll\b')
class_re = re.compile(r'^\s*public\s+class\s+\w+')

for p in root.rglob("*Controller.java"):
    lines = p.read_text(encoding="utf-8").splitlines()
    class_has_guard = False

    for i, line in enumerate(lines):
        if class_re.search(line):
            class_window = "\n".join(lines[max(0, i-20):i+1])
            class_has_guard = bool(guard_re.search(class_window))

        if mapping_re.search(line):
            j = i + 1
            while j < len(lines) and lines[j].strip().startswith("@"):
                j += 1
            if j >= len(lines):
                continue
            m = method_re.search(lines[j])
            if not m:
                continue

            method_window = "\n".join(lines[max(0, i-12):j+1])
            method_has_guard = bool(guard_re.search(method_window))

            if not (class_has_guard or method_has_guard):
                print(f"{p}:{j+1} -> {m.group(2)} (NO_GUARD)")
PY

Repository: wagle-project/wagle-server

Length of output: 181


🏁 Script executed:

# First, let's examine the full SecurityConfig.java to understand the context
cat -n src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.java

Repository: wagle-project/wagle-server

Length of output: 4015


🏁 Script executed:

# Check the HealthController to see if it's intentionally public
cat -n src/main/java/com/waglewagle/server/domain/health/controller/HealthController.java

Repository: wagle-project/wagle-server

Length of output: 542


🏁 Script executed:

# Search for the JWT filter implementation and configuration
find src/main/java -name "*JwtFilter*" -o -name "*Jwt*.java" | grep -i filter | head -5

Repository: wagle-project/wagle-server

Length of output: 140


🏁 Script executed:

# Check if there are `@PreAuthorize` annotations being used elsewhere
rg "@PreAuthorize" src/main/java --type java | head -20

Repository: wagle-project/wagle-server

Length of output: 1374


🏁 Script executed:

# Find all controller endpoints and their protection status
python3 <<'EOF'
import re
from pathlib import Path

root = Path("src/main/java")
mapping_re = re.compile(r'@(?:Get|Post|Put|Delete|Patch|Request)Mapping\(.*?(?:value|path)\s*=\s*"([^"]+)"')
method_re = re.compile(r'public\s+[\w<>\[\], ?]+\s+(\w+)\s*\(')
guard_re = re.compile(r'@PreAuthorize|@Secured|@RolesAllowed|@PermitAll')

results = []
for controller_file in sorted(root.rglob("*Controller.java")):
    content = controller_file.read_text(encoding="utf-8")
    lines = content.splitlines()
    
    for i, line in enumerate(lines):
        # Find mapping annotations
        if '@' in line and ('Mapping' in line or 'RequestMapping' in line):
            # Look for the method definition after the annotations
            j = i + 1
            while j < len(lines) and lines[j].strip().startswith("@"):
                j += 1
            
            if j >= len(lines):
                continue
            
            method_match = method_re.search(lines[j])
            if not method_match:
                continue
                
            method_name = method_match.group(1)
            
            # Check if method has security annotations
            annotation_block = "\n".join(lines[max(0, i-5):j+1])
            has_guard = bool(guard_re.search(annotation_block))
            
            # Extract path
            path_match = mapping_re.search(line)
            path = path_match.group(1) if path_match else "?"
            
            status = "✓ GUARDED" if has_guard else "✗ UNGUARDED"
            results.append(f"{controller_file.name}: {path} -> {method_name} [{status}]")

for r in results:
    print(r)
EOF

Repository: wagle-project/wagle-server

Length of output: 123


🏁 Script executed:

# Now let's examine the JwtFilter to ensure it's properly validating tokens
head -80 src/main/java/com/waglewagle/server/global/security/jwt/JwtFilter.java

Repository: wagle-project/wagle-server

Length of output: 2263


🏁 Script executed:

# Check if there are any `@PostMapping`, `@PutMapping`, `@DeleteMapping` endpoints without protection
rg "/@(?:Post|Put|Delete|Patch)Mapping" src/main/java --type java -A 10 | grep -B 3 -A 7 "public.*\(" | head -100

Repository: wagle-project/wagle-server

Length of output: 93


🏁 Script executed:

# Let me check if there are any other REST endpoints in controllers that we haven't identified
find src/main/java -name "*Controller.java" -type f | wc -l

Repository: wagle-project/wagle-server

Length of output: 71


🏁 Script executed:

# Check all endpoints more carefully - find all methods in controllers
rg "@(GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping|RequestMapping)" src/main/java --type java -B 1 | grep -E "(GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping|RequestMapping|public)" | head -40

Repository: wagle-project/wagle-server

Length of output: 4221


🏁 Script executed:

# Let me check if FestivalController endpoints have `@PreAuthorize` or should they
cat -n src/main/java/com/waglewagle/server/domain/festival/controller/FestivalController.java

Repository: wagle-project/wagle-server

Length of output: 1786


🏁 Script executed:

# Check all endpoints one more time with security status
python3 <<'EOF'
import re
from pathlib import Path

root = Path("src/main/java")

for controller in sorted(root.rglob("*Controller.java")):
    if "Docs" in controller.name:  # Skip docs interfaces
        continue
    
    content = controller.read_text(encoding="utf-8")
    
    # Find all `@XxxMapping` annotations with methods
    pattern = r'@(Get|Post|Put|Delete|Patch)Mapping.*?\n.*?@PreAuthorize.*?\npublic|@(Get|Post|Put|Delete|Patch)Mapping.*?\npublic'
    
    lines = content.splitlines()
    for i, line in enumerate(lines):
        if '@' in line and 'Mapping' in line:
            # Check next 10 lines for method and `@PreAuthorize`
            next_lines = "\n".join(lines[i:min(i+10, len(lines))])
            has_preauth = '@PreAuthorize' in next_lines
            
            method_match = re.search(r'public\s+[\w<>\[\], ?]+\s+(\w+)\s*\(', next_lines)
            if method_match:
                method = method_match.group(1)
                mapping = line.strip()
                status = "✓" if has_preauth else "✗"
                print(f"{status} {controller.name}: {mapping} -> {method}")
EOF

Repository: wagle-project/wagle-server

Length of output: 132


🏁 Script executed:

# Let me verify all unprotected endpoints in detail
python3 <<'EOF'
import re
from pathlib import Path

root = Path("src/main/java/com/waglewagle/server/domain")

print("=== UNPROTECTED ENDPOINTS ===")
for controller in sorted(root.rglob("*Controller.java")):
    if "Docs" in controller.name:
        continue
    
    content = controller.read_text(encoding="utf-8")
    lines = content.splitlines()
    
    class_mapping = ""
    for i, line in enumerate(lines):
        if "@RequestMapping" in line:
            m = re.search(r'@RequestMapping\("([^"]+)"\)', line)
            if m:
                class_mapping = m.group(1)
        
        if re.search(r'@(Get|Post|Put|Delete|Patch)Mapping', line):
            # Get full block
            block = "\n".join(lines[i:min(i+15, len(lines))])
            
            # Extract mapping path
            path_match = re.search(r'@\w+Mapping\("([^"]+)"\)|@\w+Mapping\(\)', line)
            mapping_path = path_match.group(1) if path_match and path_match.group(1) else ""
            full_path = class_mapping + mapping_path
            
            # Check for `@PreAuthorize`
            has_auth = "@PreAuthorize" in block
            
            # Get method name
            method_match = re.search(r'public\s+[\w<>\[\], ?]+\s+(\w+)\s*\(', block)
            if method_match:
                method = method_match.group(1)
                if not has_auth:
                    print(f"  {controller.name}: {full_path} -> {method}")
EOF

Repository: wagle-project/wagle-server

Length of output: 147


🏁 Script executed:

# Check if Festival endpoints are actually meant to be public by checking if they need authentication
grep -r "Festival" src/main/java/com/waglewagle/server/domain/festival/controller/ --include="*.java" | grep -i "public\|private\|auth" | head -20

Repository: wagle-project/wagle-server

Length of output: 868


🏁 Script executed:

# Double-check: are FestivalController endpoints supposed to be public?
# Look at the interface/docs to see if there's any auth requirement mentioned
cat -n src/main/java/com/waglewagle/server/domain/festival/controller/FestivalControllerDocs.java

Repository: wagle-project/wagle-server

Length of output: 4825


기본 인가 정책이 permitAll이므로 새 엔드포인트 추가 시 보호 누락 위험이 있습니다.

Line 57의 anyRequest().permitAll()은 명시적으로 허용되지 않은 엔드포인트도 모두 공개되는 fail-open 구조입니다. 현재는 /health가 명시적으로 line 53에서 permitAll()로 지정되어 있고, JwtFilter가 정상 작동하며 protected 엔드포인트들이 @PreAuthorize로 보호되어 있어 문제없이 작동합니다. 다만 새로운 엔드포인트 추가 시 @PreAuthorize 어노테이션을 누락하면 의도하지 않게 공개될 수 있으므로, 기본값을 authenticated() 또는 denyAll()로 두고 공개 API만 명시적으로 permitAll()로 지정하는 구성을 권장합니다.

🔧 제안 수정안
-                        // 나머지는 다 인증 불필요
-                        // 인증이 필요한 메소드 위 `@PreAuthorize을` 붙일 것
-                        .anyRequest().permitAll()
+                        // 기본은 인증 필요(새 엔드포인트 추가 시 실수로 인한 공개 방지)
+                        .anyRequest().authenticated()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.java`
around lines 55 - 57, The current SecurityConfig uses anyRequest().permitAll(),
which is a fail-open default that risks accidental exposure; change the policy
to a fail-closed default by replacing anyRequest().permitAll() with
anyRequest().authenticated() (or denyAll() if stricter) and explicitly add
permitAll() matchers for public endpoints such as the existing /health route and
any other intended public APIs; update the configuration in SecurityConfig
(where anyRequest().permitAll() is declared) and ensure JwtFilter and
`@PreAuthorize-protected` endpoints remain functional under the new default.

@seoyeoki seoyeoki merged commit ce721ea into develop Mar 24, 2026
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