# Provider Contract Reference Vulnerability providers convert SBOM component identities into provider-neutral `VulnerabilityFinding` objects. The `vexcalibur generate` workflow can then render those findings as CycloneDX VEX without knowing the provider's request or file format. ## Interface A provider implements `vexcalibur.domain.VulnerabilitySource`: ```python from vexcalibur.domain import ComponentIdentity, VulnerabilityFinding class ExampleSource: def findings_for_components( self, components: tuple[ComponentIdentity, ...], ) -> tuple[VulnerabilityFinding, ...]: ... ``` `components` is the tuple returned by the package inventory loader. Each component includes: - `ref`: Vexcalibur component reference. Local CycloneDX input uses the CycloneDX `bom-ref`; GitHub Dependency Graph SBOM input uses the SPDX package `SPDXID` when present, otherwise the package URL. - `name`: component name. - `version`: component version, or `None`. - `purl`: parsed `packageurl.PackageURL`. - `type`: CycloneDX component type string, defaulting to `library`. The method returns zero or more `VulnerabilityFinding` objects. ## Finding Fields Each finding must include: - `id`: vulnerability identifier. - `source_name`: provider or analysis source name. - `source_url`: provider or advisory URL. - `component_ref`: `ref` from the parsed component identity. - `purl`: package URL string for the affected component. Optional fields: - `modified`: vulnerability update timestamp. - `analysis_state`: CycloneDX VEX state. Defaults to `in_triage`. - `analysis_detail`: human-readable analysis detail. Defaults to `Detected by vulnerability source; manual exploitability analysis required.` The renderer rejects findings whose `component_ref` is not present in the parsed component set. ## Errors Use the shared error hierarchy so the CLI can report useful categories: - Raise `VulnerabilitySourceInputError` when the SBOM components cannot produce provider-specific queries or matches. `generate` reports this as an SBOM ingest failure because the source cannot operate on the provided inventory. - Raise a `VulnerabilitySourceError` subclass for provider configuration, network, response-shape, parsing, or local-file failures. - Keep provider-specific subclasses when callers need to distinguish failures. Do not leak provider stack traces to normal CLI users. The CLI catches known source errors and prints category-prefixed failure messages. ## Trust Boundary Network providers must make data sharing explicit. The OSV provider fails closed for `https://api.osv.dev` unless the caller passes `--allow-public-osv`, and it accepts private mirrors through `--osv-url`. New public network providers should follow the same pattern: - Identify the public default endpoint. - Require an explicit opt-in before sending package URLs, versions, or SBOM-derived inventories to that endpoint. - Support private or internal endpoints when the provider API can be mirrored. - Document what package data leaves the local environment. Offline providers should avoid constructing network clients and should make local-file size, schema, and matching limits explicit. ## Provider Mapping Provider-specific code belongs under `vexcalibur.sources`. Recommended provider shape: 1. Validate provider configuration before sending requests or reading large files. 2. Convert `ComponentIdentity` values into provider-specific queries or lookup keys. 3. Validate provider responses or local documents before mapping findings. 4. Return sorted, immutable tuples when practical. 5. Let the shared renderer handle CycloneDX grouping, affected components, and VEX JSON formatting. Avoid duplicating CycloneDX output rules in provider code. Providers should produce `VulnerabilityFinding` objects and leave rendering to `vexcalibur.vex`. ## Tests Provider changes should include focused tests for: - configuration validation and fail-closed public-service policy; - request or document parsing; - pagination or repeated-token failures for network providers; - invalid response or file shapes; - mapping into `VulnerabilityFinding`; - CLI error messages when the provider is reachable from a command. Run the normal offline test suite before opening a provider pull request: ```bash uv run --frozen python -m pytest -m "not live" ``` Run live tests only when the provider's public-service boundary has been reviewed and the package data used by the test is safe to send.