Skip to main content

Policy design

A policy is the contract between "what the scanner found" and "what blocks a build". Get it wrong in one direction and every build turns red on day one and the team routes around the gate; wrong in the other and the gate never blocks anything. This page helps you design a license and vulnerability policy that is enforceable from the start and tightens over time.

Audience

team_admin designing a team policy, and super_admin setting an organization-wide default. Familiarity with the license classification tiers and the build gate. Software Composition Analysis (SCA) is the practice of inventorying and risk-scoring open-source dependencies, which is what these policies govern.

What the gate actually evaluates

Two independent conditions fail a build out of the box, plus one optional dimension:

ConditionBlocks by defaultTunable
A component with a forbidden-tier licenseYesPer-team license policy
An open finding at Critical severityYesFixed — not env-driven
An open finding with a high EPSS probabilityNoGATE_EPSS_THRESHOLD (opt-in)

Design the license side and the vulnerability side separately — they use different levers.

License tiers: the three buckets

Every license resolves to one of three tiers. This is the spine of license policy:

TierMeaningGate behaviourExamples
ForbiddenBlocks the buildFailAGPL, GPL, SSPL, BUSL
ConditionalNeeds legal review + approvalPass, but raises an approval requestLGPL, MPL, EPL, CDDL
PermittedUse freelyPassMIT, Apache-2.0, BSD, ISC

Without a policy the portal classifies against a fixed built-in catalog. A license policy makes that classification editable data — you can forbid a normally-permitted license, waive a normally-forbidden one for a single component, or set the posture for uncatalogued licenses — all at runtime, no redeploy. Resolve the scope precedence (team policy, else org default, else built-in catalog) as described in effective policy resolution.

Set an org default, override per team

Author one org-default policy as super_admin for the house rules, then let each team_admin override only where a team genuinely differs (for example, a team shipping a closed-source SaaS can treat copyleft more permissively than a team shipping a redistributed binary). Do not hand every team a blank policy — the org default is the safety net for a team that never authors one.

The uncatalogued-license posture is a real decision

unknown_license_category decides how a license absent from both the catalog and your overrides is treated. The default is conditional — an unknown license routes to approval rather than silently passing or hard-blocking. Keep it there unless you have a specific reason: allowed lets genuinely unknown terms ship unreviewed, and forbidden turns every misparsed or novel license into a build failure.

When to use the approval workflow

Conditional licenses do not block the build — they raise a request on the Approvals queue that a reviewer disposes through the state machine (Pending → Under Review → Approved / Rejected). Use it when the answer is "it depends on how we use it", not "always yes" or "always no":

  • Always yes for us → override the license to allowed in the policy, or add a license_exception. No per-component review.
  • It depends on the linkage / distribution model → leave it conditional and let legal decide per component. This is the workflow's purpose.
  • Never → override the license to forbidden. The build blocks; no review needed.
A Rejected approval does not block the build in this release

The build gate evaluates the forbidden tier only. Marking an approval Rejected records the verdict for audit but does not auto-promote the component to forbidden, so a later scan still passes it. If a component must block CI, override its license to forbidden in the policy — do not rely on the Rejected verdict. See the Rejected verdict caveat.

Because the same component in two projects raises two independent requests, decide up front whether a verdict is project-specific or house-wide — see cross-project approvals. The obligations a conditional license carries (attribution, source disclosure, copyleft) are enumerated in the obligation catalog; a reviewer reads them straight off the approval drawer.

Vulnerability gate thresholds

The severity model is fixed: Critical open findings block, everything below is informational at gate time. See the severity model. Two levers shape what "open" means and what else blocks:

  • Triage discipline (the main lever). Only open findings count. A finding you have dispositioned through the VEX state machineNot affected, False positive, Fixed — is excluded from the gate. A healthy gate depends on the team actually triaging, not on lowering the bar. VEX is the Vulnerability Exploitability eXchange model that records that triage.
  • EPSS gate (optional). Set GATE_EPSS_THRESHOLD (0–1) to also fail the build when an open finding's exploit probability crosses the line, even if it is not Critical. Leave it unset until the team is comfortable triaging — see GATE_EPSS_THRESHOLD.

Start permissive, then tighten

A policy that blocks every build on rollout gets disabled or bypassed within a week. Ratchet instead:

  1. Observe. Roll the gate out in report-only spirit — keep the default thresholds, do not add overrides, and let the team see verdicts on PRs without a wall of red. Watch the dashboard for the real distribution of licenses and severities.
  2. Codify the house rules. Author the org-default policy from what you observed: forbid what legal already forbids, set the uncatalogued posture, add exceptions for the handful of waived dependencies you actually ship.
  3. Tighten per team. Where a team's risk profile warrants it, override toward forbidden and, once triage is a habit, enable the EPSS gate. Each tightening step is a policy edit — no redeploy — so you can move one team at a time.
Tightening reclassifies existing components

Enabling a stricter policy re-evaluates every component's license expression on the next scan. A dependency that passed yesterday can block today. Announce the change, and stage it per team rather than flipping the org default under everyone at once.

Verify it worked

Sanity-check the policy you designed:

  1. An org-default policy exists and a team with no policy of its own inherits it (the team's effective-policy read returns the org default, not a 404 fallback to the static catalog).
  1. A component you overrode to forbidden fails the build gate on the next scan; one you added as a license_exception passes.
  1. A conditional-license component raises an approval request rather than blocking — confirming the tier split is wired.
  1. The unknown_license_category posture is a deliberate choice (default conditional), not left unconsidered.
  1. If you enabled the EPSS gate, a finding above GATE_EPSS_THRESHOLD fails the build while a lower-probability finding of the same severity does not.

See also