Skip to content
Closed
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ Please install conda if you don't have it already. You can install [miniforge](h
# create the conda environment (assuming in base `cuopt` directory)
# note: cuOpt currently doesn't support `channel_priority: strict`;
# use `channel_priority: flexible` instead
conda env create --name cuopt_dev --file conda/environments/all_cuda-130_arch-$(uname -m).yaml
conda env create --name cuopt_dev --file conda/environments/all_cuda-131_arch-$(uname -m).yaml
# activate the environment
conda activate cuopt_dev
```
Expand Down
10 changes: 10 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# SonarQube Project Configuration
sonar.projectKey=GPUSW_cuOpt_Nvidia-cuOpt_cuopt
sonar.projectName=NVIDIA cuOpt
sonar.projectVersion=1.0

# Source code location
sonar.sources=.
60 changes: 60 additions & 0 deletions sonarqube/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# SonarQube Analysis

This directory contains the configuration and scripts for running automated SonarQube analysis on cuOpt branches.

## Files

- `sonar-branches.txt` - List of branches to analyze (one per line)
- `run-sonar-analysis.sh` - Automated script that clones, builds, and analyzes branches

## Quick Start

### 1. Configure Branches

Edit `sonar-branches.txt` to specify which branches to analyze:

```bash
# One branch per line
main
release/26.02

# Lines starting with # are comments
# Empty lines are ignored
```

### 2. Set Required Environment Variable

The script requires authentication:

```bash
export SONAR_TOKEN="your_token_here"
```

**Note**: Contact the cuOpt team for token details.

### 3. Run the Analysis

```bash
cd /path/to/cuopt
./sonarqube/run-sonar-analysis.sh
```

## Script Behavior

The script will automatically:

1. ✅ Validate branch configuration file exists and has at least one branch
2. ✅ Clone each branch into a fresh temporary directory
3. ✅ Create an isolated conda environment per branch
4. ✅ Build the project using `./build.sh`
5. ✅ Run SonarQube analysis with branch-specific tagging
6. ✅ Clean up temporary files and conda environments
7. ✅ Provide a summary of successful and failed branches

## Support

**Contact**: cuOpt team

For issues with:
- Build failures: See [CONTRIBUTING.md](../CONTRIBUTING.md)
- Script bugs: Report to the cuOpt team
238 changes: 238 additions & 0 deletions sonarqube/run-sonar-analysis.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#!/bin/bash
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BRANCHES_FILE="$SCRIPT_DIR/sonar-branches.txt"
WORK_DIR="/tmp/sonar-analysis-$(date +%Y%m%d-%H%M%S)"

# Conda environment file to use for building
# Adjust this path based on your CUDA version and architecture
# Available: all_cuda-129_arch-{x86_64,aarch64}.yaml, all_cuda-131_arch-{x86_64,aarch64}.yaml
ARCH=$(uname -m)
CONDA_ENV_FILE="conda/environments/all_cuda-131_arch-${ARCH}.yaml"

# SonarQube Configuration
# The token should be set via environment variable SONAR_TOKEN for security
if [ -z "$SONAR_TOKEN" ]; then
echo "ERROR: SONAR_TOKEN environment variable is not set"
echo "Please set it with: export SONAR_TOKEN=your_sonarqube_token"
HAD_FAILURES=1
exit 1
fi

# Repository URL
REPO_URL="git@github.com:NVIDIA/cuopt.git"

echo "Repository URL: $REPO_URL"
echo "Working directory: $WORK_DIR"

# Create working directory and logs directory
mkdir -p "$WORK_DIR"
LOG_DIR="$WORK_DIR/logs"
mkdir -p "$LOG_DIR"

# Persistent log directory for failures
PERSISTENT_LOG_DIR="/var/log/sonarqube/runs"
mkdir -p "$PERSISTENT_LOG_DIR" 2>/dev/null || PERSISTENT_LOG_DIR="$HOME/.sonarqube/logs/runs"
mkdir -p "$PERSISTENT_LOG_DIR"

# Track if we had failures (for cleanup decision)
HAD_FAILURES=0

# Cleanup function
cleanup() {
echo ""
if [ "$HAD_FAILURES" -eq 0 ] && [ ${#failed_branches[@]} -eq 0 ]; then
echo "All branches succeeded - cleaning up working directory: $WORK_DIR"
rm -rf "$WORK_DIR"
else
# Preserve logs on failure
RUN_ID=$(date +%Y%m%d-%H%M%S)
SAVED_LOG_DIR="$PERSISTENT_LOG_DIR/failed-run-$RUN_ID"
echo "Failures detected - preserving logs to: $SAVED_LOG_DIR"
mkdir -p "$SAVED_LOG_DIR"
cp -r "$LOG_DIR"/* "$SAVED_LOG_DIR/" 2>/dev/null || true
echo "Logs saved. Check: $SAVED_LOG_DIR"
echo "Cleaning up working directory: $WORK_DIR"
rm -rf "$WORK_DIR"
fi
}

# Register cleanup on exit
trap cleanup EXIT

# Check if branches file exists
if [ ! -f "$BRANCHES_FILE" ]; then
echo "ERROR: Branches file not found: $BRANCHES_FILE"
HAD_FAILURES=1
exit 1
fi

# Read and validate branches
branches=()
while IFS= read -r branch || [ -n "$branch" ]; do
# Skip comments and empty lines
[[ "$branch" =~ ^#.*$ ]] && continue
[[ -z "${branch// }" ]] && continue

# Trim whitespace and add to array
branch=$(echo "$branch" | xargs)
branches+=("$branch")
done < "$BRANCHES_FILE"

# Fail if no branches found
if [ ${#branches[@]} -eq 0 ]; then
echo "ERROR: No branches configured in $BRANCHES_FILE"
echo "Please add at least one branch to the file."
HAD_FAILURES=1
exit 1
fi

echo "Found ${#branches[@]} branch(es) to process: ${branches[*]}"
echo "Host: $(hostname)"
echo "Start time: $(date)"

# Track success/failure
successful_branches=()
failed_branches=()

# Process each branch
for branch in "${branches[@]}"; do
echo "=========================================="
echo "Processing branch: $branch"
echo "=========================================="

# Create a safe directory name from branch name
safe_branch_name="${branch//\//_}"
clone_dir="$WORK_DIR/$safe_branch_name"

# Clone the specific branch
echo "Cloning branch: $branch into $clone_dir"
git clone --single-branch --branch "$branch" --depth 1 "$REPO_URL" "$clone_dir" 2>&1 | tee "$LOG_DIR/clone_${safe_branch_name}.log"
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
echo "ERROR: Failed to clone branch: $branch"
failed_branches+=("$branch (clone failed)")
continue
fi

# Change to cloned directory
if ! cd "$clone_dir"; then
echo "ERROR: Failed to change directory to: $clone_dir"
failed_branches+=("$branch (cd failed)")
continue
fi

# Setup conda environment, build, and analyze
echo "Setting up conda environment for: $branch"

# Create a unique conda environment name for this branch
conda_env_name="cuopt_sonar_${safe_branch_name}"

# Create conda environment
mamba env create -n "$conda_env_name" -f "$CONDA_ENV_FILE" 2>&1 | tee "$LOG_DIR/conda_create_${safe_branch_name}.log"
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
echo "ERROR: Conda environment creation failed for branch: $branch. Check logs at $LOG_DIR/conda_create_${safe_branch_name}.log"
failed_branches+=("$branch (conda env creation failed)")
cd "$WORK_DIR" || echo "WARNING: Failed to cd to $WORK_DIR"
rm -rf "$clone_dir"
continue
fi

# Activate conda environment and run build + analysis in a subshell
echo "Building and analyzing branch: $branch in conda environment: $conda_env_name"

if ! bash -c "
set -e
source \$(conda info --base)/etc/profile.d/conda.sh
conda activate $conda_env_name

echo 'Conda environment activated: $conda_env_name'
echo 'Python version:' \$(python --version)

# Build the project
echo 'Building project...'
./build.sh 2>&1 | tee '$LOG_DIR/build_${safe_branch_name}.log'
if [ \${PIPESTATUS[0]} -ne 0 ]; then
echo 'Build failed'
exit 1
fi

# Run SonarQube analysis
# Note: SONAR_TOKEN is read from environment automatically by sonar-scanner
echo 'Running SonarQube analysis...'
sonar-scanner \
-Dsonar.branch.name='$branch' \
2>&1 | tee '$LOG_DIR/sonar_${safe_branch_name}.log'
if [ \${PIPESTATUS[0]} -ne 0 ]; then
echo 'SonarQube analysis failed'
exit 1
fi

echo 'Build and analysis completed successfully'
"; then
Comment on lines +145 to +173
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd sonarqube && ls -la

Repository: NVIDIA/cuopt

Length of output: 370


🏁 Script executed:

cat -n run-sonar-analysis.sh | head -200

Repository: NVIDIA/cuopt

Length of output: 109


🏁 Script executed:

# Check if sonar-branches.txt exists
find . -name "sonar-branches.txt" -o -name "*branches*" 2>/dev/null

Repository: NVIDIA/cuopt

Length of output: 86


🏁 Script executed:

cat -n sonarqube/run-sonar-analysis.sh | sed -n '140,180p'

Repository: NVIDIA/cuopt

Length of output: 1648


🏁 Script executed:

cat sonarqube/sonar-branches.txt

Repository: NVIDIA/cuopt

Length of output: 324


🏁 Script executed:

# Check how branches are read and processed in the script
cat -n sonarqube/run-sonar-analysis.sh | head -100

Repository: NVIDIA/cuopt

Length of output: 3731


🏁 Script executed:

# Check how safe_branch_name is derived and if there's any sanitization
cat -n sonarqube/run-sonar-analysis.sh | sed -n '100,145p'

Repository: NVIDIA/cuopt

Length of output: 2134


🏁 Script executed:

# Check conda activation and environment variable handling
cat -n sonarqube/run-sonar-analysis.sh | sed -n '1,40p'

Repository: NVIDIA/cuopt

Length of output: 1730


Prevent command injection via unquoted variable interpolation in the bash -c block.

The current code interpolates $branch and $conda_env_name into a bash -c string without proper quoting. If a branch name contains special characters or quotes, it can break out of the command context and execute arbitrary code. The safe_branch_name substitution only replaces / with _; it does not prevent quote injection.

Additionally, branch names read from sonar-branches.txt are not validated. Consider validating branch names against git check-ref-format --branch to ensure only valid Git references are accepted.

The proposed subshell approach with proper variable quoting is the correct solution:

🔧 Safer subshell-based rewrite
-  if ! bash -c "
-    set -e
-    source \$(conda info --base)/etc/profile.d/conda.sh
-    conda activate $conda_env_name
+  if ! (
+    set -e
+    source "$(conda info --base)/etc/profile.d/conda.sh"
+    conda activate "$conda_env_name"
 
-    echo 'Conda environment activated: $conda_env_name'
-    echo 'Python version:' \$(python --version)
+    echo "Conda environment activated: $conda_env_name"
+    echo "Python version: $(python --version 2>&1)"
 
     # Build the project
     echo 'Building project...'
-    ./build.sh 2>&1 | tee '$LOG_DIR/build_${safe_branch_name}.log'
+    ./build.sh 2>&1 | tee "$LOG_DIR/build_${safe_branch_name}.log"
     if [ \${PIPESTATUS[0]} -ne 0 ]; then
       echo 'Build failed'
       exit 1
     fi
 
     # Run SonarQube analysis
     # Note: SONAR_TOKEN is read from environment automatically by sonar-scanner
     echo 'Running SonarQube analysis...'
     sonar-scanner \
-      -Dsonar.branch.name='$branch' \
-      2>&1 | tee '$LOG_DIR/sonar_${safe_branch_name}.log'
+      -Dsonar.branch.name="$branch" \
+      2>&1 | tee "$LOG_DIR/sonar_${safe_branch_name}.log"
     if [ \${PIPESTATUS[0]} -ne 0 ]; then
       echo 'SonarQube analysis failed'
       exit 1
     fi
 
     echo 'Build and analysis completed successfully'
-  "; then
+  ); then

Also add branch name validation in the loop (lines 73–82) using git check-ref-format --branch "$branch" to reject invalid Git references early.

🤖 Prompt for AI Agents
In `@sonarqube/run-sonar-analysis.sh` around lines 145 - 173, The bash -c block
currently interpolates unquoted variables ($conda_env_name, $branch,
safe_branch_name) and can be exploited via quote/command injection; replace the
inline bash -c string with a safe subshell or heredoc that passes variables via
exported environment variables (or uses a single-quoted heredoc) so no
user-controlled value is injected into the command string, ensure all usages of
safe_branch_name and LOG_DIR in the subshell are quoted, and run sonar-scanner
and ./build.sh with their outputs piped to tee as before; additionally, add
validation where branches are read by invoking git check-ref-format --branch
"$branch" (and reject/skip invalid branches early) to prevent invalid or
malicious branch names from entering the workflow.

echo "ERROR: Build or analysis failed for branch: $branch"
if grep -q "Build failed" "$LOG_DIR/build_${safe_branch_name}.log" 2>/dev/null; then
failed_branches+=("$branch (build failed)")
else
failed_branches+=("$branch (sonar analysis failed)")
fi

# Clean up conda environment
conda env remove -n "$conda_env_name" -y 2>/dev/null || true
cd "$WORK_DIR" || echo "WARNING: Failed to cd to $WORK_DIR"
rm -rf "$clone_dir"
continue
fi

# Clean up conda environment after successful analysis
echo "Cleaning up conda environment: $conda_env_name"
conda env remove -n "$conda_env_name" -y 2>/dev/null || true

successful_branches+=("$branch")
echo "✓ Successfully completed analysis for: $branch"
echo "Progress: ${#successful_branches[@]} succeeded, ${#failed_branches[@]} failed out of ${#branches[@]} total"

# Clean up clone directory after successful analysis
echo "Cleaning up clone directory for: $branch"
cd "$WORK_DIR" || echo "WARNING: Failed to cd to $WORK_DIR"
rm -rf "$clone_dir"
done

# Final summary
echo "=========================================="
echo "SonarQube Analysis Complete"
echo "=========================================="
echo "Total branches: ${#branches[@]}"
echo "Successful: ${#successful_branches[@]}"
echo "Failed: ${#failed_branches[@]}"
echo ""

if [ ${#successful_branches[@]} -gt 0 ]; then
echo "✓ Successful branches:"
for branch in "${successful_branches[@]}"; do
echo " - $branch"
done
echo ""
fi

if [ ${#failed_branches[@]} -gt 0 ]; then
echo "✗ Failed branches:"
for branch in "${failed_branches[@]}"; do
echo " - $branch"
done
echo ""
fi

echo "End time: $(date)"
echo "=========================================="

# Exit with error if any branches failed
if [ ${#failed_branches[@]} -gt 0 ]; then
echo "ERROR: ${#failed_branches[@]} branch(es) failed analysis"
HAD_FAILURES=1
exit 1
fi

echo "All branches processed successfully!"
exit 0
12 changes: 12 additions & 0 deletions sonarqube/sonar-branches.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SonarQube Branch List
# One branch name per line
# Lines starting with # are comments and should be ignored by the cron job
# Empty lines are also ignored

# Main development branches
main
release/26.02

# Add release branches as needed
# release/v1.0
# release/v2.0