Skip to content

Commit 60a19f3

Browse files
authored
Merge pull request #19 from advanced-security/copilot/fix-18
Add support for new matrix format with language and build-mode
2 parents 9f9ba17 + 0b18e97 commit 60a19f3

File tree

5 files changed

+144
-33
lines changed

5 files changed

+144
-33
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
venv/
1+
venv/
2+
__pycache__/
3+
*.pyc

README.md

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,18 @@ on:
2929
jobs:
3030
create-matrix:
3131
runs-on: ubuntu-latest
32+
permissions:
33+
# required for all workflows
34+
security-events: write
35+
36+
# required to fetch internal or private CodeQL packs
37+
packages: read
38+
39+
# only required for workflows in private repositories
40+
actions: read
41+
contents: read
3242
outputs:
33-
matrix: ${{ steps.set-matrix.outputs.languages }}
43+
matrix: ${{ steps.set-matrix.outputs.matrix }}
3444
steps:
3545
- name: Get languages from repo
3646
id: set-matrix
@@ -43,16 +53,15 @@ jobs:
4353
needs: create-matrix
4454
if: ${{ needs.create-matrix.outputs.matrix != '[]' }}
4555
name: Analyze
46-
runs-on: ubuntu-latest
56+
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
4757
permissions:
4858
actions: read
4959
contents: read
5060
security-events: write
5161

5262
strategy:
5363
fail-fast: false
54-
matrix:
55-
language: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}
64+
matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}
5665

5766
steps:
5867
- name: Checkout repository
@@ -63,10 +72,17 @@ jobs:
6372
uses: github/codeql-action/init@v3
6473
with:
6574
languages: ${{ matrix.language }}
66-
67-
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
68-
- name: Autobuild
69-
uses: github/codeql-action/autobuild@v3
75+
build-mode: ${{ matrix.build-mode }}
76+
77+
- if: matrix.build-mode == 'manual'
78+
shell: bash
79+
run: |
80+
echo 'If you are using a "manual" build mode for one or more of the' \
81+
'languages you are analyzing, replace this with the commands to build' \
82+
'your code, for example:'
83+
echo ' make bootstrap'
84+
echo ' make release'
85+
exit 1
7086
7187
- name: Perform CodeQL Analysis
7288
uses: github/codeql-action/analyze@v3
@@ -82,7 +98,7 @@ Example:
8298
create-matrix:
8399
runs-on: ubuntu-latest
84100
outputs:
85-
matrix: ${{ steps.set-matrix.outputs.languages }}
101+
matrix: ${{ steps.set-matrix.outputs.matrix }}
86102
steps:
87103
- name: Get languages from repo
88104
id: set-matrix
@@ -94,6 +110,28 @@ Example:
94110
95111
```
96112

113+
### Build Mode Override
114+
By default, the action sets the build mode to:
115+
- `none` for most languages (python, javascript, ruby, rust, actions, etc.)
116+
- `manual` for languages that typically require custom build steps (go, swift, java)
117+
118+
If you want to override this behavior and use manual build mode for specific languages, use the `build-mode-manual-override` input:
119+
120+
``` yaml
121+
create-matrix:
122+
runs-on: ubuntu-latest
123+
outputs:
124+
matrix: ${{ steps.set-matrix.outputs.matrix }}
125+
steps:
126+
- name: Get languages from repo
127+
id: set-matrix
128+
uses: advanced-security/set-codeql-language-matrix@v1
129+
with:
130+
access-token: ${{ secrets.GITHUB_TOKEN }}
131+
endpoint: ${{ github.event.repository.languages_url }}
132+
build-mode-manual-override: 'java, csharp'
133+
```
134+
97135
### Actions support
98136

99137
The GitHub API for [List repository languages](https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repository-languages) does not by default include "YAML"/"GitHub Actions". This is particularly useful if your repository contains GitHub Actions workflows that you want to include in CodeQL analysis.

action.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,20 @@ inputs:
1212
exclude:
1313
description: 'Use a comma separated list here to exclude specific languges from your CodeQL scan. Example: "python, java"'
1414
required: false
15+
build-mode-manual-override:
16+
description: 'Use a comma separated list here to specify languages that should use manual build mode instead of the default. Example: "java, csharp"'
17+
required: false
1518
outputs:
19+
matrix:
20+
description: 'Matrix definition including language and build-mode configurations'
1621
languages:
17-
description: 'List of languages that will set the job matrix'
22+
description: 'List of languages that will set the job matrix (deprecated - use matrix instead)'
1823
runs:
1924
using: 'docker'
2025
image: 'Dockerfile'
2126
args:
2227
- ${{ inputs.access-token }}
2328
- ${{ inputs.endpoint }}
2429
- ${{ inputs.exclude }}
30+
- ${{ inputs.build-mode-manual-override }}
2531

entrypoint.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/bin/sh -l
22

33
# kick off the command
4-
python /main.py $1 $2 "$3"
4+
python /main.py $1 $2 "$3" "$4"

main.py

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
token = sys.argv[1]
77
endpoint = sys.argv[2]
8-
exclude = sys.argv[3]
8+
exclude = sys.argv[3] if len(sys.argv) > 3 else ""
9+
build_mode_manual_override = sys.argv[4] if len(sys.argv) > 4 else ""
910
codeql_languages = ["actions", "cpp", "csharp", "go", "java", "javascript", "python", "ruby", "rust", "typescript", "kotlin", "swift"]
1011

1112

@@ -17,32 +18,93 @@ def get_languages():
1718

1819
# Find the intersection of the languages returned by the API and the languages supported by CodeQL
1920
def build_languages_list(languages):
20-
languages = [language.lower() for language in languages.keys()]
21-
for i in range(len(languages)):
22-
if languages[i] == "c#":
23-
languages[i] = ("csharp")
24-
if languages[i] == "c++":
25-
languages[i] = ("cpp")
26-
if languages[i] == "c":
27-
languages[i] = ("cpp")
28-
if languages[i] == "typescript":
29-
languages[i] = ("javascript")
30-
if languages[i] == "kotlin":
31-
languages[i] = ("java")
32-
if languages[i] == "yaml":
33-
languages[i] = ("actions")
34-
print("After mapping:", languages)
35-
intersection = list(set(languages) & set(codeql_languages))
21+
original_languages = [language.lower() for language in languages.keys()]
22+
mapped_languages = []
23+
language_mapping = {} # Track mapped language -> list of original languages
24+
25+
for orig_lang in original_languages:
26+
mapped_lang = orig_lang
27+
if orig_lang == "c#":
28+
mapped_lang = "csharp"
29+
elif orig_lang == "c++":
30+
mapped_lang = "cpp"
31+
elif orig_lang == "c":
32+
mapped_lang = "cpp"
33+
elif orig_lang == "typescript":
34+
mapped_lang = "javascript"
35+
elif orig_lang == "kotlin":
36+
mapped_lang = "java"
37+
elif orig_lang == "yaml":
38+
mapped_lang = "actions"
39+
40+
mapped_languages.append(mapped_lang)
41+
42+
# Track all original languages that map to this CodeQL language
43+
if mapped_lang not in language_mapping:
44+
language_mapping[mapped_lang] = []
45+
language_mapping[mapped_lang].append(orig_lang)
46+
47+
print("After mapping:", mapped_languages)
48+
intersection = list(set(mapped_languages) & set(codeql_languages))
3649
print("Intersection:", intersection)
37-
return intersection
50+
return intersection, language_mapping
3851

3952
# return a list of objects from language list if they are not in the exclude list
4053
def exclude_languages(language_list):
54+
if not exclude:
55+
return language_list
4156
excluded = [x.strip() for x in exclude.split(',')]
4257
output = list(set(language_list).difference(excluded))
4358
print("languages={}".format(output))
4459
return output
4560

61+
# Determine build mode for each language
62+
def get_build_mode(language, original_languages=None):
63+
# Languages that should use manual build mode by default
64+
# Check original languages first if available
65+
if original_languages:
66+
# If any of the original languages require manual build mode, use manual
67+
for orig_lang in original_languages:
68+
if orig_lang in ["kotlin", "go", "swift"]:
69+
manual_by_default = True
70+
break
71+
else:
72+
manual_by_default = False
73+
else:
74+
# Fallback to mapped language check
75+
manual_by_default = language in ["go", "swift", "java"]
76+
77+
# Check if user overrode build mode to manual
78+
if build_mode_manual_override:
79+
override_languages = [x.strip() for x in build_mode_manual_override.split(',')]
80+
if language in override_languages:
81+
return "manual"
82+
if original_languages:
83+
for orig_lang in original_languages:
84+
if orig_lang in override_languages:
85+
return "manual"
86+
87+
# Use default logic
88+
if manual_by_default:
89+
return "manual"
90+
else:
91+
return "none"
92+
93+
# Build the matrix include format
94+
def build_matrix(language_list, language_mapping):
95+
include = []
96+
for language in language_list:
97+
original_languages = language_mapping.get(language, [language])
98+
build_mode = get_build_mode(language, original_languages)
99+
include.append({
100+
"language": language,
101+
"build-mode": build_mode
102+
})
103+
104+
matrix = {"include": include}
105+
print("Matrix:", matrix)
106+
return matrix
107+
46108
# Set the output of the action
47109
def set_action_output(output_name, value) :
48110
if "GITHUB_OUTPUT" in os.environ :
@@ -51,9 +113,12 @@ def set_action_output(output_name, value) :
51113

52114
def main():
53115
languages = get_languages()
54-
language_list = build_languages_list(languages)
55-
output = exclude_languages(language_list)
56-
set_action_output("languages", json.dumps(output))
116+
language_list, language_mapping = build_languages_list(languages)
117+
filtered_languages = exclude_languages(language_list)
118+
matrix = build_matrix(filtered_languages, language_mapping)
119+
set_action_output("matrix", json.dumps(matrix))
120+
# Keep the old output for backward compatibility
121+
set_action_output("languages", json.dumps(filtered_languages))
57122

58123
if __name__ == '__main__':
59124
main()

0 commit comments

Comments
 (0)