Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
56 changes: 47 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,18 @@ on:
jobs:
create-matrix:
runs-on: ubuntu-latest
permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: read
outputs:
matrix: ${{ steps.set-matrix.outputs.languages }}
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Get languages from repo
id: set-matrix
Expand All @@ -43,16 +53,15 @@ jobs:
needs: create-matrix
if: ${{ needs.create-matrix.outputs.matrix != '[]' }}
name: Analyze
runs-on: ubuntu-latest
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
actions: read
contents: read
security-events: write

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 +72,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 +98,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 +110,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
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()