Skip to content

allow "suffix" be optional in product queries for Python algorithms (… #1705

allow "suffix" be optional in product queries for Python algorithms (…

allow "suffix" be optional in product queries for Python algorithms (… #1705

# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: "CodeQL Analysis"
"on":
push:
branches: [main, develop]
pull_request:
schedule:
- cron: "0 3 * * 0" # weekly (UTC) — adjust as needed
workflow_dispatch:
inputs:
ref:
description: "The branch, ref, or SHA to checkout. Defaults to the repository's default branch."
required: false
type: string
workflow_call:
inputs:
checkout-path:
description: "Path to check out code to"
required: false
type: string
build-path:
description: "Path for build artifacts"
required: false
type: string
language-matrix:
description: "JSON array of languages to analyze"
required: false
type: string
pr-number:
description: "PR number if run in PR context"
required: false
type: string
pr-head-repo:
description: "The full name of the PR head repository"
required: false
type: string
pr-base-repo:
description: "The full name of the PR base repository"
required: false
type: string
pr-base-sha:
description: "Base SHA of the PR for relevance check"
required: false
type: string
pr-head-sha:
description: "Head SHA of the PR for relevance check"
required: false
type: string
ref:
description: "The branch, ref, or SHA to checkout"
required: false
type: string
repo:
description: "The repository to checkout from"
required: false
type: string
permissions:
actions: read
contents: read
security-events: write
env:
BUILD_TYPE: RelWithDebInfo
CPP_COMPILER: g++
jobs:
setup:
runs-on: ubuntu-latest
outputs:
is_act: ${{ steps.setup.outputs.is_act }}
ref: ${{ steps.setup.outputs.ref }}
repo: ${{ steps.setup.outputs.repo }}
base_sha: ${{ steps.setup.outputs.base_sha }}
pr_number: ${{ steps.setup.outputs.pr_number }}
checkout_path: ${{ steps.setup.outputs.checkout_path }}
build_path: ${{ steps.setup.outputs.build_path }}
skip_detection: ${{ steps.should_skip.outputs.skip }}
has_changes_cpp: ${{ steps.detect_cpp.outputs.has_changes }}
has_changes_python: ${{ steps.detect_python.outputs.has_changes }}
has_changes_actions: ${{ steps.detect_actions.outputs.has_changes }}
steps:
- name: Workflow setup
id: setup
uses: Framework-R-D/phlex/.github/actions/workflow-setup@main
with:
ref: ${{ inputs.ref }}
repo: ${{ inputs.repo }}
pr-base-sha: ${{ inputs.pr-base-sha }}
checkout-path: ${{ inputs.checkout-path }}
build-path: ${{ inputs.build-path }}
- name: Determine if detection should be skipped
id: should_skip
env:
IS_ACT: ${{ steps.setup.outputs.is_act }}
LANGUAGE_MATRIX: ${{ inputs.language-matrix }}
run: |
if [ "${GITHUB_EVENT_NAME}" = "schedule" ] || \
[ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ] || \
[ "${GITHUB_EVENT_NAME}" = "push" ] || \
{ [ "${GITHUB_EVENT_NAME}" = "workflow_call" ] && [ -n "${LANGUAGE_MATRIX}" ]; } || \
[ "${IS_ACT}" = "true" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Detect C++ changes
id: detect_cpp
if: steps.should_skip.outputs.skip != 'true'
uses: Framework-R-D/phlex/.github/actions/run-change-detection@main
with:
checkout-path: ${{ steps.setup.outputs.checkout_path }}
ref: ${{ steps.setup.outputs.ref }}
repo: ${{ steps.setup.outputs.repo }}
base-ref: ${{ steps.setup.outputs.base_sha }}
head-ref: ${{ inputs.pr-head-sha || steps.setup.outputs.ref }}
file-type: |
cpp
cmake
- name: Detect Python changes
id: detect_python
if: steps.should_skip.outputs.skip != 'true'
uses: Framework-R-D/phlex/.github/actions/run-change-detection@main
with:
checkout-path: ${{ steps.setup.outputs.checkout_path }}
ref: ${{ steps.setup.outputs.ref }}
repo: ${{ steps.setup.outputs.repo }}
base-ref: ${{ steps.setup.outputs.base_sha }}
head-ref: ${{ inputs.pr-head-sha || steps.setup.outputs.ref }}
file-type: python
- name: Detect Actions changes
id: detect_actions
if: steps.should_skip.outputs.skip != 'true'
uses: Framework-R-D/phlex/.github/actions/run-change-detection@main
with:
checkout-path: ${{ steps.setup.outputs.checkout_path }}
ref: ${{ steps.setup.outputs.ref }}
repo: ${{ steps.setup.outputs.repo }}
base-ref: ${{ steps.setup.outputs.base_sha }}
head-ref: ${{ inputs.pr-head-sha || steps.setup.outputs.ref }}
include-globs: |
.github/workflows/*.yaml
.github/workflows/*.yml
.github/actions/**/action.yaml
.github/actions/**/action.yml
determine-languages:
needs: setup
if: always() && needs.setup.result == 'success'
runs-on: ubuntu-latest
outputs:
languages: ${{ steps.build_matrix.outputs.languages }}
steps:
- name: Build language matrix
id: build_matrix
env:
LANGUAGE_MATRIX: ${{ inputs.language-matrix }}
SKIP_DETECTION: ${{ needs.setup.outputs.skip_detection }}
HAS_CHANGES_CPP: ${{ needs.setup.outputs.has_changes_cpp }}
HAS_CHANGES_PYTHON: ${{ needs.setup.outputs.has_changes_python }}
HAS_CHANGES_ACTIONS: ${{ needs.setup.outputs.has_changes_actions }}
run: |
# If detection was skipped, use all languages or the provided language-matrix
if [ "${SKIP_DETECTION}" = "true" ]; then
if [ "${GITHUB_EVENT_NAME}" = "workflow_call" ] && [ -n "${LANGUAGE_MATRIX}" ]; then
# Validate that language-matrix is valid JSON
if ! echo "${LANGUAGE_MATRIX}" | python3 -c "import sys, json; json.load(sys.stdin)" 2>/dev/null; then
echo "::error::Invalid language-matrix input: must be valid JSON array"
exit 1
fi
echo "languages=${LANGUAGE_MATRIX}" >> "$GITHUB_OUTPUT"
else
echo 'languages=["cpp", "python", "actions"]' >> "$GITHUB_OUTPUT"
fi
exit 0
fi
# Build array based on detection results
langs=()
if [ "${HAS_CHANGES_CPP}" = "true" ]; then
langs+=("cpp")
fi
if [ "${HAS_CHANGES_PYTHON}" = "true" ]; then
langs+=("python")
fi
if [ "${HAS_CHANGES_ACTIONS}" = "true" ]; then
langs+=("actions")
fi
# Convert bash array to JSON array
if [ "${#langs[@]}" -eq 0 ]; then
echo 'languages=[]' >> "$GITHUB_OUTPUT"
else
json_array="["
for i in "${!langs[@]}"; do
if [ "$i" -gt 0 ]; then
json_array+=","
fi
json_array+="\"${langs[$i]}\""
done
json_array+="]"
echo "languages=$json_array" >> "$GITHUB_OUTPUT"
fi
codeql:
needs: [setup, determine-languages]
if: >
needs.determine-languages.result == 'success' && needs.determine-languages.outputs.languages != '[]'
name: Analyze ${{ matrix.language }} with CodeQL
runs-on: ubuntu-24.04
container:
image: ghcr.io/framework-r-d/phlex-ci:latest
env:
local_checkout_path: ${{ needs.setup.outputs.checkout_path }}
local_build_path: ${{ needs.setup.outputs.build_path }}
CODEQL_EXTRACTOR_CPP_COMPILATION_DATABASE:
${{ github.workspace }}/${{ needs.setup.outputs.build_path }}/compile_commands.json
strategy:
fail-fast: false
matrix:
language: ${{ fromJson(needs.determine-languages.outputs.languages) }}
timeout-minutes: 120
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ needs.setup.outputs.ref }}
path: ${{ env.local_checkout_path }}
fetch-depth: 0
- name: Setup build environment
uses: Framework-R-D/phlex/.github/actions/setup-build-env@main
with:
build-path: ${{ env.local_build_path }}
- name: Initialize CodeQL
uses: github/codeql-action/init@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0
with:
languages: ${{ matrix.language }}
config-file: ${{ env.local_checkout_path }}/.github/codeql/codeql-config.yml
source-root: ${{ env.local_checkout_path }}
build-mode: none
- name: Produce compile_commands.json (C++ only)
if: matrix.language == 'cpp'
uses: Framework-R-D/phlex/.github/actions/configure-cmake@main
with:
build-type: ${{ env.BUILD_TYPE }}
source-path: ${{ env.local_checkout_path }}
build-path: ${{ env.local_build_path }}
- name: Verify compile_commands.json (C++ only)
if: matrix.language == 'cpp'
run: |
set -eu
if [ ! -f "$CODEQL_EXTRACTOR_CPP_COMPILATION_DATABASE" ]; then
echo "Expected compile_commands.json at $CODEQL_EXTRACTOR_CPP_COMPILATION_DATABASE" >&2
exit 1
fi
# Run CodeQL analysis (uploads results to code scanning)
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0
with:
checkout_path: ${{ env.local_checkout_path }}
output: results
category: ${{ matrix.language }}
- name: Upload SARIF results
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: codeql-sarif-${{ matrix.language }}
path: results
retention-days: 7
codeql-report:
name: Aggregate CodeQL alerts
needs: codeql
runs-on: ubuntu-24.04
if: needs.codeql.result == 'success'
permissions:
contents: read
issues: write
pull-requests: write
security-events: read
env:
CODEQL_MIN_LEVEL: warning
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Set log file path
id: set_log_path
run: echo "path=$RUNNER_TEMP/codeql-alerts.log" >> "$GITHUB_OUTPUT"
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Checkout Phlex for scripts
if: github.event_name == 'workflow_call'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: Framework-R-D/phlex
path: phlex
fetch-depth: 0
- name: Download CodeQL SARIF artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: codeql-sarif-*
path: sarif
merge-multiple: true
- name: Check CodeQL SARIF for new or resolved alerts
id: check_codeql
env:
LOG_PATH: ${{ steps.set_log_path.outputs.path }}
INPUT_PR_NUMBER: ${{ inputs.pr-number }}
run: |
set -eu
ARGS=(
--sarif "$GITHUB_WORKSPACE/sarif"
--min-level "${CODEQL_MIN_LEVEL}"
--log-path "${LOG_PATH}"
)
PR_NUMBER=""
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
PR_NUMBER="$(jq -r '.pull_request.number // empty' "${GITHUB_EVENT_PATH}")"
elif [ "${GITHUB_EVENT_NAME}" = "workflow_call" ]; then
PR_NUMBER="${INPUT_PR_NUMBER}"
fi
if [ -n "$PR_NUMBER" ]; then
ARGS+=(--ref "refs/pull/${PR_NUMBER}/merge")
fi
script_path="scripts/check_codeql_alerts.py"
if [ "${GITHUB_EVENT_NAME}" = "workflow_call" ]; then
script_path="phlex/$script_path"
fi
python3 "$script_path" "${ARGS[@]}"
- name: Upload CodeQL alerts debug log
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: codeql-alerts-debug-log
path: ${{ steps.set_log_path.outputs.path }}
retention-days: 3
- name: Prepare PR comment data
if: >-
github.event_name == 'pull_request' && steps.check_codeql.outputs.comment_path != ''
env:
COMMENT_PATH: ${{ steps.check_codeql.outputs.comment_path }}
run: |
mkdir -p pr_comment_data
jq -r '.pull_request.number // empty' "${GITHUB_EVENT_PATH}" > pr_comment_data/pr_number.txt
cp "${COMMENT_PATH}" pr_comment_data/comment_body.md
- name: Upload PR comment data
if: >-
github.event_name == 'pull_request' && steps.check_codeql.outputs.comment_path != ''
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: codeql-pr-data
path: pr_comment_data/
retention-days: 1
- name: Fail workflow due to new CodeQL alerts
# Fails the check on the PR so the user sees red X
if: >-
github.event_name == 'pull_request' && steps.check_codeql.outputs.new_alerts == 'true'
run: |
echo "New CodeQL alerts detected; failing job."
exit 1