Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Implemented comprehensive unit tests for RabbitMqTransportServer, covering constructor, disposal, connection management, event handlers, and exception handling. - Added configuration tests for RabbitMqTransportServer to validate SSL, durable queues, auto-recovery, and custom virtual host options. - Created unit tests for UdpFrameProtocol, including frame parsing and serialization, header size validation, and round-trip data preservation. - Developed tests for UdpTransportClient, focusing on connection handling, event subscriptions, and exception scenarios. - Established tests for UdpTransportServer, ensuring proper start/stop behavior, connection state management, and event handling. - Included tests for UdpTransportOptions to verify default values and modification capabilities. - Enhanced service registration tests for Udp transport services in the dependency injection container.
325 lines
6.0 KiB
Markdown
325 lines
6.0 KiB
Markdown
# Export Bundle Scheduler Contract
|
|
|
|
**Contract ID:** `CONTRACT-EXPORT-BUNDLE-009`
|
|
**Version:** 1.0
|
|
**Status:** Published
|
|
**Last Updated:** 2025-12-05
|
|
|
|
## Overview
|
|
|
|
This contract defines the export bundle job scheduling and manifest format used by the Export Center. It covers job definitions, scheduling, output formats, and attestation integration.
|
|
|
|
## Implementation References
|
|
|
|
- **Export Center:** `src/ExportCenter/`
|
|
- **API Spec:** `src/Api/StellaOps.Api.OpenApi/export-center/openapi.yaml`
|
|
|
|
## Data Models
|
|
|
|
### ExportBundleJob
|
|
|
|
Job definition for scheduled exports.
|
|
|
|
```json
|
|
{
|
|
"job_id": "job-001",
|
|
"tenant_id": "default",
|
|
"name": "daily-vex-export",
|
|
"description": "Daily VEX advisory export",
|
|
"query": {
|
|
"type": "vex",
|
|
"filters": {
|
|
"severity": ["critical", "high"],
|
|
"providers": ["github", "redhat"]
|
|
}
|
|
},
|
|
"format": "openvex",
|
|
"schedule": "0 0 * * *",
|
|
"destination": {
|
|
"type": "s3",
|
|
"config": {
|
|
"bucket": "exports",
|
|
"prefix": "vex/daily/"
|
|
}
|
|
},
|
|
"signing": {
|
|
"enabled": true,
|
|
"predicate_type": "stella.ops/vex@v1"
|
|
},
|
|
"enabled": true,
|
|
"created_at": "2025-12-05T10:00:00Z",
|
|
"last_run_at": "2025-12-05T00:00:00Z",
|
|
"next_run_at": "2025-12-06T00:00:00Z"
|
|
}
|
|
```
|
|
|
|
### Export Formats
|
|
|
|
| Format | Description | MIME Type |
|
|
|--------|-------------|-----------|
|
|
| `openvex` | OpenVEX JSON | application/json |
|
|
| `csaf` | CSAF VEX | application/json |
|
|
| `cyclonedx` | CycloneDX VEX | application/json |
|
|
| `spdx` | SPDX document | application/json |
|
|
| `ndjson` | Newline-delimited JSON | application/x-ndjson |
|
|
| `json` | Standard JSON array | application/json |
|
|
|
|
### Schedule Format
|
|
|
|
Cron expressions (5 fields):
|
|
```
|
|
┌───────────── minute (0-59)
|
|
│ ┌───────────── hour (0-23)
|
|
│ │ ┌───────────── day of month (1-31)
|
|
│ │ │ ┌───────────── month (1-12)
|
|
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
|
|
│ │ │ │ │
|
|
* * * * *
|
|
```
|
|
|
|
Examples:
|
|
| Schedule | Description |
|
|
|----------|-------------|
|
|
| `0 0 * * *` | Daily at midnight |
|
|
| `0 */6 * * *` | Every 6 hours |
|
|
| `0 0 * * 0` | Weekly on Sunday |
|
|
| `0 0 1 * *` | Monthly on the 1st |
|
|
|
|
### Destination Types
|
|
|
|
#### S3 Destination
|
|
|
|
```json
|
|
{
|
|
"type": "s3",
|
|
"config": {
|
|
"bucket": "my-exports",
|
|
"prefix": "vex/",
|
|
"region": "us-east-1",
|
|
"endpoint": "https://s3.amazonaws.com"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### File Destination
|
|
|
|
```json
|
|
{
|
|
"type": "file",
|
|
"config": {
|
|
"path": "/exports/vex/"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Webhook Destination
|
|
|
|
```json
|
|
{
|
|
"type": "webhook",
|
|
"config": {
|
|
"url": "https://example.com/webhook",
|
|
"headers": {
|
|
"Authorization": "Bearer ${SECRET}"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### ExportBundleManifest
|
|
|
|
Manifest for completed export.
|
|
|
|
```json
|
|
{
|
|
"bundle_id": "bundle-001",
|
|
"job_id": "job-001",
|
|
"tenant_id": "default",
|
|
"created_at": "2025-12-05T00:00:00Z",
|
|
"format": "openvex",
|
|
"artifact_digest": "sha256:abc123...",
|
|
"artifact_size_bytes": 1048576,
|
|
"query_signature": "sha256:def456...",
|
|
"item_count": 150,
|
|
"policy_digest": "sha256:...",
|
|
"consensus_digest": "sha256:...",
|
|
"score_digest": "sha256:...",
|
|
"attestation": {
|
|
"predicate_type": "stella.ops/vex@v1",
|
|
"rekor_uuid": "24296fb24b8ad77a...",
|
|
"rekor_index": 12345,
|
|
"signed_at": "2025-12-05T00:00:01Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Job Management
|
|
|
|
#### Create Export Job
|
|
|
|
```
|
|
POST /api/v1/export/jobs
|
|
Content-Type: application/json
|
|
Authorization: Bearer <token>
|
|
|
|
{
|
|
"name": "daily-vex-export",
|
|
"query": {...},
|
|
"format": "openvex",
|
|
"schedule": "0 0 * * *",
|
|
"destination": {...}
|
|
}
|
|
|
|
Response: 201 Created
|
|
{
|
|
"job_id": "job-001",
|
|
...
|
|
}
|
|
```
|
|
|
|
#### Update Job
|
|
|
|
```
|
|
PUT /api/v1/export/jobs/{job_id}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"schedule": "0 */12 * * *",
|
|
"enabled": true
|
|
}
|
|
|
|
Response: 200 OK
|
|
```
|
|
|
|
#### Delete Job
|
|
|
|
```
|
|
DELETE /api/v1/export/jobs/{job_id}
|
|
|
|
Response: 204 No Content
|
|
```
|
|
|
|
#### List Jobs
|
|
|
|
```
|
|
GET /api/v1/export/jobs?tenant_id=default
|
|
|
|
Response: 200 OK
|
|
{
|
|
"items": [...],
|
|
"total": 5
|
|
}
|
|
```
|
|
|
|
### Manual Execution
|
|
|
|
#### Trigger Job
|
|
|
|
```
|
|
POST /api/v1/export/jobs/{job_id}/run
|
|
|
|
Response: 202 Accepted
|
|
{
|
|
"execution_id": "exec-001",
|
|
"status": "running"
|
|
}
|
|
```
|
|
|
|
#### Get Execution Status
|
|
|
|
```
|
|
GET /api/v1/export/jobs/{job_id}/executions/{execution_id}
|
|
|
|
Response: 200 OK
|
|
{
|
|
"execution_id": "exec-001",
|
|
"status": "completed",
|
|
"bundle_id": "bundle-001",
|
|
"started_at": "2025-12-05T00:00:00Z",
|
|
"completed_at": "2025-12-05T00:00:05Z"
|
|
}
|
|
```
|
|
|
|
### Bundle Retrieval
|
|
|
|
#### Get Bundle Manifest
|
|
|
|
```
|
|
GET /api/v1/export/bundles/{bundle_id}
|
|
|
|
Response: 200 OK
|
|
{
|
|
"bundle_id": "bundle-001",
|
|
"artifact_digest": "sha256:...",
|
|
...
|
|
}
|
|
```
|
|
|
|
#### Download Bundle
|
|
|
|
```
|
|
GET /api/v1/export/bundles/{bundle_id}/download
|
|
|
|
Response: 200 OK
|
|
Content-Type: application/json
|
|
Content-Disposition: attachment; filename="vex-export-2025-12-05.json"
|
|
|
|
[bundle content]
|
|
```
|
|
|
|
## Signing Configuration
|
|
|
|
### Enable Signing
|
|
|
|
```json
|
|
{
|
|
"signing": {
|
|
"enabled": true,
|
|
"predicate_type": "stella.ops/vex@v1",
|
|
"key_id": "signing-key-001",
|
|
"include_rekor": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Predicate Types
|
|
|
|
| Type | Description |
|
|
|------|-------------|
|
|
| `stella.ops/vex@v1` | VEX export attestation |
|
|
| `stella.ops/sbom@v1` | SBOM export attestation |
|
|
| `stella.ops/policy@v1` | Policy result export |
|
|
|
|
## Job Status
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| `idle` | Job is waiting for next scheduled run |
|
|
| `running` | Job is currently executing |
|
|
| `completed` | Last run completed successfully |
|
|
| `failed` | Last run failed |
|
|
| `disabled` | Job is disabled |
|
|
|
|
## Error Codes
|
|
|
|
| Code | Message |
|
|
|------|---------|
|
|
| `ERR_EXP_001` | Invalid schedule expression |
|
|
| `ERR_EXP_002` | Invalid destination config |
|
|
| `ERR_EXP_003` | Export failed |
|
|
| `ERR_EXP_004` | Signing failed |
|
|
| `ERR_EXP_005` | Job not found |
|
|
|
|
## Unblocks
|
|
|
|
This contract unblocks the following tasks:
|
|
|
|
- EXPORT-CONSOLE-23-001
|
|
|
|
## Related Contracts
|
|
|
|
- [Mirror Bundle Contract](./mirror-bundle.md) - Bundle format for air-gap
|
|
- [Risk Scoring Contract](./risk-scoring.md) - Score digest in exports
|