Hoppa till huvudinnehållet

Licensskanning

Licensskanning svarar på frågan vad får jag leverera, som ett komplement till SBOM:ens vad finns i den här imagen och beroendeskanningens vad är sårbart. fremforge kör licensdetektering med Trivy på varje PR, klassificerar licensen för varje upplöst beroende i en allvarlighetskategori enligt SPDX-policyn och visar resultatet bredvid PR:en och i en egen instrumentpanel för organisationen. Den är på som standard för varje organisation — inget att aktivera.

Så fungerar det

fremforges centrala skanner (samma som kör SAST, beroendeskanning och skanning av images) läser licensen för varje beroende som dina låsfiler löser upp, och kör Trivys detektering av licensfiler över ditt repos egna filer LICENSE/COPYING, på varje PR. Den körs på fremforges egna runners — ingenting installeras i ditt repo. Till skillnad från SAST och beroendeskanning — som postar en lista med bara problem — postar licensskanningen en fullständig inventering av licenser: ett fynd per (paket × licens) över alla upplösta beroenden. Arbetsflödet skickar sedan inventeringen till fremforge med POST:

POST https://frem.sh/_app/api/v1/license-scan/findings

Runnerns PAT behöver behörigheten findings:write (skapas per repo av runner-styrningen när arbetsflödet installeras). Vid en lyckad inläsning gör fremforge följande:

  1. Sparar fynden. En rad per fynd i license_scan_findings. Varje skanning ersätter helt den föregående skanningen för samma (tenant, repo, pr_number) — en PR som tar bort ett beroende slutar visa dess inaktuella rader. Skanningar vid push (pr_number null) har en egen grupp, så att de inte ersätter PR-skanningar.
  2. Postar en PR-kommentar som sammanfattar fynden (allvarlighetsgrad, licens, paket, manifest), via Forgejos API för issues.
  3. Sätter commit-statusen fremforge/license-scan på PR:ens head-SHA — success när allt är rådgivande eller står på listan över tillåtna, failure när policyspärren slår till.

Kommentaren och statusen i Forgejo görs på bästa möjliga sätt: ett avbrott i Forgejo loggas och nedgraderas till rådgivande men får aldrig inläsningen att misslyckas. De sparade fynden är sanningskällan; det som visas i PR:en är ett bekvämlighetslager.

Var beroendens licenser kommer ifrån

Ingenting installeras: licenserna läses från registrens metadata för exakt den version som varje låsfil fäster. För npm, PyPI, Go och Maven läses metadatan genom din organisations beroendeproxy, via skanningstjänstens interna route, eller genom fremforges delade skanningscache när din organisation inte har någon proxy; bara när ingen av dem kan svara läses den från det publika registret genom fremforges utgående proxy. Licenser för NuGet, crates.io, RubyGems och Packagist läses från det publika registret genom den utgående proxyn. fremforges tidigare paketspeglar i klustret är avvecklade.

EkosystemKällaVad som läses
npm (låsfiler för npm / pnpm / yarn / bun)registry.npmjs.org, genom beroendeproxynpaketets fält license
Go (go.mod)proxy.golang.org, genom beroendeproxyn; privata moduler (frem.sh, din angivna GOPRIVATE) begärs aldrigmodulens filer LICENSE / COPYING i roten, klassificerade med samma detektering av licensfiler som dina egna filer (Go har ingen licensmetadata)
Maven (pom.xml, Gradles låsfiler)Maven Central, genom beroendeproxynPOM:ens <licenses>, med relokeringar och föräldra-POM:er
NuGet (packages.lock.json)nuget.org, genom den utgående proxynpaketets licensuttryck, eller en igenkännbar licens-URL
PyPI (requirements.txt, Poetry, uv)pypi.org, genom beroendeproxynreleasens JSON-metadata (license_expression, en kort license, licensklassificerare)
crates.io, RubyGems, Packagistdet publika registret, genom den utgående proxynregistrets licensfält per version

Licensnamn i fritext (GPL v3, GNU AFFERO GPL 3.0, Apache License, Version 2.0, …) mappas till SPDX-identifierare. Allt som inte kan läsas med säkerhet rapporteras som unknown och visas för granskning, och gissas aldrig vara tillåtande.

När en källa ligger nere

Om en spegel eller ett register inte svarar (nätverksfel, timeout, 5xx) läses de berörda paketen varken som rena eller får blockera: statusen fremforge/license-scan behåller det som resten av skanningen gav och lägger till lookup-unavailable for N package(s), re-scan queued. fremforge kör om skanningen automatiskt med några minuters mellanrum tills källan svarar, och anteckningen försvinner.

Allvarlighetskategorier

Licensskanningen använder en vokabulär med 7 kategorier (inte de 4 nivåerna CRITICAL/HIGH/… som CVE-skanningen använder), som motsvarar Trivys klassificering enligt SPDX-policyn — ordnade från minst till mest betungande:

KategoriBetydelseExempel på licenser
unknownLicensen kunde inte fastställas (visas ändå för granskning)NOASSERTION
unencumberedMotsvarar public domainCC0-1.0, Unlicense
permissiveFri användning, minimala skyldigheter—
noticeTillåtande med skyldighet att ange upphov / meddelandeMIT, BSD-3-Clause, Apache-2.0, ISC
reciprocalSvag copyleft — ändringar i själva biblioteket delasLGPL-2.1, LGPL-3.0, MPL-2.0, EPL-2.0, CDDL-1.0, GPL-2.0 WITH Classpath-exception-2.0
restrictedStark copyleftGPL-2.0, GPL-3.0, CC-BY-SA-4.0
forbiddenNätverks-copyleft / source-availableAGPL-3.0, SSPL-1.0, BUSL-1.1, CC-BY-NC-4.0

LGPL är reciprocal i fremforge (Trivys egen tabell placerar den i restricted): ett program får länka ett LGPL-bibliotek utan att självt bli LGPL, så det är svag copyleft och blockerar inte vid standardtröskeln.

Policyinställningar

En licenspolicy sedan 2026-10-15. Listorna, reglerna för okända och flera licenser och blockeringsgraden redigeras under Säkerhet › Policyer › Licenspolicy, tillsammans med licensreglerna för paketnedladdningar. Se Licenspolicy. Säkerhet › Fynd › Licenser behåller på/av-reglaget och åsidosättningarna per repo. API-fälten nedan fungerar fortfarande och ändrar bara pull requests.

Konfigurera på sidan Licenspolicy, via API:t (PUT /orgs/<org>/code-security/licenses/settings, bara pull requests) eller som kod med Terraform- och OpenTofu-modulen:

  • Aktiverad — när den är av svarar inläsningen 202 {accepted: 0, status: 'disabled'} (arbetsflödet körs fortfarande, fynden kastas bara). På som standard.
  • Blockeringsgrad — tröskeln på eller över vilken ett fynd blockerar merge. Standard är restricted (sedan 2026-09-29; den var forbidden, vilket släppte igenom GPL-beroenden som rådgivande): stark copyleft och uppåt blockerar, svag copyleft förblir rådgivande. En licens som inte står på någon av listorna nedan bedöms efter den här tröskeln. Kombinera med branch-skydd som kräver kontrollen fremforge/license-scan för att faktiskt blockera merge.
  • Licenspolicy — uttryckliga listor och två regler, beskrivna i nästa avsnitt.

Fynd på forbidden (→ critical) eller restricted (→ high), eller som nekas av listan över nekade, som är nyinförda och inte avfärdade av en skanning utlöser också kroken för säkerhetsaviseringar i realtid; lägre kategorier är bara rådgivande.

Licenspolicy

Varje fynd avgörs per SPDX-operand, med samma tolkning som paketpolicyn använder: i MIT OR GPL-3.0-only får konsumenten välja, så den minst restriktiva operanden avgör; i Apache-2.0 AND GPL-2.0-only gäller båda, så den mest restriktiva operanden avgör. Nästlade parenteser, WITH-undantag (GPL-2.0-only WITH Classpath-exception-2.0) och identifierare av typen LicenseRef-… läses så som SPDX definierar dem.

InställningAPI-fältStandardEffekt
Lista över tillåtnaallowlisted_license_idstomEn operand på den tillåts: fyndet avfärdas vid inläsningen (aktör tenant_allowlist), oavsett kategori.
Lista över nekadedenied_license_idstomEn operand på den blockerar, oavsett kategori. Neka vinner över tillåt för samma identifierare.
Lista över varnandewarned_license_idstomEn operand på den är rådgivande: rapporteras, blockerar aldrig, oavsett kategori.
Okända licenserunknown_actionthresholdEn licens utan SPDX-identifierare, NOASSERTION, NONE, UNKNOWN, en sträng som inte är ett SPDX-uttryck, eller en identifierare som fremforge inte kan klassificera (som en LicenseRef-… som inte står på någon lista): threshold bedömer den som kategorin unknown mot blockeringsgraden; allow avfärdar den, warn rapporterar den, deny blockerar den.
Flera licensermultiple_modeallEn komponent som anger flera licenser (separata fynd, inte ett uttryck): all bedömer varje licens för sig, så vilken som helst av dem kan blockera; any låter den minst restriktiva avgöra för alla.

Posterna i listorna är SPDX-identifierare (MIT, LicenseRef-acme) eller en identifierare med sitt undantag (GPL-2.0-only WITH Classpath-exception-2.0), och matchningen skiljer inte på versaler och gemener; GPL-2.0+ matchar GPL-2.0-or-later. En post för baslicensen täcker den med vilket undantag som helst; en post för paret täcker bara paret. Upp till 100 poster per lista. En PUT ersätter inställningarna: ett fält som utelämnas får sitt standardvärde.

Standardvärdena ändrar ingenting. Med tomma listor över nekade och varnande, unknown_action: threshold och multiple_mode: all avgörs varje fynd exakt som blockeringsgraden och listan över tillåtna avgjorde det innan den här policyn fanns. Den enda skillnaden är själva listan över tillåtna, som nu matchar operander: MIT OR GPL-3.0-only godkänns av en lista över tillåtna som innehåller MIT.

Varför ett fynd blockerar

På en pull request blockerar bara fynd som pull requesten inför: ett paket och en licens som branchen redan har blockerar inte.

Varje fynd bär beslutet som policy i Findings API (GET /orgs/<org>/code-security/licenses/findings), och instrumentpanelen visar det i kolumnen Policyns beslut:

{
  "license_id": "MIT OR GPL-3.0-only",
  "policy": {
    "action": "allow",
    "rule": "allow_list",
    "decided_by": ["MIT"],
    "operands": [
      { "operand": "MIT", "action": "allow", "rule": "allow_list", "matched": "MIT" },
      { "operand": "GPL-3.0-only", "action": "block", "rule": "deny_list", "matched": "GPL-3.0-only" }
    ],
    "why": "allowed: MIT is on the allow list (OR takes the least restrictive operand)"
  }
}

action är allow, warn eller block; rule är allow_list, deny_list, warn_list, threshold, below_threshold, unknown, multiple_any eller exception. PR-kommentaren listar varje blockerande fynd med sitt skäl, och statusen fremforge/license-scan anger reglerna (2 finding(s) blocked by the licence policy (1 denied, 1 at or above restricted)).

För att prova en policy innan en PR gör det avgör POST /orgs/<org>/code-security/licenses/evaluate en lista med licenser utan att skriva något:

curl -sS -X POST -H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
  -d '{"licenses":[{"license_id":"MIT OR GPL-3.0-only"},{"license_id":"Apache-2.0 AND GPL-2.0-only"}]}' \
  https://frem.sh/_app/api/v1/orgs/<org>/code-security/licenses/evaluate

Åsidosättningar per repo

Ett repo kan åsidosätta vilket som helst av de fem policyfälten: PUT /orgs/<org>/repos/<repo>/code-security/licenses/settings med de fält som ska sättas. Ett fält som är satt ersätter organisationens värde för det repot (en lista ersätter organisationens lista; en tom array är ett värde); ett fält som saknas eller är null ärver det. GET på samma sökväg visar åsidosättningen och den gällande policyn, DELETE tar bort den. I konsolen finns åsidosättningarna under Åsidosättningar per repo på Säkerhet › Policyer › Licenspolicy.

Licensundantag för en komponent

För att acceptera en licens för en komponent — till exempel ett GPL-verktyg som din juridiska avdelning har godkänt — begär du ett undantag (POST /orgs/<org>/exceptions med kind: package, eller via konsolen) med omfånget component, regeln licence, komponentens purl utan version (pkg:npm/left-pad, pkg:pypi/requests, pkg:maven/org.example:lib) och licensens identifierare som selektor (lämna selektorn tom för vilken licens som helst för den komponenten). Det är samma undantag som för paketpolicyer: en motivering, ett obligatoriskt utgångsdatum på högst ett år och godkännande av en ägare eller namngiven godkännare som inte är den som begärde det. När det har godkänts (POST /orgs/<org>/exceptions/<id>/approve, av någon annan än den som begärde det) avfärdar nästa skanning av vilket repo som helst de matchande fynden (aktör licence-exception:<id>, dismissal_approved_by är godkännaren, skälet med motiveringen), tills undantaget går ut (fyndet öppnas igen den dagen) eller återkallas (nästa skanning öppnar det igen).

Avfärda fynd

En administratör i organisationen kan avfärda enskilda fynd (med ett obligatoriskt skäl som skrivs till granskningsloggen) från fliken Licenser. Manuella avfärdanden förs vidare genom den ersättande omskanningen vid inläsning, med nyckeln (licens-ID, paket, manifestsökväg) — att skanna om en PR återuppväcker inte ett fynd som en administratör redan har accepterat. Ett avfärdande kan ha ett valfritt utgångsdatum, varefter fyndet öppnas igen av sig självt — se när ett fynd stängs. Avfärdanden som licenspolicyn gör (listan över tillåtna, okända med allow, multiple_mode: any, ett undantag) förs inte vidare; de härleds på nytt från inställningarna vid varje skanning, så en ändring av policyn får effekt vid nästa skanning.

Var fynden visas

Säkerhet › Fynd › Licenser listar aktiva fynd och nyligen gjorda avfärdanden. Varje fynd visar allvarlighetskategorin, SPDX-licensens ID, ecosystem:package, manifestsökvägen och policyns beslut med sitt skäl. PR-kommentaren länkar tillbaka till den här instrumentpanelen.

Lagringstid

Fynd följer tenantens policy för lagringstid i granskningsloggen, på samma sätt som de andra kodsäkerhetsskannrarna. Fynd från stängda PR:er rensas av det dagliga jobbet /jobs/license-scan-closed-pr-cleanup, eftersom en stängd PR aldrig skannas om.

Se även