name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
env:
NODE_OPTIONS: --max-old-space-size=4096
jobs:
validate:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x, 22.x]
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: Create test directories
run: mkdir -p tmp/test-brain
- name: Security audit
run: npm run audit:check
- name: Check formatting
run: npm run format:check
- name: Run linting (strict - zero warnings)
run: npm run lint:strict
- name: Run type checking
run: npm run typecheck
- name: Run full test suite with coverage
run: npm run test:coverage
- name: Build project
run: npm run build:quick
- name: Verify build performance
run: |
start_time=$(date +%s)
npm run build:quick
end_time=$(date +%s)
build_time=$((end_time - start_time))
echo "Build completed in ${build_time} seconds"
if [ $build_time -gt 60 ]; then
echo "Warning: Build time exceeded 60 seconds"
exit 1
fi
- name: Check build artifacts
run: |
required_files=(
"dist/index.js"
"dist/index.d.ts"
"dist/server/mcp-server.d.ts"
"dist/reasoning/orchestrator.d.ts"
"dist/utils/index.js"
)
for file in "${required_files[@]}"; do
if [ ! -f "$file" ]; then
echo "Build artifact missing: $file"
exit 1
fi
done
echo "All build artifacts verified"
- name: Test MCP server startup
run: |
timeout 10s node dist/index.js --help || true
echo "MCP server startup test completed"
- name: Validate package.json
run: |
node -e "
const pkg = require('./package.json');
const required = ['name', 'version', 'description', 'main', 'scripts', 'keywords', 'author', 'license'];
const missing = required.filter(field => !pkg[field]);
if (missing.length > 0) {
console.error('Missing required package.json fields:', missing);
process.exit(1);
}
if (!pkg.scripts.build || !pkg.scripts.test || !pkg.scripts.lint) {
console.error('Missing required npm scripts');
process.exit(1);
}
if (!pkg.engines || !pkg.engines.node) {
console.error('Missing Node.js engine specification');
process.exit(1);
}
console.log('package.json validation passed');
"
- name: Test package installation
run: |
npm pack
PACKAGE_NAME=$(ls *.tgz | head -1)
echo "Package created: $PACKAGE_NAME"
# Test installation in temporary directory
mkdir -p /tmp/test-install
cd /tmp/test-install
npm init -y
npm install $GITHUB_WORKSPACE/$PACKAGE_NAME
# Verify package can be imported
node --input-type=module -e "
try {
const pkg = await import('thoughtmcp');
console.log('Package installation and import successful');
console.log('Available exports:', Object.keys(pkg));
} catch (error) {
console.error('Package import failed:', error.message);
process.exit(1);
}
"
- name: Upload coverage reports
if: matrix.node-version == '20.x'
uses: codecov/codecov-action@v4
with:
file: ./development/reports/coverage/lcov.info
fail_ci_if_error: false
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.node-version }}
path: |
development/reports/coverage/
development/reports/test-results.json
retention-days: 30
security:
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.x"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Create test directories
run: mkdir -p tmp/test-brain
- name: Run security audit
run: npm run audit:check
- name: Check for sensitive files
run: |
if find . -name "*.env*" -not -path "./node_modules/*" -not -name "*.example" | grep -q .; then
echo "Warning: Found potential environment files"
find . -name "*.env*" -not -path "./node_modules/*" -not -name "*.example"
fi
- name: Scan for secrets
run: |
# Basic secret scanning
if grep -r -i "password\|secret\|key\|token" --include="*.ts" --include="*.js" --include="*.json" src/ | grep -v "// " | grep -v "test" | grep -q .; then
echo "Warning: Potential secrets found in source code"
grep -r -i "password\|secret\|key\|token" --include="*.ts" --include="*.js" --include="*.json" src/ | grep -v "// " | grep -v "test" || true
fi
performance:
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.x"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Create test directories
run: mkdir -p tmp/test-brain
- name: Build project
run: npm run build:quick
# Performance tests are excluded from the main vitest config because they
# require database setup. They run as part of the main test:coverage job
# which sets up Docker containers. This job validates build performance only.
- name: Validate build performance
run: |
echo "Performance tests run as part of the main test suite with Docker containers"
echo "This job validates build and memory performance only"
- name: Memory usage test
run: |
node -e "
const { performance, PerformanceObserver } = require('perf_hooks');
const obs = new PerformanceObserver((items) => {
items.getEntries().forEach((entry) => {
console.log(entry.name + ': ' + entry.duration + 'ms');
});
});
obs.observe({ entryTypes: ['measure'] });
performance.mark('start');
// Simulate cognitive processing
setTimeout(() => {
performance.mark('end');
performance.measure('cognitive-processing', 'start', 'end');
const memUsage = process.memoryUsage();
console.log('Memory usage:');
console.log(' RSS: ' + Math.round(memUsage.rss / 1024 / 1024) + 'MB');
console.log(' Heap Used: ' + Math.round(memUsage.heapUsed / 1024 / 1024) + 'MB');
console.log(' Heap Total: ' + Math.round(memUsage.heapTotal / 1024 / 1024) + 'MB');
if (memUsage.heapUsed > 2 * 1024 * 1024 * 1024) {
console.error('Memory usage exceeds 2GB threshold');
process.exit(1);
}
}, 100);
"
compatibility:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18.x, 20.x, 22.x]
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: Create test directories
run: mkdir -p tmp/test-brain
- name: Build project
run: npm run build:quick
# Full test suite requires Docker (PostgreSQL, Ollama containers)
# Only run on ubuntu-latest where Docker is available
# macOS and Windows runners don't have Docker pre-installed
- name: Run core tests (Ubuntu only - requires Docker)
if: matrix.os == 'ubuntu-latest'
run: npm run test:run
timeout-minutes: 15
# On non-Docker platforms, run typecheck and build validation only
- name: Validate build (non-Docker platforms)
if: matrix.os != 'ubuntu-latest'
run: |
npm run typecheck
echo "✅ TypeScript compilation successful on ${{ matrix.os }}"
echo "Note: Full test suite requires Docker and runs on Ubuntu only"