Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
venv/
venv/
__pycache__/
*.pyc
44 changes: 36 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
create-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.languages }}
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Get languages from repo
id: set-matrix
Expand All @@ -51,8 +51,7 @@ jobs:

strategy:
fail-fast: false
matrix:
language: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}
matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}

steps:
- name: Checkout repository
Expand All @@ -63,10 +62,17 @@ jobs:
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
- name: Autobuild
uses: github/codeql-action/autobuild@v3
build-mode: ${{ matrix.build-mode }}

- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
Expand All @@ -82,7 +88,7 @@ Example:
create-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.languages }}
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Get languages from repo
id: set-matrix
Expand All @@ -94,6 +100,28 @@ Example:

```

### Build Mode Override
By default, the action sets the build mode to:
- `none` for most languages (python, javascript, ruby, rust, actions, etc.)
- `manual` for languages that typically require custom build steps (go, swift, java)

If you want to override this behavior and use manual build mode for specific languages, use the `build-mode-manual-override` input:

``` yaml
create-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Get languages from repo
id: set-matrix
uses: advanced-security/set-codeql-language-matrix@v1
with:
access-token: ${{ secrets.GITHUB_TOKEN }}
endpoint: ${{ github.event.repository.languages_url }}
build-mode-manual-override: 'java, csharp'
```

### Actions support

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.
Expand Down
Binary file added __pycache__/main.cpython-312.pyc
Binary file not shown.
8 changes: 7 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ inputs:
exclude:
description: 'Use a comma separated list here to exclude specific languges from your CodeQL scan. Example: "python, java"'
required: false
build-mode-manual-override:
description: 'Use a comma separated list here to specify languages that should use manual build mode instead of the default. Example: "java, csharp"'
required: false
outputs:
matrix:
description: 'Matrix definition including language and build-mode configurations'
languages:
description: 'List of languages that will set the job matrix'
description: 'List of languages that will set the job matrix (deprecated - use matrix instead)'
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.access-token }}
- ${{ inputs.endpoint }}
- ${{ inputs.exclude }}
- ${{ inputs.build-mode-manual-override }}

2 changes: 1 addition & 1 deletion entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh -l

# kick off the command
python /main.py $1 $2 "$3"
python /main.py $1 $2 "$3" "$4"
107 changes: 86 additions & 21 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

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


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

# Find the intersection of the languages returned by the API and the languages supported by CodeQL
def build_languages_list(languages):
languages = [language.lower() for language in languages.keys()]
for i in range(len(languages)):
if languages[i] == "c#":
languages[i] = ("csharp")
if languages[i] == "c++":
languages[i] = ("cpp")
if languages[i] == "c":
languages[i] = ("cpp")
if languages[i] == "typescript":
languages[i] = ("javascript")
if languages[i] == "kotlin":
languages[i] = ("java")
if languages[i] == "yaml":
languages[i] = ("actions")
print("After mapping:", languages)
intersection = list(set(languages) & set(codeql_languages))
original_languages = [language.lower() for language in languages.keys()]
mapped_languages = []
language_mapping = {} # Track mapped language -> list of original languages

for orig_lang in original_languages:
mapped_lang = orig_lang
if orig_lang == "c#":
mapped_lang = "csharp"
elif orig_lang == "c++":
mapped_lang = "cpp"
elif orig_lang == "c":
mapped_lang = "cpp"
elif orig_lang == "typescript":
mapped_lang = "javascript"
elif orig_lang == "kotlin":
mapped_lang = "java"
elif orig_lang == "yaml":
mapped_lang = "actions"

mapped_languages.append(mapped_lang)

# Track all original languages that map to this CodeQL language
if mapped_lang not in language_mapping:
language_mapping[mapped_lang] = []
language_mapping[mapped_lang].append(orig_lang)

print("After mapping:", mapped_languages)
intersection = list(set(mapped_languages) & set(codeql_languages))
print("Intersection:", intersection)
return intersection
return intersection, language_mapping

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

# Determine build mode for each language
def get_build_mode(language, original_languages=None):
# Languages that should use manual build mode by default
# Check original languages first if available
if original_languages:
# If any of the original languages require manual build mode, use manual
for orig_lang in original_languages:
if orig_lang in ["kotlin", "go", "swift"]:
manual_by_default = True
break
else:
manual_by_default = False
else:
# Fallback to mapped language check
manual_by_default = language in ["go", "swift", "java"]

# Check if user overrode build mode to manual
if build_mode_manual_override:
override_languages = [x.strip() for x in build_mode_manual_override.split(',')]
if language in override_languages:
return "manual"
if original_languages:
for orig_lang in original_languages:
if orig_lang in override_languages:
return "manual"

# Use default logic
if manual_by_default:
return "manual"
else:
return "none"

# Build the matrix include format
def build_matrix(language_list, language_mapping):
include = []
for language in language_list:
original_languages = language_mapping.get(language, [language])
build_mode = get_build_mode(language, original_languages)
include.append({
"language": language,
"build-mode": build_mode
})

matrix = {"include": include}
print("Matrix:", matrix)
return matrix

# Set the output of the action
def set_action_output(output_name, value) :
if "GITHUB_OUTPUT" in os.environ :
Expand All @@ -51,9 +113,12 @@ def set_action_output(output_name, value) :

def main():
languages = get_languages()
language_list = build_languages_list(languages)
output = exclude_languages(language_list)
set_action_output("languages", json.dumps(output))
language_list, language_mapping = build_languages_list(languages)
filtered_languages = exclude_languages(language_list)
matrix = build_matrix(filtered_languages, language_mapping)
set_action_output("matrix", json.dumps(matrix))
# Keep the old output for backward compatibility
set_action_output("languages", json.dumps(filtered_languages))

if __name__ == '__main__':
main()