Add unit tests for SBOM ingestion and transformation
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Implement `SbomIngestServiceCollectionExtensionsTests` to verify the SBOM ingestion pipeline exports snapshots correctly.
- Create `SbomIngestTransformerTests` to ensure the transformation produces expected nodes and edges, including deduplication of license nodes and normalization of timestamps.
- Add `SbomSnapshotExporterTests` to test the export functionality for manifest, adjacency, nodes, and edges.
- Introduce `VexOverlayTransformerTests` to validate the transformation of VEX nodes and edges.
- Set up project file for the test project with necessary dependencies and configurations.
- Include JSON fixture files for testing purposes.
This commit is contained in:
master
2025-11-04 07:49:39 +02:00
parent f72c5c513a
commit 2eb6852d34
491 changed files with 39445 additions and 3917 deletions

View File

@@ -78,12 +78,15 @@ All endpoints require Authority-issued JWT + DPoP tokens with scopes `export:run
- Maps StellaOps advisory schema to Trivy DB format, handling namespace collisions and ecosystem-specific ranges.
- Validates compatibility against supported Trivy schema versions; run fails fast if mismatch.
- Emits optional manifest summarising package counts and severity distribution.
- **Mirror (`mirror:full`, `mirror:delta`).**
- Builds self-contained filesystem layout (`/manifests`, `/data/raw`, `/data/policy`, `/indexes`).
- Delta variant compares against base manifest (`base_export_id`) to write only changed artefacts; records `removed` entries for cleanup.
- Supports optional encryption of `/data` subtree (age/AES-GCM) with key wrapping stored in `provenance.json`.
Adapters expose structured telemetry events (`adapter.start`, `adapter.chunk`, `adapter.complete`) with record counts and byte totals per chunk. Failures emit `adapter.error` with reason codes.
- **Mirror (`mirror:full`, `mirror:delta`).**
- Builds self-contained filesystem layout (`/manifests`, `/data/raw`, `/data/policy`, `/indexes`).
- Delta variant compares against base manifest (`base_export_id`) to write only changed artefacts; records `removed` entries for cleanup.
- Supports optional encryption of `/data` subtree (age/AES-GCM) with key wrapping stored in `provenance.json`.
- **DevPortal (`devportal:offline`).**
- Packages developer portal static assets, OpenAPI specs, SDK releases, and changelog content into a reproducible archive with manifest/checksum pairs.
- Emits `manifest.json`, `checksums.txt`, and helper scripts described in [DevPortal Offline Bundle Specification](devportal-offline.md); signing/DSSE wiring follows the shared Export Center signing service.
Adapters expose structured telemetry events (`adapter.start`, `adapter.chunk`, `adapter.complete`) with record counts and byte totals per chunk. Failures emit `adapter.error` with reason codes.
## Signing and provenance
- **Manifest schema.** `export.json` contains run metadata, profile descriptor, selector summary, counts, SHA-256 digests, compression hints, and distribution list. Deterministic field ordering and normalized timestamps.

View File

@@ -0,0 +1,115 @@
# DevPortal Offline Bundle Specification
> Sprint 160 · Task DVOFF-64-001
> Owners: DevPortal Offline Guild · Exporter Service Guild
The DevPortal offline bundle packages developer portal assets, OpenAPI specifications, SDK binaries, and changelog content into a deterministic archive for air-gapped distribution. This document captures the first iteration of the profile produced by the new `devportal --offline` export job.
## 1. Archive layout
The bundle ships as a gzip-compressed tar archive (`devportal-offline-bundle.tgz`) with the following structure:
```
manifest.json # Bundle manifest (schema v1)
checksums.txt # SHA-256 root + per-entry checksums
instructions-portable.txt # Human-readable verification guidance
verify-offline.sh # POSIX helper that extracts + validates checksums
portal/** # Static site assets (HTML, CSS, JS, etc.)
specs/** # OpenAPI / additional specs
sdks/<name>/** # SDK artifacts grouped by logical name (dotnet, python, ...)
changelog/** # Changelog and release notes
```
Every file entry is written with fixed permissions (`0644`, `0755` for scripts) and a pinned timestamp (`2025-01-01T00:00:00Z`) so the archive is byte-for-byte reproducible.
## 2. Manifest (`manifest.json`)
The manifest is emitted with camel-cased JSON (`JsonSerializerDefaults.Web`) and the following schema:
```jsonc
{
"version": "devportal-offline/v1",
"bundleId": "14b094c9-f0b4-4f9e-b221-b7a77c3f3445",
"generatedAt": "2025-11-04T12:30:00Z",
"metadata": {
"releaseVersion": "2025.11.0"
},
"sources": {
"portalIncluded": true,
"specsIncluded": true,
"sdkNames": ["dotnet", "python"],
"changelogIncluded": true
},
"totals": {
"entryCount": 6,
"totalSizeBytes": 123456
},
"entries": [
{
"category": "portal",
"path": "portal/index.html",
"sha256": "850db3...",
"sizeBytes": 5120,
"contentType": "text/html"
},
{
"category": "sdk",
"path": "sdks/dotnet/stellaops.sdk.nupkg",
"sha256": "0e1f23...",
"sizeBytes": 20480,
"contentType": "application/zip"
}
]
}
```
- `metadata` is a free-form dictionary (release version, build tag, etc.).
- `sdkNames` is a sorted list of logical SDK identifiers (sanitised to lowercase alphanumeric / `-_.`).
- `entries` are ordered lexicographically by `path` and include per-file SHA-256 digests, size, and inferred media type.
## 3. Checksums and root hash
`checksums.txt` follows the evidence locker format:
```
# DevPortal offline bundle checksums (sha256)
root <sha256(manifest.json)>
<sha256> portal/index.html
<sha256> specs/openapi.yaml
...
```
The `root` value is the SHA-256 hash of the serialized manifest and is exposed separately in the result object for downstream signing.
## 4. Verification script
`verify-offline.sh` is a POSIX-compatible helper that:
1. Extracts the archive into a temporary directory.
2. Validates `checksums.txt` via `sha256sum` (or `shasum -a 256` fallback).
3. Prints the manifest root hash and reminds operators to run `stella devportal verify --bundle <archive>` once DSSE signing is wired.
Operators can override the archive name via the first argument (`./verify-offline.sh mybundle.tgz`).
## 5. Content categories
| Category | Target prefix | Notes |
|-----------|---------------|-------|
| `portal` | `portal/` | Static site assets (HTML, CSS, JS, images). |
| `specs` | `specs/` | OpenAPI/JSON/YAML specifications. |
| `sdk` | `sdks/<name>/`| Each SDK source defines `<name>`; files are copied recursively. |
| `changelog` | `changelog/`| Markdown, text, or PDF release notes. |
Paths are normalised to forward slashes and guarded against directory traversal.
## 6. Determinism and hashing rules
- Files are enumerated and emitted in ordinal path order.
- SHA-256 digests use lowercase hex encoding.
- Optional directories (specs, SDKs, changelog) are skipped when absent; at least one category must contain files or the builder fails fast.
## 7. Next steps
- Attach DSSE signing + timestamping (`signature.json`) once Export Center signing infrastructure is ready.
- Integrate the builder into the Export Center worker profile (`devportal --offline`) and plumb orchestration/persistence.
- Produce CLI validation tooling (`stella devportal verify`) per DVOFF-64-002 and document operator workflows under `docs/airgap/devportal-offline.md`.