Skip to content

Commit 6736a98

Browse files
committed
Fix script to handle SARIF file recategorization
adding GitPython lib
1 parent ebd508f commit 6736a98

11 files changed

Lines changed: 753 additions & 143 deletions

File tree

.github/codeql/codeql-config.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,11 @@ paths-ignore:
1919
- "**/test/**"
2020
- "**/mock/**"
2121
- "**/codeql-coding-standards-repo/**"
22+
- "**/examples/**"
23+
- "**/docs/**"
24+
- "**/target/**"
25+
- "**/bazel-*/**"
26+
- "**/.git/**"
27+
- "**/node_modules/**"
28+
- "**/build/**"
29+
- "**/dist/**"

.github/workflows/codeql-multiple-repo-scan.yml

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,55 +31,110 @@ concurrency:
3131
jobs:
3232
analyze-repos:
3333
name: Analyze Multiple Repositories
34-
runs-on: ubuntu-latest
34+
runs-on: ubuntu-latest # More powerful runner for heavy CodeQL analysis
35+
timeout-minutes: 120 # Prevent indefinite hanging
3536
permissions:
3637
security-events: write
3738
packages: read
3839
actions: read
3940
contents: read
4041
steps:
42+
- name: Check runner resources
43+
run: |
44+
echo "=== System Resources ==="
45+
free -h
46+
df -h
47+
echo "=== CPU Info ==="
48+
nproc
49+
echo "======================="
4150
- name: Checkout central repository
4251
uses: actions/checkout@v4
43-
- name: Checkout CodeQL Coding Standards scripts
44-
uses: actions/checkout@v4
45-
with:
46-
repository: github/codeql-coding-standards
47-
path: codeql-coding-standards-repo # Klonen in diesen Ordner
48-
ref: main # Oder eine spezifische Release-Version, z.B. 'v2.53.0-dev'
4952
# Add coding standard packages and dependencies
50-
- name: Install Python dependencies for Coding Standards scripts
53+
- name: Install Python dependencies
5154
run: |
5255
python3 -m pip install --upgrade pip
53-
pip3 install pyyaml jsonpath-ng jsonschema jsonpatch jsonpointer pytest sarif-tools
56+
pip3 install --break-system-packages pyyaml jsonpath-ng jsonschema jsonpatch jsonpointer pytest sarif-tools GitPython
5457
- name: Parse known_good.json and create repos.json
5558
id: parse-repos
5659
run: |
57-
scripts/workflow/parse_repos.sh
60+
python3 scripts/tooling/cli/workflow/parse_repos.py
61+
# Cache repository checkouts to speed up re-runs
62+
- name: Cache repository checkouts
63+
uses: actions/cache@v4
64+
with:
65+
path: repos/
66+
key: repos-${{ hashFiles('known_good.json') }}
67+
restore-keys: |
68+
repos-
5869
- name: Checkout all pinned repositories
5970
id: checkout-repos
71+
timeout-minutes: 30
72+
env:
73+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
74+
run: |
75+
python3 scripts/tooling/cli/workflow/checkout_repos.py
76+
- name: List files in repos directory (debug)
6077
run: |
61-
scripts/workflow/checkout_repos.sh
78+
echo "Listing repos directory structure:"
79+
du -sh repos/* 2>/dev/null || echo "repos directory not found"
80+
df -h
6281
- name: Initialize CodeQL for all repositories
82+
timeout-minutes: 15
6383
uses: github/codeql-action/init@v4
6484
with:
6585
languages: cpp
6686
build-mode: none
6787
packs: codeql/misra-cpp-coding-standards
68-
config-file: ./.github/codeql/codeql-config.yml
88+
paths:
89+
- repos
90+
paths-ignore:
91+
- '**/*test*'
92+
- '**/*mock*'
93+
- '**/test/**'
94+
- '**/mock/**'
95+
- '**/examples/**'
96+
- '**/docs/**'
97+
- '**/target/**'
98+
- '**/bazel-*/**'
99+
- '**/.git/**'
100+
- '**/node_modules/**'
101+
- '**/build/**'
102+
- '**/dist/**'
69103
- name: Perform CodeQL Analysis
104+
timeout-minutes: 120 # Increased for multi-repo MISRA analysis
70105
uses: github/codeql-action/analyze@v4
71106
with:
72107
upload-database: false # Don't upload databases for each repo
73108
output: sarif-results/
74109
category: "multi-repo-scan"
110+
# Cleanup large repo directories to free disk space
111+
- name: Cleanup repository checkouts
112+
if: always()
113+
run: |
114+
echo "Cleaning up checked out repositories to free disk space"
115+
rm -rf repos/
116+
df -h
117+
# Checkout CodeQL Coding Standards AFTER analysis for recategorization
118+
- name: Checkout CodeQL Coding Standards scripts
119+
uses: actions/checkout@v4
120+
with:
121+
repository: github/codeql-coding-standards
122+
path: codeql-coding-standards-repo
123+
ref: v2.50.0
75124
- name: Recategorize Guidelines
76125
if: always()
126+
timeout-minutes: 10
77127
run: |
78-
scripts/workflow/recategorize_guidelines.sh
128+
python3 scripts/tooling/cli/workflow/recategorize_guidelines.py
79129
- name: Generate HTML Report from SARIF
130+
timeout-minutes: 5
80131
run: |
81132
SARIF_FILE="sarif-results/cpp.sarif"
82-
sarif html "$SARIF_FILE" --output codeql-report.html
133+
if [ -f "$SARIF_FILE" ]; then
134+
sarif html "$SARIF_FILE" --output codeql-report.html
135+
else
136+
echo "SARIF file not found, skipping HTML generation"
137+
fi
83138
- name: Upload SARIF results as artifact
84139
uses: actions/upload-artifact@v4
85140
with:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2026 Qorix
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
"""Workflow CLI commands for CI/CD operations."""
14+
15+
import argparse
16+
17+
18+
def register(subparsers: argparse._SubParsersAction) -> None:
19+
"""
20+
Register workflow CLI commands.
21+
22+
Args:
23+
subparsers: Subparser action from parent parser
24+
"""
25+
# Workflow commands are standalone scripts, not subcommands
26+
# This file exists for organizational purposes
27+
pass
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#!/usr/bin/env python3
2+
# *******************************************************************************
3+
# Copyright (c) 2026 Qorix
4+
#
5+
# See the NOTICE file(s) distributed with this work for additional
6+
# information regarding copyright ownership.
7+
#
8+
# This program and the accompanying materials are made available under the
9+
# terms of the Apache License Version 2.0 which is available at
10+
# https://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# SPDX-License-Identifier: Apache-2.0
13+
# *******************************************************************************
14+
"""
15+
Checkout all pinned repositories for CodeQL analysis.
16+
17+
Uses scripts.tooling.lib.git_operations for repository checkout operations
18+
with GitHub API authentication to avoid rate limits.
19+
"""
20+
21+
import json
22+
import logging
23+
import os
24+
import sys
25+
from pathlib import Path
26+
27+
# Add repository root to path for module imports
28+
_REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent.parent
29+
if str(_REPO_ROOT) not in sys.path:
30+
sys.path.insert(0, str(_REPO_ROOT))
31+
from scripts.tooling.lib.git_operations import shallow_clone_repository
32+
33+
_LOG = logging.getLogger(__name__)
34+
logging.basicConfig(level=logging.INFO, format="%(message)s")
35+
36+
37+
def load_repos_config(config_file: str = "./repos.json") -> list[dict]:
38+
"""
39+
Load repository configuration from repos.json.
40+
41+
Args:
42+
config_file: Path to repos.json file
43+
44+
Returns:
45+
List of repository configurations
46+
47+
Raises:
48+
SystemExit: If file not found or invalid JSON
49+
"""
50+
config_path = Path(config_file)
51+
52+
if not config_path.exists():
53+
_LOG.error(f"Error: file not found '{config_file}'")
54+
sys.exit(1)
55+
56+
try:
57+
with open(config_path, "r") as f:
58+
repos = json.load(f)
59+
return repos
60+
except (json.JSONDecodeError, IOError) as e:
61+
_LOG.error(f"Error: Failed to load repos.json: {e}")
62+
sys.exit(1)
63+
64+
65+
def checkout_repo(name: str, url: str, ref: str, path: str) -> bool:
66+
"""
67+
Checkout a single repository using git_operations library.
68+
69+
Args:
70+
name: Repository name
71+
url: Repository URL
72+
ref: Git reference (branch, tag, or commit hash)
73+
path: Local path to checkout into
74+
75+
Returns:
76+
True if successful, False otherwise
77+
"""
78+
path_obj = Path(path)
79+
80+
_LOG.info(f"Checking out {name} ({ref}) to {path}")
81+
82+
return shallow_clone_repository(url=url, path=path_obj, ref=ref)
83+
84+
85+
def main() -> int:
86+
"""Main entry point for standalone execution."""
87+
# Load repository configurations
88+
repos = load_repos_config("./repos.json")
89+
repo_count = len(repos)
90+
91+
_LOG.info(f"Checking out {repo_count} repositories...")
92+
93+
# Track successfully checked out repositories
94+
repo_paths = []
95+
96+
# Checkout each repository
97+
for i, repo in enumerate(repos):
98+
name = repo.get("name", f"repo-{i}")
99+
url = repo.get("url", "")
100+
ref = repo.get("version", "")
101+
path = repo.get("path", "")
102+
103+
if not all([url, ref, path]):
104+
_LOG.warning(f"Skipping {name} - missing required fields")
105+
continue
106+
107+
if checkout_repo(name, url, ref, path):
108+
repo_paths.append(path)
109+
else:
110+
_LOG.error(f"Failed to checkout {name}")
111+
112+
# Output all paths (comma-separated for GitHub Actions compatibility)
113+
repo_paths_output = ",".join(repo_paths)
114+
115+
# Write to GITHUB_OUTPUT if available
116+
github_output = os.environ.get("GITHUB_OUTPUT")
117+
if github_output:
118+
try:
119+
with open(github_output, "a") as f:
120+
f.write(f"repo_paths={repo_paths_output}\n")
121+
except IOError as e:
122+
_LOG.warning(f"Failed to write GITHUB_OUTPUT: {e}")
123+
124+
# Print summary
125+
_LOG.info(f"\nSuccessfully checked out {len(repo_paths)} of {repo_count} repositories")
126+
_LOG.info(f"repo_paths={repo_paths_output}")
127+
128+
return 0 if len(repo_paths) == repo_count else 1
129+
130+
131+
if __name__ == "__main__":
132+
sys.exit(main())

0 commit comments

Comments
 (0)