forked from claude-did-this/claude-hub
Consolidate GitHub workflows to fix concurrent PR review issues
- Create dedicated PR workflow (pr.yml) with comprehensive CI checks - Remove pull_request triggers from ci.yml, security.yml, and deploy.yml - Remove develop branch references for trunk-based development - Include security scans, CodeQL analysis, and Docker builds in PR workflow - Prevent automated PR review from triggering multiple times 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -2,9 +2,7 @@ name: CI Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
NODE_VERSION: '20'
|
||||
|
||||
3
.github/workflows/deploy.yml
vendored
3
.github/workflows/deploy.yml
vendored
@@ -4,11 +4,8 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
tags:
|
||||
- 'v*.*.*' # Semantic versioning tags (v1.0.0, v2.1.3, etc.)
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
|
||||
319
.github/workflows/pr.yml
vendored
Normal file
319
.github/workflows/pr.yml
vendored
Normal file
@@ -0,0 +1,319 @@
|
||||
name: Pull Request CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
NODE_VERSION: '20'
|
||||
|
||||
jobs:
|
||||
# Lint job - fast and independent
|
||||
lint:
|
||||
name: Lint & Format Check
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'package-lock.json'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --prefer-offline --no-audit
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint:check || echo "No lint script found, skipping"
|
||||
|
||||
- name: Check formatting
|
||||
run: npm run format:check || echo "No format script found, skipping"
|
||||
|
||||
# Unit tests - fastest test suite
|
||||
test-unit:
|
||||
name: Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x, 20.x]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'package-lock.json'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --prefer-offline --no-audit
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test:unit
|
||||
env:
|
||||
NODE_ENV: test
|
||||
BOT_USERNAME: '@TestBot'
|
||||
GITHUB_WEBHOOK_SECRET: 'test-secret'
|
||||
GITHUB_TOKEN: 'test-token'
|
||||
|
||||
- name: Upload coverage
|
||||
if: matrix.node-version == '20.x'
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
file: ./coverage/lcov.info
|
||||
flags: unittests
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
|
||||
# Integration tests - moderate complexity
|
||||
test-integration:
|
||||
name: Integration Tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'package-lock.json'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --prefer-offline --no-audit
|
||||
|
||||
- name: Run integration tests
|
||||
run: npm run test:integration || echo "No integration tests found, skipping"
|
||||
env:
|
||||
NODE_ENV: test
|
||||
BOT_USERNAME: '@TestBot'
|
||||
GITHUB_WEBHOOK_SECRET: 'test-secret'
|
||||
GITHUB_TOKEN: 'test-token'
|
||||
|
||||
# Security scans for PRs
|
||||
security:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Full history for secret scanning
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'package-lock.json'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --prefer-offline --no-audit
|
||||
|
||||
- name: Run npm audit
|
||||
run: |
|
||||
npm audit --audit-level=moderate || {
|
||||
echo "::warning::npm audit found vulnerabilities"
|
||||
exit 0 # Don't fail the build, but warn
|
||||
}
|
||||
|
||||
- name: Check for known vulnerabilities
|
||||
run: npm run security:audit || echo "::warning::Security audit script failed"
|
||||
|
||||
- name: Run credential audit script
|
||||
run: |
|
||||
if [ -f "./scripts/security/credential-audit.sh" ]; then
|
||||
./scripts/security/credential-audit.sh || {
|
||||
echo "::error::Credential audit failed"
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
echo "::warning::Credential audit script not found"
|
||||
fi
|
||||
|
||||
- name: TruffleHog Secret Scan
|
||||
uses: trufflesecurity/trufflehog@main
|
||||
with:
|
||||
path: ./
|
||||
base: ${{ github.event.pull_request.base.sha }}
|
||||
head: ${{ github.event.pull_request.head.sha }}
|
||||
extra_args: --debug --only-verified
|
||||
|
||||
- name: Check for high-risk files
|
||||
run: |
|
||||
# Check for files that commonly contain secrets
|
||||
risk_files=$(find . -type f \( \
|
||||
-name "*.pem" -o \
|
||||
-name "*.key" -o \
|
||||
-name "*.p12" -o \
|
||||
-name "*.pfx" -o \
|
||||
-name "*secret*" -o \
|
||||
-name "*password*" -o \
|
||||
-name "*credential*" \
|
||||
\) -not -path "*/node_modules/*" -not -path "*/.git/*" | head -20)
|
||||
|
||||
if [ -n "$risk_files" ]; then
|
||||
echo "⚠️ Found potentially sensitive files:"
|
||||
echo "$risk_files"
|
||||
echo "::warning::High-risk files detected. Please ensure they don't contain secrets."
|
||||
fi
|
||||
|
||||
# CodeQL analysis for PRs
|
||||
codeql:
|
||||
name: CodeQL Analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: javascript
|
||||
config-file: ./.github/codeql-config.yml
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:javascript"
|
||||
|
||||
# Check if Docker-related files changed
|
||||
changes:
|
||||
name: Detect Changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
docker: ${{ steps.changes.outputs.docker }}
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
docker:
|
||||
- 'Dockerfile*'
|
||||
- 'scripts/**'
|
||||
- '.dockerignore'
|
||||
- 'claude-config*'
|
||||
src:
|
||||
- 'src/**'
|
||||
- 'package*.json'
|
||||
|
||||
# Docker build test for PRs (build only, don't push)
|
||||
docker-build:
|
||||
name: Docker Build Test
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.changes.outputs.docker == 'true' || needs.changes.outputs.src == 'true'
|
||||
needs: [test-unit, lint, changes]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build main Docker image (test only)
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: false
|
||||
load: true
|
||||
tags: claude-github-webhook:pr-test
|
||||
cache-from: type=gha,scope=pr-main
|
||||
cache-to: type=gha,mode=max,scope=pr-main
|
||||
platforms: linux/amd64
|
||||
|
||||
- name: Build Claude Code Docker image (test only)
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.claudecode
|
||||
push: false
|
||||
load: true
|
||||
tags: claude-code-runner:pr-test
|
||||
cache-from: type=gha,scope=pr-claudecode
|
||||
cache-to: type=gha,mode=max,scope=pr-claudecode
|
||||
platforms: linux/amd64
|
||||
|
||||
- name: Test Docker containers
|
||||
run: |
|
||||
# Test main container starts correctly
|
||||
docker run --name test-webhook -d -p 3003:3002 \
|
||||
-e NODE_ENV=test \
|
||||
-e BOT_USERNAME=@TestBot \
|
||||
-e GITHUB_WEBHOOK_SECRET=test-secret \
|
||||
-e GITHUB_TOKEN=test-token \
|
||||
claude-github-webhook:pr-test
|
||||
|
||||
# Wait for container to start
|
||||
sleep 10
|
||||
|
||||
# Test health endpoint
|
||||
curl -f http://localhost:3003/health || exit 1
|
||||
|
||||
# Cleanup
|
||||
docker stop test-webhook
|
||||
docker rm test-webhook
|
||||
|
||||
- name: Docker security scan
|
||||
if: contains(github.event.head_commit.modified, 'Dockerfile')
|
||||
run: |
|
||||
# Run Hadolint on Dockerfile
|
||||
docker run --rm -i hadolint/hadolint < Dockerfile || echo "::warning::Dockerfile linting issues found"
|
||||
|
||||
# Run Trivy scan on built image
|
||||
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v $HOME/Library/Caches:/root/.cache/ \
|
||||
aquasec/trivy:latest image --exit-code 0 --severity HIGH,CRITICAL \
|
||||
claude-github-webhook:pr-test || echo "::warning::Security vulnerabilities found"
|
||||
|
||||
# Summary job that all others depend on
|
||||
pr-summary:
|
||||
name: PR Summary
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, test-unit, test-integration, security, codeql, docker-build]
|
||||
if: always()
|
||||
|
||||
steps:
|
||||
- name: Check job statuses
|
||||
run: |
|
||||
echo "## Pull Request CI Summary"
|
||||
echo "- Lint & Format: ${{ needs.lint.result }}"
|
||||
echo "- Unit Tests: ${{ needs.test-unit.result }}"
|
||||
echo "- Integration Tests: ${{ needs.test-integration.result }}"
|
||||
echo "- Security Scan: ${{ needs.security.result }}"
|
||||
echo "- CodeQL Analysis: ${{ needs.codeql.result }}"
|
||||
echo "- Docker Build: ${{ needs.docker-build.result }}"
|
||||
|
||||
# Check for any failures
|
||||
if [[ "${{ needs.lint.result }}" == "failure" ]] || \
|
||||
[[ "${{ needs.test-unit.result }}" == "failure" ]] || \
|
||||
[[ "${{ needs.test-integration.result }}" == "failure" ]] || \
|
||||
[[ "${{ needs.security.result }}" == "failure" ]] || \
|
||||
[[ "${{ needs.codeql.result }}" == "failure" ]] || \
|
||||
[[ "${{ needs.docker-build.result }}" == "failure" ]]; then
|
||||
echo "::error::One or more CI jobs failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ All CI checks passed!"
|
||||
4
.github/workflows/security.yml
vendored
4
.github/workflows/security.yml
vendored
@@ -2,9 +2,7 @@ name: Security Scans
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
# Run daily at 2 AM UTC
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
Reference in New Issue
Block a user