Skip to content

CodeQL

CodeQL #243

Workflow file for this run

name: "CodeQL"
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Run weekly on Monday at 2:00 UTC
- cron: "0 2 * * 1"
jobs:
analyze:
name: Analyze
runs-on: ${{ matrix.runner }}
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
include:
- language: "javascript"
runner: "ubuntu-latest"
- language: "typescript"
runner: "ubuntu-latest"
- language: "kotlin"
runner: "ubuntu-latest"
- language: "swift"
runner: "macos-15"
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
config-file: .github/codeql/codeql-config.yml
# Use the linked CodeQL bundle (renamed from 'latest')
tools: linked
# Autobuild for JavaScript/TypeScript (optional - CodeQL can analyze source directly)
- name: Autobuild (JavaScript/TypeScript)
if: matrix.language == 'javascript' || matrix.language == 'typescript'
uses: github/codeql-action/autobuild@v4
# Setup for Kotlin (Android) - React Native requires Node.js dependencies
- name: Setup Node.js for Kotlin
if: matrix.language == 'kotlin'
uses: actions/setup-node@v6
with:
node-version: 20
cache: "npm"
- name: Cache node_modules for Kotlin
if: matrix.language == 'kotlin'
uses: actions/cache@v5
with:
path: node_modules
key: ${{ runner.os }}-node-modules-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-modules-
- name: Install Node dependencies for Kotlin
if: matrix.language == 'kotlin'
run: npm ci
- name: Setup Java for Kotlin
if: matrix.language == 'kotlin'
uses: actions/setup-java@v5
with:
distribution: "temurin"
java-version: "17"
cache: "gradle"
- name: Setup Android SDK for Kotlin
if: matrix.language == 'kotlin'
uses: android-actions/setup-android@v4
- name: Cache Metro bundler for Kotlin
if: matrix.language == 'kotlin'
uses: actions/cache@v5
with:
path: |
~/.cache/metro
node_modules/.cache
key: ${{ runner.os }}-metro-${{ hashFiles('package-lock.json', 'metro.config.js', 'babel.config.js') }}
restore-keys: |
${{ runner.os }}-metro-
- name: Setup Gradle Build Action for Kotlin
if: matrix.language == 'kotlin'
uses: gradle/gradle-build-action@v3
with:
gradle-version: wrapper
cache-read-only: false
- name: Free up disk space for Kotlin
if: matrix.language == 'kotlin'
run: |
# Free up disk space before building
echo "Disk space before cleanup:"
df -h
# Clean Gradle cache if needed (keep recent entries)
if [ -d ~/.gradle/caches ]; then
echo "Cleaning old Gradle cache entries..."
find ~/.gradle/caches -type f -atime +7 -delete 2>/dev/null || true
find ~/.gradle/caches -type d -empty -delete 2>/dev/null || true
fi
# Clean Android build directories from previous runs
if [ -d android/app/build ]; then
echo "Cleaning previous Android build artifacts..."
rm -rf android/app/build/outputs || true
rm -rf android/app/build/intermediates/merged_assets || true
rm -rf android/app/build/intermediates/merged_res || true
fi
echo "Disk space after cleanup:"
df -h
- name: Build for CodeQL (Kotlin)
if: matrix.language == 'kotlin'
run: |
# Build Android project for CodeQL analysis
# CodeQL needs to trace source files during build from repository root
# Optimized for minimal disk space: only debug variant, single architecture
# List source files first to verify they exist
echo "Kotlin source files:"
find android/app/src/main -name "*.kt" || echo "No Kotlin source files found"
# Build the app module's debug variant with single architecture (arm64-v8a)
# This ensures CodeQL can trace Kotlin source files during compilation
# We use assembleDebug to build the full module, but limit to single architecture
# CodeQL's build tracer will automatically intercept compiler invocations
# Building from repository root ensures CodeQL can properly trace file paths
cd android
./gradlew :app:assembleDebug \
-PreactNativeArchitectures=arm64-v8a \
--parallel \
--build-cache \
-Dorg.gradle.caching=true \
-Dorg.gradle.parallel=true \
-Dorg.gradle.configureondemand=true \
-Dorg.gradle.daemon=false \
--no-daemon
cd ..
# Verify Kotlin files were compiled (this is critical for CodeQL)
echo "Checking for compiled Kotlin classes..."
KOTLIN_CLASSES=$(find android/app/build -name "*.class" -path "*/kotlin/*" | wc -l)
JAVA_CLASSES=$(find android/app/build -name "*.class" -path "*/java/*" | wc -l)
echo "Found $KOTLIN_CLASSES Kotlin classes and $JAVA_CLASSES Java classes"
if [ "$KOTLIN_CLASSES" -eq 0 ] && [ "$JAVA_CLASSES" -eq 0 ]; then
echo "ERROR: No compiled classes found! CodeQL will not be able to analyze the code."
echo "Build output directories:"
ls -la android/app/build/ || true
exit 1
fi
# Show some example compiled classes
echo "Sample compiled classes:"
find android/app/build -name "*.class" -path "*/kotlin/*" | head -5 || true
find android/app/build -name "*.class" -path "*/java/*" | head -5 || true
# Clean up large artifacts after compilation (keep classes for CodeQL)
echo "Cleaning up large build artifacts..."
find android/app/build -name "*.apk" -delete 2>/dev/null || true
find android/app/build -name "*.aab" -delete 2>/dev/null || true
find android/app/build -path "*/merged_assets/*" -delete 2>/dev/null || true
find android/app/build -path "*/merged_res/*" -delete 2>/dev/null || true
echo "Final disk space:"
df -h
# Setup for Swift (iOS) - React Native requires Node.js and CocoaPods
- name: Setup Node.js for Swift
if: matrix.language == 'swift'
uses: actions/setup-node@v6
with:
node-version: 20
cache: "npm"
- name: Cache node_modules for Swift
if: matrix.language == 'swift'
uses: actions/cache@v5
with:
path: node_modules
key: ${{ runner.os }}-node-modules-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-modules-
- name: Install Node dependencies for Swift
if: matrix.language == 'swift'
run: npm ci
- name: Setup Ruby and Bundler for Swift
if: matrix.language == 'swift'
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2"
bundler-cache: true
- name: Setup Xcode for Swift
if: matrix.language == 'swift'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "26.0"
- name: Cache CocoaPods for Swift
if: matrix.language == 'swift'
uses: actions/cache@v5
with:
path: ios/Pods
key: ${{ runner.os }}-pods-v2-${{ hashFiles('ios/Podfile.lock') }}-${{ hashFiles('ios/Podfile') }}
restore-keys: |
${{ runner.os }}-pods-v2-${{ hashFiles('ios/Podfile.lock') }}-
${{ runner.os }}-pods-v2-
- name: Cache CocoaPods cache for Swift
if: matrix.language == 'swift'
uses: actions/cache@v5
with:
path: ~/Library/Caches/CocoaPods
key: ${{ runner.os }}-cocoapods-cache-v2-${{ hashFiles('ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-cocoapods-cache-v2-
- name: Cache Xcode Derived Data for Swift
if: matrix.language == 'swift'
uses: actions/cache@v5
with:
path: ios/build
key: ${{ runner.os }}-xcode-deriveddata-${{ hashFiles('ios/**/*.swift', 'ios/**/*.m', 'ios/**/*.h', 'ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-xcode-deriveddata-
- name: Install iOS pods for Swift
if: matrix.language == 'swift'
working-directory: ios
run: |
EXPECTED_VERSION=$(cat ../.cocoapods-version | tr -d '[:space:]')
ACTUAL_VERSION=$(bundle exec pod --version)
echo "Expected CocoaPods version: $EXPECTED_VERSION"
echo "Actual CocoaPods version: $ACTUAL_VERSION"
if [ "$ACTUAL_VERSION" != "$EXPECTED_VERSION" ]; then
echo "CocoaPods version mismatch. Updating to $EXPECTED_VERSION..."
bundle update cocoapods
ACTUAL_VERSION=$(bundle exec pod --version)
echo "Updated CocoaPods version: $ACTUAL_VERSION"
if [ "$ACTUAL_VERSION" != "$EXPECTED_VERSION" ]; then
echo "Error: Failed to update CocoaPods. Expected $EXPECTED_VERSION but got $ACTUAL_VERSION"
exit 1
fi
fi
# Clear local podspecs cache to avoid version mismatches
if [ -d "Pods/Local Podspecs" ]; then
echo "Clearing local podspecs cache..."
rm -rf "Pods/Local Podspecs"
fi
# Try pod install first
if ! bundle exec pod install --repo-update; then
echo "Pod install failed, attempting to update hermes-engine..."
# Update hermes-engine specifically to resolve version mismatch
bundle exec pod update hermes-engine --no-repo-update || true
# Retry pod install
echo "Retrying pod install..."
bundle exec pod install --repo-update
fi
- name: Build for CodeQL (Swift)
if: matrix.language == 'swift'
run: |
# Build the iOS workspace for CodeQL analysis
# Optimized for speed: Debug configuration, parallel builds, single architecture
# CodeQL can analyze Swift source code directly, but building ensures code compiles
# Debug is much faster than Release (no optimizations) and sufficient for static analysis
# Get available simulator (prefer x86_64 for faster builds on Intel runners)
SIMULATOR_DEVICE=$(xcrun simctl list devices available | grep -i "iPhone.*x86_64\|iPhone.*Simulator" | head -1 | sed -n 's/.* (\([0-9A-Fa-f-]\{36\}\)) .*/\1/p')
# Fallback to any available iPhone simulator
[ -z "$SIMULATOR_DEVICE" ] && SIMULATOR_DEVICE=$(xcrun simctl list devices available | grep "^ iPhone" | sed -n 's/.* (\([0-9A-Fa-f-]\{36\}\)) .*/\1/p' | head -1)
# Final fallback: any iOS simulator
[ -z "$SIMULATOR_DEVICE" ] && SIMULATOR_DEVICE=$(xcrun simctl list devices available | sed -n 's/.* (\([0-9A-Fa-f-]\{36\}\)) .*/\1/p' | head -1)
if [ -z "$SIMULATOR_DEVICE" ]; then
echo "No simulators found, building without specific destination"
xcodebuild \
-workspace ios/WorkTrack.xcworkspace \
-scheme WorkTrack \
-configuration Debug \
-sdk iphonesimulator \
-derivedDataPath ios/build \
-parallelizeTargets \
-jobs 4 \
ONLY_ACTIVE_ARCH=YES \
CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" \
build \
2>&1 | grep -v -E "(warning:|note:)" || true
else
echo "Using simulator UDID: $SIMULATOR_DEVICE"
xcodebuild \
-workspace ios/WorkTrack.xcworkspace \
-scheme WorkTrack \
-configuration Debug \
-sdk iphonesimulator \
-destination "platform=iOS Simulator,id=$SIMULATOR_DEVICE" \
-derivedDataPath ios/build \
-parallelizeTargets \
-jobs 4 \
ONLY_ACTIVE_ARCH=YES \
CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" \
build \
2>&1 | grep -v -E "(warning:|note:)" || true
fi
# Clean up large build artifacts after compilation (keep compiled objects for CodeQL)
echo "Cleaning up large build artifacts..."
find ios/build -name "*.app" -type d -exec rm -rf {} + 2>/dev/null || true
find ios/build -name "*.dSYM" -type d -exec rm -rf {} + 2>/dev/null || true
find ios/build -name "*.ipa" -delete 2>/dev/null || true
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{ matrix.language }}"