name: License Audit on: pull_request: paths: - '**/*.csproj' - '**/package.json' - '**/package-lock.json' - 'Directory.Build.props' - 'Directory.Packages.props' - 'NOTICE.md' - 'third-party-licenses/**' - 'docs/legal/**' - '.gitea/workflows/license-audit.yml' - '.gitea/scripts/validate/validate-licenses.sh' push: branches: [ main ] paths: - '**/*.csproj' - '**/package.json' - '**/package-lock.json' - 'Directory.Build.props' - 'Directory.Packages.props' schedule: # Weekly audit every Sunday at 00:00 UTC - cron: '0 0 * * 0' workflow_dispatch: inputs: full_scan: description: 'Run full transitive dependency scan' required: false default: 'false' type: boolean jobs: nuget-license-audit: name: NuGet License Audit runs-on: ubuntu-22.04 env: DOTNET_NOLOGO: 1 DOTNET_CLI_TELEMETRY_OPTOUT: 1 TZ: UTC steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 - name: Setup .NET 10 uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.100 include-prerelease: true - name: Cache NuGet packages uses: actions/cache@v4 with: path: | ~/.nuget/packages .nuget/packages key: license-audit-nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} - name: Install dotnet-delice run: dotnet tool install --global dotnet-delice || true - name: Extract NuGet licenses run: | mkdir -p out/license-audit # List packages from key projects for proj in \ src/Scanner/StellaOps.Scanner.WebService/StellaOps.Scanner.WebService.csproj \ src/Cli/StellaOps.Cli/StellaOps.Cli.csproj \ src/Authority/StellaOps.Authority/StellaOps.Authority.WebService/StellaOps.Authority.WebService.csproj \ src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj do if [ -f "$proj" ]; then name=$(basename $(dirname "$proj")) echo "Scanning: $proj" dotnet list "$proj" package --include-transitive 2>/dev/null | tee -a out/license-audit/nuget-packages.txt || true fi done - name: Validate against allowlist run: | bash .gitea/scripts/validate/validate-licenses.sh nuget out/license-audit/nuget-packages.txt - name: Upload NuGet license report uses: actions/upload-artifact@v4 with: name: nuget-license-report path: out/license-audit retention-days: 30 npm-license-audit: name: npm License Audit runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' cache-dependency-path: src/Web/StellaOps.Web/package-lock.json - name: Install license-checker run: npm install -g license-checker - name: Audit Angular frontend run: | mkdir -p out/license-audit cd src/Web/StellaOps.Web npm ci --prefer-offline --no-audit --no-fund 2>/dev/null || npm install license-checker --json --production > ../../../out/license-audit/npm-angular-licenses.json license-checker --csv --production > ../../../out/license-audit/npm-angular-licenses.csv license-checker --summary --production > ../../../out/license-audit/npm-angular-summary.txt - name: Audit DevPortal run: | cd src/DevPortal/StellaOps.DevPortal.Site if [ -f package-lock.json ]; then npm ci --prefer-offline --no-audit --no-fund 2>/dev/null || npm install license-checker --json --production > ../../../out/license-audit/npm-devportal-licenses.json || true fi continue-on-error: true - name: Validate against allowlist run: | bash .gitea/scripts/validate/validate-licenses.sh npm out/license-audit/npm-angular-licenses.json - name: Upload npm license report uses: actions/upload-artifact@v4 with: name: npm-license-report path: out/license-audit retention-days: 30 vendored-license-check: name: Vendored Components Check runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 - name: Verify vendored license files exist run: | echo "Checking vendored license files..." # Required license files required_files=( "third-party-licenses/tree-sitter-MIT.txt" "third-party-licenses/tree-sitter-ruby-MIT.txt" "third-party-licenses/AlexMAS.GostCryptography-MIT.txt" ) missing=0 for file in "${required_files[@]}"; do if [ ! -f "$file" ]; then echo "ERROR: Missing required license file: $file" missing=$((missing + 1)) else echo "OK: $file" fi done if [ $missing -gt 0 ]; then echo "ERROR: $missing required license file(s) missing" exit 1 fi echo "All vendored license files present." - name: Verify NOTICE.md is up to date run: | echo "Checking NOTICE.md references..." # Check that vendored components are mentioned in NOTICE.md for component in "tree-sitter" "AlexMAS.GostCryptography" "CryptoPro"; do if ! grep -q "$component" NOTICE.md; then echo "WARNING: $component not mentioned in NOTICE.md" else echo "OK: $component referenced in NOTICE.md" fi done - name: Verify vendored source has LICENSE run: | echo "Checking vendored source directories..." # GostCryptography fork must have LICENSE file gost_dir="src/__Libraries/StellaOps.Cryptography.Plugin.CryptoPro/third_party/AlexMAS.GostCryptography" if [ -d "$gost_dir" ]; then if [ ! -f "$gost_dir/LICENSE" ]; then echo "ERROR: $gost_dir is missing LICENSE file" exit 1 else echo "OK: $gost_dir/LICENSE exists" fi fi license-compatibility-check: name: License Compatibility Check runs-on: ubuntu-22.04 needs: [nuget-license-audit, npm-license-audit] steps: - name: Checkout uses: actions/checkout@v4 - name: Download NuGet report uses: actions/download-artifact@v4 with: name: nuget-license-report path: out/nuget - name: Download npm report uses: actions/download-artifact@v4 with: name: npm-license-report path: out/npm - name: Check for incompatible licenses run: | echo "Checking for AGPL-3.0-or-later incompatible licenses..." # Known incompatible licenses (SPDX identifiers) incompatible=( "GPL-2.0-only" "SSPL-1.0" "BUSL-1.1" "Commons-Clause" "Proprietary" ) found_issues=0 # Check npm report if [ -f out/npm/npm-angular-licenses.json ]; then for license in "${incompatible[@]}"; do if grep -qi "\"$license\"" out/npm/npm-angular-licenses.json; then echo "ERROR: Incompatible license found in npm dependencies: $license" found_issues=$((found_issues + 1)) fi done fi if [ $found_issues -gt 0 ]; then echo "ERROR: Found $found_issues incompatible license(s)" exit 1 fi echo "All licenses compatible with AGPL-3.0-or-later" - name: Generate combined report run: | mkdir -p out/combined cat > out/combined/license-audit-summary.md << 'EOF' # License Audit Summary Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ) Commit: ${{ github.sha }} ## Status: PASSED All dependencies use licenses compatible with AGPL-3.0-or-later. ## Allowed Licenses - MIT - Apache-2.0 - BSD-2-Clause - BSD-3-Clause - ISC - 0BSD - PostgreSQL - MPL-2.0 - CC0-1.0 - Unlicense ## Reports - NuGet: See nuget-license-report artifact - npm: See npm-license-report artifact ## Documentation - Full dependency list: docs/legal/THIRD-PARTY-DEPENDENCIES.md - Compatibility analysis: docs/legal/LICENSE-COMPATIBILITY.md EOF - name: Upload combined report uses: actions/upload-artifact@v4 with: name: license-audit-summary path: out/combined retention-days: 90