Metadata-Version: 2.5
Name: euvd-watch
Version: 0.4.0
Summary: EUVD-native software supply-chain vulnerability watch + EU Cyber Resilience Act (CRA) reporting toolkit
Author: euvd-watch contributors
License-Expression: EUPL-1.2
License-File: LICENSE
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27
Requires-Dist: jinja2>=3.1
Requires-Dist: packageurl-python>=0.15
Requires-Dist: packaging>=24
Requires-Dist: pydantic>=2
Requires-Dist: pyyaml>=6
Requires-Dist: rich>=13
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: check-jsonschema>=0.28; extra == 'dev'
Requires-Dist: fastapi>=0.115; extra == 'dev'
Requires-Dist: freezegun>=1.5; extra == 'dev'
Requires-Dist: hypothesis>=6.100; extra == 'dev'
Requires-Dist: jsonschema>=4.20; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pre-commit>=3.7; extra == 'dev'
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: python-multipart>=0.0.9; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Requires-Dist: uvicorn>=0.30; extra == 'dev'
Provides-Extra: web
Requires-Dist: fastapi>=0.115; extra == 'web'
Requires-Dist: python-multipart>=0.0.9; extra == 'web'
Requires-Dist: uvicorn>=0.30; extra == 'web'
Description-Content-Type: text/markdown

# euvd-watch

**EUVD-native software supply-chain vulnerability watch + EU Cyber Resilience Act (CRA) reporting toolkit.**

> ⚠️ **Status: work in progress.** APIs and structure may change until `1.0.0`.
> The Commands table below marks what is **✅ available today** versus **🧪 beta**
> versus **🚧 planned** — milestones M0–M5 (scan, match, VEX, the CRA workflow, `watch`
> mode, Docker image, GitHub Action, GitLab template, PyPI releases) are implemented
> and tested. The dashboard (M6) is fully implemented — app, accessibility gate, and a
> tested deployment guide (`docs/deploy.md`) — and marked **beta** only because its
> surface may still change before the `1.1` GA.

`euvd-watch` connects software supply-chain transparency to **Europe's own vulnerability infrastructure** and to the concrete reporting duties of the **EU Cyber Resilience Act**.

It ingests your **SBOM**, continuously matches every component against the **European Union Vulnerability Database (EUVD)** operated by ENISA — including its *actively exploited* flag and EPSS scores — automatically drafts machine-readable **VEX** statements to cut false-positive noise, and, when a component is hit by an actively exploited vulnerability, **drafts the CRA Article 14 notification and starts the 24-hour clock** with a tamper-evident audit trail.

## Why this exists

SBOM generation (Syft, cdxgen) and scanning against US sources (NVD, OSV) are mature. But:

- **Nothing open is built around the EUVD** — Europe's own vulnerability database, operated by ENISA.
- **Nothing connects "exploited" status to the CRA's actual reporting workflow** (the 24-hour early warning to ENISA/CSIRTs).
- **VEX generation is still mostly manual**, so teams drown in non-applicable findings.

`euvd-watch` fills that gap as a **self-hostable building block** that runs in CI/CD and on a schedule. It does **not** reinvent SBOM generators or scanners — it reuses them.

## Pipeline

```mermaid
flowchart LR
    A[SBOM<br/>CycloneDX / SPDX] -->|ingest| B[Normalized<br/>components]
    B -->|match| C[EUVD<br/>exploited + EPSS + KEV]
    C --> D[OpenVEX<br/>statements]
    C -->|trigger| E[CRA Article 14<br/>draft + 24h clock + audit log]
    B -.->|CI/CD · CLI · watch| F[Dashboard]
```

## Quickstart (everything below works today)

```bash
pip install euvd-watch
euvd-watch version

# 1. Generate an SBOM for your project (using Syft, or bring your own)
syft dir:. -o cyclonedx-json > sbom.cdx.json

# 2. See what's inside it
euvd-watch scan sbom.cdx.json

# 3. Match it against the EUVD — show only actively exploited vulnerabilities
euvd-watch match sbom.cdx.json --exploited-only

# 4. Generate OpenVEX statements (conservative by design)
euvd-watch vex generate sbom.cdx.json -o openvex.json

# 5. Check whether anything crossed your CRA reporting threshold
euvd-watch cra check sbom.cdx.json
euvd-watch cra status

# 6. Watch it on a schedule - notify only new/resolved/changed findings
euvd-watch watch sbom.cdx.json --interval 6h
```

## Commands

| Command | Status | What it does |
|---|---|---|
| `scan <sbom>` | ✅ | Parse and normalize a CycloneDX (1.4–1.6) / SPDX (2.3) **JSON** SBOM into a component inventory. |
| `match <sbom>` | ✅ | Match components against the EUVD, with confidence scoring and EPSS/KEV enrichment. Flags: `--exploited-only`, `--min-confidence`, `--fail-on`, `--no-enrich`, `--save-findings`, `--timestamp`. |
| `vex generate <sbom>` | ✅ | Draft OpenVEX statements. Only provably safe findings become `not_affected`; everything uncertain stays `under_investigation`. Merges your `vex-decisions.yaml` (`--fail-on-conflict` for CI). |
| `vex init-decisions <sbom>` | ✅ | Scaffold a `vex-decisions.yaml` from current findings for humans to fill in. |
| `cra check <sbom>` | ✅ | Evaluate the configurable reporting trigger (EUVD exploited / CISA KEV / EPSS threshold) and open events. Exit `1` when a **new** event opens; exit `3` **indeterminate** when a required signal's source (KEV/EPSS) was unavailable so a clean result can't be trusted (see `docs/cra.md`). |
| `cra status` / `cra draft <id>` / `cra mark <id>` | ✅ | Track the staged deadline clocks (24 h / 72 h / final report), render a prefilled notification draft with `TODO-HUMAN` markers, record human completion. |
| `cra verify-log` | ✅ | Verify the tamper-evident (hash-chained) audit log; names the first broken entry. |
| `watch <sbom>` | ✅ | Re-match on a schedule (`--interval 6h`) or once (`--once`, the default) and notify **only new/resolved/changed findings** (stdout, and `--webhook URL`). See `docs/watch.md`. |
| `db migrate` | ✅ | Apply pending schema migrations to the consolidated state DB (`state_dir/euvd-watch.sqlite`) and import pre-0.4 state files. Runs transparently on every state-touching command; this makes it explicit. See `docs/storage.md`. |
| `web serve` | 🧪 beta (`1.1` target) | Self-hostable dashboard: findings, VEX statuses, CRA countdowns, audit log, one password-gated write action. `web hash-password` sets the credential. WCAG 2.1 AA gated in CI; Docker Compose + Caddy deployment in `docs/deploy.md`. See `docs/web.md`. |

All implemented commands support `--output json|table` and CI-friendly exit codes
(`0` clean, `1` findings, `2` error; `cra check` adds `3` indeterminate). Unimplemented
commands exit `2` with a clear message.

## Using it in CI

The GitHub Action (`action.yml` at the repo root), the GitLab include-template
(`templates/euvd-watch.gitlab-ci.yml`) and the Docker image (`docker/Dockerfile`) are
implemented, schema-linted, and dogfooded by this repository's own CI — see
`docs/integrations.md` for the full reference.

GitHub Actions:

```yaml
- uses: anchore/sbom-action@v0          # generate SBOM with Syft
  with: { format: cyclonedx-json, output-file: sbom.cdx.json }
- uses: caisarus/euvd@v0.3.1
  with:
    sbom-path: sbom.cdx.json
    fail-on: exploited
```

GitLab CI:

```yaml
include:
  - remote: 'https://raw.githubusercontent.com/caisarus/euvd/main/templates/euvd-watch.gitlab-ci.yml'

euvd-watch:
  variables: { EUVDWATCH_SBOM: "sbom.cdx.json", EUVDWATCH_FAIL_ON: "exploited" }
```

Docker (`ghcr.io/caisarus/euvd-watch`, or build locally):

```bash
docker run --rm -v "$PWD:/work:ro" ghcr.io/caisarus/euvd-watch:latest match /work/sbom.cdx.json
# or build from a clone:
docker build -f docker/Dockerfile -t euvd-watch .
```

## Configuration

`euvd-watch.yaml` (or `--config`, or `EUVD_WATCH_*` env vars):

```yaml
cache_dir: ~/.cache/euvd-watch
epss_threshold: 0.5
min_confidence: medium
organization:
  name: "Example S.R.L."
  contact_email: security@example.com
  product_name: "Example Product"
cra_trigger:
  euvd_exploited: true
  cisa_kev: true
  epss_over_threshold: true
```

## Design principles

- **Reuse, don't reinvent** — wrap Syft/cdxgen output, OpenVEX, EPSS, KEV; build only the missing glue.
- **EUVD-first**, with OSV/KEV/EPSS as supplements.
- **Conservative VEX** — never auto-suppress something that might be real risk.
- **Human-in-the-loop reporting** — `euvd-watch` drafts; a human confirms before anything is filed. The tool never submits anything automatically.
- **Auditable** — every decision carries a human-readable explanation and lands in a hash-chained audit log.
- **Deterministic** — same inputs produce byte-identical outputs.

## What euvd-watch is NOT

- Not an SBOM generator (use Syft/cdxgen).
- Not a general-purpose scanner replacement (Grype/Trivy remain great for NVD/OSV coverage).
- Not legal advice, and not an automatic filing tool — CRA notifications are always reviewed and submitted by a human through official channels.

## Architecture & docs

- [docs/matching.md](docs/matching.md) — matching strategies & confidence scoring
- [docs/cra.md](docs/cra.md) — the CRA Article 14 workflow, deadline stages, and the
  audit log's honest threat model
- [docs/euvd-api.md](docs/euvd-api.md) — the verified EUVD API surface this tool uses
- [README.simple.md](README.simple.md) — the same story, explained so a child can follow it
- [GLOSSARY.md](GLOSSARY.md) — every technical term (SBOM, VEX, CRA, EPSS…) explained in plain language
- 🚧 coming with their milestones: `ARCHITECTURE.md`, `docs/deploy.md` (self-hosting),
  `CONTRIBUTING.md`

## Contributing

Early contributors very welcome — `CONTRIBUTING.md` is coming; until then, open an issue.

## License

[EUPL-1.2](LICENSE). Documentation provided in English and Romanian —
see [README.ro.md](README.ro.md) / vezi [README.ro.md](README.ro.md).
