Skip to content

Security Scan

Security Scan #61

Workflow file for this run

name: Security Scan
on:
schedule:
- cron: '0 2 * * *' # Run daily at 2AM UTC
workflow_dispatch:
pull_request:
jobs:
security-tools:
name: Security Tools Scan
runs-on: ubuntu-latest
outputs:
cache-key: ${{ steps.cache-key.outputs.key }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate cache key
id: cache-key
run: echo "key=security-${{ github.sha }}-${{ hashFiles('package-lock.json') }}" >> $GITHUB_OUTPUT
- name: Cache security artifacts
uses: actions/cache@v4
with:
path: |
security-env
bin
*.sarif
coverage
key: ${{ steps.cache-key.outputs.key }}
# ----- Setup Bun for TypeScript compilation -----
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
# ----- Install dependencies and compile -----
- name: Install Dependencies
run: |
if [ -f "package.json" ]; then
if [ -f "bun.lockb" ]; then
bun install --frozen-lockfile
else
bun install
fi
# Build the main project
bun run build || echo "Build completed with warnings"
# Build the test project if it exists
if [ -f "tokenmetrics-test/package.json" ]; then
cd tokenmetrics-test
bun install --frozen-lockfile
bun run build || echo "Test project build completed with warnings"
cd ..
fi
else
echo "No package.json found, skipping bun install"
fi
continue-on-error: true
# ----- Run tests for coverage -----
- name: Generate Test Coverage
run: |
mkdir -p coverage
# Try to run tests with coverage
if bun run test:coverage 2>/dev/null; then
bun run test:coverage
elif bun test 2>/dev/null; then
bun test --coverage
else
echo "No test command found, creating empty coverage"
echo '' > coverage/lcov.info
fi
# Also run tests in test project if exists
if [ -f "tokenmetrics-test/package.json" ]; then
cd tokenmetrics-test
if bun test 2>/dev/null; then
bun test --coverage
fi
cd ..
fi
continue-on-error: true
# ----- Setup Python environment -----
- name: Setup Python Environment
run: |
python3 -m venv security-env
source security-env/bin/activate
pip install --upgrade pip
pip install --disable-pip-version-check semgrep==1.88.0
# ----- Install Trivy -----
- name: Install Trivy
run: |
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b ./bin
echo "$(pwd)/bin" >> $GITHUB_PATH
# ----- TypeScript/JavaScript Static Analysis -----
- name: ESLint Analysis
run: |
mkdir -p security-reports
if [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f ".eslintrc.yml" ]; then
bun run lint --format sarif > security-reports/eslint.sarif || true
else
echo "No ESLint configuration found, checking for default linting"
if bun run lint 2>/dev/null; then
bun run lint > security-reports/eslint.sarif || true
else
echo '{"version":"2.1.0","runs":[]}' > security-reports/eslint.sarif
fi
fi
# Ensure valid SARIF exists
if [ ! -s "security-reports/eslint.sarif" ]; then
echo '{"version":"2.1.0","runs":[]}' > security-reports/eslint.sarif
fi
continue-on-error: true
# ----- TypeScript type checking -----
- name: TypeScript Type Check
run: |
if [ -f "tsconfig.json" ]; then
bunx tsc --noEmit --pretty || echo "TypeScript check completed with warnings"
fi
if [ -f "tokenmetrics-test/tsconfig.json" ]; then
cd tokenmetrics-test
bunx tsc --noEmit --pretty || echo "Test project TypeScript check completed with warnings"
cd ..
fi
continue-on-error: true
# ----- Security rules (multi-language with TypeScript focus) -----
- name: Semgrep Security Scan
run: |
source security-env/bin/activate
semgrep ci \
--config p/typescript \
--config p/javascript \
--config p/nodejs \
--config p/security-audit \
--config p/owasp-top-ten \
--sarif \
--output semgrep.sarif || true
# ----- Dependency and config scans -----
- name: Trivy FileSystem Scan
run: |
trivy fs . --exit-code 0 --severity HIGH,CRITICAL --format sarif --output trivy-fs.sarif || true
- name: Trivy Config Scan
run: |
trivy config . --exit-code 0 --severity HIGH,CRITICAL --format sarif --output trivy-config.sarif || true
sonarqube-analysis:
name: SonarQube Analysis
runs-on: ubuntu-latest
needs: security-tools
strategy:
matrix:
instance:
- name: "DO"
token: "SONAR_TOKEN_APP"
url: "http://sonarqube.tokenmetrics.com"
- name: "AKS"
token: "SONAR_AKS_TOKEN"
url: "http://sonarqube-aks.tokenmetrics.com"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Restore security artifacts
uses: actions/cache@v4
with:
path: |
security-env
bin
*.sarif
coverage
key: ${{ needs.security-tools.outputs.cache-key }}
- name: SonarQube Scan - ${{ matrix.instance.name }}
uses: SonarSource/sonarqube-scan-action@v5
env:
SONAR_TOKEN: ${{ secrets[matrix.instance.token] }}
SONAR_HOST_URL: ${{ matrix.instance.url }}
with:
args: >
-Dsonar.sarifReportPaths=semgrep.sarif,trivy-fs.sarif,trivy-config.sarif,security-reports/eslint.sarif
-Dsonar.projectKey=plugin-tokenmetrics
-Dsonar.projectName=${{ github.repository }}
-Dsonar.projectVersion=${{ github.sha }}
-Dsonar.sources=.
-Dsonar.test.inclusions=src/tests/**/*.js,tokenmetrics-test/src/__tests__/**/*.test.ts,tokenmetrics-test/src/__tests__/**/*.cy.ts,tokenmetrics-test/src/__tests__/**/*.cy.tsx
-Dsonar.typescript.tsconfigPaths=tsconfig.json,tokenmetrics-test/tsconfig.json
-Dsonar.typescript.lcov.reportPaths=coverage/lcov.info
-Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
-Dsonar.security.sources.javascriptsecurity=true
-Dsonar.exclusions=**/node_modules/**,**/dist/**,**/build/**,**/coverage/**,**/.git/**,**/security-env/**,tree.txt,bun.lockb,**/*.config.ts,**/*.config.js,src/tests/**,tokenmetrics-test/src/__tests__/**
-Dsonar.coverage.exclusions=**/*.test.ts,**/*.spec.ts,**/*.cy.ts,**/*.cy.tsx,**/*.config.ts,**/*.config.js,src/tests/**/*.js
-Dsonar.cpd.exclusions=src/tests/**,tokenmetrics-test/src/__tests__/**
-Dsonar.qualitygate.wait=true
# ----- Quality Gate Check -----
- name: SonarQube Quality Gate
uses: SonarSource/sonarqube-quality-gate-action@v1
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets[matrix.instance.token] }}
SONAR_HOST_URL: ${{ matrix.instance.url }}
security-summary:
name: Security Summary
runs-on: ubuntu-latest
needs: [security-tools, sonarqube-analysis]
if: always()
steps:
- name: Security Report Summary
run: |
echo "## Security Scan Summary" >> $GITHUB_STEP_SUMMARY
echo "### Tools Used:" >> $GITHUB_STEP_SUMMARY
echo "- ✅ ESLint (TypeScript/JavaScript Static Analysis)" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Semgrep (Multi-language Security)" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Trivy (Dependencies & Config)" >> $GITHUB_STEP_SUMMARY
echo "- ✅ SonarQube (Comprehensive Analysis)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Results:" >> $GITHUB_STEP_SUMMARY
echo "- SonarQube Quality Gate: ${{ steps.sonarqube-quality-gate.outputs.status }}" >> $GITHUB_STEP_SUMMARY
echo "- View DO results: http://sonarqube.tokenmetrics.com/dashboard?id=${{ github.repository }}" >> $GITHUB_STEP_SUMMARY
echo "- View AKS results: http://sonarqube-aks.tokenmetrics.com/dashboard?id=${{ github.repository }}" >> $GITHUB_STEP_SUMMARY
# ----- Cleanup -----
- name: Cleanup
if: always()
run: |
rm -rf security-env || true
rm -f *.sarif || true