Skip to content

Commit 4e9e4c4

Browse files
fadi-georgejinliu9508
authored andcommitted
ci: add CodeQL workflow for scanning for security issues (#2510)
1 parent 10935de commit 4e9e4c4

File tree

4 files changed

+178
-28
lines changed

4 files changed

+178
-28
lines changed

.github/codeql/codeql-config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
paths-ignore:
2+
- Examples

.github/workflows/ci.yml

Lines changed: 99 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
name: Build and Test SDK
22

3+
concurrency:
4+
group: ${{ github.workflow }}-${{ github.ref }}
5+
cancel-in-progress: true
6+
37
on:
48
pull_request:
5-
branches: "**"
9+
branches: ["**"]
610

711
env:
8-
DIFF_COVERAGE_THRESHOLD: '80'
12+
DIFF_COVERAGE_THRESHOLD: "80"
13+
14+
permissions:
15+
contents: read
16+
pull-requests: write
17+
issues: write
918

1019
jobs:
1120
build:
12-
runs-on: ubuntu-24.04
21+
runs-on: ubuntu-latest
1322
steps:
1423
- name: "[Checkout] Repo"
1524
uses: actions/checkout@v4
@@ -26,35 +35,97 @@ jobs:
2635
- name: "[Test] SDK Unit Tests"
2736
working-directory: OneSignalSDK
2837
run: |
29-
./gradlew testReleaseUnitTest --console=plain --continue
30-
- name: "[Coverage] Generate JaCoCo merged XML"
31-
working-directory: OneSignalSDK
32-
run: |
33-
./gradlew jacocoTestReportAll jacocoMergedReport --console=plain --continue
34-
- name: "[Setup] Python"
35-
uses: actions/setup-python@v5
36-
with:
37-
python-version: '3.x'
38-
- name: "[Diff Coverage] Install diff-cover"
38+
./gradlew testDebugUnitTest --console=plain --continue
39+
- name: "[Diff Coverage] Check for bypass"
40+
id: coverage_bypass
3941
run: |
40-
python -m pip install --upgrade pip diff-cover
41-
- name: "[Diff Coverage] Check and HTML report"
42+
# Check if PR has Skip Coverage Check label
43+
if [ "${{ github.event_name }}" = "pull_request" ]; then
44+
LABELS="${{ toJson(github.event.pull_request.labels.*.name) }}"
45+
if echo "$LABELS" | grep -qiE "Skip Coverage Check|skip-coverage-check"; then
46+
echo "bypass=true" >> $GITHUB_OUTPUT
47+
echo "reason=PR has 'Skip Coverage Check' label" >> $GITHUB_OUTPUT
48+
echo "⚠️ Coverage check will not fail build (PR has 'Skip Coverage Check' label)"
49+
echo " Coverage will still be checked and reported"
50+
else
51+
echo "bypass=false" >> $GITHUB_OUTPUT
52+
fi
53+
else
54+
echo "bypass=false" >> $GITHUB_OUTPUT
55+
fi
56+
- name: "[Diff Coverage] Check coverage"
4257
working-directory: OneSignalSDK
4358
run: |
44-
REPORT=build/reports/jacoco/merged/jacocoMergedReport.xml
45-
test -f "$REPORT" || { echo "Merged JaCoCo report not found at $REPORT" >&2; exit 1; }
46-
python -m diff_cover.diff_cover_tool "$REPORT" \
47-
--compare-branch=origin/main \
48-
--fail-under=$DIFF_COVERAGE_THRESHOLD
49-
python -m diff_cover.diff_cover_tool "$REPORT" \
50-
--compare-branch=origin/main \
51-
--html-report diff_coverage.html || true
52-
- name: Upload diff coverage HTML
53-
if: always()
54-
uses: actions/upload-artifact@v4
59+
# Use the shared coverage check script for consistency
60+
# Generate markdown report for PR comments
61+
# If bypassed, still run the check but don't fail the build
62+
set +e # Don't exit on error - we want to generate the report even if coverage fails
63+
if [ "${{ steps.coverage_bypass.outputs.bypass }}" = "true" ]; then
64+
SKIP_COVERAGE_CHECK=true GENERATE_MARKDOWN=true DIFF_COVERAGE_THRESHOLD=$DIFF_COVERAGE_THRESHOLD ./coverage/checkCoverage.sh
65+
else
66+
GENERATE_MARKDOWN=true DIFF_COVERAGE_THRESHOLD=$DIFF_COVERAGE_THRESHOLD ./coverage/checkCoverage.sh
67+
fi
68+
COVERAGE_EXIT_CODE=$?
69+
set -e # Re-enable exit on error
70+
71+
# Check if markdown report was generated
72+
if [ -f "diff_coverage.md" ]; then
73+
echo "✅ Coverage report generated"
74+
else
75+
echo "⚠️ Coverage report not generated"
76+
fi
77+
78+
# Only fail the build if coverage is below threshold AND not bypassed
79+
if [ "${{ steps.coverage_bypass.outputs.bypass }}" != "true" ] && [ $COVERAGE_EXIT_CODE -ne 0 ]; then
80+
echo "❌ Coverage check failed - build will fail"
81+
exit $COVERAGE_EXIT_CODE
82+
elif [ "${{ steps.coverage_bypass.outputs.bypass }}" = "true" ]; then
83+
echo "⚠️ Coverage check completed (bypassed - build will not fail)"
84+
exit 0
85+
else
86+
echo "✅ Coverage check passed"
87+
exit 0
88+
fi
89+
- name: Comment PR with coverage summary
90+
if: always() && github.event_name == 'pull_request'
91+
uses: actions/github-script@v7
5592
with:
56-
name: diff-coverage-report
57-
path: OneSignalSDK/diff_coverage.html
93+
script: |
94+
const fs = require('fs');
95+
const path = 'OneSignalSDK/diff_coverage.md';
96+
if (fs.existsSync(path)) {
97+
const content = fs.readFileSync(path, 'utf8');
98+
const body = `## 📊 Diff Coverage Report\n\n${content}\n\n📥 [View workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
99+
100+
// Find existing comment
101+
const comments = await github.rest.issues.listComments({
102+
owner: context.repo.owner,
103+
repo: context.repo.repo,
104+
issue_number: context.issue.number,
105+
});
106+
107+
const botComment = comments.data.find(comment =>
108+
comment.user.type === 'Bot' && comment.body.includes('Diff Coverage Report')
109+
);
110+
111+
if (botComment) {
112+
// Update existing comment
113+
await github.rest.issues.updateComment({
114+
owner: context.repo.owner,
115+
repo: context.repo.repo,
116+
comment_id: botComment.id,
117+
body: body
118+
});
119+
} else {
120+
// Create new comment
121+
await github.rest.issues.createComment({
122+
owner: context.repo.owner,
123+
repo: context.repo.repo,
124+
issue_number: context.issue.number,
125+
body: body
126+
});
127+
}
128+
}
58129
- name: Unit tests results
59130
if: failure()
60131
uses: actions/upload-artifact@v4

.github/workflows/codeql.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: "CodeQL"
2+
3+
concurrency:
4+
group: ${{ github.workflow }}-${{ github.ref }}
5+
cancel-in-progress: true
6+
7+
on:
8+
push:
9+
branches: ["main"]
10+
pull_request:
11+
branches: ["main"]
12+
schedule:
13+
- cron: "27 1 * * 0"
14+
15+
jobs:
16+
analyze:
17+
name: Analyze (${{ matrix.language }})
18+
# Runner size impacts CodeQL analysis time. To learn more, please see:
19+
# - https://gh.io/recommended-hardware-resources-for-running-codeql
20+
# - https://gh.io/supported-runners-and-hardware-resources
21+
# - https://gh.io/using-larger-runners (GitHub.com only)
22+
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
23+
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
24+
permissions:
25+
# required for all workflows
26+
security-events: write
27+
28+
# required to fetch internal or private CodeQL packs
29+
packages: read
30+
31+
strategy:
32+
fail-fast: false
33+
matrix:
34+
include:
35+
- language: actions
36+
build-mode: none
37+
- language: java-kotlin
38+
build-mode: none
39+
dependency-caching: true
40+
41+
steps:
42+
- name: Checkout repository
43+
uses: actions/checkout@v6
44+
45+
# Add any setup steps before running the `github/codeql-action/init` action.
46+
# This includes steps like installing compilers or runtimes (`actions/setup-node`
47+
# or others). This is typically only required for manual builds.
48+
# - name: Setup runtime (example)
49+
# uses: actions/setup-example@v1
50+
51+
# Initializes the CodeQL tools for scanning.
52+
- name: Initialize CodeQL
53+
uses: github/codeql-action/init@v4
54+
with:
55+
dependency-caching: ${{ matrix.dependency-caching }}
56+
languages: ${{ matrix.language }}
57+
build-mode: ${{ matrix.build-mode }}
58+
config-file: ./.github/codeql/codeql-config.yml
59+
60+
- name: Perform CodeQL Analysis
61+
uses: github/codeql-action/analyze@v4
62+
with:
63+
category: "/language:${{matrix.language}}"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Checks if the PR title follows semantic commit message conventions
2+
name: Lint PR
3+
permissions:
4+
contents: read
5+
pull-requests: write
6+
7+
on:
8+
pull_request:
9+
types: [opened, edited, synchronize]
10+
11+
jobs:
12+
call:
13+
uses: OneSignal/sdk-actions/.github/workflows/lint-pr-title.yml@main
14+
secrets: inherit

0 commit comments

Comments
 (0)