name: Continuous Integration
on:
pull_request:
branches: [ main, develop ]
push:
branches: [ main, develop ]
permissions:
contents: read # Required to checkout code
actions: read # Required to read workflow status
checks: write # Required to write check results
security-events: write # Required for security scanning
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Set up Node.js (for DXT CLI)
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install DXT CLI
run: npm install -g @anthropic-ai/dxt
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install pre-commit black
- name: Validate context files structure
run: |
echo "π Validating context file structure..."
python scripts/validate_contexts.py contexts/*.json
- name: Test build process
run: |
echo "π§ͺ Testing build process..."
python scripts/test_build.py
- name: Check version consistency
run: |
echo "π Checking version consistency..."
python scripts/check_versions.py
- name: Validate JSON syntax
run: |
echo "π Validating JSON syntax..."
for json_file in contexts/*.json; do
if [ -f "$json_file" ]; then
echo "Checking: $(basename $json_file)"
python -m json.tool "$json_file" > /dev/null
fi
done
echo "β
All JSON files are valid"
- name: Test full build process
run: |
echo "π¨ Testing full build process..."
python scripts/build_dxt.py --version "test-$(date +%s)"
# Verify package was created
PACKAGE_FILE=$(ls mcp-context-provider-test-*.dxt | head -1)
if [ ! -f "$PACKAGE_FILE" ]; then
echo "β Test package not created"
exit 1
fi
echo "β
Test package created: $PACKAGE_FILE"
# Test package unpack
mkdir -p test-unpack
dxt unpack "$PACKAGE_FILE" test-unpack/
# Verify unpacked structure
REQUIRED_FILES=(
"test-unpack/server/context_provider_server.py"
"test-unpack/contexts"
"test-unpack/manifest.json"
)
for file in "${REQUIRED_FILES[@]}"; do
if [ ! -e "$file" ]; then
echo "β Missing file after unpack: $file"
exit 1
fi
done
# Count context files
CONTEXT_COUNT=$(find test-unpack/contexts -name "*.json" | wc -l)
echo "β
Package test passed - $CONTEXT_COUNT context files found"
# Cleanup
rm -f "$PACKAGE_FILE"
rm -rf test-unpack/
- name: Code quality check
run: |
echo "π¨ Checking Python code quality..."
# Check if Python files exist and run black on them
if ls *.py 1> /dev/null 2>&1; then
black --check --diff *.py
fi
if ls scripts/*.py 1> /dev/null 2>&1; then
black --check --diff scripts/*.py
fi
echo "β
Code quality check passed"
compatibility-test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.10', '3.11', '3.12']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Set up Node.js (for DXT CLI)
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install DXT CLI
run: npm install -g @anthropic-ai/dxt
- name: Test basic validation
run: |
echo "π§ͺ Testing basic validation on ${{ matrix.os }} with Python ${{ matrix.python-version }}"
python scripts/validate_contexts.py contexts/*.json
- name: Test build script syntax
run: |
echo "π Testing build script syntax..."
python -m py_compile scripts/build_dxt.py
echo "β
Build script syntax check passed"
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: TruffleHog secret scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
head: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
extra_args: --debug
- name: Gitleaks secret scan
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Custom pattern check
run: |
echo "π Scanning for project-specific secret patterns..."
EXIT_CODE=0
# Azure Subscription IDs (real UUIDs, not placeholders)
if grep -rn --include='*.json' --include='*.py' --include='*.yaml' --include='*.yml' --include='*.md' \
-E '\-\-subscription\s+[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' \
--exclude-dir=.git --exclude='.gitleaks.toml' . ; then
echo "β Found Azure Subscription IDs"
EXIT_CODE=1
fi
# Internal RFC1918 IPs in connection contexts
if grep -rn --include='*.json' --include='*.py' \
-E '(host|server|address|endpoint|ssh).{0,10}(10\.[0-9]+\.[0-9]+\.[0-9]+|172\.(1[6-9]|2[0-9]|3[01])\.[0-9]+\.[0-9]+|192\.168\.[0-9]+\.[0-9]+)' \
--exclude-dir=.git --exclude='.gitleaks.toml' . ; then
echo "β Found internal IPs in connection contexts"
EXIT_CODE=1
fi
# Company domains
if grep -rn --include='*.json' --include='*.py' \
-iE '[a-z0-9.-]+\.(jivs\.com|datamigration\.ch)' \
--exclude-dir=.git --exclude='.gitleaks.toml' . ; then
echo "β Found company-specific domains"
EXIT_CODE=1
fi
# Azure Resource IDs with real subscriptions
if grep -rn --include='*.json' --include='*.py' \
-E '/subscriptions/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/' \
--exclude-dir=.git --exclude='.gitleaks.toml' . ; then
echo "β Found Azure Resource IDs with real subscription UUIDs"
EXIT_CODE=1
fi
if [ $EXIT_CODE -eq 0 ]; then
echo "β
No project-specific secret patterns found"
fi
exit $EXIT_CODE
- name: Check for sensitive files
run: |
echo "π Checking for sensitive files..."
SENSITIVE_PATTERNS=(
"*.key"
"*.pem"
"*.p12"
"*.pfx"
"*password*"
"*secret*"
"*.env"
".env.*"
"credentials.json"
"service-account*.json"
)
for pattern in "${SENSITIVE_PATTERNS[@]}"; do
if find . -name "$pattern" -not -path "./.git/*" | grep -q .; then
echo "β Found potentially sensitive files matching: $pattern"
find . -name "$pattern" -not -path "./.git/*"
exit 1
fi
done
echo "β
No sensitive files detected"