diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 44da2839..4ae375b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -187,6 +187,25 @@ jobs: run: | docker run --rm --volume $(pwd):/note-c/ --workdir /note-c/ --entrypoint ./scripts/run_cppcheck.sh ghcr.io/blues/note_c_ci:latest + run_license_scan: + runs-on: ubuntu-latest + if: ${{ always() }} + needs: [build_ci_docker_image] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Load CI Docker image + # Only load the Docker image artifact if build_ci_docker_image actually + # ran (e.g. it wasn't skipped and was successful). + if: ${{ needs.build_ci_docker_image.result == 'success' }} + uses: ./.github/actions/load-ci-image + + - name: Run license compliance scan + run: | + docker run --rm --volume $(pwd):/note-c/ --workdir /note-c/ --entrypoint ./scripts/run_license_scan.sh ghcr.io/blues/note_c_ci:latest + publish_ci_image: runs-on: ubuntu-latest # Make sure unit tests unit tests passed before publishing. diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b00c48ce..a0d20cc9 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -119,6 +119,21 @@ "$gcc" ], "group": "test" + }, + { + "label": "Note-C: Run License Compliance Scan", + "type": "shell", + "command": "${workspaceFolder}/scripts/run_license_scan.sh", + "options": { + "cwd": "${workspaceFolder}", + "env": { + "LC_ALL": "C" + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": "test" } ] } diff --git a/scripts/run_license_scan.sh b/scripts/run_license_scan.sh new file mode 100755 index 00000000..83f1d216 --- /dev/null +++ b/scripts/run_license_scan.sh @@ -0,0 +1,140 @@ +#!/bin/bash +set -eo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +SRC_DIR="$SCRIPT_DIR/.." + +echo "Running License Compliance Analysis..." +echo + +# Install FOSSology scanners if not already installed +if ! command -v nomossa &> /dev/null || ! command -v copyright &> /dev/null; then + echo "Installing FOSSology scanners..." + apt-get update -qq + apt-get install -y --no-install-recommends wget ca-certificates + + # Create a temporary directory for FOSSology tools + mkdir -p /tmp/fossology + cd /tmp/fossology + + # Download and extract FOSSology CLI tools + wget -q https://github.com/fossology/fossology/releases/download/4.4.0/fossology-4.4.0-1_amd64.deb + dpkg -x fossology-4.4.0-1_amd64.deb . + + # Copy the scanner binaries to a location in PATH + cp -f usr/lib/fossology/agents/nomossa /usr/local/bin/ + cp -f usr/lib/fossology/agents/ojo /usr/local/bin/ + cp -f usr/lib/fossology/agents/copyright /usr/local/bin/ + + # Clean up + cd - + rm -rf /tmp/fossology + + echo "FOSSology scanners installed successfully." +fi + +# Create a function to generate the summary +generate_summary() { + { + # Initialize flag + has_critical_issues=false + + echo + + # Always generate and display summary regardless of exit code + echo "=== License Compliance Summary ===" + echo + + # Display critical issues + echo "Critical License Issues:" + echo "------------------------" + grep -E "Critical:" fossology_output.txt | sort | uniq || echo "None found" + echo + + # Display license findings + echo "License Findings:" + echo "----------------" + grep -E "License:" fossology_output.txt | grep -v "Critical:" | sort | uniq || echo "None found" + echo + + # Display copyright findings + echo "Copyright Findings:" + echo "------------------" + grep -E "Copyright:" fossology_output.txt | sort | uniq || echo "None found" + echo + + # Count issues by category + echo " Issue Count by Category: " + echo "-------------------------" + for category in "Critical" "License" "Copyright" "Keyword"; do + count=$(grep -c "${category}:" fossology_output.txt) || true + printf "%-15s %3d findings\n" "${category}:" "$count" + + # Check if 'category' is 'Critical' and if 'count' is greater than 0 + if [[ "$category" == "Critical" ]] && [ "$count" -gt 0 ]; then + has_critical_issues=true + fi + done + echo + + # Display status and details + if $has_critical_issues; then + echo "Status: FAILED - Critical license issues found" + echo + echo "Review and fix critical license issues before proceeding" + else + echo "Status: PASSED - No critical license issues found" + echo + echo "Note: Review non-critical findings for potential improvements" + fi + } + + # Return 1 if critical issues found, 0 otherwise + if $has_critical_issues; then + return 1 + else + return 0 + fi +} + +# Create output file +touch fossology_output.txt + +# Run license scanners directly +echo "Running Nomos license scanner..." +find "$SRC_DIR" -type f -not -path "*/\.*" -not -path "*/build/*" | while read -r file; do + if [ -f "$file" ]; then + # Run nomos scanner + if command -v nomossa &> /dev/null; then + result=$(nomossa "$file" 2>/dev/null || echo "No license found") + if [ "$result" != "No license found" ]; then + echo "License: $result in $file" >> fossology_output.txt + + # Check for non-MIT licenses (example of a critical issue) + if [[ "$result" != *"MIT"* ]] && [[ "$result" != *"SPDX"* ]]; then + echo "Critical: Non-MIT license found: $result in $file" >> fossology_output.txt + fi + fi + fi + + # Run copyright scanner + if command -v copyright &> /dev/null; then + copyright_result=$(copyright "$file" 2>/dev/null || echo "") + if [ -n "$copyright_result" ]; then + echo "Copyright: $copyright_result in $file" >> fossology_output.txt + fi + fi + fi +done + +# Run keyword scanner (simple implementation) +echo "Running keyword scanner..." +grep -r --include="*.c" --include="*.h" --include="*.cpp" --include="*.hpp" -l "GPL\|GNU" "$SRC_DIR" | while read -r file; do + echo "Keyword: Potential GPL reference in $file" >> fossology_output.txt + echo "Critical: Potential GPL license reference in $file" >> fossology_output.txt +done + +generate_summary + +# Exit with summary's status code +exit $?