Skip to content

Develop to Main - #5

Merged
cfcromn merged 7 commits into
mainfrom
develop
Jul 6, 2026
Merged

cfcromn merged 7 commits into
mainfrom
develop

Conversation

@cfcromn

@cfcromn cfcromn commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

✨ 작업 내용

이번 PR에서 어떤 작업을 했는지 간단히 요약해주세요.


🔍 리뷰 시 참고사항

  • 리뷰어가 알면 좋은 변경 이유, 배경, 고려했던 점 등을 적어주세요.

✅ 체크리스트

  • 문서(README, .env.example 등) 변경이 필요한 경우 작성 또는 수정했나요?
  • 작업한 코드가 정상적으로 동작하는 것을 직접 확인했나요?
  • 필요한 경우 테스트 코드를 작성하거나 수정했나요?
  • Merge 대상 브랜치를 올바르게 설정했나요?
  • PR에 관련 없는 작업이 포함되지 않았나요?
  • 적절한 라벨과 리뷰어를 설정했나요?

📎 관련 이슈(선택)

  • Close #

@cfcromn
cfcromn merged commit d5c422a into main Jul 6, 2026
2 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive suite of AI coding agent configurations, skills, hooks, and project documentation to support both Claude and Codex agents, alongside Gradle updates for Kotest, MockK, and ktlint. The review feedback highlights several critical security and quality improvements, including fixing a command injection bypass in the command-guard hooks, resolving a security bypass in the pre-tool dispatcher, correcting Kotest testing guidelines to avoid class-level mock dependencies, and resolving documentation inconsistencies regarding controller response formats. Additionally, the reviewer recommended adding missing gh permissions to settings.json, utilizing the $REPO variable instead of placeholders in GitHub API calls, and replacing unsafe echo usage with printf when handling JSON inputs in bash hooks.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +6 to +14
BLOCKED_PATTERNS=(
"rm -rf[[:space:]]*/[[:space:]]*$"
"sudo rm"
"> /dev/"
"dd if="
"mkfs"
"curl.*\| sh"
"wget.*\| sh"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-high high

rm -rf 패턴에 $ 앵커가 사용되어 있어, 뒤에 공백이나 추가 플래그(예: rm -rf / --no-preserve-root 또는 rm -rf / )를 붙이는 방식으로 쉽게 우회할 수 있는 보안 취약점이 존재합니다. 앵커를 제거하고 공백 또는 줄바꿈을 안전하게 처리할 수 있도록 패턴을 개선해야 합니다.

Suggested change
BLOCKED_PATTERNS=(
"rm -rf[[:space:]]*/[[:space:]]*$"
"sudo rm"
"> /dev/"
"dd if="
"mkfs"
"curl.*\| sh"
"wget.*\| sh"
)
BLOCKED_PATTERNS=(
"rm -rf[[:space:]]+/[[:space:]]*([[:space:]]|$)"
"sudo rm"
"> /dev/"
"dd if="
"mkfs"
"curl.*\| sh"
"wget.*\| sh"
)

Comment on lines +7 to +15
BLOCKED_PATTERNS=(
"rm -rf[[:space:]]*/[[:space:]]*$"
"sudo rm"
"> /dev/"
"dd if="
"mkfs"
"curl.*\| sh"
"wget.*\| sh"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-high high

rm -rf 패턴에 $ 앵커가 사용되어 있어, 뒤에 공백이나 추가 플래그(예: rm -rf / --no-preserve-root 또는 rm -rf / )를 붙이는 방식으로 쉽게 우회할 수 있는 보안 취약점이 존재합니다. 앵커를 제거하고 공백 또는 줄바꿈을 안전하게 처리할 수 있도록 패턴을 개선해야 합니다.

Suggested change
BLOCKED_PATTERNS=(
"rm -rf[[:space:]]*/[[:space:]]*$"
"sudo rm"
"> /dev/"
"dd if="
"mkfs"
"curl.*\| sh"
"wget.*\| sh"
)
BLOCKED_PATTERNS=(
"rm -rf[[:space:]]+/[[:space:]]*([[:space:]]|$)"
"sudo rm"
"> /dev/"
"dd if="
"mkfs"
"curl.*\| sh"
"wget.*\| sh"
)

Comment on lines +8 to +12
for hook in "$MODULES_DIR"/*/preToolUse.sh; do
[[ -f "$hook" ]] || continue
echo "$INPUT" | bash "$hook"
[[ $? -eq 2 ]] && exit 2
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-high high

현재 디스패처는 pre-tool 훅의 종료 코드가 2인 경우만 처리하고 다른 비정상 종료 코드(예: 1)는 무시합니다. 이로 인해 보안 검사 스크립트(예: secret-guard)에서 문법 오류나 실행 실패가 발생하더라도 도구 실행이 그대로 진행되어 보안 검사가 우회될 수 있습니다. 또한, $INPUT 변수를 전달할 때 echo 대신 printf를 사용하는 것이 안전합니다.

Suggested change
for hook in "$MODULES_DIR"/*/preToolUse.sh; do
[[ -f "$hook" ]] || continue
echo "$INPUT" | bash "$hook"
[[ $? -eq 2 ]] && exit 2
done
for hook in "$MODULES_DIR"/*/preToolUse.sh; do
[[ -f "$hook" ]] || continue
printf '%s\n' "$INPUT" | bash "$hook"
STATUS=$?
[[ $STATUS -ne 0 ]] && exit $STATUS
done

Comment on lines +47 to +51
### Mock Creation
```kotlin
private val repository: ApiKeyRepository = mockk()
private val service = ApiKeyService(repository)
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Kotest 가이드라인 및 프로젝트 컨벤션에 따르면, 테스트 의존성은 DescribeSpec 생성자 람다 내부의 로컬 변수로 선언하고 beforeEach에서 초기화해야 합니다. 클래스 멤버 프로퍼티(private val)로 선언하여 직접 초기화하는 방식은 테스트 간 상태 공유 문제를 유발할 수 있으며 프로젝트 규칙에 위배됩니다.

Suggested change
### Mock Creation
```kotlin
private val repository: ApiKeyRepository = mockk()
private val service = ApiKeyService(repository)
```
class ApiKeyServiceTest : DescribeSpec({
lateinit var repository: ApiKeyRepository
lateinit var service: ApiKeyService
beforeEach {
repository = mockk()
service = ApiKeyService(repository)
}
})
References
  1. Kotest 테스트에서 의존성은 DescribeSpec 생성자 람다 내부의 로컬 변수로 선언하고 beforeEach에서 초기화해야 합니다.

Comment on lines +47 to +51
### Mock Creation
```kotlin
private val repository: ApiKeyRepository = mockk()
private val service = ApiKeyService(repository)
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Kotest 가이드라인 및 프로젝트 컨벤션에 따르면, 테스트 의존성은 DescribeSpec 생성자 람다 내부의 로컬 변수로 선언하고 beforeEach에서 초기화해야 합니다. 클래스 멤버 프로퍼티(private val)로 선언하여 직접 초기화하는 방식은 테스트 간 상태 공유 문제를 유발할 수 있으며 프로젝트 규칙에 위배됩니다.

Suggested change
### Mock Creation
```kotlin
private val repository: ApiKeyRepository = mockk()
private val service = ApiKeyService(repository)
```
class ApiKeyServiceTest : DescribeSpec({
lateinit var repository: ApiKeyRepository
lateinit var service: ApiKeyService
beforeEach {
repository = mockk()
service = ApiKeyService(repository)
}
})
References
  1. Kotest 테스트에서 의존성은 DescribeSpec 생성자 람다 내부의 로컬 변수로 선언하고 beforeEach에서 초기화해야 합니다.

Comment thread .claude/settings.json
Comment on lines +7 to +21
"permissions": {
"allow": [
"WebSearch",
"WebFetch",
"Bash(./gradlew *)",
"Bash(git diff*)",
"Bash(git status)",
"Bash(git log*)",
"Bash(git add*)",
"Bash(git commit*)",
"Bash(git branch*)",
"Bash(git checkout*)",
"Bash(git rev-parse*)"
]
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

프로젝트 내의 resolve-reviews 및 write-pr 스킬은 GitHub CLI(gh) 명령어를 빈번하게 사용합니다. 하지만 허용된 권한 목록에 gh 관련 권한이 누락되어 있어, 실행 시마다 사용자에게 권한 확인을 요청하거나 비대화형 환경에서 실패할 수 있습니다. "Bash(gh *)" 권한을 추가하는 것이 좋습니다.

  "permissions": {
    "allow": [
      "WebSearch",
      "WebFetch",
      "Bash(./gradlew *)",
      "Bash(git diff*)",
      "Bash(git status)",
      "Bash(git log*)",
      "Bash(git add*)",
      "Bash(git commit*)",
      "Bash(git branch*)",
      "Bash(git checkout*)",
      "Bash(git rev-parse*)",
      "Bash(gh *)"
    ]
  },

Comment on lines +113 to +116
```bash
gh api "repos/<owner>/<repo>/pulls/<pr_number>/comments/<comment_id>/replies" \
-f body="<reply_body>"
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

GitHub API 호출 시 <owner> 및 <repo> 플레이스홀더를 사용하는 대신, Step 1에서 이미 수집한 $REPO 변수를 활용하면 수동 파싱 및 치환 과정 없이 더 안전하고 간결하게 명령어를 실행할 수 있습니다.

Suggested change
```bash
gh api "repos/<owner>/<repo>/pulls/<pr_number>/comments/<comment_id>/replies" \
-f body="<reply_body>"
```
gh api "repos/$REPO/pulls/$PR_NUMBER/comments/$COMMENT_ID/replies" \
-f body="<reply_body>"

Comment on lines +103 to +106
```bash
gh api "repos/<owner>/<repo>/pulls/<pr_number>/comments/<comment_id>/replies" \
-f body="<reply_body>"
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

GitHub API 호출 시 <owner> 및 <repo> 플레이스홀더를 사용하는 대신, Step 1에서 이미 수집한 $REPO 변수를 활용하면 수동 파싱 및 치환 과정 없이 더 안전하고 간결하게 명령어를 실행할 수 있습니다.

Suggested change
```bash
gh api "repos/<owner>/<repo>/pulls/<pr_number>/comments/<comment_id>/replies" \
-f body="<reply_body>"
```
gh api "repos/$REPO/pulls/$PR_NUMBER/comments/$COMMENT_ID/replies" \
-f body="<reply_body>"

Comment on lines +2 to +6
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
if [[ "$TOOL_NAME" == "Write" ]] || [[ "$TOOL_NAME" == "Edit" ]]; then
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Bash에서 JSON 문자열이 포함된 $INPUT 변수를 echo로 출력하면, 문자열이 하이픈(-)으로 시작하거나 백슬래시가 포함된 경우 오동작하거나 JSON이 깨질 수 있습니다. 안전하고 일관된 출력을 위해 printf '%s\n'을 사용하는 것이 좋습니다.

Suggested change
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
if [[ "$TOOL_NAME" == "Write" ]] || [[ "$TOOL_NAME" == "Edit" ]]; then
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
INPUT=$(cat)
TOOL_NAME=$(printf '%s\n' "$INPUT" | jq -r '.tool_name')
if [[ "$TOOL_NAME" == "Write" ]] || [[ "$TOOL_NAME" == "Edit" ]]; then
CONTENT=$(printf '%s\n' "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // empty')
FILE_PATH=$(printf '%s\n' "$INPUT" | jq -r '.tool_input.file_path // empty')

Comment on lines +3 to +8
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')

if [[ "$TOOL_NAME" == "Write" ]] || [[ "$TOOL_NAME" == "Edit" ]] || [[ "$TOOL_NAME" == "write_file" ]]; then
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Bash에서 JSON 문자열이 포함된 $INPUT 변수를 echo로 출력하면, 문자열이 하이픈(-)으로 시작하거나 백슬래시가 포함된 경우 오동작하거나 JSON이 깨질 수 있습니다. 안전하고 일관된 출력을 위해 printf '%s\n'을 사용하는 것이 좋습니다.

Suggested change
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
if [[ "$TOOL_NAME" == "Write" ]] || [[ "$TOOL_NAME" == "Edit" ]] || [[ "$TOOL_NAME" == "write_file" ]]; then
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')
TOOL_NAME=$(printf '%s\n' "$INPUT" | jq -r '.tool_name')
if [[ "$TOOL_NAME" == "Write" ]] || [[ "$TOOL_NAME" == "Edit" ]] || [[ "$TOOL_NAME" == "write_file" ]]; then
CONTENT=$(printf '%s\n' "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // empty')
FILE_PATH=$(printf '%s\n' "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')

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.

1 participant