> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scanoss.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from SCANOSS tools

> Move from the SCANOSS pre-commit hook, scanoss-py, Code Compare, the SCANOSS GitHub Action, and Dependency-Track policies to Earnie, in five phases.

This guide moves a team from the standalone SCANOSS toolchain to Earnie. It replaces:

* the `scanoss/pre-commit-hooks` pre-commit hook
* local `scanoss-py` scans and their `.scanoss/results.json` output
* triage in **Code Compare**, written into `scanoss.json`
* the `scanoss/actions-scan` GitHub Action and its three policy checks
* Dependency-Track as the place your policies, violations, and exceptions live

In Earnie, one product covers what that chain did: projects, scans, triage, organisation-wide policies, a merge gate, pull-request feedback, approvals, audit, and SBOM export.

**There's no side-by-side mode.** Earnie doesn't run in parallel with the old chain to compare verdicts. Phases 1 to 3 leave your existing gate in force. Phase 4 switches it over in one pull request per repository.

## What replaces what

| Legacy step | Earnie replacement |
| - | - |
| `scanoss-py scan` in a pre-commit hook, blocking on any undeclared match | The Earnie pre-commit hook, which checks your staged changes against the project's policies and produces a [Self-check](/en/latest/earnie/using-earnie/self-checks). |
| Code Compare triage, written as `bom.include`, `bom.remove`, and `bom.replace` in `scanoss.json` | [Triage](/en/latest/earnie/using-earnie/triaging-findings) in the Review Workspace. Every decision records who made it, when, and why. |
| `scanoss.json` skip patterns and component decisions | [Scan Configuration](/en/latest/earnie/using-earnie/scan-configuration), at organisation and project level. Earnie still reads your committed `scanoss.json`, and never writes to it. |
| `scanoss/actions-scan` running `scanoss-py` on your CI runners | The Earnie GitHub App or GitLab connection scans every push and pull request, inside your Earnie environment. For other pipelines, or if you prefer a CI step, run the [Earnie CLI](/en/latest/earnie/using-earnie/earnie-cli#running-in-a-pipeline). |
| Three checks: `Policy Check: Copyleft`, `Policy Check: Undeclared`, `Policy Check: Dependency Track` | One check named **Earnie** per pull request. |
| Commit comments on matched lines, a pull-request comment, and a job summary | One summary comment per pull request, updated in place, plus inline comments on the lines the pull request added. See [Merge gate](/en/latest/earnie/using-earnie/merge-gate). |
| `scanoss-py convert` to CycloneDX, SPDX Lite, or CSV | [SBOM snapshots](/en/latest/earnie/evidence/exporting-sboms) in CycloneDX 1.7 and SPDX 2.3 Lite, plus reports as HTML, CSV, Excel, or PDF, notice files, and more. `earnie export` writes one from a pipeline. |
| `scanoss-py export dt`, uploading the SBOM to Dependency-Track | Earnie keeps each project's inventory, posture, licences, and vulnerabilities itself. There's no upload step. |
| Dependency-Track policies and violation audit | Organisation-wide [Policies](/en/latest/earnie/using-earnie/setting-policies) attached to projects, and **Policy Approvals** as the one way to make an exception. |

Earnie also gives the same policies to coding agents over MCP. The legacy chain has no equivalent. See [Earnie MCP](/en/latest/earnie/mcp/overview).

## The five phases

Each phase ends with one exit criterion. Don't start the next phase until you meet it.

### Phase 1: Connect and scan

Set up your organisation, then connect your Git provider and import the repositories you want to govern. Earnie connects to GitHub, including GitHub Enterprise Server, through the Earnie GitHub App. It connects to GitLab, on gitlab.com or self-managed, with an access token. **Import all repositories** on **Settings → Integrations** imports a whole organisation or group in one action.

See [Workspace setup](/en/latest/earnie/getting-started/workspace-setup) and [Connecting a repository](/en/latest/earnie/getting-started/connecting-a-repository).

**Exit criterion:** every project in scope has one completed **full-coverage** scan of its default branch, and every connection on **Settings → Integrations** reads **Healthy**.

<Note>
  **Expect a backlog on the first full scan.** If you ran the GitHub Action in
  delta mode only, nothing has ever assessed your whole repository. The first
  full scan reports findings the legacy chain never showed you. That's not a
  regression. Plan time to triage it.
</Note>

### Phase 2: Bring over your identifications

Earnie reads each repository's committed `scanoss.json` on every scan. You don't need to import it.

| `scanoss.json` entry | What Earnie does |
| - | - |
| Skip patterns | Added to the organisation's and project's skip patterns. Earnie doesn't scan a file that any layer skips. |
| `bom.remove` | Settles the matching findings as **Mark original**. The code is your own, and the findings leave the gate. |
| `bom.replace` | Settles the matching findings as **Replace component**, against the package you named. |
| `bom.include` (or `bom.identify`) | Settles the matching findings as **Confirm match**. The component is real and declared. |
| `settings.file_snippet` header skipping and ranking threshold | Applied, unless the project sets its own value under **Snippet tuning** in Scan Configuration. The repository's value takes precedence over the organisation's. Earnie doesn't apply other snippet-matching settings in the file, and Scan Configuration says so. |
| `bom.ignore` and `bom.exclude` | Not applied. Earnie records every match as a finding and lets you decide it, rather than dropping matches before anyone sees them. |

Earnie records each settled finding in its audit trail and names the `scanoss.json` file as the source of the decision. See [Component overrides](/en/latest/earnie/using-earnie/triaging-findings#component-overrides).

**Watch the difference between declaring and accepting.** In Code Compare, *Include* declared a component, and that satisfied the undeclared-component check. In Earnie, **Confirm match** records that the match is real, and the finding **still counts** towards your policies. A copyleft policy still catches a confirmed GPL component. Only **Mark original** removes a finding from the gate, and it means "this is our own code", not "we accept this component". To accept a real component that a policy flags, use a Policy Approval, covered in phase 3.

Triage what remains in the [Review Workspace](/en/latest/earnie/using-earnie/triaging-findings). In Components mode, **Bulk decide** settles every open file of a component at once.

**Exit criterion:** no project shows findings your team considers already decided, and your reviewers agree that what's left open is real work.

### Phase 3: Rebuild your policies

Rebuild your Dependency-Track policies as Earnie policies, using the [equivalence table](#dependency-track-to-earnie-policies) below. There's no automatic Dependency-Track importer, because the fields, operators, and expression languages all differ.

Start from Earnie's built-in templates where you can. They cover the rules most teams gate on, and they're quicker to review than a hand-written rule:

| Template | Action | Replaces in Dependency-Track |
| - | - | - |
| **Block banned licenses** | Block | A `LICENSE` deny list |
| **Enforce license allowlist** | Require approval | A `LICENSE` allow list |
| **Require approval for strong copyleft** | Require approval | The strong half of `LICENSE_GROUP` = Copyleft |
| **Warn on weak copyleft** | Warn | The weak half of `LICENSE_GROUP` = Copyleft, and the Action's copyleft check |
| **Flag unknown licenses** | Require approval | Nothing. A new safety net. |
| **Block high-severity vulnerabilities** | Block | `SEVERITY` |
| **Block known exploited vulnerabilities** | Block | `VULNERABILITY_ID` against a known-exploited list |
| **Warn on high EPSS** | Warn | `EPSS` |
| **Warn on outdated components** | Warn | `AGE` and `VERSION_DISTANCE` |
| **Require approval for deprecated components** | Require approval | Nothing. A new safety net. |

Where your organisation has cryptography or AI provenance enabled, more templates are available. See [Cryptography](/en/latest/earnie/domains/cryptography#policies-for-cryptography) and [AI provenance](/en/latest/earnie/using-earnie/ai-provenance).

<Warning>
  **One copyleft policy becomes two.** Dependency-Track ships one Copyleft
  licence group. Earnie separates strong copyleft from weak copyleft, and the
  two templates act differently. Strong copyleft gets Require approval, and weak copyleft gets Warn.
  If you enable only the first, Earnie stops gating every weak-copyleft licence
  you used to gate on, without any warning. Enable both, or write one policy on **Copyleft**
  if you want them treated alike.
</Warning>

A policy belongs to your organisation, and you **attach** it to the projects it should gate. A per-repository rule becomes a per-project attachment. You can't override a policy for one project. To vary the rule itself, clone it. See [Where a policy applies](/en/latest/earnie/using-earnie/setting-policies#where-a-policy-applies).

**Exit criterion:** for each project, Earnie's gate agrees with the Dependency-Track verdict on the same code, or your policy owner has written down and accepted every difference. To compare, use the read-only policy commands. They change nothing and never re-evaluate:

```bash theme={null}
earnie policy list --project <project-slug>
earnie policy violations <policy-slug> --project <project-slug>
```

### Phase 4: Switch the gate

In **one pull request per repository**:

1. Add **Earnie** as a required status check.
2. Remove the three `Policy Check: *` required checks.
3. Delete the GitHub Action workflow and its Dependency-Track upload step.

Do all three in the same pull request. Branch protection names the legacy checks literally. A required check whose workflow you deleted never reports, and every pull request then waits for it forever. If both sets stay required, every pull request is gated twice.

The Earnie check reports the gate like this:

| Gate | Check |
| - | - |
| Pass, Warn, or no policy applied | Success |
| Block | Failure |
| Require approval | Failure, until approved |
| Evaluation failed | Failure |
| Base branch moved, or no baseline | Neutral |
| Scan cancelled | Cancelled |

On a pull request, **the findings the pull request introduced** decide the check. The summary comment lists findings the default branch already carried, but they don't hold the pull request.

**A neutral check means "not comparable", not "pass".** It appears when Earnie has no completed scan of the default branch to compare against (*No baseline to compare against; result is not conclusive*), or when the default branch has moved since the pull request was scanned (*Base branch moved; result is not conclusive*). Push a commit, or re-run the scan, to get a real answer. See [When the branch you're merging into moves](/en/latest/earnie/using-earnie/merge-gate#when-the-branch-youre-merging-into-moves).

**An approval updates the pull request without a push.** When an Admin grants a Policy Approval, Earnie updates that scan's check and comments straight away. Earnie doesn't re-scan anything, so the check turns green only if the approval cleared every violation holding the gate. Revoking an approval works the same way in reverse.

<Warning>
  **A skipped pull request gets no check at all.** A project can skip draft
  pull requests, bot-authored pull requests, or pull requests outside chosen
  base branches or paths. Earnie never scans a skipped pull request, so a
  required **Earnie** check never arrives. Either leave those controls off where
  **Earnie** is required, or agree that those pull requests merge without an
  Earnie gate. See [Choosing which pull requests Earnie
  checks](/en/latest/earnie/using-earnie/merge-gate#choosing-which-pull-requests-earnie-checks).
</Warning>

On GitLab, Earnie can enforce a block only where your group's plan allows it. See [Merge blocking depends on your GitLab plan](/en/latest/earnie/getting-started/connecting-a-repository#merge-blocking-depends-on-your-gitlab-plan).

**Exit criterion:** in each repository, one pull request has merged with **Earnie** as the only required policy check, no workflow still runs `scanoss/actions-scan`, and you have checked any pull-request filters against the repositories where **Earnie** is required.

### Phase 5: Move developer tooling

**Install the CLI** wherever developers or pipelines need it:

```bash theme={null}
brew install scanoss/dist/earnie
# or
curl -fsSL https://github.com/scanoss/earnie-cli/releases/latest/download/install.sh | sh
```

Sign in once with `earnie auth login`. See [Earnie CLI](/en/latest/earnie/using-earnie/earnie-cli#installing).

**Replace the pre-commit hook.** If your repositories use the pre-commit framework, replace the `scanoss/pre-commit-hooks` entry in `.pre-commit-config.yaml`:

```yaml theme={null}
repos:
  - repo: https://github.com/scanoss/earnie-pre-commit
    rev: vX.Y.Z # pin to a release tag
    hooks:
      - id: earnie
```

Then run `pre-commit install --install-hooks` and `pre-commit run earnie` once, so the framework downloads and verifies the pinned CLI before the first commit. Without the framework, run `earnie hook install` in each checkout instead.

Either way, the hook runs `earnie scan staged --format hook`. It checks what you've staged in Git, not your working files, and creates a Self-check. A Self-check never adds findings or changes a project's posture.

| Verdict | Commit |
| - | - |
| Pass, Warn, or no policy applied | Allowed |
| Block | Stopped |
| Require approval | Allowed, with an approval notice. The pull-request check still decides. |

By default, the hook reports a technical failure but lets the commit through. Technical failures include a network or authentication error and hitting the 60-second time limit. An Operator or Admin can make a technical failure stop the commit instead, at **Project → Scan Configuration → Pre-commit technical failures**. See [When the check can't run](/en/latest/earnie/using-earnie/earnie-cli#when-the-check-cant-run).

**Optionally, connect coding agents.** `earnie mcp setup` connects Claude Code, Cursor, VS Code, or Codex to Earnie, so agents follow your policies while they write code. See [Connecting an AI client](/en/latest/earnie/mcp/connecting-a-client).

Finally, uninstall Code Compare.

**Exit criterion:** no repository's developer instructions still mention `scanoss/pre-commit-hooks`, Code Compare, or `scanoss-py`, and a test commit in each repository produces a Self-check in Earnie.

## Dependency-Track to Earnie policies

This table covers the fifteen condition subjects of Dependency-Track's classic policy model. It isn't a complete account of every way a Dependency-Track instance can express a policy. In particular, Dependency-Track 5.0 adds expression-based policies, which no row below covers. Read each one and rewrite it. Earnie policies also use CEL, but the two object models differ, so you can rarely copy an expression across unchanged.

**List the policies in your own Dependency-Track instance first**, and note its version. Use this table to translate what you find, not to decide what exists.

| Dependency-Track subject | Earnie field (CEL path) | Operators | Notes |
| - | - | - | - |
| `SEVERITY` | Vulnerability Severity (`vulnerability.severity`) | equals, not equals, in | Values `critical`, `high`, `medium`, `low`, `none`. |
| `EPSS` | EPSS Score, EPSS Percentile (`vulnerability.epss_score`, `vulnerability.epss_percentile`) | equals, less than, greater than (and or-equal) | |
| `VULNERABILITY_ID` | CVE Id (`vulnerability.cve_id`) | equals, not equals | For "known exploited", use Known Exploited Vulnerability (`vulnerability.kev`) instead of a list of IDs. |
| `LICENSE` | SPDX License Id (`license.spdx_id`) | equals, not equals, in | Allow and deny lists. |
| `LICENSE_GROUP` | License Category (`license.category`), Copyleft (`license.copyleft`) | equals, in / equals | Categories `permissive`, `copyleft-weak`, `copyleft-strong`, `proprietary`, `public-domain`, `unknown`. Copyleft splits into weak and strong, so counts will move. |
| `AGE` | Component Age in Days (`component.age_days`) | equals, less than, greater than (and or-equal) | |
| `VERSION_DISTANCE` | Versions Behind (`component.versions_behind`) | equals, less than, greater than (and or-equal) | A single count of versions, not Dependency-Track's major, minor, and patch distance. Re-express the threshold. |
| `PACKAGE_URL` | Package URL (`component.purl`) | equals, contains | No regular expressions. Rewrite a `MATCHES` condition as exact values or a substring. |
| `COORDINATES` | Package URL, Component Version (`component.purl`, `component.version`) | equals, contains / equals, not equals | Partial. Express what you can as a package URL plus a version. |
| `VERSION` | Component Version (`component.version`) | equals, not equals | Text comparison only. There are no numeric version comparisons. |
| `CWE` | CWE (`vulnerability.cwe`) | None | Not available yet, because Earnie produces no CWE data. The policy editor shows the field as unavailable. Earnie can't evaluate a policy written on it, so the policy fails the gate as **Evaluation failed**. Don't rebuild CWE policies. |
| `CPE` | None | None | No equivalent. |
| `SWID_TAGID` | None | None | No equivalent. |
| `COMPONENT_HASH` | None | None | No equivalent. |
| `IS_INTERNAL` | None | None | No equivalent. Scope the policy by attaching it to the right projects instead. |

Earnie also has fields that Dependency-Track lacks, which you may want to use in the rebuild: Dual Licensed, Patent Clauses, License Data Source, Component Status, Match Percentage, the finding's State and Domain, and the whole cryptography and AI provenance field groups where enabled. `earnie policy show <policy-slug>` prints the exact expression a policy runs.

### Violation states and exceptions

Start from what your pipeline does **today**. The legacy GitHub Action failed on **any** Dependency-Track violation, whatever its state. `INFO`, `WARN`, and `FAIL` all turned the check red, so in that pipeline every violation blocks.

If your CI read Dependency-Track's API or project badge directly instead, it could tell the states apart and gate on `FAIL` alone. Check which setup you're replacing before you map anything.

No rule translates one into the other. Choosing an Earnie action decides how your gate behaves, so make the choice with your policy owner:

| Dependency-Track | Earnie action | Consequence |
| - | - | - |
| `INFO` | Warn | The check stays green. **This loosens your gate**, because these violations fail the build today. |
| `WARN` | Warn, or Block to change nothing | Warn loosens the gate. Block keeps today's behaviour, since the Action already fails on `WARN`. |
| `FAIL` | Block, or Require approval | Block keeps today's behaviour. Require approval adds an approver in front of each violation, which needs someone who'll answer. |
| Violation audit: approved and suppressed | Require approval, plus a **Policy Approval** | Where you suppressed a violation to unblock a pipeline, the gate now holds until an approval exists. |

Whichever you choose, write down the mapping and the reason for it. Your build behaviour changes either way, and you'll need the reason when the first unexpected green check appears.

A Policy Approval records a justification category from CISA's VEX categories, a written justification, the approver, an optional expiry, and any later revocation. Requesting an approval never changes the verdict. Only an Admin's decision does. Each approval covers one finding. See [Request an approval](/en/latest/earnie/using-earnie/merge-gate#route-3-request-an-approval).

Every scan also records the exact revision of each policy that judged it, so you can still see why a check failed months later.

## What changes for your team

* **One check, not three.** Branch protection names **Earnie** instead of the three `Policy Check: *` entries.
* **Decisions carry a name, a time, and a reason.** A `scanoss.json` entry recorded none of those. Earnie records all three for every triage decision and Policy Approval, in the finding's audit trail. See [Audit log](/en/latest/earnie/evidence/audit-log). `earnie scan audit <scan-id>` prints a scan's own trail: its submission, its gate, approvals that moved it, and its publications to the pull request.
* **You fix findings in Earnie, not in files.** Instead of pasting a `scanoss.json` snippet and pushing, you decide the finding or request an approval in Earnie, and the pull request updates without a push. A fix to the code itself still needs a push before Earnie can scan it.
* **No local results file.** Earnie doesn't write `.scanoss/results.json`. The hook prints a short summary and a link, and the results are in Earnie. Remove `.scanoss/` from the repository and from `.gitignore`.
* **No upload to Dependency-Track.** If other tools also feed Dependency-Track and you want to keep it, upload Earnie's SBOM yourself. Run `earnie export --bom-format cyclonedx --output sbom.json` in a pipeline step, then upload the file with your own step. Dependency-Track's project versions have no equivalent. One Earnie project is one codebase for its whole life.
* **Code Compare is retired as a scanner.** The CLI sends source to your Earnie environment, and scanning and policy evaluation run there. By design, there's no offline mode and no local policy evaluation.
* **Inline comments are limited.** Earnie comments only on lines the pull request added, from Medium severity up, and at most ten per review by default. Findings it can't place on a line go in the summary comment. See [Inline comments on the changed lines](/en/latest/earnie/using-earnie/merge-gate#inline-comments-on-the-changed-lines).
* **Publishing is separate from the verdict.** If GitHub or GitLab rejects Earnie's write, the scan's verdict still stands and the scan page offers **Retry publication**. Retrying never re-runs the scan.
* **Feedback appears on the pull request and in Earnie.** Earnie doesn't send policy-violation notifications by email or chat. If you relied on Dependency-Track's notifications, plan a replacement.

## Before you start

Check these against your setup before phase 1:

* **CWE policies** can't be rebuilt yet. See the [table](#dependency-track-to-earnie-policies).
* **Policy migration is manual.** There's no Dependency-Track policy importer.
* **Approvals are per finding.** A component matched in many files needs an approval for each finding a policy flags.
* **No sub-path or dependency-scope setting.** In a monorepo, narrow a project's scope with skip patterns.
* **`bom.ignore` isn't applied.** Repositories that rely on it will see those matches as findings to decide.

## What's next

Start phase 1 with [Workspace setup](/en/latest/earnie/getting-started/workspace-setup), then [connect your repositories](/en/latest/earnie/getting-started/connecting-a-repository).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.