Skip to content

Commit 7f0b93c

Browse files
committed
migrate codeql-action into package
1 parent 18be27c commit 7f0b93c

File tree

18 files changed

+1060
-0
lines changed

18 files changed

+1060
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: 'Reusable CodeQL Analysis'
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
languages:
7+
description: 'JSON array of programming languages to scan (e.g., ["javascript", "python"])'
8+
required: true
9+
type: string
10+
repo:
11+
description: 'Repository that requested the scan'
12+
required: true
13+
type: string
14+
paths_ignored:
15+
description: 'Comma delimited paths to ignore during scan'
16+
required: false
17+
type: string
18+
default: ''
19+
rules_excluded:
20+
description: 'Comma delimited IDs of rules to exclude'
21+
required: false
22+
type: string
23+
default: ''
24+
outputs:
25+
sarif-id:
26+
description: 'SARIF file identifier'
27+
value: ${{ jobs.codeql-analysis.outputs.sarif-id }}
28+
29+
jobs:
30+
codeql-analysis:
31+
runs-on: ubuntu-latest
32+
permissions:
33+
actions: read
34+
contents: read
35+
security-events: write
36+
37+
strategy:
38+
fail-fast: false
39+
matrix:
40+
language: ${{ fromJSON(inputs.languages) }}
41+
42+
outputs:
43+
sarif-id: ${{ steps.upload.outputs.sarif-id }}
44+
45+
steps:
46+
- name: Checkout repository
47+
uses: actions/checkout@v4
48+
with:
49+
repository: ${{ inputs.repo }}
50+
path: ${{ inputs.repo }}
51+
52+
- name: Call Security Code Scanner CodeQL Action
53+
id: codeql-scan
54+
uses: ./packages/codeql-action@main
55+
with:
56+
repo: ${{ inputs.repo }}
57+
language: ${{ matrix.language }}
58+
paths_ignored: ${{ inputs.paths_ignored }}
59+
rules_excluded: ${{ inputs.rules_excluded }}
60+
61+
- name: Upload SARIF with language suffix
62+
id: upload
63+
uses: github/codeql-action/upload-sarif@v3
64+
with:
65+
sarif_file: ${{ steps.codeql-scan.outputs.sarif-output }}
66+
category: codeql-${{ matrix.language }}

packages/codeql-action/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
node_modules/
2+
package-lock.json
3+
.env
4+
pnpm-lock.yaml
5+
package-lock.json
6+
.DS_Store
7+
codeql-config-generated.yml
8+
github_output
9+
.env.test
10+
.yarn/cache
11+
.yarn/install-state.gz

packages/codeql-action/README.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# CodeQL Action
2+
3+
Custom CodeQL analysis action with repository-specific configurations and custom query suites.
4+
5+
## Overview
6+
7+
This action provides flexible CodeQL scanning with:
8+
- **Automatic language detection** via GitHub API
9+
- **Repository-specific configurations** in `repo-configs/`
10+
- **Custom query suites** for specialized security analysis
11+
- **Per-language build settings** (version, distribution, build commands)
12+
13+
## Architecture
14+
15+
The action works as part of the security scanning workflow:
16+
17+
1. **Language detector** creates scan matrix from detected languages
18+
2. **Config loader** reads repo-specific config from `repo-configs/<repo-name>.js`
19+
3. **Config generator** merges inputs with repo config and generates CodeQL config
20+
4. **CodeQL** performs analysis and uploads SARIF results
21+
22+
## Inputs
23+
24+
| Input | Required | Description |
25+
|-------|----------|-------------|
26+
| `repo` || Repository name (format: `owner/repo`) |
27+
| `language` || Language to scan (e.g., `javascript-typescript`, `java-kotlin`, `python`) |
28+
| `paths_ignored` || Newline-delimited paths to ignore |
29+
| `rules_excluded` || Newline-delimited CodeQL rule IDs to exclude |
30+
| `build_mode` || Build mode: `none`, `autobuild`, or `manual` |
31+
| `build_command` || Build command for `manual` build mode |
32+
| `version` || Language/runtime version (e.g., `21` for Java, `3.10` for Python) |
33+
| `distribution` || Distribution (e.g., `temurin`, `zulu` for Java) |
34+
35+
## Usage
36+
37+
### Via Reusable Workflow (Recommended)
38+
39+
```yaml
40+
name: Security Scan
41+
on: [push, pull_request]
42+
43+
jobs:
44+
security:
45+
uses: metamask/security-codescanner-monorepo/.github/workflows/security-scan.yml@main
46+
with:
47+
repo: ${{ github.repository }}
48+
permissions:
49+
actions: read
50+
contents: read
51+
security-events: write
52+
```
53+
54+
### Direct Action Usage
55+
56+
```yaml
57+
- name: Run CodeQL Analysis
58+
uses: metamask/security-codescanner-monorepo/packages/codeql-action@main
59+
with:
60+
repo: ${{ github.repository }}
61+
language: javascript-typescript
62+
paths_ignored: |
63+
test/
64+
docs/
65+
rules_excluded: |
66+
js/log-injection
67+
```
68+
69+
## Repository Configuration
70+
71+
### File-Based Config
72+
73+
Create `repo-configs/<repo-name>.js`:
74+
75+
```javascript
76+
const config = {
77+
// Paths to ignore during scan
78+
pathsIgnored: ['test', 'vendor', 'node_modules'],
79+
80+
// Rule IDs to exclude
81+
rulesExcluded: ['js/log-injection', 'js/unsafe-dynamic-method-access'],
82+
83+
// Per-language configuration
84+
languages_config: [
85+
{
86+
language: 'java-kotlin',
87+
build_mode: 'manual',
88+
build_command: './gradlew :coordinator:app:build',
89+
version: '21',
90+
distribution: 'temurin'
91+
},
92+
{
93+
language: 'javascript-typescript',
94+
// Uses default config (no build needed)
95+
},
96+
{
97+
language: 'cpp',
98+
ignore: true // Skip C++ scanning
99+
}
100+
],
101+
102+
// CodeQL query suites
103+
queries: [
104+
{ name: 'Base security queries', uses: './query-suites/base.qls' },
105+
{ name: 'Custom queries', uses: './custom-queries/query-suites/custom-queries.qls' }
106+
]
107+
};
108+
109+
export default config;
110+
```
111+
112+
### Configuration Priority
113+
114+
1. **Workflow input** (highest priority) - overrides everything
115+
2. **Repo config file** - `repo-configs/<repo-name>.js`
116+
3. **Default config** - `repo-configs/default.js`
117+
118+
### Default Configurations
119+
120+
The action includes sensible defaults for common languages:
121+
122+
```javascript
123+
const DEFAULT_CONFIGS = {
124+
'javascript': { language: 'javascript-typescript' },
125+
'typescript': { language: 'javascript-typescript' },
126+
'python': { language: 'python' },
127+
'go': { language: 'go' },
128+
'java': {
129+
language: 'java-kotlin',
130+
build_mode: 'manual',
131+
build_command: './mvnw compile'
132+
},
133+
'cpp': { language: 'cpp' },
134+
'csharp': { language: 'csharp' },
135+
'ruby': { language: 'ruby' }
136+
};
137+
```
138+
139+
## Supported Languages
140+
141+
| GitHub Language | CodeQL Language | Build Required |
142+
|-----------------|-----------------|----------------|
143+
| JavaScript | `javascript-typescript` | No |
144+
| TypeScript | `javascript-typescript` | No |
145+
| Python | `python` | No |
146+
| Java | `java-kotlin` | Yes (defaults to `./mvnw compile`) |
147+
| Kotlin | `java-kotlin` | Yes |
148+
| Go | `go` | No |
149+
| C/C++ | `cpp` | Yes |
150+
| C# | `csharp` | Yes |
151+
| Ruby | `ruby` | No |
152+
153+
## Build Modes
154+
155+
### `none`
156+
No build needed (interpreted languages like JavaScript, Python)
157+
158+
### `autobuild`
159+
CodeQL automatically detects and runs build (works for simple projects)
160+
161+
### `manual`
162+
Specify exact build command:
163+
```javascript
164+
{
165+
language: 'java-kotlin',
166+
build_mode: 'manual',
167+
build_command: './gradlew clean build'
168+
}
169+
```
170+
171+
## Custom Query Suites
172+
173+
Query suites define which CodeQL queries to run:
174+
175+
**Built-in suites:**
176+
- `./query-suites/base.qls` - Standard security queries
177+
- `./query-suites/linea-monorepo.qls` - Project-specific queries
178+
179+
**Custom queries:**
180+
- Checked out from `metamask/CodeQL-Queries` repository
181+
- Available at `./custom-queries/query-suites/custom-queries.qls`
182+
183+
## Troubleshooting
184+
185+
### Config not loading
186+
- Filename must match repo: `owner/repo` → `repo.js`
187+
- Must use ESM: `export default config`
188+
- Check logs: `[config-loader] Loading config for repository: ...`
189+
190+
### Build failures
191+
- Verify `build_command` works locally
192+
- Check Java version matches `version` input
193+
- Review build step logs in Actions
194+
195+
### Language not detected
196+
- Check GitHub language stats (repo → Insights → Languages)
197+
- Add language manually via `languages_config` in repo config
198+
- Verify language mapping in `language-detector/src/job-configurator.js`
199+
200+
### SARIF upload errors
201+
- Ensure workflow has `security-events: write` permission
202+
- Check SARIF file is generated in `${{ steps.codeql-analysis.outputs.sarif-output }}`
203+
- Review CodeQL analysis logs
204+
205+
## Security
206+
207+
See [SECURITY.md](../../SECURITY.md) for:
208+
- Threat model and security boundaries
209+
- Input validation approach
210+
- Token permissions model
211+
212+
## Development
213+
214+
### Testing Config Changes
215+
216+
```bash
217+
# Run config generator locally
218+
cd packages/codeql-action
219+
REPO=owner/repo LANGUAGE=javascript node scripts/generate-config.js
220+
221+
# Validate generated config
222+
cat codeql-config-generated.yml
223+
```
224+
225+
### Adding New Language Support
226+
227+
1. Add to `LANGUAGE_MAPPING` in `language-detector/src/job-configurator.js`
228+
2. Add default config in `language-detector/src/job-configurator.js` → `DEFAULT_CONFIGS`
229+
3. Update this README's supported languages table
230+
231+
## License
232+
233+
ISC

0 commit comments

Comments
 (0)