Skip to content
Closed
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
179 changes: 167 additions & 12 deletions .github/workflows/weekly-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,30 +86,146 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
BRANCH_NAME="weekly-update-$(date +%Y%m%d)"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git"
git checkout -b "$BRANCH_NAME"
echo "branch=$BRANCH_NAME" >> $GITHUB_OUTPUT

- name: Run updating skill with Claude Code
id: claude
timeout-minutes: 30
- uses: SocketDev/socket-registry/.github/actions/setup-git-signing@6096b06b1790f411714c89c40f72aade2eeaab7c # main
with:
gpg-private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}

- name: Update dependencies (haiku — fast, cheap)
id: update
timeout-minutes: 10
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

if [ -z "$ANTHROPIC_API_KEY" ]; then
echo "ANTHROPIC_API_KEY not set - skipping automated update"
echo "success=false" >> $GITHUB_OUTPUT
exit 0
fi

set +e
pnpm exec claude --print --dangerously-skip-permissions \
pnpm exec claude --print \
--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" \
--model haiku \
--max-turns 15 \
"$(cat <<'PROMPT'
/updating

<context>
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.
</context>

<instructions>
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.
Do not run builds or tests — the next step handles that.
</instructions>

<success_criteria>
Each updated dependency has its own commit.
The lockfile is consistent with package.json changes.
No uncommitted changes remain in the working tree.
</success_criteria>
PROMPT
)" \
2>&1 | tee claude-update.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: Run tests
id: tests
if: steps.update.outputs.success == '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

set +e
pnpm build 2>&1 | tee build.log
BUILD_EXIT=${PIPESTATUS[0]}

pnpm test 2>&1 | tee test.log
TEST_EXIT=${PIPESTATUS[0]}
set -e

if [ "$BUILD_EXIT" -eq 0 ] && [ "$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
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

FAILURE_LOG="$(cat build.log test.log 2>/dev/null)"

set +e
pnpm exec claude --print \
--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" \
--model sonnet \
"/updating - Run the updating skill to update all dependencies. Create atomic commits for each update. You are running in CI mode - skip builds and tests. Do not push or create a PR." \
2>&1 | tee claude-output.log
--max-turns 25 \
"$(cat <<PROMPT
<context>
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.
Dependencies were updated in the previous step but build/tests failed.
</context>

<failure_log>
$FAILURE_LOG
</failure_log>

<instructions>
The dependency updates above caused build or test failures.
Diagnose the failures from the logs and fix the code so it builds and tests pass.
Create one atomic commit per fix with a conventional commit message.
Run pnpm build && pnpm test to verify your fixes.
Leave all changes local — the workflow handles pushing and PR creation.
</instructions>

<success_criteria>
pnpm build succeeds.
pnpm test succeeds.
Each fix has its own commit.
No uncommitted changes remain in the working tree.
</success_criteria>
PROMPT
)" \
2>&1 | tee claude-fix.log
CLAUDE_EXIT=${PIPESTATUS[0]}
set -e

Expand All @@ -119,6 +235,38 @@ jobs:
echo "success=false" >> $GITHUB_OUTPUT
fi

- name: Set final status
id: final
if: always()
run: |
if [ "${{ steps.update.outputs.success }}" = "true" ] && [ "${{ steps.tests.outputs.tests-passed }}" = "true" ]; then
echo "success=true" >> $GITHUB_OUTPUT
elif [ "${{ steps.update.outputs.success }}" = "true" ] && [ "${{ steps.claude.outputs.success }}" = "true" ]; then
echo "success=true" >> $GITHUB_OUTPUT
else
echo "success=false" >> $GITHUB_OUTPUT
fi

- name: Validate changes
id: validate
if: steps.final.outputs.success == 'true'
run: |
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) ;;
src/*|test/*) ;;
*.ts|*.mts|*.js|*.mjs) ;;
*) 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: |
Expand All @@ -129,13 +277,13 @@ jobs:
fi

- name: Push branch
if: steps.claude.outputs.success == '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.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 }}
Expand Down Expand Up @@ -164,7 +312,7 @@ jobs:
--base main

- name: Add job summary
if: steps.claude.outputs.success == '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: |
Expand All @@ -179,9 +327,16 @@ jobs:
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: claude-output-${{ github.run_id }}
path: claude-output.log
path: |
claude-update.log
claude-fix.log
build.log
test.log
retention-days: 7

- uses: SocketDev/socket-registry/.github/actions/cleanup-git-signing@6096b06b1790f411714c89c40f72aade2eeaab7c # main
if: always()

notify:
name: Notify results
needs: [check-updates, apply-updates]
Expand Down
5 changes: 2 additions & 3 deletions .npmrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ link-workspace-packages=false
loglevel=error
prefer-workspace-packages=false

# Minimum release age - wait 7 days before installing newly published packages
# pnpm uses minimum-release-age (minutes), npm v11+ uses min-release-age (days)
minimum-release-age=10080
# Minimum release age for npm v11+ (days).
# pnpm equivalent is in pnpm-workspace.yaml (minimumReleaseAge).
min-release-age=7

# Trust policy - prevent downgrade attacks
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ All shared standards (git, testing, code style, cross-platform, CI) defined in s
- Backward Compatibility: 🚨 FORBIDDEN to maintain - actively remove when encountered (see canonical CLAUDE.md)
- Work Safeguards: MANDATORY commit + backup branch before bulk changes
- Safe Deletion: Use `safeDelete()` from `@socketsecurity/lib/fs` (NEVER `fs.rm/rmSync` or `rm -rf`)
- HTTP Requests: NEVER use `fetch()` — use `httpJson`/`httpText`/`httpRequest` from `@socketsecurity/lib/http-request`

### Documentation Policy

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"fix:all": "node scripts/fix.mjs --all",
"lint": "node scripts/lint.mjs",
"lint:all": "node scripts/lint.mjs --all",
"format": "oxfmt --write .",
"format:check": "oxfmt .",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Format check script writes files instead of checking

Medium Severity

The format:check script runs oxfmt . without the --check flag. Since --write is oxfmt's default behavior, this command will silently modify files in place rather than performing a non-destructive formatting check. The --check flag is needed to only verify formatting and return a non-zero exit code on violations.

Fix in Cursor Fix in Web

"// Claude": "",
"claude": "pnpm --filter @socketsecurity/cli run claude --",
"// Type Checking": "",
Expand Down
4 changes: 4 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
settings:
# Wait 7 days (10080 minutes) before installing newly published packages.
minimumReleaseAge: 10080

packages:
- packages/*
- '!packages/package-builder/build'
Expand Down