name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
release:
types: [ published ]
env:
NODE_OPTIONS: '--max-old-space-size=4096'
jobs:
lint-and-format:
name: Code Quality
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Check Node.js version compatibility
run: npm run check-node
- name: Run Biome linting
run: npm run lint
- name: Check code formatting
run: npm run format:check
test:
name: Test Suite
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22, 24]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Build project
run: npm run build
- name: Run unit tests
run: npm run test:unit
- name: Run integration tests
run: npm run test:integration
- name: Run performance tests
run: npm run test:performance
docker-test:
name: Docker Integration
runs-on: ubuntu-latest
needs: [lint-and-format]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Build Docker image
run: |
docker build -f docker/Dockerfile -t browserloop:test .
- name: Test Docker image
run: |
# Test that the Docker image can start and respond to basic commands
echo "Testing Docker container startup..."
# Test 1: Verify the container can start and show help/version
echo "Test 1: Container startup test"
timeout 10 docker run --rm browserloop:test --help || echo "Help command test completed"
# Test 2: Test with a simple echo input (MCP servers respond to stdin)
echo "Test 2: MCP server stdin/stdout test"
echo '{"jsonrpc": "2.0", "id": 1, "method": "ping"}' | timeout 10 docker run --rm -i browserloop:test || echo "MCP server test completed"
# Test 3: Verify the container environment
echo "Test 3: Container environment test"
docker run --rm --entrypoint=/bin/sh browserloop:test -c "node --version && which chromium-browser && whoami"
echo "✅ Docker image tests completed successfully"
- name: Run Docker Integration tests
run: |
# Run Docker-specific integration tests
npm run test:e2e:docker
- name: Run E2E tests
run: |
# Run the actual E2E tests against the built application
npm run test:e2e
docker-build:
name: Docker Build & Scan
runs-on: ubuntu-latest
needs: [test, docker-test]
if: github.event_name == 'push' || github.event_name == 'release'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: browserloop
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha
type=raw,value=latest,enable={{is_default_branch}}
- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
file: docker/Dockerfile
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
outputs: type=oci,dest=/tmp/browserloop.tar
- name: Upload Docker image artifact
uses: actions/upload-artifact@v4
with:
name: docker-image
path: /tmp/browserloop.tar
retention-days: 7
security-scan:
name: Security Scan
runs-on: ubuntu-latest
needs: [lint-and-format]
permissions:
# Required for CodeQL to upload SARIF results
security-events: write
# Required for actions to read repository contents
contents: read
# Required for pull request comments (if needed)
pull-requests: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level=moderate
- name: Run CodeQL Analysis
uses: github/codeql-action/init@v3
with:
languages: typescript
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
release:
name: Release
runs-on: ubuntu-latest
needs: [test, docker-test, security-scan, docker-build]
if: github.event_name == 'release'
permissions:
# Required to update releases and upload assets
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Validate package before release
run: npm run validate:package
- name: Publish to npm registry
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Download Docker image
uses: actions/download-artifact@v4
with:
name: docker-image
path: /tmp
- name: Load Docker image
run: |
# Install skopeo for OCI image handling
sudo apt-get update && sudo apt-get install -y skopeo
# Extract OCI tar and copy to Docker daemon
mkdir -p /tmp/oci-image
tar -xf /tmp/browserloop.tar -C /tmp/oci-image
# Copy OCI image to Docker daemon (using the first available manifest)
skopeo copy oci:/tmp/oci-image docker-daemon:browserloop:latest
# List loaded images for verification
docker images browserloop
- name: Create release assets
run: |
# Create tarball of built project
tar -czf browserloop-${{ github.ref_name }}.tar.gz \
dist/ package.json README.md docs/
- name: Upload release assets
uses: softprops/action-gh-release@v2
with:
files: browserloop-${{ github.ref_name }}.tar.gz
token: ${{ secrets.GITHUB_TOKEN }}
performance-benchmark:
name: Performance Benchmark
runs-on: ubuntu-latest
needs: [test]
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Build project
run: npm run build
- name: Run performance benchmarks
run: |
npm run test:performance > performance-results.txt 2>&1 || true
- name: Upload performance results
uses: actions/upload-artifact@v4
with:
name: performance-results
path: performance-results.txt
retention-days: 30