Skip to content

Refine MCP Client architecture diagram #873

Refine MCP Client architecture diagram

Refine MCP Client architecture diagram #873

Workflow file for this run

# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
# SPDX-License-Identifier: MIT
name: Test Electron Framework and Apps
on:
workflow_call:
push:
branches: ["main"]
pull_request:
branches: ["main"]
types: [opened, synchronize, reopened, ready_for_review]
merge_group:
workflow_dispatch:
# Cancel in-progress runs when a new run is triggered
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
jobs:
test-electron-framework:
name: Test Electron Framework
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
steps:
- uses: actions/checkout@v6
- name: Free disk space
uses: ./.github/actions/free-disk-space
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: tests/electron/package.json
- name: Install test dependencies
run: |
cd tests/electron
npm ci
- name: Run Electron framework unit tests
run: |
cd tests/electron
npm test
- name: Upload test coverage
if: always()
uses: actions/upload-artifact@v6
with:
name: electron-framework-coverage
path: tests/electron/coverage/
retention-days: 7
test-apps-integration:
name: Test Apps Integration
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
steps:
- uses: actions/checkout@v6
- name: Free disk space
uses: ./.github/actions/free-disk-space
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: tests/electron/package.json
- name: Install test dependencies
run: |
cd tests/electron
npm ci
- name: Run app integration tests
run: |
cd tests/electron
# Run structure tests for all apps and framework integration
npm test -- test_electron_jira_app.js test_electron_example_app.js test_electron_emr_dashboard.js test_electron_framework_integration.js
- name: Upload test results
if: always()
uses: actions/upload-artifact@v6
with:
name: apps-integration-test-results
path: tests/electron/coverage/
retention-days: 7
test-apps-functional:
name: Test Apps Functionality
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
- name: Free disk space
uses: ./.github/actions/free-disk-space
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Install test dependencies
run: |
cd tests/electron
npm ci
- name: Run functional tests (builds and installs apps)
run: |
cd tests/electron
# These tests actually install deps and try to build the apps
npm test -- test_electron_functional.js --verbose
timeout-minutes: 15
- name: Upload functional test results
if: always()
uses: actions/upload-artifact@v6
with:
name: apps-functional-test-results
path: tests/electron/coverage/
retention-days: 7
test-apps-build:
name: Test Apps Build (${{ matrix.app.name }})
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
strategy:
fail-fast: false
matrix:
app:
- name: jira
path: src/gaia/apps/jira/webui
has_package_script: true
- name: example
path: src/gaia/apps/example/webui
has_package_script: true
- name: emr-dashboard
path: src/gaia/agents/emr/dashboard/electron
has_package_script: false
steps:
- uses: actions/checkout@v6
- name: Free disk space
uses: ./.github/actions/free-disk-space
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: ${{ matrix.app.path }}/package-lock.json
- name: Install app dependencies
run: |
cd ${{ matrix.app.path }}
npm ci --prefix .
- name: Check for high-severity vulnerabilities
run: |
cd ${{ matrix.app.path }}
# Allow command to fail but capture output
npm audit --json > audit-results.json || true
# Check for high/critical vulnerabilities
HIGH=$(cat audit-results.json | jq -r '.metadata.vulnerabilities.high // 0')
CRITICAL=$(cat audit-results.json | jq -r '.metadata.vulnerabilities.critical // 0')
echo "High severity vulnerabilities: $HIGH"
echo "Critical severity vulnerabilities: $CRITICAL"
if [ "$HIGH" -gt 0 ] || [ "$CRITICAL" -gt 0 ]; then
echo "::warning::Found $HIGH high and $CRITICAL critical vulnerabilities in ${{ matrix.app.name }}"
cat audit-results.json | jq '.vulnerabilities'
fi
continue-on-error: true
- name: Verify package scripts
run: |
cd ${{ matrix.app.path }}
npm run --if-present lint || echo "No lint script"
- name: Test app packaging (Linux)
if: matrix.app.has_package_script
run: |
cd ${{ matrix.app.path }}
# Package the app for Linux - validates dependencies work together
# Note: This runs on ubuntu-latest, so only Linux packaging is tested.
# Windows/macOS packaging is tested separately in build-electron-apps.yml
# BLOCKING: Packaging failures indicate broken dependencies from Dependabot updates
npm run package
env:
# Electron Forge will auto-detect Linux platform
DEBUG: electron-forge:*
- name: Verify build artifacts exist
if: matrix.app.has_package_script
run: |
cd ${{ matrix.app.path }}
if [ -d "out" ]; then
echo "✅ Build artifacts created successfully"
ls -R out/ | head -20
else
echo "❌ No build artifacts found - packaging failed"
echo "This indicates a dependency compatibility issue from the update."
exit 1
fi
- name: Validate Electron can be required (EMR Dashboard)
if: matrix.app.name == 'emr-dashboard'
run: |
cd ${{ matrix.app.path }}
# Verify Electron module can be loaded
node -e "require('electron'); console.log('✅ Electron module loads successfully')"
dependency-audit:
name: Audit Dependencies
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
strategy:
matrix:
package:
- name: electron-framework
path: src/gaia/electron
- name: jira-app
path: src/gaia/apps/jira/webui
- name: example-app
path: src/gaia/apps/example/webui
- name: emr-dashboard
path: src/gaia/agents/emr/dashboard/electron
steps:
- uses: actions/checkout@v6
- name: Free disk space
uses: ./.github/actions/free-disk-space
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Audit ${{ matrix.package.name }} dependencies
run: |
cd ${{ matrix.package.path }}
npm audit --audit-level=high || true
npm audit --json > audit-results.json || true
continue-on-error: true
- name: Upload audit results
if: always()
uses: actions/upload-artifact@v6
with:
name: audit-${{ matrix.package.name }}
path: ${{ matrix.package.path }}/audit-results.json
retention-days: 30
# Headless E2E tests - actually launches Electron apps to catch runtime breakage
test-electron-runtime:
name: Test Electron Runtime (${{ matrix.app.name }})
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
app:
- name: jira
path: src/gaia/apps/jira/webui
- name: example
path: src/gaia/apps/example/webui
steps:
- uses: actions/checkout@v6
- name: Free disk space
uses: ./.github/actions/free-disk-space
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: ${{ matrix.app.path }}/package-lock.json
- name: Install app dependencies
run: |
cd ${{ matrix.app.path }}
npm ci --prefix .
- name: Install xvfb for headless display
run: |
sudo apt-get update
sudo apt-get install -y xvfb
- name: Test Electron app launches (headless)
run: |
cd ${{ matrix.app.path }}
# Start xvfb for headless display
export DISPLAY=:99
Xvfb :99 -screen 0 1024x768x24 &
sleep 2
# Create a test script in app directory so it can find electron in node_modules
cat > test-launch.js << 'EOF'
const { spawn } = require('child_process');
const path = require('path');
/**
* Electron App Launch Test
*
* This script launches an Electron app in headless mode and verifies
* it starts without crashing. Used to catch breaking changes from
* Dependabot dependency updates.
*
* Timeout Configuration:
* - ELECTRON_LAUNCH_TIMEOUT_MS: Time to wait for app initialization (default: 5000ms)
* - 5 seconds is sufficient for most GAIA apps which have minimal startup logic
* - Apps with heavy initialization (database, network) may need longer timeouts
* - The timeout only needs to be long enough to detect startup crashes
*/
const LAUNCH_TIMEOUT_MS = parseInt(process.env.ELECTRON_LAUNCH_TIMEOUT_MS || '5000', 10);
console.log('Starting Electron app launch test...');
console.log(`Launch timeout: ${LAUNCH_TIMEOUT_MS}ms`);
const electronPath = require('electron');
const appPath = process.cwd();
// Get the main entry point from package.json
const pkg = require(path.join(appPath, 'package.json'));
const mainFile = pkg.main || 'src/main.js';
console.log(`Launching: ${electronPath} ${mainFile}`);
const proc = spawn(electronPath, [mainFile], {
cwd: appPath,
env: {
...process.env,
ELECTRON_DISABLE_SANDBOX: '1',
ELECTRON_NO_ATTACH_CONSOLE: '1',
GAIA_TEST_MODE: '1'
},
stdio: ['ignore', 'pipe', 'pipe']
});
let stdout = '';
let stderr = '';
let crashed = false;
proc.stdout.on('data', (data) => {
stdout += data.toString();
console.log('[stdout]', data.toString().trim());
});
proc.stderr.on('data', (data) => {
stderr += data.toString();
const msg = data.toString();
console.log('[stderr]', msg.trim());
// Check for crash indicators
if (msg.includes('crashed') || msg.includes('SIGSEGV') || msg.includes('SIGABRT')) {
crashed = true;
}
});
// Wait for app to initialize, then terminate
// This timeout is configurable via ELECTRON_LAUNCH_TIMEOUT_MS
setTimeout(() => {
if (!crashed) {
console.log('✅ App launched successfully without crashing');
proc.kill('SIGTERM');
process.exit(0);
} else {
console.log('❌ App crashed during startup');
proc.kill('SIGTERM');
process.exit(1);
}
}, LAUNCH_TIMEOUT_MS);
proc.on('error', (err) => {
console.log('❌ Failed to start Electron:', err.message);
process.exit(1);
});
proc.on('exit', (code, signal) => {
if (code !== null && code !== 0 && !signal) {
console.log(`❌ Electron exited with code ${code}`);
process.exit(1);
}
});
EOF
node test-launch.js
rm test-launch.js
timeout-minutes: 3
test-summary:
name: Test Summary
runs-on: ubuntu-latest
if: always()
needs: [test-electron-framework, test-apps-integration, test-apps-functional, test-apps-build, dependency-audit, test-electron-runtime]
steps:
- name: Check test results
run: |
echo "=========================================="
echo " ELECTRON TEST RESULTS "
echo "=========================================="
echo ""
echo "Test Electron Framework: ${{ needs.test-electron-framework.result }}"
echo "Test Apps Integration: ${{ needs.test-apps-integration.result }}"
echo "Test Apps Functionality: ${{ needs.test-apps-functional.result }}"
echo "Test Apps Build: ${{ needs.test-apps-build.result }}"
echo "Test Electron Runtime: ${{ needs.test-electron-runtime.result }}"
echo "Dependency Audit: ${{ needs.dependency-audit.result }}"
echo ""
FAILED=false
if [[ "${{ needs.test-electron-framework.result }}" == "failure" ]]; then
echo "❌ FAILED: Electron Framework tests"
FAILED=true
fi
if [[ "${{ needs.test-apps-integration.result }}" == "failure" ]]; then
echo "❌ FAILED: Apps Integration tests"
FAILED=true
fi
if [[ "${{ needs.test-apps-functional.result }}" == "failure" ]]; then
echo "❌ FAILED: Apps Functional tests"
FAILED=true
fi
if [[ "${{ needs.test-apps-build.result }}" == "failure" ]]; then
echo "❌ FAILED: Apps Build tests - dependencies may be broken"
FAILED=true
fi
if [[ "${{ needs.test-electron-runtime.result }}" == "failure" ]]; then
echo "❌ FAILED: Electron Runtime tests - apps crash on startup"
FAILED=true
fi
echo ""
if [[ "$FAILED" == "true" ]]; then
echo "=========================================="
echo " ❌ SOME ELECTRON TESTS FAILED "
echo "=========================================="
echo ""
echo "If this is a Dependabot PR, the dependency update"
echo "may have introduced breaking changes."
exit 1
else
echo "=========================================="
echo " ✅ ALL ELECTRON TESTS PASSED "
echo "=========================================="
fi