Skip to content

updating workflows #123

updating workflows

updating workflows #123

name: Build and Test MarchProxy

Check failure on line 1 in .github/workflows/build-and-test.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/build-and-test.yml

Invalid workflow file

(Line: 458, Col: 1): Unexpected value 'schedule'
on:
push:
branches: [ main, develop, 'feature/*', 'release/*' ]
tags: [ 'v*' ]
pull_request:
branches: [ main, develop ]
env:
REGISTRY: ghcr.io
IMAGE_NAME_MANAGER: ${{ github.repository }}/manager
IMAGE_NAME_PROXY: ${{ github.repository }}/proxy
jobs:
# Test Go proxy application
test-proxy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: '1.22'
- name: Cache Go modules
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Install eBPF dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev linux-headers-$(uname -r) || true
- name: Build proxy
working-directory: ./proxy
run: |
go mod tidy
go build -v ./...
- name: Test proxy
working-directory: ./proxy
run: |
go test -v ./...
- name: Run security scan
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
if: false # Disabled for now, enable when ready
with:
sarif_file: 'security-scan-results.sarif'
# Test Python manager application
test-manager:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: marchproxy_test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: '3.12'
- name: Cache Python packages
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install Python dependencies
working-directory: ./manager
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest pytest-cov black flake8 mypy
- name: Lint Python code
working-directory: ./manager
run: |
black --check --diff .
flake8 . --max-line-length=100 --extend-ignore=E203,W503
mypy apps/marchproxy/ --ignore-missing-imports || true
- name: Test manager
working-directory: ./manager
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/marchproxy_test
JWT_SECRET: test-secret-key-for-ci
run: |
python -m pytest tests/ -v --cov=apps/marchproxy/ || true
# Note: Tests may not exist yet, so we allow failure
# Build single arch per platform (truly parallel)
build-platform:
needs: [test-proxy, test-manager]
runs-on: ubuntu-latest
strategy:
matrix:
component: [manager, proxy]
platform: [linux/amd64, linux/arm64]
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Log in to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate platform tag
id: platform-tag
env:
PLATFORM: ${{ matrix.platform }}
run: |
ARCH=$(echo "${PLATFORM}" | cut -d'/' -f2)
echo "arch=${ARCH}" >> $GITHUB_OUTPUT
- name: Extract image name
id: image-name
run: |
if [ "${{ matrix.component }}" = "manager" ]; then
echo "name=${{ env.IMAGE_NAME_MANAGER }}" >> $GITHUB_OUTPUT
else
echo "name=${{ env.IMAGE_NAME_PROXY }}" >> $GITHUB_OUTPUT
fi
- name: Extract version and build tag
id: version
env:
REF: ${{ github.ref }}
REF_NAME: ${{ github.ref_name }}
run: |
VERSION="${REF_NAME}"
EPOCH=$(date +%s)
if [[ "${REF}" == "refs/tags/v"* ]]; then
# Release tag: v1.2.3
echo "version=${VERSION}" >> $GITHUB_OUTPUT
elif [[ "${REF}" == "refs/heads/release/"* ]]; then
# Release branch: release/v1.x.x -> v1.x.x-beta
echo "version=${VERSION}-beta" >> $GITHUB_OUTPUT
echo "epoch-tag=beta-${EPOCH}" >> $GITHUB_OUTPUT
elif [[ "${REF}" == "refs/heads/main" ]]; then
# Main branch: gamma
echo "version=gamma-${EPOCH}" >> $GITHUB_OUTPUT
else
# Feature/develop branches: alpha
echo "version=alpha-${EPOCH}" >> $GITHUB_OUTPUT
fi
- name: Build and push Docker image (platform-specific)
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
with:
context: .
file: ./docker/${{ matrix.component }}/Dockerfile
platforms: ${{ matrix.platform }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ env.REGISTRY }}/${{ steps.image-name.outputs.name }}:${{ steps.version.outputs.version }}-${{ steps.platform-tag.outputs.arch }}
labels: |
org.opencontainers.image.version=${{ steps.version.outputs.version }}
org.opencontainers.image.revision=${{ github.sha }}
target: production
cache-from: type=gha,scope=${{ matrix.component }}-${{ matrix.platform }}
cache-to: type=gha,scope=${{ matrix.component }}-${{ matrix.platform }},mode=max
build-args: |
VERSION=${{ github.ref_name }}
VCS_REF=${{ github.sha }}
# Merge multi-arch manifests
merge-manifests:
needs: build-platform
runs-on: ubuntu-latest
strategy:
matrix:
component: [manager, proxy]
if: github.event_name != 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Log in to Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Extract image name
id: image-name
run: |
if [ "${{ matrix.component }}" = "manager" ]; then
echo "name=${{ env.IMAGE_NAME_MANAGER }}" >> $GITHUB_OUTPUT
else
echo "name=${{ env.IMAGE_NAME_PROXY }}" >> $GITHUB_OUTPUT
fi
- name: Determine manifest tags and source version
id: manifest
env:
REF: ${{ github.ref }}
REF_NAME: ${{ github.ref_name }}
REGISTRY: ${{ env.REGISTRY }}
IMAGE_NAME: ${{ steps.image-name.outputs.name }}
run: |
VERSION="${REF_NAME}"
EPOCH=$(date +%s)
TAGS=""
SOURCE_VERSION=""
if [[ "${REF}" == "refs/tags/v"* ]]; then
# Release tag: v1.2.3 -> tag as v1.2.3 and latest
SOURCE_VERSION="${VERSION}"
TAGS="${REGISTRY}/${IMAGE_NAME}:${VERSION} ${REGISTRY}/${IMAGE_NAME}:latest"
elif [[ "${REF}" == "refs/heads/release/"* ]]; then
# Release branch: release/v1.x.x -> tag as v1.x.x-beta and beta-<epoch>
SOURCE_VERSION="${VERSION}-beta"
TAGS="${REGISTRY}/${IMAGE_NAME}:${VERSION}-beta ${REGISTRY}/${IMAGE_NAME}:beta-${EPOCH}"
elif [[ "${REF}" == "refs/heads/main" ]]; then
# Main branch: gamma-<epoch>
SOURCE_VERSION="gamma-${EPOCH}"
TAGS="${REGISTRY}/${IMAGE_NAME}:gamma-${EPOCH}"
else
# Feature/develop branches: alpha-<epoch>
SOURCE_VERSION="alpha-${EPOCH}"
TAGS="${REGISTRY}/${IMAGE_NAME}:alpha-${EPOCH}"
fi
echo "source-version=${SOURCE_VERSION}" >> $GITHUB_OUTPUT
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
- name: Create and push manifest
env:
REGISTRY: ${{ env.REGISTRY }}
IMAGE_NAME: ${{ steps.image-name.outputs.name }}
SOURCE_VERSION: ${{ steps.manifest.outputs.source-version }}
TAGS: ${{ steps.manifest.outputs.tags }}
run: |
# Create manifest list from amd64 and arm64 images
docker buildx imagetools create -t "${REGISTRY}/${IMAGE_NAME}:${SOURCE_VERSION}" \
"${REGISTRY}/${IMAGE_NAME}:${SOURCE_VERSION}-amd64" \
"${REGISTRY}/${IMAGE_NAME}:${SOURCE_VERSION}-arm64"
# Add additional tags
for TAG in ${TAGS}; do
if [ "${TAG}" != "${REGISTRY}/${IMAGE_NAME}:${SOURCE_VERSION}" ]; then
docker buildx imagetools create -t "${TAG}" \
"${REGISTRY}/${IMAGE_NAME}:${SOURCE_VERSION}-amd64" \
"${REGISTRY}/${IMAGE_NAME}:${SOURCE_VERSION}-arm64"
fi
done
# Integration testing with multi-arch images
integration-test:
needs: [merge-manifests]
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Log in to Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run integration tests
run: |
# Update docker-compose to use built images
export MANAGER_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME_MANAGER }}:${{ github.ref_name }}"
export PROXY_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME_PROXY }}:${{ github.ref_name }}"
# Start services
docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d
# Wait for services to be healthy
timeout 300s bash -c 'until docker-compose ps | grep -q "healthy"; do sleep 10; done'
# Run basic connectivity tests
curl -f http://localhost:8000/healthz || exit 1
curl -f http://localhost:8081/healthz || exit 1
# Cleanup
docker-compose down -v
# Security scanning
security-scan:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
if: always()
with:
sarif_file: 'trivy-results.sarif'
# Release creation (only on tags)
release:
needs: [integration-test, security-scan]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Generate release notes
id: release_notes
run: |
# Extract version from tag
VERSION=${GITHUB_REF#refs/tags/}
echo "version=$VERSION" >> $GITHUB_OUTPUT
# Generate release notes (basic version)
cat > release_notes.md << EOF
# MarchProxy $VERSION
## Docker Images
### Manager (Multi-Architecture)
- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME_MANAGER }}:$VERSION\`
- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME_MANAGER }}:latest\`
### Proxy (Multi-Architecture)
- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME_PROXY }}:$VERSION\`
- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME_PROXY }}:latest\`
## Supported Architectures
- linux/amd64 (Intel/AMD 64-bit)
- linux/arm64 (ARM 64-bit, Apple Silicon, AWS Graviton)
- linux/arm/v7 (ARM 32-bit, Raspberry Pi)
## Quick Start
\`\`\`bash
# Download docker-compose.yml
curl -L -O https://raw.githubusercontent.com/$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')/$VERSION/docker-compose.yml
# Start MarchProxy
docker-compose up -d
# Access web interface
open http://localhost:8000
\`\`\`
## What's Changed
* See commit history for detailed changes
* Full system capabilities: proxy management, clustering, authentication
* Enterprise features available with valid license
EOF
- name: Create GitHub Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
with:
body_path: release_notes.md
draft: false
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }}
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Cleanup old images (runs weekly)
cleanup:
runs-on: ubuntu-latest
if: github.event_name == 'schedule'
steps:
- name: Cleanup old container images
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const packages = await github.rest.packages.listPackagesForOrganization({
org: context.repo.owner,
package_type: 'container',
visibility: 'private'
});
for (const pkg of packages.data) {
if (pkg.name.includes('marchproxy')) {
const versions = await github.rest.packages.getAllPackageVersionsForPackageOwnedByOrg({
org: context.repo.owner,
package_type: 'container',
package_name: pkg.name
});
// Keep latest 10 versions, delete older ones
const oldVersions = versions.data.slice(10);
for (const version of oldVersions) {
await github.rest.packages.deletePackageVersionForOrg({
org: context.repo.owner,
package_type: 'container',
package_name: pkg.name,
package_version_id: version.id
});
}
}
}
# Schedule cleanup weekly
schedule:
- cron: '0 2 * * 0' # Sunday at 2 AM UTC