From 31346329e2a46a6dc6795cd534d6e468816333d1 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 10:14:13 +0000 Subject: [PATCH 01/12] fix: handle UID 0 (root user) case in docker-entrypoint.sh - Detect when host user is root (CLAUDE_UID=0) - Use fallback UID 1000 to avoid conflict with existing root user - Also handle CLAUDE_GID=0 case with same fallback - Display clear warning messages about fallback behavior - Preserves security by still running as non-root in container - Fixes "usermod: UID '0' already exists" error Resolves #21 Co-authored-by: Eric Wang --- docker-entrypoint.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 582f7cf..2022435 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -59,6 +59,17 @@ setup_nonroot_user() { local current_uid=$(id -u "$CLAUDE_USER") local current_gid=$(id -g "$CLAUDE_USER") + # Handle UID=0 case (host user is root) + if [ "$CLAUDE_UID" = "0" ]; then + echo "[entrypoint] WARNING: Host user is root (UID=0). Using fallback UID 1000 for security." + echo "[entrypoint] Container runs as non-root claude user but files will be owned by root on host." + CLAUDE_UID=1000 + # Also use fallback GID if it was 0 + if [ "$CLAUDE_GID" = "0" ]; then + CLAUDE_GID=1000 + fi + fi + if [ "$CLAUDE_GID" != "$current_gid" ]; then [ "$VERBOSE" = "true" ] && echo "[entrypoint] updating $CLAUDE_USER GID: $current_gid -> $CLAUDE_GID" if getent group "$CLAUDE_GID" >/dev/null 2>&1; then From e9e14e0a358ca9f78062609c2a363cd04dc45890 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 04:34:00 -0700 Subject: [PATCH 02/12] fix: handle UID=0 and GID=0 independently for security MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Separate UID=0 and GID=0 checks to prevent security bypass - Fix case where host user has UID≠0 but GID=0 (would assign root group) - Remove inaccurate warning message about file ownership - Addresses Cursor BugBot security vulnerability report 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docker-entrypoint.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 2022435..3cd328e 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -62,12 +62,13 @@ setup_nonroot_user() { # Handle UID=0 case (host user is root) if [ "$CLAUDE_UID" = "0" ]; then echo "[entrypoint] WARNING: Host user is root (UID=0). Using fallback UID 1000 for security." - echo "[entrypoint] Container runs as non-root claude user but files will be owned by root on host." CLAUDE_UID=1000 - # Also use fallback GID if it was 0 - if [ "$CLAUDE_GID" = "0" ]; then - CLAUDE_GID=1000 - fi + fi + + # Handle GID=0 case (host user in root group) + if [ "$CLAUDE_GID" = "0" ]; then + echo "[entrypoint] WARNING: Host user is in root group (GID=0). Using fallback GID 1000 for security." + CLAUDE_GID=1000 fi if [ "$CLAUDE_GID" != "$current_gid" ]; then From 232b0ea1c8c4ed33f5bb4c9bbacb7cbd777f2795 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 04:38:06 -0700 Subject: [PATCH 03/12] fix: add explicit github_token to claude-code-review action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add github_token parameter to prevent OIDC token exchange errors - Fixes 401 Unauthorized - Invalid OIDC token error in claude-review CI - Action was trying to use GitHub App auth instead of direct token auth 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/claude-code-review.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 3b24156..88bd60f 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -38,6 +38,7 @@ jobs: uses: anthropics/claude-code-action@beta with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + github_token: ${{ secrets.GITHUB_TOKEN }} # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4) # model: "claude-opus-4-20250514" From 35db5ef3143f66af6e142e2b0888a68bd00ee387 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 04:40:02 -0700 Subject: [PATCH 04/12] docs: add OIDC token fix to dev log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- DEV-LOGS.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/DEV-LOGS.md b/DEV-LOGS.md index e9ef513..25771e4 100644 --- a/DEV-LOGS.md +++ b/DEV-LOGS.md @@ -5,6 +5,20 @@ ## Issue Analysis: 2025-06-23 +### [bug-fixed] Claude Code Review OIDC token authentication error + +**Problem**: CI failing with "Invalid OIDC token" after changing permissions to write. + +**Solution**: Added explicit `github_token: ${{ secrets.GITHUB_TOKEN }}` to force direct token auth. + +**Cause**: Write permissions trigger GitHub App auth by default, but no App configured. + +**Status**: ✅ **COMPLETED** + +--- + +## Issue Analysis: 2025-06-23 + ### [enhancement-completed] Claude Code Review workflow simplification **Problem**: Overcomplicated workflow with manual duplicate detection using GitHub CLI. From c0e985f81f6a7609a8f20d2bb8a2ba53fbee4217 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 04:42:48 -0700 Subject: [PATCH 05/12] refactor: remove redundant comments in UID/GID handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove obvious comments that don't add value - Add missing dev log entry for root user handling fix 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- DEV-LOGS.md | 14 ++++++++++++++ docker-entrypoint.sh | 2 -- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/DEV-LOGS.md b/DEV-LOGS.md index 25771e4..43be890 100644 --- a/DEV-LOGS.md +++ b/DEV-LOGS.md @@ -5,6 +5,20 @@ ## Issue Analysis: 2025-06-23 +### [bug-fixed] Root user (UID 0) handling in docker-entrypoint.sh + +**Problem**: `sudo claude-yolo` fails with "usermod: UID '0' already exists" error. + +**Solution**: Detect UID=0 and GID=0 cases independently, use fallback UID/GID 1000. + +**Security Fix**: Prevent container user getting root group when host has GID=0 but UID≠0. + +**Status**: ✅ **COMPLETED** - PR #22 + +--- + +## Issue Analysis: 2025-06-23 + ### [bug-fixed] Claude Code Review OIDC token authentication error **Problem**: CI failing with "Invalid OIDC token" after changing permissions to write. diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 3cd328e..cb3c4d8 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -59,13 +59,11 @@ setup_nonroot_user() { local current_uid=$(id -u "$CLAUDE_USER") local current_gid=$(id -g "$CLAUDE_USER") - # Handle UID=0 case (host user is root) if [ "$CLAUDE_UID" = "0" ]; then echo "[entrypoint] WARNING: Host user is root (UID=0). Using fallback UID 1000 for security." CLAUDE_UID=1000 fi - # Handle GID=0 case (host user in root group) if [ "$CLAUDE_GID" = "0" ]; then echo "[entrypoint] WARNING: Host user is in root group (GID=0). Using fallback GID 1000 for security." CLAUDE_GID=1000 From 21a2739033e7539d41e6040ab2de3504e0224ae0 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 04:44:39 -0700 Subject: [PATCH 06/12] feat: dynamic fallback UID/GID selection for root users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace hardcoded 1000 fallback with dynamic search - Find first available UID/GID starting from 1000 - Prevents collision with existing container users/groups - More robust handling of edge cases 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docker-entrypoint.sh | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index cb3c4d8..edce355 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -60,13 +60,23 @@ setup_nonroot_user() { local current_gid=$(id -g "$CLAUDE_USER") if [ "$CLAUDE_UID" = "0" ]; then - echo "[entrypoint] WARNING: Host user is root (UID=0). Using fallback UID 1000 for security." - CLAUDE_UID=1000 + # Find first available UID starting from 1000 + fallback_uid=1000 + while getent passwd "$fallback_uid" >/dev/null 2>&1; do + fallback_uid=$((fallback_uid + 1)) + done + echo "[entrypoint] WARNING: Host user is root (UID=0). Using fallback UID $fallback_uid for security." + CLAUDE_UID=$fallback_uid fi if [ "$CLAUDE_GID" = "0" ]; then - echo "[entrypoint] WARNING: Host user is in root group (GID=0). Using fallback GID 1000 for security." - CLAUDE_GID=1000 + # Find first available GID starting from 1000 + fallback_gid=1000 + while getent group "$fallback_gid" >/dev/null 2>&1; do + fallback_gid=$((fallback_gid + 1)) + done + echo "[entrypoint] WARNING: Host user is in root group (GID=0). Using fallback GID $fallback_gid for security." + CLAUDE_GID=$fallback_gid fi if [ "$CLAUDE_GID" != "$current_gid" ]; then From 4dfc33dc7279d1b3538fac1aed5baba04fd433bf Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 04:46:50 -0700 Subject: [PATCH 07/12] simplify: revert to hardcoded 1000 fallback for root users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use UID/GID 1000 fallback for predictable file ownership - Existing usermod logic handles UID collision properly - Most host users are UID 1000, so this provides correct file ownership - Simpler than dynamic search while achieving the goal 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docker-entrypoint.sh | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index edce355..cb3c4d8 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -60,23 +60,13 @@ setup_nonroot_user() { local current_gid=$(id -g "$CLAUDE_USER") if [ "$CLAUDE_UID" = "0" ]; then - # Find first available UID starting from 1000 - fallback_uid=1000 - while getent passwd "$fallback_uid" >/dev/null 2>&1; do - fallback_uid=$((fallback_uid + 1)) - done - echo "[entrypoint] WARNING: Host user is root (UID=0). Using fallback UID $fallback_uid for security." - CLAUDE_UID=$fallback_uid + echo "[entrypoint] WARNING: Host user is root (UID=0). Using fallback UID 1000 for security." + CLAUDE_UID=1000 fi if [ "$CLAUDE_GID" = "0" ]; then - # Find first available GID starting from 1000 - fallback_gid=1000 - while getent group "$fallback_gid" >/dev/null 2>&1; do - fallback_gid=$((fallback_gid + 1)) - done - echo "[entrypoint] WARNING: Host user is in root group (GID=0). Using fallback GID $fallback_gid for security." - CLAUDE_GID=$fallback_gid + echo "[entrypoint] WARNING: Host user is in root group (GID=0). Using fallback GID 1000 for security." + CLAUDE_GID=1000 fi if [ "$CLAUDE_GID" != "$current_gid" ]; then From 088402fb118fcac1a0b6db41833f25b72376e758 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 04:51:01 -0700 Subject: [PATCH 08/12] docs: clarify root cause and solution for UID 0 handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Explain why UID 0 can't be reassigned (root user exists) - Clarify security fix prevents root group assignment - Note that 1000 fallback provides proper file ownership 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- DEV-LOGS.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/DEV-LOGS.md b/DEV-LOGS.md index 43be890..1efc724 100644 --- a/DEV-LOGS.md +++ b/DEV-LOGS.md @@ -9,9 +9,11 @@ **Problem**: `sudo claude-yolo` fails with "usermod: UID '0' already exists" error. -**Solution**: Detect UID=0 and GID=0 cases independently, use fallback UID/GID 1000. +**Root Cause**: Can't reassign existing UID 0 (root) to claude user. -**Security Fix**: Prevent container user getting root group when host has GID=0 but UID≠0. +**Security Fix**: Handle UID=0 and GID=0 independently to prevent root group assignment. + +**Solution**: Use fallback UID/GID 1000 for proper file ownership with existing collision handling. **Status**: ✅ **COMPLETED** - PR #22 From 9f5c77e8e7f68566e6f27963bc9ead623d8ad5e2 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 05:27:53 -0700 Subject: [PATCH 09/12] perf: improve Docker build caching in GitHub Actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add registry cache alongside GitHub Actions cache for better persistence - Add Docker build job in CI to warm cache on PRs - Registry cache survives across branches and reduces release build times - Resolves #19: Docker image build performance issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ .github/workflows/release.yml | 8 ++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 279a658..d694d07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,3 +37,25 @@ jobs: run: | ./claude.sh --version ./claude-yolo --version + + docker-build: + name: Docker Build Test & Cache + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image (cache only) + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64 + push: false + cache-from: | + type=gha + type=registry,ref=ghcr.io/${{ github.repository }}:buildcache + cache-to: type=gha,mode=max diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cc0d0e4..f16fced 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,8 +56,12 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: | + type=gha + type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache + cache-to: | + type=gha,mode=max + type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max release: name: Create GitHub Release From 212827fab31c244ef509866c9041755e0eaa10e0 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 05:30:48 -0700 Subject: [PATCH 10/12] docs: update logs and changelog for issue #19 caching fix - Add perf optimization entry to DEV-LOGS.md - Document dual caching strategy in CHANGELOG.md under Performance section Closes #19 --- CHANGELOG.md | 4 ++++ DEV-LOGS.md | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2c7a0f..3e457ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - claude-trace --run-with syntax (removed unnecessary "claude" argument) - Container shortcuts now properly exit after --ps command +### Performance +- Docker build caching in GitHub Actions (dual GHA + registry cache strategy) +- Added cache warming via CI builds on PRs to accelerate release builds + ### Changed - Consolidated all claude-yolo argument parsing through single parse_args() function - Enhanced claude-trace argument injection for proper --dangerously-skip-permissions placement diff --git a/DEV-LOGS.md b/DEV-LOGS.md index 1efc724..e37c2d0 100644 --- a/DEV-LOGS.md +++ b/DEV-LOGS.md @@ -5,6 +5,23 @@ ## Issue Analysis: 2025-06-23 +### [perf-optimized] Docker build caching in GitHub Actions (Issue #19) + +**Problem**: Docker image builds taking 49+ minutes due to lack of effective caching. + +**Root Cause**: Limited GitHub Actions cache scope, no registry cache, no cache warming. + +**Solution**: Dual caching strategy + cache warming +- Registry cache persists across branches/runners +- CI job warms cache on PRs for release builds +- Combined GHA + registry cache maximizes hit rates + +**Status**: ✅ **COMPLETED** + +--- + +## Issue Analysis: 2025-06-23 + ### [bug-fixed] Root user (UID 0) handling in docker-entrypoint.sh **Problem**: `sudo claude-yolo` fails with "usermod: UID '0' already exists" error. From b9a2de9db596aa6cd35cb935dd134fcb8e022935 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 05:37:21 -0700 Subject: [PATCH 11/12] chore: bump version to 0.2.3 --- CHANGELOG.md | 2 ++ claude.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e457ae..4f40b9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.2.3] - 2025-06-23 + ### Added - Unified logging system for improved UX - Clean output by default showing only authentication method diff --git a/claude.sh b/claude.sh index 8689795..4068de8 100755 --- a/claude.sh +++ b/claude.sh @@ -4,7 +4,7 @@ set -e # Claude Starter Script with Docker Support # Runs Claude Code CLI locally or in a Docker container for safe execution -VERSION="0.2.2" +VERSION="0.2.3" DOCKER_IMAGE="${DOCKER_IMAGE:-ghcr.io/lroolle/claude-code-yolo}" DOCKER_TAG="${DOCKER_TAG:-latest}" From 2da66f45550b9f5c4950990385a8fa42a6990e98 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Mon, 23 Jun 2025 05:38:19 -0700 Subject: [PATCH 12/12] fix: change claude-code-review from pull_request_target to pull_request Action doesn't support pull_request_target event type --- .github/workflows/claude-code-review.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 88bd60f..83f9519 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -1,7 +1,7 @@ name: Claude Code Review on: - pull_request_target: + pull_request: types: [opened, reopened] issue_comment: types: [created] @@ -14,7 +14,7 @@ concurrency: jobs: claude-review: if: | - github.event_name == 'pull_request_target' || + github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '@claude')) @@ -31,7 +31,6 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha || github.event.pull_request.merge_commit_sha }} - name: Run Claude Code Review id: claude-review