save development progress

This commit is contained in:
StellaOps Bot
2025-12-25 23:09:58 +02:00
parent d71853ad7e
commit aa70af062e
351 changed files with 37683 additions and 150156 deletions

View File

@@ -0,0 +1,278 @@
# Federation Bundle Export
Per SPRINT_8200_0014_0002.
## Overview
Federation bundles enable multi-site synchronization of canonical advisory data. Each bundle contains a delta of changes since a specified cursor position, allowing incremental sync between federated Concelier instances.
## Bundle Format
Bundles use a TAR archive compressed with ZStandard (ZST):
```
feedser-bundle-v1.zst
├── MANIFEST.json # Bundle metadata
├── canonicals.ndjson # Canonical advisories (one per line)
├── edges.ndjson # Source edges (one per line)
├── deletions.ndjson # Withdrawn/deleted canonical IDs
└── SIGNATURE.json # DSSE envelope (optional)
```
### MANIFEST.json
```json
{
"version": "feedser-bundle/1.0",
"site_id": "site-us-west-1",
"export_cursor": "2025-01-15T10:30:00.000Z#0042",
"since_cursor": "2025-01-14T00:00:00.000Z#0000",
"exported_at": "2025-01-15T10:30:15.123Z",
"counts": {
"canonicals": 1234,
"edges": 3456,
"deletions": 12,
"total": 4702
},
"bundle_hash": "sha256:a1b2c3d4..."
}
```
| Field | Type | Description |
|-------|------|-------------|
| `version` | string | Bundle format version identifier |
| `site_id` | string | Identifier of the exporting site |
| `export_cursor` | string | Cursor position after this export |
| `since_cursor` | string? | Cursor position from which changes were exported (null for full export) |
| `exported_at` | ISO8601 | Timestamp when bundle was created |
| `counts` | object | Item counts by type |
| `bundle_hash` | string | SHA256 hash of compressed bundle content |
### canonicals.ndjson
Each line contains a canonical advisory record:
```json
{"id":"uuid","cve":"CVE-2024-1234","affects_key":"pkg:npm/express@4.0.0","merge_hash":"a1b2c3...","status":"active","severity":"high","title":"..."}
```
### edges.ndjson
Each line contains a source edge linking a canonical to its source advisory:
```json
{"id":"uuid","canonical_id":"uuid","source":"nvd","source_advisory_id":"CVE-2024-1234","vendor_status":"affected"}
```
### deletions.ndjson
Each line contains a deletion record for withdrawn or deleted canonicals:
```json
{"canonical_id":"uuid","deleted_at":"2025-01-15T10:00:00Z","reason":"withdrawn"}
```
### SIGNATURE.json
When signing is enabled, contains a DSSE envelope over the bundle hash:
```json
{
"payload_type": "application/vnd.stellaops.bundle-hash+json",
"payload": "eyJidW5kbGVfaGFzaCI6InNoYTI1NjphMWIy..."}",
"signatures": [
{
"keyid": "sha256:xyz...",
"sig": "MEUCIQD..."
}
]
}
```
## API Endpoints
### Export Bundle
```
GET /api/v1/federation/export
```
Exports a delta bundle for federation sync.
**Query Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `since_cursor` | string | null | Export changes since this cursor (null = full export) |
| `sign` | bool | true | Sign the bundle with Authority key |
| `max_items` | int | 10000 | Maximum items per bundle (1-100000) |
| `compress_level` | int | 3 | ZST compression level (1-19) |
**Response Headers:**
| Header | Description |
|--------|-------------|
| `Content-Type` | `application/zstd` |
| `Content-Disposition` | `attachment; filename="feedser-bundle-{timestamp}.zst"` |
| `X-Bundle-Hash` | SHA256 hash of bundle content |
| `X-Export-Cursor` | Cursor position after this export |
| `X-Items-Count` | Total items in bundle |
**Response:** Streaming ZST-compressed TAR archive.
**Errors:**
| Status | Code | Description |
|--------|------|-------------|
| 400 | `VALIDATION_FAILED` | Invalid parameter values |
| 503 | `FEDERATION_DISABLED` | Federation is not enabled |
### Preview Export
```
GET /api/v1/federation/export/preview
```
Preview export statistics without creating a bundle.
**Query Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `since_cursor` | string | null | Preview changes since this cursor |
**Response:**
```json
{
"since_cursor": "2025-01-14T00:00:00Z#0000",
"estimated_canonicals": 1234,
"estimated_edges": 3456,
"estimated_deletions": 12,
"estimated_size_bytes": 5242880,
"estimated_size_mb": 5.0
}
```
### Federation Status
```
GET /api/v1/federation/status
```
Get federation configuration status.
**Response:**
```json
{
"enabled": true,
"site_id": "site-us-west-1",
"default_compression_level": 3,
"default_max_items": 10000
}
```
## CLI Commands
### Export Bundle
```bash
stella feedser bundle export [options]
```
**Options:**
| Option | Short | Default | Description |
|--------|-------|---------|-------------|
| `--since-cursor` | `-c` | null | Export changes since cursor |
| `--output` | `-o` | stdout | Output file path |
| `--sign` | `-s` | true | Sign bundle with Authority key |
| `--compress-level` | `-l` | 3 | ZST compression level (1-19) |
| `--max-items` | `-m` | 10000 | Maximum items per bundle |
| `--json` | | false | Output metadata as JSON |
**Examples:**
```bash
# Full export to file
stella feedser bundle export -o ./bundle.zst
# Delta export since cursor
stella feedser bundle export -c "2025-01-14T00:00:00Z#0000" -o ./delta.zst
# Export without signing (for testing)
stella feedser bundle export --sign=false -o ./unsigned.zst
# High compression for archival
stella feedser bundle export -l 19 -o ./archived.zst
```
### Preview Export
```bash
stella feedser bundle preview [options]
```
**Options:**
| Option | Short | Description |
|--------|-------|-------------|
| `--since-cursor` | `-c` | Preview changes since cursor |
| `--json` | | Output as JSON |
**Example:**
```bash
stella feedser bundle preview -c "2025-01-14T00:00:00Z#0000"
```
## Configuration
Federation is configured in `concelier.yaml`:
```yaml
Federation:
Enabled: true
SiteId: "site-us-west-1"
DefaultCompressionLevel: 3
DefaultMaxItems: 10000
RequireSignature: true
```
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `Enabled` | bool | false | Enable federation endpoints |
| `SiteId` | string | "default" | Identifier for this site |
| `DefaultCompressionLevel` | int | 3 | Default ZST compression level |
| `DefaultMaxItems` | int | 10000 | Default max items per bundle |
| `RequireSignature` | bool | true | Require bundle signatures |
## Cursor Format
Cursors encode a timestamp and sequence number:
```
{ISO8601}#{sequence}
```
Example: `2025-01-15T10:30:00.000Z#0042`
- Timestamp: When the change was recorded
- Sequence: Monotonically increasing within timestamp
Cursors are opaque to consumers and should be passed through unchanged.
## Determinism
Bundles are deterministic:
- Same cursor range produces identical bundle content
- Same content produces identical bundle hash
- Suitable for caching and deduplication
## Security
- Bundles can be signed with DSSE for integrity verification
- Signatures use Authority keys for cross-site trust
- Bundle hash prevents tampering during transit
- ZST compression is not encryption - bundles should be transferred over TLS