- 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.
4.4 KiB
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:
{
"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"
}
]
}
metadatais a free-form dictionary (release version, build tag, etc.).sdkNamesis a sorted list of logical SDK identifiers (sanitised to lowercase alphanumeric /-_.).entriesare ordered lexicographically bypathand 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:
- Extracts the archive into a temporary directory.
- Validates
checksums.txtviasha256sum(orshasum -a 256fallback). - 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 underdocs/airgap/devportal-offline.md.