From 036653a8007dc2c2d73a216c61388482e002b1cc Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com.> Date: Thu, 17 Jul 2025 16:16:05 +0100 Subject: [PATCH] OR license check --- .../workflows/frontend-licenses-update.yml | 39 ++++++---- frontend/package-lock.json | 78 +++++++++---------- frontend/scripts/generate-licenses.js | 36 ++++++++- 3 files changed, 97 insertions(+), 56 deletions(-) diff --git a/.github/workflows/frontend-licenses-update.yml b/.github/workflows/frontend-licenses-update.yml index c55c20e8a..0aaeda10f 100644 --- a/.github/workflows/frontend-licenses-update.yml +++ b/.github/workflows/frontend-licenses-update.yml @@ -1,6 +1,13 @@ name: Frontend License Report Workflow on: + push: + branches: + - V2 + paths: + - "frontend/package.json" + - "frontend/package-lock.json" + - "frontend/scripts/generate-licenses.js" pull_request: branches: - V2 @@ -60,8 +67,9 @@ jobs: echo "LICENSE_WARNINGS_EXIST=false" >> $GITHUB_ENV fi + # PR Event: Check licenses and comment on PR - name: Delete previous license check comments - if: github.event.pull_request + if: github.event_name == 'pull_request' uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: github-token: ${{ steps.setup-bot.outputs.token }} @@ -94,7 +102,7 @@ jobs: } - name: Comment on PR - License Check Results - if: github.event.pull_request + if: github.event_name == 'pull_request' uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: github-token: ${{ steps.setup-bot.outputs.token }} @@ -140,21 +148,22 @@ The frontend license report has been updated successfully.`; body: commentBody }); - - name: Fail workflow if license warnings exist - if: env.LICENSE_WARNINGS_EXIST == 'true' + - name: Fail workflow if license warnings exist (PR only) + if: github.event_name == 'pull_request' && env.LICENSE_WARNINGS_EXIST == 'true' run: | echo "❌ License warnings detected. Failing the workflow." exit 1 - - name: Commit changes + # Push Event: Commit license files and create PR + - name: Commit changes (Push only) + if: github.event_name == 'push' run: | git add frontend/src/assets/3rdPartyLicenses.json - if [ -f "frontend/src/assets/license-warnings.json" ]; then - git add frontend/src/assets/license-warnings.json - fi + # Note: Do NOT commit license-warnings.json - it's only for PR review git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV - - name: Prepare PR body + - name: Prepare PR body (Push only) + if: github.event_name == 'push' run: | PR_BODY="Auto-generated by ${{ steps.setup-bot.outputs.app-slug }}[bot] @@ -176,9 +185,9 @@ The frontend license report has been updated successfully.`; echo "$PR_BODY" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV - - name: Create Pull Request + - name: Create Pull Request (Push only) id: cpr - if: env.CHANGES_DETECTED == 'true' + if: github.event_name == 'push' && env.CHANGES_DETECTED == 'true' uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: token: ${{ steps.setup-bot.outputs.token }} @@ -195,14 +204,14 @@ The frontend license report has been updated successfully.`; delete-branch: true sign-commits: true - - name: Enable Pull Request Automerge - if: steps.cpr.outputs.pull-request-operation == 'created' && env.LICENSE_WARNINGS_EXIST == 'false' + - name: Enable Pull Request Automerge (Push only) + if: github.event_name == 'push' && steps.cpr.outputs.pull-request-operation == 'created' && env.LICENSE_WARNINGS_EXIST == 'false' run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}" env: GH_TOKEN: ${{ steps.setup-bot.outputs.token }} - - name: Add review required label - if: steps.cpr.outputs.pull-request-operation == 'created' && env.LICENSE_WARNINGS_EXIST == 'true' + - name: Add review required label (Push only) + if: github.event_name == 'push' && steps.cpr.outputs.pull-request-operation == 'created' && env.LICENSE_WARNINGS_EXIST == 'true' run: gh pr edit "${{ steps.cpr.outputs.pull-request-number }}" --add-label "license-review-required" env: GH_TOKEN: ${{ steps.setup-bot.outputs.token }} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2394cca9e..60c2af7e4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -3688,6 +3688,44 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/license-checker": { "version": "25.0.1", "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", @@ -3820,45 +3858,7 @@ "has-flag": "^3.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" + "node": ">=4" } }, "node_modules/lie": { diff --git a/frontend/scripts/generate-licenses.js b/frontend/scripts/generate-licenses.js index 1d747852a..cfd5f675a 100644 --- a/frontend/scripts/generate-licenses.js +++ b/frontend/scripts/generate-licenses.js @@ -276,6 +276,14 @@ function checkLicenseCompatibility(licenseSummary, licenseArray) { 'SEE LICENSE IN https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/proprietary/LICENSE' ]); + // Helper function to normalize license names for comparison + function normalizeLicense(license) { + return license + .replace(/-or-later$/, '') // Remove -or-later suffix + .replace(/\+$/, '') // Remove + suffix + .trim(); + } + // Check each license type Object.entries(licenseSummary).forEach(([license, count]) => { // Skip known good licenses @@ -302,7 +310,26 @@ function checkLicenseCompatibility(licenseSummary, licenseArray) { // Check for compound licenses like "(MIT AND Zlib)" or "(MIT OR CC0-1.0)" if (license.includes('AND') || license.includes('OR')) { - // Parse compound license + // For OR licenses, check if there's at least one acceptable license option + if (license.includes('OR')) { + // Extract license components from OR expression + const orComponents = license + .replace(/[()]/g, '') // Remove parentheses + .split(' OR ') + .map(component => component.trim()); + + // Check if any component is in the goodLicenses set (with normalization) + const hasGoodLicense = orComponents.some(component => { + const normalized = normalizeLicense(component); + return goodLicenses.has(component) || goodLicenses.has(normalized); + }); + + if (hasGoodLicense) { + return; // Skip warning - can use the good license option + } + } + + // For AND licenses or OR licenses with no good options, check for problematic components const hasProblematicComponent = Object.keys(problematicLicenses).some(problematic => license.includes(problematic) ); @@ -319,11 +346,16 @@ function checkLicenseCompatibility(licenseSummary, licenseArray) { url: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}` })); + const licenseType = license.includes('AND') ? 'AND' : 'OR'; + const reason = licenseType === 'AND' + ? 'Compound license with AND requirement - all components must be compatible' + : 'Compound license with potentially problematic components and no good fallback options'; + warnings.push({ message: `📋 This PR contains ${count} package${count > 1 ? 's' : ''} with compound license "${license}" - manual review recommended`, licenseType: license, licenseUrl: '', - reason: 'Compound license with potentially problematic components', + reason: reason, packageCount: count, affectedDependencies: affectedPackages });