Add License Scanning and Reporting for Endpoints Changes on Main. - #412
Add License Scanning and Reporting for Endpoints Changes on Main.#412arav-agarwal2 wants to merge 4 commits into
Conversation
|
MLCommons CLA bot All contributors have signed the MLCommons CLA ✍️ ✅ |
There was a problem hiding this comment.
Code Review
This pull request adds a .github/scanoss.json configuration file to define scanning skip patterns (such as tests, vendor, and third-party directories) and specify BOM inclusions and exclusions. There are no review comments, and I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
arekay-nv
left a comment
There was a problem hiding this comment.
Review-council: SCANOSS license-scan workflow
Three independent reviewers (Codex gpt-5.5, Grok 4.5, Claude) looked at this PR. The workflow is well-built and security-conscious — correct push-to-main trigger (not pull_request_target), permissions: contents: read, and defensive shell (handles the all-zeros first-push SHA, empty deltas, and a missing key). No critical/high issues: ${{ }} interpolation into run: is limited to commit SHAs + env.REPORTS_DIR (not injectable), and the data.items() results walk matches SCANOSS's output shape.
Findings below are reliability/hardening, most-severe first. The top one (flagged by all three reviewers) is the only thing I'd treat as merge-worthy — a failed scan currently reports as "clean." The rest are optional. Nothing here blocks the PR.
Co-authored-by: arekay-nv <230885705+arekay-nv@users.noreply.github.com>
| python-version: "3.11" | ||
|
|
||
| - name: Install scanoss-py | ||
| run: pip install scanoss |
There was a problem hiding this comment.
Can we pin the version for scanoss here
| python3 - <<'PY' | ||
| import json, os, uuid | ||
|
|
||
| R = os.environ.get("REPORTS_DIR", "scanoss-reports") | ||
| out = [] | ||
| def w(s=""): out.append(s) | ||
|
|
||
| # ---- license risk classification ---- | ||
| PERMISSIVE = { | ||
| "mit", "mit-0", "apache-2.0", "bsd-2-clause", "bsd-3-clause", "isc", "0bsd", | ||
| "zlib", "cc0-1.0", "unlicense", "bsl-1.0", "x11", "ncsa", "python-2.0", | ||
| "postgresql", "cc-by-4.0", "cc-by-3.0", "ofl-1.1", | ||
| } | ||
| COPYLEFT = ("gpl", "agpl", "lgpl", "mpl", "epl", "cddl", "osl", "eupl", | ||
| "cecill", "gfdl", "cc-by-sa", "sleepycat", "ms-rl") | ||
|
|
||
| def risk(name, copyleft_flag=None): | ||
| """Return a short risk reason for a single license, or None if clear.""" | ||
| n = (name or "").strip().rstrip(".").lower() | ||
| if not n: | ||
| return None | ||
| if "cc-by-nc" in n or "noncommercial" in n: | ||
| return "non-commercial" | ||
| if copyleft_flag in ("yes", True, "true") or any(c in n for c in COPYLEFT): | ||
| return "copyleft" | ||
| if n in PERMISSIVE: | ||
| return None | ||
| return "review" # not clearly permissive — worth a look | ||
|
|
||
| w("## SCANOSS — merged-delta report") | ||
| w() | ||
| w(f"Commit `{os.environ.get('GITHUB_SHA','')[:12]}` on `{os.environ.get('GITHUB_REF_NAME','')}`") | ||
| w() | ||
|
|
||
| # ---- current file-scan quota (per-key X-Ratelimit-* headers; needs the key) ---- | ||
| key = os.environ.get("SCANOSS_API_KEY", "") | ||
| if key: | ||
| try: | ||
| import requests | ||
| from scanoss.winnowing import Winnowing | ||
| wfp = Winnowing().wfp_for_contents(".github/scanoss.json", False, open(".github/scanoss.json", "rb").read()) | ||
| rid = str(uuid.uuid4()) | ||
| r = requests.post( | ||
| "https://api.osskb.org/scan/direct", | ||
| files={"file": (rid + ".wfp", wfp)}, | ||
| headers={"x-api-key": key, "X-Session": key, "User-Agent": "scanoss-ci-quota"}, | ||
| timeout=30, | ||
| ) | ||
| h = r.headers | ||
| w("### File-scan quota remaining (per key, as of this run)") | ||
| w() | ||
| w("| Window | Remaining | Limit |") | ||
| w("|---|---|---|") | ||
| for win in ("Daily", "Weekly", "Monthly"): | ||
| w(f"| {win} | {h.get('X-Ratelimit-Remaining-' + win, '?')} | {h.get('X-Ratelimit-Limit-' + win, '?')} |") | ||
| w() | ||
| except Exception as e: | ||
| w(f"_Quota probe failed: {e}_") | ||
| w() | ||
| else: | ||
| w("_Quota not shown — set the `SCANOSS_API_KEY` repo secret to enable per-key quota reporting._") | ||
| w() | ||
|
|
||
| # ---- file -> component / match% / license / risk table ---- | ||
| try: | ||
| data = json.load(open(f"{R}/results.json")) | ||
| except Exception: | ||
| data = {} | ||
|
|
||
| rows = [] | ||
| flagged = 0 | ||
| for fpath, matches in data.items(): | ||
| for m in matches: | ||
| if m.get("id") == "none": # scanned but no match | ||
| continue | ||
| purls = m.get("purl") or [] | ||
| comp = purls[0] if purls else "" | ||
| pct = m.get("matched", "") or "" | ||
| lic_objs = m.get("licenses") or [] | ||
| lics = sorted({l.get("name", "") for l in lic_objs if l.get("name")}) | ||
| reasons = sorted({r for l in lic_objs for r in [risk(l.get("name"), l.get("copyleft"))] if r}) | ||
| flag = "⚠️ " + ", ".join(reasons) if reasons else "—" | ||
| if reasons: | ||
| flagged += 1 | ||
| rows.append((fpath, comp, pct, ", ".join(lics) or "—", flag)) | ||
|
|
||
| w("### Detected components (file → license)") | ||
| w() | ||
| if flagged: | ||
| w(f"⚠️ **{flagged} of {len(rows)}** matched component(s) use potentially problematic licenses " | ||
| f"(copyleft / non-commercial / non-permissive) — see the **Potentially problematic** column.") | ||
| w() | ||
| w("| File | Component | Match | License(s) | Potentially problematic |") | ||
| w("|---|---|---|---|---|") | ||
| for fpath, comp, pct, lics, flag in rows: | ||
| w(f"| `{fpath}` | {comp} | {pct} | {lics} | {flag} |") | ||
| if not rows: | ||
| w("| _no components detected in this delta_ | | | | |") | ||
| w() | ||
|
|
||
| with open(os.environ["GITHUB_STEP_SUMMARY"], "a") as f: | ||
| f.write("\n".join(out) + "\n") | ||
| PY |
There was a problem hiding this comment.
Can we lift this out to a separate file .github/scripts/scanoss_report.py
| w() | ||
| w(f"Commit `{os.environ.get('GITHUB_SHA','')[:12]}` on `{os.environ.get('GITHUB_REF_NAME','')}`") | ||
| w() | ||
|
|
There was a problem hiding this comment.
We should also be checking SCANOSS_RC to see if the tool ran to differentiate the call failing versus a clean scan.
| { | ||
| "purl": "pkg:github/nvidia/tensorrt-edge-llm" | ||
| }, | ||
| { | ||
| "purl": "pkg:github/nvlabs/cosmos-policy" | ||
| } |
| "purl": "pkg:github/nvlabs/cosmos-policy" | ||
| } | ||
| ], | ||
| "exclude": [ |
There was a problem hiding this comment.
Is "exclude" a valid category? Didn't find it here
What does this PR do?
As part of the rollout for our AI coding policy, we'd like to add a small licensing checker to this codebase. It shouldn't block anything - it just reports changes on an action report we can review asynchronously.
Type of change
Related issues
Testing
Checklist