From eeeb68bcd60a751a89bc74f9f167388fbc64de69 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 21 Feb 2026 22:44:25 -0700 Subject: [PATCH] ci: add license compliance workflow and CI Testing Pipeline gate job Add SHIELD license compliance scan workflow that checks dependencies against an allowlist of permissive licenses on dependency changes, weekly schedule, and manual dispatch. Add CI Testing Pipeline aggregation job to ci.yml so branch protection can require a single check instead of every matrix combination. Update admin-guide.md with the new required status checks. --- .github/workflows/ci.yml | 13 ++ .../workflows/shield-license-compliance.yml | 130 ++++++++++++++++++ docs/admin-guide.md | 2 +- 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/shield-license-compliance.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ded3a682..cface025 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,3 +68,16 @@ jobs: - name: Check compilation run: cargo check --workspace + + ci-pipeline: + if: always() + needs: [lint, test, rust-check] + runs-on: ubuntu-latest + name: CI Testing Pipeline + steps: + - name: Check results + run: | + if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + echo "One or more CI jobs failed or were cancelled." + exit 1 + fi diff --git a/.github/workflows/shield-license-compliance.yml b/.github/workflows/shield-license-compliance.yml new file mode 100644 index 00000000..506e137a --- /dev/null +++ b/.github/workflows/shield-license-compliance.yml @@ -0,0 +1,130 @@ +name: "[SHIELD] Open Source Licenses" + +on: + push: + branches: [main] + paths: + - "package.json" + - "package-lock.json" + pull_request: + branches: [main] + paths: + - "package.json" + - "package-lock.json" + workflow_dispatch: + schedule: + - cron: "0 3 * * 1" # Weekly on Monday at 3 AM + +jobs: + os-license: + name: License Compliance Scan + permissions: + contents: read + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: "22" + cache: "npm" + + - name: Install dependencies + run: npm ci --prefer-offline --no-audit --no-fund + + - name: Install license-checker + run: npm install -g license-checker + + - name: Create reports directory + run: mkdir -p license-reports + + - name: Run license check (allowlist) + id: allowlist + continue-on-error: true + run: | + license-checker \ + --onlyAllow 'MIT;BSD-2-Clause;BSD-3-Clause;Apache-2.0;ISC;CC0-1.0;Unlicense;WTFPL;0BSD;CC-BY-3.0;CC-BY-4.0;BlueOak-1.0.0;Python-2.0' \ + --summary | tee license-reports/allowlist-check.txt + + - name: Generate JSON report + run: license-checker --json > license-reports/licenses.json + + - name: Generate CSV report + run: license-checker --csv --out license-reports/licenses.csv + + - name: Analyze results + run: | + report="license-reports/licenses.json" + total=$(jq 'keys | length' "$report") + + echo "## License Compliance Results" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Total dependencies scanned**: $total" >> $GITHUB_STEP_SUMMARY + echo "- **Scan date**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # Show license distribution + echo "### License Distribution" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + jq -r '[.[] | .licenses // "Unknown"] | group_by(.) | map({license: .[0], count: length}) | sort_by(-.count) | .[] | "\(.count) x \(.license)"' "$report" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # Check for restrictive licenses + restrictive=$(jq -r 'to_entries[] | select(.value.licenses | test("GPL|AGPL|LGPL|SSPL|BSL"; "i")) | "- **\(.key)**: \(.value.licenses)"' "$report" 2>/dev/null || true) + + if [ -n "$restrictive" ]; then + echo "### Restrictive Licenses Found" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "$restrictive" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + echo "### License Restrictions Guide" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if echo "$restrictive" | grep -qi "AGPL\|GPL-[23]"; then + echo "#### RED - GPL/AGPL" >> $GITHUB_STEP_SUMMARY + echo "- Must release ALL source code under GPL/AGPL if distributed" >> $GITHUB_STEP_SUMMARY + echo "- AGPL extends to network/SaaS use" >> $GITHUB_STEP_SUMMARY + echo "- **Action**: Replace with MIT/BSD/Apache alternatives" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + if echo "$restrictive" | grep -qi "LGPL"; then + echo "#### CAUTION - LGPL" >> $GITHUB_STEP_SUMMARY + echo "- Must provide source of LGPL components (not entire app)" >> $GITHUB_STEP_SUMMARY + echo "- Users must be able to replace LGPL components" >> $GITHUB_STEP_SUMMARY + echo "- **Action**: Review compliance requirements or replace" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + if echo "$restrictive" | grep -qi "SSPL\|BSL"; then + echo "#### RED - SSPL/BSL" >> $GITHUB_STEP_SUMMARY + echo "- Cannot offer as a service without releasing infrastructure code" >> $GITHUB_STEP_SUMMARY + echo "- **Action**: Replace if offering SaaS/cloud services" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + # Save issues summary + echo "# Restrictive Licenses Found" > license-reports/issues-summary.md + echo "" >> license-reports/issues-summary.md + echo "$restrictive" >> license-reports/issues-summary.md + + echo "FAILURE: Restrictive licenses found in dependencies" + exit 1 + else + echo "### All Clear" >> $GITHUB_STEP_SUMMARY + echo "All dependencies use permissive licenses (MIT, BSD, Apache, ISC, etc.)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "All dependencies use acceptable licenses" + fi + + - name: Upload license reports + uses: actions/upload-artifact@v5 + with: + name: license-compliance-reports + path: license-reports/ + retention-days: 90 + if: always() diff --git a/docs/admin-guide.md b/docs/admin-guide.md index 8e1398ce..56ef6984 100644 --- a/docs/admin-guide.md +++ b/docs/admin-guide.md @@ -15,7 +15,7 @@ Go to **Settings > Branches > Add branch protection rule** for `main`: | Required approvals | 1 | | Dismiss stale pull request approvals when new commits are pushed | Yes | | Require status checks to pass before merging | Yes | -| Required status checks | `Preflight checks` (CI), `Lint` (CI), `Validate commits` (Commitlint), `Validate branch name` (Commitlint) | +| Required status checks | `CI Testing Pipeline` (CI), `Lint` (CI), `Validate commits` (Commitlint), `Validate branch name` (Commitlint), `License Compliance Scan` (SHIELD) | | Require branches to be up to date before merging | Yes | | Require conversation resolution before merging | Yes | | Restrict who can push to matching branches | Optional (recommended for teams) |