# Repository SBOMs

Avrea generates a Software Bill of Materials (SBOM) for each connected
repository: a commit-pinned record of the repository's production
dependencies, their versions, and their licences. Open a repository in the
console and select the **SBOM** tab.

Detection is static analysis of dependency manifests and lockfiles inside an
isolated, egress-restricted VM; repository code is not executed. When a
manifest does not declare a licence, the identifier is backfilled from the
package's public registry (PyPI, crates.io, npm, Maven Central, NuGet,
rubygems.org). A package whose licence still cannot be established is
reported as `NOASSERTION` rather than guessed.

## What a snapshot contains

Each SBOM is pinned to a single commit and records when it was generated. The
summary view shows:

- **Counts** — total dependencies, unresolved licences (`NOASSERTION`),
  copyleft-licensed packages, and ecosystems. The dependency, unresolved, and
  copyleft counts link straight to the matching subset of the dependency list.
- **Licence distribution** — how many dependencies carry each SPDX identifier.
- **Copyleft dependencies** — the packages whose licence carries a copyleft
  obligation (GPL/LGPL/MPL/EPL/CDDL/EUPL families).
- **Artifacts** — downloadable exports: CycloneDX (`bom.cyclonedx.json`),
  SPDX (`bom.spdx.json`), and the machine-readable dependency inventory
  (`inventory.json`) that powers the dependency browser.

## Generating an SBOM

SBOMs are produced automatically: a repository is analysed when it is first
synced to Avrea, and re-analysed when a push to the default branch changes
its GitHub Actions workflows.

**Generate SBOM** on the SBOM tab starts a run on demand against the
default-branch tip. A few rules keep runs cheap and predictable:

- One analysis runs per repository at a time. Requesting a run while one is
  active joins the running scan instead of queueing a second.
- After a successful scan, the repository has a ten-minute cooldown before
  the next one. A failed scan can be retried immediately.
- Generation takes a few minutes; the page tracks the run and refreshes
  itself when the result lands.

## Browsing dependencies

**Browse all dependencies** opens the full per-package table: name, version,
ecosystem, licence, and the manifest the dependency was discovered in. Narrow
it by:

- text search over package names and licence identifiers,
- ecosystem quick filters (one badge per detected ecosystem),
- licence quick filters — resolved, `NOASSERTION`, or copyleft only.

The licence filter is carried in the URL, so a filtered view can be shared or
bookmarked.

## History and per-commit views

**History** lists every recorded SBOM for the repository: commit, branch,
whether it was a release, and its dependency counts. Each row links to a
commit-pinned snapshot page with the same summary, dependency browser, and
artifact downloads as the latest view, so the SBOM that shipped with a given
release remains retrievable later.

## API access

Everything on the SBOM tab is served by the public API. All routes require
read access to the repository on GitHub.

| Method | Path | Purpose |
|--------|------|---------|
| `GET` | `/orgs/{org_id}/repos/{repo_id}/analysis/sbom/latest` | Latest snapshot metadata and summary |
| `GET` | `/orgs/{org_id}/repos/{repo_id}/analysis/sbom` | Snapshot history (paginated) |
| `GET` | `/orgs/{org_id}/repos/{repo_id}/analysis/sbom/commits/{commit_sha}` | Snapshot for a specific commit |
| `GET` | `/orgs/{org_id}/repos/{repo_id}/analysis/sbom/commits/{commit_sha}/artifacts/{filename}` | Download one artifact (decompressed) |
| `POST` | `/orgs/{org_id}/repos/{repo_id}/analysis/sbom/generate` | Start a run on demand |

`POST .../generate` returns the task id and either `generating` or
`already_running` (the request joined a scan already in flight). Inside the
cooldown window it returns `429` with a `Retry-After` header; a run for a
different ref returns `409`.

The optional `ref` is a branch, tag, or commit SHA. An abbreviated SHA of 7 or
more characters, such as the one the history shows, is expanded to the full
SHA before the run starts, and the response's `commit_sha` carries it (it is
also set for a full SHA, and `null` for a branch or tag). An abbreviated SHA
that matches no commit returns `422`; if GitHub cannot be reached to expand it,
`503` with a `Retry-After` header; if the Avrea GitHub App cannot reach the
repository, `409`.

## Supported ecosystems

Python, Go, npm (including pnpm, yarn, and bun lockfiles), Rust (Cargo),
PHP (Composer), Java (Maven), .NET (NuGet), Ruby (Bundler), container base
images from Dockerfiles, and upstream projects bundled in the source tree.
Both direct and transitive dependencies are recorded where the ecosystem's
lockfile provides them.