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.
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:
| Condition | Blocks by default | Tunable |
|---|---|---|
| A component with a forbidden-tier license | Yes | Per-team license policy |
| An open finding at Critical severity | Yes | Fixed — not env-driven |
| An open finding with a high EPSS probability | No | GATE_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:
| Tier | Meaning | Gate behaviour | Examples |
|---|---|---|---|
| Forbidden | Blocks the build | Fail | AGPL, GPL, SSPL, BUSL |
| Conditional | Needs legal review + approval | Pass, but raises an approval request | LGPL, MPL, EPL, CDDL |
| Permitted | Use freely | Pass | MIT, 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.
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
allowedin the policy, or add alicense_exception. No per-component review. - It depends on the linkage / distribution model → leave it
conditionaland let legal decide per component. This is the workflow's purpose. - Never → override the license to
forbidden. The build blocks; no review needed.
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 machine —
Not 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 — seeGATE_EPSS_THRESHOLD.
Start permissive, then tighten
A policy that blocks every build on rollout gets disabled or bypassed within a week. Ratchet instead:
- 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.
- 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.
- Tighten per team. Where a team's risk profile warrants it, override toward
forbiddenand, 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.
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:
- 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
404fallback to the static catalog).
- A component you overrode to
forbiddenfails the build gate on the next scan; one you added as alicense_exceptionpasses.
- A conditional-license component raises an approval request rather than blocking — confirming the tier split is wired.
- The
unknown_license_categoryposture is a deliberate choice (defaultconditional), not left unconsidered.
- If you enabled the EPSS gate, a finding above
GATE_EPSS_THRESHOLDfails the build while a lower-probability finding of the same severity does not.
See also
- License policies — tiers, scopes, overrides, exceptions, and the editor
- Obligation catalog — duties per license category
- Approvals — the conditional-license workflow
- Vulnerabilities — VEX triage that shapes the gate
- Environment variables — Build gate —
GATE_EPSS_THRESHOLD