From 67597b1478e0a69bb2eec586f050063e2786c230 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 3 Apr 2026 23:33:20 -0400 Subject: [PATCH 1/6] chore(ci): align weekly-update workflow with other repos - Use pnpm exec claude (not bare claude) - Add structured context/instructions/success_criteria to /updating prompt - Remove stale comment, shell: bash override, pnpm alias --- .github/workflows/weekly-update.yml | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/weekly-update.yml b/.github/workflows/weekly-update.yml index 9dcc87a5c..e6ee6fe03 100644 --- a/.github/workflows/weekly-update.yml +++ b/.github/workflows/weekly-update.yml @@ -51,8 +51,6 @@ jobs: steps: - uses: SocketDev/socket-registry/.github/actions/setup-and-install@6096b06b1790f411714c89c40f72aade2eeaab7c # main - # claude-code is now a devDependency, installed via setup-and-install - - name: Create update branch id: branch env: @@ -70,12 +68,10 @@ jobs: - name: Run updating skill with Claude Code id: claude timeout-minutes: 30 - shell: bash env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} GITHUB_ACTIONS: 'true' run: | - alias pnpm="$SFW_BIN pnpm" if [ -z "$ANTHROPIC_API_KEY" ]; then echo "ANTHROPIC_API_KEY not set - skipping automated update" echo "success=false" >> $GITHUB_OUTPUT @@ -83,9 +79,30 @@ jobs: fi set +e - claude --print --dangerously-skip-permissions \ + pnpm exec claude --print --dangerously-skip-permissions \ --model sonnet \ - "/updating" \ + "$(cat <<'PROMPT' + /updating + + + You are an automated CI agent in a weekly dependency update workflow. + Git is configured with GPG signing. A branch has been created for you. + + + + Update all dependencies to their latest versions. + Create one atomic commit per dependency update with a conventional commit message. + Leave all changes local — the workflow handles pushing and PR creation. + Skip running builds, tests, and type checks — CI runs those separately. + + + + Each updated dependency has its own commit. + The lockfile is consistent with package.json changes. + No uncommitted changes remain in the working tree. + + PROMPT + )" \ 2>&1 | tee claude-output.log CLAUDE_EXIT=${PIPESTATUS[0]} set -e From 165cee824f65e016d1683ca92c64b7157d6d0b87 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 3 Apr 2026 23:37:55 -0400 Subject: [PATCH 2/6] fix: restore shell: bash and pnpm alias, keep structured prompt --- .github/workflows/weekly-update.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/weekly-update.yml b/.github/workflows/weekly-update.yml index e6ee6fe03..0191d0e0e 100644 --- a/.github/workflows/weekly-update.yml +++ b/.github/workflows/weekly-update.yml @@ -68,10 +68,12 @@ jobs: - name: Run updating skill with Claude Code id: claude timeout-minutes: 30 + shell: bash env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} GITHUB_ACTIONS: 'true' run: | + alias pnpm="$SFW_BIN pnpm" if [ -z "$ANTHROPIC_API_KEY" ]; then echo "ANTHROPIC_API_KEY not set - skipping automated update" echo "success=false" >> $GITHUB_OUTPUT @@ -79,7 +81,7 @@ jobs: fi set +e - pnpm exec claude --print --dangerously-skip-permissions \ + claude --print --dangerously-skip-permissions \ --model sonnet \ "$(cat <<'PROMPT' /updating From 05358cd60c4ee6999e2bf3c25414c763f5e1f001 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 3 Apr 2026 23:44:14 -0400 Subject: [PATCH 3/6] - Replace --dangerously-skip-permissions with --allowedTools whitelist (Bash pnpm/git only, Read, Write, Edit, Glob, Grep) - Switch to --model haiku (cheapest, sufficient for dependency updates) - Add --max-turns 25 to prevent runaway loops - Fix SFW_BIN: use PATH wrapper instead of alias (propagates to subprocesses) - Add post-agent diff validation (block unexpected file modifications) - Gate push/PR on validation passing - Reduce timeout-minutes from 30 to 15 --- .github/workflows/weekly-update.yml | 42 ++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/.github/workflows/weekly-update.yml b/.github/workflows/weekly-update.yml index 0191d0e0e..8e91790cc 100644 --- a/.github/workflows/weekly-update.yml +++ b/.github/workflows/weekly-update.yml @@ -67,13 +67,20 @@ jobs: - name: Run updating skill with Claude Code id: claude - timeout-minutes: 30 + timeout-minutes: 15 shell: bash env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} GITHUB_ACTIONS: 'true' run: | - alias pnpm="$SFW_BIN pnpm" + # Wrap pnpm through Socket firewall for all subprocesses (not just this shell). + if [ -n "$SFW_BIN" ]; then + mkdir -p /tmp/sfw-bin + printf '#!/bin/bash\nexec "%s" pnpm "$@"\n' "$SFW_BIN" > /tmp/sfw-bin/pnpm + chmod +x /tmp/sfw-bin/pnpm + export PATH="/tmp/sfw-bin:$PATH" + fi + if [ -z "$ANTHROPIC_API_KEY" ]; then echo "ANTHROPIC_API_KEY not set - skipping automated update" echo "success=false" >> $GITHUB_OUTPUT @@ -81,8 +88,10 @@ jobs: fi set +e - claude --print --dangerously-skip-permissions \ - --model sonnet \ + claude --print \ + --model haiku \ + --max-turns 25 \ + --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Read" "Write" "Edit" "Glob" "Grep" \ "$(cat <<'PROMPT' /updating @@ -115,6 +124,25 @@ jobs: echo "success=false" >> $GITHUB_OUTPUT fi + - name: Validate changes + id: validate + if: steps.claude.outputs.success == 'true' + run: | + # Only allow changes to dependency-related files. + UNEXPECTED="" + for file in $(git diff --name-only origin/main..HEAD); do + case "$file" in + package.json|*/package.json|pnpm-lock.yaml|*/pnpm-lock.yaml|.npmrc|pnpm-workspace.yaml) ;; + *) UNEXPECTED="$UNEXPECTED $file" ;; + esac + done + if [ -n "$UNEXPECTED" ]; then + echo "::error::Unexpected files modified by Claude:$UNEXPECTED" + echo "valid=false" >> $GITHUB_OUTPUT + else + echo "valid=true" >> $GITHUB_OUTPUT + fi + - name: Check for changes id: changes run: | @@ -125,13 +153,13 @@ jobs: fi - name: Push branch - if: steps.claude.outputs.success == 'true' && steps.changes.outputs.has-changes == 'true' + if: steps.claude.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' env: BRANCH_NAME: ${{ steps.branch.outputs.branch }} run: git push origin "$BRANCH_NAME" - name: Create Pull Request - if: steps.claude.outputs.success == 'true' && steps.changes.outputs.has-changes == 'true' + if: steps.claude.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' env: GH_TOKEN: ${{ github.token }} BRANCH_NAME: ${{ steps.branch.outputs.branch }} @@ -160,7 +188,7 @@ jobs: --base main - name: Add job summary - if: steps.claude.outputs.success == 'true' && steps.changes.outputs.has-changes == 'true' + if: steps.claude.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' env: BRANCH_NAME: ${{ steps.branch.outputs.branch }} run: | From 879412bffb645e1337eaa66335f1df7452681e7b Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 3 Apr 2026 23:52:23 -0400 Subject: [PATCH 4/6] fix(ci): use sonnet model for CI agent (haiku insufficient for test fixing) --- .github/workflows/weekly-update.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/weekly-update.yml b/.github/workflows/weekly-update.yml index 8e91790cc..cf9c39da0 100644 --- a/.github/workflows/weekly-update.yml +++ b/.github/workflows/weekly-update.yml @@ -89,7 +89,7 @@ jobs: set +e claude --print \ - --model haiku \ + --model sonnet \ --max-turns 25 \ --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Read" "Write" "Edit" "Glob" "Grep" \ "$(cat <<'PROMPT' From 6bb3b696ee60106900cec352bd4b1a38c854753b Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 3 Apr 2026 23:54:30 -0400 Subject: [PATCH 5/6] =?UTF-8?q?feat(ci):=20two-phase=20update=20=E2=80=94?= =?UTF-8?q?=20haiku=20for=20deps,=20sonnet=20escalation=20for=20test=20fix?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1: haiku updates deps (cheap, fast, 15 turns, 10min timeout) Phase 2: build + test to verify updates work Phase 3: if tests fail, sonnet diagnoses and fixes (25 turns, 15min) gets build/test failure logs as context Validate: allow dependency files + source/test files from fix step --- .github/workflows/weekly-update.yml | 137 ++++++++++++++++++++++++---- 1 file changed, 121 insertions(+), 16 deletions(-) diff --git a/.github/workflows/weekly-update.yml b/.github/workflows/weekly-update.yml index cf9c39da0..9656bd9ec 100644 --- a/.github/workflows/weekly-update.yml +++ b/.github/workflows/weekly-update.yml @@ -65,9 +65,9 @@ jobs: with: gpg-private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }} - - name: Run updating skill with Claude Code - id: claude - timeout-minutes: 15 + - name: Update dependencies (haiku — fast, cheap) + id: update + timeout-minutes: 10 shell: bash env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} @@ -89,8 +89,8 @@ jobs: set +e claude --print \ - --model sonnet \ - --max-turns 25 \ + --model haiku \ + --max-turns 15 \ --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Read" "Write" "Edit" "Glob" "Grep" \ "$(cat <<'PROMPT' /updating @@ -104,7 +104,7 @@ jobs: Update all dependencies to their latest versions. Create one atomic commit per dependency update with a conventional commit message. Leave all changes local — the workflow handles pushing and PR creation. - Skip running builds, tests, and type checks — CI runs those separately. + Do not run builds or tests — the next step handles that. @@ -124,20 +124,122 @@ jobs: echo "success=false" >> $GITHUB_OUTPUT fi + - name: Run tests + id: tests + if: steps.update.outputs.success == 'true' + shell: bash + run: | + if [ -n "$SFW_BIN" ]; then + mkdir -p /tmp/sfw-bin + printf '#!/bin/bash\nexec "%s" pnpm "$@"\n' "$SFW_BIN" > /tmp/sfw-bin/pnpm + chmod +x /tmp/sfw-bin/pnpm + export PATH="/tmp/sfw-bin:$PATH" + fi + + set +e + pnpm run build 2>&1 | tee build-output.log + BUILD_EXIT=$? + if [ "$BUILD_EXIT" -ne 0 ]; then + echo "tests-passed=false" >> $GITHUB_OUTPUT + exit 0 + fi + + pnpm test 2>&1 | tee test-output.log + TEST_EXIT=$? + set -e + + if [ "$TEST_EXIT" -eq 0 ]; then + echo "tests-passed=true" >> $GITHUB_OUTPUT + else + echo "tests-passed=false" >> $GITHUB_OUTPUT + fi + + - name: Fix test failures (sonnet — smarter, escalated) + id: claude + if: steps.update.outputs.success == 'true' && steps.tests.outputs.tests-passed == 'false' + timeout-minutes: 15 + shell: bash + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GITHUB_ACTIONS: 'true' + run: | + if [ -n "$SFW_BIN" ]; then + mkdir -p /tmp/sfw-bin + printf '#!/bin/bash\nexec "%s" pnpm "$@"\n' "$SFW_BIN" > /tmp/sfw-bin/pnpm + chmod +x /tmp/sfw-bin/pnpm + export PATH="/tmp/sfw-bin:$PATH" + fi + + # Collect failure context for the agent. + FAILURE_LOG="" + if [ -f build-output.log ]; then + FAILURE_LOG+="Build output (last 50 lines):"$'\n' + FAILURE_LOG+="$(tail -50 build-output.log)"$'\n\n' + fi + if [ -f test-output.log ]; then + FAILURE_LOG+="Test output (last 100 lines):"$'\n' + FAILURE_LOG+="$(tail -100 test-output.log)"$'\n' + fi + + set +e + claude --print \ + --model sonnet \ + --max-turns 25 \ + --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Read" "Write" "Edit" "Glob" "Grep" \ + "$(cat < + $FAILURE_LOG + + + + Diagnose the failures from the output above. + Fix the code — do not revert the dependency updates. + Run the tests again to verify your fix works. + Create a commit for each fix with a conventional commit message. + + PROMPT + )" \ + 2>&1 | tee -a claude-output.log + CLAUDE_EXIT=${PIPESTATUS[0]} + set -e + + if [ "$CLAUDE_EXIT" -eq 0 ]; then + echo "success=true" >> $GITHUB_OUTPUT + else + echo "success=false" >> $GITHUB_OUTPUT + fi + + - name: Set final status + id: final + if: always() + run: | + # Success if: update succeeded AND (tests passed OR fix succeeded) + if [ "${{ steps.update.outputs.success }}" = "true" ]; then + if [ "${{ steps.tests.outputs.tests-passed }}" = "true" ] || [ "${{ steps.claude.outputs.success }}" = "true" ]; then + echo "success=true" >> $GITHUB_OUTPUT + exit 0 + fi + fi + echo "success=false" >> $GITHUB_OUTPUT + - name: Validate changes id: validate - if: steps.claude.outputs.success == 'true' + if: steps.final.outputs.success == 'true' run: | - # Only allow changes to dependency-related files. + # Allow dependency files + source/test fixes from the fix step. UNEXPECTED="" for file in $(git diff --name-only origin/main..HEAD); do case "$file" in - package.json|*/package.json|pnpm-lock.yaml|*/pnpm-lock.yaml|.npmrc|pnpm-workspace.yaml) ;; + package.json|*/package.json|pnpm-lock.yaml|*/pnpm-lock.yaml) ;; + .npmrc|pnpm-workspace.yaml) ;; + src/*|test/*|*.ts|*.mts|*.js|*.mjs) ;; *) UNEXPECTED="$UNEXPECTED $file" ;; esac done if [ -n "$UNEXPECTED" ]; then - echo "::error::Unexpected files modified by Claude:$UNEXPECTED" + echo "::error::Unexpected files modified:$UNEXPECTED" echo "valid=false" >> $GITHUB_OUTPUT else echo "valid=true" >> $GITHUB_OUTPUT @@ -153,13 +255,13 @@ jobs: fi - name: Push branch - if: steps.claude.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' + if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' env: BRANCH_NAME: ${{ steps.branch.outputs.branch }} run: git push origin "$BRANCH_NAME" - name: Create Pull Request - if: steps.claude.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' + if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' env: GH_TOKEN: ${{ github.token }} BRANCH_NAME: ${{ steps.branch.outputs.branch }} @@ -188,7 +290,7 @@ jobs: --base main - name: Add job summary - if: steps.claude.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' + if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' env: BRANCH_NAME: ${{ steps.branch.outputs.branch }} run: | @@ -198,12 +300,15 @@ jobs: echo "**Branch:** \`${BRANCH_NAME}\`" >> $GITHUB_STEP_SUMMARY echo "**Commits:** ${COMMIT_COUNT}" >> $GITHUB_STEP_SUMMARY - - name: Upload Claude output + - name: Upload logs if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: claude-output-${{ github.run_id }} - path: claude-output.log + name: weekly-update-logs-${{ github.run_id }} + path: | + claude-output.log + build-output.log + test-output.log retention-days: 7 - uses: SocketDev/socket-registry/.github/actions/cleanup-git-signing@6096b06b1790f411714c89c40f72aade2eeaab7c # main From 6dfc746b8a0cc75fc0189fddac04285511ac014c Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 3 Apr 2026 23:58:43 -0400 Subject: [PATCH 6/6] fix(ci): restrict git commands to add/commit/status/diff/log (no push/remote) --- .github/workflows/weekly-update.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/weekly-update.yml b/.github/workflows/weekly-update.yml index 9656bd9ec..d9ef38b4e 100644 --- a/.github/workflows/weekly-update.yml +++ b/.github/workflows/weekly-update.yml @@ -91,7 +91,10 @@ jobs: claude --print \ --model haiku \ --max-turns 15 \ - --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Read" "Write" "Edit" "Glob" "Grep" \ + --allowedTools \ + "Bash(pnpm:*)" \ + "Bash(git add:*)" "Bash(git commit:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git rev-parse:*)" \ + "Read" "Write" "Edit" "Glob" "Grep" \ "$(cat <<'PROMPT' /updating @@ -185,7 +188,10 @@ jobs: claude --print \ --model sonnet \ --max-turns 25 \ - --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Read" "Write" "Edit" "Glob" "Grep" \ + --allowedTools \ + "Bash(pnpm:*)" \ + "Bash(git add:*)" "Bash(git commit:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git rev-parse:*)" \ + "Read" "Write" "Edit" "Glob" "Grep" \ "$(cat <