Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 0 additions & 72 deletions PushAndPull/.claude/commands/commit.md

This file was deleted.

26 changes: 0 additions & 26 deletions PushAndPull/.claude/commands/migrate.md

This file was deleted.

16 changes: 0 additions & 16 deletions PushAndPull/.claude/commands/test.md

This file was deleted.

61 changes: 0 additions & 61 deletions PushAndPull/.claude/hooks/commit-msg.sh

This file was deleted.

49 changes: 49 additions & 0 deletions PushAndPull/.claude/hooks/postToolUse.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash
# .claude/hooks/postToolUse.sh

INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

if [[ "$TOOL_NAME" != "Edit" && "$TOOL_NAME" != "Write" ]]; then
exit 0
fi

if [[ "$FILE_PATH" != *.cs ]]; then
exit 0
fi

echo "[Hook] C# file modified: $FILE_PATH" >&2

dotnet format --no-restore 2>/dev/null || echo "[Hook] format failed (ignored)" >&2

CACHE_FILE=".claude/.last_build_hash"

CURRENT_HASH=$(find . -name "*.cs" -not -path "*/obj/*" | sort | xargs md5sum 2>/dev/null | md5sum | cut -d' ' -f1)

LAST_HASH=""
if [[ -f "$CACHE_FILE" ]]; then
LAST_HASH=$(cat "$CACHE_FILE")
fi

if [[ "$CURRENT_HASH" != "$LAST_HASH" ]]; then
echo "[Hook] Running dotnet build..." >&2
if dotnet build PushAndPull/PushAndPull.csproj --no-restore; then
echo "$CURRENT_HASH" > "$CACHE_FILE"
else
echo "[Hook] Build failed" >&2
exit 2
fi
else
echo "[Hook] Skip build (no source changes)" >&2
fi

echo "[Hook] Running tests..." >&2
if dotnet test PushAndPull.Test/PushAndPull.Test.csproj --no-build --verbosity minimal; then
echo "[Hook] Tests passed" >&2
else
echo "[Hook] Tests failed" >&2
exit 2
fi

exit 0
50 changes: 32 additions & 18 deletions PushAndPull/.claude/hooks/preCommit.sh
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
#!/bin/bash
# .claude/hooks/preCommit.sh
# Ensure tests pass before allowing dotnet build/run/publish (Claude Code PreToolUse hook)

INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
COMMIT_MSG="$TOOL_PARAMS_MESSAGE"

if [[ "$TOOL_NAME" != "Bash" ]]; then
exit 0
fi
# allowed types
PATTERN="^(feat|fix|update|docs): .+"

if [[ ! "$COMMAND" =~ dotnet[[:space:]]+(build|run|publish) ]]; then
exit 0
if [[ ! "$COMMIT_MSG" =~ $PATTERN ]]; then
echo "[Hook] ✗ Invalid commit message format"
echo ""
echo "Expected:"
echo " {type}: {Korean description}"
echo ""
echo "Types:"
echo " feat — new feature"
echo " fix — bug fix or missing DI/config"
echo " update — modification to existing code"
echo " docs — documentation changes"
echo ""
echo "Examples:"
echo " feat: 방 생성 API 추가"
echo " fix: 세션 DI 누락 수정"
echo " update: Room 엔터티 수정"
exit 1
Comment on lines +7 to +25
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

preCommit.sh의 커밋 메시지 검증 패턴(PATTERN)과 도움말 메시지가 프로젝트의 다른 문서(commit/SKILL.md, pr/SKILL.md) 및 실제 사용 사례(PR 제목의 refactor 등)와 일치하지 않습니다. 특히 refactorchore 타입이 누락되어 있어, 해당 타입으로 커밋을 시도할 경우 훅에 의해 차단될 수 있습니다.

PATTERN="^(feat|fix|update|docs|refactor|chore): .+"

if [[ ! "$COMMIT_MSG" =~ $PATTERN ]]; then
    echo "[Hook] ✗ Invalid commit message format"
    echo ""
    echo "Expected:"
    echo "  {type}: {Korean description}"
    echo ""
    echo "Types:"
    echo "  feat     — new feature"
    echo "  fix      — bug fix or missing DI/config"
    echo "  update   — modification to existing code"
    echo "  docs     — documentation changes"
    echo "  refactor — code refactoring"
    echo "  chore    — tooling, config, etc."
    echo ""
    echo "Examples:"
    echo "  feat: 방 생성 API 추가"
    echo "  fix: 세션 DI 누락 수정"
    echo "  update: Room 엔터티 수정"
    exit 1

fi

echo "[Hook] Checking tests before proceeding..."

dotnet test PushAndPull/PushAndPull.sln --nologo --no-build 2>/dev/null
RESULT=$?
# punctuation check
if [[ "$COMMIT_MSG" =~ [\.\!]$ ]]; then
echo "[Hook] ✗ Do not end the message with punctuation"
echo "Example: feat: 방 생성 API 추가"
exit 1
fi

if [ $RESULT -ne 0 ]; then
echo "[Hook] ✗ Tests failed — fix tests before running dotnet $BASH_REMATCH[1]"
exit 2
# ensure single line
if [[ "$COMMIT_MSG" == *$'\n'* ]]; then
echo "[Hook] ✗ Commit body is not allowed"
echo "Use subject line only"
exit 1
fi

echo "[Hook] ✓ Tests passed"
exit 0
echo "[Hook] ✓ Commit message format valid"
51 changes: 29 additions & 22 deletions PushAndPull/.claude/hooks/preToolUse.sh
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
#!/bin/bash
# .claude/hooks/preToolUser.sh
# .claude/hooks/preToolUse.sh
# Block dangerous commands before execution (Claude Code PreToolUse hook)

INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

if [[ "$TOOL_NAME" != "Bash" ]]; then
exit 0
fi
[[ "$TOOL_NAME" != "Bash" ]] && exit 0

NORMALIZED=$(echo "$COMMAND" | tr -s ' ')
NORMALIZED=$(echo "$COMMAND" | tr -s ' ' | tr -d '\n')

BLOCKED_PATTERNS=(
"rm -rf /"
"rm -rf \."
"rm -rf ~"
"rm -rf \*"
"sudo .*rm"
"> /dev/"
"dd if="
DANGEROUS_KEYWORDS=(
"rm -rf"
"mkfs"
"curl .*\| .*sh"
"curl .*\| .*bash"
"wget .*\| .*sh"
"wget .*\| .*bash"
"dd if="
"shutdown"
"reboot"
"kill -9 -1"
":(){"
"> /dev/sda"
"chmod -R 777 /"
"chown -R root"
)
Comment on lines +13 to 24
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

DANGEROUS_KEYWORDS"rm -rf"가 포함되어 있어, 개발 중 빈번하게 발생하는 일반적인 디렉토리 삭제 명령(예: rm -rf bin/, rm -rf obj/)까지 모두 차단됩니다. 하단(35-38행)에서 루트(/)나 와일드카드(*)를 사용한 위험한 삭제 명령을 이미 별도로 검사하고 있으므로, 키워드 목록에서 "rm -rf"를 제거하여 개발 편의성을 높이는 것이 좋습니다.

Suggested change
DANGEROUS_KEYWORDS=(
"rm -rf"
"mkfs"
"curl .*\| .*sh"
"curl .*\| .*bash"
"wget .*\| .*sh"
"wget .*\| .*bash"
"dd if="
"shutdown"
"reboot"
"kill -9 -1"
":(){"
"> /dev/sda"
"chmod -R 777 /"
"chown -R root"
)
DANGEROUS_KEYWORDS=(
"mkfs"
"dd if="
"shutdown"
"reboot"
"kill -9 -1"
":(){"
"> /dev/sda"
"chmod -R 777 /"
"chown -R root"
)


for pattern in "${BLOCKED_PATTERNS[@]}"; do
if [[ "$NORMALIZED" =~ $pattern ]]; then
echo "[Hook] ✗ Blocked dangerous command"
echo "Command: $COMMAND"
echo "Reason: matched pattern '$pattern'"
for keyword in "${DANGEROUS_KEYWORDS[@]}"; do
if [[ "$NORMALIZED" == *"$keyword"* ]]; then
echo "[Hook] ✗ Blocked dangerous keyword: $keyword" >&2
echo "Command: $COMMAND" >&2
exit 2
fi
done

# rm -rf / or rm -rf *
if [[ "$NORMALIZED" =~ rm[[:space:]]+-rf.*(/|\*) ]]; then
echo "[Hook] ✗ Blocked root/wildcard deletion" >&2
exit 2
fi

# curl/wget → pipe/redirect → sh/bash
if [[ "$NORMALIZED" =~ (curl|wget).*(\||>).*(sh|bash) ]]; then
echo "[Hook] ✗ Blocked remote execution" >&2
exit 2
fi

exit 0
Loading
Loading