Skip to content

Commit 9532b07

Browse files
committed
Fix script to handle SARIF file recategorization
Signed-off-by: Saumya Rai <saumya.rai@qorix.ai> adding debug adding python files for codeql scripts adding formatting adding filter for coding guidelines files
1 parent 8038ca2 commit 9532b07

File tree

5 files changed

+497
-3
lines changed

5 files changed

+497
-3
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,15 @@ jobs:
5454
- name: Parse known_good.json and create repos.json
5555
id: parse-repos
5656
run: |
57-
scripts/workflow/parse_repos.sh
57+
python3 scripts/workflow/parse_repos.py
5858
- name: Checkout all pinned repositories
5959
id: checkout-repos
6060
run: |
61-
scripts/workflow/checkout_repos.sh
61+
python3 scripts/workflow/checkout_repos.py
62+
- name: List files in repos directory (debug)
63+
run: |
64+
echo "Listing all files in repos directory before CodeQL analysis:"
65+
find repos || echo "repos directory not found"
6266
- name: Initialize CodeQL for all repositories
6367
uses: github/codeql-action/init@v4
6468
with:
@@ -75,7 +79,7 @@ jobs:
7579
- name: Recategorize Guidelines
7680
if: always()
7781
run: |
78-
scripts/workflow/recategorize_guidelines.sh
82+
python3 scripts/workflow/recategorize_guidelines.py
7983
- name: Generate HTML Report from SARIF
8084
run: |
8185
SARIF_FILE="sarif-results/cpp.sarif"

scripts/workflow/checkout_repos.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#!/usr/bin/env python3
2+
# *******************************************************************************
3+
# Copyright (c) 2025 Contributors to the Eclipse Foundation
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 based on repos.json configuration.
16+
"""
17+
18+
import json
19+
import sys
20+
import subprocess
21+
import re
22+
import os
23+
from pathlib import Path
24+
25+
26+
def load_repos_config(config_file="./repos.json"):
27+
"""
28+
Load repository configuration from repos.json.
29+
30+
Args:
31+
config_file: Path to repos.json file
32+
33+
Returns:
34+
List of repository configurations
35+
"""
36+
config_path = Path(config_file)
37+
38+
if not config_path.exists():
39+
print(f"Error: file not found '{config_file}'", file=sys.stderr)
40+
sys.exit(1)
41+
42+
try:
43+
with open(config_path, "r") as f:
44+
repos = json.load(f)
45+
return repos
46+
except (json.JSONDecodeError, IOError) as e:
47+
print(f"Error: Failed to load repos.json: {e}", file=sys.stderr)
48+
sys.exit(1)
49+
50+
51+
def is_commit_hash(ref):
52+
"""
53+
Check if reference looks like a commit hash (40 hex characters for SHA-1).
54+
55+
Args:
56+
ref: Git reference (branch, tag, or hash)
57+
58+
Returns:
59+
True if ref matches commit hash pattern
60+
"""
61+
return bool(re.match(r"^[0-9a-fA-F]{40}$", ref))
62+
63+
64+
def checkout_repo(name, url, ref, path):
65+
"""
66+
Checkout a single repository.
67+
68+
Args:
69+
name: Repository name
70+
url: Repository URL
71+
ref: Git reference (branch, tag, or commit hash)
72+
path: Local path to checkout into
73+
74+
Returns:
75+
True if successful, False otherwise
76+
"""
77+
path_obj = Path(path)
78+
79+
try:
80+
# Create parent directory if needed
81+
path_obj.parent.mkdir(parents=True, exist_ok=True)
82+
83+
if is_commit_hash(ref):
84+
print(f"Checking out {name} ({ref}) to {path}")
85+
print(f" Detected commit hash. Cloning and then checking out.")
86+
87+
# Clone the repository
88+
subprocess.run(["git", "clone", url, path], check=True, capture_output=True)
89+
90+
# Checkout specific commit
91+
subprocess.run(["git", "-C", path, "checkout", ref], check=True, capture_output=True)
92+
else:
93+
print(f"Checking out {name} ({ref}) to {path}")
94+
print(f" Detected branch/tag. Cloning with --branch.")
95+
96+
# Clone with shallow copy and specific branch/tag
97+
# Add 'v' prefix if not already present (common convention)
98+
branch_ref = ref if ref.startswith("v") else f"v{ref}"
99+
subprocess.run(
100+
["git", "clone", "--depth", "1", "--branch", branch_ref, url, path], check=True, capture_output=True
101+
)
102+
103+
return True
104+
105+
except subprocess.CalledProcessError as e:
106+
print(f"Error: Failed to checkout {name}: {e}", file=sys.stderr)
107+
return False
108+
109+
110+
def main():
111+
"""Main entry point."""
112+
# Load repository configurations
113+
repos = load_repos_config("./repos.json")
114+
repo_count = len(repos)
115+
116+
# Track successfully checked out repositories
117+
repo_paths = []
118+
119+
# Checkout each repository
120+
for i, repo in enumerate(repos):
121+
name = repo.get("name", f"repo-{i}")
122+
url = repo.get("url", "")
123+
ref = repo.get("version", "")
124+
path = repo.get("path", "")
125+
126+
if not all([url, ref, path]):
127+
print(f"Warning: Skipping {name} - missing required fields", file=sys.stderr)
128+
continue
129+
130+
if checkout_repo(name, url, ref, path):
131+
repo_paths.append(path)
132+
133+
# Output all paths (comma-separated for GitHub Actions compatibility)
134+
repo_paths_output = ",".join(repo_paths)
135+
136+
# Write to GITHUB_OUTPUT if available
137+
github_output = os.environ.get("GITHUB_OUTPUT")
138+
if github_output:
139+
try:
140+
with open(github_output, "a") as f:
141+
f.write(f"repo_paths={repo_paths_output}\n")
142+
except IOError as e:
143+
print(f"Warning: Failed to write GITHUB_OUTPUT: {e}", file=sys.stderr)
144+
145+
# Also print for debugging
146+
print(f"\nSuccessfully checked out {len(repo_paths)} of {repo_count} repositories")
147+
print(f"repo_paths={repo_paths_output}")
148+
149+
return 0 if len(repo_paths) == repo_count else 1
150+
151+
152+
if __name__ == "__main__":
153+
sys.exit(main())

scripts/workflow/parse_repos.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/usr/bin/env python3
2+
# *******************************************************************************
3+
# Copyright (c) 2025 Contributors to the Eclipse Foundation
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+
Parse known_good.json and create repos.json for multi-repository CodeQL analysis.
16+
"""
17+
18+
import json
19+
import os
20+
import sys
21+
import subprocess
22+
from pathlib import Path
23+
24+
25+
def install_dependencies():
26+
"""Ensure jq is installed (for reference, though we use Python's json)."""
27+
try:
28+
subprocess.run(["sudo", "apt-get", "update"], check=True, capture_output=True)
29+
subprocess.run(["sudo", "apt-get", "install", "-y", "jq"], check=True, capture_output=True)
30+
except subprocess.CalledProcessError as e:
31+
print(f"Warning: Failed to install jq: {e}", file=sys.stderr)
32+
33+
34+
def parse_known_good(json_file="./known_good.json"):
35+
"""
36+
Parse known_good.json and transform modules into repository objects.
37+
38+
Args:
39+
json_file: Path to known_good.json file
40+
41+
Returns:
42+
Tuple of (repos list, module count, module outputs dict)
43+
"""
44+
json_path = Path(json_file)
45+
46+
if not json_path.exists():
47+
print(f"Error: file not found '{json_file}'", file=sys.stderr)
48+
print(f"Current directory: {Path.cwd()}", file=sys.stderr)
49+
sys.exit(1)
50+
51+
try:
52+
with open(json_path, "r") as f:
53+
data = json.load(f)
54+
except json.JSONDecodeError as e:
55+
print(f"Error: Failed to parse JSON: {e}", file=sys.stderr)
56+
sys.exit(1)
57+
58+
# Extract target_sw modules
59+
modules = data.get("modules", {}).get("target_sw", {})
60+
61+
# Transform modules into repository objects
62+
repos = []
63+
module_outputs = {}
64+
65+
for name, config in modules.items():
66+
repo_url = config.get("repo", "")
67+
version = config.get("version", "")
68+
branch = config.get("branch", "")
69+
hash_val = config.get("hash", "")
70+
71+
# Use version, branch, or hash (in that order of preference)
72+
ref = version or branch or hash_val
73+
74+
repo_obj = {"name": name, "url": repo_url, "version": ref, "path": f"repos/{name}"}
75+
repos.append(repo_obj)
76+
77+
# Store module outputs for GITHUB_OUTPUT compatibility
78+
module_outputs[f"{name}_url"] = repo_url
79+
if version:
80+
module_outputs[f"{name}_version"] = version
81+
if branch:
82+
module_outputs[f"{name}_branch"] = branch
83+
if hash_val:
84+
module_outputs[f"{name}_hash"] = hash_val
85+
86+
return repos, len(modules), module_outputs
87+
88+
89+
def write_repos_json(repos, output_file="./repos.json"):
90+
"""Write repositories to repos.json file."""
91+
output_path = Path(output_file)
92+
93+
try:
94+
with open(output_path, "w") as f:
95+
json.dump(repos, f, indent=2)
96+
print(f"Generated {output_file}:")
97+
print(json.dumps(repos, indent=2))
98+
print() # Add newline for readability
99+
except IOError as e:
100+
print(f"Error: Failed to write {output_file}: {e}", file=sys.stderr)
101+
sys.exit(1)
102+
103+
104+
def write_github_output(outputs):
105+
"""
106+
Write outputs to GITHUB_OUTPUT for GitHub Actions compatibility.
107+
108+
Args:
109+
outputs: Dictionary of key-value pairs to output
110+
"""
111+
github_output = Path(os.environ.get("GITHUB_OUTPUT", "/dev/null"))
112+
113+
if github_output.exists() or github_output.parent.exists():
114+
try:
115+
with open(github_output, "a") as f:
116+
for key, value in outputs.items():
117+
f.write(f"{key}={value}\n")
118+
except IOError as e:
119+
print(f"Warning: Failed to write GITHUB_OUTPUT: {e}", file=sys.stderr)
120+
121+
122+
def main():
123+
"""Main entry point."""
124+
import os
125+
126+
# Install dependencies (optional, jq not strictly needed in Python version)
127+
# install_dependencies()
128+
129+
# Parse known_good.json
130+
repos, module_count, module_outputs = parse_known_good("./known_good.json")
131+
132+
# Write repos.json
133+
write_repos_json(repos)
134+
135+
# Write GitHub Actions outputs
136+
github_outputs = {"MODULE_COUNT": str(module_count)}
137+
github_outputs.update(module_outputs)
138+
write_github_output(github_outputs)
139+
140+
print("Parse complete!")
141+
142+
143+
if __name__ == "__main__":
144+
main()

0 commit comments

Comments
 (0)